From ecaa660b9dc5d9b0a9484856a4789d71908f8e2f Mon Sep 17 00:00:00 2001 From: Olivier Desenfans Date: Wed, 13 Nov 2019 13:28:21 +0100 Subject: [PATCH 001/520] Revert "Single project-wide header for driver functions" This reverts commit 07c61316b3b89f4885a6fddae6daad5cf5c41e39. Will start from beginning. Try to keep git history. --- CO_driver.h | 281 ------------------ CO_types.h | 86 ------ .../{CO_driver_target.h => CO_driver.h} | 118 ++++++-- .../{CO_driver_target.h => CO_driver.h} | 150 +++++++--- .../{CO_driver_target.h => CO_driver.h} | 130 ++++++-- .../{CO_driver_target.h => CO_driver.h} | 214 +++++++++---- .../PIC32/{CO_driver_target.h => CO_driver.h} | 145 +++++++-- .../SAM3X/{CO_driver_target.h => CO_driver.h} | 135 +++++++-- .../STM32/{CO_driver_target.h => CO_driver.h} | 115 +++++-- .../{CO_driver_target.h => CO_driver.h} | 87 +++++- .../{CO_driver_target.h => CO_driver.h} | 237 +++++++++++++-- .../{CO_driver_target.h => CO_driver.h} | 125 ++++++-- .../eCos/{CO_driver_target.h => CO_driver.h} | 140 +++++++-- stack/neuberger-socketCAN/CO_driver.c | 12 +- .../{CO_driver_target.h => CO_driver.h} | 115 ++++++- stack/neuberger-socketCAN/CO_driver_base.h | 77 +++-- .../{CO_driver_target.h => CO_driver.h} | 120 ++++++-- 17 files changed, 1548 insertions(+), 739 deletions(-) delete mode 100644 CO_driver.h delete mode 100644 CO_types.h rename stack/LPC1768/{CO_driver_target.h => CO_driver.h} (55%) rename stack/LPC177x_8x/{CO_driver_target.h => CO_driver.h} (53%) rename stack/MCF5282/{CO_driver_target.h => CO_driver.h} (79%) rename stack/PIC24_dsPIC33/{CO_driver_target.h => CO_driver.h} (74%) rename stack/PIC32/{CO_driver_target.h => CO_driver.h} (75%) rename stack/SAM3X/{CO_driver_target.h => CO_driver.h} (53%) rename stack/STM32/{CO_driver_target.h => CO_driver.h} (67%) rename stack/STM32F3/{CO_driver_target.h => CO_driver.h} (70%) rename stack/drvTemplate/{CO_driver_target.h => CO_driver.h} (58%) rename stack/dsPIC30F/{CO_driver_target.h => CO_driver.h} (81%) rename stack/eCos/{CO_driver_target.h => CO_driver.h} (59%) rename stack/neuberger-socketCAN/{CO_driver_target.h => CO_driver.h} (80%) rename stack/socketCAN/{CO_driver_target.h => CO_driver.h} (60%) diff --git a/CO_driver.h b/CO_driver.h deleted file mode 100644 index 90c88f75..00000000 --- a/CO_driver.h +++ /dev/null @@ -1,281 +0,0 @@ -/** - * CAN driver functions. - * - * Defines functions that must be implemented for each target. - * - * @file CO_driver.h - * @ingroup CO_driver - * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CO_DRIVER_H -#define CO_DRIVER_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include "CO_driver_target.h" -#include "CO_types.h" - -/* Include processor header file */ -#include /* for 'int8_t' to 'uint64_t' */ - -/** - * @defgroup CO_driver Driver - * @ingroup CO_CANopen - * @{ - * - * Microcontroller specific code for CANopenNode. - * - * This file contains type definitions, functions and macros for: - * - Basic data types. - * - Receive and transmit buffers for CANopen messages. - * - Interaction with CAN module on the microcontroller. - * - CAN receive and transmit interrupts. - * - * This file is not only a CAN driver. There are no classic CAN queues for CAN - * messages. This file provides direct connection with other CANopen - * objects. It tries to provide fast responses and tries to avoid unnecessary - * calculations and memory consumptions. - * - * CO_CANmodule_t contains an array of _Received message objects_ (of type - * CO_CANrx_t) and an array of _Transmit message objects_ (of type CO_CANtx_t). - * Each CANopen communication object owns one member in one of the arrays. - * For example Heartbeat producer generates one CANopen transmitting object, - * so it has reserved one member in CO_CANtx_t array. - * SYNC module may produce sync or consume sync, so it has reserved one member - * in CO_CANtx_t and one member in CO_CANrx_t array. - * - * ###Reception of CAN messages. - * Before CAN messages can be received, each member in CO_CANrx_t must be - * initialized. CO_CANrxBufferInit() is called by CANopen module, which - * uses specific member. For example @ref CO_HBconsumer uses multiple members - * in CO_CANrx_t array. (It monitors multiple heartbeat messages from remote - * nodes.) It must call CO_CANrxBufferInit() multiple times. - * - * Main arguments to the CO_CANrxBufferInit() function are CAN identifier - * and a pointer to callback function. Those two arguments (and some others) - * are copied to the member of the CO_CANrx_t array. - * - * Callback function is a function, specified by specific CANopen module - * (for example by @ref CO_HBconsumer). Each CANopen module defines own - * callback function. Callback function will process the received CAN message. - * It will copy the necessary data from CAN message to proper place. It may - * also trigger additional task, which will further process the received message. - * Callback function must be fast and must only make the necessary calculations - * and copying. - * - * Received CAN messages are processed by CAN receive interrupt function. - * After CAN message is received, function first tries to find matching CAN - * identifier from CO_CANrx_t array. If found, then a corresponding callback - * function is called. - * - * Callback function accepts two parameters: - * - object is pointer to object registered by CO_CANrxBufferInit(). - * - msg is pointer to CAN message of type CO_CANrxMsg_t. - * - * Callback function must return #CO_ReturnError_t: CO_ERROR_NO, - * CO_ERROR_RX_OVERFLOW, CO_ERROR_RX_PDO_OVERFLOW, CO_ERROR_RX_MSG_LENGTH or - * CO_ERROR_RX_PDO_LENGTH. - * - * - * ###Transmission of CAN messages. - * Before CAN messages can be transmitted, each member in CO_CANtx_t must be - * initialized. CO_CANtxBufferInit() is called by CANopen module, which - * uses specific member. For example Heartbeat producer must initialize it's - * member in CO_CANtx_t array. - * - * CO_CANtxBufferInit() returns a pointer of type CO_CANtx_t, which contains buffer - * where CAN message data can be written. CAN message is send with calling - * CO_CANsend() function. If at that moment CAN transmit buffer inside - * microcontroller's CAN module is free, message is copied directly to CAN module. - * Otherwise CO_CANsend() function sets _bufferFull_ flag to true. Message will be - * then sent by CAN TX interrupt as soon as CAN module is freed. Until message is - * not copied to CAN module, its contents must not change. There may be multiple - * _bufferFull_ flags in CO_CANtx_t array set to true. In that case messages with - * lower index inside array will be sent first. - */ - -/** - * Request CAN configuration (stopped) mode and *wait* untill it is set. - * - * @param CANdriverState User-provided CAN module structure. - */ -void CO_CANsetConfigurationMode(void *CANdriverState); - - -/** - * Request CAN normal (opearational) mode and *wait* untill it is set. - * - * @param CANmodule This object. - */ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/** - * 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 User-provided CAN module structure.. - * @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 Valid values are (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. - * If value is illegal, bitrate defaults to 125. - * - * Return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. - */ -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); - - -/** - * Switch off CANmodule. 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, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/** - * 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 This flag bit is used for synchronous TPDO messages. If it is set, - * message will not be sent, if curent time is outside synchronous window. - * - * @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, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/** - * 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); - - -/** - * Clear all synchronous TPDOs from CAN module transmit buffers. - * - * CANopen allows synchronous PDO communication only inside time between SYNC - * message and SYNC Window. If time is outside this window, new synchronous PDOs - * must not be sent and all pending sync TPDOs, which may be on CAN TX buffers, - * must be cleared. - * - * This function checks (and aborts transmission if necessary) CAN TX buffers - * when it is called. Function should be called by the stack in the moment, - * when SYNC time was just passed out of synchronous window. - * - * @param CANmodule This object. - */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/** - * Verify all errors of CAN module. - * - * Function is called directly from CO_EM_process() function. - * - * @param CANmodule This object. - */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -/** @} */ -#endif /* CO_DRIVER_H */ diff --git a/CO_types.h b/CO_types.h deleted file mode 100644 index 67a371cb..00000000 --- a/CO_types.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * CANopenNode types. - * - * Defines common types for CANopenNode. - * - * @file CO_types.h - * @ingroup CO_CANopen - * @author Olivier Desenfans - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CO_TYPES_H -#define CO_TYPES_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** - * Return values of some CANopen functions. - * - * A function should return 0 on success and a negative value on error. - */ -typedef enum { - /** Operation completed successfully */ - CO_ERROR_NO = 0, - /** Error in function arguments */ - CO_ERROR_ILLEGAL_ARGUMENT = -1, - /** Memory allocation failed */ - CO_ERROR_OUT_OF_MEMORY = -2, - /** Function timeout */ - CO_ERROR_TIMEOUT = -3, - /** Illegal baudrate passed to function CO_CANmodule_init() */ - CO_ERROR_ILLEGAL_BAUDRATE = -4, - /** Previous message was not processed yet */ - CO_ERROR_RX_OVERFLOW = -5, - /** previous PDO was not processed yet */ - CO_ERROR_RX_PDO_OVERFLOW = -6, - /** Wrong receive message length */ - CO_ERROR_RX_MSG_LENGTH = -7, - /** Wrong receive PDO length */ - CO_ERROR_RX_PDO_LENGTH = -8, - /** Previous message is still waiting, buffer full */ - CO_ERROR_TX_OVERFLOW = -9, - /** Synchronous TPDO is outside window */ - CO_ERROR_TX_PDO_WINDOW = -10, - /** Transmit buffer was not confugured properly */ - CO_ERROR_TX_UNCONFIGURED = -11, - /** Error in function function parameters */ - CO_ERROR_PARAMETERS = -12, - /** Stored data are corrupt */ - CO_ERROR_DATA_CORRUPT = -13, - /** CRC does not match */ - CO_ERROR_CRC = -14, - /** Sending rejected because driver is busy. Try again */ - CO_ERROR_TX_BUSY = -15, - /** Command can't be processed in current state */ - CO_ERROR_WRONG_NMT_STATE = -16, - /** Syscall failed */ - CO_ERROR_SYSCALL = -17, - /** Driver not ready */ - CO_ERROR_INVALID_STATE = -18, -} CO_ReturnError_t; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -/** @} */ -#endif /* CO_TYPES_H */ diff --git a/stack/LPC1768/CO_driver_target.h b/stack/LPC1768/CO_driver.h similarity index 55% rename from stack/LPC1768/CO_driver_target.h rename to stack/LPC1768/CO_driver.h index 19b87ea5..9f4aac9a 100644 --- a/stack/LPC1768/CO_driver_target.h +++ b/stack/LPC1768/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for LPC1768 microcontroller using Mbed SDK. * - * @file CO_driver_target.h + * @file CO_driver.h * @ingroup CO_driver * @author Benoit Rapidel * @copyright 2016 Benoit Rapidel @@ -44,8 +44,8 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H /* For documentation see file drvTemplate/CO_driver.h */ @@ -56,32 +56,49 @@ #include /* for 'true', 'false' */ -/* Endianness */ -#define CO_LITTLE_ENDIAN - /* CAN module base address */ #define MBED_CAN 1 /* Critical sections */ -#define CO_LOCK_CAN_SEND() -#define CO_UNLOCK_CAN_SEND() + #define CO_LOCK_CAN_SEND() + #define CO_UNLOCK_CAN_SEND() -#define CO_LOCK_EMCY() -#define CO_UNLOCK_EMCY() + #define CO_LOCK_EMCY() + #define CO_UNLOCK_EMCY() -#define CO_LOCK_OD() -#define CO_UNLOCK_OD() + #define CO_LOCK_OD() + #define CO_UNLOCK_OD() /* Data types */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; + + +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; /* CAN receive message structure as aligned in CAN module. */ @@ -128,8 +145,69 @@ typedef struct{ }CO_CANmodule_t; +/* Endianes */ +#define CO_LITTLE_ENDIAN + + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. */ +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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* Receives and transmits CAN messages. */ void CO_CANinterrupt(CO_CANmodule_t *CANmodule); -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/LPC177x_8x/CO_driver_target.h b/stack/LPC177x_8x/CO_driver.h similarity index 53% rename from stack/LPC177x_8x/CO_driver_target.h rename to stack/LPC177x_8x/CO_driver.h index fbd628d8..23d8ced5 100644 --- a/stack/LPC177x_8x/CO_driver_target.h +++ b/stack/LPC177x_8x/CO_driver.h @@ -3,7 +3,7 @@ * * This file is a template for other microcontrollers. * - * @file CO_driver_target.h + * @file CO_driver.h * @author Janez Paternoster * @author Amit H * @copyright 2004 - 2014 Janez Paternoster @@ -46,8 +46,11 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H + + +/* For documentation see file drvTemplate/CO_driver.h */ #include "FreeRTOS.h" @@ -57,48 +60,65 @@ #include /* for 'int8_t' to 'uint64_t' */ -/* Endianness */ -#define CO_LITTLE_ENDIAN - /* CAN module base address */ -#define ADDR_CAN1 0 -#define ADDR_CAN2 1 + #define ADDR_CAN1 0 + #define ADDR_CAN2 1 -#define CAN_NODE_ID_0_PORT 1 -#define CAN_NODE_ID_0_PIN 23 -#define CAN_NODE_ID_1_PORT 1 -#define CAN_NODE_ID_1_PIN 24 -#define CAN_NODE_ID_2_PORT 1 -#define CAN_NODE_ID_2_PIN 25 -#define CAN_NODE_ID_3_PORT 1 -#define CAN_NODE_ID_3_PIN 26 -#define CAN_NODE_ID_4_PORT 1 -#define CAN_NODE_ID_4_PIN 28 + #define CAN_NODE_ID_0_PORT 1 + #define CAN_NODE_ID_0_PIN 23 + #define CAN_NODE_ID_1_PORT 1 + #define CAN_NODE_ID_1_PIN 24 + #define CAN_NODE_ID_2_PORT 1 + #define CAN_NODE_ID_2_PIN 25 + #define CAN_NODE_ID_3_PORT 1 + #define CAN_NODE_ID_3_PIN 26 + #define CAN_NODE_ID_4_PORT 1 + #define CAN_NODE_ID_4_PIN 28 -#define CAN_RUN_LED_PORT 1 -#define CAN_RUN_LED_PIN 20 + #define CAN_RUN_LED_PORT 1 + #define CAN_RUN_LED_PIN 20 /* Critical sections */ -#define CO_LOCK_CAN_SEND() taskENTER_CRITICAL() -#define CO_UNLOCK_CAN_SEND() taskEXIT_CRITICAL() + #define CO_LOCK_CAN_SEND() taskENTER_CRITICAL() + #define CO_UNLOCK_CAN_SEND() taskEXIT_CRITICAL() -#define CO_LOCK_EMCY() taskENTER_CRITICAL() -#define CO_UNLOCK_EMCY() taskEXIT_CRITICAL() + #define CO_LOCK_EMCY() taskENTER_CRITICAL() + #define CO_UNLOCK_EMCY() taskEXIT_CRITICAL() -#define CO_LOCK_OD() taskENTER_CRITICAL() -#define CO_UNLOCK_OD() taskEXIT_CRITICAL() + #define CO_LOCK_OD() taskENTER_CRITICAL() + #define CO_UNLOCK_OD() taskEXIT_CRITICAL() /* Data types */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; + + +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; /* CAN receive message structure as aligned in CAN module. */ @@ -147,8 +167,70 @@ typedef struct{ void *em; }CO_CANmodule_t; + +/* Endianes */ +#define CO_LITTLE_ENDIAN + + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. */ +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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* CAN interrupt receives and transmits CAN messages. */ void CO_CANinterrupt(CO_CANmodule_t *CANmodule); -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/MCF5282/CO_driver_target.h b/stack/MCF5282/CO_driver.h similarity index 79% rename from stack/MCF5282/CO_driver_target.h rename to stack/MCF5282/CO_driver.h index 8a4aedff..ed29678a 100644 --- a/stack/MCF5282/CO_driver_target.h +++ b/stack/MCF5282/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for Freescale MCF5282 ColdFire V2 microcontroller. * - * @file CO_driver_target.h + * @file CO_driver.h * @author Janez Paternoster * @author Laurent Grosbois * @copyright 2004 - 2014 Janez Paternoster @@ -44,8 +44,11 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H + + +/* For documentation see file drvTemplate/CO_driver.h */ #include "mcf5282.h" /* processor header file */ @@ -53,23 +56,20 @@ #include /* for 'int8_t' to 'uint64_t' */ -/* Endianness */ -#define CO_LITTLE_ENDIAN - /* CAN module base address */ -#define ADDR_CAN1 0 -#define ADDR_CAN2 (_CAN2_BASE_ADDRESS - _CAN1_BASE_ADDRESS) + #define ADDR_CAN1 0 + #define ADDR_CAN2 (_CAN2_BASE_ADDRESS - _CAN1_BASE_ADDRESS) /* Critical sections */ -#define CO_LOCK_CAN_SEND() asm{ move.w #0x2700,sr}; -#define CO_UNLOCK_CAN_SEND() asm{ move.w #0x2000,sr}; + #define CO_LOCK_CAN_SEND() asm{ move.w #0x2700,sr}; + #define CO_UNLOCK_CAN_SEND() asm{ move.w #0x2000,sr}; -#define CO_LOCK_EMCY() asm{ move.w #0x2700,sr}; -#define CO_UNLOCK_EMCY() asm{ move.w #0x2000,sr}; + #define CO_LOCK_EMCY() asm{ move.w #0x2700,sr}; + #define CO_UNLOCK_EMCY() asm{ move.w #0x2000,sr}; -#define CO_LOCK_OD() asm{ move.w #0x2700,sr}; -#define CO_UNLOCK_OD() asm{ move.w #0x2000,sr}; + #define CO_LOCK_OD() asm{ move.w #0x2700,sr}; + #define CO_UNLOCK_OD() asm{ move.w #0x2000,sr}; /* MACRO : get information from Rx buffer */ @@ -77,13 +77,13 @@ /* Data types */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; /* CAN bit rates @@ -305,6 +305,26 @@ typedef struct{ }CO_CANbitRateData_t; +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; + + /* CAN receive message structure as aligned in CAN module. */ typedef struct{ unsigned timestamp :8; /* 8 bits timestamp, see MCF5282 documentation */ @@ -356,8 +376,74 @@ typedef struct{ }CO_CANmodule_t; +/* Endianes */ +#define CO_LITTLE_ENDIAN + + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. + * + * MCF5282 FlexCAN configuration: 16 buffers are available. + * Buffers [0..13] are used for reception + * Buffers [14..15] are used for reception + */ +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); /* Valid values are (in kbps): 125, 1000. If value is illegal, bitrate defaults to 125. */ + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* CAN interrupt receives and transmits CAN messages. */ void CO_CANinterrupt(CO_CANmodule_t *CANmodule, uint16_t ICODE); -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/PIC24_dsPIC33/CO_driver_target.h b/stack/PIC24_dsPIC33/CO_driver.h similarity index 74% rename from stack/PIC24_dsPIC33/CO_driver_target.h rename to stack/PIC24_dsPIC33/CO_driver.h index fc02b733..9a58a03d 100644 --- a/stack/PIC24_dsPIC33/CO_driver_target.h +++ b/stack/PIC24_dsPIC33/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for Microchip dsPIC33 or PIC24 microcontroller. * - * @file CO_driver_target.h + * @file CO_driver.h * @author Janez Paternoster * @author Peter Rozsahegyi (EDS) * @author Jens Nielsen (CAN receive) @@ -25,8 +25,11 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H + + +/* For documentation see file drvTemplate/CO_driver.h */ #if defined(__dsPIC33F__) || defined(__PIC24H__) @@ -38,93 +41,91 @@ #include /* for 'int8_t' to 'uint64_t' */ #include /* for 'true' and 'false' */ -/* Endianness */ -#define CO_LITTLE_ENDIAN /* CAN message buffer sizes for CAN module 1 and 2. Valid values * are 0, 4, 6, 8, 12, 16. Default is one TX and seven RX messages (FIFO). */ -#ifndef CO_CAN1msgBuffSize - #define CO_CAN1msgBuffSize 8 -#endif /* CO_CAN1msgBuffSize */ -#ifndef CO_CAN2msgBuffSize - #define CO_CAN2msgBuffSize 0 //CAN module 2 not used by default -#endif /* CO_CAN2msgBuffSize */ + #ifndef CO_CAN1msgBuffSize + #define CO_CAN1msgBuffSize 8 + #endif + #ifndef CO_CAN2msgBuffSize + #define CO_CAN2msgBuffSize 0 //CAN module 2 not used by default + #endif /* Default DMA addresses for CAN modules. */ -#ifndef CO_CAN1_DMA0 - #define CO_CAN1_DMA0 ADDR_DMA0 -#endif /* CO_CAN1_DMA0 */ -#ifndef CO_CAN1_DMA1 - #define CO_CAN1_DMA1 ADDR_DMA1 -#endif /* CO_CAN1_DMA1 */ -#ifndef CO_CAN2_DMA0 - #define CO_CAN2_DMA0 ADDR_DMA2 -#endif /* CO_CAN2_DMA0 */ -#ifndef CO_CAN2_DMA1 - #define CO_CAN2_DMA1 ADDR_DMA3 -#endif /* CO_CAN2_DMA1 */ + #ifndef CO_CAN1_DMA0 + #define CO_CAN1_DMA0 ADDR_DMA0 + #endif + #ifndef CO_CAN1_DMA1 + #define CO_CAN1_DMA1 ADDR_DMA1 + #endif + #ifndef CO_CAN2_DMA0 + #define CO_CAN2_DMA0 ADDR_DMA2 + #endif + #ifndef CO_CAN2_DMA1 + #define CO_CAN2_DMA1 ADDR_DMA3 + #endif /* Define DMA attribute on supported platforms */ -#if defined(__dsPIC33F__) || defined(__PIC24H__) || defined(__DMA_BASE) - #define __dma __attribute__((space(dma))) -#else - #define __dma - #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) - #define __builtin_dmaoffset(V) (uint16_t)V + #if defined(__dsPIC33F__) || defined(__PIC24H__) || defined(__DMA_BASE) + #define __dma __attribute__((space(dma))) + #else + #define __dma + #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) + #define __builtin_dmaoffset(V) (uint16_t)V + #endif #endif -#endif /* Define EDS attribute on supported platforms */ -#if defined(__HAS_EDS__) - #define __eds __attribute__((eds)) - #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) - #define __builtin_dmapage(V) (uint16_t)0 + #if defined(__HAS_EDS__) + #define __eds __attribute__((eds)) + #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) + #define __builtin_dmapage(V) (uint16_t)0 + #endif + #else + #define __eds + #define __eds__ #endif -#else - #define __eds - #define __eds__ -#endif /* CAN module base addresses */ -#define ADDR_CAN1 ((uint16_t)&C1CTRL1) -#define ADDR_CAN2 ((uint16_t)&C2CTRL1) + #define ADDR_CAN1 ((uint16_t)&C1CTRL1) + #define ADDR_CAN2 ((uint16_t)&C2CTRL1) /* DMA addresses */ -#define ADDR_DMA0 ((uint16_t)&DMA0CON) -#define ADDR_DMA1 ((uint16_t)&DMA1CON) -#define ADDR_DMA2 ((uint16_t)&DMA2CON) -#define ADDR_DMA3 ((uint16_t)&DMA3CON) -#define ADDR_DMA4 ((uint16_t)&DMA4CON) -#define ADDR_DMA5 ((uint16_t)&DMA5CON) -#define ADDR_DMA6 ((uint16_t)&DMA6CON) -#define ADDR_DMA7 ((uint16_t)&DMA7CON) + #define ADDR_DMA0 ((uint16_t)&DMA0CON) + #define ADDR_DMA1 ((uint16_t)&DMA1CON) + #define ADDR_DMA2 ((uint16_t)&DMA2CON) + #define ADDR_DMA3 ((uint16_t)&DMA3CON) + #define ADDR_DMA4 ((uint16_t)&DMA4CON) + #define ADDR_DMA5 ((uint16_t)&DMA5CON) + #define ADDR_DMA6 ((uint16_t)&DMA6CON) + #define ADDR_DMA7 ((uint16_t)&DMA7CON) /* Critical sections */ -#define CO_LOCK_CAN_SEND() asm volatile ("disi #0x3FFF") -#define CO_UNLOCK_CAN_SEND() asm volatile ("disi #0x0000") + #define CO_LOCK_CAN_SEND() asm volatile ("disi #0x3FFF") + #define CO_UNLOCK_CAN_SEND() asm volatile ("disi #0x0000") -#define CO_LOCK_EMCY() asm volatile ("disi #0x3FFF") -#define CO_UNLOCK_EMCY() asm volatile ("disi #0x0000") + #define CO_LOCK_EMCY() asm volatile ("disi #0x3FFF") + #define CO_UNLOCK_EMCY() asm volatile ("disi #0x0000") -#define CO_LOCK_OD() asm volatile ("disi #0x3FFF") -#define CO_UNLOCK_OD() asm volatile ("disi #0x0000") + #define CO_LOCK_OD() asm volatile ("disi #0x3FFF") + #define CO_UNLOCK_OD() asm volatile ("disi #0x0000") -#define CO_DISABLE_INTERRUPTS() asm volatile ("disi #0x3FFF") -#define CO_ENABLE_INTERRUPTS() asm volatile ("disi #0x0000") + #define CO_DISABLE_INTERRUPTS() asm volatile ("disi #0x3FFF") + #define CO_ENABLE_INTERRUPTS() asm volatile ("disi #0x0000") /* Data types */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; /* CAN bit rates @@ -343,8 +344,8 @@ typedef unsigned char domain_t; {1, 2, TQ_x_17} /*Not working*/ #else #error define_CO_FCY CO_FCY not supported - #endif /* CO_FCY == */ -#endif /* CO_FCY */ + #endif +#endif /* Structure contains timing coefficients for CAN module. @@ -365,6 +366,26 @@ typedef struct{ }CO_CANbitRateData_t; +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; + + /* CAN receive message structure as aligned in CAN module. * In dsPIC33F and PIC24H this structure is used for both: transmitting and * receiving to and from CAN module. (Object is ownded by CAN module). @@ -420,6 +441,67 @@ typedef struct{ }CO_CANmodule_t; +/* Endianes */ +#define CO_LITTLE_ENDIAN + + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. */ +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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* CAN interrupt receives and transmits CAN messages. * * Function must be called directly from _C1Interrupt or _C2Interrupt with @@ -428,4 +510,4 @@ typedef struct{ void CO_CANinterrupt(CO_CANmodule_t *CANmodule); -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/PIC32/CO_driver_target.h b/stack/PIC32/CO_driver.h similarity index 75% rename from stack/PIC32/CO_driver_target.h rename to stack/PIC32/CO_driver.h index e0e9c7fa..8dd8a687 100644 --- a/stack/PIC32/CO_driver_target.h +++ b/stack/PIC32/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for Microchip PIC32MX microcontroller. * - * @file CO_driver_target.h + * @file CO_driver.h * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * @@ -23,8 +23,11 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H + + +/* For documentation see file drvTemplate/CO_driver.h */ #include /* processor header file */ @@ -32,43 +35,41 @@ #include /* for 'int8_t' to 'uint64_t' */ #include /* for 'true', 'false' */ -/* Endianness */ -#define CO_LITTLE_ENDIAN /* CAN module base address */ -#define ADDR_CAN1 0 -#define ADDR_CAN2 (_CAN2_BASE_ADDRESS - _CAN1_BASE_ADDRESS) + #define ADDR_CAN1 0 + #define ADDR_CAN2 (_CAN2_BASE_ADDRESS - _CAN1_BASE_ADDRESS) /* Translate a kernel virtual address in KSEG0 or KSEG1 to a real -* physical address and back. */ -typedef unsigned long CO_paddr_t; /* a physical address */ -typedef unsigned long CO_vaddr_t; /* a virtual address */ -#define CO_KVA_TO_PA(v) ((CO_paddr_t)(v) & 0x1fffffff) -#define CO_PA_TO_KVA0(pa) ((void *) ((pa) | 0x80000000)) -#define CO_PA_TO_KVA1(pa) ((void *) ((pa) | 0xa0000000)) + * physical address and back. */ + typedef unsigned long CO_paddr_t; /* a physical address */ + typedef unsigned long CO_vaddr_t; /* a virtual address */ + #define CO_KVA_TO_PA(v) ((CO_paddr_t)(v) & 0x1fffffff) + #define CO_PA_TO_KVA0(pa) ((void *) ((pa) | 0x80000000)) + #define CO_PA_TO_KVA1(pa) ((void *) ((pa) | 0xa0000000)) /* Critical sections */ -extern unsigned int CO_interruptStatus; -#define CO_LOCK_CAN_SEND() CO_interruptStatus = __builtin_disable_interrupts() -#define CO_UNLOCK_CAN_SEND() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} + extern unsigned int CO_interruptStatus; + #define CO_LOCK_CAN_SEND() CO_interruptStatus = __builtin_disable_interrupts() + #define CO_UNLOCK_CAN_SEND() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} -#define CO_LOCK_EMCY() CO_interruptStatus = __builtin_disable_interrupts() -#define CO_UNLOCK_EMCY() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} + #define CO_LOCK_EMCY() CO_interruptStatus = __builtin_disable_interrupts() + #define CO_UNLOCK_EMCY() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} -#define CO_LOCK_OD() CO_interruptStatus = __builtin_disable_interrupts() -#define CO_UNLOCK_OD() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} + #define CO_LOCK_OD() CO_interruptStatus = __builtin_disable_interrupts() + #define CO_UNLOCK_OD() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} /* Data types */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; /* CAN bit rates @@ -290,6 +291,26 @@ typedef struct{ }CO_CANbitRateData_t; +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; + + /* CAN receive message structure as aligned in CAN module. */ typedef struct{ unsigned ident :11; /* Standard Identifier */ @@ -341,6 +362,74 @@ typedef struct{ }CO_CANmodule_t; +/* Endianes */ +#define CO_LITTLE_ENDIAN + + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. + * + * PIC32MX CAN FIFO configuration: Two FIFOs are used. First FIFO is 32 messages + * long and is used for reception. Second is used for transmission and is 1 + * message long. Format of message in fifo is described by CO_CANrxMsg_t for + * both: receiving and transmitting messages. However transmitting messages does + * not use all structure members. + */ +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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* CAN interrupt receives and transmits CAN messages. * * Function must be called directly from _C1Interrupt or _C2Interrupt with @@ -349,4 +438,4 @@ typedef struct{ void CO_CANinterrupt(CO_CANmodule_t *CANmodule); -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/SAM3X/CO_driver_target.h b/stack/SAM3X/CO_driver.h similarity index 53% rename from stack/SAM3X/CO_driver_target.h rename to stack/SAM3X/CO_driver.h index 4776d858..c337fccc 100644 --- a/stack/SAM3X/CO_driver_target.h +++ b/stack/SAM3X/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for the Atmel SAM3X microcontroller. * - * @file CO_driver_target.h + * @file CO_driver.h * @author Janez Paternoster * @author Olof Larsson * @copyright 2014 Janez Paternoster @@ -44,8 +44,11 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H + + +/* For documentation see file drvTemplate/CO_driver.h */ #include /* for 'NULL' */ @@ -56,40 +59,57 @@ #include -/** Endianness */ -#define CO_LITTLE_ENDIAN - /* CAN module base address */ -#define ADDR_CAN1 CAN0 -#define ADDR_CAN2 CAN1 -/* -Remember to set: - #define CONF_BOARD_CAN0 - #define CONF_BOARD_CAN1 -in conf_board.h -*/ + #define ADDR_CAN1 CAN0 + #define ADDR_CAN2 CAN1 + /* + Remember to set: + #define CONF_BOARD_CAN0 + #define CONF_BOARD_CAN1 + in conf_board.h + */ /* Critical sections */ -#define CO_LOCK_CAN_SEND() //taskENTER_CRITICAL() -#define CO_UNLOCK_CAN_SEND() //taskEXIT_CRITICAL() + #define CO_LOCK_CAN_SEND() //taskENTER_CRITICAL() + #define CO_UNLOCK_CAN_SEND() //taskEXIT_CRITICAL() -#define CO_LOCK_EMCY() //taskENTER_CRITICAL() -#define CO_UNLOCK_EMCY() //taskEXIT_CRITICAL() + #define CO_LOCK_EMCY() //taskENTER_CRITICAL() + #define CO_UNLOCK_EMCY() //taskEXIT_CRITICAL() -#define CO_LOCK_OD() //taskENTER_CRITICAL() -#define CO_UNLOCK_OD() //taskEXIT_CRITICAL() + #define CO_LOCK_OD() //taskENTER_CRITICAL() + #define CO_UNLOCK_OD() //taskEXIT_CRITICAL() /* Data types */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; + + +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; /* CAN receive message structure as aligned in CAN module. */ @@ -141,6 +161,67 @@ typedef struct{ }CO_CANmodule_t; +/* Endianes */ +#define CO_LITTLE_ENDIAN + + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. */ +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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* CAN interrupt receives and transmits CAN messages. */ void CO_CANinterrupt(CO_CANmodule_t *CANmodule); diff --git a/stack/STM32/CO_driver_target.h b/stack/STM32/CO_driver.h similarity index 67% rename from stack/STM32/CO_driver_target.h rename to stack/STM32/CO_driver.h index bae49e4b..a9f17df8 100644 --- a/stack/STM32/CO_driver_target.h +++ b/stack/STM32/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for ST STM32F103 microcontroller. * - * @file CO_driver_target.h + * @file CO_driver.h * @author Janez Paternoster * @author Ondrej Netik * @author Vijayendra @@ -46,31 +46,34 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H + + +/* For documentation see file drvTemplate/CO_driver.h */ /* Includes ------------------------------------------------------------------*/ -// #include "common.h" -// #include "stm32f10x_conf.h" +#include "common.h" +#include "stm32f10x_conf.h" /* Exported define -----------------------------------------------------------*/ #define PACKED_STRUCT __attribute__((packed)) #define ALIGN_STRUCT_DWORD __attribute__((aligned(4))) /* Peripheral addresses */ -#define ADDR_CAN1 CAN1 -#define TMIDxR_TXRQ ((uint32_t)0x00000001) /* Transmit mailbox request */ + #define ADDR_CAN1 CAN1 + #define TMIDxR_TXRQ ((uint32_t)0x00000001) /* Transmit mailbox request */ /* Critical sections */ -#define CO_LOCK_CAN_SEND() __set_PRIMASK(1); -#define CO_UNLOCK_CAN_SEND() __set_PRIMASK(0); + #define CO_LOCK_CAN_SEND() __set_PRIMASK(1); + #define CO_UNLOCK_CAN_SEND() __set_PRIMASK(0); -#define CO_LOCK_EMCY() __set_PRIMASK(1); -#define CO_UNLOCK_EMCY() __set_PRIMASK(0); + #define CO_LOCK_EMCY() __set_PRIMASK(1); + #define CO_UNLOCK_EMCY() __set_PRIMASK(0); -#define CO_LOCK_OD() __set_PRIMASK(1); -#define CO_UNLOCK_OD() __set_PRIMASK(0); + #define CO_LOCK_OD() __set_PRIMASK(1); + #define CO_UNLOCK_OD() __set_PRIMASK(0); #define CLOCK_CAN RCC_APB1Periph_CAN1 @@ -117,11 +120,30 @@ #define INAK_TIMEOUT ((uint32_t)0x0000FFFF) /* Data types */ -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; + +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; /* CAN receive message structure as aligned in CAN module. * prevzato z stm32f10_can.h - velikostne polozky a poradi odpovidaji. */ @@ -192,10 +214,65 @@ void CanLedsSet(eCoLeds led); #endif /* CO_USE_LEDS */ +/* Request CAN configuration or normal mode */ +//void CO_CANsetConfigurationMode(CAN_TypeDef *CANdriverState); +//void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + +/* Initialize CAN module object. */ +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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +//uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + int8_t rtr, + void *object, + void (*pFunct)(void *object, CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + int8_t rtr, + uint8_t noOfBytes, + int8_t syncFlag); + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* CAN interrupts receives and transmits CAN messages. */ void CO_CANinterrupt_Rx(CO_CANmodule_t *CANmodule); void CO_CANinterrupt_Tx(CO_CANmodule_t *CANmodule); void CO_CANinterrupt_Status(CO_CANmodule_t *CANmodule); -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/STM32F3/CO_driver_target.h b/stack/STM32F3/CO_driver.h similarity index 70% rename from stack/STM32F3/CO_driver_target.h rename to stack/STM32F3/CO_driver.h index c1680410..71db38bd 100644 --- a/stack/STM32F3/CO_driver_target.h +++ b/stack/STM32F3/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for ST STM32F334 microcontroller. * - * @file CO_driver_target.h + * @file CO_driver.h * @author Janez Paternoster * @author Ondrej Netik * @author Vijayendra @@ -113,12 +113,30 @@ #define INAK_TIMEOUT ((uint32_t)0x0000FFFF) /* Data types */ -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; - + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; + +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; /* CAN receive message structure as aligned in CAN module. * prevzato z stm32f10_can.h - velikostne polozky a poradi odpovidaji. */ @@ -171,9 +189,62 @@ typedef struct{ void *em; }CO_CANmodule_t; +/* Exported variables -----------------------------------------------------------*/ + +/* Exported functions -----------------------------------------------------------*/ + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + +/* Initialize CAN module object. */ +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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + int8_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + int8_t rtr, + uint8_t noOfBytes, + int8_t syncFlag); + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + /* CAN interrupts receives and transmits CAN messages. */ void CO_CANinterrupt_Rx(CO_CANmodule_t *CANmodule); void CO_CANinterrupt_Tx(CO_CANmodule_t *CANmodule); -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/drvTemplate/CO_driver_target.h b/stack/drvTemplate/CO_driver.h similarity index 58% rename from stack/drvTemplate/CO_driver_target.h rename to stack/drvTemplate/CO_driver.h index 9d40a74d..9d3b9417 100644 --- a/stack/drvTemplate/CO_driver_target.h +++ b/stack/drvTemplate/CO_driver.h @@ -3,7 +3,7 @@ * * This file is a template for other microcontrollers. * - * @file CO_driver_target.h + * @file CO_driver.h * @ingroup CO_driver * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster @@ -26,8 +26,8 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H #ifdef __cplusplus extern "C" { @@ -39,15 +39,6 @@ extern "C" { #include /* for 'true', 'false' */ -/** - * Endianness. - * - * Depending on processor or compiler architecture, one of the two macros must - * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little endian. - */ -#define CO_LITTLE_ENDIAN - - /** * @defgroup CO_driver Driver * @ingroup CO_CANopen @@ -159,14 +150,14 @@ extern "C" { * CO_SYNC_initCallback() function. * @{ */ -#define CO_LOCK_CAN_SEND() /**< Lock critical section in CO_CANsend() */ -#define CO_UNLOCK_CAN_SEND()/**< Unlock critical section in CO_CANsend() */ + #define CO_LOCK_CAN_SEND() /**< Lock critical section in CO_CANsend() */ + #define CO_UNLOCK_CAN_SEND()/**< Unlock critical section in CO_CANsend() */ -#define CO_LOCK_EMCY() /**< Lock critical section in CO_errorReport() or CO_errorReset() */ -#define CO_UNLOCK_EMCY() /**< Unlock critical section in CO_errorReport() or CO_errorReset() */ + #define CO_LOCK_EMCY() /**< Lock critical section in CO_errorReport() or CO_errorReset() */ + #define CO_UNLOCK_EMCY() /**< Unlock critical section in CO_errorReport() or CO_errorReset() */ -#define CO_LOCK_OD() /**< Lock critical section when accessing Object Dictionary */ -#define CO_UNLOCK_OD() /**< Unock critical section when accessing Object Dictionary */ + #define CO_LOCK_OD() /**< Lock critical section when accessing Object Dictionary */ + #define CO_UNLOCK_OD() /**< Unock critical section when accessing Object Dictionary */ /** @} */ /** @@ -199,16 +190,39 @@ extern "C" { * * According to Misra C */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; /**< bool_t */ -typedef float float32_t; /**< float32_t */ -typedef long double float64_t; /**< float64_t */ -typedef char char_t; /**< char_t */ -typedef unsigned char oChar_t; /**< oChar_t */ -typedef unsigned char domain_t; /**< domain_t */ + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; /**< bool_t */ + typedef float float32_t; /**< float32_t */ + typedef long double float64_t; /**< float64_t */ + typedef char char_t; /**< char_t */ + typedef unsigned char oChar_t; /**< oChar_t */ + typedef unsigned char domain_t; /**< domain_t */ /** @} */ +/** + * Return values of some CANopen functions. If function was executed + * successfully it returns 0 otherwise it returns <0. + */ +typedef enum{ + CO_ERROR_NO = 0, /**< Operation completed successfully */ + CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ + CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ + CO_ERROR_TIMEOUT = -3, /**< Function timeout */ + CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function CO_CANmodule_init() */ + CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed yet */ + CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ + CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ + CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ + CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, buffer full */ + CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ + CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not confugured properly */ + CO_ERROR_PARAMETERS = -12, /**< Error in function function parameters */ + CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ + CO_ERROR_CRC = -14 /**< CRC does not match */ +}CO_ReturnError_t; + + /** * CAN receive message structure as aligned in CAN module. It is different in * different microcontrollers. It usually contains other variables. @@ -274,6 +288,175 @@ typedef struct{ }CO_CANmodule_t; +/** + * Endianness. + * + * Depending on processor or compiler architecture, one of the two macros must + * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little endian. + */ +#define CO_LITTLE_ENDIAN + + +/** + * Request CAN configuration (stopped) mode and *wait* untill it is set. + * + * @param CANdriverState User-provided CAN module structure. + */ +void CO_CANsetConfigurationMode(void *CANdriverState); + + +/** + * Request CAN normal (opearational) mode and *wait* untill it is set. + * + * @param CANmodule This object. + */ +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/** + * 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 User-provided CAN module structure.. + * @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 Valid values are (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. + * If value is illegal, bitrate defaults to 125. + * + * Return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + */ +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); + + +/** + * Switch off CANmodule. 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, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/** + * 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 This flag bit is used for synchronous TPDO messages. If it is set, + * message will not be sent, if curent time is outside synchronous window. + * + * @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, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/** + * 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); + + +/** + * Clear all synchronous TPDOs from CAN module transmit buffers. + * + * CANopen allows synchronous PDO communication only inside time between SYNC + * message and SYNC Window. If time is outside this window, new synchronous PDOs + * must not be sent and all pending sync TPDOs, which may be on CAN TX buffers, + * must be cleared. + * + * This function checks (and aborts transmission if necessary) CAN TX buffers + * when it is called. Function should be called by the stack in the moment, + * when SYNC time was just passed out of synchronous window. + * + * @param CANmodule This object. + */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/** + * Verify all errors of CAN module. + * + * Function is called directly from CO_EM_process() function. + * + * @param CANmodule This object. + */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /** * Receives and transmits CAN messages. * @@ -285,7 +468,7 @@ void CO_CANinterrupt(CO_CANmodule_t *CANmodule); #ifdef __cplusplus } -#endif /* __cplusplus */ +#endif /*__cplusplus*/ /** @} */ -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/dsPIC30F/CO_driver_target.h b/stack/dsPIC30F/CO_driver.h similarity index 81% rename from stack/dsPIC30F/CO_driver_target.h rename to stack/dsPIC30F/CO_driver.h index af8c8aec..3677fedd 100644 --- a/stack/dsPIC30F/CO_driver_target.h +++ b/stack/dsPIC30F/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for Microchip dsPIC30F microcontroller. * - * @file CO_driver_target.h + * @file CO_driver.h * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * @@ -23,8 +23,11 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H + + +/* For documentation see file drvTemplate/CO_driver.h */ #include /* processor header file */ @@ -32,34 +35,31 @@ #include /* for 'int8_t' to 'uint64_t' */ #include /* for true and false */ -/* Endianness */ -#define CO_LITTLE_ENDIAN - /* CAN module base address */ -#define ADDR_CAN1 0x300 -#define ADDR_CAN2 0x3C0 + #define ADDR_CAN1 0x300 + #define ADDR_CAN2 0x3C0 /* Critical sections */ -#define CO_LOCK_CAN_SEND() asm volatile ("disi #0x3FFF") -#define CO_UNLOCK_CAN_SEND() asm volatile ("disi #0x0000") + #define CO_LOCK_CAN_SEND() asm volatile ("disi #0x3FFF") + #define CO_UNLOCK_CAN_SEND() asm volatile ("disi #0x0000") -#define CO_LOCK_EMCY() asm volatile ("disi #0x3FFF") -#define CO_UNLOCK_EMCY() asm volatile ("disi #0x0000") + #define CO_LOCK_EMCY() asm volatile ("disi #0x3FFF") + #define CO_UNLOCK_EMCY() asm volatile ("disi #0x0000") -#define CO_LOCK_OD() asm volatile ("disi #0x3FFF") -#define CO_UNLOCK_OD() asm volatile ("disi #0x0000") + #define CO_LOCK_OD() asm volatile ("disi #0x3FFF") + #define CO_UNLOCK_OD() asm volatile ("disi #0x0000") /* Data types */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; /* CAN bit rates @@ -311,6 +311,26 @@ typedef struct{ }CO_CANbitRateData_t; +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; + + /* CAN receive message structure as aligned in CAN module. */ typedef struct{ uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: @@ -360,6 +380,67 @@ typedef struct{ }CO_CANmodule_t; +/* Endianes */ +#define CO_LITTLE_ENDIAN + + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. */ +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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* CAN interrupt receives and transmits CAN messages. * * Function must be called directly from _C1Interrupt or _C2Interrupt with @@ -368,4 +449,4 @@ typedef struct{ void CO_CANinterrupt(CO_CANmodule_t *CANmodule); -#endif /* CO_DRIVER_TARGET_H */ +#endif diff --git a/stack/eCos/CO_driver_target.h b/stack/eCos/CO_driver.h similarity index 59% rename from stack/eCos/CO_driver_target.h rename to stack/eCos/CO_driver.h index 0d19932b..0553e337 100644 --- a/stack/eCos/CO_driver_target.h +++ b/stack/eCos/CO_driver.h @@ -1,7 +1,7 @@ /* * CAN module object for eCos RTOS CAN layer * - * @file CO_driver_target.h + * @file CO_driver.h * @author Uwe Kindler * @copyright 2013 Uwe Kindler * @@ -43,8 +43,8 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H /* For documentation see file drvTemplate/CO_driver.h */ @@ -58,10 +58,6 @@ #include #include -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ //=========================================================================== // CONFIGURATION @@ -90,40 +86,60 @@ extern "C" /* CAN module base address */ // we don't really care about the addresses here because the eCos port // uses I/O handles for accessing its CAN devices -#define ADDR_CAN1 0 -#define ADDR_CAN2 1 + #define ADDR_CAN1 0 + #define ADDR_CAN2 1 /* Critical sections */ // shared data is accessed only from thread level code (not from ISR or DSR) // so we simply do a scheduler lock here to prevent access from different // threads -#define CO_LOCK_CAN_SEND() cyg_scheduler_lock() -#define CO_UNLOCK_CAN_SEND() cyg_scheduler_unlock() + #define CO_LOCK_CAN_SEND() cyg_scheduler_lock() + #define CO_UNLOCK_CAN_SEND() cyg_scheduler_unlock() -#define CO_LOCK_EMCY() cyg_scheduler_lock() -#define CO_UNLOCK_EMCY() cyg_scheduler_unlock() + #define CO_LOCK_EMCY() cyg_scheduler_lock() + #define CO_UNLOCK_EMCY() cyg_scheduler_unlock() -#define CO_LOCK_OD() cyg_scheduler_lock() -#define CO_UNLOCK_OD() cyg_scheduler_unlock() + #define CO_LOCK_OD() cyg_scheduler_lock() + #define CO_UNLOCK_OD() cyg_scheduler_unlock() /* Data types */ -typedef unsigned char bool_t; -typedef cyg_uint8 uint8_t; -typedef cyg_uint16 uint16_t; -typedef cyg_uint32 uint32_t; -typedef cyg_uint64 uint64_t; -typedef cyg_int8 int8_t; -typedef cyg_int16 int16_t; -typedef cyg_int32 int32_t; -typedef cyg_int64 int64_t; -typedef float float32_t; -typedef long double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + typedef unsigned char bool_t; + typedef cyg_uint8 uint8_t; + typedef cyg_uint16 uint16_t; + typedef cyg_uint32 uint32_t; + typedef cyg_uint64 uint64_t; + typedef cyg_int8 int8_t; + typedef cyg_int16 int16_t; + typedef cyg_int32 int32_t; + typedef cyg_int64 int64_t; + typedef float float32_t; + typedef long double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; + + +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; /* CAN receive message structure as aligned in CAN module. */ @@ -173,7 +189,69 @@ typedef struct{ cyg_io_handle_t ioHandle; }CO_CANmodule_t; +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. */ +int16_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); + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +int16_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + uint8_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint8_t rtr, + uint8_t noOfBytes, + uint8_t syncFlag); + + +/* Send CAN message. */ +int16_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + #ifdef __cplusplus } //extern "C" -#endif /* __cplusplus */ -#endif /* CO_DRIVER_TARGET_H */ +#endif +#endif diff --git a/stack/neuberger-socketCAN/CO_driver.c b/stack/neuberger-socketCAN/CO_driver.c index 8cd13fd3..46dee7af 100644 --- a/stack/neuberger-socketCAN/CO_driver.c +++ b/stack/neuberger-socketCAN/CO_driver.c @@ -498,9 +498,9 @@ uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg) /******************************************************************************/ CO_ReturnError_t CO_CANrxBufferInit( CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, + uint32_t index, + uint32_t ident, + uint32_t mask, bool_t rtr, void *object, void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) @@ -508,7 +508,7 @@ CO_ReturnError_t CO_CANrxBufferInit( CO_ReturnError_t ret = CO_ERROR_NO; if((CANmodule!=NULL) && (index < CANmodule->rxSize)){ - uint16_t i; + uint32_t i; CO_CANrx_t *buffer; /* check if COB ID is already used */ @@ -599,8 +599,8 @@ bool_t CO_CANrxBuffer_getInterface( /******************************************************************************/ CO_CANtx_t *CO_CANtxBufferInit( CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, + uint32_t index, + uint32_t ident, bool_t rtr, uint8_t noOfBytes, bool_t syncFlag) diff --git a/stack/neuberger-socketCAN/CO_driver_target.h b/stack/neuberger-socketCAN/CO_driver.h similarity index 80% rename from stack/neuberger-socketCAN/CO_driver_target.h rename to stack/neuberger-socketCAN/CO_driver.h index 7a5ffcc8..97aaeb5b 100644 --- a/stack/neuberger-socketCAN/CO_driver_target.h +++ b/stack/neuberger-socketCAN/CO_driver.h @@ -3,7 +3,7 @@ * * This file is a template for other microcontrollers. * - * @file CO_driver_target.h + * @file CO_driver.h * @ingroup CO_driver * @author Janez Paternoster, Martin Wagner * @copyright 2004 - 2015 Janez Paternoster, 2017 Neuberger Gebaeudeautomation GmbH @@ -47,12 +47,12 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ +#endif /** @@ -87,7 +87,7 @@ extern "C" { #ifdef CO_DRIVER_ERROR_REPORTING #include "CO_error.h" -#endif /* CO_DRIVER_ERROR_REPORTING */ +#endif /** * socketCAN interface object @@ -125,9 +125,24 @@ typedef struct{ */ 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_DRIVER_MULTI_INTERFACE */ +#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 /** @@ -164,7 +179,7 @@ typedef struct{ * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or * CO_ERROR_SYSCALL. */ -#endif /* CO_DRIVER_MULTI_INTERFACE */ +#endif CO_ReturnError_t CO_CANmodule_init( CO_CANmodule_t *CANmodule, void *CANdriverState, @@ -190,7 +205,23 @@ CO_ReturnError_t CO_CANmodule_addInterface( CO_CANmodule_t *CANmodule, void *CANdriverState); -#endif /* CO_DRIVER_MULTI_INTERFACE */ +#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); /** @@ -218,9 +249,9 @@ CO_ReturnError_t CO_CANmodule_addInterface( */ CO_ReturnError_t CO_CANrxBufferInit( CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, + uint32_t index, + uint32_t ident, + uint32_t mask, bool_t rtr, void *object, void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); @@ -244,10 +275,39 @@ CO_ReturnError_t CO_CANrxBufferInit( */ bool_t CO_CANrxBuffer_getInterface( CO_CANmodule_t *CANmodule, - uint16_t ident, + 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 * @@ -265,11 +325,22 @@ bool_t CO_CANrxBuffer_getInterface( */ CO_ReturnError_t CO_CANtxBuffer_setInterface( CO_CANmodule_t *CANmodule, - uint16_t ident, + uint32_t ident, void *CANdriverStateTx); -#endif /* CO_DRIVER_MULTI_INTERFACE */ +#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 @@ -288,6 +359,20 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface( */ 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. @@ -310,7 +395,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff #ifdef __cplusplus } -#endif /* __cplusplus */ +#endif /*__cplusplus*/ /** @} */ #endif diff --git a/stack/neuberger-socketCAN/CO_driver_base.h b/stack/neuberger-socketCAN/CO_driver_base.h index 29d19736..89bf53a8 100644 --- a/stack/neuberger-socketCAN/CO_driver_base.h +++ b/stack/neuberger-socketCAN/CO_driver_base.h @@ -1,7 +1,7 @@ /** * CAN module object for Linux socketCAN. * - * @file CO_driver_target.h + * @file CO_driver_base.h * @ingroup CO_driver * @author Janez Paternoster, Martin Wagner * @copyright 2004 - 2015 Janez Paternoster, 2018 Neuberger Gebaeudeautomation GmbH @@ -57,25 +57,9 @@ #include #include -#include "CO_types.h" - #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ - -/** - * Endianness. - * - * Depending on processor or compiler architecture, one of the two macros must - * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little endian. - */ -#ifdef __BYTE_ORDER -#if __BYTE_ORDER == __LITTLE_ENDIAN - #define CO_LITTLE_ENDIAN -#else - #define CO_BIG_ENDIAN -#endif /* __BYTE_ORDER == __LITTLE_ENDIAN */ -#endif /* __BYTE_ORDER */ +#endif /** * @defgroup CO_driver Driver @@ -233,16 +217,43 @@ static inline void CO_UNLOCK_OD() { (void)pthread_mutex_unlock(&CO_OD_mutex); * * According to Misra C */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; /**< bool_t */ -typedef float float32_t; /**< float32_t */ -typedef long double float64_t; /**< float64_t */ -typedef char char_t; /**< char_t */ -typedef unsigned char oChar_t; /**< oChar_t */ -typedef unsigned char domain_t; /**< domain_t */ + /* int8_t to uint64_t are defined in stdint.h */ + typedef unsigned char bool_t; /**< bool_t */ + typedef float float32_t; /**< float32_t */ + typedef long double float64_t; /**< float64_t */ + typedef char char_t; /**< char_t */ + typedef unsigned char oChar_t; /**< oChar_t */ + typedef unsigned char domain_t; /**< domain_t */ /** @} */ +/** + * Return values of some CANopen functions. If function was executed + * successfully it returns 0 otherwise it returns <0. + */ +typedef enum{ + CO_ERROR_NO = 0, /**< Operation completed successfully */ + CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ + CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ + CO_ERROR_TIMEOUT = -3, /**< Function timeout */ + CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function CO_CANmodule_init() */ + CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed yet */ + CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ + CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ + CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ + CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, buffer full */ + CO_ERROR_TX_BUSY = -10, /**< Sending rejected because driver is busy. Try again */ + CO_ERROR_TX_PDO_WINDOW = -11, /**< Synchronous TPDO is outside window */ + CO_ERROR_TX_UNCONFIGURED = -12, /**< Transmit buffer was not confugured properly */ + CO_ERROR_PARAMETERS = -13, /**< Error in function function parameters */ + CO_ERROR_DATA_CORRUPT = -14, /**< Stored data are corrupt */ + CO_ERROR_CRC = -15, /**< CRC does not match */ + CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current state */ + CO_ERROR_SYSCALL = -17, /**< Syscall failed */ + CO_ERROR_INVALID_STATE = -18 /**< Driver not ready */ +}CO_ReturnError_t; + + /** * Max COB ID for standard frame format */ @@ -293,9 +304,23 @@ typedef struct{ void *CANdriverState; /**< CAN Interface identifier to use */ } CO_CANtx_t; +/** + * Endianess. + * + * Depending on processor or compiler architecture, one of the two macros must + * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little endian. + */ +#ifdef __BYTE_ORDER +#if __BYTE_ORDER == __LITTLE_ENDIAN + #define CO_LITTLE_ENDIAN +#else + #define CO_BIG_ENDIAN +#endif +#endif + #ifdef __cplusplus } -#endif /* __cplusplus */ +#endif /*__cplusplus*/ /** @} */ #endif diff --git a/stack/socketCAN/CO_driver_target.h b/stack/socketCAN/CO_driver.h similarity index 60% rename from stack/socketCAN/CO_driver_target.h rename to stack/socketCAN/CO_driver.h index bb816967..f6b6fe30 100644 --- a/stack/socketCAN/CO_driver_target.h +++ b/stack/socketCAN/CO_driver.h @@ -23,8 +23,8 @@ */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H +#ifndef CO_DRIVER_H +#define CO_DRIVER_H /* For documentation see file drvTemplate/CO_driver.h */ @@ -45,16 +45,6 @@ #include -/* Endianness */ -#ifdef BYTE_ORDER -#if BYTE_ORDER == LITTLE_ENDIAN - #define CO_LITTLE_ENDIAN -#else - #define CO_BIG_ENDIAN -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -#endif /* BYTE_ORDER */ - - /* general configuration */ // #define CO_LOG_CAN_MESSAGES /* Call external function for each received or transmitted CAN message. */ #define CO_SDO_BUFFER_SIZE 889 /* Override default SDO buffer size. */ @@ -85,7 +75,7 @@ #define CO_UNLOCK_OD() {if(pthread_mutex_unlock(&CO_OD_mtx) != 0) CO_errExit("Mutex unlock CO_OD_mtx failed");} #define CANrxMemoryBarrier() {__sync_synchronize();} -#endif /* CO_SINGLE_THREAD */ +#endif /* Syncronisation functions */ #define IS_CANrxNew(rxNew) ((uintptr_t)rxNew) @@ -94,13 +84,33 @@ /* Data types */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef _Bool bool_t; -typedef float float32_t; -typedef double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; + /* int8_t to uint64_t are defined in stdint.h */ + typedef _Bool bool_t; + typedef float float32_t; + typedef double float64_t; + typedef char char_t; + typedef unsigned char oChar_t; + typedef unsigned char domain_t; + + +/* Return values */ +typedef enum{ + CO_ERROR_NO = 0, + CO_ERROR_ILLEGAL_ARGUMENT = -1, + CO_ERROR_OUT_OF_MEMORY = -2, + CO_ERROR_TIMEOUT = -3, + CO_ERROR_ILLEGAL_BAUDRATE = -4, + CO_ERROR_RX_OVERFLOW = -5, + CO_ERROR_RX_PDO_OVERFLOW = -6, + CO_ERROR_RX_MSG_LENGTH = -7, + CO_ERROR_RX_PDO_LENGTH = -8, + CO_ERROR_TX_OVERFLOW = -9, + CO_ERROR_TX_PDO_WINDOW = -10, + CO_ERROR_TX_UNCONFIGURED = -11, + CO_ERROR_PARAMETERS = -12, + CO_ERROR_DATA_CORRUPT = -13, + CO_ERROR_CRC = -14 +}CO_ReturnError_t; /* CAN receive message structure as aligned in CAN module. */ @@ -153,10 +163,78 @@ typedef struct{ void *em; }CO_CANmodule_t; + +/* Endianes */ +#ifdef BYTE_ORDER +#if BYTE_ORDER == LITTLE_ENDIAN + #define CO_LITTLE_ENDIAN +#else + #define CO_BIG_ENDIAN +#endif +#endif + + /* Helper function, must be defined externally. */ void CO_errExit(char* msg); +/* Request CAN configuration or normal mode */ +void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); + + +/* Initialize CAN module object. */ +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); /* not used */ + + +/* Switch off CANmodule. */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); + + +/* Read CAN identifier */ +uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); + + +/* Configure CAN message receive buffer. */ +CO_ReturnError_t CO_CANrxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); + + +/* Configure CAN message transmit buffer. */ +CO_CANtx_t *CO_CANtxBufferInit( + CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); + + +/* Send CAN message. */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); + + +/* Clear all synchronous TPDOs from CAN module transmit buffers. */ +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); + + +/* Verify all errors of CAN module. */ +void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); + + /* Functions receives CAN messages. It is blocking. * * @param CANmodule This object. @@ -164,4 +242,4 @@ void CO_errExit(char* msg); void CO_CANrxWait(CO_CANmodule_t *CANmodule); -#endif /* CO_DRIVER_TARGET_H */ +#endif From 1459c7d154b5e4d205e7466c5a18fa4946899830 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 14 Jan 2020 16:51:03 +0100 Subject: [PATCH 002/520] Move files from stack/drvTemplate to stack/ and example/. Makefile updated. --- Makefile | 71 ++++++++++++---------- {stack/drvTemplate => example}/CO_driver.c | 0 {stack/drvTemplate => example}/eeprom.c | 0 {stack/drvTemplate => example}/eeprom.h | 0 stack/{drvTemplate => }/CO_driver.h | 6 +- 5 files changed, 43 insertions(+), 34 deletions(-) rename {stack/drvTemplate => example}/CO_driver.c (100%) rename {stack/drvTemplate => example}/eeprom.c (100%) rename {stack/drvTemplate => example}/eeprom.h (100%) rename stack/{drvTemplate => }/CO_driver.h (98%) diff --git a/Makefile b/Makefile index 58b06c86..b7c5e788 100644 --- a/Makefile +++ b/Makefile @@ -1,38 +1,40 @@ # Makefile for CANopenNode, basic compile with no CAN device. -STACKDRV_SRC = stack/drvTemplate -STACK_SRC = stack -CANOPEN_SRC = . -APPL_SRC = example - - -LINK_TARGET = canopennode - - -INCLUDE_DIRS = -I$(STACKDRV_SRC) \ - -I$(STACK_SRC) \ - -I$(CANOPEN_SRC) \ - -I$(APPL_SRC) - - -SOURCES = $(STACKDRV_SRC)/CO_driver.c \ - $(STACKDRV_SRC)/eeprom.c \ - $(STACK_SRC)/crc16-ccitt.c \ - $(STACK_SRC)/CO_SDO.c \ - $(STACK_SRC)/CO_Emergency.c \ - $(STACK_SRC)/CO_NMT_Heartbeat.c \ - $(STACK_SRC)/CO_SYNC.c \ - $(STACK_SRC)/CO_TIME.c \ - $(STACK_SRC)/CO_PDO.c \ - $(STACK_SRC)/CO_HBconsumer.c \ - $(STACK_SRC)/CO_SDOmaster.c \ - $(STACK_SRC)/CO_LSSmaster.c \ - $(STACK_SRC)/CO_LSSslave.c \ - $(STACK_SRC)/CO_trace.c \ - $(CANOPEN_SRC)/CANopen.c \ - $(APPL_SRC)/CO_OD.c \ - $(APPL_SRC)/main.c +DRV_SRC = example +STACK_SRC = stack +CANOPEN_SRC =. +APPL_SRC = example + + +LINK_TARGET = canopennode + + +INCLUDE_DIRS = \ + -I$(DRV_SRC) \ + -I$(STACK_SRC) \ + -I$(CANOPEN_SRC) \ + -I$(APPL_SRC) + + +SOURCES = \ + $(DRV_SRC)/CO_driver.c \ + $(DRV_SRC)/eeprom.c \ + $(STACK_SRC)/crc16-ccitt.c \ + $(STACK_SRC)/CO_SDO.c \ + $(STACK_SRC)/CO_Emergency.c \ + $(STACK_SRC)/CO_NMT_Heartbeat.c \ + $(STACK_SRC)/CO_SYNC.c \ + $(STACK_SRC)/CO_TIME.c \ + $(STACK_SRC)/CO_PDO.c \ + $(STACK_SRC)/CO_HBconsumer.c \ + $(STACK_SRC)/CO_SDOmaster.c \ + $(STACK_SRC)/CO_LSSmaster.c \ + $(STACK_SRC)/CO_LSSslave.c \ + $(STACK_SRC)/CO_trace.c \ + $(CANOPEN_SRC)/CANopen.c \ + $(APPL_SRC)/CO_OD.c \ + $(APPL_SRC)/main.c OBJS = $(SOURCES:%.c=%.o) @@ -41,13 +43,16 @@ CFLAGS = -Wall $(INCLUDE_DIRS) LDFLAGS = -.PHONY: all clean +.PHONY: all clean doc all: clean $(LINK_TARGET) clean: rm -f $(OBJS) $(LINK_TARGET) +doc: + doxygen + %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ diff --git a/stack/drvTemplate/CO_driver.c b/example/CO_driver.c similarity index 100% rename from stack/drvTemplate/CO_driver.c rename to example/CO_driver.c diff --git a/stack/drvTemplate/eeprom.c b/example/eeprom.c similarity index 100% rename from stack/drvTemplate/eeprom.c rename to example/eeprom.c diff --git a/stack/drvTemplate/eeprom.h b/example/eeprom.h similarity index 100% rename from stack/drvTemplate/eeprom.h rename to example/eeprom.h diff --git a/stack/drvTemplate/CO_driver.h b/stack/CO_driver.h similarity index 98% rename from stack/drvTemplate/CO_driver.h rename to stack/CO_driver.h index 9d3b9417..c09615cd 100644 --- a/stack/drvTemplate/CO_driver.h +++ b/stack/CO_driver.h @@ -219,7 +219,11 @@ typedef enum{ CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not confugured properly */ CO_ERROR_PARAMETERS = -12, /**< Error in function function parameters */ CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ - CO_ERROR_CRC = -14 /**< CRC does not match */ + CO_ERROR_CRC = -14, /**< CRC does not match */ + CO_ERROR_TX_BUSY = -15, /**< Sending rejected because driver is busy. Try again */ + CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current state */ + CO_ERROR_SYSCALL = -17, /**< Syscall failed */ + CO_ERROR_INVALID_STATE = -18 /**< Driver not ready */ }CO_ReturnError_t; From 12fa8e51731451dd851041764ad65630d54f4381 Mon Sep 17 00:00:00 2001 From: Janez Date: Sun, 19 Jan 2020 02:06:46 +0100 Subject: [PATCH 003/520] Extract target specific code from CO_driver.h into /example/CO_driver_target.h - Keep example code CO_driver_target.h also in CO_driver.h (for doxygen). - Add extra members into enum CO_ReturnError_t - Move enum CO_Default_CAN_ID_t from CANopen.h into CO_driver.h - Make files in 'stack' directory independent form CANopen.h. CANopen.h file is more part of the application example than the stack. - Second argument to receive callback function is 'void*' instead of 'const CO_CANrxMsg_t*'. New (macros) are introduced: CO_CANrxMsg_readIdent(), CO_CANrxMsg_readDLC() and CO_CANrxMsg_readData() CAN receive functions in all source files are updated. - IS_CANrxNew, SET_CANrxNew and CLEAR_CANrxNew renamed to CO_CANrxNew_READ, CO_CANrxNew_SET and CO_CANrxNew_CLEAR. Replace broken link in doc. - Doxyfile: parameter change 'INPUT = README.md stack'. CANopen.h is excluded and updated. Doxywizard saved file to newer version of doxygen. - Documentation in CO_driver.h is updated. - Full documentation for CO_driver_target.h file is added to CO_driver.h. - used clang-format on the CO_driver.h --- CANopen.h | 113 ++--- Doxyfile | 824 +++++++++++++++++++++---------------- example/CO_driver.c | 24 +- example/CO_driver_target.h | 118 ++++++ example/main.c | 6 +- stack/CO_Emergency.c | 20 +- stack/CO_Emergency.h | 2 +- stack/CO_HBconsumer.c | 21 +- stack/CO_HBconsumer.h | 2 +- stack/CO_LSS.h | 8 +- stack/CO_LSSmaster.c | 76 ++-- stack/CO_LSSmaster.h | 20 +- stack/CO_LSSslave.c | 52 +-- stack/CO_LSSslave.h | 23 +- stack/CO_NMT_Heartbeat.c | 10 +- stack/CO_PDO.c | 68 +-- stack/CO_PDO.h | 3 +- stack/CO_SDO.c | 68 +-- stack/CO_SDOmaster.c | 76 ++-- stack/CO_SYNC.c | 29 +- stack/CO_TIME.c | 21 +- stack/CO_TIME.h | 2 + stack/CO_driver.h | 676 +++++++++++++++++------------- stack/CO_trace.c | 5 - stack/CO_trace.h | 9 +- 25 files changed, 1268 insertions(+), 1008 deletions(-) create mode 100644 example/CO_driver_target.h diff --git a/CANopen.h b/CANopen.h index e3b6d6b4..cb5ecef6 100644 --- a/CANopen.h +++ b/CANopen.h @@ -1,4 +1,4 @@ -/** +/* * Main CANopen stack file. * * It combines Object dictionary (CO_OD) and all other CANopen source files. @@ -38,32 +38,6 @@ extern "C" { #endif -/** - * @defgroup CO_CANopen CANopen stack - * @{ - * - * CANopenNode is free and open source CANopen Stack. - * - * CANopen is the internationally standardized (EN 50325-4) (CiA DS-301) - * CAN-based higher-layer protocol for embedded control system. For more - * information on CANopen see http://www.can-cia.org/ - * - * CANopenNode homepage is https://github.com/CANopenNode/CANopenNode - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - #include "CO_driver.h" #include "CO_OD.h" #include "CO_SDO.h" @@ -86,69 +60,41 @@ extern "C" { #include "CO_LSSmaster.h" #endif -/** - * Default CANopen identifiers. - * - * Default CANopen identifiers for CANopen communication objects. Same as - * 11-bit addresses of CAN messages. These are default identifiers and - * can be changed in CANopen. Especially PDO identifiers are confgured - * in PDO linking phase of the CANopen network configuration. - */ -typedef enum{ - CO_CAN_ID_NMT_SERVICE = 0x000, /**< 0x000, Network management */ - CO_CAN_ID_SYNC = 0x080, /**< 0x080, Synchronous message */ - CO_CAN_ID_EMERGENCY = 0x080, /**< 0x080, Emergency messages (+nodeID) */ - CO_CAN_ID_TIME = 0x100, /**< 0x100, Time message */ - CO_CAN_ID_TPDO_1 = 0x180, /**< 0x180, Default TPDO1 (+nodeID) */ - CO_CAN_ID_RPDO_1 = 0x200, /**< 0x200, Default RPDO1 (+nodeID) */ - CO_CAN_ID_TPDO_2 = 0x280, /**< 0x280, Default TPDO2 (+nodeID) */ - CO_CAN_ID_RPDO_2 = 0x300, /**< 0x300, Default RPDO2 (+nodeID) */ - CO_CAN_ID_TPDO_3 = 0x380, /**< 0x380, Default TPDO3 (+nodeID) */ - CO_CAN_ID_RPDO_3 = 0x400, /**< 0x400, Default RPDO3 (+nodeID) */ - CO_CAN_ID_TPDO_4 = 0x480, /**< 0x480, Default TPDO4 (+nodeID) */ - CO_CAN_ID_RPDO_4 = 0x500, /**< 0x500, Default RPDO5 (+nodeID) */ - CO_CAN_ID_TSDO = 0x580, /**< 0x580, SDO response from server (+nodeID) */ - CO_CAN_ID_RSDO = 0x600, /**< 0x600, SDO request from client (+nodeID) */ - CO_CAN_ID_HEARTBEAT = 0x700, /**< 0x700, Heartbeat message */ - CO_CAN_ID_LSS_CLI = 0x7E4, /**< 0x7E4, LSS response from server to client */ - CO_CAN_ID_LSS_SRV = 0x7E5 /**< 0x7E5, LSS request from client to server */ -}CO_Default_CAN_ID_t; - -/** +/* * CANopen stack object combines pointers to all CANopen objects. */ typedef struct{ - CO_CANmodule_t *CANmodule[1]; /**< CAN module objects */ - CO_SDO_t *SDO[CO_NO_SDO_SERVER]; /**< SDO object */ - CO_EM_t *em; /**< Emergency report object */ - CO_EMpr_t *emPr; /**< Emergency process object */ - CO_NMT_t *NMT; /**< NMT object */ - CO_SYNC_t *SYNC; /**< SYNC object */ - CO_TIME_t *TIME; /**< TIME object */ - CO_RPDO_t *RPDO[CO_NO_RPDO];/**< RPDO objects */ - CO_TPDO_t *TPDO[CO_NO_TPDO];/**< TPDO objects */ - CO_HBconsumer_t *HBcons; /**< Heartbeat consumer object*/ + CO_CANmodule_t *CANmodule[1]; /* CAN module objects */ + CO_SDO_t *SDO[CO_NO_SDO_SERVER]; /* SDO object */ + CO_EM_t *em; /* Emergency report object */ + CO_EMpr_t *emPr; /* Emergency process object */ + CO_NMT_t *NMT; /* NMT object */ + CO_SYNC_t *SYNC; /* SYNC object */ + CO_TIME_t *TIME; /* TIME object */ + CO_RPDO_t *RPDO[CO_NO_RPDO];/* RPDO objects */ + CO_TPDO_t *TPDO[CO_NO_TPDO];/* TPDO objects */ + CO_HBconsumer_t *HBcons; /* Heartbeat consumer object*/ #if CO_NO_LSS_SERVER == 1 - CO_LSSslave_t *LSSslave; /**< LSS server/slave object */ + CO_LSSslave_t *LSSslave; /* LSS server/slave object */ #endif #if CO_NO_LSS_CLIENT == 1 - CO_LSSmaster_t *LSSmaster; /**< LSS master/client object */ + CO_LSSmaster_t *LSSmaster; /* LSS master/client object */ #endif #if CO_NO_SDO_CLIENT != 0 - CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */ + CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /* SDO client object */ #endif #if CO_NO_TRACE > 0 - CO_trace_t *trace[CO_NO_TRACE]; /**< Trace object for monitoring variables */ + CO_trace_t *trace[CO_NO_TRACE]; /* Trace object for monitoring variables */ #endif }CO_t; -/** CANopen object */ +/* CANopen object */ extern CO_t *CO; -/** +/* * Function CO_sendNMTcommand() is simple function, which sends CANopen message. * This part of code is an example of custom definition of simple CANopen * object. Follow the code in CANopen.c file. If macro CO_NO_NMT_MASTER is 1, @@ -167,7 +113,7 @@ typedef struct{ #if CO_NO_LSS_SERVER == 1 -/** +/* * Allocate and initialize memory for CANopen object * * Function must be called in the communication reset section. @@ -178,7 +124,7 @@ typedef struct{ CO_ReturnError_t CO_new(void); -/** +/* * Initialize CAN driver * * Function must be called in the communication reset section. @@ -193,7 +139,7 @@ CO_ReturnError_t CO_CANinit( uint16_t bitRate); -/** +/* * Initialize CANopen LSS slave * * Function must be called in the communication reset section. @@ -207,7 +153,7 @@ CO_ReturnError_t CO_LSSinit( uint16_t bitRate); -/** +/* * Initialize CANopen stack. * * Function must be called in the communication reset section. @@ -220,7 +166,7 @@ CO_ReturnError_t CO_CANopenInit( #else /* CO_NO_LSS_SERVER == 1 */ -/** +/* * Initialize CANopen stack. * * Function must be called in the communication reset section. @@ -240,7 +186,7 @@ CO_ReturnError_t CO_init( #endif /* CO_NO_LSS_SERVER == 1 */ -/** +/* * Delete CANopen object and free memory. Must be called at program exit. * * @param CANdriverState Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). @@ -248,7 +194,7 @@ CO_ReturnError_t CO_init( void CO_delete(void *CANdriverState); -/** +/* * Process CANopen objects. * * Function must be called cyclically. It processes all "asynchronous" CANopen @@ -272,7 +218,7 @@ CO_NMT_reset_cmd_t CO_process( #if CO_NO_SYNC == 1 -/** +/* * Process CANopen SYNC objects. * * Function must be called cyclically from real time thread with constant @@ -288,7 +234,7 @@ bool_t CO_process_SYNC( uint32_t timeDifference_us); #endif -/** +/* * Process CANopen RPDO objects. * * Function must be called cyclically from real time thread with constant. @@ -301,7 +247,7 @@ void CO_process_RPDO( CO_t *CO, bool_t syncWas); -/** +/* * Process CANopen TPDO objects. * * Function must be called cyclically from real time thread with constant. @@ -320,5 +266,4 @@ void CO_process_TPDO( } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /*CANopen_H*/ diff --git a/Doxyfile b/Doxyfile index 996c1b23..369ec70a 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.8 +# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -24,7 +24,7 @@ # for the list of possible encodings. # The default value is: UTF-8. -DOXYFILE_ENCODING = UTF-8 +DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the @@ -32,35 +32,35 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = CANopenNode +PROJECT_NAME = CANopenNode # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doc +OUTPUT_DIRECTORY = doc -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where @@ -68,7 +68,7 @@ OUTPUT_DIRECTORY = doc # performance problems for the file system. # The default value is: NO. -CREATE_SUBDIRS = NO +CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII @@ -76,7 +76,7 @@ CREATE_SUBDIRS = NO # U+3044. # The default value is: NO. -ALLOW_UNICODE_NAMES = NO +ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this @@ -91,23 +91,23 @@ ALLOW_UNICODE_NAMES = NO # Ukrainian and Vietnamese. # The default value is: English. -OUTPUT_LANGUAGE = English +OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. -BRIEF_MEMBER_DESC = YES +BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. -REPEAT_BRIEF = YES +REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found @@ -118,14 +118,14 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. -ALWAYS_DETAILED_SEC = NO +ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those @@ -133,14 +133,14 @@ ALWAYS_DETAILED_SEC = NO # operators of the base classes will not be shown. # The default value is: NO. -INLINE_INHERITED_MEMB = NO +INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = YES +FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -152,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -161,14 +161,14 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. -SHORT_NAMES = NO +SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief @@ -177,7 +177,7 @@ SHORT_NAMES = NO # description.) # The default value is: NO. -JAVADOC_AUTOBRIEF = YES +JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If @@ -185,7 +185,7 @@ JAVADOC_AUTOBRIEF = YES # requiring an explicit \brief command for a brief description.) # The default value is: NO. -QT_AUTOBRIEF = NO +QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as @@ -203,20 +203,20 @@ MULTILINE_CPP_IS_BRIEF = NO # documentation from any documented member that it re-implements. # The default value is: YES. -INHERIT_DOCS = YES +INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. # The default value is: NO. -SEPARATE_MEMBER_PAGES = NO +SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. -TAB_SIZE = 4 +TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: @@ -228,13 +228,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. -TCL_SUBST = +TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -242,7 +242,7 @@ TCL_SUBST = # members will be omitted, etc. # The default value is: NO. -OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored @@ -250,19 +250,19 @@ OPTIMIZE_OUTPUT_FOR_C = YES # qualified scopes will look different, etc. # The default value is: NO. -OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. -OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. -OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given @@ -276,12 +276,12 @@ OPTIMIZE_OUTPUT_VHDL = NO # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # -# Note For files without extension you can use no_extension as a placeholder. +# Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -291,15 +291,24 @@ EXTENSION_MAPPING = # case of backward compatibilities issues. # The default value is: YES. -MARKDOWN_SUPPORT = YES +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. -AUTOLINK_SUPPORT = YES +AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this @@ -309,13 +318,13 @@ AUTOLINK_SUPPORT = YES # diagrams that involve STL classes more complete and accurate. # The default value is: NO. -BUILTIN_STL_SUPPORT = NO +BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. -CPP_CLI_SUPPORT = NO +CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen @@ -323,7 +332,7 @@ CPP_CLI_SUPPORT = NO # of private inheritance when no explicit protection keyword is present. # The default value is: NO. -SIP_SUPPORT = NO +SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make @@ -333,15 +342,22 @@ SIP_SUPPORT = NO # should set this option to NO. # The default value is: YES. -IDL_PROPERTY_SUPPORT = YES +IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first +# tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. -DISTRIBUTE_GROUP_DOC = YES +DISTRIBUTE_GROUP_DOC = YES + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that @@ -350,7 +366,7 @@ DISTRIBUTE_GROUP_DOC = YES # \nosubgrouping command. # The default value is: YES. -SUBGROUPING = YES +SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) @@ -371,7 +387,7 @@ INLINE_GROUPED_CLASSES = NO # Man pages) or section (for LaTeX and RTF). # The default value is: NO. -INLINE_SIMPLE_STRUCTS = NO +INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So @@ -382,7 +398,7 @@ INLINE_SIMPLE_STRUCTS = NO # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. -TYPEDEF_HIDES_STRUCT = NO +TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be @@ -395,13 +411,13 @@ TYPEDEF_HIDES_STRUCT = NO # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. -LOOKUP_CACHE_SIZE = 0 +LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -409,41 +425,41 @@ LOOKUP_CACHE_SIZE = 0 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = NO +EXTRACT_ALL = NO -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. -EXTRACT_PRIVATE = NO +EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. -EXTRACT_PACKAGE = NO +EXTRACT_PACKAGE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = NO +EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are +# included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. -EXTRACT_LOCAL_METHODS = NO +EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called @@ -452,7 +468,7 @@ EXTRACT_LOCAL_METHODS = NO # are hidden. # The default value is: NO. -EXTRACT_ANON_NSPACES = NO +EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these @@ -460,92 +476,99 @@ EXTRACT_ANON_NSPACES = NO # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. -HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. # The default value is: NO. -HIDE_UNDOC_CLASSES = YES +HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be +# (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. -HIDE_FRIEND_COMPOUNDS = NO +HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these +# documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. -HIDE_IN_BODY_DOCS = NO +HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. -INTERNAL_DOCS = NO +INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also +# names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. -CASE_SENSE_NAMES = YES +CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the +# their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. -HIDE_SCOPE_NAMES = NO +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. -SHOW_INCLUDE_FILES = YES +SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. -SHOW_GROUPED_MEMB_INC = NO +SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. -FORCE_LOCAL_INCLUDES = NO +FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. -INLINE_INFO = YES +INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. -SORT_MEMBER_DOCS = YES +SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that +# name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. -SORT_BRIEF_DOCS = NO +SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and @@ -564,7 +587,7 @@ SORT_MEMBERS_CTORS_1ST = NO # appear in their defined order. # The default value is: NO. -SORT_GROUP_NAMES = NO +SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will @@ -574,7 +597,7 @@ SORT_GROUP_NAMES = NO # list. # The default value is: NO. -SORT_BY_SCOPE_NAME = NO +SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between @@ -584,40 +607,38 @@ SORT_BY_SCOPE_NAME = NO # accept a match between prototype and implementation in such cases. # The default value is: NO. -STRICT_PROTO_MATCHING = NO +STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. # The default value is: YES. -GENERATE_TODOLIST = YES +GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. # The default value is: YES. -GENERATE_TESTLIST = YES +GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. -GENERATE_BUGLIST = YES +GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. -GENERATE_DEPRECATEDLIST = YES +GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -628,28 +649,28 @@ ENABLED_SECTIONS = # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. -MAX_INITIALIZER_LINES = 30 +MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. # The default value is: YES. -SHOW_USED_FILES = YES +SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. -SHOW_FILES = YES +SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. -SHOW_NAMESPACES = YES +SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from @@ -659,7 +680,7 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated @@ -672,7 +693,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -682,7 +703,7 @@ LAYOUT_FILE = # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -693,23 +714,23 @@ CITE_BIB_FILES = # messages are off. # The default value is: NO. -QUIET = NO +QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. -WARNINGS = YES +WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. -WARN_IF_UNDOCUMENTED = YES +WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters @@ -717,15 +738,21 @@ WARN_IF_UNDOCUMENTED = YES # markup commands wrongly. # The default value is: YES. -WARN_IF_DOC_ERROR = YES +WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. # The default value is: NO. -WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which @@ -735,13 +762,13 @@ WARN_NO_PARAMDOC = NO # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. -WARN_FORMAT = "$file:$line: $text" +WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -750,10 +777,11 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = . stack stack/drvTemplate +INPUT = README.md \ + stack # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -762,24 +790,29 @@ INPUT = . stack stack/drvTemplate # possible encodings. # The default value is: UTF-8. -INPUT_ENCODING = UTF-8 +INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. -FILE_PATTERNS = +FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. -RECURSIVE = NO +RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a @@ -788,14 +821,14 @@ RECURSIVE = NO # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. -EXCLUDE_SYMLINKS = NO +EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude @@ -804,7 +837,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -815,33 +848,33 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. -EXAMPLE_RECURSIVE = NO +EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -857,8 +890,12 @@ IMAGE_PATH = # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -866,15 +903,19 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for +# INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. -FILTER_SOURCE_FILES = NO +FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and @@ -902,20 +943,20 @@ USE_MDFILE_AS_MAINPAGE = # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = NO +SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. -INLINE_SOURCES = NO +INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. -STRIP_CODE_COMMENTS = YES +STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. @@ -927,10 +968,10 @@ REFERENCED_BY_RELATION = NO # all documented entities called/used by that function will be listed. # The default value is: NO. -REFERENCES_RELATION = NO +REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. @@ -945,7 +986,7 @@ REFERENCES_LINK_SOURCE = YES # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. -SOURCE_TOOLTIPS = YES +SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in @@ -967,7 +1008,7 @@ SOURCE_TOOLTIPS = YES # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. -USE_HTAGS = NO +USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is @@ -975,15 +1016,15 @@ USE_HTAGS = NO # See also: Section \class. # The default value is: YES. -VERBATIM_HEADERS = YES +VERBATIM_HEADERS = YES -# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the # cost of reduced performance. This can be particularly helpful with template # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was -# compiled with the --with-libclang option. +# generated with the -Duse-libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO @@ -994,7 +1035,7 @@ CLANG_ASSISTED_PARSING = NO # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. -CLANG_OPTIONS = +CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index @@ -1005,14 +1046,14 @@ CLANG_OPTIONS = # classes, structs, unions or interfaces. # The default value is: YES. -ALPHABETICAL_INDEX = YES +ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -COLS_IN_ALPHA_INDEX = 5 +COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag @@ -1020,16 +1061,16 @@ COLS_IN_ALPHA_INDEX = 5 # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = YES +GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1037,14 +1078,14 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = html +HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FILE_EXTENSION = .html +HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a @@ -1064,7 +1105,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1074,7 +1115,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1086,20 +1127,20 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. +# standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. -# Note: The order of the extra stylesheet files is of importance (e.g. the last -# stylesheet in the list overrules the setting of the previous ones in the +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1109,10 +1150,10 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to +# will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 @@ -1120,7 +1161,7 @@ HTML_EXTRA_FILES = # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A @@ -1128,7 +1169,7 @@ HTML_COLORSTYLE_HUE = 220 # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 @@ -1139,15 +1180,16 @@ HTML_COLORSTYLE_SAT = 100 # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE_GAMMA = 80 +HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_TIMESTAMP = YES +HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the @@ -1155,7 +1197,7 @@ HTML_TIMESTAMP = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand @@ -1182,7 +1224,7 @@ HTML_INDEX_NUM_ENTRIES = 100 # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_DOCSET = NO +GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider @@ -1190,7 +1232,7 @@ GENERATE_DOCSET = NO # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. @@ -1198,7 +1240,7 @@ DOCSET_FEEDNAME = "Doxygen generated docs" # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style @@ -1206,13 +1248,13 @@ DOCSET_BUNDLE_ID = org.doxygen.Project # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_PUBLISHER_NAME = Publisher +DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The @@ -1230,50 +1272,50 @@ DOCSET_PUBLISHER_NAME = Publisher # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_HTMLHELP = NO +GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -GENERATE_CHI = NO +GENERATE_CHI = NO -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -BINARY_TOC = NO +BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -TOC_EXPAND = NO +TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that @@ -1282,14 +1324,14 @@ TOC_EXPAND = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_QHP = NO +GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace @@ -1297,7 +1339,7 @@ QCH_FILE = # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_NAMESPACE = org.doxygen.Project +QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual @@ -1306,7 +1348,7 @@ QHP_NAMESPACE = org.doxygen.Project # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_VIRTUAL_FOLDER = doc +QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom @@ -1314,7 +1356,7 @@ QHP_VIRTUAL_FOLDER = doc # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom @@ -1322,21 +1364,21 @@ QHP_CUST_FILTER_NAME = # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To @@ -1348,7 +1390,7 @@ QHG_LOCATION = # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_ECLIPSEHELP = NO +GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this @@ -1356,7 +1398,7 @@ GENERATE_ECLIPSEHELP = NO # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. -ECLIPSE_DOC_ID = org.doxygen.Project +ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The @@ -1367,7 +1409,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -DISABLE_INDEX = NO +DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag @@ -1375,7 +1417,7 @@ DISABLE_INDEX = NO # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has @@ -1384,7 +1426,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = YES +GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. @@ -1394,21 +1436,21 @@ GENERATE_TREEVIEW = YES # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. -ENUM_VALUES_PER_LINE = 4 +ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. -TREEVIEW_WIDTH = 250 +TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -EXT_LINKS_IN_WINDOW = NO +EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful @@ -1417,7 +1459,7 @@ EXT_LINKS_IN_WINDOW = NO # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. -FORMULA_FONTSIZE = 10 +FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not @@ -1428,18 +1470,18 @@ FORMULA_FONTSIZE = 10 # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -FORMULA_TRANSPARENT = YES +FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -USE_MATHJAX = NO +USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: @@ -1449,7 +1491,7 @@ USE_MATHJAX = NO # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_FORMAT = HTML-CSS +MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory @@ -1462,14 +1504,14 @@ MATHJAX_FORMAT = HTML-CSS # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site @@ -1477,7 +1519,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1498,7 +1540,7 @@ MATHJAX_CODEFILE = # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -SEARCHENGINE = YES +SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There @@ -1510,7 +1552,7 @@ SEARCHENGINE = YES # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. -SERVER_BASED_SEARCH = NO +SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file @@ -1518,7 +1560,7 @@ SERVER_BASED_SEARCH = NO # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). # @@ -1526,18 +1568,18 @@ SERVER_BASED_SEARCH = NO # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH = NO +EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1545,7 +1587,7 @@ SEARCHENGINE_URL = # The default file is: searchdata.xml. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHDATA_FILE = searchdata.xml +SEARCHDATA_FILE = searchdata.xml # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is @@ -1553,7 +1595,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1563,16 +1605,16 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. -GENERATE_LATEX = NO +GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1580,7 +1622,7 @@ GENERATE_LATEX = NO # The default directory is: latex. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_OUTPUT = latex +LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. @@ -1591,22 +1633,22 @@ LATEX_OUTPUT = latex # The default file is: latex. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_CMD_NAME = latex +LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. -MAKEINDEX_CMD_NAME = makeindex +MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -COMPACT_LATEX = NO +COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used by the # printer. @@ -1615,16 +1657,19 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4 +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # generated LaTeX document. The header should contain everything until the first @@ -1635,12 +1680,12 @@ EXTRA_PACKAGES = # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, # $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string, -# for the replacement values of the other commands the user is refered to -# HTML_HEADER. +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last @@ -1651,7 +1696,18 @@ LATEX_HEADER = # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1659,7 +1715,7 @@ LATEX_FOOTER = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1668,15 +1724,15 @@ LATEX_EXTRA_FILES = # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. -PDF_HYPERLINKS = YES +PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a +# the PDF file directly from the LaTeX files. Set this option to YES, to get a # higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. -USE_PDFLATEX = YES +USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running @@ -1685,14 +1741,14 @@ USE_PDFLATEX = YES # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_BATCHMODE = NO +LATEX_BATCHMODE = NO # If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the # index chapters (such as File Index, Compound Index, etc.) in the output. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HIDE_INDICES = NO +LATEX_HIDE_INDICES = NO # If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source # code with syntax highlighting in the LaTeX output. @@ -1702,7 +1758,7 @@ LATEX_HIDE_INDICES = NO # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_SOURCE_CODE = NO +LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See @@ -1710,18 +1766,26 @@ LATEX_SOURCE_CODE = NO # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_BIB_STYLE = plain +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. -GENERATE_RTF = NO +GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1729,15 +1793,15 @@ GENERATE_RTF = NO # The default directory is: rtf. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_OUTPUT = rtf +RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. -COMPACT_RTF = NO +COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will # contain hyperlink fields. The RTF file will contain links (just like the HTML @@ -1749,7 +1813,7 @@ COMPACT_RTF = NO # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_HYPERLINKS = NO +RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's config # file, i.e. a series of assignments. You only have to provide replacements, @@ -1759,24 +1823,34 @@ RTF_HYPERLINKS = NO # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's config file. A template extensions file can be generated # using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. -GENERATE_MAN = NO +GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1785,7 +1859,7 @@ GENERATE_MAN = NO # The default directory is: man. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_OUTPUT = man +MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to the generated # man pages. In case the manual section does not start with a number, the number @@ -1794,14 +1868,14 @@ MAN_OUTPUT = man # The default value is: .3. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_EXTENSION = .3 +MAN_EXTENSION = .3 # The MAN_SUBDIR tag determines the name of the directory created within # MAN_OUTPUT in which the man pages are placed. If defaults to man followed by # MAN_EXTENSION with the initial . removed. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_SUBDIR = +MAN_SUBDIR = # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real @@ -1810,17 +1884,17 @@ MAN_SUBDIR = # The default value is: NO. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_LINKS = NO +MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. -GENERATE_XML = NO +GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1828,26 +1902,26 @@ GENERATE_XML = NO # The default directory is: xml. # This tag requires that the tag GENERATE_XML is set to YES. -XML_OUTPUT = xml +XML_OUTPUT = xml -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. # The default value is: YES. # This tag requires that the tag GENERATE_XML is set to YES. -XML_PROGRAMLISTING = YES +XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. -GENERATE_DOCBOOK = NO +GENERATE_DOCBOOK = NO # The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be put in @@ -1855,9 +1929,9 @@ GENERATE_DOCBOOK = NO # The default directory is: docbook. # This tag requires that the tag GENERATE_DOCBOOK is set to YES. -DOCBOOK_OUTPUT = docbook +DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the # program listings (including syntax highlighting and cross-referencing # information) to the DOCBOOK output. Note that enabling this will significantly # increase the size of the DOCBOOK output. @@ -1870,43 +1944,43 @@ DOCBOOK_PROGRAMLISTING = NO # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. # The default value is: NO. -GENERATE_AUTOGEN_DEF = NO +GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. # The default value is: NO. -GENERATE_PERLMOD = NO +GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_LATEX = NO +PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_PRETTY = YES +PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file are # prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful @@ -1920,20 +1994,20 @@ PERLMOD_MAKEVAR_PREFIX = # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. -ENABLE_PREPROCESSING = YES +ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -1941,21 +2015,21 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -SEARCH_INCLUDES = YES +SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = +INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -1963,7 +2037,7 @@ INCLUDE_PATH = # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -1973,7 +2047,9 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = CO_DOXYGEN CO_NO_SDO_CLIENT=1 CO_NO_NMT_MASTER=1 +PREDEFINED = CO_DOXYGEN \ + CO_NO_SDO_CLIENT=1 \ + CO_NO_NMT_MASTER=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -1982,7 +2058,7 @@ PREDEFINED = CO_DOXYGEN CO_NO_SDO_CLIENT=1 CO_NO_NMT_MASTER=1 # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have @@ -1992,7 +2068,7 @@ EXPAND_AS_DEFINED = # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -SKIP_FUNCTION_MACROS = YES +SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references @@ -2011,52 +2087,53 @@ SKIP_FUNCTION_MACROS = YES # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. # The default value is: NO. -ALLEXTERNALS = NO +ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. -EXTERNAL_GROUPS = YES +EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. -EXTERNAL_PAGES = YES +EXTERNAL_PAGES = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of 'which perl'). # The default file (with absolute path) is: /usr/bin/perl. -PERL_PATH = /usr/bin/perl +PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # NO turns the diagrams off. Note that this option also works with HAVE_DOT # disabled, but it is recommended to install and use dot, since it yields more # powerful graphs. # The default value is: YES. -CLASS_DIAGRAMS = NO +CLASS_DIAGRAMS = NO # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see: @@ -2065,20 +2142,20 @@ CLASS_DIAGRAMS = NO # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. -HIDE_UNDOC_RELATIONS = YES +HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: @@ -2087,7 +2164,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: YES. -HAVE_DOT = NO +HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of @@ -2097,7 +2174,7 @@ HAVE_DOT = NO # Minimum value: 0, maximum value: 32, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_NUM_THREADS = 0 +DOT_NUM_THREADS = 0 # When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make @@ -2107,21 +2184,21 @@ DOT_NUM_THREADS = 0 # The default value is: Helvetica. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size (in points) of the font of # dot graphs. # Minimum value: 4, maximum value: 24, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the default font as specified with # DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # each documented class showing the direct and indirect inheritance relations. @@ -2129,7 +2206,7 @@ DOT_FONTPATH = # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -CLASS_GRAPH = YES +CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation @@ -2138,22 +2215,22 @@ CLASS_GRAPH = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -COLLABORATION_GRAPH = YES +COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for # groups, showing the direct groups dependencies. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GROUP_GRAPHS = YES +GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -UML_LOOK = NO +UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside the # class node. If there are many fields or methods and many nodes the graph may @@ -2166,7 +2243,7 @@ UML_LOOK = NO # Minimum value: 0, maximum value: 100, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. -UML_LIMIT_NUM_FIELDS = 10 +UML_LIMIT_NUM_FIELDS = 10 # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their @@ -2174,7 +2251,7 @@ UML_LIMIT_NUM_FIELDS = 10 # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -TEMPLATE_RELATIONS = NO +TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the @@ -2183,7 +2260,7 @@ TEMPLATE_RELATIONS = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -INCLUDE_GRAPH = YES +INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing @@ -2192,36 +2269,38 @@ INCLUDE_GRAPH = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -INCLUDED_BY_GRAPH = YES +INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH tag is set to YES then doxygen will generate a call # dependency graph for every global function or class method. # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -CALL_GRAPH = NO +CALL_GRAPH = NO # If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller # dependency graph for every global function or class method. # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -CALLER_GRAPH = NO +CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical # hierarchy of all classes instead of a textual one. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GRAPHICAL_HIERARCHY = YES +GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The @@ -2230,20 +2309,24 @@ GRAPHICAL_HIERARCHY = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -DIRECTORY_GRAPH = YES +DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). # Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, # png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, -# gif:cairo:gd, gif:gd, gif:gd:gd and svg. +# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_IMAGE_FORMAT = png +DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. @@ -2255,41 +2338,50 @@ DOT_IMAGE_FORMAT = png # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -INTERACTIVE_SVG = NO +INTERACTIVE_SVG = NO # The DOT_PATH tag can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the # path where java can find the plantuml.jar file. If left blank, it is assumed # PlantUML is not used or called during a preprocessing step. Doxygen will # generate a warning when it encounters a \startuml command in this case and # will not generate output for the diagram. -# This tag requires that the tag HAVE_DOT is set to YES. -PLANTUML_JAR_PATH = +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes @@ -2301,7 +2393,7 @@ PLANTUML_JAR_PATH = # Minimum value: 0, maximum value: 10000, default value: 50. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_GRAPH_MAX_NODES = 50 +DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs # generated by dot. A depth value of 3 means that only nodes reachable from the @@ -2313,7 +2405,7 @@ DOT_GRAPH_MAX_NODES = 50 # Minimum value: 0, maximum value: 1000, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. -MAX_DOT_GRAPH_DEPTH = 0 +MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not seem @@ -2325,16 +2417,16 @@ MAX_DOT_GRAPH_DEPTH = 0 # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_TRANSPARENT = NO +DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_MULTI_TARGETS = NO +DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated @@ -2342,11 +2434,11 @@ DOT_MULTI_TARGETS = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GENERATE_LEGEND = YES +GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_CLEANUP = YES +DOT_CLEANUP = YES diff --git a/example/CO_driver.c b/example/CO_driver.c index f30bdd60..f70cc949 100644 --- a/example/CO_driver.c +++ b/example/CO_driver.c @@ -79,7 +79,7 @@ CO_ReturnError_t CO_CANmodule_init( rxArray[i].ident = 0U; rxArray[i].mask = 0xFFFFFFFFU; rxArray[i].object = NULL; - rxArray[i].pFunct = NULL; + rxArray[i].CANrx_callback = NULL; } for(i=0U; iident; -} - - /******************************************************************************/ CO_ReturnError_t CO_CANrxBufferInit( CO_CANmodule_t *CANmodule, @@ -133,17 +127,17 @@ CO_ReturnError_t CO_CANrxBufferInit( uint16_t mask, bool_t rtr, void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) + void (*CANrx_callback)(void *object, void *message)) { CO_ReturnError_t ret = CO_ERROR_NO; - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){ + if((CANmodule!=NULL) && (object!=NULL) && (CANrx_callback!=NULL) && (index < CANmodule->rxSize)){ /* buffer, which will be configured */ CO_CANrx_t *buffer = &CANmodule->rxArray[index]; /* Configure object variables */ buffer->object = object; - buffer->pFunct = pFunct; + buffer->CANrx_callback = CANrx_callback; /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */ buffer->ident = ident & 0x07FFU; @@ -320,6 +314,12 @@ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ /******************************************************************************/ +typedef struct { + uint32_t ident; + uint8_t DLC; + uint8_t data[8]; +} CO_CANrxMsg_t; + void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ /* receive interrupt */ @@ -358,8 +358,8 @@ void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ } /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){ - buffer->pFunct(buffer->object, rcvMsg); + if(msgMatched && (buffer != NULL) && (buffer->CANrx_callback != NULL)){ + buffer->CANrx_callback(buffer->object, (void*) rcvMsg); } /* Clear interrupt flag */ diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h new file mode 100644 index 00000000..7589e85a --- /dev/null +++ b/example/CO_driver_target.h @@ -0,0 +1,118 @@ +/* + * Device and application specific definitions for CANopenNode. + * + * @file CO_driver_target.h + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CO_DRIVER_TARGET +#define CO_DRIVER_TARGET + +#ifdef __cplusplus +extern "C" { +#endif + +/* This file contains device and application specific definitions. + * It is included from CO_driver.h, which contains documentation + * for definitions below. */ + +#include +#include +#include + + +/* Basic definitions */ +#define CO_LITTLE_ENDIAN +/* NULL is defined in stddef.h */ +/* true and false are defined in stdbool.h */ +/* int8_t to uint64_t are defined in stdint.h */ +typedef unsigned char bool_t; +typedef float float32_t; +typedef long double float64_t; +typedef char char_t; +typedef unsigned char oChar_t; +typedef unsigned char domain_t; + + +/* Access to received CAN message */ +#define CO_CANrxMsg_readIdent(msg) ((uint16_t)0) +#define CO_CANrxMsg_readDLC(msg) ((uint8_t)0) +#define CO_CANrxMsg_readData(msg) ((uint8_t *)NULL) + +/* Received message object */ +typedef struct { + uint16_t ident; + uint16_t mask; + void *object; + void (*CANrx_callback)(void *object, void *message); +} CO_CANrx_t; + +/* Transmit message object */ +typedef struct { + uint32_t ident; + uint8_t DLC; + uint8_t data[8]; + volatile bool_t bufferFull; + volatile bool_t syncFlag; +} CO_CANtx_t; + +/* CAN module object */ +typedef struct { + void *CANdriverState; + CO_CANrx_t *rxArray; + uint16_t rxSize; + CO_CANtx_t *txArray; + uint16_t txSize; + volatile bool_t CANnormal; + volatile bool_t useCANrxFilters; + volatile bool_t bufferInhibitFlag; + volatile bool_t firstCANtxMessage; + volatile uint16_t CANtxCount; + uint32_t errOld; + void *em; +} CO_CANmodule_t; + + +/* (un)lock critical section in CO_CANsend() */ +#define CO_LOCK_CAN_SEND() +#define CO_UNLOCK_CAN_SEND() + +/* (un)lock critical section in CO_errorReport() or CO_errorReset() */ +#define CO_LOCK_EMCY() +#define CO_UNLOCK_EMCY() + +/* (un)lock critical section when accessing Object Dictionary */ +#define CO_LOCK_OD() +#define CO_UNLOCK_OD() + +/* Synchronization between CAN receive and message processing threads. */ +#define CO_MemoryBarrier() +#define CO_CANrxNew_READ(rxNew) ((uintptr_t)rxNew) +#define CO_CANrxNew_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} +#define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = (void*)0L;} + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +/** @} */ +#endif /* CO_DRIVER_TARGET */ diff --git a/example/main.c b/example/main.c index 816ea4e3..ca5d697a 100644 --- a/example/main.c +++ b/example/main.c @@ -119,7 +119,7 @@ int main (void){ /* timer thread executes in constant intervals ********************************/ -static void tmrTask_thread(void){ +void tmrTask_thread(void){ for(;;) { @@ -150,10 +150,8 @@ static void tmrTask_thread(void){ } -/* CAN interrupt function *****************************************************/ +/* CAN interrupt function executes on received CAN message ********************/ void /* interrupt */ CO_CAN1InterruptHandler(void){ - CO_CANinterrupt(CO->CANmodule[0]); - /* clear interrupt flag */ } diff --git a/stack/CO_Emergency.c b/stack/CO_Emergency.c index 3067187f..dff38434 100644 --- a/stack/CO_Emergency.c +++ b/stack/CO_Emergency.c @@ -27,7 +27,6 @@ #include "CO_driver.h" #include "CO_SDO.h" #include "CO_Emergency.h" -#include "CANopen.h" /* @@ -37,20 +36,23 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_EM_receive(void *object, const CO_CANrxMsg_t *msg){ +static void CO_EM_receive(void *object, void *msg) { CO_EM_t *em; - uint16_t errorCode; - uint32_t infoCode; em = (CO_EM_t*)object; if(em!=NULL && em->pFunctSignalRx!=NULL){ - CO_memcpySwap2(&errorCode, &msg->data[0]); - CO_memcpySwap4(&infoCode, &msg->data[4]); - em->pFunctSignalRx(CO_CANrxMsg_readIdent(msg), + uint16_t ident = CO_CANrxMsg_readIdent(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); + uint16_t errorCode; + uint32_t infoCode; + + CO_memcpySwap2(&errorCode, &data[0]); + CO_memcpySwap4(&infoCode, &data[4]); + em->pFunctSignalRx(ident, errorCode, - msg->data[2], - msg->data[3], + data[2], + data[3], infoCode); } } diff --git a/stack/CO_Emergency.h b/stack/CO_Emergency.h index 84abac8f..40bb9ae2 100644 --- a/stack/CO_Emergency.h +++ b/stack/CO_Emergency.h @@ -412,7 +412,7 @@ void CO_EM_initCallback( * inside an ISR * * @param em This object. - * @param pFunctSignal Pointer to the callback function. Not called if NULL. + * @param pFunctSignalRx Pointer to the callback function. Not called if NULL. */ void CO_EM_initCallbackRx( CO_EM_t *em, diff --git a/stack/CO_HBconsumer.c b/stack/CO_HBconsumer.c index ec4dbf2c..d699c0bc 100644 --- a/stack/CO_HBconsumer.c +++ b/stack/CO_HBconsumer.c @@ -23,7 +23,10 @@ * limitations under the License. */ -#include "CANopen.h" +#include "CO_driver.h" +#include "CO_SDO.h" +#include "CO_Emergency.h" +#include "CO_NMT_Heartbeat.h" #include "CO_HBconsumer.h" /* @@ -33,16 +36,18 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_HBcons_receive(void *object, const CO_CANrxMsg_t *msg){ +static void CO_HBcons_receive(void *object, void *msg){ CO_HBconsNode_t *HBconsNode; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); HBconsNode = (CO_HBconsNode_t*) object; /* this is the correct pointer type of the first argument */ /* verify message length */ - if(msg->DLC == 1){ + if(DLC == 1){ /* copy data and set 'new message' flag. */ - HBconsNode->NMTstate = (CO_NMT_internalState_t)msg->data[0]; - SET_CANrxNew(HBconsNode->CANrxNew); + HBconsNode->NMTstate = (CO_NMT_internalState_t)data[0]; + CO_CANrxNew_SET(HBconsNode->CANrxNew); } } @@ -277,7 +282,7 @@ void CO_HBconsumer_process( for(i=0; inumberOfMonitoredNodes; i++){ if(monitoredNode->time > 0){/* is node monitored */ /* Verify if received message is heartbeat or bootup */ - if(IS_CANrxNew(monitoredNode->CANrxNew)){ + if(CO_CANrxNew_READ(monitoredNode->CANrxNew)){ if(monitoredNode->NMTstate == CO_NMT_INITIALIZING){ /* bootup message, call callback */ if (monitoredNode->pFunctSignalRemoteReset != NULL) { @@ -296,7 +301,7 @@ void CO_HBconsumer_process( monitoredNode->timeoutTimer = 0; /* reset timer */ timeDifference_ms = 0; } - CLEAR_CANrxNew(monitoredNode->CANrxNew); + CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); } /* Verify timeout */ @@ -336,7 +341,7 @@ void CO_HBconsumer_process( else{ /* not in (pre)operational state */ for(i=0; inumberOfMonitoredNodes; i++){ monitoredNode->NMTstate = CO_NMT_INITIALIZING; - CLEAR_CANrxNew(monitoredNode->CANrxNew); + CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); if(monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED){ monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; } diff --git a/stack/CO_HBconsumer.h b/stack/CO_HBconsumer.h index f0e11e63..d4b21715 100644 --- a/stack/CO_HBconsumer.h +++ b/stack/CO_HBconsumer.h @@ -249,7 +249,7 @@ CO_HBconsumer_state_t CO_HBconsumer_getState( * * @param HBcons This object. * @param idx object sub index - * @param [out] #CO_NMT_internalState_t of this index + * @param [out] nmtState of this index * @retval 0 NMT state has been received and is valid * @retval -1 not valid */ diff --git a/stack/CO_LSS.h b/stack/CO_LSS.h index 45b790d6..f35e9a0f 100644 --- a/stack/CO_LSS.h +++ b/stack/CO_LSS.h @@ -85,8 +85,6 @@ extern "C" { * For CAN identifiers see #CO_Default_CAN_ID_t */ -#if CO_NO_LSS_CLIENT == 1 || CO_NO_LSS_SERVER == 1 - /** * LSS protocol command specifiers * @@ -263,11 +261,9 @@ static const uint16_t CO_LSS_bitTimingTableLookup[] = { a1.identity.serialNumber == a2.identity.serialNumber && \ a1.identity.vendorID == a2.identity.vendorID) -#endif /* CO_NO_LSS_CLIENT == 1 || CO_NO_LSS_SERVER == 1 */ - +/** @} */ /*@defgroup CO_LSS*/ #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /*CO_LSS_H*/ diff --git a/stack/CO_LSSmaster.c b/stack/CO_LSSmaster.c index 6269f122..f7837575 100644 --- a/stack/CO_LSSmaster.c +++ b/stack/CO_LSSmaster.c @@ -43,11 +43,10 @@ * to do so, delete this exception statement from your version. */ -#include "CANopen.h" +#include "CO_driver.h" +#include "CO_SDO.h" /* for helper functions */ #include "CO_LSSmaster.h" -#if CO_NO_LSS_CLIENT == 1 - /* * LSS master slave select state machine. Compared to #CO_LSS_state_t this * has information if we currently have selected one or all slaves. This @@ -92,27 +91,29 @@ typedef enum { * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_LSSmaster_receive(void *object, const CO_CANrxMsg_t *msg) +static void CO_LSSmaster_receive(void *object, void *msg) { CO_LSSmaster_t *LSSmaster; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */ /* verify message length and message overflow (previous message was not processed yet) */ - if(msg->DLC==8 && !IS_CANrxNew(LSSmaster->CANrxNew) && + if(DLC==8 && !CO_CANrxNew_READ(LSSmaster->CANrxNew) && LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING){ /* copy data and set 'new message' flag */ - LSSmaster->CANrxData[0] = msg->data[0]; - LSSmaster->CANrxData[1] = msg->data[1]; - LSSmaster->CANrxData[2] = msg->data[2]; - LSSmaster->CANrxData[3] = msg->data[3]; - LSSmaster->CANrxData[4] = msg->data[4]; - LSSmaster->CANrxData[5] = msg->data[5]; - LSSmaster->CANrxData[6] = msg->data[6]; - LSSmaster->CANrxData[7] = msg->data[7]; + LSSmaster->CANrxData[0] = data[0]; + LSSmaster->CANrxData[1] = data[1]; + LSSmaster->CANrxData[2] = data[2]; + LSSmaster->CANrxData[3] = data[3]; + LSSmaster->CANrxData[4] = data[4]; + LSSmaster->CANrxData[5] = data[5]; + LSSmaster->CANrxData[6] = data[6]; + LSSmaster->CANrxData[7] = data[7]; - SET_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_SET(LSSmaster->CANrxNew); /* Optional signal to RTOS, which can resume task, which handles SDO client. */ if(LSSmaster->pFunctSignal != NULL) { @@ -164,7 +165,7 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->state = CO_LSSmaster_STATE_WAITING; LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; LSSmaster->timeoutTimer = 0; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); CO_memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); LSSmaster->pFunctSignal = NULL; LSSmaster->functSignalObject = NULL; @@ -231,7 +232,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( LSSmaster->command = CO_LSSmaster_COMMAND_SWITCH_STATE; LSSmaster->timeoutTimer = 0; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); CO_memset(&LSSmaster->TXbuff->data[6], 0, 3); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); @@ -252,7 +253,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( /* switch state global */ LSSmaster->state = CO_LSSmaster_STATE_CFG_GLOBAL; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION; CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); @@ -273,9 +274,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( { CO_LSSmaster_return_t ret; - if (IS_CANrxNew(LSSmaster->CANrxNew)) { + if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); if (cs == CO_LSS_SWITCH_STATE_SEL) { /* confirmation received */ @@ -345,7 +346,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( LSSmaster->timeoutTimer = 0; /* switch state global */ - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_WAITING; CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); @@ -383,10 +384,10 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( { CO_LSSmaster_return_t ret; - if (IS_CANrxNew(LSSmaster->CANrxNew)) { + if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; uint8_t errorCode = LSSmaster->CANrxData[1]; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); if (cs == csWait) { if (errorCode == 0) { @@ -448,7 +449,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( LSSmaster->command = CO_LSSmaster_COMMAND_CFG_BIT_TIMING; LSSmaster->timeoutTimer = 0; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_BIT_TIMING; LSSmaster->TXbuff->data[1] = 0; LSSmaster->TXbuff->data[2] = bitTiming; @@ -494,7 +495,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( LSSmaster->command = CO_LSSmaster_COMMAND_CFG_NODE_ID; LSSmaster->timeoutTimer = 0; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_NODE_ID; LSSmaster->TXbuff->data[1] = nodeId; CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); @@ -535,7 +536,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( LSSmaster->command = CO_LSSmaster_COMMAND_CFG_STORE; LSSmaster->timeoutTimer = 0; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_STORE; CO_memset(&LSSmaster->TXbuff->data[1], 0, 7); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -573,7 +574,7 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( if (LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL && LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){ - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); CO_memset(&LSSmaster->TXbuff->data[3], 0, 5); @@ -593,7 +594,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( CO_LSSmaster_t *LSSmaster, uint8_t cs) { - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = cs; CO_memset(&LSSmaster->TXbuff->data[1], 0, 7); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -612,10 +613,10 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait( { CO_LSSmaster_return_t ret; - if (IS_CANrxNew(LSSmaster->CANrxNew)) { + if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; *value = CO_getUint32(&LSSmaster->CANrxData[1]); - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); if (cs == csWait) { ret = CO_LSSmaster_OK; @@ -768,7 +769,7 @@ static void CO_LSSmaster_FsSendMsg( { LSSmaster->timeoutTimer = 0; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_IDENT_FASTSCAN; CO_setUint32(&LSSmaster->TXbuff->data[1], idNumber); LSSmaster->TXbuff->data[5] = bitCheck; @@ -791,9 +792,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsCheckWait( if (ret == CO_LSSmaster_TIMEOUT) { ret = CO_LSSmaster_SCAN_NOACK; - if (IS_CANrxNew(LSSmaster->CANrxNew)) { + if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); if (cs == CO_LSS_IDENT_SLAVE) { /* At least one node is waiting for fastscan */ @@ -861,9 +862,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( ret = CO_LSSmaster_WAIT_SLAVE; - if (IS_CANrxNew(LSSmaster->CANrxNew)) { + if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); if (cs != CO_LSS_IDENT_SLAVE) { /* wrong response received. Can not continue */ @@ -944,9 +945,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait( *idNumberRet = 0; ret = CO_LSSmaster_SCAN_NOACK; - if (IS_CANrxNew(LSSmaster->CANrxNew)) { + if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; - CLEAR_CANrxNew(LSSmaster->CANrxNew); + CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); if (cs == CO_LSS_IDENT_SLAVE) { *idNumberRet = LSSmaster->fsIdNumber; @@ -1116,6 +1117,3 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } return ret; } - - -#endif diff --git a/stack/CO_LSSmaster.h b/stack/CO_LSSmaster.h index aa49918e..424bde74 100644 --- a/stack/CO_LSSmaster.h +++ b/stack/CO_LSSmaster.h @@ -51,12 +51,9 @@ extern "C" { #endif -#if CO_NO_LSS_CLIENT == 1 - #include "CO_LSS.h" /** - * @addtogroup CO_LSS * @defgroup CO_LSSmaster LSS Master * @ingroup CO_LSS * @{ @@ -482,22 +479,9 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( uint16_t timeDifference_ms, CO_LSSmaster_fastscan_t *fastscan); - -#else /* CO_NO_LSS_CLIENT == 1 */ - -/** - * @addtogroup CO_LSS - * @{ - * If you need documetation for LSS master usage, add "CO_NO_LSS_CLIENT=1" to doxygen - * "PREDEFINED" variable. - * - */ - -#endif /* CO_NO_LSS_CLIENT == 1 */ - +/** @} */ /*@defgroup CO_LSSmaster*/ #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /*CO_LSSmaster_H*/ diff --git a/stack/CO_LSSslave.c b/stack/CO_LSSslave.c index 9ed39fa4..f9086aa1 100644 --- a/stack/CO_LSSslave.c +++ b/stack/CO_LSSslave.c @@ -43,20 +43,20 @@ * to do so, delete this exception statement from your version. */ -#include "CANopen.h" +#include "CO_driver.h" +#include "CO_SDO.h" /* for helper functions */ #include "CO_LSSslave.h" -#if CO_NO_LSS_SERVER == 1 - /* * Helper function - Handle service "switch state global" */ static void CO_LSSslave_serviceSwitchStateGlobal( CO_LSSslave_t *LSSslave, CO_LSS_cs_t service, - const CO_CANrxMsg_t *msg) + void *msg) { - uint8_t mode = msg->data[1]; + uint8_t *data = CO_CANrxMsg_readData(msg); + uint8_t mode = data[1]; switch (mode) { case CO_LSS_STATE_WAITING: @@ -77,10 +77,11 @@ static void CO_LSSslave_serviceSwitchStateGlobal( static void CO_LSSslave_serviceSwitchStateSelective( CO_LSSslave_t *LSSslave, CO_LSS_cs_t service, - const CO_CANrxMsg_t *msg) + void *msg) { uint32_t value; - CO_memcpySwap4(&value, &msg->data[1]); + uint8_t *data = CO_CANrxMsg_readData(msg); + CO_memcpySwap4(&value, &data[1]); if(LSSslave->lssState != CO_LSS_STATE_WAITING) { return; @@ -122,20 +123,23 @@ static void CO_LSSslave_serviceSwitchStateSelective( static void CO_LSSslave_serviceConfig( CO_LSSslave_t *LSSslave, CO_LSS_cs_t service, - const CO_CANrxMsg_t *msg) + const void *msg) { uint8_t nid; uint8_t tableSelector; uint8_t tableIndex; uint8_t errorCode; + uint8_t *data; if(LSSslave->lssState != CO_LSS_STATE_CONFIGURATION) { return; } + data = CO_CANrxMsg_readData(msg); + switch (service) { case CO_LSS_CFG_NODE_ID: - nid = msg->data[1]; + nid = data[1]; errorCode = CO_LSS_CFG_NODE_ID_OK; if (CO_LSS_NODE_ID_VALID(nid)) { @@ -158,8 +162,8 @@ static void CO_LSSslave_serviceConfig( break; } - tableSelector = msg->data[1]; - tableIndex = msg->data[2]; + tableSelector = data[1]; + tableIndex = data[2]; errorCode = CO_LSS_CFG_BIT_TIMING_OK; if (tableSelector==0 && CO_LSS_BIT_TIMING_VALID(tableIndex)) { @@ -195,7 +199,7 @@ static void CO_LSSslave_serviceConfig( /* notify application */ if (LSSslave->pFunctLSSactivateBitRate != NULL) { uint16_t delay; - CO_memcpySwap2(&delay, &msg->data[1]); + CO_memcpySwap2(&delay, &data[1]); LSSslave->pFunctLSSactivateBitRate( LSSslave->functLSSactivateBitRateObject, delay); } @@ -235,7 +239,7 @@ static void CO_LSSslave_serviceConfig( static void CO_LSSslave_serviceInquire( CO_LSSslave_t *LSSslave, CO_LSS_cs_t service, - const CO_CANrxMsg_t *msg) + void *msg) { uint32_t value; @@ -275,13 +279,14 @@ static void CO_LSSslave_serviceInquire( static void CO_LSSslave_serviceIdent( CO_LSSslave_t *LSSslave, CO_LSS_cs_t service, - const CO_CANrxMsg_t *msg) + void *msg) { uint32_t idNumber; uint8_t bitCheck; uint8_t lssSub; uint8_t lssNext; bool_t ack; + uint8_t *data = CO_CANrxMsg_readData(msg); if (LSSslave->lssState != CO_LSS_STATE_WAITING) { /* fastscan is only allowed in waiting state */ @@ -297,10 +302,10 @@ static void CO_LSSslave_serviceIdent( return; } - CO_memcpySwap4(&idNumber, &msg->data[1]); - bitCheck = msg->data[5]; - lssSub = msg->data[6]; - lssNext = msg->data[7]; + CO_memcpySwap4(&idNumber, &data[1]); + bitCheck = data[5]; + lssSub = data[6]; + lssNext = data[7]; if (!CO_LSS_FASTSCAN_BITCHECK_VALID(bitCheck) || !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssSub) || @@ -346,14 +351,16 @@ static void CO_LSSslave_serviceIdent( * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_LSSslave_receive(void *object, const CO_CANrxMsg_t *msg) +static void CO_LSSslave_receive(void *object, void *msg) { CO_LSSslave_t *LSSslave; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); LSSslave = (CO_LSSslave_t*)object; /* this is the correct pointer type of the first argument */ - if(msg->DLC == 8){ - CO_LSS_cs_t cs = msg->data[0]; + if(DLC == 8){ + CO_LSS_cs_t cs = data[0]; if (CO_LSS_CS_SERVICE_IS_SWITCH_GLOBAL(cs)) { CO_LSSslave_serviceSwitchStateGlobal(LSSslave, cs, msg); @@ -543,6 +550,3 @@ bool_t CO_LSSslave_LEDprocess( } return false; } - - -#endif diff --git a/stack/CO_LSSslave.h b/stack/CO_LSSslave.h index f935d453..fa059d92 100644 --- a/stack/CO_LSSslave.h +++ b/stack/CO_LSSslave.h @@ -51,12 +51,9 @@ extern "C" { #endif -#if CO_NO_LSS_SERVER == 1 - #include "CO_LSS.h" /** - * @addtogroup CO_LSS * @defgroup CO_LSSslave LSS Slave * @ingroup CO_LSS * @{ @@ -76,8 +73,8 @@ extern "C" { * After CAN module start, the LSS server and NMT server are started and then * coexist alongside each other. To achieve this behaviour, the CANopen node * startup process has to be conrolled more detailled. Therefore, the function - * CO_init() is split up into the functions #CO_new(), #CO_CANinit(), #CO_LSSinit() - * and #CO_CANopenInit(). + * CO_init() is split up into the functions CO_new(), CO_CANinit(), CO_LSSinit() + * and CO_CANopenInit(). * Moreover, the LSS server needs to pause the NMT server initialization in case * no valid node ID is available at start up. * @@ -429,21 +426,9 @@ void CO_LSSslave_initCfgStoreCallback( void *object, bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate)); -#else /* CO_NO_LSS_SERVER == 1 */ - -/** - * @addtogroup CO_LSS - * @{ - * If you need documetation for LSS slave usage, add "CO_NO_LSS_SERVER=1" to doxygen - * "PREDEFINED" variable. - * - */ - -#endif /* CO_NO_LSS_SERVER == 1 */ - +/** @} */ /*@defgroup CO_LSSslave*/ #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /*CO_LSSslave_H*/ diff --git a/stack/CO_NMT_Heartbeat.c b/stack/CO_NMT_Heartbeat.c index 5574bb47..2c7df36f 100644 --- a/stack/CO_NMT_Heartbeat.c +++ b/stack/CO_NMT_Heartbeat.c @@ -36,16 +36,18 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_NMT_receive(void *object, const CO_CANrxMsg_t *msg){ +static void CO_NMT_receive(void *object, void *msg){ CO_NMT_t *NMT; uint8_t nodeId; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); NMT = (CO_NMT_t*)object; /* this is the correct pointer type of the first argument */ - nodeId = msg->data[1]; + nodeId = data[1]; - if((msg->DLC == 2) && ((nodeId == 0) || (nodeId == NMT->nodeId))){ - uint8_t command = msg->data[0]; + if((DLC == 2) && ((nodeId == 0) || (nodeId == NMT->nodeId))){ + uint8_t command = data[0]; uint8_t currentOperatingState = NMT->operatingState; switch(command){ diff --git a/stack/CO_PDO.c b/stack/CO_PDO.c index 679ee5d3..e42b07fb 100644 --- a/stack/CO_PDO.c +++ b/stack/CO_PDO.c @@ -40,40 +40,42 @@ * If new message arrives and previous message wasn't processed yet, then * previous message will be lost and overwritten by new message. That's OK with PDOs. */ -static void CO_PDO_receive(void *object, const CO_CANrxMsg_t *msg){ +static void CO_PDO_receive(void *object, void *msg){ CO_RPDO_t *RPDO; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); RPDO = (CO_RPDO_t*)object; /* this is the correct pointer type of the first argument */ if( (RPDO->valid) && (*RPDO->operatingState == CO_NMT_OPERATIONAL) && - (msg->DLC >= RPDO->dataLength)) + (DLC >= RPDO->dataLength)) { if(RPDO->SYNC && RPDO->synchronous && RPDO->SYNC->CANrxToggle) { /* copy data into second buffer and set 'new message' flag */ - RPDO->CANrxData[1][0] = msg->data[0]; - RPDO->CANrxData[1][1] = msg->data[1]; - RPDO->CANrxData[1][2] = msg->data[2]; - RPDO->CANrxData[1][3] = msg->data[3]; - RPDO->CANrxData[1][4] = msg->data[4]; - RPDO->CANrxData[1][5] = msg->data[5]; - RPDO->CANrxData[1][6] = msg->data[6]; - RPDO->CANrxData[1][7] = msg->data[7]; - - SET_CANrxNew(RPDO->CANrxNew[1]); + RPDO->CANrxData[1][0] = data[0]; + RPDO->CANrxData[1][1] = data[1]; + RPDO->CANrxData[1][2] = data[2]; + RPDO->CANrxData[1][3] = data[3]; + RPDO->CANrxData[1][4] = data[4]; + RPDO->CANrxData[1][5] = data[5]; + RPDO->CANrxData[1][6] = data[6]; + RPDO->CANrxData[1][7] = data[7]; + + CO_CANrxNew_SET(RPDO->CANrxNew[1]); } else { /* copy data into default buffer and set 'new message' flag */ - RPDO->CANrxData[0][0] = msg->data[0]; - RPDO->CANrxData[0][1] = msg->data[1]; - RPDO->CANrxData[0][2] = msg->data[2]; - RPDO->CANrxData[0][3] = msg->data[3]; - RPDO->CANrxData[0][4] = msg->data[4]; - RPDO->CANrxData[0][5] = msg->data[5]; - RPDO->CANrxData[0][6] = msg->data[6]; - RPDO->CANrxData[0][7] = msg->data[7]; - - SET_CANrxNew(RPDO->CANrxNew[0]); + RPDO->CANrxData[0][0] = data[0]; + RPDO->CANrxData[0][1] = data[1]; + RPDO->CANrxData[0][2] = data[2]; + RPDO->CANrxData[0][3] = data[3]; + RPDO->CANrxData[0][4] = data[4]; + RPDO->CANrxData[0][5] = data[5]; + RPDO->CANrxData[0][6] = data[6]; + RPDO->CANrxData[0][7] = data[7]; + + CO_CANrxNew_SET(RPDO->CANrxNew[0]); } } } @@ -108,8 +110,8 @@ static void CO_RPDOconfigCom(CO_RPDO_t* RPDO, uint32_t COB_IDUsedByRPDO){ else{ ID = 0; RPDO->valid = false; - CLEAR_CANrxNew(RPDO->CANrxNew[0]); - CLEAR_CANrxNew(RPDO->CANrxNew[1]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[0]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); } r = CO_CANrxBufferInit( RPDO->CANdevRx, /* CAN device */ @@ -121,8 +123,8 @@ static void CO_RPDOconfigCom(CO_RPDO_t* RPDO, uint32_t COB_IDUsedByRPDO){ CO_PDO_receive); /* this function will process received message */ if(r != CO_ERROR_NO){ RPDO->valid = false; - CLEAR_CANrxNew(RPDO->CANrxNew[0]); - CLEAR_CANrxNew(RPDO->CANrxNew[1]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[0]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); } } @@ -472,7 +474,7 @@ static CO_SDO_abortCode_t CO_ODF_RPDOcom(CO_ODF_arg_t *ODF_arg){ /* Remove old message from second buffer. */ if(RPDO->synchronous != synchronousPrev) { - CLEAR_CANrxNew(RPDO->CANrxNew[1]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); } } @@ -742,8 +744,8 @@ CO_ReturnError_t CO_RPDO_init( CO_OD_configure(SDO, idx_RPDOMapPar, CO_ODF_RPDOmap, (void*)RPDO, 0, 0); /* configure communication and mapping */ - CLEAR_CANrxNew(RPDO->CANrxNew[0]); - CLEAR_CANrxNew(RPDO->CANrxNew[1]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[0]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); RPDO->CANdevRx = CANdevRx; RPDO->CANdevRxIdx = CANdevRxIdx; @@ -892,8 +894,8 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ if(!RPDO->valid || !(*RPDO->operatingState == CO_NMT_OPERATIONAL)) { - CLEAR_CANrxNew(RPDO->CANrxNew[0]); - CLEAR_CANrxNew(RPDO->CANrxNew[1]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[0]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); } else if(!RPDO->synchronous || syncWas) { @@ -908,7 +910,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ bufNo = 1; } - while(IS_CANrxNew(RPDO->CANrxNew[bufNo])){ + while(CO_CANrxNew_READ(RPDO->CANrxNew[bufNo])){ int16_t i; uint8_t* pPDOdataByte; uint8_t** ppODdataByte; @@ -919,7 +921,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ /* Copy data to Object dictionary. If between the copy operation CANrxNew * is set to true by receive thread, then copy the latest data again. */ - CLEAR_CANrxNew(RPDO->CANrxNew[bufNo]); + CO_CANrxNew_CLEAR(RPDO->CANrxNew[bufNo]); for(; i>0; i--) { **(ppODdataByte++) = *(pPDOdataByte++); } diff --git a/stack/CO_PDO.h b/stack/CO_PDO.h index a2743f61..0f7b4a2b 100644 --- a/stack/CO_PDO.h +++ b/stack/CO_PDO.h @@ -234,6 +234,7 @@ typedef struct{ * @param RPDO This object will be initialized. * @param em Emergency object. * @param SDO SDO server object. + * @param SYNC SYNC object. * @param operatingState Pointer to variable indicating CANopen device NMT internal state. * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. * @param defaultCOB_ID Default COB ID for this PDO (without NodeId). @@ -280,6 +281,7 @@ CO_ReturnError_t CO_RPDO_init( * @param TPDO This object will be initialized. * @param em Emergency object. * @param SDO SDO object. + * @param SYNC SYNC object. * @param operatingState Pointer to variable indicating CANopen device NMT internal state. * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. * @param defaultCOB_ID Default COB ID for this PDO (without NodeId). @@ -370,7 +372,6 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas); * CO_TPDOisCOS() must be called before. * * @param TPDO This object. - * @param SYNC SYNC object. Ignored if NULL. * @param syncWas True, if CANopen SYNC message was just received or transmitted. * @param timeDifference_us Time difference from previous function call in [microseconds]. */ diff --git a/stack/CO_SDO.c b/stack/CO_SDO.c index 2054e04d..45d693f2 100644 --- a/stack/CO_SDO.c +++ b/stack/CO_SDO.c @@ -168,9 +168,11 @@ void CO_memcpySwap8(void* dest, const void* src){ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_SDO_receive(void *object, const CO_CANrxMsg_t *msg); -static void CO_SDO_receive(void *object, const CO_CANrxMsg_t *msg){ +static void CO_SDO_receive(void *object, void *msg); +static void CO_SDO_receive(void *object, void *msg){ CO_SDO_t *SDO; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); SDO = (CO_SDO_t*)object; /* this is the correct pointer type of the first argument */ @@ -180,25 +182,25 @@ static void CO_SDO_receive(void *object, const CO_CANrxMsg_t *msg){ * See: https://github.com/CANopenNode/CANopenNode/issues/39 */ /* verify message length and message overflow (previous message was not processed yet) */ - if((msg->DLC == 8U) && (!IS_CANrxNew(SDO->CANrxNew))){ + if((DLC == 8U) && (!CO_CANrxNew_READ(SDO->CANrxNew))){ if(SDO->state != CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) { /* copy data and set 'new message' flag */ - SDO->CANrxData[0] = msg->data[0]; - SDO->CANrxData[1] = msg->data[1]; - SDO->CANrxData[2] = msg->data[2]; - SDO->CANrxData[3] = msg->data[3]; - SDO->CANrxData[4] = msg->data[4]; - SDO->CANrxData[5] = msg->data[5]; - SDO->CANrxData[6] = msg->data[6]; - SDO->CANrxData[7] = msg->data[7]; - - SET_CANrxNew(SDO->CANrxNew); + SDO->CANrxData[0] = data[0]; + SDO->CANrxData[1] = data[1]; + SDO->CANrxData[2] = data[2]; + SDO->CANrxData[3] = data[3]; + SDO->CANrxData[4] = data[4]; + SDO->CANrxData[5] = data[5]; + SDO->CANrxData[6] = data[6]; + SDO->CANrxData[7] = data[7]; + + CO_CANrxNew_SET(SDO->CANrxNew); } else { /* block download, copy data directly */ uint8_t seqno; - SDO->CANrxData[0] = msg->data[0]; + SDO->CANrxData[0] = data[0]; seqno = SDO->CANrxData[0] & 0x7fU; SDO->timeoutTimer = 0; @@ -211,11 +213,11 @@ static void CO_SDO_receive(void *object, const CO_CANrxMsg_t *msg){ /* copy data */ for(i=1; i<8; i++) { - SDO->ODF_arg.data[SDO->bufferOffset++] = msg->data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer + SDO->ODF_arg.data[SDO->bufferOffset++] = data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer if(SDO->bufferOffset >= CO_SDO_BUFFER_SIZE) { /* buffer full, break reception */ SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - SET_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_SET(SDO->CANrxNew); break; } } @@ -223,7 +225,7 @@ static void CO_SDO_receive(void *object, const CO_CANrxMsg_t *msg){ /* break reception if last segment or block sequence is too large */ if(((SDO->CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) { SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - SET_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_SET(SDO->CANrxNew); } } else if((seqno == SDO->sequence) || (SDO->sequence == 0U)){ @@ -232,12 +234,12 @@ static void CO_SDO_receive(void *object, const CO_CANrxMsg_t *msg){ else { /* seqno is totally wrong, break reception. */ SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - SET_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_SET(SDO->CANrxNew); } } /* Optional signal to RTOS, which can resume task, which handles SDO server. */ - if(IS_CANrxNew(SDO->CANrxNew) && SDO->pFunctSignal != NULL) { + if(CO_CANrxNew_READ(SDO->CANrxNew) && SDO->pFunctSignal != NULL) { SDO->pFunctSignal(); } } @@ -316,7 +318,7 @@ CO_ReturnError_t CO_SDO_init( /* Configure object variables */ SDO->nodeId = nodeId; SDO->state = CO_SDO_ST_IDLE; - CLEAR_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_CLEAR(SDO->CANrxNew); SDO->pFunctSignal = NULL; @@ -757,7 +759,7 @@ static void CO_SDO_abort(CO_SDO_t *SDO, uint32_t code){ SDO->CANtxBuff->data[3] = SDO->ODF_arg.subIndex; CO_memcpySwap4(&SDO->CANtxBuff->data[4], &code); SDO->state = CO_SDO_ST_IDLE; - CLEAR_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_CLEAR(SDO->CANrxNew); CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); } @@ -775,19 +777,19 @@ int8_t CO_SDO_process( bool_t sendResponse = false; /* return if idle */ - if((SDO->state == CO_SDO_ST_IDLE) && (!IS_CANrxNew(SDO->CANrxNew))){ + if((SDO->state == CO_SDO_ST_IDLE) && (!CO_CANrxNew_READ(SDO->CANrxNew))){ return 0; } /* SDO is allowed to work only in operational or pre-operational NMT state */ if(!NMTisPreOrOperational){ SDO->state = CO_SDO_ST_IDLE; - CLEAR_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_CLEAR(SDO->CANrxNew); return 0; } /* Is something new to process? */ - if((!SDO->CANtxBuff->bufferFull) && ((IS_CANrxNew(SDO->CANrxNew)) || (SDO->state == CO_SDO_ST_UPLOAD_BL_SUBBLOCK))){ + if((!SDO->CANtxBuff->bufferFull) && ((CO_CANrxNew_READ(SDO->CANrxNew)) || (SDO->state == CO_SDO_ST_UPLOAD_BL_SUBBLOCK))){ uint8_t CCS = SDO->CANrxData[0] >> 5; /* Client command specifier */ /* reset timeout */ @@ -799,9 +801,9 @@ int8_t CO_SDO_process( SDO->CANtxBuff->data[4] = SDO->CANtxBuff->data[5] = SDO->CANtxBuff->data[6] = SDO->CANtxBuff->data[7] = 0; /* Is abort from client? */ - if((IS_CANrxNew(SDO->CANrxNew)) && (SDO->CANrxData[0] == CCS_ABORT)){ + if((CO_CANrxNew_READ(SDO->CANrxNew)) && (SDO->CANrxData[0] == CCS_ABORT)){ SDO->state = CO_SDO_ST_IDLE; - CLEAR_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_CLEAR(SDO->CANrxNew); return -1; } @@ -884,7 +886,7 @@ int8_t CO_SDO_process( return 0; } - /* state machine (buffer is freed (CLEAR_CANrxNew()) at the end) */ + /* state machine (buffer is freed (CO_CANrxNew_CLEAR()) at the end) */ switch(state){ uint32_t abortCode; uint16_t len, i; @@ -1309,14 +1311,14 @@ int8_t CO_SDO_process( SDO->bufferOffset = 0; SDO->sequence = 0; SDO->endOfTransfer = false; - CLEAR_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_CLEAR(SDO->CANrxNew); SDO->state = CO_SDO_ST_UPLOAD_BL_SUBBLOCK; /* continue in next case */ } case CO_SDO_ST_UPLOAD_BL_SUBBLOCK:{ /* is block confirmation received */ - if(IS_CANrxNew(SDO->CANrxNew)){ + if(CO_CANrxNew_READ(SDO->CANrxNew)){ uint8_t ackseq; uint16_t j; @@ -1395,12 +1397,12 @@ int8_t CO_SDO_process( SDO->endOfTransfer = false; /* clear flag here */ - CLEAR_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_CLEAR(SDO->CANrxNew); } /* return, if all segments was already transfered or on end of transfer */ if((SDO->sequence == SDO->blksize) || (SDO->endOfTransfer)){ - return 1;/* don't call CLEAR_CANrxNew, so return directly */ + return 1;/* don't call CO_CANrxNew_CLEAR, so return directly */ } /* reset timeout */ @@ -1436,7 +1438,7 @@ int8_t CO_SDO_process( *timerNext_ms = 0; } - /* don't call CLEAR_CANrxNew, so return directly */ + /* don't call CO_CANrxNew_CLEAR, so return directly */ return 1; } @@ -1458,7 +1460,7 @@ int8_t CO_SDO_process( } /* free buffer and send message */ - CLEAR_CANrxNew(SDO->CANrxNew); + CO_CANrxNew_CLEAR(SDO->CANrxNew); if(sendResponse) { CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); } diff --git a/stack/CO_SDOmaster.c b/stack/CO_SDOmaster.c index d0a7036a..fbff8b6e 100644 --- a/stack/CO_SDOmaster.c +++ b/stack/CO_SDOmaster.c @@ -95,31 +95,33 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_SDOclient_receive(void *object, const CO_CANrxMsg_t *msg){ +static void CO_SDOclient_receive(void *object, void *msg){ CO_SDOclient_t *SDO_C; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); SDO_C = (CO_SDOclient_t*)object; /* this is the correct pointer type of the first argument */ /* verify message length and message overflow (previous message was not processed yet) */ - if((msg->DLC == 8U) && (!IS_CANrxNew(SDO_C->CANrxNew)) && (SDO_C->state != SDO_STATE_NOTDEFINED)){ + if((DLC == 8U) && (!CO_CANrxNew_READ(SDO_C->CANrxNew)) && (SDO_C->state != SDO_STATE_NOTDEFINED)){ if(SDO_C->state != SDO_STATE_BLOCKUPLOAD_INPROGRES) { /* copy data and set 'new message' flag */ - SDO_C->CANrxData[0] = msg->data[0]; - SDO_C->CANrxData[1] = msg->data[1]; - SDO_C->CANrxData[2] = msg->data[2]; - SDO_C->CANrxData[3] = msg->data[3]; - SDO_C->CANrxData[4] = msg->data[4]; - SDO_C->CANrxData[5] = msg->data[5]; - SDO_C->CANrxData[6] = msg->data[6]; - SDO_C->CANrxData[7] = msg->data[7]; - - SET_CANrxNew(SDO_C->CANrxNew); + SDO_C->CANrxData[0] = data[0]; + SDO_C->CANrxData[1] = data[1]; + SDO_C->CANrxData[2] = data[2]; + SDO_C->CANrxData[3] = data[3]; + SDO_C->CANrxData[4] = data[4]; + SDO_C->CANrxData[5] = data[5]; + SDO_C->CANrxData[6] = data[6]; + SDO_C->CANrxData[7] = data[7]; + + CO_CANrxNew_SET(SDO_C->CANrxNew); } else { /* block upload, copy data directly */ uint8_t seqno; - SDO_C->CANrxData[0] = msg->data[0]; + SDO_C->CANrxData[0] = data[0]; seqno = SDO_C->CANrxData[0] & 0x7f; SDO_C->timeoutTimer = 0; SDO_C->timeoutTimerBLOCK = 0; @@ -133,11 +135,11 @@ static void CO_SDOclient_receive(void *object, const CO_CANrxMsg_t *msg){ /* copy data */ for(i=1; i<8; i++) { - SDO_C->buffer[SDO_C->dataSizeTransfered++] = msg->data[i]; + SDO_C->buffer[SDO_C->dataSizeTransfered++] = data[i]; if(SDO_C->dataSizeTransfered >= SDO_C->bufferSize) { /* buffer full, break reception */ SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - SET_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_SET(SDO_C->CANrxNew); break; } } @@ -145,7 +147,7 @@ static void CO_SDOclient_receive(void *object, const CO_CANrxMsg_t *msg){ /* break reception if last segment or block sequence is too large */ if(((SDO_C->CANrxData[0] & 0x80U) == 0x80U) || (SDO_C->block_seqno >= SDO_C->block_blksize)) { SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - SET_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_SET(SDO_C->CANrxNew); } } else if((seqno == SDO_C->block_seqno) || (SDO_C->block_seqno == 0U)){ @@ -154,12 +156,12 @@ static void CO_SDOclient_receive(void *object, const CO_CANrxMsg_t *msg){ else { /* seqno is totally wrong, break reception. */ SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - SET_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_SET(SDO_C->CANrxNew); } } /* Optional signal to RTOS, which can resume task, which handles SDO client. */ - if(IS_CANrxNew(SDO_C->CANrxNew) && SDO_C->pFunctSignal != NULL) { + if(CO_CANrxNew_READ(SDO_C->CANrxNew) && SDO_C->pFunctSignal != NULL) { SDO_C->pFunctSignal(); } } @@ -184,7 +186,7 @@ CO_ReturnError_t CO_SDOclient_init( /* Configure object variables */ SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); SDO_C->pst = 21; /* block transfer */ SDO_C->block_size_max = 127; /* block transfer */ @@ -239,7 +241,7 @@ CO_SDOclient_return_t CO_SDOclient_setup( /* Configure object variables */ SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); /* setup Object Dictionary variables */ if((COB_IDClientToServer & 0x80000000L) != 0 || (COB_IDServerToClient & 0x80000000L) != 0 || nodeIDOfTheSDOServer == 0){ @@ -301,7 +303,7 @@ static void CO_SDOclient_abort(CO_SDOclient_t *SDO_C, uint32_t code){ CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &code); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); } @@ -396,7 +398,7 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( } /* empty receive buffer, reset timeout timer and send message */ - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); SDO_C->timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); @@ -424,7 +426,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ if(SDO_C->SDO && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); /* If SDO server is busy return error */ if(SDO_C->SDO->state != 0){ @@ -451,14 +453,14 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* RX data ****************************************************************************************** */ - if(IS_CANrxNew(SDO_C->CANrxNew)){ + if(CO_CANrxNew_READ(SDO_C->CANrxNew)){ uint8_t SCS = SDO_C->CANrxData[0]>>5; /* Client command specifier */ /* ABORT */ if (SDO_C->CANrxData[0] == (SCS_ABORT<<5)){ SDO_C->state = SDO_STATE_NOTDEFINED; CO_memcpySwap4(pSDOabortCode , &SDO_C->CANrxData[4]); - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_endedWithServerAbort; } @@ -470,7 +472,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( if(SDO_C->bufferSize <= 4){ /* expedited transfer */ SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } else{ @@ -505,7 +507,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* is end of transfer? */ if(SDO_C->bufferOffset == SDO_C->bufferSize){ SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } SDO_C->state = SDO_STATE_DOWNLOAD_REQUEST; @@ -591,7 +593,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* SDO block download successfully transferred */ SDO_C->state = SDO_STATE_NOTDEFINED; SDO_C->timeoutTimer = 0; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } else{ @@ -608,7 +610,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( } } SDO_C->timeoutTimer = 0; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); } /* TMO *********************************************************************************************** */ @@ -801,7 +803,7 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( } /* empty receive buffer, reset timeout timer and send message */ - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); SDO_C->timeoutTimer = 0; SDO_C->timeoutTimerBLOCK =0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); @@ -833,7 +835,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ if(SDO_C->SDO && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); /* If SDO server is busy return error */ if(SDO_C->SDO->state != 0){ @@ -872,13 +874,13 @@ CO_SDOclient_return_t CO_SDOclientUpload( /* RX data ******************************************************************************** */ - if(IS_CANrxNew(SDO_C->CANrxNew)){ + if(CO_CANrxNew_READ(SDO_C->CANrxNew)){ uint8_t SCS = SDO_C->CANrxData[0]>>5; /* Client command specifier */ /* ABORT */ if (SDO_C->CANrxData[0] == (SCS_ABORT<<5)){ SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); CO_memcpySwap4(pSDOabortCode , &SDO_C->CANrxData[4]); return CO_SDOcli_endedWithServerAbort; } @@ -901,7 +903,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( /* copy data */ while(size--) SDO_C->buffer[size] = SDO_C->CANrxData[4+size]; SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } @@ -946,7 +948,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( if(SDO_C->CANrxData[0] & 0x01){ *pDataSize = SDO_C->bufferOffset; SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } /* set state */ @@ -1013,7 +1015,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( /* copy data */ while(size--) SDO_C->buffer[size] = SDO_C->CANrxData[4+size]; SDO_C->state = SDO_STATE_NOTDEFINED; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } @@ -1101,7 +1103,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( } } SDO_C->timeoutTimer = 0; - CLEAR_CANrxNew(SDO_C->CANrxNew); + CO_CANrxNew_CLEAR(SDO_C->CANrxNew); } /* TMO *************************************************************************************************** */ diff --git a/stack/CO_SYNC.c b/stack/CO_SYNC.c index 557ac110..c598313f 100644 --- a/stack/CO_SYNC.c +++ b/stack/CO_SYNC.c @@ -37,7 +37,7 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_SYNC_receive(void *object, const CO_CANrxMsg_t *msg){ +static void CO_SYNC_receive(void *object, void *msg) { CO_SYNC_t *SYNC; uint8_t operState; @@ -45,24 +45,27 @@ static void CO_SYNC_receive(void *object, const CO_CANrxMsg_t *msg){ operState = *SYNC->operatingState; if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){ + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + if(SYNC->counterOverflowValue == 0){ - if(msg->DLC == 0U){ - SET_CANrxNew(SYNC->CANrxNew); + if(DLC == 0U){ + CO_CANrxNew_SET(SYNC->CANrxNew); } else{ - SYNC->receiveError = (uint16_t)msg->DLC | 0x0100U; + SYNC->receiveError = (uint16_t)DLC | 0x0100U; } } else{ - if(msg->DLC == 1U){ - SYNC->counter = msg->data[0]; - SET_CANrxNew(SYNC->CANrxNew); + if(DLC == 1U){ + uint8_t *data = CO_CANrxMsg_readData(msg); + SYNC->counter = data[0]; + CO_CANrxNew_SET(SYNC->CANrxNew); } else{ - SYNC->receiveError = (uint16_t)msg->DLC | 0x0200U; + SYNC->receiveError = (uint16_t)DLC | 0x0200U; } } - if(IS_CANrxNew(SYNC->CANrxNew)) { + if(CO_CANrxNew_READ(SYNC->CANrxNew)) { SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; } } @@ -252,7 +255,7 @@ CO_ReturnError_t CO_SYNC_init( SYNC->curentSyncTimeIsInsideWindow = true; - CLEAR_CANrxNew(SYNC->CANrxNew); + CO_CANrxNew_CLEAR(SYNC->CANrxNew); SYNC->CANrxToggle = false; SYNC->timer = 0; SYNC->counter = 0; @@ -309,10 +312,10 @@ uint8_t CO_SYNC_process( if(timerNew > SYNC->timer) SYNC->timer = timerNew; /* was SYNC just received */ - if(IS_CANrxNew(SYNC->CANrxNew)){ + if(CO_CANrxNew_READ(SYNC->CANrxNew)){ SYNC->timer = 0; ret = 1; - CLEAR_CANrxNew(SYNC->CANrxNew); + CO_CANrxNew_CLEAR(SYNC->CANrxNew); } /* SYNC producer */ @@ -348,7 +351,7 @@ uint8_t CO_SYNC_process( CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); } else { - CLEAR_CANrxNew(SYNC->CANrxNew); + CO_CANrxNew_CLEAR(SYNC->CANrxNew); } /* verify error from receive function */ diff --git a/stack/CO_TIME.c b/stack/CO_TIME.c index 446e56b5..96223623 100644 --- a/stack/CO_TIME.c +++ b/stack/CO_TIME.c @@ -23,7 +23,11 @@ * limitations under the License. */ -#include "CANopen.h" +#include "CO_driver.h" +#include "CO_SDO.h" +#include "CO_Emergency.h" +#include "CO_NMT_Heartbeat.h" +#include "CO_TIME.h" /* * Read received message from CAN module. @@ -31,20 +35,23 @@ * Function will be called (by CAN receive interrupt) every time, when CAN * message with correct identifier will be received. */ -static void CO_TIME_receive(void *object, const CO_CANrxMsg_t *msg){ +static void CO_TIME_receive(void *object, void *msg){ CO_TIME_t *TIME; uint8_t operState; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); TIME = (CO_TIME_t*)object; /* this is the correct pointer type of the first argument */ operState = *TIME->operatingState; + if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){ - SET_CANrxNew(TIME->CANrxNew); // Process Time from msg buffer - CO_memcpy((uint8_t*)&TIME->Time.ullValue, msg->data, msg->DLC); + CO_memcpy((uint8_t*)&TIME->Time.ullValue, data, DLC); + CO_CANrxNew_SET(TIME->CANrxNew); } else{ - TIME->receiveError = (uint16_t)msg->DLC; + TIME->receiveError = (uint16_t)DLC; } } @@ -78,7 +85,7 @@ CO_ReturnError_t CO_TIME_init( if(TIME->periodTimeoutTime < TIMECyclePeriod) TIME->periodTimeoutTime = 0xFFFFFFFFL; - CLEAR_CANrxNew(TIME->CANrxNew); + CO_CANrxNew_CLEAR(TIME->CANrxNew); TIME->timer = 0; TIME->receiveError = 0U; @@ -152,7 +159,7 @@ uint8_t CO_TIME_process( CO_errorReport(TIME->em, CO_EM_TIME_TIMEOUT, CO_EMC_COMMUNICATION, TIME->timer); } else { - CLEAR_CANrxNew(TIME->CANrxNew); + CO_CANrxNew_CLEAR(TIME->CANrxNew); } /* verify error from receive function */ diff --git a/stack/CO_TIME.h b/stack/CO_TIME.h index 1c80acaf..0884a6f3 100644 --- a/stack/CO_TIME.h +++ b/stack/CO_TIME.h @@ -120,6 +120,8 @@ typedef struct{ * @param TIMECyclePeriod TIME period in ms (may also be used in consumer mode for timeout detection (1.5x period)). * @param CANdevRx CAN device for TIME reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. + * @param CANdevTx CAN device for TIME transmission. + * @param CANdevTxIdx Index of transmit buffer in the above CAN device. * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ diff --git a/stack/CO_driver.h b/stack/CO_driver.h index c09615cd..72f2a833 100644 --- a/stack/CO_driver.h +++ b/stack/CO_driver.h @@ -1,7 +1,5 @@ /** - * CAN module object for generic microcontroller. - * - * This file is a template for other microcontrollers. + * Interface between CAN hardware and CANopenNode. * * @file CO_driver.h * @ingroup CO_driver @@ -33,272 +31,412 @@ extern "C" { #endif -/* Include processor header file */ -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ -#include /* for 'true', 'false' */ - +#include "CO_driver_target.h" /** * @defgroup CO_driver Driver * @ingroup CO_CANopen * @{ * - * Microcontroller specific code for CANopenNode. - * - * This file contains type definitions, functions and macros for: - * - Basic data types. - * - Receive and transmit buffers for CANopen messages. - * - Interaction with CAN module on the microcontroller. - * - CAN receive and transmit interrupts. - * - * This file is not only a CAN driver. There are no classic CAN queues for CAN - * messages. This file provides direct connection with other CANopen - * objects. It tries to provide fast responses and tries to avoid unnecessary - * calculations and memory consumptions. - * - * CO_CANmodule_t contains an array of _Received message objects_ (of type - * CO_CANrx_t) and an array of _Transmit message objects_ (of type CO_CANtx_t). - * Each CANopen communication object owns one member in one of the arrays. - * For example Heartbeat producer generates one CANopen transmitting object, - * so it has reserved one member in CO_CANtx_t array. - * SYNC module may produce sync or consume sync, so it has reserved one member - * in CO_CANtx_t and one member in CO_CANrx_t array. - * - * ###Reception of CAN messages. - * Before CAN messages can be received, each member in CO_CANrx_t must be - * initialized. CO_CANrxBufferInit() is called by CANopen module, which - * uses specific member. For example @ref CO_HBconsumer uses multiple members - * in CO_CANrx_t array. (It monitors multiple heartbeat messages from remote - * nodes.) It must call CO_CANrxBufferInit() multiple times. - * - * Main arguments to the CO_CANrxBufferInit() function are CAN identifier - * and a pointer to callback function. Those two arguments (and some others) - * are copied to the member of the CO_CANrx_t array. - * - * Callback function is a function, specified by specific CANopen module - * (for example by @ref CO_HBconsumer). Each CANopen module defines own - * callback function. Callback function will process the received CAN message. - * It will copy the necessary data from CAN message to proper place. It may - * also trigger additional task, which will further process the received message. - * Callback function must be fast and must only make the necessary calculations - * and copying. - * - * Received CAN messages are processed by CAN receive interrupt function. - * After CAN message is received, function first tries to find matching CAN - * identifier from CO_CANrx_t array. If found, then a corresponding callback - * function is called. - * - * Callback function accepts two parameters: - * - object is pointer to object registered by CO_CANrxBufferInit(). - * - msg is pointer to CAN message of type CO_CANrxMsg_t. - * - * Callback function must return #CO_ReturnError_t: CO_ERROR_NO, - * CO_ERROR_RX_OVERFLOW, CO_ERROR_RX_PDO_OVERFLOW, CO_ERROR_RX_MSG_LENGTH or - * CO_ERROR_RX_PDO_LENGTH. - * - * - * ###Transmission of CAN messages. - * Before CAN messages can be transmitted, each member in CO_CANtx_t must be - * initialized. CO_CANtxBufferInit() is called by CANopen module, which - * uses specific member. For example Heartbeat producer must initialize it's - * member in CO_CANtx_t array. - * - * CO_CANtxBufferInit() returns a pointer of type CO_CANtx_t, which contains buffer - * where CAN message data can be written. CAN message is send with calling - * CO_CANsend() function. If at that moment CAN transmit buffer inside - * microcontroller's CAN module is free, message is copied directly to CAN module. - * Otherwise CO_CANsend() function sets _bufferFull_ flag to true. Message will be - * then sent by CAN TX interrupt as soon as CAN module is freed. Until message is - * not copied to CAN module, its contents must not change. There may be multiple - * _bufferFull_ flags in CO_CANtx_t array set to true. In that case messages with - * lower index inside array will be sent first. + * Interface between the hardware and the CANopenNode. + * + * CANopenNode is designed for speed and portability. It runs efficiently on + * devices from simple 16-bit microcontrollers to PC computers. It can run in + * multiple threads. Reception of CAN messages is pre-processed with very fast + * functions. Time critical objects, such as PDO or SYNC are processed in + * real-time thread and other objects are processed in normal thread. See + * Flowchart in [README.md](README.md) for more information. + * + * @anchor CO_obj + * #### CANopenNode Object + * CANopenNode is implemented as a collection of different objects, for example + * SDO, SYNC, Emergency, PDO, NMT, Heartbeat, etc. Code is written in C language + * and tries to be object oriented. So each CANopenNode Object is implemented in + * a pair of .h/.c files. It basically contains a structure with all necessary + * variables and some functions which operates on it. CANopenNode Object is + * usually connected with one or more CAN receive or transmit Message Objects. + * (CAN message Object is a CAN message with specific 11-bit CAN identifier + * (usually one fixed or a range).) + * + * #### Hardware interface of CANopenNode + * It consists of minimum three files: + * - **CO_driver.h** file declares common functions. This file is part of the + * CANopenNode. It is included from each .c file from CANopenNode. + * - **CO_driver_target.h** file declares microcontroller specific type + * declarations and defines some macros, which are necessary for CANopenNode. + * This file is included from CO_driver.h. + * - **CO_driver.c** file defines functions declared in CO_driver.h. + * + * **CO_driver_target.h** and **CO_driver.c** files are specific for each + * different microcontroller and are not part of CANopenNode. There are separate + * projects for different microcontrollers, which usually include CANopenNode as + * a git submodule. CANopenNode only includes those two files in the `example` + * directory and they are basically empty. It should be possible to compile the + * `CANopenNode/example` on any system, however compiled program is not usable. + * CO_driver.h contains documentation for all necessary macros, types and + * functions. + * + * See [CANopenNode/Wiki](https://github.com/CANopenNode/CANopenNode/wiki) for a + * known list of available implementations of CANopenNode on different systems + * and microcontrollers. Everybody is welcome to extend the list with a link to + * his own implementation. + * + * Implementation of the hardware interface for specific microcontroller is not + * always an easy task. For reliable and efficient operation it is necessary to + * know some parts of the target microcontroller in detail (for example threads + * (or interrupts), CAN module, etc.). */ - +/* Macros and declarations in following part are only used for documentation. */ +#ifdef CO_DOXYGEN /** - * @name Critical sections - * CANopenNode is designed to run in different threads, as described in README. - * Threads are implemented differently in different systems. In microcontrollers - * threads are interrupts with different priorities, for example. - * It is necessary to protect sections, where different threads access to the - * same resource. In simple systems interrupts or scheduler may be temporary - * disabled between access to the shared resource. Otherwise mutexes or - * semaphores can be used. - * - * ####Reentrant functions. - * Functions CO_CANsend() from C_driver.h, CO_errorReport() from CO_Emergency.h - * and CO_errorReset() from CO_Emergency.h may be called from different threads. - * Critical sections must be protected. Eather by disabling scheduler or - * interrupts or by mutexes or semaphores. + * @defgroup CO_dataTypes Basic definitions + * @{ * - * ####Object Dictionary variables. - * In general, there are two threads, which accesses OD variables: mainline and - * timer. CANopenNode initialization and SDO server runs in mainline. PDOs runs - * in faster timer thread. Processing of PDOs must not be interrupted by - * mainline. Mainline thread must protect sections, which accesses the same OD - * variables as timer thread. This care must also take the application. Note - * that not all variables are allowed to be mapped to PDOs, so they may not need - * to be protected. SDO server protects sections with access to OD variables. + * Target specific basic definitions and data types according to Misra C + * specification. * - * ####CAN receive thread. - * It partially processes received CAN data and puts them into appropriate - * objects. Objects are later processed. It does not need protection of - * critical sections. There is one circumstance, where CANrx should be disabled: - * After presence of SYNC message on CANopen bus, CANrx should be temporary - * disabled until all receive PDOs are processed. See also CO_SYNC.h file and - * CO_SYNC_initCallback() function. - * @{ + * Must be defined in the **CO_driver_target.h** file. + * + * Depending on processor or compiler architecture, one of the two macros must + * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little + * endian. + * + * Basic data types may be specified differently on different architectures. + * Usually `true` and `false` are defined in ``, `NULL` is defined in + * ``, `int8_t` to `uint64_t` are defined in ``. */ - #define CO_LOCK_CAN_SEND() /**< Lock critical section in CO_CANsend() */ - #define CO_UNLOCK_CAN_SEND()/**< Unlock critical section in CO_CANsend() */ - - #define CO_LOCK_EMCY() /**< Lock critical section in CO_errorReport() or CO_errorReset() */ - #define CO_UNLOCK_EMCY() /**< Unlock critical section in CO_errorReport() or CO_errorReset() */ - - #define CO_LOCK_OD() /**< Lock critical section when accessing Object Dictionary */ - #define CO_UNLOCK_OD() /**< Unock critical section when accessing Object Dictionary */ +/** CO_LITTLE_ENDIAN or CO_BIG_ENDIAN must be defined */ +#define CO_LITTLE_ENDIAN +/** NULL, for general use */ +#define NULL (0) +/** Logical true, for general use */ +#define true 1 +/** Logical false, for general use */ +#define false 0 +/** Boolean data type for general use */ +typedef unsigned char bool_t; +/** INTEGER8 in CANopen (0002h), 8-bit signed integer */ +typedef signed char int8_t; +/** INTEGER16 in CANopen (0003h), 16-bit signed integer */ +typedef signed int int16_t; +/** INTEGER32 in CANopen (0004h), 32-bit signed integer */ +typedef signed long int int32_t; +/** INTEGER64 in CANopen (0015h), 64-bit signed integer */ +typedef signed long long int int64_t; +/** UNSIGNED8 in CANopen (0005h), 8-bit unsigned integer */ +typedef unsigned char uint8_t; +/** UNSIGNED16 in CANopen (0006h), 16-bit unsigned integer */ +typedef unsigned int uint16_t; +/** UNSIGNED32 in CANopen (0007h), 32-bit unsigned integer */ +typedef unsigned long int uint32_t; +/** UNSIGNED64 in CANopen (001Bh), 64-bit unsigned integer */ +typedef unsigned long long int uint64_t; +/** REAL32 in CANopen (0008h), single precision floating point value, 32-bit */ +typedef float float32_t; +/** REAL64 in CANopen (0011h), double precision floating point value, 64-bit */ +typedef long double float64_t; +/** VISIBLE_STRING in CANopen (0009h), string of signed 8-bit values */ +typedef char char_t; +/** OCTET_STRING in CANopen (000Ah), string of unsigned 8-bit values */ +typedef unsigned char oChar_t; +/** DOMAIN in CANopen (000Fh), used to transfer a large block of data */ +typedef unsigned char domain_t; /** @} */ + /** - * @name Syncronisation functions - * syncronisation for message buffer for communication between CAN receive and - * message processing threads. - * - * If receive function runs inside IRQ, no further synchronsiation is needed. - * Otherwise, some kind of synchronsiation has to be included. The following - * example uses GCC builtin memory barrier __sync_synchronize(). A comprehensive - * list can be found here: https://gist.github.com/leo-yuriev/ba186a6bf5cf3a27bae7 - * \code{.c} - #define CANrxMemoryBarrier() {__sync_synchronize();} - * \endcode + * @defgroup CO_CAN_Message_reception Reception of CAN messages * @{ + * + * Target specific definitions and description of CAN message reception + * + * CAN messages in CANopenNode are usually received by its own thread or higher + * priority interrupt. Received CAN messages are first filtered by hardware or + * by software. Thread then examines its 11-bit CAN-id and mask and determines, + * to which \ref CO_obj "CANopenNode Object" it belongs to. After that it calls + * predefined CANrx_callback() function, which quickly pre-processes the message + * and fetches the relevant data. CANrx_callback() function is defined by each + * \ref CO_obj "CANopenNode Object" separately. Pre-processed fetched data are + * later processed in another thread. + * + * If \ref CO_obj "CANopenNode Object" reception of specific CAN message, it + * must first configure its own CO_CANrx_t object with the CO_CANrxBufferInit() + * function. */ -/** Memory barrier */ -#define CANrxMemoryBarrier() -/** Check if new message has arrived */ -#define IS_CANrxNew(rxNew) ((uintptr_t)rxNew) -/** Set new message flag */ -#define SET_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)1L;} -/** Clear new message flag */ -#define CLEAR_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)0L;} -/** @} */ /** - * @defgroup CO_dataTypes Data types - * @{ + * CAN receive callback function which pre-processes received CAN message + * + * It is called by fast CAN receive thread. Each \ref CO_obj "CANopenNode + * Object" defines its own and registers it with CO_CANrxBufferInit(), by + * passing function pointer. * - * According to Misra C + * @param object pointer to specific \ref CO_obj "CANopenNode Object", + * registered with CO_CANrxBufferInit() + * @param rxMsg pointer to received CAN message */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; /**< bool_t */ - typedef float float32_t; /**< float32_t */ - typedef long double float64_t; /**< float64_t */ - typedef char char_t; /**< char_t */ - typedef unsigned char oChar_t; /**< oChar_t */ - typedef unsigned char domain_t; /**< domain_t */ -/** @} */ +void CANrx_callback(void *object, void *rxMsg); +/** + * CANrx_callback() can read CAN identifier from received CAN message + * + * Must be defined in the **CO_driver_target.h** file. + * + * This is target specific function and is specific for specific + * microcontroller. It is best to implement it by using inline function or + * macro. `rxMsg` parameter should cast to a ponter to structure. For best + * efficiency structure may have the same alignment as CAN registers inside CAN + * module. + * + * @param rxMsg Pointer to received message + * @return 11-bit CAN standard identifier. + */ +uint16_t CO_CANrxMsg_readIdent(void *rxMsg); /** - * Return values of some CANopen functions. If function was executed - * successfully it returns 0 otherwise it returns <0. + * CANrx_callback() can read Data Length Code from received CAN message + * + * See also CO_CANrxMsg_readIdent(): + * + * @param rxMsg Pointer to received message + * @return data length in bytes (0 to 8) */ -typedef enum{ - CO_ERROR_NO = 0, /**< Operation completed successfully */ - CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ - CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ - CO_ERROR_TIMEOUT = -3, /**< Function timeout */ - CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function CO_CANmodule_init() */ - CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed yet */ - CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ - CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ - CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ - CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, buffer full */ - CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ - CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not confugured properly */ - CO_ERROR_PARAMETERS = -12, /**< Error in function function parameters */ - CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ - CO_ERROR_CRC = -14, /**< CRC does not match */ - CO_ERROR_TX_BUSY = -15, /**< Sending rejected because driver is busy. Try again */ - CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current state */ - CO_ERROR_SYSCALL = -17, /**< Syscall failed */ - CO_ERROR_INVALID_STATE = -18 /**< Driver not ready */ -}CO_ReturnError_t; +uint8_t CO_CANrxMsg_readDLC(void *rxMsg); +/** + * CANrx_callback() can read pointer to data from received CAN message + * + * See also CO_CANrxMsg_readIdent(): + * + * @param rxMsg Pointer to received message + * @return pointer to data buffer + */ +uint8_t *CO_CANrxMsg_readData(void *rxMsg); /** - * CAN receive message structure as aligned in CAN module. It is different in - * different microcontrollers. It usually contains other variables. + * Configuration object for CAN received message for specific \ref CO_obj + * "CANopenNode Object". + * + * Must be defined in the **CO_driver_target.h** file. + * + * Data fields of this structure are used exclusively by the driver. Usually it + * has the following data fields, but they may differ for different + * microcontrollers. Array of multiple CO_CANrx_t objects is included inside + * CO_CANmodule_t. */ -typedef struct{ - /** CAN identifier. It must be read through CO_CANrxMsg_readIdent() function. */ - uint32_t ident; - uint8_t DLC ; /**< Length of CAN message */ - uint8_t data[8]; /**< 8 data bytes */ -}CO_CANrxMsg_t; +typedef struct { + uint16_t ident; /**< Standard CAN Identifier (bits 0..10) + RTR (bit 11) */ + uint16_t mask; /**< Standard CAN Identifier mask with the same alignment as + ident */ + void *object; /**< \ref CO_obj "CANopenNode Object" initialized in from + CO_CANrxBufferInit() */ + void (*pCANrx_callback)( + void *object, void *message); /**< Pointer to CANrx_callback() + initialized in CO_CANrxBufferInit() */ +} CO_CANrx_t; +/** @} */ + +/** + * @defgroup CO_CAN_Message_transmission Transmission of CAN messages + * @{ + * + * Target specific definitions and description of CAN message transmission + * + * If \ref CO_obj "CANopenNode Object" needs transmitting CAN message, it must + * first configure its own CO_CANtx_t object with the CO_CANtxBufferInit() + * function. CAN message can then be sent with CO_CANsend() function. If at that + * moment CAN transmit buffer inside microcontroller's CAN module is free, + * message is copied directly to the CAN module. Otherwise CO_CANsend() function + * sets _bufferFull_ flag to true. Message will be then sent by CAN TX interrupt + * as soon as CAN module is freed. Until message is not copied to CAN module, + * its contents must not change. If there are multiple CO_CANtx_t objects with + * _bufferFull_ flag set to true, then CO_CANtx_t with lower index will be sent + * first. + */ /** - * Received message object + * Configuration object for CAN transmit message for specific \ref CO_obj + * "CANopenNode Object". + * + * Must be defined in the **CO_driver_target.h** file. + * + * Data fields of this structure are used exclusively by the driver. Usually it + * has the following data fields, but they may differ for different + * microcontrollers. Array of multiple CO_CANtx_t objects is included inside + * CO_CANmodule_t. */ -typedef struct{ - uint16_t ident; /**< Standard CAN Identifier (bits 0..10) + RTR (bit 11) */ - uint16_t mask; /**< Standard Identifier mask with same alignment as ident */ - void *object; /**< From CO_CANrxBufferInit() */ - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); /**< From CO_CANrxBufferInit() */ -}CO_CANrx_t; +typedef struct { + uint32_t ident; /**< CAN identifier as aligned in CAN module */ + uint8_t DLC; /**< Length of CAN message */ + uint8_t data[8]; /**< 8 data bytes */ + volatile bool_t bufferFull; /**< True if previous message is still in the + buffer */ + volatile bool_t syncFlag; /**< Synchronous PDO messages has this flag set. + It prevents them to be sent outside the synchronous window */ +} CO_CANtx_t; +/** @} */ /** - * Transmit message object. + * Complete CAN module object. + * + * Must be defined in the **CO_driver_target.h** file. + * + * Usually it has the following data fields, but they may differ for different + * microcontrollers. */ -typedef struct{ - uint32_t ident; /**< CAN identifier as aligned in CAN module */ - uint8_t DLC ; /**< Length of CAN message. (DLC may also be part of ident) */ - uint8_t data[8]; /**< 8 data bytes */ - volatile bool_t bufferFull; /**< True if previous message is still in buffer */ - /** Synchronous PDO messages has this flag set. It prevents them to be sent outside the synchronous window */ - volatile bool_t syncFlag; -}CO_CANtx_t; +typedef struct { + void *CANdriverState; /**< From CO_CANmodule_init() */ + CO_CANrx_t *rxArray; /**< From CO_CANmodule_init() */ + uint16_t rxSize; /**< From CO_CANmodule_init() */ + 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 */ + volatile bool_t useCANrxFilters; /**< Value different than zero indicates, + that CAN module hardware filters are used for CAN reception. If + there is not enough hardware filters, they won't be used. In this + case will be *all* received CAN messages processed by software. */ + volatile bool_t bufferInhibitFlag; /**< If flag is true, then message in + transmit buffer is synchronous PDO message, which will be aborted, + if CO_clearPendingSyncPDOs() function will be called by application. + This may be necessary if Synchronous window time was expired. */ + volatile bool_t firstCANtxMessage; /**< Equal to 1, when the first + transmitted message (bootup message) is in CAN TX buffers */ + volatile uint16_t CANtxCount; /**< Number of messages in transmit + buffer, which are waiting to be copied to the CAN module */ + uint32_t errOld; /**< Previous state of CAN errors */ + void *em; /**< Emergency object */ +} CO_CANmodule_t; /** - * CAN module object. It may be different in different microcontrollers. + * @defgroup CO_critical_sections Critical sections + * @{ + * CANopenNode is designed to run in different threads, as described in + * [README.md](README.md). Threads are implemented differently in different + * systems. In microcontrollers threads are interrupts with different + * priorities, for example. It is necessary to protect sections, where different + * threads access to the same resource. In simple systems interrupts or + * scheduler may be temporary disabled between access to the shared resource. + * Otherwise mutexes or semaphores can be used. + * + * #### Reentrant functions + * Functions CO_CANsend() from C_driver.h, CO_errorReport() from CO_Emergency.h + * and CO_errorReset() from CO_Emergency.h may be called from different threads. + * Critical sections must be protected. Either by disabling scheduler or + * interrupts or by mutexes or semaphores. + * + * #### Object Dictionary variables + * In general, there are two threads, which accesses OD variables: mainline and + * timer. CANopenNode initialization and SDO server runs in mainline. PDOs runs + * in faster timer thread. Processing of PDOs must not be interrupted by + * mainline. Mainline thread must protect sections, which accesses the same OD + * variables as timer thread. This care must also take the application. Note + * that not all variables are allowed to be mapped to PDOs, so they may not need + * to be protected. SDO server protects sections with access to OD variables. + * + * #### Synchronization functions for CAN receive + * After CAN message is received, it is pre-processed in CANrx_callback(), which + * copies some data into appropriate object and at the end sets **new_message** + * flag. This flag is then pooled in another thread, which further processes the + * message. The problem is, that compiler optimization may shuffle memory + * operations, so it is necessary to ensure, that **new_message** flag is surely + * set at the end. It is necessary to use [Memory + * barrier](https://en.wikipedia.org/wiki/Memory_barrier). + * + * If receive function runs inside IRQ, no further synchronization is needed. + * Otherwise, some kind of synchronization has to be included. The following + * example uses GCC builtin memory barrier `__sync_synchronize()`. More + * information can be found + * [here](https://stackoverflow.com/questions/982129/what-does-sync-synchronize-do#982179). */ -typedef struct{ - void *CANdriverState; /**< From CO_CANmodule_init() */ - CO_CANrx_t *rxArray; /**< From CO_CANmodule_init() */ - uint16_t rxSize; /**< From CO_CANmodule_init() */ - 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 */ - /** Value different than zero indicates, that CAN module hardware filters - * are used for CAN reception. If there is not enough hardware filters, - * they won't be used. In this case will be *all* received CAN messages - * processed by software. */ - volatile bool_t useCANrxFilters; - /** If flag is true, then message in transmitt buffer is synchronous PDO - * message, which will be aborted, if CO_clearPendingSyncPDOs() function - * will be called by application. This may be necessary if Synchronous - * window time was expired. */ - volatile bool_t bufferInhibitFlag; - /** Equal to 1, when the first transmitted message (bootup message) is in CAN TX buffers */ - volatile bool_t firstCANtxMessage; - /** Number of messages in transmit buffer, which are waiting to be copied to the CAN module */ - volatile uint16_t CANtxCount; - uint32_t errOld; /**< Previous state of CAN errors */ - void *em; /**< Emergency object */ -}CO_CANmodule_t; + +/** Lock critical section in CO_CANsend() */ +#define CO_LOCK_CAN_SEND() +/** Unlock critical section in CO_CANsend() */ +#define CO_UNLOCK_CAN_SEND() +/** Lock critical section in CO_errorReport() or CO_errorReset() */ +#define CO_LOCK_EMCY() +/** Unlock critical section in CO_errorReport() or CO_errorReset() */ +#define CO_UNLOCK_EMCY() +/** Lock critical section when accessing Object Dictionary */ +#define CO_LOCK_OD() +/** Unock critical section when accessing Object Dictionary */ +#define CO_UNLOCK_OD() + +/** Check if new message has arrived */ +#define CO_CANrxNew_READ(rxNew) ((uintptr_t)rxNew) +/** Set new message flag */ +#define CO_CANrxNew_SET(rxNew) { __sync_synchronize(); rxNew = (void *)1L; } +/** Clear new message flag */ +#define CO_CANrxNew_CLEAR(rxNew) { __sync_synchronize(); rxNew = (void *)0L; } + +/** @} */ +#endif /* CO_DOXYGEN */ /** - * Endianness. + * Default CANopen identifiers. * - * Depending on processor or compiler architecture, one of the two macros must - * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little endian. + * Default CANopen identifiers for CANopen communication objects. Same as + * 11-bit addresses of CAN messages. These are default identifiers and + * can be changed in CANopen. Especially PDO identifiers are confgured + * in PDO linking phase of the CANopen network configuration. */ -#define CO_LITTLE_ENDIAN +typedef enum { + CO_CAN_ID_NMT_SERVICE = 0x000, /**< 0x000, Network management */ + CO_CAN_ID_SYNC = 0x080, /**< 0x080, Synchronous message */ + CO_CAN_ID_EMERGENCY = 0x080, /**< 0x080, Emergency messages (+nodeID) */ + CO_CAN_ID_TIME = 0x100, /**< 0x100, Time message */ + CO_CAN_ID_TPDO_1 = 0x180, /**< 0x180, Default TPDO1 (+nodeID) */ + CO_CAN_ID_RPDO_1 = 0x200, /**< 0x200, Default RPDO1 (+nodeID) */ + CO_CAN_ID_TPDO_2 = 0x280, /**< 0x280, Default TPDO2 (+nodeID) */ + CO_CAN_ID_RPDO_2 = 0x300, /**< 0x300, Default RPDO2 (+nodeID) */ + CO_CAN_ID_TPDO_3 = 0x380, /**< 0x380, Default TPDO3 (+nodeID) */ + CO_CAN_ID_RPDO_3 = 0x400, /**< 0x400, Default RPDO3 (+nodeID) */ + CO_CAN_ID_TPDO_4 = 0x480, /**< 0x480, Default TPDO4 (+nodeID) */ + CO_CAN_ID_RPDO_4 = 0x500, /**< 0x500, Default RPDO5 (+nodeID) */ + CO_CAN_ID_TSDO = 0x580, /**< 0x580, SDO response from server (+nodeID) */ + CO_CAN_ID_RSDO = 0x600, /**< 0x600, SDO request from client (+nodeID) */ + CO_CAN_ID_HEARTBEAT = 0x700, /**< 0x700, Heartbeat message */ + CO_CAN_ID_LSS_CLI = 0x7E4, /**< 0x7E4, LSS response from server to client */ + CO_CAN_ID_LSS_SRV = 0x7E5 /**< 0x7E5, LSS request from client to server */ +} CO_Default_CAN_ID_t; + + +/** + * Return values of some CANopen functions. If function was executed + * successfully it returns 0 otherwise it returns <0. + */ +typedef enum { + CO_ERROR_NO = 0, /**< Operation completed successfully */ + CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ + CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ + CO_ERROR_TIMEOUT = -3, /**< Function timeout */ + CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function + CO_CANmodule_init() */ + CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed + yet */ + CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ + CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ + CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ + CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, + buffer full */ + CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ + CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not confugured + properly */ + CO_ERROR_PARAMETERS = -12, /**< Error in function function parameters*/ + CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ + CO_ERROR_CRC = -14, /**< CRC does not match */ + CO_ERROR_TX_BUSY = -15, /**< Sending rejected because driver is + busy. Try again */ + CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current + state */ + CO_ERROR_SYSCALL = -17, /**< Syscall failed */ + CO_ERROR_INVALID_STATE = -18 /**< Driver not ready */ +} CO_ReturnError_t; /** @@ -312,7 +450,7 @@ void CO_CANsetConfigurationMode(void *CANdriverState); /** * Request CAN normal (opearational) mode and *wait* untill it is set. * - * @param CANmodule This object. + * @param CANmodule CO_CANmodule_t object. */ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); @@ -326,22 +464,23 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); * @param CANmodule This object will be initialized. * @param CANdriverState User-provided CAN module structure.. * @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 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 Valid values are (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. - * If value is illegal, bitrate defaults to 125. + * @param txSize Size of the above array. Must be equal to number of + * transmitting CAN objects. + * @param CANbitRate Valid values are (in kbps): 10, 20, 50, 125, 250, 500, 800, + * 1000. If value is illegal, bitrate defaults to 125. * * Return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -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); +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); /** @@ -352,15 +491,6 @@ CO_ReturnError_t CO_CANmodule_init( 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. * @@ -375,23 +505,23 @@ uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); * 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. + * @param object CANopen object, to which buffer is connected. It will be used + * as an argument to CANrx_callback. Its type is (void), CANrx_callback will + * change its type back to the correct object type. + * @param CANrx_callback 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, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); +CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + uint16_t mask, + bool_t rtr, + void *object, + void (*CANrx_callback)(void *object, + void *message)); /** @@ -405,20 +535,19 @@ CO_ReturnError_t CO_CANrxBufferInit( * @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 This flag bit is used for synchronous TPDO messages. If it is set, - * message will not be sent, if curent time is outside synchronous window. + * @param syncFlag This flag bit is used for synchronous TPDO messages. If it is + * set, message will not be sent, if curent time is outside synchronous window. * * @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, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); +CO_CANtx_t *CO_CANtxBufferInit(CO_CANmodule_t *CANmodule, + uint16_t index, + uint16_t ident, + bool_t rtr, + uint8_t noOfBytes, + bool_t syncFlag); /** @@ -460,19 +589,10 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); */ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - -/** - * Receives and transmits CAN messages. - * - * Function must be called directly from high priority CAN interrupt. - * - * @param CANmodule This object. - */ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule); +/** @} */ /* @defgroup CO_driver Driver */ #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* CO_DRIVER_H */ diff --git a/stack/CO_trace.c b/stack/CO_trace.c index cf63f75d..0ccc248d 100644 --- a/stack/CO_trace.c +++ b/stack/CO_trace.c @@ -24,9 +24,6 @@ #include "CO_trace.h" - -#if CO_NO_TRACE > 0 - #include #include @@ -503,5 +500,3 @@ void CO_trace_process(CO_trace_t *trace, uint32_t timestamp) { trace->lastTimeStamp = timestamp; } } - -#endif /* CO_NO_TRACE */ diff --git a/stack/CO_trace.h b/stack/CO_trace.h index eb7f0d4e..822bd108 100644 --- a/stack/CO_trace.h +++ b/stack/CO_trace.h @@ -31,9 +31,8 @@ extern "C" { #endif -#include "CANopen.h" - -#if CO_NO_TRACE > 0 +#include "CO_driver.h" +#include "CO_SDO.h" /** @@ -121,7 +120,7 @@ typedef struct { * @param valueBuffer Memory block for storing value records. * @param bufferSize Size of the above buffers. * @param map Map to variable in Object Dictionary, which will be monitored. Same structure as in PDO. - * @param Format Format of the plot. If first bit is 1, above variable is unsigned. For more info see Object Dictionary. + * @param format Format of the plot. If first bit is 1, above variable is unsigned. For more info see Object Dictionary. * @param trigger If different than zero, trigger time is recorded, when variable goes through threshold. * @param threshold Used with trigger. * @param value Pointer to variable, which will show last value of the variable. @@ -164,8 +163,6 @@ void CO_trace_init( */ void CO_trace_process(CO_trace_t *trace, uint32_t timestamp); -#endif /* CO_NO_TRACE */ - #ifdef __cplusplus } #endif /*__cplusplus*/ From 8e33f80b8fa7d1ee7de1fbef14a226c5c6383462 Mon Sep 17 00:00:00 2001 From: Janez Date: Sun, 19 Jan 2020 02:36:18 +0100 Subject: [PATCH 004/520] minor corrections --- example/CO_driver.c | 2 +- stack/CO_TIME.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/CO_driver.c b/example/CO_driver.c index 532acbd8..bda7b6c4 100644 --- a/example/CO_driver.c +++ b/example/CO_driver.c @@ -77,7 +77,7 @@ CO_ReturnError_t CO_CANmodule_init( for(i=0U; itimer = timerNew; /* was TIME just received */ - if(TIME->CANrxNew){ + if(CO_CANrxNew_READ(TIME->CANrxNew)){ TIME->timer = 0; ret = 1; - CLEAR_CANrxNew(TIME->CANrxNew); + CO_CANrxNew_CLEAR(TIME->CANrxNew); } /* TIME producer */ From 63df34d19447909e6c731a76dabf4af4493cfd64 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 20 Jan 2020 22:05:17 +0100 Subject: [PATCH 005/520] Rename CANdriverState to CANptr --- CANopen.c | 22 +++++++++++----------- CANopen.h | 12 ++++++------ example/CO_driver.c | 6 +++--- example/CO_driver_target.h | 3 +-- stack/CO_driver.h | 10 +++++----- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/CANopen.c b/CANopen.c index daaaaafa..5443aeaa 100644 --- a/CANopen.c +++ b/CANopen.c @@ -157,7 +157,7 @@ CO_ReturnError_t CO_new(void); CO_ReturnError_t CO_CANinit( - void *CANdriverState, + void *CANptr, uint16_t bitRate); CO_ReturnError_t CO_LSSinit( @@ -170,7 +170,7 @@ CO_ReturnError_t CO_CANopenInit( #else /* CO_NO_LSS_SERVER == 0 */ CO_ReturnError_t CO_init( - void *CANdriverState, + void *CANptr, uint8_t nodeId, uint16_t bitRate); @@ -439,17 +439,17 @@ CO_ReturnError_t CO_new(void) /******************************************************************************/ CO_ReturnError_t CO_CANinit( - void *CANdriverState, + void *CANptr, uint16_t bitRate) { CO_ReturnError_t err; CO->CANmodule[0]->CANnormal = false; - CO_CANsetConfigurationMode(CANdriverState); + CO_CANsetConfigurationMode(CANptr); err = CO_CANmodule_init( CO->CANmodule[0], - CANdriverState, + CANptr, CO_CANmodule_rxArray0, CO_RXCAN_NO_MSGS, CO_CANmodule_txArray0, @@ -728,7 +728,7 @@ CO_ReturnError_t CO_CANopenInit( /******************************************************************************/ CO_ReturnError_t CO_init( - void *CANdriverState, + void *CANptr, uint8_t nodeId, uint16_t bitRate) { @@ -739,15 +739,15 @@ CO_ReturnError_t CO_init( return err; } - err = CO_CANinit(CANdriverState, bitRate); + err = CO_CANinit(CANptr, bitRate); if (err) { - CO_delete(CANdriverState); + CO_delete(CANptr); return err; } err = CO_CANopenInit(nodeId); if (err) { - CO_delete(CANdriverState); + CO_delete(CANptr); return err; } @@ -756,12 +756,12 @@ CO_ReturnError_t CO_init( /******************************************************************************/ -void CO_delete(void *CANdriverState){ +void CO_delete(void *CANptr){ #ifndef CO_USE_GLOBALS int16_t i; #endif - CO_CANsetConfigurationMode(CANdriverState); + CO_CANsetConfigurationMode(CANptr); CO_CANmodule_disable(CO->CANmodule[0]); #ifndef CO_USE_GLOBALS diff --git a/CANopen.h b/CANopen.h index 4c9e10e6..e97bb9aa 100644 --- a/CANopen.h +++ b/CANopen.h @@ -129,13 +129,13 @@ CO_ReturnError_t CO_new(void); * * Function must be called in the communication reset section. * - * @param CANdriverState Pointer to the CAN module, passed to CO_CANmodule_init(). + * @param CANptr Pointer to the CAN module, passed to CO_CANmodule_init(). * @param bitRate CAN bit rate. * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, * CO_ERROR_ILLEGAL_BAUDRATE, CO_ERROR_OUT_OF_MEMORY */ CO_ReturnError_t CO_CANinit( - void *CANdriverState, + void *CANptr, uint16_t bitRate); @@ -171,7 +171,7 @@ CO_ReturnError_t CO_CANopenInit( * * Function must be called in the communication reset section. * - * @param CANdriverState Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). + * @param CANptr Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). * @param nodeId Node ID of the CANopen device (1 ... 127). * @param bitRate CAN bit rate. * @@ -179,7 +179,7 @@ CO_ReturnError_t CO_CANopenInit( * CO_ERROR_OUT_OF_MEMORY, CO_ERROR_ILLEGAL_BAUDRATE */ CO_ReturnError_t CO_init( - void *CANdriverState, + void *CANptr, uint8_t nodeId, uint16_t bitRate); @@ -189,9 +189,9 @@ CO_ReturnError_t CO_init( /* * Delete CANopen object and free memory. Must be called at program exit. * - * @param CANdriverState Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). + * @param CANptr Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). */ -void CO_delete(void *CANdriverState); +void CO_delete(void *CANptr); /* diff --git a/example/CO_driver.c b/example/CO_driver.c index bda7b6c4..3e955122 100644 --- a/example/CO_driver.c +++ b/example/CO_driver.c @@ -31,7 +31,7 @@ /******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ +void CO_CANsetConfigurationMode(void *CANptr){ /* Put CAN module in configuration mode */ } @@ -47,7 +47,7 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ /******************************************************************************/ CO_ReturnError_t CO_CANmodule_init( CO_CANmodule_t *CANmodule, - void *CANdriverState, + void *CANptr, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], @@ -62,7 +62,7 @@ CO_ReturnError_t CO_CANmodule_init( } /* Configure object variables */ - CANmodule->CANdriverState = CANdriverState; + CANmodule->CANptr = CANptr; CANmodule->rxArray = rxArray; CANmodule->rxSize = rxSize; CANmodule->txArray = txArray; diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 7589e85a..6ab2b463 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -76,7 +76,7 @@ typedef struct { /* CAN module object */ typedef struct { - void *CANdriverState; + void *CANptr; CO_CANrx_t *rxArray; uint16_t rxSize; CO_CANtx_t *txArray; @@ -114,5 +114,4 @@ typedef struct { } #endif /*__cplusplus*/ -/** @} */ #endif /* CO_DRIVER_TARGET */ diff --git a/stack/CO_driver.h b/stack/CO_driver.h index 72f2a833..047a1466 100644 --- a/stack/CO_driver.h +++ b/stack/CO_driver.h @@ -288,7 +288,7 @@ typedef struct { * microcontrollers. */ typedef struct { - void *CANdriverState; /**< From CO_CANmodule_init() */ + void *CANptr; /**< From CO_CANmodule_init() */ CO_CANrx_t *rxArray; /**< From CO_CANmodule_init() */ uint16_t rxSize; /**< From CO_CANmodule_init() */ CO_CANtx_t *txArray; /**< From CO_CANmodule_init() */ @@ -442,9 +442,9 @@ typedef enum { /** * Request CAN configuration (stopped) mode and *wait* untill it is set. * - * @param CANdriverState User-provided CAN module structure. + * @param CANptr Pointer to CAN device */ -void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetConfigurationMode(void *CANptr); /** @@ -462,7 +462,7 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); * be in Configuration Mode before. * * @param CANmodule This object will be initialized. - * @param CANdriverState User-provided CAN module structure.. + * @param CANptr Pointer to CAN device. * @param rxArray Array for handling received CAN messages * @param rxSize Size of the above array. Must be equal to number of receiving * CAN objects. @@ -475,7 +475,7 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); * Return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, - void *CANdriverState, + void *CANptr, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], From efe87c8b7cca0c5b7585a7559d32998964cbd62b Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 22 Jan 2020 07:57:42 +0100 Subject: [PATCH 006/520] minor corrections example/application.* removed --- example/CO_driver_target.h | 1 + example/application.c | 57 -------------- example/application.h | 153 ------------------------------------- stack/CO_driver.h | 6 +- stack/CO_trace.c | 4 +- 5 files changed, 8 insertions(+), 213 deletions(-) delete mode 100644 example/application.c delete mode 100644 example/application.h diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 6ab2b463..59ab9fb1 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -41,6 +41,7 @@ extern "C" { /* Basic definitions */ #define CO_LITTLE_ENDIAN +#define CO_USE_LEDS /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ diff --git a/example/application.c b/example/application.c deleted file mode 100644 index fbfa58c1..00000000 --- a/example/application.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Application interface for CANopenNode stack. - * - * @file application.c - * @ingroup application - * @author Janez Paternoster - * @copyright 2012 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "CANopen.h" - - -/*******************************************************************************/ -void programStart(void){ - -} - - -/*******************************************************************************/ -void communicationReset(void){ - -} - - -/*******************************************************************************/ -void programEnd(void){ - -} - - -/*******************************************************************************/ -void programAsync(uint16_t timer1msDiff){ - -} - - -/*******************************************************************************/ -void program1ms(void){ - -} diff --git a/example/application.h b/example/application.h deleted file mode 100644 index cd42f0be..00000000 --- a/example/application.h +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Application interface for CANopenNode stack. - * - * @file application.h - * @ingroup CO_application - * @author Janez Paternoster - * @copyright 2012 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_APPLICATION_H -#define CO_APPLICATION_H - - -/** - * @defgroup CO_application Application interface - * @ingroup CO_CANopen - * @{ - * - * Application interface for CANopenNode stack. Function is called - * from file main_xxx.c (if implemented). - * - * ###Main program flow chart - * - * @code - (Program Start) - | - V - +------------------------------------+ - | programStart() | - +------------------------------------+ - | - |<-------------------------+ - | | - V | - (Initialze CANopen) | - | | - V | - +------------------------------------+ | - | communicationReset() | | - +------------------------------------+ | - | | - V | - (Enable CAN and interrupts) | - | | - |<----------------------+ | - | | | - V | | - +------------------------------------+ | | - | programAsync() | | | - +------------------------------------+ | | - | | | - V | | - (Process CANopen asynchronous) | | - | | | - +- infinite loop -------+ | - | | - +- reset communication ----+ - | - V - +------------------------------------+ - | programEnd() | - +------------------------------------+ - | - V - (delete CANopen) - | - V - (Program end) - @endcode - * - * - * ###Timer program flow chart - * - * @code - (Timer interrupt 1 millisecond) - | - V - (CANopen read RPDOs) - | - V - +------------------------------------+ - | program1ms() | - +------------------------------------+ - | - V - (CANopen write TPDOs) - @endcode - * - * - * ###Receive and transmit high priority interrupt flow chart - * - * @code - (CAN receive event or) - (CAN transmit buffer empty event) - | - V - (Process received CAN message or) - (copy next message to CAN transmit buffer) - @endcode - */ - - -/** - * Called after microcontroller reset. - */ -void programStart(void); - - -/** - * Called after communication reset. - */ -void communicationReset(void); - - -/** - * Called before program end. - */ -void programEnd(void); - - -/** - * Called cyclically from main. - * - * @param timer1msDiff Time difference since last call - */ -void programAsync(uint16_t timer1msDiff); - - -/** - * Called cyclically from 1ms timer task. - */ -void program1ms(void); - - -/** @} */ -#endif diff --git a/stack/CO_driver.h b/stack/CO_driver.h index 047a1466..892446c9 100644 --- a/stack/CO_driver.h +++ b/stack/CO_driver.h @@ -108,7 +108,9 @@ extern "C" { */ /** CO_LITTLE_ENDIAN or CO_BIG_ENDIAN must be defined */ #define CO_LITTLE_ENDIAN -/** NULL, for general use */ +/** Enable LED blinking calculation, optional */ +#define CO_USE_LEDS +/** NULL, for general usage */ #define NULL (0) /** Logical true, for general use */ #define true 1 @@ -367,7 +369,7 @@ typedef struct { #define CO_UNLOCK_OD() /** Check if new message has arrived */ -#define CO_CANrxNew_READ(rxNew) ((uintptr_t)rxNew) +#define CO_CANrxNew_READ(rxNew) ((int *)rxNew) /** Set new message flag */ #define CO_CANrxNew_SET(rxNew) { __sync_synchronize(); rxNew = (void *)1L; } /** Clear new message flag */ diff --git a/stack/CO_trace.c b/stack/CO_trace.c index 0ccc248d..943568f9 100644 --- a/stack/CO_trace.c +++ b/stack/CO_trace.c @@ -25,7 +25,9 @@ #include "CO_trace.h" #include -#include +#ifndef CO_OWN_INTTYPES +#include /* for PRIu32("u" or "lu") and PRId32("d" or "ld") */ +#endif /* Different functions for processing value for different data types. */ static int32_t getValueI8 (void *OD_variable) { return (int32_t) *((int8_t*) OD_variable);} From fdda4c834076270db8720a50d24e92e0af294307 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 24 Jan 2020 08:40:58 +0100 Subject: [PATCH 007/520] move stack/neuberger-socketCAN/ socketCAN Compare with initial commit of neuberger-socketCAN. Try to use original code. --- .../CO_Linux_threads.c | 0 .../CO_Linux_threads.h | 0 .../CO_driver.c | 80 ++++++++++--------- .../CO_driver.h | 26 +++--- .../CO_driver_base.h | 6 +- .../CO_error.c | 0 .../CO_error.h | 0 .../CO_notify_pipe.c | 0 .../CO_notify_pipe.h | 0 9 files changed, 59 insertions(+), 53 deletions(-) rename {stack/neuberger-socketCAN => socketCAN}/CO_Linux_threads.c (100%) rename {stack/neuberger-socketCAN => socketCAN}/CO_Linux_threads.h (100%) rename {stack/neuberger-socketCAN => socketCAN}/CO_driver.c (94%) rename {stack/neuberger-socketCAN => socketCAN}/CO_driver.h (94%) rename {stack/neuberger-socketCAN => socketCAN}/CO_driver_base.h (98%) rename {stack/neuberger-socketCAN => socketCAN}/CO_error.c (100%) rename {stack/neuberger-socketCAN => socketCAN}/CO_error.h (100%) rename {stack/neuberger-socketCAN => socketCAN}/CO_notify_pipe.c (100%) rename {stack/neuberger-socketCAN => socketCAN}/CO_notify_pipe.h (100%) diff --git a/stack/neuberger-socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c similarity index 100% rename from stack/neuberger-socketCAN/CO_Linux_threads.c rename to socketCAN/CO_Linux_threads.c diff --git a/stack/neuberger-socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h similarity index 100% rename from stack/neuberger-socketCAN/CO_Linux_threads.h rename to socketCAN/CO_Linux_threads.h diff --git a/stack/neuberger-socketCAN/CO_driver.c b/socketCAN/CO_driver.c similarity index 94% rename from stack/neuberger-socketCAN/CO_driver.c rename to socketCAN/CO_driver.c index 74e4b7c8..5c6620b1 100644 --- a/stack/neuberger-socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -3,6 +3,7 @@ * * This file is a template for other microcontrollers. * + * @file CO_driver.c * @ingroup CO_driver * @author Janez Paternoster, Martin Wagner * @copyright 2004 - 2015 Janez Paternoster, 2017 - 2020 Neuberger Gebaeudeautomation GmbH @@ -53,7 +54,7 @@ pthread_mutex_t CO_EMCY_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; #ifndef CO_DRIVER_MULTI_INTERFACE -static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, void *CANdriverState); +static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, int32_t CANbaseAddress); #endif #ifdef CO_DRIVER_MULTI_INTERFACE @@ -174,7 +175,7 @@ static CO_ReturnError_t setRxFilters(CO_CANmodule_t *CANmodule) /******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState) +void CO_CANsetConfigurationMode(void *CANptr) { /* Can't do anything because no object is provided */ } @@ -200,7 +201,7 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) /******************************************************************************/ CO_ReturnError_t CO_CANmodule_init( CO_CANmodule_t *CANmodule, - void *CANdriverState, + void *CANptr, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], @@ -273,7 +274,7 @@ CO_ReturnError_t CO_CANmodule_init( rxArray[i].object = NULL; rxArray[i].pFunct = NULL; #ifdef CO_DRIVER_MULTI_INTERFACE - rxArray[i].CANdriverState = NULL; + rxArray[i].CANbaseAddress = -1; rxArray[i].timestamp.tv_sec = 0; rxArray[i].timestamp.tv_nsec = 0; #endif @@ -281,7 +282,7 @@ CO_ReturnError_t CO_CANmodule_init( #ifndef CO_DRIVER_MULTI_INTERFACE /* add one interface */ - ret = CO_CANmodule_addInterface(CANmodule, CANdriverState); + ret = CO_CANmodule_addInterface(CANmodule, (int32_t)CANptr); if (ret != CO_ERROR_NO) { CO_CANmodule_disable(CANmodule); } @@ -298,7 +299,7 @@ static #endif CO_ReturnError_t CO_CANmodule_addInterface( CO_CANmodule_t *CANmodule, - void *CANdriverState) + int32_t CANbaseAddress) { int32_t ret; int32_t tmp; @@ -312,7 +313,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( can_err_mask_t err_mask; #endif - if (!CANmodule->CANnormal) { + if (CANmodule->CANnormal) { /* can't change config now! */ return CO_ERROR_INVALID_STATE; } @@ -327,8 +328,8 @@ CO_ReturnError_t CO_CANmodule_addInterface( } interface = &CANmodule->CANinterfaces[CANmodule->CANinterfaceCount - 1]; - interface->CANdriverState = CANdriverState; - ifName = if_indextoname((uintptr_t)interface->CANdriverState, interface->ifName); + interface->CANbaseAddress = CANbaseAddress; + ifName = if_indextoname(CANbaseAddress, interface->ifName); if (ifName == NULL) { log_printf(LOG_DEBUG, DBG_ERRNO, "if_indextoname()"); return CO_ERROR_ILLEGAL_ARGUMENT; @@ -376,7 +377,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( /* bind socket */ memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.can_family = AF_CAN; - sockAddr.can_ifindex = (uintptr_t)interface->CANdriverState; + sockAddr.can_ifindex = CANbaseAddress; ret = bind(interface->fd, (struct sockaddr*)&sockAddr, sizeof(sockAddr)); if(ret < 0){ log_printf(LOG_ERR, CAN_BINDING_FAILED, interface->ifName); @@ -514,7 +515,7 @@ CO_ReturnError_t CO_CANrxBufferInit( buffer->object = object; buffer->pFunct = pFunct; #ifdef CO_DRIVER_MULTI_INTERFACE - buffer->CANdriverState = NULL; + buffer->CANbaseAddress = -1; buffer->timestamp.tv_nsec = 0; buffer->timestamp.tv_sec = 0; #endif @@ -547,30 +548,35 @@ CO_ReturnError_t CO_CANrxBufferInit( bool_t CO_CANrxBuffer_getInterface( CO_CANmodule_t *CANmodule, uint32_t ident, - void **CANdriverStateRx, + int32_t *CANbaseAddressRx, struct timespec *timestamp) { - CO_CANrx_t *buffer; + if (CANmodule != NULL){ + uint32_t index; + CO_CANrx_t *buffer; - if (CANmodule == NULL){ - return false; - } + index = CO_CANgetIndexFromIdent(CANmodule->rxIdentToIndex, ident); + if ((index == CO_INVALID_COB_ID) || (index > CANmodule->rxSize)) { + return false; + } + buffer = &CANmodule->rxArray[index]; - const uint32_t index = CO_CANgetIndexFromIdent(CANmodule->rxIdentToIndex, ident); - if ((index == CO_INVALID_COB_ID) || (index > CANmodule->rxSize)) { - return false; - } - buffer = &CANmodule->rxArray[index]; + /* return values */ + if (CANbaseAddressRx != NULL) { + *CANbaseAddressRx = buffer->CANbaseAddress; + } + if (timestamp != NULL) { + *timestamp = buffer->timestamp; + } - /* return values */ - if (CANbaseAddressRx != NULL) { - *CANbaseAddressRx = buffer->CANbaseAddress; - } - if (timestamp != NULL) { - *timestamp = buffer->timestamp; + if (buffer->CANbaseAddress >= 0) { + return true; + } + else { + return false; + } } - - return buffer->CANbaseAddress >= 0; + return false; } #endif @@ -595,7 +601,7 @@ CO_CANtx_t *CO_CANtxBufferInit( CO_CANsetIdentToIndex(CANmodule->txIdentToIndex, index, ident, buffer->ident); #endif - buffer->CANdriverState = NULL; + buffer->CANbaseAddress = -1; /* CAN identifier and rtr */ buffer->ident = ident & CAN_SFF_MASK; @@ -616,7 +622,7 @@ CO_CANtx_t *CO_CANtxBufferInit( CO_ReturnError_t CO_CANtxBuffer_setInterface( CO_CANmodule_t *CANmodule, uint32_t ident, - void *CANdriverStateTx) + int32_t CANbaseAddressTx) { if (CANmodule != NULL) { uint32_t index; @@ -625,7 +631,7 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface( if ((index == CO_INVALID_COB_ID) || (index > CANmodule->txSize)) { return CO_ERROR_PARAMETERS; } - CANmodule->txArray[index].CANdriverState = CANdriverStateTx; + CANmodule->txArray[index].CANbaseAddress = CANbaseAddressTx; return CO_ERROR_NO; } @@ -726,8 +732,8 @@ CO_ReturnError_t CO_CANCheckSend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) for (i = 0; i < CANmodule->CANinterfaceCount; i++) { CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; - if ((buffer->CANdriverState == NULL) || - buffer->CANdriverState == interface->CANdriverState) { + if (buffer->CANbaseAddress < 0 || + buffer->CANbaseAddress == interface->CANbaseAddress) { CO_ReturnError_t tmp; @@ -873,7 +879,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff { int32_t retval; int32_t ret; - void *CANdriverState __attribute__((unused)); + int32_t CANbaseAddress __attribute__((unused)); CO_ReturnError_t err; CO_CANinterface_t *interface = NULL; struct epoll_event ev[1]; @@ -933,7 +939,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff if (ev[0].data.fd == interface->fd) { /* get interface handle */ - CANdriverState = interface->CANdriverState; + CANbaseAddress = interface->CANbaseAddress; /* get message */ err = CO_CANread(CANmodule, interface, &msg, ×tamp); if (err != CO_ERROR_NO) { @@ -972,7 +978,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff #ifdef CO_DRIVER_MULTI_INTERFACE /* Store message info */ CANmodule->rxArray[msgIndex].timestamp = timestamp; - CANmodule->rxArray[msgIndex].CANdriverState = CANdriverState; + CANmodule->rxArray[msgIndex].CANbaseAddress = CANbaseAddress; #endif } retval = msgIndex; diff --git a/stack/neuberger-socketCAN/CO_driver.h b/socketCAN/CO_driver.h similarity index 94% rename from stack/neuberger-socketCAN/CO_driver.h rename to socketCAN/CO_driver.h index 25b68ddb..c72161be 100644 --- a/stack/neuberger-socketCAN/CO_driver.h +++ b/socketCAN/CO_driver.h @@ -73,7 +73,7 @@ extern "C" { * socketCAN interface object */ typedef struct { - void *CANdriverState; /**< CAN Interface identifier */ + int32_t CANbaseAddress; /**< CAN Interface identifier */ char ifName[IFNAMSIZ]; /**< CAN Interface name */ int fd; /**< socketCAN file descriptor */ #ifdef CO_DRIVER_ERROR_REPORTING @@ -111,9 +111,9 @@ typedef struct{ /** * Request CAN configuration (stopped) mode and *wait* until it is set. * - * @param CANdriverState CAN module base address. + * @param CANptr CAN module base address. */ -void CO_CANsetConfigurationMode(void *CANdriverState); +void CO_CANsetConfigurationMode(void *CANptr); /** @@ -132,7 +132,7 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); * be in Configuration Mode before. * * @param CANmodule This object will be initialized. - * @param CANdriverState unused + * @param CANptr 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 @@ -149,7 +149,7 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); * be in Configuration Mode before. * * @param CANmodule This object will be initialized. - * @param CANdriverState CAN module base address. + * @param CANptr 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 @@ -162,7 +162,7 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); #endif CO_ReturnError_t CO_CANmodule_init( CO_CANmodule_t *CANmodule, - void *CANdriverState, + void *CANptr, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], @@ -177,13 +177,13 @@ CO_ReturnError_t CO_CANmodule_init( * Function must be called after CO_CANmodule_init. * * @param CANmodule This object will be initialized. - * @param CANdriverState CAN module base address. + * @param CANbaseAddress 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); + int32_t CANbaseAddress); #endif @@ -246,7 +246,7 @@ CO_ReturnError_t CO_CANrxBufferInit( * * @param CANmodule This object. * @param ident 11-bit standard CAN Identifier. - * @param [out] CANdriverStateRx message was received on this interface + * @param [out] CANbaseAddressRx 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 @@ -256,7 +256,7 @@ CO_ReturnError_t CO_CANrxBufferInit( bool_t CO_CANrxBuffer_getInterface( CO_CANmodule_t *CANmodule, uint32_t ident, - void **CANdriverStateRx, + int32_t *CANbaseAddressRx, struct timespec *timestamp); #endif @@ -294,19 +294,19 @@ CO_CANtx_t *CO_CANtxBufferInit( * 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 + * If given interface is unknown or "-1" 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 + * @param CANbaseAddressTx use this interface. -1 = 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); + int32_t CANbaseAddressTx); #endif diff --git a/stack/neuberger-socketCAN/CO_driver_base.h b/socketCAN/CO_driver_base.h similarity index 98% rename from stack/neuberger-socketCAN/CO_driver_base.h rename to socketCAN/CO_driver_base.h index c279b3ce..6bd6800a 100644 --- a/stack/neuberger-socketCAN/CO_driver_base.h +++ b/socketCAN/CO_driver_base.h @@ -184,7 +184,7 @@ static inline void CO_UNLOCK_OD() { (void)pthread_mutex_unlock(&CO_OD_mutex); /** Memory barrier */ #define CANrxMemoryBarrier() {__sync_synchronize();} /** Check if new message has arrived */ -#define IS_CANrxNew(rxNew) ((uintptr_t)rxNew) +#define IS_CANrxNew(rxNew) ((int)rxNew) /** Set new message flag */ #define SET_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)1L;} /** Clear new message flag */ @@ -261,7 +261,7 @@ typedef struct{ #ifdef CO_DRIVER_MULTI_INTERFACE /** info about last received message */ - void *CANdriverState; /**< CAN Interface identifier */ + int32_t CANbaseAddress; /**< CAN Interface identifier */ struct timespec timestamp; /**< time of reception */ #endif }CO_CANrx_t; @@ -281,7 +281,7 @@ typedef struct{ volatile bool_t syncFlag; /** info about transmit message */ - void *CANdriverState; /**< CAN Interface identifier to use */ + int32_t CANbaseAddress; /**< CAN Interface identifier to use */ } CO_CANtx_t; /** diff --git a/stack/neuberger-socketCAN/CO_error.c b/socketCAN/CO_error.c similarity index 100% rename from stack/neuberger-socketCAN/CO_error.c rename to socketCAN/CO_error.c diff --git a/stack/neuberger-socketCAN/CO_error.h b/socketCAN/CO_error.h similarity index 100% rename from stack/neuberger-socketCAN/CO_error.h rename to socketCAN/CO_error.h diff --git a/stack/neuberger-socketCAN/CO_notify_pipe.c b/socketCAN/CO_notify_pipe.c similarity index 100% rename from stack/neuberger-socketCAN/CO_notify_pipe.c rename to socketCAN/CO_notify_pipe.c diff --git a/stack/neuberger-socketCAN/CO_notify_pipe.h b/socketCAN/CO_notify_pipe.h similarity index 100% rename from stack/neuberger-socketCAN/CO_notify_pipe.h rename to socketCAN/CO_notify_pipe.h From 23a37f0d922a4452446581efae786f8281971a0a Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 24 Jan 2020 14:59:45 +0100 Subject: [PATCH 008/520] New socketCAN/CO_driver_target.h - Reduce CO_driver.h and CO_driver_base.h into CO_driver_target.h - New functions: CO_CANrxMsg_readIdent, _DLC, _data - rxArray[i].pFunct changed to -> rxArray[i].CANrx_callback - (*pFunct)(void *object, const CO_CANrxMsg_t *message)) changed to (*CANrx_callback)(void *object, void *message)) - change to '#define CO_CANrxNew_READ(rxNew) ((bool_t)rxNew)' --- example/CO_driver_target.h | 9 +- socketCAN/CO_driver.c | 44 +++- socketCAN/CO_driver.h | 381 ----------------------------------- socketCAN/CO_driver_base.h | 306 ---------------------------- socketCAN/CO_driver_target.h | 287 ++++++++++++++++++++++++++ stack/CO_driver.h | 12 +- 6 files changed, 333 insertions(+), 706 deletions(-) delete mode 100644 socketCAN/CO_driver.h delete mode 100644 socketCAN/CO_driver_base.h create mode 100644 socketCAN/CO_driver_target.h diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 59ab9fb1..0232c2ae 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -26,10 +26,6 @@ #ifndef CO_DRIVER_TARGET #define CO_DRIVER_TARGET -#ifdef __cplusplus -extern "C" { -#endif - /* This file contains device and application specific definitions. * It is included from CO_driver.h, which contains documentation * for definitions below. */ @@ -38,6 +34,9 @@ extern "C" { #include #include +#ifdef __cplusplus +extern "C" { +#endif /* Basic definitions */ #define CO_LITTLE_ENDIAN @@ -106,7 +105,7 @@ typedef struct { /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() -#define CO_CANrxNew_READ(rxNew) ((uintptr_t)rxNew) +#define CO_CANrxNew_READ(rxNew) ((bool_t)rxNew) #define CO_CANrxNew_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} #define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = (void*)0L;} diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 5c6620b1..549ac192 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -272,7 +272,7 @@ CO_ReturnError_t CO_CANmodule_init( rxArray[i].ident = 0U; rxArray[i].mask = 0xFFFFFFFFU; rxArray[i].object = NULL; - rxArray[i].pFunct = NULL; + rxArray[i].CANrx_callback = NULL; #ifdef CO_DRIVER_MULTI_INTERFACE rxArray[i].CANbaseAddress = -1; rxArray[i].timestamp.tv_sec = 0; @@ -469,10 +469,18 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) /******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg) -{ +static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg) { + CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; /* remove socketCAN flags */ - return (uint16_t) (rxMsg->ident & CAN_SFF_MASK); + return (uint16_t) (rxMsgCasted->ident & CAN_SFF_MASK); +} +static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg) { + CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; + return (uint8_t) (rxMsgCasted->DLC); +} +static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg) { + CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; + return (uint8_t *) (rxMsgCasted->data); } @@ -484,7 +492,7 @@ CO_ReturnError_t CO_CANrxBufferInit( uint32_t mask, bool_t rtr, void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) + void (*CANrx_callback)(void *object, void *message)) { CO_ReturnError_t ret = CO_ERROR_NO; @@ -513,7 +521,7 @@ CO_ReturnError_t CO_CANrxBufferInit( /* Configure object variables */ buffer->object = object; - buffer->pFunct = pFunct; + buffer->CANrx_callback = CANrx_callback; #ifdef CO_DRIVER_MULTI_INTERFACE buffer->CANbaseAddress = -1; buffer->timestamp.tv_nsec = 0; @@ -704,6 +712,26 @@ static CO_ReturnError_t CO_CANCheckSendInterface( } +/* + * 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. + * + * (It is not in header, because usage of CO_CANCheckSend() is unclear.) + * + * @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); + + /******************************************************************************/ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) { @@ -858,8 +886,8 @@ static int32_t CO_CANrxMsg( } if(msgMatched) { /* Call specific function, which will process the message */ - if ((rcvMsgObj != NULL) && (rcvMsgObj->pFunct != NULL)){ - rcvMsgObj->pFunct(rcvMsgObj->object, rcvMsg); + if ((rcvMsgObj != NULL) && (rcvMsgObj->CANrx_callback != NULL)){ + rcvMsgObj->CANrx_callback(rcvMsgObj->object, (void *)rcvMsg); } /* return message */ if (buffer != NULL) { diff --git a/socketCAN/CO_driver.h b/socketCAN/CO_driver.h deleted file mode 100644 index c72161be..00000000 --- a/socketCAN/CO_driver.h +++ /dev/null @@ -1,381 +0,0 @@ -/** - * 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 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#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 { - int32_t CANbaseAddress; /**< 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 CANptr CAN module base address. - */ -void CO_CANsetConfigurationMode(void *CANptr); - - -/** - * 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 CANptr 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 CANptr 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 *CANptr, - 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 CANbaseAddress 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, - int32_t CANbaseAddress); - -#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] CANbaseAddressRx 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, - int32_t *CANbaseAddressRx, - 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 "-1" is used, a message is transmitted on - * all available interfaces. - * - * @param CANmodule This object. - * @param ident 11-bit standard CAN Identifier. - * @param CANbaseAddressTx use this interface. -1 = 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, - int32_t CANbaseAddressTx); - -#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 diff --git a/socketCAN/CO_driver_base.h b/socketCAN/CO_driver_base.h deleted file mode 100644 index 6bd6800a..00000000 --- a/socketCAN/CO_driver_base.h +++ /dev/null @@ -1,306 +0,0 @@ -/** - * CAN module object for Linux socketCAN. - * - * @file CO_driver_base.h - * @ingroup CO_driver - * @author Janez Paternoster, Martin Wagner - * @copyright 2004 - 2015 Janez Paternoster, 2018 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CO_DRIVER_BASE_H -#define CO_DRIVER_BASE_H - -/* Include processor header file */ -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ -#include /* for 'true', 'false' */ -#include /* for 'struct timespec' */ -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_driver Driver - * @ingroup CO_CANopen - * @{ - * - * socketCAN specific code for CANopenNode. - * - * This file contains type definitions, functions and macros for: - * - Basic data types. - * - Receive and transmit buffers for CANopen messages. - * - Interaction with CAN module on the microcontroller. - * - CAN receive and transmit interrupts. - * - * This file is not only a CAN driver. There are no classic CAN queues for CAN - * messages. This file provides direct connection with other CANopen - * objects. It tries to provide fast responses and tries to avoid unnecessary - * calculations and memory consumptions. - * - * CO_CANmodule_t contains an array of _Received message objects_ (of type - * CO_CANrx_t) and an array of _Transmit message objects_ (of type CO_CANtx_t). - * Each CANopen communication object owns one member in one of the arrays. - * For example Heartbeat producer generates one CANopen transmitting object, - * so it has reserved one member in CO_CANtx_t array. - * SYNC module may produce sync or consume sync, so it has reserved one member - * in CO_CANtx_t and one member in CO_CANrx_t array. - * - * ###Reception of CAN messages. - * Before CAN messages can be received, each member in CO_CANrx_t must be - * initialized. CO_CANrxBufferInit() is called by CANopen module, which - * uses specific member. For example @ref CO_HBconsumer uses multiple members - * in CO_CANrx_t array. (It monitors multiple heartbeat messages from remote - * nodes.) It must call CO_CANrxBufferInit() multiple times. - * - * Main arguments to the CO_CANrxBufferInit() function are CAN identifier - * and a pointer to callback function. Those two arguments (and some others) - * are copied to the member of the CO_CANrx_t array. - * - * Callback function is a function, specified by specific CANopen module - * (for example by @ref CO_HBconsumer). Each CANopen module defines own - * callback function. Callback function will process the received CAN message. - * It will copy the necessary data from CAN message to proper place. It may - * also trigger additional task, which will further process the received message. - * Callback function must be fast and must only make the necessary calculations - * and copying. - * - * Received CAN messages are processed by CAN receive interrupt function. - * After CAN message is received, function first tries to find matching CAN - * identifier from CO_CANrx_t array. If found, then a corresponding callback - * function is called. - * - * Callback function accepts two parameters: - * - object is pointer to object registered by CO_CANrxBufferInit(). - * - msg is pointer to CAN message of type CO_CANrxMsg_t. - * - * Callback function must return #CO_ReturnError_t: CO_ERROR_NO, - * CO_ERROR_RX_OVERFLOW, CO_ERROR_RX_PDO_OVERFLOW, CO_ERROR_RX_MSG_LENGTH or - * CO_ERROR_RX_PDO_LENGTH. - * - * - * ###Transmission of CAN messages. - * Before CAN messages can be transmitted, each member in CO_CANtx_t must be - * initialized. CO_CANtxBufferInit() is called by CANopen module, which - * uses specific member. For example Heartbeat producer must initialize it's - * member in CO_CANtx_t array. - * - * CO_CANtxBufferInit() returns a pointer of type CO_CANtx_t, which contains buffer - * where CAN message data can be written. CAN message is send with calling - * CO_CANsend() function. If at that moment CAN transmit buffer inside - * microcontroller's CAN module is free, message is copied directly to CAN module. - * Otherwise CO_CANsend() function sets _bufferFull_ flag to true. Message will be - * then sent by CAN TX interrupt as soon as CAN module is freed. Until message is - * not copied to CAN module, its contents must not change. There may be multiple - * _bufferFull_ flags in CO_CANtx_t array set to true. In that case messages with - * lower index inside array will be sent first. - */ - - -/** - * @name Critical sections - * CANopenNode is designed to run in different threads, as described in README. - * Threads are implemented differently in different systems. In microcontrollers - * threads are interrupts with different priorities, for example. - * It is necessary to protect sections, where different threads access to the - * same resource. In simple systems interrupts or scheduler may be temporary - * disabled between access to the shared resource. Otherwise mutexes or - * semaphores can be used. - * - * ####Reentrant functions. - * Functions CO_CANsend() from C_driver.h, CO_errorReport() from CO_Emergency.h - * and CO_errorReset() from CO_Emergency.h may be called from different threads. - * Critical sections must be protected. Eather by disabling scheduler or - * interrupts or by mutexes or semaphores. - * - * ####Object Dictionary variables. - * In general, there are two threads, which accesses OD variables: mainline and - * timer. CANopenNode initialization and SDO server runs in mainline. PDOs runs - * in faster timer thread. Processing of PDOs must not be interrupted by - * mainline. Mainline thread must protect sections, which accesses the same OD - * variables as timer thread. This care must also take the application. Note - * that not all variables are allowed to be mapped to PDOs, so they may not need - * to be protected. SDO server protects sections with access to OD variables. - * - * ####CAN receive thread. - * It partially processes received CAN data and puts them into appropriate - * objects. Objects are later processed. It does not need protection of - * critical sections. There is one circumstance, where CANrx should be disabled: - * After presence of SYNC message on CANopen bus, CANrx should be temporary - * disabled until all receive PDOs are processed. See also CO_SYNC.h file and - * CO_SYNC_initCallback() function. - * @{ - */ - -/* unused */ -#define CO_LOCK_CAN_SEND() /**< Lock critical section in CO_CANsend() */ -#define CO_UNLOCK_CAN_SEND()/**< Unlock critical section in CO_CANsend() */ - -extern pthread_mutex_t CO_EMCY_mutex; -static inline int CO_LOCK_EMCY() { return pthread_mutex_lock(&CO_EMCY_mutex); } /**< Lock critical section in CO_errorReport() or CO_errorReset() */ -static inline void CO_UNLOCK_EMCY() { (void)pthread_mutex_unlock(&CO_EMCY_mutex); } /**< Unlock critical section in CO_errorReport() or CO_errorReset() */ - -extern pthread_mutex_t CO_OD_mutex; -static inline int CO_LOCK_OD() { return pthread_mutex_lock(&CO_OD_mutex); } /**< Lock critical section when accessing Object Dictionary */ -static inline void CO_UNLOCK_OD() { (void)pthread_mutex_unlock(&CO_OD_mutex); } /**< Unock critical section when accessing Object Dictionary */ - -/** @} */ - -/** - * @name Syncronisation functions - * syncronisation for message buffer for communication between CAN receive and - * message processing threads. - * - * If receive function runs inside IRQ, no further synchronsiation is needed. - * Otherwise, some kind of synchronsiation has to be included. The following - * example uses GCC builtin memory barrier __sync_synchronize(). A comprehensive - * list can be found here: https://gist.github.com/leo-yuriev/ba186a6bf5cf3a27bae7 - * \code{.c} - #define CANrxMemoryBarrier() {__sync_synchronize();} - * \endcode - * @{ - */ -/** Memory barrier */ -#define CANrxMemoryBarrier() {__sync_synchronize();} -/** Check if new message has arrived */ -#define IS_CANrxNew(rxNew) ((int)rxNew) -/** Set new message flag */ -#define SET_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)1L;} -/** Clear new message flag */ -#define CLEAR_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)0L;} -/** @} */ - -/** - * @defgroup CO_dataTypes Data types - * @{ - * - * According to Misra C - */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; /**< bool_t */ - typedef float float32_t; /**< float32_t */ - typedef long double float64_t; /**< float64_t */ - typedef char char_t; /**< char_t */ - typedef unsigned char oChar_t; /**< oChar_t */ - typedef unsigned char domain_t; /**< domain_t */ -/** @} */ - - -/** - * Return values of some CANopen functions. If function was executed - * successfully it returns 0 otherwise it returns <0. - */ -typedef enum{ - CO_ERROR_NO = 0, /**< Operation completed successfully */ - CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ - CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ - CO_ERROR_TIMEOUT = -3, /**< Function timeout */ - CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function CO_CANmodule_init() */ - CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed yet */ - CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ - CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ - CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ - CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, buffer full */ - CO_ERROR_TX_BUSY = -10, /**< Sending rejected because driver is busy. Try again */ - CO_ERROR_TX_PDO_WINDOW = -11, /**< Synchronous TPDO is outside window */ - CO_ERROR_TX_UNCONFIGURED = -12, /**< Transmit buffer was not confugured properly */ - CO_ERROR_PARAMETERS = -13, /**< Error in function function parameters */ - CO_ERROR_DATA_CORRUPT = -14, /**< Stored data are corrupt */ - CO_ERROR_CRC = -15, /**< CRC does not match */ - CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current state */ - CO_ERROR_SYSCALL = -17, /**< Syscall failed */ - CO_ERROR_INVALID_STATE = -18 /**< Driver not ready */ -}CO_ReturnError_t; - - -/** - * Max COB ID for standard frame format - */ -#define CO_CAN_MSG_SFF_MAX_COB_ID (1 << CAN_SFF_ID_BITS) - -/** - * CAN receive message structure as aligned in socketCAN. - */ -typedef struct{ - /** CAN identifier. It must be read through CO_CANrxMsg_readIdent() function. */ - uint32_t ident; - uint8_t DLC ; /**< Length of CAN message */ - uint8_t padding[3]; /**< ensure alignment */ - uint8_t data[8]; /**< 8 data bytes */ -}CO_CANrxMsg_t; - -/** - * Received message object - */ -typedef struct{ - uint32_t ident; /**< Standard CAN Identifier (bits 0..10) + RTR (bit 11) */ - uint32_t mask; /**< Standard Identifier mask with same alignment as ident */ - void *object; /**< From CO_CANrxBufferInit() */ - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); /**< From CO_CANrxBufferInit() */ - -#ifdef CO_DRIVER_MULTI_INTERFACE - /** info about last received message */ - int32_t CANbaseAddress; /**< CAN Interface identifier */ - struct timespec timestamp; /**< time of reception */ -#endif -}CO_CANrx_t; - - -/** - * Transmit message object as aligned in socketCAN. - */ -typedef struct{ - /** CAN identifier. It must be read through CO_CANrxMsg_readIdent() function. */ - uint32_t ident; - uint8_t DLC ; /**< Length of CAN message */ - uint8_t padding[3]; /**< ensure alignment */ - uint8_t data[8]; /**< 8 data bytes */ - volatile bool_t bufferFull; /**< True if previous message is still in buffer (not used in this driver) */ - /** Synchronous PDO messages has this flag set. It prevents them to be sent outside the synchronous window */ - volatile bool_t syncFlag; - - /** info about transmit message */ - int32_t CANbaseAddress; /**< CAN Interface identifier to use */ -} CO_CANtx_t; - -/** - * Endianess. - * - * Depending on processor or compiler architecture, one of the two macros must - * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little endian. - */ -#ifdef __BYTE_ORDER -#if __BYTE_ORDER == __LITTLE_ENDIAN - #define CO_LITTLE_ENDIAN -#else - #define CO_BIG_ENDIAN -#endif -#endif - -#ifdef __cplusplus -} -#endif /*__cplusplus*/ - -/** @} */ -#endif diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h new file mode 100644 index 00000000..fd10316e --- /dev/null +++ b/socketCAN/CO_driver_target.h @@ -0,0 +1,287 @@ +/* + * Linux socketCAN specific definitions for CANopenNode. + * + * @file CO_driver_target.h + * @author Janez Paternoster + * @author Martin Wagner + * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CO_DRIVER_TARGET +#define CO_DRIVER_TARGET + +/* This file contains device and application specific definitions. + * It is included from CO_driver.h, which contains documentation + * for definitions below. */ + +/* + * @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. + * + * If CO_DRIVER_MULTI_INTERFACE is disabled, then CO_CANmodule_init() + * adds single socketCAN interface specified by CANptr argument. In case of + * failure, CO_CANmodule_init() returns CO_ERROR_SYSCALL. + * + * If CO_DRIVER_MULTI_INTERFACE is enabled, then CO_CANmodule_init() + * ignores CANptr argument. Interfaces must be added by + * CO_CANmodule_addInterface() function after CO_CANmodule_init(). + * + * This is not intended to realize interface redundancy!!! + */ +/* #define CO_DRIVER_MULTI_INTERFACE */ + +/* + * @name CAN bus error reporting + * + * CO_DRIVER_ERROR_REPORTING enabled adds 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 functionality to be implemented... + */ +#ifndef CO_DRIVER_ERROR_REPORTING_DISABLE +#define CO_DRIVER_ERROR_REPORTING +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CO_notify_pipe.h" +#ifdef CO_DRIVER_ERROR_REPORTING + #include "CO_error.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Basic definitions */ +#ifdef __BYTE_ORDER +#if __BYTE_ORDER == __LITTLE_ENDIAN + #define CO_LITTLE_ENDIAN +#else + #define CO_BIG_ENDIAN +#endif +#endif +/* #define CO_USE_LEDS */ +/* NULL is defined in stddef.h */ +/* true and false are defined in stdbool.h */ +/* int8_t to uint64_t are defined in stdint.h */ +typedef unsigned char bool_t; +typedef float float32_t; +typedef long double float64_t; +typedef char char_t; +typedef unsigned char oChar_t; +typedef unsigned char domain_t; + + +/* CAN receive message structure as aligned in socketCAN. */ +typedef struct { + uint32_t ident; + uint8_t DLC; + uint8_t padding[3]; + uint8_t data[8]; +} CO_CANrxMsg_t; + +/* Access to received CAN message */ +static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg); +static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg); +static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg); + +/* Received message object */ +typedef struct { + uint32_t ident; + uint32_t mask; + void *object; + void (*CANrx_callback)(void *object, void *message); +#ifdef CO_DRIVER_MULTI_INTERFACE + /* info about last received message */ + int32_t CANbaseAddress; /* CAN Interface identifier */ + struct timespec timestamp; /* time of reception */ +#endif +} CO_CANrx_t; + +/* Transmit message object as aligned in socketCAN. */ +typedef struct { + uint32_t ident; + uint8_t DLC; + uint8_t padding[3]; /* ensure alignment */ + uint8_t data[8]; + volatile bool_t syncFlag; + /* info about transmit message */ + int32_t CANbaseAddress; /* CAN Interface identifier to use */ +} CO_CANtx_t; + + +/* Max COB ID for standard frame format */ +#define CO_CAN_MSG_SFF_MAX_COB_ID (1 << CAN_SFF_ID_BITS) + +/* socketCAN interface object */ +typedef struct { + int32_t CANbaseAddress; /* 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 */ +typedef struct { + /* List of can interfaces. From CO_CANmodule_init() or one per + * CO_CANmodule_addInterface() call */ + CO_CANinterface_t *CANinterfaces; + uint32_t CANinterfaceCount; /* interface count */ + CO_CANrx_t *rxArray; + uint16_t rxSize; + struct can_filter *rxFilter;/* socketCAN filter list, one per rx buffer */ + uint32_t rxDropCount; /* messages dropped on rx socket queue */ + CO_CANtx_t *txArray; + uint16_t txSize; + volatile bool_t CANnormal; + void *em; + 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]; + uint32_t txIdentToIndex[CO_CAN_MSG_SFF_MAX_COB_ID]; +#endif +} CO_CANmodule_t; + + +/* (un)lock critical section in CO_CANsend() - unused */ +#define CO_LOCK_CAN_SEND() +#define CO_UNLOCK_CAN_SEND() + +/* (un)lock critical section in CO_errorReport() or CO_errorReset() */ +extern pthread_mutex_t CO_EMCY_mutex; +static inline int CO_LOCK_EMCY() { return pthread_mutex_lock(&CO_EMCY_mutex); } +static inline void CO_UNLOCK_EMCY() { (void)pthread_mutex_unlock(&CO_EMCY_mutex); } + +/* (un)lock critical section when accessing Object Dictionary */ +extern pthread_mutex_t CO_OD_mutex; +static inline int CO_LOCK_OD() { return pthread_mutex_lock(&CO_OD_mutex); } +static inline void CO_UNLOCK_OD() { (void)pthread_mutex_unlock(&CO_OD_mutex); } + +/* Synchronization between CAN receive and message processing threads. */ +#define CO_MemoryBarrier() {__sync_synchronize();} +#define CO_CANrxNew_READ(rxNew) ((bool_t)rxNew) +#define CO_CANrxNew_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} +#define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = (void*)0L;} + + +#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 CANbaseAddress 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, + int32_t CANbaseAddress); + +/* + * 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] CANbaseAddressRx 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, + int32_t *CANbaseAddressRx, + struct timespec *timestamp); + +/* + * 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 "-1" is used, a message is transmitted on + * all available interfaces. + * + * @param CANmodule This object. + * @param ident 11-bit standard CAN Identifier. + * @param CANbaseAddressTx use this interface. -1 = 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, + int32_t CANbaseAddressTx); +#endif + + +/* + * 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 /* CO_DRIVER_TARGET */ diff --git a/stack/CO_driver.h b/stack/CO_driver.h index 892446c9..8eb56494 100644 --- a/stack/CO_driver.h +++ b/stack/CO_driver.h @@ -27,12 +27,12 @@ #ifndef CO_DRIVER_H #define CO_DRIVER_H +#include "CO_driver_target.h" + #ifdef __cplusplus extern "C" { #endif -#include "CO_driver_target.h" - /** * @defgroup CO_driver Driver * @ingroup CO_CANopen @@ -194,7 +194,7 @@ void CANrx_callback(void *object, void *rxMsg); * @param rxMsg Pointer to received message * @return 11-bit CAN standard identifier. */ -uint16_t CO_CANrxMsg_readIdent(void *rxMsg); +static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg); /** * CANrx_callback() can read Data Length Code from received CAN message @@ -204,7 +204,7 @@ uint16_t CO_CANrxMsg_readIdent(void *rxMsg); * @param rxMsg Pointer to received message * @return data length in bytes (0 to 8) */ -uint8_t CO_CANrxMsg_readDLC(void *rxMsg); +static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg); /** * CANrx_callback() can read pointer to data from received CAN message @@ -214,7 +214,7 @@ uint8_t CO_CANrxMsg_readDLC(void *rxMsg); * @param rxMsg Pointer to received message * @return pointer to data buffer */ -uint8_t *CO_CANrxMsg_readData(void *rxMsg); +static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg); /** * Configuration object for CAN received message for specific \ref CO_obj @@ -369,7 +369,7 @@ typedef struct { #define CO_UNLOCK_OD() /** Check if new message has arrived */ -#define CO_CANrxNew_READ(rxNew) ((int *)rxNew) +#define CO_CANrxNew_READ(rxNew) ((bool_t)rxNew) /** Set new message flag */ #define CO_CANrxNew_SET(rxNew) { __sync_synchronize(); rxNew = (void *)1L; } /** Clear new message flag */ From d50e50e2c6ecbcd4519040e6c5a12ec76747e773 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 24 Jan 2020 18:57:38 +0100 Subject: [PATCH 009/520] socketCAN related updates - move stack/socketCAN/CO_OD_storage.* in socketCAN/CO_OD_storage.* - CO_CANrxNew_ macros updated - some corrections --- example/CO_driver_target.h | 6 +-- .../socketCAN => socketCAN}/CO_OD_storage.c | 0 .../socketCAN => socketCAN}/CO_OD_storage.h | 0 socketCAN/CO_driver.c | 29 ++++---------- socketCAN/CO_driver_target.h | 40 ++++++++++++++----- socketCAN/CO_error.c | 1 + socketCAN/CO_error.h | 6 +-- stack/CO_HBconsumer.c | 1 + stack/CO_LSSslave.c | 2 +- stack/CO_driver.h | 18 ++++++--- 10 files changed, 58 insertions(+), 45 deletions(-) rename {stack/socketCAN => socketCAN}/CO_OD_storage.c (100%) rename {stack/socketCAN => socketCAN}/CO_OD_storage.h (100%) diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 0232c2ae..655e29a3 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -105,13 +105,13 @@ typedef struct { /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() -#define CO_CANrxNew_READ(rxNew) ((bool_t)rxNew) +#define CO_CANrxNew_READ(rxNew) ((rxNew) != NULL) #define CO_CANrxNew_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} -#define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = (void*)0L;} +#define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* CO_DRIVER_TARGET */ diff --git a/stack/socketCAN/CO_OD_storage.c b/socketCAN/CO_OD_storage.c similarity index 100% rename from stack/socketCAN/CO_OD_storage.c rename to socketCAN/CO_OD_storage.c diff --git a/stack/socketCAN/CO_OD_storage.h b/socketCAN/CO_OD_storage.h similarity index 100% rename from stack/socketCAN/CO_OD_storage.h rename to socketCAN/CO_OD_storage.h diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 549ac192..3218fcb2 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -282,7 +282,8 @@ CO_ReturnError_t CO_CANmodule_init( #ifndef CO_DRIVER_MULTI_INTERFACE /* add one interface */ - ret = CO_CANmodule_addInterface(CANmodule, (int32_t)CANptr); + intptr_t CANaddr = (intptr_t)CANptr; + ret = CO_CANmodule_addInterface(CANmodule, (int32_t)CANaddr); if (ret != CO_ERROR_NO) { CO_CANmodule_disable(CANmodule); } @@ -468,28 +469,12 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) } -/******************************************************************************/ -static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg) { - CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; - /* remove socketCAN flags */ - return (uint16_t) (rxMsgCasted->ident & CAN_SFF_MASK); -} -static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg) { - CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; - return (uint8_t) (rxMsgCasted->DLC); -} -static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg) { - CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; - return (uint8_t *) (rxMsgCasted->data); -} - - /******************************************************************************/ CO_ReturnError_t CO_CANrxBufferInit( CO_CANmodule_t *CANmodule, - uint32_t index, - uint32_t ident, - uint32_t mask, + uint16_t index, + uint16_t ident, + uint16_t mask, bool_t rtr, void *object, void (*CANrx_callback)(void *object, void *message)) @@ -593,8 +578,8 @@ bool_t CO_CANrxBuffer_getInterface( /******************************************************************************/ CO_CANtx_t *CO_CANtxBufferInit( CO_CANmodule_t *CANmodule, - uint32_t index, - uint32_t ident, + uint16_t index, + uint16_t ident, bool_t rtr, uint8_t noOfBytes, bool_t syncFlag) diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index fd10316e..f007af10 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -115,9 +115,20 @@ typedef struct { } CO_CANrxMsg_t; /* Access to received CAN message */ -static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg); -static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg); -static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg); +static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg) { + CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; + return (uint16_t) (rxMsgCasted->ident & CAN_SFF_MASK); +} +static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg) { + CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; + return (uint8_t) (rxMsgCasted->DLC); +} +static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg) { + CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; + return (uint8_t *) (rxMsgCasted->data); +} + + /* Received message object */ typedef struct { @@ -138,6 +149,7 @@ typedef struct { uint8_t DLC; uint8_t padding[3]; /* ensure alignment */ uint8_t data[8]; + volatile bool_t bufferFull; /* not used */ volatile bool_t syncFlag; /* info about transmit message */ int32_t CANbaseAddress; /* CAN Interface identifier to use */ @@ -189,19 +201,27 @@ typedef struct { /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ extern pthread_mutex_t CO_EMCY_mutex; -static inline int CO_LOCK_EMCY() { return pthread_mutex_lock(&CO_EMCY_mutex); } -static inline void CO_UNLOCK_EMCY() { (void)pthread_mutex_unlock(&CO_EMCY_mutex); } +static inline int CO_LOCK_EMCY() { + return pthread_mutex_lock(&CO_EMCY_mutex); +} +static inline void CO_UNLOCK_EMCY() { + (void)pthread_mutex_unlock(&CO_EMCY_mutex); +} /* (un)lock critical section when accessing Object Dictionary */ extern pthread_mutex_t CO_OD_mutex; -static inline int CO_LOCK_OD() { return pthread_mutex_lock(&CO_OD_mutex); } -static inline void CO_UNLOCK_OD() { (void)pthread_mutex_unlock(&CO_OD_mutex); } +static inline int CO_LOCK_OD() { + return pthread_mutex_lock(&CO_OD_mutex); +} +static inline void CO_UNLOCK_OD() { + (void)pthread_mutex_unlock(&CO_OD_mutex); +} /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() {__sync_synchronize();} -#define CO_CANrxNew_READ(rxNew) ((bool_t)rxNew) +#define CO_CANrxNew_READ(rxNew) ((rxNew) != NULL) #define CO_CANrxNew_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} -#define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = (void*)0L;} +#define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} #ifdef CO_DRIVER_MULTI_INTERFACE @@ -282,6 +302,6 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* CO_DRIVER_TARGET */ diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index fd652ea6..b8aa2cd4 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -29,6 +29,7 @@ #include #include +#include "CO_driver.h" #include "CO_error.h" diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 3e887d22..732c1a80 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -28,12 +28,12 @@ #ifndef CO_ERROR_H #define CO_ERROR_H +#include + #ifdef __cplusplus extern "C" { #endif -#include "CO_driver_base.h" - /** * driver interface state * @@ -75,7 +75,7 @@ typedef struct { uint32_t noackCounter; - volatile bool_t listenOnly; /**< set to listen only mode */ + volatile unsigned char listenOnly; /**< set to listen only mode */ struct timespec timestamp; /**< listen only mode started at this time */ } CO_CANinterfaceErrorhandler_t; diff --git a/stack/CO_HBconsumer.c b/stack/CO_HBconsumer.c index d699c0bc..725910bf 100644 --- a/stack/CO_HBconsumer.c +++ b/stack/CO_HBconsumer.c @@ -71,6 +71,7 @@ static void CO_HBcons_monitoredNodeConfig( monitoredNode->time = time; monitoredNode->NMTstate = CO_NMT_INITIALIZING; monitoredNode->HBstate = CO_HBconsumer_UNCONFIGURED; + CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); /* is channel used */ if(monitoredNode->nodeId && monitoredNode->time){ diff --git a/stack/CO_LSSslave.c b/stack/CO_LSSslave.c index 77f967ee..6c5a7154 100644 --- a/stack/CO_LSSslave.c +++ b/stack/CO_LSSslave.c @@ -104,7 +104,7 @@ static void CO_LSSslave_serviceSwitchStateSelective( static void CO_LSSslave_serviceConfig( CO_LSSslave_t *LSSslave, CO_LSS_cs_t service, - const void *msg) + void *msg) { uint8_t nid; uint8_t tableSelector; diff --git a/stack/CO_driver.h b/stack/CO_driver.h index 8eb56494..5265a9ab 100644 --- a/stack/CO_driver.h +++ b/stack/CO_driver.h @@ -194,7 +194,9 @@ void CANrx_callback(void *object, void *rxMsg); * @param rxMsg Pointer to received message * @return 11-bit CAN standard identifier. */ -static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg); +static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg) { + return 0; +} /** * CANrx_callback() can read Data Length Code from received CAN message @@ -204,7 +206,9 @@ static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg); * @param rxMsg Pointer to received message * @return data length in bytes (0 to 8) */ -static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg); +static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg) { + return 0; +} /** * CANrx_callback() can read pointer to data from received CAN message @@ -214,7 +218,9 @@ static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg); * @param rxMsg Pointer to received message * @return pointer to data buffer */ -static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg); +static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg) { + return NULL; +} /** * Configuration object for CAN received message for specific \ref CO_obj @@ -369,11 +375,11 @@ typedef struct { #define CO_UNLOCK_OD() /** Check if new message has arrived */ -#define CO_CANrxNew_READ(rxNew) ((bool_t)rxNew) +#define CO_CANrxNew_READ(rxNew) ((rxNew) != NULL) /** Set new message flag */ #define CO_CANrxNew_SET(rxNew) { __sync_synchronize(); rxNew = (void *)1L; } /** Clear new message flag */ -#define CO_CANrxNew_CLEAR(rxNew) { __sync_synchronize(); rxNew = (void *)0L; } +#define CO_CANrxNew_CLEAR(rxNew) { __sync_synchronize(); rxNew = NULL; } /** @} */ #endif /* CO_DOXYGEN */ @@ -595,6 +601,6 @@ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* CO_DRIVER_H */ From 0efcf4b1b5893e9b4dbab064eb5d3e79f93fbb58 Mon Sep 17 00:00:00 2001 From: Marcel Maage <49716622+joao404@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:18:46 +0100 Subject: [PATCH 010/520] Added typecast needed for g++ g++ throws several errors when compiling because of missed typecasts. Files can no be compiled to .o. --- stack/CO_LSSslave.c | 2 +- stack/CO_NMT_Heartbeat.c | 10 +++++----- stack/CO_PDO.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/stack/CO_LSSslave.c b/stack/CO_LSSslave.c index 6c5a7154..cb4bb1bb 100644 --- a/stack/CO_LSSslave.c +++ b/stack/CO_LSSslave.c @@ -341,7 +341,7 @@ static void CO_LSSslave_receive(void *object, void *msg) LSSslave = (CO_LSSslave_t*)object; /* this is the correct pointer type of the first argument */ if(DLC == 8){ - CO_LSS_cs_t cs = data[0]; + CO_LSS_cs_t cs = (CO_LSS_cs_t) data[0]; if (CO_LSS_CS_SERVICE_IS_SWITCH_GLOBAL(cs)) { CO_LSSslave_serviceSwitchStateGlobal(LSSslave, cs, msg); diff --git a/stack/CO_NMT_Heartbeat.c b/stack/CO_NMT_Heartbeat.c index 867bdc54..2b5365a3 100644 --- a/stack/CO_NMT_Heartbeat.c +++ b/stack/CO_NMT_Heartbeat.c @@ -73,7 +73,7 @@ static void CO_NMT_receive(void *object, void *msg){ } if(NMT->pFunctNMT!=NULL && currentOperatingState!=NMT->operatingState){ - NMT->pFunctNMT(NMT->operatingState); + NMT->pFunctNMT((CO_NMT_internalState_t) NMT->operatingState); } } } @@ -152,7 +152,7 @@ void CO_NMT_initCallback( if(NMT != NULL){ NMT->pFunctNMT = pFunctNMT; if(NMT->pFunctNMT != NULL){ - NMT->pFunctNMT(NMT->operatingState); + NMT->pFunctNMT((CO_NMT_internalState_t) NMT->operatingState); } } } @@ -336,10 +336,10 @@ CO_NMT_reset_cmd_t CO_NMT_process( } if(NMT->pFunctNMT!=NULL && currentOperatingState!=NMT->operatingState){ - NMT->pFunctNMT(NMT->operatingState); + NMT->pFunctNMT((CO_NMT_internalState_t) NMT->operatingState); } - return NMT->resetCommand; + return (CO_NMT_reset_cmd_t) NMT->resetCommand; } @@ -348,7 +348,7 @@ CO_NMT_internalState_t CO_NMT_getInternalState( CO_NMT_t *NMT) { if(NMT != NULL){ - return NMT->operatingState; + return (CO_NMT_internalState_t) NMT->operatingState; } return CO_NMT_INITIALIZING; } diff --git a/stack/CO_PDO.c b/stack/CO_PDO.c index f4446663..c37a23e7 100644 --- a/stack/CO_PDO.c +++ b/stack/CO_PDO.c @@ -617,7 +617,7 @@ static CO_SDO_abortCode_t CO_ODF_RPDOmap(CO_ODF_arg_t *ODF_arg){ return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds PDO length. */ /* configure mapping */ - return CO_RPDOconfigMap(RPDO, *value); + return (CO_SDO_abortCode_t) CO_RPDOconfigMap(RPDO, *value); } /* mappedObject */ @@ -632,7 +632,7 @@ static CO_SDO_abortCode_t CO_ODF_RPDOmap(CO_ODF_arg_t *ODF_arg){ return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */ /* verify if mapping is correct */ - return CO_PDOfindMap( + return (CO_SDO_abortCode_t) CO_PDOfindMap( RPDO->SDO, value, 0, @@ -683,7 +683,7 @@ static CO_SDO_abortCode_t CO_ODF_TPDOmap(CO_ODF_arg_t *ODF_arg){ return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds PDO length. */ /* configure mapping */ - return CO_TPDOconfigMap(TPDO, *value); + return (CO_SDO_abortCode_t) CO_TPDOconfigMap(TPDO, *value); } /* mappedObject */ @@ -698,7 +698,7 @@ static CO_SDO_abortCode_t CO_ODF_TPDOmap(CO_ODF_arg_t *ODF_arg){ return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */ /* verify if mapping is correct */ - return CO_PDOfindMap( + return (CO_SDO_abortCode_t) CO_PDOfindMap( TPDO->SDO, value, 1, From 729a139c127bf41b666c548c3dfeed0a5b58725d Mon Sep 17 00:00:00 2001 From: Miles Simpson Date: Thu, 30 Jan 2020 08:58:12 -0800 Subject: [PATCH 011/520] Implementing PDO and SYNC timerNext_us return value --- CANopen.c | 38 +++++++++++++++++++++++++++++++++++--- CANopen.h | 24 +++++++++++++++++++++++- stack/CO_PDO.c | 18 +++++++++++++----- stack/CO_PDO.h | 4 +++- stack/CO_SYNC.c | 18 +++++++++++++++++- stack/CO_SYNC.h | 4 +++- 6 files changed, 94 insertions(+), 12 deletions(-) diff --git a/CANopen.c b/CANopen.c index 5443aeaa..916cb394 100644 --- a/CANopen.c +++ b/CANopen.c @@ -841,7 +841,6 @@ CO_NMT_reset_cmd_t CO_process( } } - for(i=0; iSDO[i], @@ -892,7 +891,7 @@ bool_t CO_process_SYNC( { bool_t syncWas = false; - switch(CO_SYNC_process(co->SYNC, timeDifference_us, OD_synchronousWindowLength)){ + switch(CO_SYNC_process(co->SYNC, timeDifference_us, OD_synchronousWindowLength, NULL)){ case 1: //immediately after the SYNC message syncWas = true; break; @@ -930,6 +929,39 @@ void CO_process_TPDO( for(i=0; iTPDO[i]->sendRequest) co->TPDO[i]->sendRequest = CO_TPDOisCOS(co->TPDO[i]); - CO_TPDO_process(co->TPDO[i], syncWas, timeDifference_us); + CO_TPDO_process(co->TPDO[i], syncWas, timeDifference_us, NULL); } } + + +/******************************************************************************/ +bool_t CO_process_SYNC_PDO( + CO_t *CO, + uint32_t timeDifference_us, + uint32_t *timerNext_us) +{ + int16_t i; + bool_t syncWas = false; + + switch(CO_SYNC_process(CO->SYNC, timeDifference_us, OD_synchronousWindowLength, timerNext_us)){ + case 1: //immediately after the SYNC message + syncWas = true; + break; + case 2: //outside SYNC window + CO_CANclearPendingSyncPDOs(CO->CANmodule[0]); + break; + } + + /* Process RPDOs */ + for(i=0; iRPDO[i], syncWas); + } + + /* Verify PDO Change Of State and process TPDOs */ + for(i=0; iTPDO[i]->sendRequest) CO->TPDO[i]->sendRequest = CO_TPDOisCOS(CO->TPDO[i]); + CO_TPDO_process(CO->TPDO[i], syncWas, timeDifference_us, timerNext_us); + } + + return syncWas; +} diff --git a/CANopen.h b/CANopen.h index e97bb9aa..569fdbea 100644 --- a/CANopen.h +++ b/CANopen.h @@ -60,7 +60,6 @@ extern "C" { #include "CO_LSSmaster.h" #endif - /* * CANopen stack object combines pointers to all CANopen objects. */ @@ -262,6 +261,29 @@ void CO_process_TPDO( bool_t syncWas, uint32_t timeDifference_us); + +/** + * Process CANopen SYNC and PDO objects. + * + * Function must be called cyclically from real time thread with constant. + * interval (1ms typically). It processes SYNC and PDO CANopen objects. + * + * @param CO This object. + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timerNext_us Return value - info to OS - maximum delay after function + * should be called next time in [microseconds]. Value can be used for OS + * sleep time. Initial value must be set to something, 1000us typically. + * Output will be equal or lower to initial value. If there is new object + * to process, delay should be suspended and this function should be + * called immediately. Parameter is ignored if NULL. + * + * @return True, if CANopen SYNC message was just received or transmitted. + */ +bool_t CO_process_SYNC_PDO( + CO_t *CO, + uint32_t timeDifference_us, + uint32_t *timerNext_us); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/stack/CO_PDO.c b/stack/CO_PDO.c index c37a23e7..7204990e 100644 --- a/stack/CO_PDO.c +++ b/stack/CO_PDO.c @@ -973,8 +973,13 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ void CO_TPDO_process( CO_TPDO_t *TPDO, bool_t syncWas, - uint32_t timeDifference_us) + uint32_t timeDifference_us, + uint32_t *timerNext_us) { + /* update timers */ + TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) : 0; + TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) ? (TPDO->eventTimer - timeDifference_us) : 0; + if(TPDO->valid && *TPDO->operatingState == CO_NMT_OPERATIONAL){ /* Send PDO by application request or by Event timer */ @@ -986,6 +991,13 @@ void CO_TPDO_process( TPDO->eventTimer = ((uint32_t) TPDO->TPDOCommPar->eventTimer) * 1000; } } + if(timerNext_us != NULL){ + if(TPDO->TPDOCommPar->inhibitTime && *timerNext_us > TPDO->inhibitTimer){ + *timerNext_us = TPDO->inhibitTimer + 1; /* Schedule for just beyond inhibit window */ + }else if(TPDO->TPDOCommPar->eventTimer && *timerNext_us > TPDO->eventTimer){ + *timerNext_us = TPDO->eventTimer; /* Schedule for next maximum event time */ + } + } } /* Synchronous PDOs */ @@ -1024,8 +1036,4 @@ void CO_TPDO_process( if(TPDO->TPDOCommPar->transmissionType>=254) TPDO->sendRequest = 1; else TPDO->sendRequest = 0; } - - /* update timers */ - TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) : 0; - TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) ? (TPDO->eventTimer - timeDifference_us) : 0; } diff --git a/stack/CO_PDO.h b/stack/CO_PDO.h index 0f7b4a2b..b76d47e8 100644 --- a/stack/CO_PDO.h +++ b/stack/CO_PDO.h @@ -374,11 +374,13 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas); * @param TPDO This object. * @param syncWas True, if CANopen SYNC message was just received or transmitted. * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timerNext_us Return value - info to OS - see CO_process_SYNC_PDO(). */ void CO_TPDO_process( CO_TPDO_t *TPDO, bool_t syncWas, - uint32_t timeDifference_us); + uint32_t timeDifference_us, + uint32_t *timerNext_us); #ifdef __cplusplus } diff --git a/stack/CO_SYNC.c b/stack/CO_SYNC.c index c598313f..c299ef00 100644 --- a/stack/CO_SYNC.c +++ b/stack/CO_SYNC.c @@ -301,7 +301,8 @@ CO_ReturnError_t CO_SYNC_init( uint8_t CO_SYNC_process( CO_SYNC_t *SYNC, uint32_t timeDifference_us, - uint32_t ObjDict_synchronousWindowLength) + uint32_t ObjDict_synchronousWindowLength, + uint32_t *timerNext_us) { uint8_t ret = 0; uint32_t timerNew; @@ -320,6 +321,7 @@ uint8_t CO_SYNC_process( /* SYNC producer */ if(SYNC->isProducer && SYNC->periodTime){ + uint32_t diff; if(SYNC->timer >= SYNC->periodTime){ if(++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1; SYNC->timer = 0; @@ -327,6 +329,16 @@ uint8_t CO_SYNC_process( SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; SYNC->CANtxBuff->data[0] = SYNC->counter; CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff); + diff = SYNC->periodTime; + }else{ + /* Calculate when next SYNC needs to be sent */ + diff = SYNC->periodTime - SYNC->timer; + } + /* Set lower timerNext_us if necessary. */ + if(timerNext_us != NULL){ + if(*timerNext_us > diff){ + *timerNext_us = diff; + } } } @@ -340,6 +352,10 @@ uint8_t CO_SYNC_process( } else{ SYNC->curentSyncTimeIsInsideWindow = true; + /* Immediately continue while inside the window */ + if(timerNext_us != NULL){ + *timerNext_us = 0; + } } } else{ diff --git a/stack/CO_SYNC.h b/stack/CO_SYNC.h index 82463f57..80e44493 100644 --- a/stack/CO_SYNC.h +++ b/stack/CO_SYNC.h @@ -146,6 +146,7 @@ CO_ReturnError_t CO_SYNC_init( * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param ObjDict_synchronousWindowLength _Synchronous window length_ variable from * Object dictionary (index 0x1007). + * @param timerNext_us Return value - info to OS - see CO_process_SYNC_PDO(). * * @return 0: No special meaning. * @return 1: New SYNC message recently received or was just transmitted. @@ -154,7 +155,8 @@ CO_ReturnError_t CO_SYNC_init( uint8_t CO_SYNC_process( CO_SYNC_t *SYNC, uint32_t timeDifference_us, - uint32_t ObjDict_synchronousWindowLength); + uint32_t ObjDict_synchronousWindowLength, + uint32_t *timerNext_us); #ifdef __cplusplus } From 1de453c92fdbf4d32064cb0cb04180b948acf904 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 31 Jan 2020 12:25:22 +0100 Subject: [PATCH 012/520] Update CO_SYNC.c `*timerNext_us` added also to 'Verify timeout' --- stack/CO_SYNC.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/stack/CO_SYNC.c b/stack/CO_SYNC.c index c299ef00..3de1f9f1 100644 --- a/stack/CO_SYNC.c +++ b/stack/CO_SYNC.c @@ -363,8 +363,17 @@ uint8_t CO_SYNC_process( } /* Verify timeout of SYNC */ - if(SYNC->periodTime && SYNC->timer > SYNC->periodTimeoutTime && *SYNC->operatingState == CO_NMT_OPERATIONAL) - CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); + if(SYNC->periodTime && *SYNC->operatingState == CO_NMT_OPERATIONAL) { + if(SYNC->timer > SYNC->periodTimeoutTime) { + CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); + } + else if(timerNext_us != NULL) { + uint32_t diff = SYNC->periodTimeoutTime - SYNC->timer; + if(*timerNext_us > diff){ + *timerNext_us = diff; + } + } + } } else { CO_CANrxNew_CLEAR(SYNC->CANrxNew); From 38d5181807d08ea4e1d006d70d4add853c8b64d6 Mon Sep 17 00:00:00 2001 From: Miles Simpson Date: Fri, 31 Jan 2020 08:02:18 -0800 Subject: [PATCH 013/520] Implemented changes based on PR feedback --- CANopen.c | 14 ++++++++------ CANopen.h | 4 +++- stack/CO_PDO.c | 4 ++-- stack/CO_SYNC.c | 4 ---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CANopen.c b/CANopen.c index 916cb394..561a058f 100644 --- a/CANopen.c +++ b/CANopen.c @@ -935,33 +935,35 @@ void CO_process_TPDO( /******************************************************************************/ +#if CO_NO_SYNC == 1 bool_t CO_process_SYNC_PDO( - CO_t *CO, + CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { int16_t i; bool_t syncWas = false; - switch(CO_SYNC_process(CO->SYNC, timeDifference_us, OD_synchronousWindowLength, timerNext_us)){ + switch(CO_SYNC_process(co->SYNC, timeDifference_us, OD_synchronousWindowLength, timerNext_us)){ case 1: //immediately after the SYNC message syncWas = true; break; case 2: //outside SYNC window - CO_CANclearPendingSyncPDOs(CO->CANmodule[0]); + CO_CANclearPendingSyncPDOs(co->CANmodule[0]); break; } /* Process RPDOs */ for(i=0; iRPDO[i], syncWas); + CO_RPDO_process(co->RPDO[i], syncWas); } /* Verify PDO Change Of State and process TPDOs */ for(i=0; iTPDO[i]->sendRequest) CO->TPDO[i]->sendRequest = CO_TPDOisCOS(CO->TPDO[i]); - CO_TPDO_process(CO->TPDO[i], syncWas, timeDifference_us, timerNext_us); + if(!co->TPDO[i]->sendRequest) co->TPDO[i]->sendRequest = CO_TPDOisCOS(co->TPDO[i]); + CO_TPDO_process(co->TPDO[i], syncWas, timeDifference_us, timerNext_us); } return syncWas; } +#endif diff --git a/CANopen.h b/CANopen.h index 569fdbea..d7dc413b 100644 --- a/CANopen.h +++ b/CANopen.h @@ -262,6 +262,7 @@ void CO_process_TPDO( uint32_t timeDifference_us); +#if CO_NO_SYNC == 1 /** * Process CANopen SYNC and PDO objects. * @@ -280,9 +281,10 @@ void CO_process_TPDO( * @return True, if CANopen SYNC message was just received or transmitted. */ bool_t CO_process_SYNC_PDO( - CO_t *CO, + CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us); +#endif #ifdef __cplusplus } diff --git a/stack/CO_PDO.c b/stack/CO_PDO.c index 7204990e..cf0eb470 100644 --- a/stack/CO_PDO.c +++ b/stack/CO_PDO.c @@ -992,8 +992,8 @@ void CO_TPDO_process( } } if(timerNext_us != NULL){ - if(TPDO->TPDOCommPar->inhibitTime && *timerNext_us > TPDO->inhibitTimer){ - *timerNext_us = TPDO->inhibitTimer + 1; /* Schedule for just beyond inhibit window */ + if(TPDO->sendRequest && *timerNext_us > TPDO->inhibitTimer){ + *timerNext_us = TPDO->inhibitTimer; /* Schedule for just beyond inhibit window */ }else if(TPDO->TPDOCommPar->eventTimer && *timerNext_us > TPDO->eventTimer){ *timerNext_us = TPDO->eventTimer; /* Schedule for next maximum event time */ } diff --git a/stack/CO_SYNC.c b/stack/CO_SYNC.c index 3de1f9f1..d34456a4 100644 --- a/stack/CO_SYNC.c +++ b/stack/CO_SYNC.c @@ -352,10 +352,6 @@ uint8_t CO_SYNC_process( } else{ SYNC->curentSyncTimeIsInsideWindow = true; - /* Immediately continue while inside the window */ - if(timerNext_us != NULL){ - *timerNext_us = 0; - } } } else{ From 1d051aa3d2c4b89bfd7d9f55ab1e64bf0d86fab1 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 1 Feb 2020 10:14:52 +0100 Subject: [PATCH 014/520] minor compiler error in CO_SDOmaster.c #56 --- stack/CO_SDOmaster.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/stack/CO_SDOmaster.c b/stack/CO_SDOmaster.c index fbff8b6e..e33bbcea 100644 --- a/stack/CO_SDOmaster.c +++ b/stack/CO_SDOmaster.c @@ -630,6 +630,9 @@ CO_SDOclient_return_t CO_SDOclientDownload( CO_SDOTxBufferClear(SDO_C); switch (SDO_C->state){ + uint16_t i, j; + uint16_t tmp16; + /* ABORT */ case SDO_STATE_ABORT:{ SDO_C->state = SDO_STATE_NOTDEFINED; @@ -639,7 +642,6 @@ CO_SDOclient_return_t CO_SDOclientDownload( } /* SEGMENTED */ case SDO_STATE_DOWNLOAD_REQUEST:{ - uint16_t i, j; /* calculate length to be sent */ j = SDO_C->bufferSize - SDO_C->bufferOffset; if(j > 7) j = 7; @@ -674,7 +676,6 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* set data */ SDO_C->block_noData = 0; - uint8_t i; for(i = 1; i < 8; i++){ if(SDO_C->bufferOffset < SDO_C->bufferSize){ SDO_C->CANtxBuff->data[i] = *(SDO_C->buffer + SDO_C->bufferOffset); @@ -703,8 +704,6 @@ CO_SDOclient_return_t CO_SDOclientDownload( case SDO_STATE_BLOCKDOWNLOAD_CRC:{ SDO_C->CANtxBuff->data[0] = (CCS_DOWNLOAD_BLOCK<<5) | (SDO_C->block_noData << 2) | 0x01; - uint16_t tmp16; - tmp16 = crc16_ccitt((unsigned char *)SDO_C->buffer, (unsigned int)SDO_C->bufferSize, 0); SDO_C->CANtxBuff->data[1] = (uint8_t) tmp16; From c19879b659ac8ee1cdd987391c04ce42d92dcbe1 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 Feb 2020 20:28:33 +0100 Subject: [PATCH 015/520] Time base CHANGED TO MICROSECONDS in all objects. FIX OS! - Necessary to update Time base in OS too - call to CO_process() function. - timerNext_us info to OS implemented in in all objects. - CO_NMT_blinkingProcess50ms() moved inside CO_NMT_process(). - CO_HBconsumer_process() function optimized and revised. - Bugfix "timeDifference_us = 0;" inside the for loop. --- CANopen.c | 34 ++---- CANopen.h | 14 +-- socketCAN/CO_driver.c | 4 +- socketCAN/CO_notify_pipe.h | 4 +- stack/CO_Emergency.c | 24 ++-- stack/CO_Emergency.h | 12 +- stack/CO_HBconsumer.c | 234 +++++++++++++++++++------------------ stack/CO_HBconsumer.h | 18 ++- stack/CO_LSSmaster.c | 88 +++++++------- stack/CO_LSSmaster.h | 46 ++++---- stack/CO_LSSslave.c | 10 +- stack/CO_LSSslave.h | 4 +- stack/CO_NMT_Heartbeat.c | 157 +++++++++++++------------ stack/CO_NMT_Heartbeat.h | 31 ++--- stack/CO_PDO.h | 2 +- stack/CO_SDO.c | 21 ++-- stack/CO_SDO.h | 16 +-- stack/CO_SDOmaster.c | 71 ++++++++--- stack/CO_SDOmaster.h | 32 +++-- stack/CO_SYNC.h | 2 +- stack/CO_TIME.c | 3 +- stack/CO_TIME.h | 4 +- 22 files changed, 438 insertions(+), 393 deletions(-) diff --git a/CANopen.c b/CANopen.c index 358f3588..695e18d1 100644 --- a/CANopen.c +++ b/CANopen.c @@ -525,6 +525,7 @@ CO_ReturnError_t CO_CANopenInit( CO_OD_NoOfElements, CO_SDO_ODExtensions, nodeId, + 1000, CO->CANmodule[0], CO_RXCAN_SDO_SRV+i, CO->CANmodule[0], @@ -815,63 +816,52 @@ void CO_delete(void *CANptr){ /******************************************************************************/ CO_NMT_reset_cmd_t CO_process( CO_t *co, - uint16_t timeDifference_ms, - uint16_t *timerNext_ms) + uint32_t timeDifference_us, + uint32_t *timerNext_us) { uint8_t i; bool_t NMTisPreOrOperational = false; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; -#ifdef CO_USE_LEDS - static uint16_t ms50 = 0; -#endif /* CO_USE_LEDS */ if(co->NMT->operatingState == CO_NMT_PRE_OPERATIONAL || co->NMT->operatingState == CO_NMT_OPERATIONAL) NMTisPreOrOperational = true; -#ifdef CO_USE_LEDS - ms50 += timeDifference_ms; - if(ms50 >= 50){ - ms50 -= 50; - CO_NMT_blinkingProcess50ms(co->NMT); - } -#endif /* CO_USE_LEDS */ - for(i=0; iSDO[i], NMTisPreOrOperational, - timeDifference_ms, - 1000, - timerNext_ms); + timeDifference_us, + timerNext_us); } CO_EM_process( co->emPr, NMTisPreOrOperational, - timeDifference_ms * 10, + timeDifference_us, OD_inhibitTimeEMCY, - timerNext_ms); + timerNext_us); reset = CO_NMT_process( co->NMT, - timeDifference_ms, + timeDifference_us, OD_producerHeartbeatTime, OD_NMTStartup, OD_errorRegister, OD_errorBehavior, - timerNext_ms); + timerNext_us); CO_HBconsumer_process( co->HBcons, NMTisPreOrOperational, - timeDifference_ms); + timeDifference_us, + timerNext_us); #if CO_NO_TIME == 1 CO_TIME_process( co->TIME, - timeDifference_ms); + timeDifference_us); #endif return reset; diff --git a/CANopen.h b/CANopen.h index d7dc413b..2f6e794c 100644 --- a/CANopen.h +++ b/CANopen.h @@ -200,10 +200,10 @@ void CO_delete(void *CANptr); * objects. * * @param co CANopen object. - * @param timeDifference_ms Time difference from previous function call in [milliseconds]. - * @param timerNext_ms Return value - info to OS - maximum delay after function - * should be called next time in [milliseconds]. Value can be used for OS - * sleep time. Initial value must be set to something, 50ms typically. + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timerNext_us [out] info to OS - maximum delay after function + * should be called next time in [microseconds]. Value can be used for OS + * sleep time. Initial value must be set to something, 50000us typically. * Output will be equal or lower to initial value. If there is new object * to process, delay should be suspended and this function should be * called immediately. Parameter is ignored if NULL. @@ -212,8 +212,8 @@ void CO_delete(void *CANptr); */ CO_NMT_reset_cmd_t CO_process( CO_t *co, - uint16_t timeDifference_ms, - uint16_t *timerNext_ms); + uint32_t timeDifference_us, + uint32_t *timerNext_us); #if CO_NO_SYNC == 1 @@ -271,7 +271,7 @@ void CO_process_TPDO( * * @param CO This object. * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param timerNext_us Return value - info to OS - maximum delay after function + * @param timerNext_us [out] info to OS - maximum delay after function * should be called next time in [microseconds]. Value can be used for OS * sleep time. Initial value must be set to something, 1000us typically. * Output will be equal or lower to initial value. If there is new object diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 3218fcb2..9b3d6d44 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -1,7 +1,5 @@ /* - * CAN module object for Linux socketCAN. - * - * This file is a template for other microcontrollers. + * Linux socketCAN interface for CANopenNode. * * @file CO_driver.c * @ingroup CO_driver diff --git a/socketCAN/CO_notify_pipe.h b/socketCAN/CO_notify_pipe.h index b7bea177..52a46cc0 100644 --- a/socketCAN/CO_notify_pipe.h +++ b/socketCAN/CO_notify_pipe.h @@ -1,7 +1,5 @@ /** - * CAN module object for Linux socketCAN. - * - * This file is a template for other microcontrollers. + * Notify pipe for Linux threads. * * @file CO_notify_pipe.h * @ingroup CO_driver diff --git a/stack/CO_Emergency.c b/stack/CO_Emergency.c index 4ee75b51..60366bd6 100644 --- a/stack/CO_Emergency.c +++ b/stack/CO_Emergency.c @@ -232,15 +232,16 @@ void CO_EM_initCallbackRx( void CO_EM_process( CO_EMpr_t *emPr, bool_t NMTisPreOrOperational, - uint16_t timeDifference_100us, - uint16_t emInhTime, - uint16_t *timerNext_ms) + uint32_t timeDifference_us, + uint16_t emInhTime_100us, + uint32_t *timerNext_us) { CO_EM_t *em = emPr->em; uint8_t errorRegister; uint8_t errorMask; uint8_t i; + uint32_t emInhTime_us = (uint32_t)emInhTime_100us * 100; /* verify errors from driver and other */ CO_CANverifyErrors(emPr->CANdev); @@ -270,8 +271,8 @@ void CO_EM_process( *emPr->errorRegister = (*emPr->errorRegister & errorMask) | errorRegister; /* inhibit time */ - if(emPr->inhibitEmTimer < emInhTime){ - emPr->inhibitEmTimer += timeDifference_100us; + if (emPr->inhibitEmTimer < emInhTime_us) { + emPr->inhibitEmTimer += timeDifference_us; } /* send Emergency message. */ @@ -282,7 +283,7 @@ void CO_EM_process( uint32_t preDEF; /* preDefinedErrorField */ uint16_t diff; - if (emPr->inhibitEmTimer >= emInhTime) { + if (emPr->inhibitEmTimer >= emInhTime_us) { /* inhibit time elapsed, send message */ /* add error register */ @@ -323,11 +324,12 @@ void CO_EM_process( /* send CAN message */ CO_CANsend(emPr->CANdev, emPr->CANtxBuff); } - - /* check again after inhibit time elapsed */ - diff = (emInhTime + 9) / 10; /* time difference in ms, always round up */ - if (timerNext_ms != NULL && *timerNext_ms > diff) { - *timerNext_ms = diff; + else if (timerNext_us != NULL) { + /* check again after inhibit time elapsed */ + diff = emInhTime_us - emPr->inhibitEmTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } } } diff --git a/stack/CO_Emergency.h b/stack/CO_Emergency.h index 40bb9ae2..4bb3d85a 100644 --- a/stack/CO_Emergency.h +++ b/stack/CO_Emergency.h @@ -339,7 +339,7 @@ typedef struct{ uint32_t *preDefErr; /**< From CO_EM_init() */ uint8_t preDefErrSize; /**< From CO_EM_init() */ uint8_t preDefErrNoOfErrors;/**< Number of active errors in preDefErr */ - uint16_t inhibitEmTimer; /**< Internal timer for emergency message */ + uint32_t inhibitEmTimer; /**< Internal timer for emergency message */ CO_EM_t *em; /**< CO_EM_t sub object is included here */ CO_CANmodule_t *CANdev; /**< From CO_EM_init() */ CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer */ @@ -432,16 +432,16 @@ void CO_EM_initCallbackRx( * * @param emPr This object. * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. - * @param timeDifference_100us Time difference from previous function call in [100 * microseconds]. - * @param emInhTime _Inhibit time EMCY_ (object dictionary, index 0x1015). - * @param timerNext_ms Return value - info to OS - see CO_process(). + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param emInhTime _Inhibit time EMCY_ in [100*us] (object dictionary, index 0x1015). + * @param timerNext_us [out] info to OS - see CO_process(). */ void CO_EM_process( CO_EMpr_t *emPr, bool_t NMTisPreOrOperational, - uint16_t timeDifference_100us, + uint32_t timeDifference_us, uint16_t emInhTime, - uint16_t *timerNext_ms); + uint32_t *timerNext_us); #endif diff --git a/stack/CO_HBconsumer.c b/stack/CO_HBconsumer.c index 725910bf..b3204452 100644 --- a/stack/CO_HBconsumer.c +++ b/stack/CO_HBconsumer.c @@ -52,52 +52,6 @@ static void CO_HBcons_receive(void *object, void *msg){ } -/* - * Configure one monitored node. - */ -static void CO_HBcons_monitoredNodeConfig( - CO_HBconsumer_t *HBcons, - uint8_t idx, - uint8_t nodeId, - uint16_t time) -{ - uint16_t COB_ID; - CO_HBconsNode_t *monitoredNode; - - if(idx >= HBcons->numberOfMonitoredNodes) return; - - monitoredNode = &HBcons->monitoredNodes[idx]; - monitoredNode->nodeId = nodeId; - monitoredNode->time = time; - monitoredNode->NMTstate = CO_NMT_INITIALIZING; - monitoredNode->HBstate = CO_HBconsumer_UNCONFIGURED; - CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); - - /* is channel used */ - if(monitoredNode->nodeId && monitoredNode->time){ - COB_ID = monitoredNode->nodeId + CO_CAN_ID_HEARTBEAT; - monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; - - } - else{ - COB_ID = 0; - monitoredNode->time = 0; - } - - /* configure Heartbeat consumer CAN reception */ - if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { - CO_CANrxBufferInit( - HBcons->CANdevRx, - HBcons->CANdevRxIdxStart + idx, - COB_ID, - 0x7FF, - 0, - (void*)&HBcons->monitoredNodes[idx], - CO_HBcons_receive); - } -} - - /* * OD function for accessing _Consumer Heartbeat Time_ (index 0x1016) from SDO server. * @@ -156,7 +110,9 @@ CO_ReturnError_t CO_HBconsumer_init( HBcons->HBconsTime = HBconsTime; HBcons->monitoredNodes = monitoredNodes; HBcons->numberOfMonitoredNodes = numberOfMonitoredNodes; - HBcons->allMonitoredOperational = 0; + HBcons->allMonitoredActive = false; + HBcons->allMonitoredOperational = CO_NMT_INITIALIZING; + HBcons->NMTisPreOrOperationalPrev = false; HBcons->CANdevRx = CANdevRx; HBcons->CANdevRxIdxStart = CANdevRxIdxStart; @@ -178,7 +134,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( CO_HBconsumer_t *HBcons, uint8_t idx, uint8_t nodeId, - uint16_t consumerTime) + uint16_t consumerTime_ms) { CO_ReturnError_t ret = CO_ERROR_NO; @@ -187,7 +143,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( return CO_ERROR_ILLEGAL_ARGUMENT; } - if((consumerTime != 0) && (nodeId != 0)){ + if((consumerTime_ms != 0) && (nodeId != 0)){ uint8_t i; /* there must not be more entries with same index and time different than zero */ for(i = 0U; inumberOfMonitoredNodes; i++){ @@ -200,9 +156,37 @@ CO_ReturnError_t CO_HBconsumer_initEntry( } } - /* Configure */ - if(ret == CO_ERROR_NO){ - CO_HBcons_monitoredNodeConfig(HBcons, idx, nodeId, consumerTime); + /* Configure one monitored node */ + if (ret == CO_ERROR_NO && idx < HBcons->numberOfMonitoredNodes ) { + uint16_t COB_ID; + + CO_HBconsNode_t * monitoredNode = &HBcons->monitoredNodes[idx]; + monitoredNode->nodeId = nodeId; + monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; + monitoredNode->NMTstate = CO_NMT_INITIALIZING; + CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); + + /* is channel used */ + if (monitoredNode->nodeId && monitoredNode->time_us) { + COB_ID = monitoredNode->nodeId + CO_CAN_ID_HEARTBEAT; + monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; + } + else { + COB_ID = 0; + monitoredNode->time_us = 0; + monitoredNode->HBstate = CO_HBconsumer_UNCONFIGURED; + } + + /* configure Heartbeat consumer CAN reception */ + if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { + CO_CANrxBufferInit(HBcons->CANdevRx, + HBcons->CANdevRxIdxStart + idx, + COB_ID, + 0x7FF, + 0, + (void*)&HBcons->monitoredNodes[idx], + CO_HBcons_receive); + } } return ret; } @@ -264,102 +248,120 @@ void CO_HBconsumer_initCallbackRemoteReset( monitoredNode->functSignalObjectRemoteReset = object; } + /******************************************************************************/ void CO_HBconsumer_process( CO_HBconsumer_t *HBcons, bool_t NMTisPreOrOperational, - uint16_t timeDifference_ms) + uint32_t timeDifference_us, + uint32_t *timerNext_us) { uint8_t i; - uint8_t emcyHeartbeatTimeoutActive = 0; - uint8_t emcyRemoteResetActive = 0; - uint8_t AllMonitoredOperationalCopy; - CO_HBconsNode_t *monitoredNode; + bool_t allMonitoredActiveCurrent = true; + uint8_t allMonitoredOperationalCurrent = CO_NMT_OPERATIONAL; + CO_HBconsNode_t *monitoredNode = &HBcons->monitoredNodes[0]; - AllMonitoredOperationalCopy = 5; - monitoredNode = &HBcons->monitoredNodes[0]; + if (NMTisPreOrOperational && HBcons->NMTisPreOrOperationalPrev) { + for (i=0; inumberOfMonitoredNodes; i++) { + uint32_t timeDifference_us_copy = timeDifference_us; - if(NMTisPreOrOperational){ - for(i=0; inumberOfMonitoredNodes; i++){ - if(monitoredNode->time > 0){/* is node monitored */ - /* Verify if received message is heartbeat or bootup */ - if(CO_CANrxNew_READ(monitoredNode->CANrxNew)){ - if(monitoredNode->NMTstate == CO_NMT_INITIALIZING){ - /* bootup message, call callback */ - if (monitoredNode->pFunctSignalRemoteReset != NULL) { - monitoredNode->pFunctSignalRemoteReset(monitoredNode->nodeId, i, - monitoredNode->functSignalObjectRemoteReset); - } + if (monitoredNode->HBstate == CO_HBconsumer_UNCONFIGURED) { + /* continue, if node is not monitored */ + continue; + } + /* Verify if received message is heartbeat or bootup */ + if (CO_CANrxNew_READ(monitoredNode->CANrxNew)) { + if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) { + /* bootup message, call callback */ + if (monitoredNode->pFunctSignalRemoteReset != NULL) { + monitoredNode->pFunctSignalRemoteReset( + monitoredNode->nodeId, i, + monitoredNode->functSignalObjectRemoteReset); } - else { - /* heartbeat message */ - if (monitoredNode->HBstate!=CO_HBconsumer_ACTIVE && - monitoredNode->pFunctSignalHbStarted!=NULL) { - monitoredNode->pFunctSignalHbStarted(monitoredNode->nodeId, i, - monitoredNode->functSignalObjectHbStarted); - } - monitoredNode->HBstate = CO_HBconsumer_ACTIVE; - monitoredNode->timeoutTimer = 0; /* reset timer */ - timeDifference_ms = 0; + if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) { + CO_errorReport(HBcons->em, + CO_EM_HB_CONSUMER_REMOTE_RESET, + CO_EMC_HEARTBEAT, i); } - CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); - } + monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; - /* Verify timeout */ - if(monitoredNode->timeoutTimer < monitoredNode->time) { - monitoredNode->timeoutTimer += timeDifference_ms; } - if(monitoredNode->HBstate!=CO_HBconsumer_UNCONFIGURED && - monitoredNode->HBstate!=CO_HBconsumer_UNKNOWN) { - if(monitoredNode->timeoutTimer >= monitoredNode->time){ - /* timeout expired */ - CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, i); - emcyHeartbeatTimeoutActive = 1; - - monitoredNode->NMTstate = CO_NMT_INITIALIZING; - if (monitoredNode->HBstate!=CO_HBconsumer_TIMEOUT && - monitoredNode->pFunctSignalTimeout!=NULL) { - monitoredNode->pFunctSignalTimeout(monitoredNode->nodeId, i, - monitoredNode->functSignalObjectTimeout); - } - monitoredNode->HBstate = CO_HBconsumer_TIMEOUT; + else { + /* heartbeat message, call callback */ + if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE && + monitoredNode->pFunctSignalHbStarted != NULL) { + monitoredNode->pFunctSignalHbStarted( + monitoredNode->nodeId, i, + monitoredNode->functSignalObjectHbStarted); } - else if(monitoredNode->NMTstate == CO_NMT_INITIALIZING){ - /* there was a bootup message */ - CO_errorReport(HBcons->em, CO_EM_HB_CONSUMER_REMOTE_RESET, CO_EMC_HEARTBEAT, i); - emcyRemoteResetActive = 1; + monitoredNode->HBstate = CO_HBconsumer_ACTIVE; + /* reset timer */ + monitoredNode->timeoutTimer = 0; + timeDifference_us_copy = 0; + } + CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); + } + + /* Verify timeout */ + if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) { + monitoredNode->timeoutTimer += timeDifference_us_copy; - monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; + if (monitoredNode->timeoutTimer >= monitoredNode->time_us) { + /* timeout expired, call callback */ + if (monitoredNode->pFunctSignalTimeout!=NULL) { + monitoredNode->pFunctSignalTimeout( + monitoredNode->nodeId, i, + monitoredNode->functSignalObjectTimeout); } + CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, + CO_EMC_HEARTBEAT, i); + monitoredNode->NMTstate = CO_NMT_INITIALIZING; + monitoredNode->HBstate = CO_HBconsumer_TIMEOUT; } - if(monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { - AllMonitoredOperationalCopy = 0; + + else if (timerNext_us != NULL) { + /* Calculate timerNext_us for next timeout checking. */ + uint32_t diff = monitoredNode->time_us + - monitoredNode->timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } } } + + if(monitoredNode->HBstate != CO_HBconsumer_ACTIVE) { + allMonitoredActiveCurrent = false; + } + if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { + allMonitoredOperationalCurrent = CO_NMT_INITIALIZING; + } monitoredNode++; } } - else{ /* not in (pre)operational state */ - for(i=0; inumberOfMonitoredNodes; i++){ + else if (NMTisPreOrOperational || HBcons->NMTisPreOrOperationalPrev) { + /* (pre)operational state changed, clear variables */ + for(i=0; inumberOfMonitoredNodes; i++) { monitoredNode->NMTstate = CO_NMT_INITIALIZING; CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); - if(monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED){ + if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; } monitoredNode++; } - AllMonitoredOperationalCopy = 0; + allMonitoredActiveCurrent = false; + allMonitoredOperationalCurrent = CO_NMT_INITIALIZING; } - /* clear emergencies. We only have one emergency index for all - * monitored nodes! */ - if ( ! emcyHeartbeatTimeoutActive) { + + /* Clear emergencies when all monitored nodes becomes active. + * We only have one emergency index for all monitored nodes! */ + if (!HBcons->allMonitoredActive && allMonitoredActiveCurrent) { CO_errorReset(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, 0); - } - if ( ! emcyRemoteResetActive) { CO_errorReset(HBcons->em, CO_EM_HB_CONSUMER_REMOTE_RESET, 0); } - HBcons->allMonitoredOperational = AllMonitoredOperationalCopy; + HBcons->allMonitoredActive = allMonitoredActiveCurrent; + HBcons->allMonitoredOperational = allMonitoredOperationalCurrent; + HBcons->NMTisPreOrOperationalPrev = NMTisPreOrOperational; } diff --git a/stack/CO_HBconsumer.h b/stack/CO_HBconsumer.h index d4b21715..37bb2f06 100644 --- a/stack/CO_HBconsumer.h +++ b/stack/CO_HBconsumer.h @@ -68,8 +68,8 @@ typedef struct{ uint8_t nodeId; /**< Node Id of the monitored node */ CO_NMT_internalState_t NMTstate; /**< Of the remote node (Heartbeat payload) */ CO_HBconsumer_state_t HBstate; /**< Current heartbeat state */ - uint16_t timeoutTimer; /**< Time since last heartbeat received */ - uint16_t time; /**< Consumer heartbeat time from OD */ + uint32_t timeoutTimer; /**< Time since last heartbeat received */ + uint32_t time_us; /**< Consumer heartbeat time from OD */ volatile void *CANrxNew; /**< Indication if new Heartbeat message received from the CAN bus */ /** Callback for heartbeat state change to active event */ void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void *object); /**< From CO_HBconsumer_initTimeoutCallback() or NULL */ @@ -94,9 +94,13 @@ typedef struct{ const uint32_t *HBconsTime; /**< From CO_HBconsumer_init() */ CO_HBconsNode_t *monitoredNodes; /**< From CO_HBconsumer_init() */ uint8_t numberOfMonitoredNodes; /**< From CO_HBconsumer_init() */ + /** True, if all monitored nodes are active or no node is + monitored. Can be read by the application */ + bool_t allMonitoredActive; /** True, if all monitored nodes are NMT operational or no node is monitored. Can be read by the application */ uint8_t allMonitoredOperational; + bool_t NMTisPreOrOperationalPrev; /**< previous state of var */ CO_CANmodule_t *CANdevRx; /**< From CO_HBconsumer_init() */ uint16_t CANdevRxIdxStart; /**< From CO_HBconsumer_init() */ }CO_HBconsumer_t; @@ -142,14 +146,14 @@ CO_ReturnError_t CO_HBconsumer_init( * @param HBcons This object. * @param idx index of the node in HBcons object * @param nodeId see OD 0x1016 description - * @param consumerTime see OD 0x1016 description + * @param consumerTime in milliseconds. see OD 0x1016 description * @return */ CO_ReturnError_t CO_HBconsumer_initEntry( CO_HBconsumer_t *HBcons, uint8_t idx, uint8_t nodeId, - uint16_t consumerTime); + uint16_t consumerTime_ms); /** * Initialize Heartbeat consumer started callback function. @@ -213,12 +217,14 @@ void CO_HBconsumer_initCallbackRemoteReset( * * @param HBcons This object. * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. - * @param timeDifference_ms Time difference from previous function call in [milliseconds]. + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timerNext_us [out] info to OS - see CO_process(). */ void CO_HBconsumer_process( CO_HBconsumer_t *HBcons, bool_t NMTisPreOrOperational, - uint16_t timeDifference_ms); + uint32_t timeDifference_us, + uint32_t *timerNext_us); /** * Get the heartbeat producer object index by node ID diff --git a/stack/CO_LSSmaster.c b/stack/CO_LSSmaster.c index 0819e1b5..87553a33 100644 --- a/stack/CO_LSSmaster.c +++ b/stack/CO_LSSmaster.c @@ -112,12 +112,12 @@ static void CO_LSSmaster_receive(void *object, void *msg) */ static CO_LSSmaster_return_t CO_LSSmaster_check_timeout( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms) + uint32_t timeDifference_us) { CO_LSSmaster_return_t ret = CO_LSSmaster_WAIT_SLAVE; - LSSmaster->timeoutTimer += timeDifference_ms; - if (LSSmaster->timeoutTimer >= LSSmaster->timeout) { + LSSmaster->timeoutTimer += timeDifference_us; + if (LSSmaster->timeoutTimer >= LSSmaster->timeout_us) { LSSmaster->timeoutTimer = 0; ret = CO_LSSmaster_TIMEOUT; } @@ -142,7 +142,7 @@ CO_ReturnError_t CO_LSSmaster_init( return CO_ERROR_ILLEGAL_ARGUMENT; } - LSSmaster->timeout = timeout_ms; + LSSmaster->timeout_us = (uint32_t)timeout_ms * 1000; LSSmaster->state = CO_LSSmaster_STATE_WAITING; LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; LSSmaster->timeoutTimer = 0; @@ -181,7 +181,7 @@ void CO_LSSmaster_changeTimeout( uint16_t timeout_ms) { if (LSSmaster != NULL) { - LSSmaster->timeout = timeout_ms; + LSSmaster->timeout_us = (uint32_t)timeout_ms * 1000; } } @@ -251,7 +251,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( */ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms) + uint32_t timeDifference_us) { CO_LSSmaster_return_t ret; @@ -264,11 +264,11 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( ret = CO_LSSmaster_OK; } else { - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } } else { - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } return ret; @@ -277,7 +277,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( /******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSS_address_t *lssAddress) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; @@ -294,7 +294,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( } /* Wait for confirmation */ else if (LSSmaster->command == CO_LSSmaster_COMMAND_SWITCH_STATE) { - ret = CO_LSSmaster_switchStateSelectWait(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_switchStateSelectWait(LSSmaster, timeDifference_us); } if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) { @@ -360,7 +360,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( */ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, uint8_t csWait) { CO_LSSmaster_return_t ret; @@ -382,11 +382,11 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( } } else { - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } } else { - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) { @@ -400,7 +400,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( /******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, uint16_t bit) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; @@ -442,7 +442,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( /* Wait for confirmation */ else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_BIT_TIMING) { - ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_BIT_TIMING); } @@ -457,7 +457,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( /******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, uint8_t nodeId) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; @@ -487,7 +487,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( /* Wait for confirmation */ else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_NODE_ID) { - ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_NODE_ID); } @@ -502,7 +502,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( /******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_configureStore( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms) + uint32_t timeDifference_us) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; @@ -527,7 +527,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( /* Wait for confirmation */ else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_STORE) { - ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_STORE); } @@ -588,7 +588,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( */ static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, uint8_t csWait, uint32_t *value) { @@ -603,11 +603,11 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait( ret = CO_LSSmaster_OK; } else { - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } } else { - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } return ret; @@ -616,7 +616,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait( /******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSS_address_t *lssAddress) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; @@ -629,7 +629,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( /* Check for reply */ if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_VENDOR) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_VENDOR, &lssAddress->identity.vendorID); if (ret == CO_LSSmaster_OK) { /* Start next request */ @@ -639,7 +639,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( } else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_PRODUCT) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_PRODUCT, &lssAddress->identity.productCode); if (ret == CO_LSSmaster_OK) { /* Start next request */ @@ -649,7 +649,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( } else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_REV) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_REV, &lssAddress->identity.revisionNumber); if (ret == CO_LSSmaster_OK) { /* Start next request */ @@ -659,7 +659,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( } else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_SERIAL) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_SERIAL, &lssAddress->identity.serialNumber); } /* Check for next request */ @@ -703,7 +703,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( /******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, uint8_t *nodeId) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; @@ -726,7 +726,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId( else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_NODE_ID) { uint32_t tmp = 0; - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_NODE_ID, &tmp); *nodeId = tmp & 0xff; @@ -765,11 +765,11 @@ static void CO_LSSmaster_FsSendMsg( */ static CO_LSSmaster_return_t CO_LSSmaster_FsCheckWait( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms) + uint32_t timeDifference_us) { CO_LSSmaster_return_t ret; - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); if (ret == CO_LSSmaster_TIMEOUT) { ret = CO_LSSmaster_SCAN_NOACK; @@ -792,7 +792,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsCheckWait( */ static CO_LSSmaster_return_t CO_LSSmaster_FsScanInitiate( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, CO_LSS_fastscan_lss_sub_next lssSub) { @@ -824,7 +824,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanInitiate( */ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan) { CO_LSSmaster_return_t ret; @@ -840,7 +840,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( return CO_LSSmaster_SCAN_FAILED; } - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); if (ret == CO_LSSmaster_TIMEOUT) { ret = CO_LSSmaster_WAIT_SLAVE; @@ -880,7 +880,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( */ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, uint32_t idNumberCheck, CO_LSS_fastscan_lss_sub_next lssNext) @@ -913,7 +913,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate( */ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, uint32_t *idNumberRet) { @@ -923,7 +923,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait( return CO_LSSmaster_SCAN_FAILED; } - ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); if (ret == CO_LSSmaster_TIMEOUT) { *idNumberRet = 0; @@ -970,7 +970,7 @@ static CO_LSS_fastscan_lss_sub_next CO_LSSmaster_FsSearchNext( /******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSSmaster_fastscan_t *fastscan) { uint8_t i; @@ -1036,12 +1036,12 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( * and the correspondign error is returned. */ switch (LSSmaster->fsState) { case CO_LSSmaster_FS_STATE_CHECK: - ret = CO_LSSmaster_FsCheckWait(LSSmaster, timeDifference_ms); + ret = CO_LSSmaster_FsCheckWait(LSSmaster, timeDifference_us); if (ret == CO_LSSmaster_SCAN_FINISHED) { CO_memset((uint8_t*)&fastscan->found, 0, sizeof(fastscan->found)); /* start scanning procedure by triggering vendor ID scan */ - CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_ms, + CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_us, fastscan->scan[CO_LSS_FASTSCAN_VENDOR_ID], CO_LSS_FASTSCAN_VENDOR_ID); ret = CO_LSSmaster_WAIT_SLAVE; @@ -1050,14 +1050,14 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } break; case CO_LSSmaster_FS_STATE_SCAN: - ret = CO_LSSmaster_FsScanWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_FsScanWait(LSSmaster, timeDifference_us, fastscan->scan[LSSmaster->fsLssSub]); if (ret == CO_LSSmaster_SCAN_FINISHED) { /* scanning finished, initiate verifcation. The verification * message also contains the node state machine "switch to * next state" request */ next = CO_LSSmaster_FsSearchNext(LSSmaster, fastscan); - ret = CO_LSSmaster_FsVerifyInitiate(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_FsVerifyInitiate(LSSmaster, timeDifference_us, fastscan->scan[LSSmaster->fsLssSub], fastscan->match.addr[LSSmaster->fsLssSub], next); @@ -1065,7 +1065,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } break; case CO_LSSmaster_FS_STATE_VERIFY: - ret = CO_LSSmaster_FsVerifyWait(LSSmaster, timeDifference_ms, + ret = CO_LSSmaster_FsVerifyWait(LSSmaster, timeDifference_us, fastscan->scan[LSSmaster->fsLssSub], &fastscan->found.addr[LSSmaster->fsLssSub]); if (ret == CO_LSSmaster_SCAN_FINISHED) { @@ -1082,7 +1082,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( else { /* initiate scan for next part of LSS address */ ret = CO_LSSmaster_FsScanInitiate(LSSmaster, - timeDifference_ms, fastscan->scan[next], next); + timeDifference_us, fastscan->scan[next], next); if (ret == CO_LSSmaster_SCAN_FINISHED) { /* Scanning is not requested. Initiate verification * step in next function call */ diff --git a/stack/CO_LSSmaster.h b/stack/CO_LSSmaster.h index b1c72393..5c6150fa 100644 --- a/stack/CO_LSSmaster.h +++ b/stack/CO_LSSmaster.h @@ -105,11 +105,11 @@ typedef enum { * LSS master object. */ typedef struct{ - uint16_t timeout; /**< LSS response timeout in ms */ + uint16_t timeout_us; /**< LSS response timeout in us */ uint8_t state; /**< Node is currently selected */ uint8_t command; /**< Active command */ - uint16_t timeoutTimer; /**< Timeout timer for LSS communication */ + uint32_t timeoutTimer; /**< Timeout timer for LSS communication */ uint8_t fsState; /**< Current state of fastscan master state machine */ uint8_t fsLssSub; /**< Current state of node state machine */ @@ -212,15 +212,15 @@ void CO_LSSmaster_initCallback( * @remark Only one selection can be active at any time. * * @param LSSmaster This object. - * @param timeDifference_ms Time difference from previous function call in - * [milliseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. Zero when request is started. * @param lssAddress LSS target address. If NULL, all nodes are selected * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSS_address_t *lssAddress); @@ -251,8 +251,8 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( * Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_ms Time difference from previous function call in - * [milliseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. Zero when request is started. * @param bit new bit rate * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT, @@ -260,7 +260,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( */ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, uint16_t bit); @@ -275,8 +275,8 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( * Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_ms Time difference from previous function call in - * [milliseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. Zero when request is started. * @param nodeId new node ID. Special value #CO_LSS_NODE_ID_ASSIGNMENT can be * used to invalidate node ID. * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, @@ -285,7 +285,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( */ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, uint8_t nodeId); @@ -301,15 +301,15 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( * Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_ms Time difference from previous function call in - * [milliseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. Zero when request is started. * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT, * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT */ CO_LSSmaster_return_t CO_LSSmaster_configureStore( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms); + uint32_t timeDifference_us); /** @@ -348,15 +348,15 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( * Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_ms Time difference from previous function call in - * [milliseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. Zero when request is started. * @param lssAddress [out] read result when function returns successfully * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSS_address_t *lssAddress); @@ -371,15 +371,15 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( * Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_ms Time difference from previous function call in - * [milliseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. Zero when request is started. * @param nodeId [out] read result when function returns successfully * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, uint8_t *nodeId); @@ -448,8 +448,8 @@ fastscan.scan[CO_LSS_FASTSCAN_SERIAL] = CO_LSSmaster_FS_SCAN; * Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_ms Time difference from previous function call in - * [milliseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. Zero when request is started. * @param fastscan struct according to #CO_LSSmaster_fastscan_t. * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_SCAN_FINISHED, #CO_LSSmaster_SCAN_NOACK, @@ -457,7 +457,7 @@ fastscan.scan[CO_LSS_FASTSCAN_SERIAL] = CO_LSSmaster_FS_SCAN; */ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( CO_LSSmaster_t *LSSmaster, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, CO_LSSmaster_fastscan_t *fastscan); /** @} */ /*@defgroup CO_LSSmaster*/ diff --git a/stack/CO_LSSslave.c b/stack/CO_LSSslave.c index cb4bb1bb..c6c74187 100644 --- a/stack/CO_LSSslave.c +++ b/stack/CO_LSSslave.c @@ -498,17 +498,17 @@ CO_LSS_state_t CO_LSSslave_getState( /******************************************************************************/ bool_t CO_LSSslave_LEDprocess( CO_LSSslave_t *LSSslave, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, bool_t *LEDon) { - static uint16_t ms50 = 0; + static uint32_t ms50 = 0; static int8_t flash1, flash2; if (LSSslave == NULL || LEDon == NULL) return false; - ms50 += timeDifference_ms; - if(ms50 >= 50) { - ms50 -= 50; + ms50 += timeDifference_us; + if(ms50 >= 50000) { + ms50 -= 50000; /* 4 cycles on, 50 cycles off */ if(++flash1 >= 4) flash1 = -50; diff --git a/stack/CO_LSSslave.h b/stack/CO_LSSslave.h index 1add4810..ca14dee4 100644 --- a/stack/CO_LSSslave.h +++ b/stack/CO_LSSslave.h @@ -332,14 +332,14 @@ CO_LSS_state_t CO_LSSslave_getState( * If none of above conditions apply, returns false. * * @param LSSslave This object. - * @param timeDifference_ms The amount of time elapsed since the last call + * @param timeDifference_us The amount of time elapsed since the last call * @param LEDon [out] LED state * * @return true if LSS is involved (unconfigured node or selected node) */ bool_t CO_LSSslave_LEDprocess( CO_LSSslave_t *LSSslave, - uint16_t timeDifference_ms, + uint32_t timeDifference_us, bool_t *LEDon); /** diff --git a/stack/CO_NMT_Heartbeat.c b/stack/CO_NMT_Heartbeat.c index 2b5365a3..b704a8c6 100644 --- a/stack/CO_NMT_Heartbeat.c +++ b/stack/CO_NMT_Heartbeat.c @@ -84,7 +84,7 @@ CO_ReturnError_t CO_NMT_init( CO_NMT_t *NMT, CO_EMpr_t *emPr, uint8_t nodeId, - uint16_t firstHBTime, + uint16_t firstHBTime_ms, CO_CANmodule_t *NMT_CANdev, uint16_t NMT_rxIdx, uint16_t CANidRxNMT, @@ -97,26 +97,25 @@ CO_ReturnError_t CO_NMT_init( return CO_ERROR_ILLEGAL_ARGUMENT; } - /* blinking bytes */ + /* blinking bytes and LEDS */ #ifdef CO_USE_LEDS + NMT->LEDtimer = 0; NMT->LEDflickering = 0; NMT->LEDblinking = 0; NMT->LEDsingleFlash = 0; NMT->LEDdoubleFlash = 0; NMT->LEDtripleFlash = 0; NMT->LEDquadrupleFlash = 0; + NMT->LEDgreenRun = -1; + NMT->LEDredError = 1; #endif /* CO_USE_LEDS */ /* Configure object variables */ NMT->operatingState = CO_NMT_INITIALIZING; -#ifdef CO_USE_LEDS - NMT->LEDgreenRun = -1; - NMT->LEDredError = 1; -#endif /* CO_USE_LEDS */ NMT->nodeId = nodeId; - NMT->firstHBTime = firstHBTime; + NMT->firstHBTime = (int32_t)firstHBTime_ms * 1000; NMT->resetCommand = 0; - NMT->HBproducerTimer = 0xFFFF; + NMT->HBproducerTimer = 0; NMT->emPr = emPr; NMT->pFunctNMT = NULL; @@ -158,64 +157,25 @@ void CO_NMT_initCallback( } -/******************************************************************************/ -#ifdef CO_USE_LEDS -void CO_NMT_blinkingProcess50ms(CO_NMT_t *NMT){ - - if(++NMT->LEDflickering >= 1) NMT->LEDflickering = -1; - - if(++NMT->LEDblinking >= 4) NMT->LEDblinking = -4; - - if(++NMT->LEDsingleFlash >= 4) NMT->LEDsingleFlash = -20; - - switch(++NMT->LEDdoubleFlash){ - case 4: NMT->LEDdoubleFlash = -104; break; - case -100: NMT->LEDdoubleFlash = 100; break; - case 104: NMT->LEDdoubleFlash = -20; break; - default: break; - } - - switch(++NMT->LEDtripleFlash){ - case 4: NMT->LEDtripleFlash = -104; break; - case -100: NMT->LEDtripleFlash = 100; break; - case 104: NMT->LEDtripleFlash = -114; break; - case -110: NMT->LEDtripleFlash = 110; break; - case 114: NMT->LEDtripleFlash = -20; break; - default: break; - } - - switch(++NMT->LEDquadrupleFlash){ - case 4: NMT->LEDquadrupleFlash = -104; break; - case -100: NMT->LEDquadrupleFlash = 100; break; - case 104: NMT->LEDquadrupleFlash = -114; break; - case -110: NMT->LEDquadrupleFlash = 110; break; - case 114: NMT->LEDquadrupleFlash = -124; break; - case -120: NMT->LEDquadrupleFlash = 120; break; - case 124: NMT->LEDquadrupleFlash = -20; break; - default: break; - } -} -#endif /* CO_USE_LEDS */ - - /******************************************************************************/ CO_NMT_reset_cmd_t CO_NMT_process( CO_NMT_t *NMT, - uint16_t timeDifference_ms, - uint16_t HBtime, + uint32_t timeDifference_us, + uint16_t HBtime_ms, uint32_t NMTstartup, uint8_t errorRegister, const uint8_t errorBehavior[], - uint16_t *timerNext_ms) + uint32_t *timerNext_us) { uint8_t CANpassive; uint8_t currentOperatingState = NMT->operatingState; + uint32_t HBtime = (uint32_t)HBtime_ms * 1000; - NMT->HBproducerTimer += timeDifference_ms; + NMT->HBproducerTimer += timeDifference_us; /* Heartbeat producer message & Bootup message */ - if((HBtime != 0 && NMT->HBproducerTimer >= HBtime) || NMT->operatingState == CO_NMT_INITIALIZING){ + if ((HBtime != 0 && NMT->HBproducerTimer >= HBtime) || NMT->operatingState == CO_NMT_INITIALIZING) { /* Start from the beginning. If OS is slow, time sliding may occur. However, heartbeat is * not for synchronization, it is for health report. */ @@ -224,10 +184,12 @@ CO_NMT_reset_cmd_t CO_NMT_process( NMT->HB_TXbuff->data[0] = NMT->operatingState; CO_CANsend(NMT->HB_CANdev, NMT->HB_TXbuff); - if(NMT->operatingState == CO_NMT_INITIALIZING){ - if(HBtime > NMT->firstHBTime) NMT->HBproducerTimer = HBtime - NMT->firstHBTime; - else NMT->HBproducerTimer = 0; - + if (NMT->operatingState == CO_NMT_INITIALIZING) { + /* After bootup messages send first heartbeat earlier */ + if (HBtime > NMT->firstHBTime) { + NMT->HBproducerTimer = HBtime - NMT->firstHBTime; + } + /* NMT slave self starting */ if (NMTstartup == 0x00000008U) NMT->operatingState = CO_NMT_OPERATIONAL; else NMT->operatingState = CO_NMT_PRE_OPERATIONAL; @@ -235,19 +197,6 @@ CO_NMT_reset_cmd_t CO_NMT_process( } - /* Calculate, when next Heartbeat needs to be send and lower timerNext_ms if necessary. */ - if(HBtime != 0 && timerNext_ms != NULL){ - if(NMT->HBproducerTimer < HBtime){ - uint16_t diff = HBtime - NMT->HBproducerTimer; - if(*timerNext_ms > diff){ - *timerNext_ms = diff; - } - }else{ - *timerNext_ms = 0; - } - } - - /* CAN passive flag */ CANpassive = 0; if(CO_isError(NMT->emPr->em, CO_EM_CAN_TX_BUS_PASSIVE) || CO_isError(NMT->emPr->em, CO_EM_CAN_RX_BUS_PASSIVE)) @@ -255,6 +204,51 @@ CO_NMT_reset_cmd_t CO_NMT_process( #ifdef CO_USE_LEDS + NMT->LEDtimer += timeDifference_us; + if (NMT->LEDtimer >= 50000) { + NMT->LEDtimer -= 50000; + + if (timerNext_us != NULL) { + uint32_t diff = 50000 - NMT->LEDtimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } + + if (++NMT->LEDflickering >= 1) NMT->LEDflickering = -1; + + if (++NMT->LEDblinking >= 4) NMT->LEDblinking = -4; + + if (++NMT->LEDsingleFlash >= 4) NMT->LEDsingleFlash = -20; + + switch (++NMT->LEDdoubleFlash) { + case 4: NMT->LEDdoubleFlash = -104; break; + case -100: NMT->LEDdoubleFlash = 100; break; + case 104: NMT->LEDdoubleFlash = -20; break; + default: break; + } + + switch (++NMT->LEDtripleFlash) { + case 4: NMT->LEDtripleFlash = -104; break; + case -100: NMT->LEDtripleFlash = 100; break; + case 104: NMT->LEDtripleFlash = -114; break; + case -110: NMT->LEDtripleFlash = 110; break; + case 114: NMT->LEDtripleFlash = -20; break; + default: break; + } + + switch (++NMT->LEDquadrupleFlash) { + case 4: NMT->LEDquadrupleFlash = -104; break; + case -100: NMT->LEDquadrupleFlash = 100; break; + case 104: NMT->LEDquadrupleFlash = -114; break; + case -110: NMT->LEDquadrupleFlash = 110; break; + case 114: NMT->LEDquadrupleFlash = -124; break; + case -120: NMT->LEDquadrupleFlash = 120; break; + case 124: NMT->LEDquadrupleFlash = -20; break; + default: break; + } + } + /* CANopen green RUN LED (DR 303-3) */ switch(NMT->operatingState){ case CO_NMT_STOPPED: NMT->LEDgreenRun = NMT->LEDsingleFlash; break; @@ -335,8 +329,26 @@ CO_NMT_reset_cmd_t CO_NMT_process( } } - if(NMT->pFunctNMT!=NULL && currentOperatingState!=NMT->operatingState){ - NMT->pFunctNMT((CO_NMT_internalState_t) NMT->operatingState); + if (currentOperatingState != NMT->operatingState) { + if (NMT->pFunctNMT != NULL) { + NMT->pFunctNMT((CO_NMT_internalState_t) NMT->operatingState); + } + /* execute next CANopen processing immediately */ + if (timerNext_us != NULL) { + *timerNext_us = 0; + } + } + + /* Calculate, when next Heartbeat needs to be send and lower timerNext_us if necessary. */ + if (HBtime != 0 && timerNext_us != NULL) { + if (NMT->HBproducerTimer < HBtime) { + uint32_t diff = HBtime - NMT->HBproducerTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } else { + *timerNext_us = 0; + } } return (CO_NMT_reset_cmd_t) NMT->resetCommand; @@ -352,4 +364,3 @@ CO_NMT_internalState_t CO_NMT_getInternalState( } return CO_NMT_INITIALIZING; } - diff --git a/stack/CO_NMT_Heartbeat.h b/stack/CO_NMT_Heartbeat.h index 9199fde8..652f4cfb 100644 --- a/stack/CO_NMT_Heartbeat.h +++ b/stack/CO_NMT_Heartbeat.h @@ -129,8 +129,8 @@ typedef enum{ * @ref CO_NMT_statusLEDdiodes. Object is initialized by CO_NMT_init(). */ typedef struct{ - uint8_t operatingState; /**< See @ref CO_NMT_internalState_t */ #ifdef CO_USE_LEDS + uint32_t LEDtimer; /**< 50ms led timer */ int8_t LEDflickering; /**< See @ref CO_NMT_statusLEDdiodes */ int8_t LEDblinking; /**< See @ref CO_NMT_statusLEDdiodes */ int8_t LEDsingleFlash; /**< See @ref CO_NMT_statusLEDdiodes */ @@ -141,10 +141,11 @@ typedef struct{ int8_t LEDredError; /**< See @ref CO_NMT_statusLEDdiodes */ #endif /* CO_USE_LEDS */ + uint8_t operatingState; /**< See @ref CO_NMT_internalState_t */ uint8_t resetCommand; /**< If different than zero, device will reset */ uint8_t nodeId; /**< CANopen Node ID of this device */ - uint16_t HBproducerTimer;/**< Internal timer for HB producer */ - uint16_t firstHBTime; /**< From CO_NMT_init() */ + uint32_t HBproducerTimer;/**< Internal timer for HB producer */ + uint32_t firstHBTime; /**< From CO_NMT_init() */ CO_EMpr_t *emPr; /**< From CO_NMT_init() */ CO_CANmodule_t *HB_CANdev; /**< From CO_NMT_init() */ void (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallback() or NULL */ @@ -176,7 +177,7 @@ CO_ReturnError_t CO_NMT_init( CO_NMT_t *NMT, CO_EMpr_t *emPr, uint8_t nodeId, - uint16_t firstHBTime, + uint16_t firstHBTime_ms, CO_CANmodule_t *NMT_CANdev, uint16_t NMT_rxIdx, uint16_t CANidRxNMT, @@ -203,43 +204,31 @@ void CO_NMT_initCallback( void (*pFunctNMT)(CO_NMT_internalState_t state)); -/** - * Calculate blinking bytes. - * - * Function must be called cyclically every 50 milliseconds. See @ref CO_NMT_statusLEDdiodes. - * - * @param NMT NMT object. - */ -#ifdef CO_USE_LEDS -void CO_NMT_blinkingProcess50ms(CO_NMT_t *NMT); -#endif /* CO_USE_LEDS */ - - /** * Process received NMT and produce Heartbeat messages. * * Function must be called cyclically. * * @param NMT This object. - * @param timeDifference_ms Time difference from previous function call in [milliseconds]. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param HBtime _Producer Heartbeat time_ (object dictionary, index 0x1017). * @param NMTstartup _NMT startup behavior_ (object dictionary, index 0x1F80). * @param errorRegister _Error register_ (object dictionary, index 0x1001). * @param errorBehavior pointer to _Error behavior_ array (object dictionary, index 0x1029). * Object controls, if device should leave NMT operational state. * Length of array must be 6. If pointer is NULL, no calculation is made. - * @param timerNext_ms Return value - info to OS - see CO_process(). + * @param timerNext_us [out] info to OS - see CO_process(). * * @return #CO_NMT_reset_cmd_t */ CO_NMT_reset_cmd_t CO_NMT_process( CO_NMT_t *NMT, - uint16_t timeDifference_ms, - uint16_t HBtime, + uint32_t timeDifference_us, + uint16_t HBtime_ms, uint32_t NMTstartup, uint8_t errorRegister, const uint8_t errorBehavior[], - uint16_t *timerNext_ms); + uint32_t *timerNext_us); /** diff --git a/stack/CO_PDO.h b/stack/CO_PDO.h index b76d47e8..a2e6440e 100644 --- a/stack/CO_PDO.h +++ b/stack/CO_PDO.h @@ -374,7 +374,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas); * @param TPDO This object. * @param syncWas True, if CANopen SYNC message was just received or transmitted. * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param timerNext_us Return value - info to OS - see CO_process_SYNC_PDO(). + * @param timerNext_us [out] info to OS - see CO_process_SYNC_PDO(). */ void CO_TPDO_process( CO_TPDO_t *TPDO, diff --git a/stack/CO_SDO.c b/stack/CO_SDO.c index 7579e79c..da92a76b 100644 --- a/stack/CO_SDO.c +++ b/stack/CO_SDO.c @@ -281,6 +281,7 @@ CO_ReturnError_t CO_SDO_init( uint16_t ODSize, CO_OD_extension_t *ODExtensions, uint8_t nodeId, + uint16_t SDOtimeoutTime_ms, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t *CANdevTx, @@ -317,6 +318,7 @@ CO_ReturnError_t CO_SDO_init( /* Configure object variables */ SDO->nodeId = nodeId; + SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; SDO->state = CO_SDO_ST_IDLE; CO_CANrxNew_CLEAR(SDO->CANrxNew); SDO->pFunctSignal = NULL; @@ -768,9 +770,8 @@ static void CO_SDO_abort(CO_SDO_t *SDO, uint32_t code){ int8_t CO_SDO_process( CO_SDO_t *SDO, bool_t NMTisPreOrOperational, - uint16_t timeDifference_ms, - uint16_t SDOtimeoutTime, - uint16_t *timerNext_ms) + uint32_t timeDifference_us, + uint32_t *timerNext_us) { CO_SDO_state_t state = CO_SDO_ST_IDLE; bool_t timeoutSubblockDownolad = false; @@ -867,10 +868,10 @@ int8_t CO_SDO_process( } /* verify SDO timeout */ - if(SDO->timeoutTimer < SDOtimeoutTime){ - SDO->timeoutTimer += timeDifference_ms; + if (SDO->timeoutTimer < SDO->SDOtimeoutTime_us) { + SDO->timeoutTimer += timeDifference_us; } - if(SDO->timeoutTimer >= SDOtimeoutTime){ + if (SDO->timeoutTimer >= SDO->SDOtimeoutTime_us) { if((SDO->state == CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) && (SDO->sequence != 0) && (!SDO->CANtxBuff->bufferFull)){ timeoutSubblockDownolad = true; state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; @@ -1434,9 +1435,9 @@ int8_t CO_SDO_process( /* send response */ CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - /* Set timerNext_ms to 0 to inform OS to call this function again without delay. */ - if(timerNext_ms != NULL){ - *timerNext_ms = 0; + /* Set timerNext_us to 0 to inform OS to call this function again without delay. */ + if (timerNext_us != NULL) { + *timerNext_us = 0; } /* don't call CO_CANrxNew_CLEAR, so return directly */ @@ -1453,7 +1454,7 @@ int8_t CO_SDO_process( SDO->state = CO_SDO_ST_IDLE; break; } - + case CO_SDO_ST_IDLE: { /* Nothing to do it seems */ diff --git a/stack/CO_SDO.h b/stack/CO_SDO.h index 20bffeef..875696e3 100644 --- a/stack/CO_SDO.h +++ b/stack/CO_SDO.h @@ -613,8 +613,10 @@ typedef struct{ CO_SDO_state_t state; /** Toggle bit in segmented transfer or block sequence in block transfer */ uint8_t sequence; + /** Maximum timeout time between request and response in microseconds. */ + uint32_t SDOtimeoutTime_us; /** Timeout timer for SDO communication */ - uint16_t timeoutTimer; + uint32_t timeoutTimer; /** Number of segments per block with 1 <= blksize <= 127 */ uint8_t blksize; /** True, if CRC calculation by block transfer is enabled */ @@ -753,6 +755,7 @@ void CO_memcpySwap8(void* dest, const void* src); * @param ODExtensions Pointer to the externally defined array of the same size * as ODSize. * @param nodeId CANopen Node ID of this device. + * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param CANdevRx CAN device for SDO server reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for SDO server transmission. @@ -770,6 +773,7 @@ CO_ReturnError_t CO_SDO_init( uint16_t ODSize, CO_OD_extension_t ODExtensions[], uint8_t nodeId, + uint16_t SDOtimeoutTime_ms, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t *CANdevTx, @@ -799,9 +803,8 @@ void CO_SDO_initCallback( * @param SDO This object. * @param NMTisPreOrOperational Different than zero, if #CO_NMT_internalState_t is * NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. - * @param timeDifference_ms Time difference from previous function call in [milliseconds]. - * @param SDOtimeoutTime Timeout time for SDO communication in milliseconds. - * @param timerNext_ms Return value - info to OS - see CO_process(). + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timerNext_us [out] info to OS - see CO_process(). * * @return 0: SDO server is idle. * @return 1: SDO server is in transfer state. @@ -810,9 +813,8 @@ void CO_SDO_initCallback( int8_t CO_SDO_process( CO_SDO_t *SDO, bool_t NMTisPreOrOperational, - uint16_t timeDifference_ms, - uint16_t SDOtimeoutTime, - uint16_t *timerNext_ms); + uint32_t timeDifference_us, + uint32_t *timerNext_us); /** diff --git a/stack/CO_SDOmaster.c b/stack/CO_SDOmaster.c index e33bbcea..c716ce2b 100644 --- a/stack/CO_SDOmaster.c +++ b/stack/CO_SDOmaster.c @@ -330,6 +330,7 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( uint8_t subIndex, uint8_t *dataTx, uint32_t dataSize, + uint16_t SDOtimeoutTime_ms, uint8_t blockEnable) { /* verify parameters */ @@ -340,6 +341,8 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( /* save parameters */ SDO_C->buffer = dataTx; SDO_C->bufferSize = dataSize; + SDO_C->SDOtimeoutTimeHalf_us = (uint32_t)SDOtimeoutTime_ms * 500; + SDO_C->SDOtimeoutTime_us = SDO_C->SDOtimeoutTimeHalf_us * 2; SDO_C->state = SDO_STATE_DOWNLOAD_INITIATE; @@ -409,9 +412,9 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( /******************************************************************************/ CO_SDOclient_return_t CO_SDOclientDownload( CO_SDOclient_t *SDO_C, - uint16_t timeDifference_ms, - uint16_t SDOtimeoutTime, - uint32_t *pSDOabortCode) + uint32_t timeDifference_us, + uint32_t *pSDOabortCode, + uint32_t *timerNext_us) { CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse; @@ -614,14 +617,23 @@ CO_SDOclient_return_t CO_SDOclientDownload( } /* TMO *********************************************************************************************** */ - if(SDO_C->timeoutTimer < SDOtimeoutTime){ - SDO_C->timeoutTimer += timeDifference_ms; + if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { + SDO_C->timeoutTimer += timeDifference_us; } - if(SDO_C->timeoutTimer >= SDOtimeoutTime){ /* communication TMO */ + + /* communication TMO */ + if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { *pSDOabortCode = CO_SDO_AB_TIMEOUT; CO_SDOclient_abort(SDO_C, *pSDOabortCode); return CO_SDOcli_endedWithTimeout; } + else if (timerNext_us != NULL) { + /* check again after inhibit time elapsed */ + uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } /* TX data ******************************************************************************************* */ if(SDO_C->CANtxBuff->bufferFull) { @@ -670,9 +682,6 @@ CO_SDOclient_return_t CO_SDOclientDownload( SDO_C->block_seqno += 1; SDO_C->CANtxBuff->data[0] = SDO_C->block_seqno; - if(SDO_C->block_seqno >= SDO_C->block_blksize){ - SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK; - } /* set data */ SDO_C->block_noData = 0; @@ -693,6 +702,13 @@ CO_SDOclient_return_t CO_SDOclientDownload( SDO_C->block_blksize = SDO_C->block_seqno; SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK; } + else if (SDO_C->block_seqno >= SDO_C->block_blksize) { + SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK; + } + else if (timerNext_us != NULL) { + /* Set timerNext_us to 0 to inform OS to call this function again without delay. */ + *timerNext_us = 0; + } /* tx data */ SDO_C->timeoutTimer = 0; @@ -742,6 +758,7 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( uint8_t subIndex, uint8_t *dataRx, uint32_t dataRxSize, + uint16_t SDOtimeoutTime_ms, uint8_t blockEnable) { /* verify parameters */ @@ -752,6 +769,8 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( /* save parameters */ SDO_C->buffer = dataRx; SDO_C->bufferSize = dataRxSize; + SDO_C->SDOtimeoutTimeHalf_us = (uint32_t)SDOtimeoutTime_ms * 500; + SDO_C->SDOtimeoutTime_us = SDO_C->SDOtimeoutTimeHalf_us * 2; /* prepare CAN tx message */ CO_SDOTxBufferClear(SDO_C); @@ -814,10 +833,10 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( /******************************************************************************/ CO_SDOclient_return_t CO_SDOclientUpload( CO_SDOclient_t *SDO_C, - uint16_t timeDifference_ms, - uint16_t SDOtimeoutTime, + uint32_t timeDifference_us, uint32_t *pDataSize, - uint32_t *pSDOabortCode) + uint32_t *pSDOabortCode, + uint32_t *timerNext_us) { uint16_t indexTmp; uint32_t tmp32; @@ -1106,19 +1125,37 @@ CO_SDOclient_return_t CO_SDOclientUpload( } /* TMO *************************************************************************************************** */ - if(SDO_C->timeoutTimer < SDOtimeoutTime){ - SDO_C->timeoutTimer += timeDifference_ms; + if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { + SDO_C->timeoutTimer += timeDifference_us; if (SDO_C->state == SDO_STATE_BLOCKUPLOAD_INPROGRES) - SDO_C->timeoutTimerBLOCK += timeDifference_ms; + SDO_C->timeoutTimerBLOCK += timeDifference_us; } - if(SDO_C->timeoutTimer >= SDOtimeoutTime){ /* communication TMO */ + + /* communication TMO */ + if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { *pSDOabortCode = CO_SDO_AB_TIMEOUT; CO_SDOclient_abort(SDO_C, *pSDOabortCode); return CO_SDOcli_endedWithTimeout; } - if(SDO_C->timeoutTimerBLOCK >= (SDOtimeoutTime/2)){ /* block TMO */ + else if (timerNext_us != NULL) { + /* check again after inhibit time elapsed */ + uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } + + /* block TMO */ + if (SDO_C->timeoutTimerBLOCK >= SDO_C->SDOtimeoutTimeHalf_us) { SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_ACK; } + else if (timerNext_us != NULL) { + /* check again after inhibit time elapsed */ + uint32_t diff = SDO_C->SDOtimeoutTimeHalf_us - SDO_C->timeoutTimerBLOCK; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } /* TX data ******************************************************************************** */ diff --git a/stack/CO_SDOmaster.h b/stack/CO_SDOmaster.h index bf592144..95f4da74 100644 --- a/stack/CO_SDOmaster.h +++ b/stack/CO_SDOmaster.h @@ -112,10 +112,14 @@ typedef struct{ uint32_t dataSize; /** Data length transferred in block transfer */ uint32_t dataSizeTransfered; + /** Maximum timeout time between request and response in microseconds. */ + uint32_t SDOtimeoutTime_us; + /** Half of maximum timeout time between request and response. */ + uint32_t SDOtimeoutTimeHalf_us; /** Timeout timer for SDO communication */ - uint16_t timeoutTimer; + uint32_t timeoutTimer; /** Timeout timer for SDO block transfer */ - uint16_t timeoutTimerBLOCK; + uint32_t timeoutTimerBLOCK; /** Index of current object in Object Dictionary */ uint16_t index; /** Subindex of current object in Object Dictionary */ @@ -246,6 +250,7 @@ CO_SDOclient_return_t CO_SDOclient_setup( * format, because CANopen itself uses little-endian. Take care, * when using processors with big-endian. * @param dataSize Size of data in dataTx. + * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. * * @return #CO_SDOclient_return_t @@ -256,6 +261,7 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( uint8_t subIndex, uint8_t *dataTx, uint32_t dataSize, + uint16_t SDOtimeoutTime_ms, uint8_t blockEnable); @@ -267,18 +273,18 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( * Function is non-blocking. * * @param SDO_C This object. - * @param timeDifference_ms Time difference from previous function call in [milliseconds]. - * @param SDOtimeoutTime Timeout time for SDO communication in milliseconds. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param pSDOabortCode Pointer to external variable written by this function * in case of error in communication. + * @param timerNext_us [out] info to OS - see CO_process(). * * @return #CO_SDOclient_return_t */ CO_SDOclient_return_t CO_SDOclientDownload( CO_SDOclient_t *SDO_C, - uint16_t timeDifference_ms, - uint16_t SDOtimeoutTime, - uint32_t *pSDOabortCode); + uint32_t timeDifference_us, + uint32_t *pSDOabortCode, + uint32_t *timerNext_us); /** @@ -296,6 +302,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( * in little-endian format, because CANopen itself uses * little-endian. Take care, when using processors with big-endian. * @param dataRxSize Size of dataRx. + * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. * * @return #CO_SDOclient_return_t @@ -306,6 +313,7 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( uint8_t subIndex, uint8_t *dataRx, uint32_t dataRxSize, + uint16_t SDOtimeoutTime_ms, uint8_t blockEnable); @@ -317,21 +325,21 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( * Function is non-blocking. * * @param SDO_C This object. - * @param timeDifference_ms Time difference from previous function call in [milliseconds]. - * @param SDOtimeoutTime Timeout time for SDO communication in milliseconds. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param pDataSize pointer to external variable, where size of received * data will be written. * @param pSDOabortCode Pointer to external variable written by this function * in case of error in communication. + * @param timerNext_us [out] info to OS - see CO_process(). * * @return #CO_SDOclient_return_t */ CO_SDOclient_return_t CO_SDOclientUpload( CO_SDOclient_t *SDO_C, - uint16_t timeDifference_ms, - uint16_t SDOtimeoutTime, + uint32_t timeDifference_us, uint32_t *pDataSize, - uint32_t *pSDOabortCode); + uint32_t *pSDOabortCode, + uint32_t *timerNext_us); /** diff --git a/stack/CO_SYNC.h b/stack/CO_SYNC.h index 80e44493..5a889404 100644 --- a/stack/CO_SYNC.h +++ b/stack/CO_SYNC.h @@ -146,7 +146,7 @@ CO_ReturnError_t CO_SYNC_init( * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param ObjDict_synchronousWindowLength _Synchronous window length_ variable from * Object dictionary (index 0x1007). - * @param timerNext_us Return value - info to OS - see CO_process_SYNC_PDO(). + * @param timerNext_us [out] info to OS - see CO_process_SYNC_PDO(). * * @return 0: No special meaning. * @return 1: New SYNC message recently received or was just transmitted. diff --git a/stack/CO_TIME.c b/stack/CO_TIME.c index aa550220..3482ae1b 100644 --- a/stack/CO_TIME.c +++ b/stack/CO_TIME.c @@ -125,13 +125,14 @@ CO_ReturnError_t CO_TIME_init( /******************************************************************************/ uint8_t CO_TIME_process( CO_TIME_t *TIME, - uint32_t timeDifference_ms) + uint32_t timeDifference_us) { uint8_t ret = 0; uint32_t timerNew; if(*TIME->operatingState == CO_NMT_OPERATIONAL || *TIME->operatingState == CO_NMT_PRE_OPERATIONAL){ /* update TIME timer, no overflow */ + uint32_t timeDifference_ms = (timeDifference_us+500) / 1000; //this should be optimized timerNew = TIME->timer + timeDifference_ms; if(timerNew > TIME->timer) TIME->timer = timerNew; diff --git a/stack/CO_TIME.h b/stack/CO_TIME.h index 0884a6f3..a3eea4c5 100644 --- a/stack/CO_TIME.h +++ b/stack/CO_TIME.h @@ -143,14 +143,14 @@ CO_ReturnError_t CO_TIME_init( * Function must be called cyclically. * * @param TIME This object. - * @param timeDifference_ms Time difference from previous function call in [milliseconds]. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * * @return 0: No special meaning. * @return 1: New TIME message recently received (consumer) / transmited (producer). */ uint8_t CO_TIME_process( CO_TIME_t *TIME, - uint32_t timeDifference_ms); + uint32_t timeDifference_us); #ifdef __cplusplus } From 4495e32fe8df8ba100ece8a1be34a73c22b7a9cc Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 Feb 2020 20:39:10 +0100 Subject: [PATCH 016/520] Rename macros CO_CANrxNew_* into CO_FLAG_* --- example/CO_driver_target.h | 6 ++--- socketCAN/CO_driver_target.h | 6 ++--- stack/CO_HBconsumer.c | 10 ++++---- stack/CO_LSSmaster.c | 48 +++++++++++++++++----------------- stack/CO_PDO.c | 26 +++++++++---------- stack/CO_SDO.c | 40 ++++++++++++++--------------- stack/CO_SDOmaster.c | 50 ++++++++++++++++++------------------ stack/CO_SYNC.c | 14 +++++----- stack/CO_TIME.c | 10 ++++---- stack/CO_driver.h | 6 ++--- 10 files changed, 108 insertions(+), 108 deletions(-) diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 655e29a3..bb3d84e9 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -105,9 +105,9 @@ typedef struct { /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() -#define CO_CANrxNew_READ(rxNew) ((rxNew) != NULL) -#define CO_CANrxNew_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} -#define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} +#define CO_FLAG_READ(rxNew) ((rxNew) != NULL) +#define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} +#define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} #ifdef __cplusplus diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index f007af10..53ef9dc2 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -219,9 +219,9 @@ static inline void CO_UNLOCK_OD() { /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() {__sync_synchronize();} -#define CO_CANrxNew_READ(rxNew) ((rxNew) != NULL) -#define CO_CANrxNew_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} -#define CO_CANrxNew_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} +#define CO_FLAG_READ(rxNew) ((rxNew) != NULL) +#define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} +#define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} #ifdef CO_DRIVER_MULTI_INTERFACE diff --git a/stack/CO_HBconsumer.c b/stack/CO_HBconsumer.c index b3204452..c21d8686 100644 --- a/stack/CO_HBconsumer.c +++ b/stack/CO_HBconsumer.c @@ -47,7 +47,7 @@ static void CO_HBcons_receive(void *object, void *msg){ if(DLC == 1){ /* copy data and set 'new message' flag. */ HBconsNode->NMTstate = (CO_NMT_internalState_t)data[0]; - CO_CANrxNew_SET(HBconsNode->CANrxNew); + CO_FLAG_SET(HBconsNode->CANrxNew); } } @@ -164,7 +164,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( monitoredNode->nodeId = nodeId; monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; monitoredNode->NMTstate = CO_NMT_INITIALIZING; - CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); + CO_FLAG_CLEAR(monitoredNode->CANrxNew); /* is channel used */ if (monitoredNode->nodeId && monitoredNode->time_us) { @@ -270,7 +270,7 @@ void CO_HBconsumer_process( continue; } /* Verify if received message is heartbeat or bootup */ - if (CO_CANrxNew_READ(monitoredNode->CANrxNew)) { + if (CO_FLAG_READ(monitoredNode->CANrxNew)) { if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) { /* bootup message, call callback */ if (monitoredNode->pFunctSignalRemoteReset != NULL) { @@ -299,7 +299,7 @@ void CO_HBconsumer_process( monitoredNode->timeoutTimer = 0; timeDifference_us_copy = 0; } - CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); + CO_FLAG_CLEAR(monitoredNode->CANrxNew); } /* Verify timeout */ @@ -342,7 +342,7 @@ void CO_HBconsumer_process( /* (pre)operational state changed, clear variables */ for(i=0; inumberOfMonitoredNodes; i++) { monitoredNode->NMTstate = CO_NMT_INITIALIZING; - CO_CANrxNew_CLEAR(monitoredNode->CANrxNew); + CO_FLAG_CLEAR(monitoredNode->CANrxNew); if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; } diff --git a/stack/CO_LSSmaster.c b/stack/CO_LSSmaster.c index 87553a33..7a5011bb 100644 --- a/stack/CO_LSSmaster.c +++ b/stack/CO_LSSmaster.c @@ -81,7 +81,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */ /* verify message length and message overflow (previous message was not processed yet) */ - if(DLC==8 && !CO_CANrxNew_READ(LSSmaster->CANrxNew) && + if(DLC==8 && !CO_FLAG_READ(LSSmaster->CANrxNew) && LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING){ /* copy data and set 'new message' flag */ @@ -94,7 +94,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) LSSmaster->CANrxData[6] = data[6]; LSSmaster->CANrxData[7] = data[7]; - CO_CANrxNew_SET(LSSmaster->CANrxNew); + CO_FLAG_SET(LSSmaster->CANrxNew); /* Optional signal to RTOS, which can resume task, which handles SDO client. */ if(LSSmaster->pFunctSignal != NULL) { @@ -146,7 +146,7 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->state = CO_LSSmaster_STATE_WAITING; LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; LSSmaster->timeoutTimer = 0; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); CO_memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); LSSmaster->pFunctSignal = NULL; LSSmaster->functSignalObject = NULL; @@ -213,7 +213,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( LSSmaster->command = CO_LSSmaster_COMMAND_SWITCH_STATE; LSSmaster->timeoutTimer = 0; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); CO_memset(&LSSmaster->TXbuff->data[6], 0, 3); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); @@ -234,7 +234,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( /* switch state global */ LSSmaster->state = CO_LSSmaster_STATE_CFG_GLOBAL; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION; CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); @@ -255,9 +255,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( { CO_LSSmaster_return_t ret; - if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { + if (CO_FLAG_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); if (cs == CO_LSS_SWITCH_STATE_SEL) { /* confirmation received */ @@ -327,7 +327,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( LSSmaster->timeoutTimer = 0; /* switch state global */ - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_WAITING; CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); @@ -365,10 +365,10 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( { CO_LSSmaster_return_t ret; - if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { + if (CO_FLAG_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; uint8_t errorCode = LSSmaster->CANrxData[1]; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); if (cs == csWait) { if (errorCode == 0) { @@ -430,7 +430,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( LSSmaster->command = CO_LSSmaster_COMMAND_CFG_BIT_TIMING; LSSmaster->timeoutTimer = 0; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_BIT_TIMING; LSSmaster->TXbuff->data[1] = 0; LSSmaster->TXbuff->data[2] = bitTiming; @@ -476,7 +476,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( LSSmaster->command = CO_LSSmaster_COMMAND_CFG_NODE_ID; LSSmaster->timeoutTimer = 0; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_NODE_ID; LSSmaster->TXbuff->data[1] = nodeId; CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); @@ -517,7 +517,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( LSSmaster->command = CO_LSSmaster_COMMAND_CFG_STORE; LSSmaster->timeoutTimer = 0; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_STORE; CO_memset(&LSSmaster->TXbuff->data[1], 0, 7); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -555,7 +555,7 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( if (LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL && LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){ - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); CO_memset(&LSSmaster->TXbuff->data[3], 0, 5); @@ -575,7 +575,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( CO_LSSmaster_t *LSSmaster, uint8_t cs) { - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = cs; CO_memset(&LSSmaster->TXbuff->data[1], 0, 7); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -594,10 +594,10 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait( { CO_LSSmaster_return_t ret; - if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { + if (CO_FLAG_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; *value = CO_getUint32(&LSSmaster->CANrxData[1]); - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); if (cs == csWait) { ret = CO_LSSmaster_OK; @@ -750,7 +750,7 @@ static void CO_LSSmaster_FsSendMsg( { LSSmaster->timeoutTimer = 0; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_IDENT_FASTSCAN; CO_setUint32(&LSSmaster->TXbuff->data[1], idNumber); LSSmaster->TXbuff->data[5] = bitCheck; @@ -773,9 +773,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsCheckWait( if (ret == CO_LSSmaster_TIMEOUT) { ret = CO_LSSmaster_SCAN_NOACK; - if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { + if (CO_FLAG_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); if (cs == CO_LSS_IDENT_SLAVE) { /* At least one node is waiting for fastscan */ @@ -845,9 +845,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( ret = CO_LSSmaster_WAIT_SLAVE; - if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { + if (CO_FLAG_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); if (cs != CO_LSS_IDENT_SLAVE) { /* wrong response received. Can not continue */ @@ -929,9 +929,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait( *idNumberRet = 0; ret = CO_LSSmaster_SCAN_NOACK; - if (CO_CANrxNew_READ(LSSmaster->CANrxNew)) { + if (CO_FLAG_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; - CO_CANrxNew_CLEAR(LSSmaster->CANrxNew); + CO_FLAG_CLEAR(LSSmaster->CANrxNew); if (cs == CO_LSS_IDENT_SLAVE) { *idNumberRet = LSSmaster->fsIdNumber; diff --git a/stack/CO_PDO.c b/stack/CO_PDO.c index cf0eb470..f7fd9107 100644 --- a/stack/CO_PDO.c +++ b/stack/CO_PDO.c @@ -62,7 +62,7 @@ static void CO_PDO_receive(void *object, void *msg){ RPDO->CANrxData[1][6] = data[6]; RPDO->CANrxData[1][7] = data[7]; - CO_CANrxNew_SET(RPDO->CANrxNew[1]); + CO_FLAG_SET(RPDO->CANrxNew[1]); } else { /* copy data into default buffer and set 'new message' flag */ @@ -75,7 +75,7 @@ static void CO_PDO_receive(void *object, void *msg){ RPDO->CANrxData[0][6] = data[6]; RPDO->CANrxData[0][7] = data[7]; - CO_CANrxNew_SET(RPDO->CANrxNew[0]); + CO_FLAG_SET(RPDO->CANrxNew[0]); } } } @@ -110,8 +110,8 @@ static void CO_RPDOconfigCom(CO_RPDO_t* RPDO, uint32_t COB_IDUsedByRPDO){ else{ ID = 0; RPDO->valid = false; - CO_CANrxNew_CLEAR(RPDO->CANrxNew[0]); - CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); + CO_FLAG_CLEAR(RPDO->CANrxNew[0]); + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); } r = CO_CANrxBufferInit( RPDO->CANdevRx, /* CAN device */ @@ -123,8 +123,8 @@ static void CO_RPDOconfigCom(CO_RPDO_t* RPDO, uint32_t COB_IDUsedByRPDO){ CO_PDO_receive); /* this function will process received message */ if(r != CO_ERROR_NO){ RPDO->valid = false; - CO_CANrxNew_CLEAR(RPDO->CANrxNew[0]); - CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); + CO_FLAG_CLEAR(RPDO->CANrxNew[0]); + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); } } @@ -477,7 +477,7 @@ static CO_SDO_abortCode_t CO_ODF_RPDOcom(CO_ODF_arg_t *ODF_arg){ /* Remove old message from second buffer. */ if(RPDO->synchronous != synchronousPrev) { - CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); } } @@ -751,8 +751,8 @@ CO_ReturnError_t CO_RPDO_init( CO_OD_configure(SDO, idx_RPDOMapPar, CO_ODF_RPDOmap, (void*)RPDO, 0, 0); /* configure communication and mapping */ - CO_CANrxNew_CLEAR(RPDO->CANrxNew[0]); - CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); + CO_FLAG_CLEAR(RPDO->CANrxNew[0]); + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); RPDO->CANdevRx = CANdevRx; RPDO->CANdevRxIdx = CANdevRxIdx; @@ -901,8 +901,8 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ if(!RPDO->valid || !(*RPDO->operatingState == CO_NMT_OPERATIONAL)) { - CO_CANrxNew_CLEAR(RPDO->CANrxNew[0]); - CO_CANrxNew_CLEAR(RPDO->CANrxNew[1]); + CO_FLAG_CLEAR(RPDO->CANrxNew[0]); + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); } else if(!RPDO->synchronous || syncWas) { @@ -917,7 +917,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ bufNo = 1; } - while(CO_CANrxNew_READ(RPDO->CANrxNew[bufNo])){ + while(CO_FLAG_READ(RPDO->CANrxNew[bufNo])){ int16_t i; uint8_t* pPDOdataByte; uint8_t** ppODdataByte; @@ -928,7 +928,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ /* Copy data to Object dictionary. If between the copy operation CANrxNew * is set to true by receive thread, then copy the latest data again. */ - CO_CANrxNew_CLEAR(RPDO->CANrxNew[bufNo]); + CO_FLAG_CLEAR(RPDO->CANrxNew[bufNo]); for(; i>0; i--) { **(ppODdataByte++) = *(pPDOdataByte++); } diff --git a/stack/CO_SDO.c b/stack/CO_SDO.c index da92a76b..b9e4810a 100644 --- a/stack/CO_SDO.c +++ b/stack/CO_SDO.c @@ -182,7 +182,7 @@ static void CO_SDO_receive(void *object, void *msg){ * See: https://github.com/CANopenNode/CANopenNode/issues/39 */ /* verify message length and message overflow (previous message was not processed yet) */ - if((DLC == 8U) && (!CO_CANrxNew_READ(SDO->CANrxNew))){ + if((DLC == 8U) && (!CO_FLAG_READ(SDO->CANrxNew))){ if(SDO->state != CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) { /* copy data and set 'new message' flag */ SDO->CANrxData[0] = data[0]; @@ -194,7 +194,7 @@ static void CO_SDO_receive(void *object, void *msg){ SDO->CANrxData[6] = data[6]; SDO->CANrxData[7] = data[7]; - CO_CANrxNew_SET(SDO->CANrxNew); + CO_FLAG_SET(SDO->CANrxNew); } else { /* block download, copy data directly */ @@ -217,7 +217,7 @@ static void CO_SDO_receive(void *object, void *msg){ if(SDO->bufferOffset >= CO_SDO_BUFFER_SIZE) { /* buffer full, break reception */ SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - CO_CANrxNew_SET(SDO->CANrxNew); + CO_FLAG_SET(SDO->CANrxNew); break; } } @@ -225,7 +225,7 @@ static void CO_SDO_receive(void *object, void *msg){ /* break reception if last segment or block sequence is too large */ if(((SDO->CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) { SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - CO_CANrxNew_SET(SDO->CANrxNew); + CO_FLAG_SET(SDO->CANrxNew); } } else if((seqno == SDO->sequence) || (SDO->sequence == 0U)){ @@ -234,12 +234,12 @@ static void CO_SDO_receive(void *object, void *msg){ else { /* seqno is totally wrong, break reception. */ SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - CO_CANrxNew_SET(SDO->CANrxNew); + CO_FLAG_SET(SDO->CANrxNew); } } /* Optional signal to RTOS, which can resume task, which handles SDO server. */ - if(CO_CANrxNew_READ(SDO->CANrxNew) && SDO->pFunctSignal != NULL) { + if(CO_FLAG_READ(SDO->CANrxNew) && SDO->pFunctSignal != NULL) { SDO->pFunctSignal(); } } @@ -320,7 +320,7 @@ CO_ReturnError_t CO_SDO_init( SDO->nodeId = nodeId; SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; SDO->state = CO_SDO_ST_IDLE; - CO_CANrxNew_CLEAR(SDO->CANrxNew); + CO_FLAG_CLEAR(SDO->CANrxNew); SDO->pFunctSignal = NULL; @@ -761,7 +761,7 @@ static void CO_SDO_abort(CO_SDO_t *SDO, uint32_t code){ SDO->CANtxBuff->data[3] = SDO->ODF_arg.subIndex; CO_memcpySwap4(&SDO->CANtxBuff->data[4], &code); SDO->state = CO_SDO_ST_IDLE; - CO_CANrxNew_CLEAR(SDO->CANrxNew); + CO_FLAG_CLEAR(SDO->CANrxNew); CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); } @@ -778,19 +778,19 @@ int8_t CO_SDO_process( bool_t sendResponse = false; /* return if idle */ - if((SDO->state == CO_SDO_ST_IDLE) && (!CO_CANrxNew_READ(SDO->CANrxNew))){ + if((SDO->state == CO_SDO_ST_IDLE) && (!CO_FLAG_READ(SDO->CANrxNew))){ return 0; } /* SDO is allowed to work only in operational or pre-operational NMT state */ if(!NMTisPreOrOperational){ SDO->state = CO_SDO_ST_IDLE; - CO_CANrxNew_CLEAR(SDO->CANrxNew); + CO_FLAG_CLEAR(SDO->CANrxNew); return 0; } /* Is something new to process? */ - if((!SDO->CANtxBuff->bufferFull) && ((CO_CANrxNew_READ(SDO->CANrxNew)) || (SDO->state == CO_SDO_ST_UPLOAD_BL_SUBBLOCK))){ + if((!SDO->CANtxBuff->bufferFull) && ((CO_FLAG_READ(SDO->CANrxNew)) || (SDO->state == CO_SDO_ST_UPLOAD_BL_SUBBLOCK))){ uint8_t CCS = SDO->CANrxData[0] >> 5; /* Client command specifier */ /* reset timeout */ @@ -802,9 +802,9 @@ int8_t CO_SDO_process( SDO->CANtxBuff->data[4] = SDO->CANtxBuff->data[5] = SDO->CANtxBuff->data[6] = SDO->CANtxBuff->data[7] = 0; /* Is abort from client? */ - if((CO_CANrxNew_READ(SDO->CANrxNew)) && (SDO->CANrxData[0] == CCS_ABORT)){ + if((CO_FLAG_READ(SDO->CANrxNew)) && (SDO->CANrxData[0] == CCS_ABORT)){ SDO->state = CO_SDO_ST_IDLE; - CO_CANrxNew_CLEAR(SDO->CANrxNew); + CO_FLAG_CLEAR(SDO->CANrxNew); return -1; } @@ -887,7 +887,7 @@ int8_t CO_SDO_process( return 0; } - /* state machine (buffer is freed (CO_CANrxNew_CLEAR()) at the end) */ + /* state machine (buffer is freed (CO_FLAG_CLEAR()) at the end) */ switch(state){ uint32_t abortCode; uint16_t len, i; @@ -1312,7 +1312,7 @@ int8_t CO_SDO_process( SDO->bufferOffset = 0; SDO->sequence = 0; SDO->endOfTransfer = false; - CO_CANrxNew_CLEAR(SDO->CANrxNew); + CO_FLAG_CLEAR(SDO->CANrxNew); SDO->state = CO_SDO_ST_UPLOAD_BL_SUBBLOCK; /* continue in next case */ } @@ -1320,7 +1320,7 @@ int8_t CO_SDO_process( case CO_SDO_ST_UPLOAD_BL_SUBBLOCK:{ /* is block confirmation received */ - if(CO_CANrxNew_READ(SDO->CANrxNew)){ + if(CO_FLAG_READ(SDO->CANrxNew)){ uint8_t ackseq; uint16_t j; @@ -1399,12 +1399,12 @@ int8_t CO_SDO_process( SDO->endOfTransfer = false; /* clear flag here */ - CO_CANrxNew_CLEAR(SDO->CANrxNew); + CO_FLAG_CLEAR(SDO->CANrxNew); } /* return, if all segments was already transfered or on end of transfer */ if((SDO->sequence == SDO->blksize) || (SDO->endOfTransfer)){ - return 1;/* don't call CO_CANrxNew_CLEAR, so return directly */ + return 1;/* don't call CO_FLAG_CLEAR, so return directly */ } /* reset timeout */ @@ -1440,7 +1440,7 @@ int8_t CO_SDO_process( *timerNext_us = 0; } - /* don't call CO_CANrxNew_CLEAR, so return directly */ + /* don't call CO_FLAG_CLEAR, so return directly */ return 1; } @@ -1468,7 +1468,7 @@ int8_t CO_SDO_process( } /* free buffer and send message */ - CO_CANrxNew_CLEAR(SDO->CANrxNew); + CO_FLAG_CLEAR(SDO->CANrxNew); if(sendResponse) { CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); } diff --git a/stack/CO_SDOmaster.c b/stack/CO_SDOmaster.c index c716ce2b..b621c9e3 100644 --- a/stack/CO_SDOmaster.c +++ b/stack/CO_SDOmaster.c @@ -103,7 +103,7 @@ static void CO_SDOclient_receive(void *object, void *msg){ SDO_C = (CO_SDOclient_t*)object; /* this is the correct pointer type of the first argument */ /* verify message length and message overflow (previous message was not processed yet) */ - if((DLC == 8U) && (!CO_CANrxNew_READ(SDO_C->CANrxNew)) && (SDO_C->state != SDO_STATE_NOTDEFINED)){ + if((DLC == 8U) && (!CO_FLAG_READ(SDO_C->CANrxNew)) && (SDO_C->state != SDO_STATE_NOTDEFINED)){ if(SDO_C->state != SDO_STATE_BLOCKUPLOAD_INPROGRES) { /* copy data and set 'new message' flag */ SDO_C->CANrxData[0] = data[0]; @@ -115,7 +115,7 @@ static void CO_SDOclient_receive(void *object, void *msg){ SDO_C->CANrxData[6] = data[6]; SDO_C->CANrxData[7] = data[7]; - CO_CANrxNew_SET(SDO_C->CANrxNew); + CO_FLAG_SET(SDO_C->CANrxNew); } else { /* block upload, copy data directly */ @@ -139,7 +139,7 @@ static void CO_SDOclient_receive(void *object, void *msg){ if(SDO_C->dataSizeTransfered >= SDO_C->bufferSize) { /* buffer full, break reception */ SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - CO_CANrxNew_SET(SDO_C->CANrxNew); + CO_FLAG_SET(SDO_C->CANrxNew); break; } } @@ -147,7 +147,7 @@ static void CO_SDOclient_receive(void *object, void *msg){ /* break reception if last segment or block sequence is too large */ if(((SDO_C->CANrxData[0] & 0x80U) == 0x80U) || (SDO_C->block_seqno >= SDO_C->block_blksize)) { SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - CO_CANrxNew_SET(SDO_C->CANrxNew); + CO_FLAG_SET(SDO_C->CANrxNew); } } else if((seqno == SDO_C->block_seqno) || (SDO_C->block_seqno == 0U)){ @@ -156,12 +156,12 @@ static void CO_SDOclient_receive(void *object, void *msg){ else { /* seqno is totally wrong, break reception. */ SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - CO_CANrxNew_SET(SDO_C->CANrxNew); + CO_FLAG_SET(SDO_C->CANrxNew); } } /* Optional signal to RTOS, which can resume task, which handles SDO client. */ - if(CO_CANrxNew_READ(SDO_C->CANrxNew) && SDO_C->pFunctSignal != NULL) { + if(CO_FLAG_READ(SDO_C->CANrxNew) && SDO_C->pFunctSignal != NULL) { SDO_C->pFunctSignal(); } } @@ -186,7 +186,7 @@ CO_ReturnError_t CO_SDOclient_init( /* Configure object variables */ SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->pst = 21; /* block transfer */ SDO_C->block_size_max = 127; /* block transfer */ @@ -241,7 +241,7 @@ CO_SDOclient_return_t CO_SDOclient_setup( /* Configure object variables */ SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); /* setup Object Dictionary variables */ if((COB_IDClientToServer & 0x80000000L) != 0 || (COB_IDServerToClient & 0x80000000L) != 0 || nodeIDOfTheSDOServer == 0){ @@ -303,7 +303,7 @@ static void CO_SDOclient_abort(CO_SDOclient_t *SDO_C, uint32_t code){ CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &code); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); } @@ -401,7 +401,7 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( } /* empty receive buffer, reset timeout timer and send message */ - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); @@ -429,7 +429,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ if(SDO_C->SDO && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); /* If SDO server is busy return error */ if(SDO_C->SDO->state != 0){ @@ -456,14 +456,14 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* RX data ****************************************************************************************** */ - if(CO_CANrxNew_READ(SDO_C->CANrxNew)){ + if(CO_FLAG_READ(SDO_C->CANrxNew)){ uint8_t SCS = SDO_C->CANrxData[0]>>5; /* Client command specifier */ /* ABORT */ if (SDO_C->CANrxData[0] == (SCS_ABORT<<5)){ SDO_C->state = SDO_STATE_NOTDEFINED; CO_memcpySwap4(pSDOabortCode , &SDO_C->CANrxData[4]); - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_endedWithServerAbort; } @@ -475,7 +475,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( if(SDO_C->bufferSize <= 4){ /* expedited transfer */ SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } else{ @@ -510,7 +510,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* is end of transfer? */ if(SDO_C->bufferOffset == SDO_C->bufferSize){ SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } SDO_C->state = SDO_STATE_DOWNLOAD_REQUEST; @@ -596,7 +596,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( /* SDO block download successfully transferred */ SDO_C->state = SDO_STATE_NOTDEFINED; SDO_C->timeoutTimer = 0; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } else{ @@ -613,7 +613,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( } } SDO_C->timeoutTimer = 0; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); } /* TMO *********************************************************************************************** */ @@ -821,7 +821,7 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( } /* empty receive buffer, reset timeout timer and send message */ - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->timeoutTimer = 0; SDO_C->timeoutTimerBLOCK =0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); @@ -853,7 +853,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ if(SDO_C->SDO && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); /* If SDO server is busy return error */ if(SDO_C->SDO->state != 0){ @@ -892,13 +892,13 @@ CO_SDOclient_return_t CO_SDOclientUpload( /* RX data ******************************************************************************** */ - if(CO_CANrxNew_READ(SDO_C->CANrxNew)){ + if(CO_FLAG_READ(SDO_C->CANrxNew)){ uint8_t SCS = SDO_C->CANrxData[0]>>5; /* Client command specifier */ /* ABORT */ if (SDO_C->CANrxData[0] == (SCS_ABORT<<5)){ SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); CO_memcpySwap4(pSDOabortCode , &SDO_C->CANrxData[4]); return CO_SDOcli_endedWithServerAbort; } @@ -921,7 +921,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( /* copy data */ while(size--) SDO_C->buffer[size] = SDO_C->CANrxData[4+size]; SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } @@ -966,7 +966,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( if(SDO_C->CANrxData[0] & 0x01){ *pDataSize = SDO_C->bufferOffset; SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } /* set state */ @@ -1033,7 +1033,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( /* copy data */ while(size--) SDO_C->buffer[size] = SDO_C->CANrxData[4+size]; SDO_C->state = SDO_STATE_NOTDEFINED; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); return CO_SDOcli_ok_communicationEnd; } @@ -1121,7 +1121,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( } } SDO_C->timeoutTimer = 0; - CO_CANrxNew_CLEAR(SDO_C->CANrxNew); + CO_FLAG_CLEAR(SDO_C->CANrxNew); } /* TMO *************************************************************************************************** */ diff --git a/stack/CO_SYNC.c b/stack/CO_SYNC.c index d34456a4..ae70709a 100644 --- a/stack/CO_SYNC.c +++ b/stack/CO_SYNC.c @@ -49,7 +49,7 @@ static void CO_SYNC_receive(void *object, void *msg) { if(SYNC->counterOverflowValue == 0){ if(DLC == 0U){ - CO_CANrxNew_SET(SYNC->CANrxNew); + CO_FLAG_SET(SYNC->CANrxNew); } else{ SYNC->receiveError = (uint16_t)DLC | 0x0100U; @@ -59,13 +59,13 @@ static void CO_SYNC_receive(void *object, void *msg) { if(DLC == 1U){ uint8_t *data = CO_CANrxMsg_readData(msg); SYNC->counter = data[0]; - CO_CANrxNew_SET(SYNC->CANrxNew); + CO_FLAG_SET(SYNC->CANrxNew); } else{ SYNC->receiveError = (uint16_t)DLC | 0x0200U; } } - if(CO_CANrxNew_READ(SYNC->CANrxNew)) { + if(CO_FLAG_READ(SYNC->CANrxNew)) { SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; } } @@ -255,7 +255,7 @@ CO_ReturnError_t CO_SYNC_init( SYNC->curentSyncTimeIsInsideWindow = true; - CO_CANrxNew_CLEAR(SYNC->CANrxNew); + CO_FLAG_CLEAR(SYNC->CANrxNew); SYNC->CANrxToggle = false; SYNC->timer = 0; SYNC->counter = 0; @@ -313,10 +313,10 @@ uint8_t CO_SYNC_process( if(timerNew > SYNC->timer) SYNC->timer = timerNew; /* was SYNC just received */ - if(CO_CANrxNew_READ(SYNC->CANrxNew)){ + if(CO_FLAG_READ(SYNC->CANrxNew)){ SYNC->timer = 0; ret = 1; - CO_CANrxNew_CLEAR(SYNC->CANrxNew); + CO_FLAG_CLEAR(SYNC->CANrxNew); } /* SYNC producer */ @@ -372,7 +372,7 @@ uint8_t CO_SYNC_process( } } else { - CO_CANrxNew_CLEAR(SYNC->CANrxNew); + CO_FLAG_CLEAR(SYNC->CANrxNew); } /* verify error from receive function */ diff --git a/stack/CO_TIME.c b/stack/CO_TIME.c index 3482ae1b..6d0dc64f 100644 --- a/stack/CO_TIME.c +++ b/stack/CO_TIME.c @@ -48,7 +48,7 @@ static void CO_TIME_receive(void *object, void *msg){ if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){ // Process Time from msg buffer CO_memcpy((uint8_t*)&TIME->Time.ullValue, data, DLC); - CO_CANrxNew_SET(TIME->CANrxNew); + CO_FLAG_SET(TIME->CANrxNew); } else{ TIME->receiveError = (uint16_t)DLC; @@ -85,7 +85,7 @@ CO_ReturnError_t CO_TIME_init( if(TIME->periodTimeoutTime < TIMECyclePeriod) TIME->periodTimeoutTime = 0xFFFFFFFFL; - CO_CANrxNew_CLEAR(TIME->CANrxNew); + CO_FLAG_CLEAR(TIME->CANrxNew); TIME->timer = 0; TIME->receiveError = 0U; @@ -138,10 +138,10 @@ uint8_t CO_TIME_process( TIME->timer = timerNew; /* was TIME just received */ - if(CO_CANrxNew_READ(TIME->CANrxNew)){ + if(CO_FLAG_READ(TIME->CANrxNew)){ TIME->timer = 0; ret = 1; - CO_CANrxNew_CLEAR(TIME->CANrxNew); + CO_FLAG_CLEAR(TIME->CANrxNew); } /* TIME producer */ @@ -160,7 +160,7 @@ uint8_t CO_TIME_process( CO_errorReport(TIME->em, CO_EM_TIME_TIMEOUT, CO_EMC_COMMUNICATION, TIME->timer); } else { - CO_CANrxNew_CLEAR(TIME->CANrxNew); + CO_FLAG_CLEAR(TIME->CANrxNew); } /* verify error from receive function */ diff --git a/stack/CO_driver.h b/stack/CO_driver.h index 5265a9ab..72a47d9f 100644 --- a/stack/CO_driver.h +++ b/stack/CO_driver.h @@ -375,11 +375,11 @@ typedef struct { #define CO_UNLOCK_OD() /** Check if new message has arrived */ -#define CO_CANrxNew_READ(rxNew) ((rxNew) != NULL) +#define CO_FLAG_READ(rxNew) ((rxNew) != NULL) /** Set new message flag */ -#define CO_CANrxNew_SET(rxNew) { __sync_synchronize(); rxNew = (void *)1L; } +#define CO_FLAG_SET(rxNew) { __sync_synchronize(); rxNew = (void *)1L; } /** Clear new message flag */ -#define CO_CANrxNew_CLEAR(rxNew) { __sync_synchronize(); rxNew = NULL; } +#define CO_FLAG_CLEAR(rxNew) { __sync_synchronize(); rxNew = NULL; } /** @} */ #endif /* CO_DOXYGEN */ From 62ffc7c9f50187f767297c45c3d98e214b521b9f Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 Feb 2020 21:40:07 +0100 Subject: [PATCH 017/520] Drivers removed from stack, directory structure rearranged. - Change log added to README. - Doxygen documentation updated. --- {stack => 301}/CO_Emergency.c | 10 +- {stack => 301}/CO_Emergency.h | 8 +- {stack => 301}/CO_HBconsumer.c | 12 +- {stack => 301}/CO_HBconsumer.h | 4 +- {stack => 301}/CO_NMT_Heartbeat.c | 8 +- {stack => 301}/CO_NMT_Heartbeat.h | 6 +- {stack => 301}/CO_PDO.c | 20 +- {stack => 301}/CO_PDO.h | 2 +- stack/CO_SDOmaster.c => 301/CO_SDOclient.c | 12 +- stack/CO_SDOmaster.h => 301/CO_SDOclient.h | 12 +- stack/CO_SDO.c => 301/CO_SDOserver.c | 12 +- stack/CO_SDO.h => 301/CO_SDOserver.h | 18 +- {stack => 301}/CO_SYNC.c | 16 +- {stack => 301}/CO_SYNC.h | 6 +- {stack => 301}/CO_TIME.c | 10 +- {stack => 301}/CO_TIME.h | 6 +- {stack => 301}/CO_driver.h | 4 +- {stack => 301}/crc16-ccitt.c | 2 +- {stack => 301}/crc16-ccitt.h | 2 +- {stack => 305}/CO_LSS.h | 6 +- {stack => 305}/CO_LSSmaster.c | 6 +- {stack => 305}/CO_LSSmaster.h | 12 +- {stack => 305}/CO_LSSslave.c | 6 +- {stack => 305}/CO_LSSslave.h | 20 +- CANopen.h | 173 ++-- Doxyfile | 149 ++-- LICENSE.old | 340 -------- Makefile | 26 +- README.md | 102 +-- example/CO_OD.c | 6 +- example/CO_OD.h | 2 +- example/CO_OD_with_trace/CO_OD.c | 4 +- example/CO_OD_with_trace/CO_OD.h | 2 +- example/CO_driver.c | 4 +- example/eeprom.c | 12 +- example/eeprom.h | 2 +- {stack => extra}/CO_trace.c | 6 +- {stack => extra}/CO_trace.h | 10 +- socketCAN/CO_Linux_threads.c | 2 +- socketCAN/CO_OD_storage.c | 8 +- socketCAN/CO_OD_storage.h | 4 +- socketCAN/CO_driver.c | 6 +- socketCAN/CO_error.c | 2 +- stack/LPC1768/CO_CAN.h | 69 -- stack/LPC1768/CO_driver.cpp | 485 ----------- stack/LPC1768/CO_driver.h | 213 ----- stack/LPC177x_8x/CANOpenTask.c | 211 ----- stack/LPC177x_8x/CANOpenTask.h | 36 - stack/LPC177x_8x/CO_driver.c | 842 -------------------- stack/LPC177x_8x/CO_driver.h | 236 ------ stack/LPC177x_8x/application.c | 106 --- stack/LPC177x_8x/application.h | 173 ---- stack/LPC177x_8x/readme | 4 - stack/MCF5282/CO_driver.c | 491 ------------ stack/MCF5282/CO_driver.h | 449 ----------- stack/MCF5282/readme | 4 - stack/PIC24_dsPIC33/CO_driver.c | 809 ------------------- stack/PIC24_dsPIC33/CO_driver.h | 513 ------------ stack/PIC32/CO_driver.c | 595 -------------- stack/PIC32/CO_driver.h | 441 ---------- stack/PIC32/eeprom.c | 534 ------------- stack/PIC32/eeprom.h | 100 --- stack/PIC32/main_PIC32.c | 330 -------- stack/SAM3X/CO_Flash.c | 302 ------- stack/SAM3X/CO_Flash.h | 70 -- stack/SAM3X/CO_driver.c | 665 ---------------- stack/SAM3X/CO_driver.h | 229 ------ stack/SAM3X/readme | 6 - stack/STM32/CO_driver.c | 550 ------------- stack/STM32/CO_driver.h | 278 ------- stack/STM32F3/CO_Flash.c | 276 ------- stack/STM32F3/CO_Flash.h | 71 -- stack/STM32F3/CO_driver.c | 511 ------------ stack/STM32F3/CO_driver.h | 250 ------ stack/dsPIC30F/CO_driver.c | 535 ------------- stack/dsPIC30F/CO_driver.h | 452 ----------- stack/eCos/CO_Flash.c | 335 -------- stack/eCos/CO_Flash.h | 71 -- stack/eCos/CO_PollingTimer.c | 88 -- stack/eCos/CO_PollingTimer.h | 54 -- stack/eCos/CO_driver.c | 886 --------------------- stack/eCos/CO_driver.h | 257 ------ stack/eCos/Makefile | 87 -- stack/eCos/application.cpp | 69 -- stack/eCos/ecos_helper.cpp | 56 -- stack/eCos/ecos_helper.h | 29 - stack/eCos/main.c | 109 --- stack/eCos/readme | 12 - stack/socketCAN/CO_Linux_tasks.c | 306 ------- stack/socketCAN/CO_Linux_tasks.h | 113 --- stack/socketCAN/CO_driver.c | 444 ----------- stack/socketCAN/CO_driver.h | 245 ------ 92 files changed, 412 insertions(+), 14665 deletions(-) rename {stack => 301}/CO_Emergency.c (98%) rename {stack => 301}/CO_Emergency.h (99%) rename {stack => 301}/CO_HBconsumer.c (98%) rename {stack => 301}/CO_HBconsumer.h (99%) rename {stack => 301}/CO_NMT_Heartbeat.c (99%) rename {stack => 301}/CO_NMT_Heartbeat.h (98%) rename {stack => 301}/CO_PDO.c (99%) rename {stack => 301}/CO_PDO.h (99%) rename stack/CO_SDOmaster.c => 301/CO_SDOclient.c (99%) rename stack/CO_SDOmaster.h => 301/CO_SDOclient.h (98%) rename stack/CO_SDO.c => 301/CO_SDOserver.c (99%) rename stack/CO_SDO.h => 301/CO_SDOserver.h (99%) rename {stack => 301}/CO_SYNC.c (97%) rename {stack => 301}/CO_SYNC.h (98%) rename {stack => 301}/CO_TIME.c (97%) rename {stack => 301}/CO_TIME.h (98%) rename {stack => 301}/CO_driver.h (99%) rename {stack => 301}/crc16-ccitt.c (99%) rename {stack => 301}/crc16-ccitt.h (98%) rename {stack => 305}/CO_LSS.h (98%) rename {stack => 305}/CO_LSSmaster.c (99%) rename {stack => 305}/CO_LSSmaster.h (98%) rename {stack => 305}/CO_LSSslave.c (99%) rename {stack => 305}/CO_LSSslave.h (96%) delete mode 100644 LICENSE.old rename {stack => extra}/CO_trace.c (99%) rename {stack => extra}/CO_trace.h (96%) delete mode 100644 stack/LPC1768/CO_CAN.h delete mode 100644 stack/LPC1768/CO_driver.cpp delete mode 100644 stack/LPC1768/CO_driver.h delete mode 100644 stack/LPC177x_8x/CANOpenTask.c delete mode 100644 stack/LPC177x_8x/CANOpenTask.h delete mode 100644 stack/LPC177x_8x/CO_driver.c delete mode 100644 stack/LPC177x_8x/CO_driver.h delete mode 100644 stack/LPC177x_8x/application.c delete mode 100644 stack/LPC177x_8x/application.h delete mode 100644 stack/LPC177x_8x/readme delete mode 100644 stack/MCF5282/CO_driver.c delete mode 100644 stack/MCF5282/CO_driver.h delete mode 100644 stack/MCF5282/readme delete mode 100644 stack/PIC24_dsPIC33/CO_driver.c delete mode 100644 stack/PIC24_dsPIC33/CO_driver.h delete mode 100644 stack/PIC32/CO_driver.c delete mode 100644 stack/PIC32/CO_driver.h delete mode 100644 stack/PIC32/eeprom.c delete mode 100644 stack/PIC32/eeprom.h delete mode 100644 stack/PIC32/main_PIC32.c delete mode 100644 stack/SAM3X/CO_Flash.c delete mode 100644 stack/SAM3X/CO_Flash.h delete mode 100644 stack/SAM3X/CO_driver.c delete mode 100644 stack/SAM3X/CO_driver.h delete mode 100644 stack/SAM3X/readme delete mode 100644 stack/STM32/CO_driver.c delete mode 100644 stack/STM32/CO_driver.h delete mode 100644 stack/STM32F3/CO_Flash.c delete mode 100644 stack/STM32F3/CO_Flash.h delete mode 100644 stack/STM32F3/CO_driver.c delete mode 100644 stack/STM32F3/CO_driver.h delete mode 100644 stack/dsPIC30F/CO_driver.c delete mode 100644 stack/dsPIC30F/CO_driver.h delete mode 100644 stack/eCos/CO_Flash.c delete mode 100644 stack/eCos/CO_Flash.h delete mode 100644 stack/eCos/CO_PollingTimer.c delete mode 100644 stack/eCos/CO_PollingTimer.h delete mode 100644 stack/eCos/CO_driver.c delete mode 100644 stack/eCos/CO_driver.h delete mode 100644 stack/eCos/Makefile delete mode 100644 stack/eCos/application.cpp delete mode 100644 stack/eCos/ecos_helper.cpp delete mode 100644 stack/eCos/ecos_helper.h delete mode 100644 stack/eCos/main.c delete mode 100644 stack/eCos/readme delete mode 100644 stack/socketCAN/CO_Linux_tasks.c delete mode 100644 stack/socketCAN/CO_Linux_tasks.h delete mode 100644 stack/socketCAN/CO_driver.c delete mode 100644 stack/socketCAN/CO_driver.h diff --git a/stack/CO_Emergency.c b/301/CO_Emergency.c similarity index 98% rename from stack/CO_Emergency.c rename to 301/CO_Emergency.c index 60366bd6..b7f93738 100644 --- a/stack/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -24,9 +24,9 @@ */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" /* @@ -60,7 +60,7 @@ static void CO_EM_receive(void *object, void *msg) { /* * Function for accessing _Pre-Defined Error Field_ (index 0x1003) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1003(CO_ODF_arg_t *ODF_arg); static CO_SDO_abortCode_t CO_ODF_1003(CO_ODF_arg_t *ODF_arg){ @@ -107,7 +107,7 @@ static CO_SDO_abortCode_t CO_ODF_1003(CO_ODF_arg_t *ODF_arg){ /* * Function for accessing _COB ID EMCY_ (index 0x1014) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1014(CO_ODF_arg_t *ODF_arg); static CO_SDO_abortCode_t CO_ODF_1014(CO_ODF_arg_t *ODF_arg){ diff --git a/stack/CO_Emergency.h b/301/CO_Emergency.h similarity index 99% rename from stack/CO_Emergency.h rename to 301/CO_Emergency.h index 4bb3d85a..87e293a6 100644 --- a/stack/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -33,7 +33,7 @@ extern "C" { /** * @defgroup CO_Emergency Emergency - * @ingroup CO_CANopen + * @ingroup CO_CANopen_301 * @{ * * CANopen Emergency protocol. @@ -323,10 +323,10 @@ bool_t CO_isError(CO_EM_t *em, const uint8_t errorBit); #ifdef CO_DOXYGEN -/** Skip section, if CO_SDO.h is not included */ - #define CO_SDO_H +/** Skip section, if CO_SDOserver.h is not included */ + #define CO_SDO_SERVER_H #endif -#ifdef CO_SDO_H +#ifdef CO_SDO_SERVER_H /** diff --git a/stack/CO_HBconsumer.c b/301/CO_HBconsumer.c similarity index 98% rename from stack/CO_HBconsumer.c rename to 301/CO_HBconsumer.c index c21d8686..5ee4347e 100644 --- a/stack/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -23,11 +23,11 @@ * limitations under the License. */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" -#include "CO_NMT_Heartbeat.h" -#include "CO_HBconsumer.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" +#include "301/CO_HBconsumer.h" /* * Read received message from CAN module. @@ -55,7 +55,7 @@ static void CO_HBcons_receive(void *object, void *msg){ /* * OD function for accessing _Consumer Heartbeat Time_ (index 0x1016) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1016(CO_ODF_arg_t *ODF_arg) { diff --git a/stack/CO_HBconsumer.h b/301/CO_HBconsumer.h similarity index 99% rename from stack/CO_HBconsumer.h rename to 301/CO_HBconsumer.h index 37bb2f06..c3c439e5 100644 --- a/stack/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -33,7 +33,7 @@ extern "C" { /** * @defgroup CO_HBconsumer Heartbeat consumer - * @ingroup CO_CANopen + * @ingroup CO_CANopen_301 * @{ * * CANopen Heartbeat consumer protocol. @@ -146,7 +146,7 @@ CO_ReturnError_t CO_HBconsumer_init( * @param HBcons This object. * @param idx index of the node in HBcons object * @param nodeId see OD 0x1016 description - * @param consumerTime in milliseconds. see OD 0x1016 description + * @param consumerTime_ms in milliseconds. see OD 0x1016 description * @return */ CO_ReturnError_t CO_HBconsumer_initEntry( diff --git a/stack/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c similarity index 99% rename from stack/CO_NMT_Heartbeat.c rename to 301/CO_NMT_Heartbeat.c index b704a8c6..cb7c0704 100644 --- a/stack/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -24,10 +24,10 @@ */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" -#include "CO_NMT_Heartbeat.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" /* * Read received message from CAN module. diff --git a/stack/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h similarity index 98% rename from stack/CO_NMT_Heartbeat.h rename to 301/CO_NMT_Heartbeat.h index 652f4cfb..1d9805e8 100644 --- a/stack/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -33,7 +33,7 @@ extern "C" { /** * @defgroup CO_NMT_Heartbeat NMT and Heartbeat - * @ingroup CO_CANopen + * @ingroup CO_CANopen_301 * @{ * * CANopen Network management and Heartbeat producer protocol. @@ -161,7 +161,7 @@ typedef struct{ * @param NMT This object will be initialized. * @param emPr Emergency main object. * @param nodeId CANopen Node ID of this device. - * @param firstHBTime Time between bootup and first heartbeat message in milliseconds. + * @param firstHBTime_ms Time between bootup and first heartbeat message in milliseconds. * If firstHBTime is greater than _Producer Heartbeat time_ * (object dictionary, index 0x1017), latter is used instead. * @param NMT_CANdev CAN device for NMT reception. @@ -211,7 +211,7 @@ void CO_NMT_initCallback( * * @param NMT This object. * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param HBtime _Producer Heartbeat time_ (object dictionary, index 0x1017). + * @param HBtime_ms _Producer Heartbeat time_ (object dictionary, index 0x1017). * @param NMTstartup _NMT startup behavior_ (object dictionary, index 0x1F80). * @param errorRegister _Error register_ (object dictionary, index 0x1001). * @param errorBehavior pointer to _Error behavior_ array (object dictionary, index 0x1029). diff --git a/stack/CO_PDO.c b/301/CO_PDO.c similarity index 99% rename from stack/CO_PDO.c rename to 301/CO_PDO.c index f7fd9107..ce466f11 100644 --- a/stack/CO_PDO.c +++ b/301/CO_PDO.c @@ -24,12 +24,12 @@ */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" -#include "CO_NMT_Heartbeat.h" -#include "CO_SYNC.h" -#include "CO_PDO.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" +#include "301/CO_SYNC.h" +#include "301/CO_PDO.h" /* * Read received message from CAN module. @@ -414,7 +414,7 @@ static uint32_t CO_TPDOconfigMap(CO_TPDO_t* TPDO, uint8_t noOfMappedObjects){ /* * Function for accessing _RPDO communication parameter_ (index 0x1400+) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_RPDOcom(CO_ODF_arg_t *ODF_arg){ CO_RPDO_t *RPDO; @@ -488,7 +488,7 @@ static CO_SDO_abortCode_t CO_ODF_RPDOcom(CO_ODF_arg_t *ODF_arg){ /* * Function for accessing _TPDO communication parameter_ (index 0x1800+) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_TPDOcom(CO_ODF_arg_t *ODF_arg){ CO_TPDO_t *TPDO; @@ -583,7 +583,7 @@ static CO_SDO_abortCode_t CO_ODF_TPDOcom(CO_ODF_arg_t *ODF_arg){ /* * Function for accessing _RPDO mapping parameter_ (index 0x1600+) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_RPDOmap(CO_ODF_arg_t *ODF_arg){ CO_RPDO_t *RPDO; @@ -649,7 +649,7 @@ static CO_SDO_abortCode_t CO_ODF_RPDOmap(CO_ODF_arg_t *ODF_arg){ /* * Function for accessing _TPDO mapping parameter_ (index 0x1A00+) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_TPDOmap(CO_ODF_arg_t *ODF_arg){ CO_TPDO_t *TPDO; diff --git a/stack/CO_PDO.h b/301/CO_PDO.h similarity index 99% rename from stack/CO_PDO.h rename to 301/CO_PDO.h index a2e6440e..21f7b7da 100644 --- a/stack/CO_PDO.h +++ b/301/CO_PDO.h @@ -33,7 +33,7 @@ extern "C" { /** * @defgroup CO_PDO PDO - * @ingroup CO_CANopen + * @ingroup CO_CANopen_301 * @{ * * CANopen Process Data Object protocol. diff --git a/stack/CO_SDOmaster.c b/301/CO_SDOclient.c similarity index 99% rename from stack/CO_SDOmaster.c rename to 301/CO_SDOclient.c index b621c9e3..3815cca9 100644 --- a/stack/CO_SDOmaster.c +++ b/301/CO_SDOclient.c @@ -1,8 +1,8 @@ /* * CANopen Service Data Object - client. * - * @file CO_SDOmaster.c - * @ingroup CO_SDOmaster + * @file CO_SDOclient.c + * @ingroup CO_SDOclient * @author Janez Paternoster * @author Matej Severkar * @copyright 2004 - 2020 Janez Paternoster @@ -25,10 +25,10 @@ */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_SDOmaster.h" -#include "crc16-ccitt.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_SDOclient.h" +#include "301/crc16-ccitt.h" /* Client command specifier */ diff --git a/stack/CO_SDOmaster.h b/301/CO_SDOclient.h similarity index 98% rename from stack/CO_SDOmaster.h rename to 301/CO_SDOclient.h index 95f4da74..28df959e 100644 --- a/stack/CO_SDOmaster.h +++ b/301/CO_SDOclient.h @@ -1,8 +1,8 @@ /** * CANopen Service Data Object - client protocol. * - * @file CO_SDOmaster.h - * @ingroup CO_SDOmaster + * @file CO_SDOclient.h + * @ingroup CO_SDOclient * @author Janez Paternoster * @author Matej Severkar * @copyright 2004 - 2020 Janez Paternoster @@ -33,13 +33,13 @@ extern "C" { #endif /** - * @defgroup CO_SDOmaster SDO client - * @ingroup CO_CANopen + * @defgroup CO_SDOclient SDO client + * @ingroup CO_CANopen_301 * @{ * - * CANopen Service Data Object - client protocol. + * CANopen Service Data Object - client protocol (master functionality). * - * @see @ref CO_SDO + * @see @ref CO_SDOserver */ diff --git a/stack/CO_SDO.c b/301/CO_SDOserver.c similarity index 99% rename from stack/CO_SDO.c rename to 301/CO_SDOserver.c index b9e4810a..bd5c278a 100644 --- a/stack/CO_SDO.c +++ b/301/CO_SDOserver.c @@ -1,8 +1,8 @@ /* * CANopen Service Data Object - server. * - * @file CO_SDO.c - * @ingroup CO_SDO + * @file CO_SDOserver.c + * @ingroup CO_SDOserver * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * @@ -24,9 +24,9 @@ */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "crc16-ccitt.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/crc16-ccitt.h" /* Client command specifier, see DS301 */ @@ -250,7 +250,7 @@ static void CO_SDO_receive(void *object, void *msg){ * Function for accessing _SDO server parameter_ for default SDO (index 0x1200) * from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1200(CO_ODF_arg_t *ODF_arg); static CO_SDO_abortCode_t CO_ODF_1200(CO_ODF_arg_t *ODF_arg){ diff --git a/stack/CO_SDO.h b/301/CO_SDOserver.h similarity index 99% rename from stack/CO_SDO.h rename to 301/CO_SDOserver.h index 875696e3..3e1ea83a 100644 --- a/stack/CO_SDO.h +++ b/301/CO_SDOserver.h @@ -1,8 +1,8 @@ /** * CANopen Service Data Object - server protocol. * - * @file CO_SDO.h - * @ingroup CO_SDO + * @file CO_SDOserver.h + * @ingroup CO_SDOserver * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * @@ -24,16 +24,16 @@ */ -#ifndef CO_SDO_H -#define CO_SDO_H +#ifndef CO_SDO_SERVER_H +#define CO_SDO_SERVER_H #ifdef __cplusplus extern "C" { #endif /** - * @defgroup CO_SDO SDO server - * @ingroup CO_CANopen + * @defgroup CO_SDOserver SDO server + * @ingroup CO_CANopen_301 * @{ * * CANopen Service Data Object - server protocol. @@ -47,13 +47,13 @@ extern "C" { * All CANopen devices must have implemented SDO server and first SDO server * channel. Servers serves data from Object dictionary. Object dictionary * is a collection of variables, arrays or records (structures), which can be - * used by the stack or by the application. This file (CO_SDO.h) implements - * SDO server. + * used by the stack or by the application. This file (CO_SDOserver.h) + * implements SDO server. * * SDO client can be (optionally) implemented on one (or multiple, if multiple * SDO channels are used) device in CANopen network. Usually this is master * device and provides also some kind of user interface, so configuration of - * the network is possible. Code for the SDO client is in file CO_SDOmaster.h. + * the network is possible. Code for the SDO client is in file CO_SDOclient.h. * * SDO communication cycle is initiated by the client. Client can upload (read) data * from device or can download (write) data to device. If data are less or equal diff --git a/stack/CO_SYNC.c b/301/CO_SYNC.c similarity index 97% rename from stack/CO_SYNC.c rename to 301/CO_SYNC.c index ae70709a..a5347884 100644 --- a/stack/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -24,11 +24,11 @@ */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" -#include "CO_NMT_Heartbeat.h" -#include "CO_SYNC.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" +#include "301/CO_SYNC.h" /* * Read received message from CAN module. @@ -75,7 +75,7 @@ static void CO_SYNC_receive(void *object, void *msg) { /* * Function for accessing _COB ID SYNC Message_ (index 0x1005) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1005(CO_ODF_arg_t *ODF_arg){ CO_SYNC_t *SYNC; @@ -147,7 +147,7 @@ static CO_SDO_abortCode_t CO_ODF_1005(CO_ODF_arg_t *ODF_arg){ /* * Function for accessing _Communication cycle period_ (index 0x1006) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1006(CO_ODF_arg_t *ODF_arg){ CO_SYNC_t *SYNC; @@ -180,7 +180,7 @@ static CO_SDO_abortCode_t CO_ODF_1006(CO_ODF_arg_t *ODF_arg){ /** * Function for accessing _Synchronous counter overflow value_ (index 0x1019) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1019(CO_ODF_arg_t *ODF_arg){ CO_SYNC_t *SYNC; diff --git a/stack/CO_SYNC.h b/301/CO_SYNC.h similarity index 98% rename from stack/CO_SYNC.h rename to 301/CO_SYNC.h index 5a889404..ebe163ec 100644 --- a/stack/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -1,5 +1,5 @@ /** - * CANopen SYNC object protocol. + * CANopen Synchronisation protocol. * * @file CO_SYNC.h * @ingroup CO_SYNC @@ -33,10 +33,10 @@ extern "C" { /** * @defgroup CO_SYNC SYNC - * @ingroup CO_CANopen + * @ingroup CO_CANopen_301 * @{ * - * CANopen SYNC object protocol. + * CANopen Synchronisation protocol. * * For CAN identifier see #CO_Default_CAN_ID_t * diff --git a/stack/CO_TIME.c b/301/CO_TIME.c similarity index 97% rename from stack/CO_TIME.c rename to 301/CO_TIME.c index 6d0dc64f..a4644a38 100644 --- a/stack/CO_TIME.c +++ b/301/CO_TIME.c @@ -23,11 +23,11 @@ * limitations under the License. */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" -#include "CO_NMT_Heartbeat.h" -#include "CO_TIME.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" +#include "301/CO_TIME.h" /* * Read received message from CAN module. diff --git a/stack/CO_TIME.h b/301/CO_TIME.h similarity index 98% rename from stack/CO_TIME.h rename to 301/CO_TIME.h index a3eea4c5..7b789053 100644 --- a/stack/CO_TIME.h +++ b/301/CO_TIME.h @@ -1,5 +1,5 @@ /** - * CANopen TIME object protocol. + * CANopen Time-stamp protocol. * * @file CO_TIME.c * @ingroup CO_TIME @@ -36,10 +36,10 @@ extern "C" { /** * @defgroup CO_TIME TIME - * @ingroup CO_CANopen + * @ingroup CO_CANopen_301 * @{ * - * CANopen TIME object protocol. + * CANopen Time-stamp protocol. * * For CAN identifier see #CO_Default_CAN_ID_t * diff --git a/stack/CO_driver.h b/301/CO_driver.h similarity index 99% rename from stack/CO_driver.h rename to 301/CO_driver.h index 72a47d9f..c4bff4fc 100644 --- a/stack/CO_driver.h +++ b/301/CO_driver.h @@ -35,10 +35,10 @@ extern "C" { /** * @defgroup CO_driver Driver - * @ingroup CO_CANopen + * @ingroup CO_CANopen_301 * @{ * - * Interface between the hardware and the CANopenNode. + * Interface between CAN hardware and CANopenNode. * * CANopenNode is designed for speed and portability. It runs efficiently on * devices from simple 16-bit microcontrollers to PC computers. It can run in diff --git a/stack/crc16-ccitt.c b/301/crc16-ccitt.c similarity index 99% rename from stack/crc16-ccitt.c rename to 301/crc16-ccitt.c index bff5d069..2d0e7a2d 100644 --- a/stack/crc16-ccitt.c +++ b/301/crc16-ccitt.c @@ -25,7 +25,7 @@ #ifndef CO_USE_OWN_CRC16 -#include "crc16-ccitt.h" +#include "301/crc16-ccitt.h" /* diff --git a/stack/crc16-ccitt.h b/301/crc16-ccitt.h similarity index 98% rename from stack/crc16-ccitt.h rename to 301/crc16-ccitt.h index 9d3344f5..791f2864 100644 --- a/stack/crc16-ccitt.h +++ b/301/crc16-ccitt.h @@ -34,7 +34,7 @@ extern "C" { /** * @defgroup CO_crc16_ccitt CRC 16 CCITT - * @ingroup CO_CANopen + * @ingroup CO_CANopen_301 * @{ * * Calculation of CRC 16 CCITT polynomial. diff --git a/stack/CO_LSS.h b/305/CO_LSS.h similarity index 98% rename from stack/CO_LSS.h rename to 305/CO_LSS.h index 726dd339..b5fbab8c 100644 --- a/stack/CO_LSS.h +++ b/305/CO_LSS.h @@ -1,5 +1,5 @@ /** - * CANopen LSS Master/Slave protocol. + * CANopen Layer Setting Services protocol (common). * * @file CO_LSS.h * @ingroup CO_LSS @@ -33,10 +33,10 @@ extern "C" { /** * @defgroup CO_LSS LSS - * @ingroup CO_CANopen + * @ingroup CO_CANopen_305 * @{ * - * CANopen Layer Setting Services protocol + * CANopen Layer Setting Services protocol (common). * * LSS protocol is according to CiA DSP 305 V3.0.0. * diff --git a/stack/CO_LSSmaster.c b/305/CO_LSSmaster.c similarity index 99% rename from stack/CO_LSSmaster.c rename to 305/CO_LSSmaster.c index 7a5011bb..49136335 100644 --- a/stack/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -24,9 +24,9 @@ * limitations under the License. */ -#include "CO_driver.h" -#include "CO_SDO.h" /* for helper functions */ -#include "CO_LSSmaster.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" /* for helper functions */ +#include "305/CO_LSSmaster.h" /* * LSS master slave select state machine. Compared to #CO_LSS_state_t this diff --git a/stack/CO_LSSmaster.h b/305/CO_LSSmaster.h similarity index 98% rename from stack/CO_LSSmaster.h rename to 305/CO_LSSmaster.h index 5c6150fa..48cfd8f8 100644 --- a/stack/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -1,5 +1,5 @@ /** - * CANopen LSS Master/Slave protocol. + * CANopen Layer Setting Service - master protocol. * * @file CO_LSSmaster.h * @ingroup CO_LSS @@ -32,14 +32,14 @@ extern "C" { #endif -#include "CO_LSS.h" +#include "305/CO_LSS.h" /** * @defgroup CO_LSSmaster LSS Master - * @ingroup CO_LSS + * @ingroup CO_CANopen_305 * @{ * - * CANopen Layer Setting Service - client protocol + * CANopen Layer Setting Service - master protocol. * * The client/master can use the following services * - node selection via LSS address @@ -89,7 +89,7 @@ extern "C" { */ typedef enum { CO_LSSmaster_SCAN_FINISHED = 2, /**< Scanning finished successful */ - CO_LSSmaster_WAIT_SLAVE = 1, /**< No response arrived from server yet */ + CO_LSSmaster_WAIT_SLAVE = 1, /**< No response arrived from slave yet */ CO_LSSmaster_OK = 0, /**< Success, end of communication */ CO_LSSmaster_TIMEOUT = -1, /**< No reply received */ CO_LSSmaster_ILLEGAL_ARGUMENT = -2, /**< Invalid argument */ @@ -185,7 +185,7 @@ void CO_LSSmaster_changeTimeout( /** - * Initialize LSSserverRx callback function. + * Initialize LSSmasterRx callback function. * * Function initializes optional callback function, which is called after new * message is received from the CAN bus. Function may wake up external task, diff --git a/stack/CO_LSSslave.c b/305/CO_LSSslave.c similarity index 99% rename from stack/CO_LSSslave.c rename to 305/CO_LSSslave.c index c6c74187..e9ec5808 100644 --- a/stack/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -24,9 +24,9 @@ * limitations under the License. */ -#include "CO_driver.h" -#include "CO_SDO.h" /* for helper functions */ -#include "CO_LSSslave.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" /* for helper functions */ +#include "305/CO_LSSslave.h" /* * Helper function - Handle service "switch state global" diff --git a/stack/CO_LSSslave.h b/305/CO_LSSslave.h similarity index 96% rename from stack/CO_LSSslave.h rename to 305/CO_LSSslave.h index ca14dee4..d38b8bfc 100644 --- a/stack/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -1,5 +1,5 @@ /** - * CANopen LSS Master/Slave protocol. + * CANopen Layer Setting Service - slave protocol. * * @file CO_LSSslave.h * @ingroup CO_LSS @@ -32,16 +32,16 @@ extern "C" { #endif -#include "CO_LSS.h" +#include "305/CO_LSS.h" /** * @defgroup CO_LSSslave LSS Slave - * @ingroup CO_LSS + * @ingroup CO_CANopen_305 * @{ * - * CANopen Layer Setting Service - server protocol + * CANopen Layer Setting Service - slave protocol. * - * The server/slave provides the following services + * The slave provides the following services * - node selection via LSS address * - node selection via LSS fastscan * - Inquire LSS address of currently selected node @@ -51,12 +51,12 @@ extern "C" { * - Activate bit timing parameters * - Store configuration (bit rate and node ID) * - * After CAN module start, the LSS server and NMT server are started and then + * After CAN module start, the LSS slave and NMT slave are started and then * coexist alongside each other. To achieve this behaviour, the CANopen node * startup process has to be conrolled more detailled. Therefore, the function * CO_init() is split up into the functions CO_new(), CO_CANinit(), CO_LSSinit() * and CO_CANopenInit(). - * Moreover, the LSS server needs to pause the NMT server initialization in case + * Moreover, the LSS slave needs to pause the NMT slave initialization in case * no valid node ID is available at start up. * * ###Example @@ -66,7 +66,7 @@ extern "C" { * to understand what this example does and where you need to change it for your * requirements. * - * The following code is only a suggestion on how to use the LSS server. It is + * The following code is only a suggestion on how to use the LSS slave. It is * not a working example! To simplify the code, no error handling is * included. For stable code, proper error handling has to be added to the user * code. @@ -348,7 +348,7 @@ bool_t CO_LSSslave_LEDprocess( * Function initializes callback function, which is called when "config bit * timing parameters" is used. The callback function needs to check if the new bit * rate is supported by the CANopen device. Callback returns "true" if supported. - * When no callback is set the LSS server will no-ack the request, indicating to + * When no callback is set the LSS slave will no-ack the request, indicating to * the master that bit rate change is not supported. * * @remark Depending on the CAN driver implementation, this function is called @@ -392,7 +392,7 @@ void CO_LSSslave_initActivateBitRateCallback( * The callback function gives the user an event to store the corresponding node id and bit rate * to NVM. Those values have to be supplied to the init function as "persistent values" * after reset. If callback returns "true", success is send to the LSS master. When no - * callback is set the LSS server will no-ack the request, indicating to the master + * callback is set the LSS slave will no-ack the request, indicating to the master * that storing is not supported. * * @remark Depending on the CAN driver implementation, this function is called diff --git a/CANopen.h b/CANopen.h index 2f6e794c..7696773a 100644 --- a/CANopen.h +++ b/CANopen.h @@ -1,11 +1,5 @@ -/* - * Main CANopen stack file. - * - * It combines Object dictionary (CO_OD) and all other CANopen source files. - * Configuration information are read from CO_OD.h file. This file uses one - * CAN module. If multiple CAN modules are to be used, then this file may be - * customized for different CANopen configuration. (One or multiple CANopen - * device on one or multiple CAN modules.) +/** + * Main CANopenNode file. * * @file CANopen.h * @ingroup CO_CANopen @@ -38,62 +32,134 @@ extern "C" { #endif - #include "CO_driver.h" - #include "CO_OD.h" - #include "CO_SDO.h" - #include "CO_Emergency.h" - #include "CO_NMT_Heartbeat.h" - #include "CO_SYNC.h" - #include "CO_TIME.h" - #include "CO_PDO.h" - #include "CO_HBconsumer.h" +/** + * @defgroup CO_CANopen CANopen + * @{ + * + * CANopenNode is free and open source implementation of CANopen communication + * protocol. + * + * CANopen is the internationally standardized (EN 50325-4) (CiA DS-301) + * CAN-based higher-layer protocol for embedded control system. For more + * information on CANopen see http://www.can-cia.org/ + * + * CANopenNode homepage is https://github.com/CANopenNode/CANopenNode + * + * CANopen.h file combines Object dictionary (CO_OD) and all other CANopen + * source files. Configuration information are read from CO_OD.h file. + * CO_OD.h/.c files defines CANopen Object Dictionary and are generated by + * external tool. + * CANopen.h file contains most common configuration of CANopenNode objects + * and can also be a template for custom, more complex configurations. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * @} + */ + +/** + * @defgroup CO_CANopen_301 CANopen_301 + * @{ + * + * CANopen application layer and communication profile. + * + * Definitions of data types, encoding rules, object dictionary objects and + * CANopen communication services and protocols. + * @} + */ + +/** + * @defgroup CO_CANopen_305 CANopen_305 + * @{ + * + * CANopen layer setting services (LSS) and protocols. + * + * Inquire or change three parameters on a CANopen device with LSS slave + * capability by a CANopen device with LSS master capability via the CAN + * network: the settings of Node-ID of the CANopen device, bit timing + * parameters of the physical layer (bit rate) or LSS address compliant to the + * identity object (1018h). + * @} + */ + +/** + * @defgroup CO_CANopen_extra CANopen_extra + * @{ + * + * Additional non-standard objects related to CANopenNode. + * @} + */ + +/** + * @addtogroup CO_CANopen + * @{ + */ + + #include "301/CO_driver.h" + #include "301/CO_SDOserver.h" + #include "301/CO_Emergency.h" + #include "301/CO_NMT_Heartbeat.h" + #include "301/CO_SYNC.h" + #include "301/CO_TIME.h" + #include "301/CO_PDO.h" + #include "301/CO_HBconsumer.h" #if CO_NO_SDO_CLIENT != 0 - #include "CO_SDOmaster.h" + #include "301/CO_SDOclient.h" #endif #if CO_NO_TRACE > 0 - #include "CO_trace.h" + #include "extra/CO_trace.h" #endif #if CO_NO_LSS_SERVER == 1 - #include "CO_LSSslave.h" + #include "305/CO_LSSslave.h" #endif #if CO_NO_LSS_CLIENT == 1 - #include "CO_LSSmaster.h" + #include "305/CO_LSSmaster.h" #endif + #include "CO_OD.h" -/* - * CANopen stack object combines pointers to all CANopen objects. +/** + * CANopen object combines pointers to all CANopen objects. */ typedef struct{ - CO_CANmodule_t *CANmodule[1]; /* CAN module objects */ - CO_SDO_t *SDO[CO_NO_SDO_SERVER]; /* SDO object */ - CO_EM_t *em; /* Emergency report object */ - CO_EMpr_t *emPr; /* Emergency process object */ - CO_NMT_t *NMT; /* NMT object */ - CO_SYNC_t *SYNC; /* SYNC object */ - CO_TIME_t *TIME; /* TIME object */ - CO_RPDO_t *RPDO[CO_NO_RPDO];/* RPDO objects */ - CO_TPDO_t *TPDO[CO_NO_TPDO];/* TPDO objects */ - CO_HBconsumer_t *HBcons; /* Heartbeat consumer object*/ + CO_CANmodule_t *CANmodule[1]; /**< CAN module objects */ + CO_SDO_t *SDO[CO_NO_SDO_SERVER]; /**< SDO object */ + CO_EM_t *em; /**< Emergency report object */ + CO_EMpr_t *emPr; /**< Emergency process object */ + CO_NMT_t *NMT; /**< NMT object */ + CO_SYNC_t *SYNC; /**< SYNC object */ + CO_TIME_t *TIME; /**< TIME object */ + CO_RPDO_t *RPDO[CO_NO_RPDO];/**< RPDO objects */ + CO_TPDO_t *TPDO[CO_NO_TPDO];/**< TPDO objects */ + CO_HBconsumer_t *HBcons; /**< Heartbeat consumer object*/ #if CO_NO_LSS_SERVER == 1 - CO_LSSslave_t *LSSslave; /* LSS server/slave object */ + CO_LSSslave_t *LSSslave; /**< LSS server/slave object */ #endif #if CO_NO_LSS_CLIENT == 1 - CO_LSSmaster_t *LSSmaster; /* LSS master/client object */ + CO_LSSmaster_t *LSSmaster; /**< LSS master/client object */ #endif #if CO_NO_SDO_CLIENT != 0 - CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /* SDO client object */ + CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */ #endif #if CO_NO_TRACE > 0 - CO_trace_t *trace[CO_NO_TRACE]; /* Trace object for monitoring variables */ + CO_trace_t *trace[CO_NO_TRACE]; /**< Trace object for monitoring variables */ #endif }CO_t; -/* CANopen object */ +/** CANopen object */ extern CO_t *CO; -/* +/** * Function CO_sendNMTcommand() is simple function, which sends CANopen message. * This part of code is an example of custom definition of simple CANopen * object. Follow the code in CANopen.c file. If macro CO_NO_NMT_MASTER is 1, @@ -112,7 +178,7 @@ typedef struct{ #if CO_NO_LSS_SERVER == 1 -/* +/** * Allocate and initialize memory for CANopen object * * Function must be called in the communication reset section. @@ -123,7 +189,7 @@ typedef struct{ CO_ReturnError_t CO_new(void); -/* +/** * Initialize CAN driver * * Function must be called in the communication reset section. @@ -138,7 +204,7 @@ CO_ReturnError_t CO_CANinit( uint16_t bitRate); -/* +/** * Initialize CANopen LSS slave * * Function must be called in the communication reset section. @@ -152,8 +218,8 @@ CO_ReturnError_t CO_LSSinit( uint16_t bitRate); -/* - * Initialize CANopen stack. +/** + * Initialize CANopenNode. * * Function must be called in the communication reset section. * @@ -165,8 +231,8 @@ CO_ReturnError_t CO_CANopenInit( #else /* CO_NO_LSS_SERVER == 1 */ -/* - * Initialize CANopen stack. +/** + * Initialize CANopenNode. * * Function must be called in the communication reset section. * @@ -185,7 +251,7 @@ CO_ReturnError_t CO_init( #endif /* CO_NO_LSS_SERVER == 1 */ -/* +/** * Delete CANopen object and free memory. Must be called at program exit. * * @param CANptr Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). @@ -193,7 +259,7 @@ CO_ReturnError_t CO_init( void CO_delete(void *CANptr); -/* +/** * Process CANopen objects. * * Function must be called cyclically. It processes all "asynchronous" CANopen @@ -217,7 +283,7 @@ CO_NMT_reset_cmd_t CO_process( #if CO_NO_SYNC == 1 -/* +/** * Process CANopen SYNC objects. * * Function must be called cyclically from real time thread with constant @@ -233,7 +299,7 @@ bool_t CO_process_SYNC( uint32_t timeDifference_us); #endif -/* +/** * Process CANopen RPDO objects. * * Function must be called cyclically from real time thread with constant. @@ -246,7 +312,7 @@ void CO_process_RPDO( CO_t *co, bool_t syncWas); -/* +/** * Process CANopen TPDO objects. * * Function must be called cyclically from real time thread with constant. @@ -269,7 +335,7 @@ void CO_process_TPDO( * Function must be called cyclically from real time thread with constant. * interval (1ms typically). It processes SYNC and PDO CANopen objects. * - * @param CO This object. + * @param co This object. * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param timerNext_us [out] info to OS - maximum delay after function * should be called next time in [microseconds]. Value can be used for OS @@ -290,4 +356,5 @@ bool_t CO_process_SYNC_PDO( } #endif /*__cplusplus*/ -#endif /*CANopen_H*/ +/** @} */ +#endif /* CANopen_H */ diff --git a/Doxyfile b/Doxyfile index 369ec70a..1ab67ed2 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,20 +38,20 @@ PROJECT_NAME = CANopenNode # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -118,7 +118,7 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief @@ -152,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -161,7 +161,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -228,13 +228,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. -TCL_SUBST = +TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -281,7 +281,7 @@ OPTIMIZE_OUTPUT_VHDL = NO # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -638,7 +638,7 @@ GENERATE_DEPRECATEDLIST= YES # sections, marked by \if ... \endif and \cond # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -680,7 +680,7 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated @@ -693,7 +693,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -703,7 +703,7 @@ LAYOUT_FILE = # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -768,7 +768,7 @@ WARN_FORMAT = "$file:$line: $text" # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -781,7 +781,10 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = README.md \ - stack + CANopen.h \ + 301 \ + 305 \ + extra \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -806,7 +809,7 @@ INPUT_ENCODING = UTF-8 # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, # *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. -FILE_PATTERNS = +FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -821,7 +824,7 @@ RECURSIVE = NO # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -837,7 +840,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -848,20 +851,20 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands @@ -874,7 +877,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -895,7 +898,7 @@ IMAGE_PATH = # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -908,7 +911,7 @@ INPUT_FILTER = # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for @@ -923,14 +926,14 @@ FILTER_SOURCE_FILES = NO # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -1035,7 +1038,7 @@ CLANG_ASSISTED_PARSING = NO # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. -CLANG_OPTIONS = +CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index @@ -1061,7 +1064,7 @@ COLS_IN_ALPHA_INDEX = 5 # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output @@ -1105,7 +1108,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1115,7 +1118,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1127,7 +1130,7 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets @@ -1140,7 +1143,7 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1150,7 +1153,7 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to @@ -1279,7 +1282,7 @@ GENERATE_HTMLHELP = NO # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, @@ -1287,7 +1290,7 @@ CHM_FILE = # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). @@ -1300,7 +1303,7 @@ GENERATE_CHI = NO # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it @@ -1331,7 +1334,7 @@ GENERATE_QHP = NO # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace @@ -1356,7 +1359,7 @@ QHP_VIRTUAL_FOLDER = doc # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom @@ -1364,21 +1367,21 @@ QHP_CUST_FILTER_NAME = # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To @@ -1511,7 +1514,7 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site @@ -1519,7 +1522,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1579,7 +1582,7 @@ EXTERNAL_SEARCH = NO # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1595,7 +1598,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1605,7 +1608,7 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output @@ -1669,7 +1672,7 @@ PAPER_TYPE = a4 # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # generated LaTeX document. The header should contain everything until the first @@ -1685,7 +1688,7 @@ EXTRA_PACKAGES = # to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last @@ -1696,7 +1699,7 @@ LATEX_HEADER = # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = # The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined # LaTeX style sheets that are included after the standard style sheets created @@ -1707,7 +1710,7 @@ LATEX_FOOTER = # list). # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1715,7 +1718,7 @@ LATEX_EXTRA_STYLESHEET = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1823,14 +1826,14 @@ RTF_HYPERLINKS = NO # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's config file. A template extensions file can be generated # using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = # If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code # with syntax highlighting in the RTF output. @@ -1875,7 +1878,7 @@ MAN_EXTENSION = .3 # MAN_EXTENSION with the initial . removed. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_SUBDIR = +MAN_SUBDIR = # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real @@ -1988,7 +1991,7 @@ PERLMOD_PRETTY = YES # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor @@ -2029,7 +2032,7 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = +INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -2037,7 +2040,7 @@ INCLUDE_PATH = # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -2048,8 +2051,12 @@ INCLUDE_FILE_PATTERNS = # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. PREDEFINED = CO_DOXYGEN \ + CO_NO_SYNC=1 \ CO_NO_SDO_CLIENT=1 \ - CO_NO_NMT_MASTER=1 + CO_NO_NMT_MASTER=1 \ + CO_NO_LSS_SERVER \ + CO_NO_LSS_CLIENT \ + CO_NO_TRACE=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2058,7 +2065,7 @@ PREDEFINED = CO_DOXYGEN \ # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have @@ -2087,13 +2094,13 @@ SKIP_FUNCTION_MACROS = YES # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES, all external class will be listed in # the class index. If set to NO, only the inherited external classes will be @@ -2142,14 +2149,14 @@ CLASS_DIAGRAMS = NO # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. @@ -2198,7 +2205,7 @@ DOT_FONTSIZE = 10 # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # each documented class showing the direct and indirect inheritance relations. @@ -2344,26 +2351,26 @@ INTERACTIVE_SVG = NO # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the # path where java can find the plantuml.jar file. If left blank, it is assumed @@ -2371,17 +2378,17 @@ DIAFILE_DIRS = # generate a warning when it encounters a \startuml command in this case and # will not generate output for the diagram. -PLANTUML_JAR_PATH = +PLANTUML_JAR_PATH = # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a # configuration file for plantuml. -PLANTUML_CFG_FILE = +PLANTUML_CFG_FILE = # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. -PLANTUML_INCLUDE_PATH = +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes diff --git a/LICENSE.old b/LICENSE.old deleted file mode 100644 index 1f963da0..00000000 --- a/LICENSE.old +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program 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 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. - diff --git a/Makefile b/Makefile index b7c5e788..73baf712 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,6 @@ DRV_SRC = example -STACK_SRC = stack CANOPEN_SRC =. APPL_SRC = example @@ -12,7 +11,6 @@ LINK_TARGET = canopennode INCLUDE_DIRS = \ -I$(DRV_SRC) \ - -I$(STACK_SRC) \ -I$(CANOPEN_SRC) \ -I$(APPL_SRC) @@ -20,18 +18,18 @@ INCLUDE_DIRS = \ SOURCES = \ $(DRV_SRC)/CO_driver.c \ $(DRV_SRC)/eeprom.c \ - $(STACK_SRC)/crc16-ccitt.c \ - $(STACK_SRC)/CO_SDO.c \ - $(STACK_SRC)/CO_Emergency.c \ - $(STACK_SRC)/CO_NMT_Heartbeat.c \ - $(STACK_SRC)/CO_SYNC.c \ - $(STACK_SRC)/CO_TIME.c \ - $(STACK_SRC)/CO_PDO.c \ - $(STACK_SRC)/CO_HBconsumer.c \ - $(STACK_SRC)/CO_SDOmaster.c \ - $(STACK_SRC)/CO_LSSmaster.c \ - $(STACK_SRC)/CO_LSSslave.c \ - $(STACK_SRC)/CO_trace.c \ + $(CANOPEN_SRC)/301/CO_SDOserver.c \ + $(CANOPEN_SRC)/301/CO_Emergency.c \ + $(CANOPEN_SRC)/301/CO_NMT_Heartbeat.c \ + $(CANOPEN_SRC)/301/CO_HBconsumer.c \ + $(CANOPEN_SRC)/301/CO_SYNC.c \ + $(CANOPEN_SRC)/301/CO_PDO.c \ + $(CANOPEN_SRC)/301/CO_TIME.c \ + $(CANOPEN_SRC)/301/CO_SDOclient.c \ + $(CANOPEN_SRC)/301/crc16-ccitt.c \ + $(CANOPEN_SRC)/305/CO_LSSslave.c \ + $(CANOPEN_SRC)/305/CO_LSSmaster.c \ + $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ $(APPL_SRC)/CO_OD.c \ $(APPL_SRC)/main.c diff --git a/README.md b/README.md index 7fd420c5..c97195d6 100644 --- a/README.md +++ b/README.md @@ -144,46 +144,25 @@ Flowchart of a typical CANopenNode implementation File structure -------------- - - **CANopen.h/.c** - Initialization and processing of CANopen objects. Most - usual implementation of CANopen device. - - **stack** - Directory with all CANopen objects in separate files. - - **CO_Emergency.h/.c** - CANopen Emergency object. - - **CO_NMT_Heartbeat.h/.c** - CANopen Network slave and Heartbeat producer object. - - **CO_HBconsumer.h/.c** - CANopen Heartbeat consumer object. - - **CO_LSS.h** - CANopen LSS common. This is common to LSS master and slave. - - **CO_LSSmaster.h/.c** - CANopen LSS master functionality. - - **CO_LSSslave.h/.c** - CANopen LSS slave functionality. - - **CO_SYNC.h/.c** - CANopen SYNC producer and consumer object. - - **CO_TIME.h/.c** - CANopen TIME protocol object. - - **CO_SDO.h/.c** - CANopen SDO server object. It serves data from Object dictionary. - - **CO_PDO.h/.c** - CANopen PDO object. It configures, receives and transmits CANopen process data. - - **CO_SDOmaster.h/.c** - CANopen SDO client object (master functionality). - - **CO_trace.h/.c** - Trace object with timestamp for monitoring variables from Object Dictionary (optional). - - **crc16-ccitt.h/.c** - CRC calculation object. - - **drvTemplate** - Directory with microcontroller specific files. In this - case it is template for new implementations. It is also documented, other - directories are not. - - **CO_driver.h/.c** - Microcontroller specific objects for CAN module. - - **eeprom.h/.c** - Functions for storage of Object dictionary, optional. - - **helpers.h/.c** - Some optional files with specific helper functions. - - **socketCAN** - Directory for Linux socketCAN interface. - - **PIC32** - Directory for PIC32 devices from Microchip. - - **PIC24_dsPIC33** - Directory for PIC24 and dsPIC33 devices from Microchip. - - **dsPIC30F** - Directory for dsPIC30F devices from Microchip. - - **eCos** - Directory for all devices supported by eCos RTOS. - - **SAM3X** - Directory for SAM3X ARM Cortex M3 devices with ASF library from Atmel. - - **STM32** - Directory for STM32 ARM devices from ST. - - **LPC177x_8x** - Directory for LPC177x (Cortex M3) devices with FreeRTOS from NXP. - - **MCF5282** - Directory for MCF5282 (ColdFire V2) device from Freescale. - - **codingStyle** - Description of the coding style. - - **Doxyfile** - Configuration file for the documentation generator *doxygen*. - - **Makefile** - Basic makefile. - - **LICENSE** - License. - - **README.md** - This file. - - **example** - Directory with basic example. + - **301/** - CANopen application layer and communication profile. + - **CO_driver.h** - Interface between CAN hardware and CANopenNode. + - **CO_Emergency.h/.c** - CANopen Emergency protocol. + - **CO_HBconsumer.h/.c** - CANopen Heartbeat consumer protocol. + - **CO_NMT_Heartbeat.h/.c** - CANopen Network management and Heartbeat producer protocol. + - **CO_PDO.h/.c** - CANopen Process Data Object protocol. + - **CO_SDOclient.h/.c** - CANopen Service Data Object - client protocol (master functionality). + - **CO_SDOserver.h/.c** - CANopen Service Data Object - server protocol. + - **CO_SYNC.h/.c** - CANopen Synchronisation protocol (producer and consumer). + - **CO_TIME.h/.c** - CANopen Time-stamp protocol. + - **crc16-ccitt.h/.c** - Calculation of CRC 16 CCITT polynomial. + - **305/** - CANopen layer setting services (LSS) and protocols. + - **CO_LSS.h** - CANopen Layer Setting Services protocol (common). + - **CO_LSSmaster.h/.c** - CANopen Layer Setting Service - master protocol. + - **CO_LSSslave.h/.c** - CANopen Layer Setting Service - slave protocol. + - **extra/** + - **CO_trace.h/.c** - CANopen trace object for recording variables over time. + - **example/** - Directory with basic example. - **main.c** - Mainline and other threads - example template. - - **application.h/.c** - Separate file with some functions, which are - called from main.c. May be used for application specific code. - **CO_OD.h/.c** - CANopen Object dictionary. Automatically generated files. - **IO.eds** - Standard CANopen EDS file, which may be used from CANopen configuration tool. Automatically generated file. @@ -191,6 +170,20 @@ File structure It is used by *Object dictionary editor* application, which generates other files. - _ **project.html** - *Object dictionary editor* launcher. + - **socketCAN/** - Directory for Linux socketCAN interface. + - **CO_driver_target.h** - Linux socketCAN specific definitions for CANopenNode. + - **CO_driver.c** - Interface between Linux socketCAN and CANopenNode. + - **CO_error.h/.c** - Linux socketCAN Error handling object. + - **CO_Linux_threads.h/.c** - Helper functions for implementing CANopen threads in Linux. + - **CO_notify_pipe.h/.c** - Notify pipe for Linux threads. + - **CO_OD_storage.h/.c** - Object Dictionary storage object for Linux SocketCAN. + - **CANopen.h/.c** - Initialization and processing of CANopen objects. + - **codingStyle** - Example of the coding style. + - **.clang-format** - Definition file for the coding style. + - **Doxyfile** - Configuration file for the documentation generator *doxygen*. + - **Makefile** - Basic makefile. + - **LICENSE** - License. + - **README.md** - This file. ### Object dictionary editor @@ -232,12 +225,31 @@ For the driver developers, who wish to share and cooperate, I recommend the foll 6. Write a good README.md file, where you describe your project, specify demo board, tools used, etc. -History of the project ----------------------- -Project was initially hosted on http://sourceforge.net/projects/canopennode/ -It started in 2004 with PIC18F microcontrollers from Microchip. -Fresh, cleaned repository of CANopenNode stack started on 25.7.2015. -For older history see http://sourceforge.net/p/canopennode/code_complete/ +Change Log +---------- +- [Unreleased split-driver](https://github.com/CANopenNode/CANopenNode/tree/split-driver): [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/master...split-driver) + - All drivers removed from this project, except Neuberger-socketCAN for Linux. + - Driver interface clarified, common CO_driver.h, specific CO_driver_target.h. + - Directory structure rearranged. + - Time base is now microsecond in all functions. + - All CANopen objects calculates next timer info for OS. + - Heartbeat consumer optimized and fixed. + - Basic Linux socketCAN example. +- [Unreleased master](https://github.com/CANopenNode/CANopenNode): [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...master) + - License changed to Apache 2.0. + - CANopen TIME protocol added. + - Various fixes. +- **[v1.2](https://github.com/CANopenNode/CANopenNode/tree/v1.2)** - 2019-10-08: [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v1.1...v1.2) + - CANopen LSS master/slave protocol added for configuration for bitrate and node ID. + - Memory barrier implemented for setting/clearing flags for CAN received message. + - Neuberger-socketCAN driver added. + - Emergency consumer added with callbacks. Emergency revised. + - Heartbeat consumer revised, callbacks added. +- **[v1.1](https://github.com/CANopenNode/CANopenNode/tree/v1.1)** - 2019-10-08: Bugfixes. [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v1.0...v1.1) +- **[v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0)** - 2017-08-01: Stable. [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v0.5...v1.0) +- **[v0.5](https://github.com/CANopenNode/CANopenNode/tree/v0.5)** - 2015-10-20: Git repository started on GitHub. +- **[v0.4](https://sourceforge.net/p/canopennode/code_complete/ci/master/tree/)** - 2012-02-26: Git repository started on Sourceforge. +- **[v0.1](https://sourceforge.net/projects/canopennode/files/canopennode/CANopenNode-0.80/)** - 2004-06-29: First edition of CANopenNode on SourceForge. License diff --git a/example/CO_OD.c b/example/CO_OD.c index 4422ae9f..290a9fbe 100644 --- a/example/CO_OD.c +++ b/example/CO_OD.c @@ -6,7 +6,7 @@ * Object Dictionary Editor is currently an older, but functional web * application. For more info see See 'Object_Dictionary_Editor/about.html' in * - * For more information on CANopen Object Dictionary see . + * For more information on CANopen Object Dictionary see . * * @file CO_OD.c * @author Janez Paternoster @@ -30,9 +30,9 @@ */ -#include "CO_driver.h" +#include "301/CO_driver.h" #include "CO_OD.h" -#include "CO_SDO.h" +#include "301/CO_SDOserver.h" /******************************************************************************* diff --git a/example/CO_OD.h b/example/CO_OD.h index c22264bb..756970cf 100644 --- a/example/CO_OD.h +++ b/example/CO_OD.h @@ -6,7 +6,7 @@ * Object Dictionary Editor is currently an older, but functional web * application. For more info see See 'Object_Dictionary_Editor/about.html' in * - * For more information on CANopen Object Dictionary see . + * For more information on CANopen Object Dictionary see . * * @file CO_OD.h * @author Janez Paternoster diff --git a/example/CO_OD_with_trace/CO_OD.c b/example/CO_OD_with_trace/CO_OD.c index 2ea6b490..2c50709d 100644 --- a/example/CO_OD_with_trace/CO_OD.c +++ b/example/CO_OD_with_trace/CO_OD.c @@ -6,7 +6,7 @@ * Object Dictionary Editor is currently an older, but functional web * application. For more info see See 'Object_Dictionary_Editor/about.html' in * - * For more information on CANopen Object Dictionary see . + * For more information on CANopen Object Dictionary see . * * @file CO_OD.c * @author Janez Paternoster @@ -32,7 +32,7 @@ #include "CO_driver.h" #include "CO_OD.h" -#include "CO_SDO.h" +#include "CO_SDOserver.h" /******************************************************************************* diff --git a/example/CO_OD_with_trace/CO_OD.h b/example/CO_OD_with_trace/CO_OD.h index f9710441..717b749b 100644 --- a/example/CO_OD_with_trace/CO_OD.h +++ b/example/CO_OD_with_trace/CO_OD.h @@ -6,7 +6,7 @@ * Object Dictionary Editor is currently an older, but functional web * application. For more info see See 'Object_Dictionary_Editor/about.html' in * - * For more information on CANopen Object Dictionary see . + * For more information on CANopen Object Dictionary see . * * @file CO_OD.h * @author Janez Paternoster diff --git a/example/CO_driver.c b/example/CO_driver.c index 3e955122..47737652 100644 --- a/example/CO_driver.c +++ b/example/CO_driver.c @@ -26,8 +26,8 @@ */ -#include "CO_driver.h" -#include "CO_Emergency.h" +#include "301/CO_driver.h" +#include "301/CO_Emergency.h" /******************************************************************************/ diff --git a/example/eeprom.c b/example/eeprom.c index 81a231ef..ad2b2a96 100644 --- a/example/eeprom.c +++ b/example/eeprom.c @@ -26,17 +26,17 @@ */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/crc16-ccitt.h" #include "eeprom.h" -#include "crc16-ccitt.h" /** * OD function for accessing _Store parameters_ (index 0x1010) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg); static CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg){ @@ -73,7 +73,7 @@ static CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg){ /** * OD function for accessing _Restore default parameters_ (index 0x1011) from SDO server. * - * For more information see file CO_SDO.h. + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg); static CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg){ diff --git a/example/eeprom.h b/example/eeprom.h index 5f6d981d..6ed302f6 100644 --- a/example/eeprom.h +++ b/example/eeprom.h @@ -35,7 +35,7 @@ extern "C" { /** * @defgroup CO_eeprom Nonvolatile storage - * @ingroup CO_CANopen + * @ingroup CO_CANopen_extra * @{ * * Storage of nonvolatile CANopen variables into the eeprom. diff --git a/stack/CO_trace.c b/extra/CO_trace.c similarity index 99% rename from stack/CO_trace.c rename to extra/CO_trace.c index 943568f9..5bfcb27c 100644 --- a/stack/CO_trace.c +++ b/extra/CO_trace.c @@ -23,7 +23,7 @@ */ -#include "CO_trace.h" +#include "extra/CO_trace.h" #include #ifndef CO_OWN_INTTYPES #include /* for PRIu32("u" or "lu") and PRId32("d" or "ld") */ @@ -170,7 +170,7 @@ static void findVariable(CO_trace_t *trace) { /* OD function for accessing _OD_traceConfig_ (index 0x2300+) from SDO server. - * For more information see file CO_SDO.h. */ + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_traceConfig(CO_ODF_arg_t *ODF_arg) { CO_trace_t *trace; CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; @@ -239,7 +239,7 @@ static CO_SDO_abortCode_t CO_ODF_traceConfig(CO_ODF_arg_t *ODF_arg) { /* OD function for accessing _OD_trace_ (index 0x2400+) from SDO server. - * For more information see file CO_SDO.h. */ + * For more information see file CO_SDOserver.h. */ static CO_SDO_abortCode_t CO_ODF_trace(CO_ODF_arg_t *ODF_arg) { CO_trace_t *trace; CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; diff --git a/stack/CO_trace.h b/extra/CO_trace.h similarity index 96% rename from stack/CO_trace.h rename to extra/CO_trace.h index 822bd108..17d2e9e3 100644 --- a/stack/CO_trace.h +++ b/extra/CO_trace.h @@ -1,5 +1,5 @@ /** - * CANopen trace interface. + * CANopen trace object for recording variables over time. * * @file CO_trace.h * @ingroup CO_trace @@ -31,16 +31,16 @@ extern "C" { #endif -#include "CO_driver.h" -#include "CO_SDO.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" /** * @defgroup CO_trace Trace - * @ingroup CO_CANopen + * @ingroup CO_CANopen_extra * @{ * - * CANopen trace for recording variables over time. + * CANopen trace object for recording variables over time. * * In embedded systems there is often a need to monitor some variables over time. * Results are then displayed on graph, similar as in oscilloscope. diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index 80394a81..be24d2fa 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -28,7 +28,7 @@ #include #include -#include "CO_driver.h" +#include "301/CO_driver.h" #include "CANopen.h" /* Helper function - get monotonic clock time in ms */ diff --git a/socketCAN/CO_OD_storage.c b/socketCAN/CO_OD_storage.c index bce6e701..be71bfae 100644 --- a/socketCAN/CO_OD_storage.c +++ b/socketCAN/CO_OD_storage.c @@ -23,11 +23,11 @@ */ -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/crc16-ccitt.h" #include "CO_OD_storage.h" -#include "crc16-ccitt.h" #include #include /* for memcpy */ diff --git a/socketCAN/CO_OD_storage.h b/socketCAN/CO_OD_storage.h index 23aab080..965a7ad2 100644 --- a/socketCAN/CO_OD_storage.h +++ b/socketCAN/CO_OD_storage.h @@ -27,8 +27,8 @@ #define CO_OD_STORAGE_H -#include "CO_driver.h" -#include "CO_SDO.h" +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" #include diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 9b3d6d44..9f6f76c4 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -34,7 +34,7 @@ #include #include -#include "CO_driver.h" +#include "301/CO_driver.h" #if defined CO_DRIVER_ERROR_REPORTING && __has_include("syslog/log.h") #include "syslog/log.h" @@ -43,8 +43,8 @@ #define log_printf(macropar_prio, macropar_message, ...) #endif -#if __has_include("CO_Emergency.h") - #include "CO_Emergency.h" +#if __has_include("301/CO_Emergency.h") + #include "301/CO_Emergency.h" #define USE_EMERGENCY_OBJECT #endif diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index b8aa2cd4..25d3bc1a 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -29,7 +29,7 @@ #include #include -#include "CO_driver.h" +#include "301/CO_driver.h" #include "CO_error.h" diff --git a/stack/LPC1768/CO_CAN.h b/stack/LPC1768/CO_CAN.h deleted file mode 100644 index 3858aa66..00000000 --- a/stack/LPC1768/CO_CAN.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * CAN module object for LPC1768 microcontroller using Mbed SDK. - * - * @file CO_CAN.h - * @author Benoit Rapidel - * @copyright 2016 Benoit Rapidel - * - * 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_CAN_H -#define CO_CAN_H - -#ifndef MBED_CAN -#error "MBED_CAN must be defined to select CAN port" -#endif - -#include "mbed.h" - -#if (MBED_CAN == 0) -#define MBED_CAN_RX p9 -#define MBED_CAN_TX p10 -#define MBED_CAN_REG LPC_CAN1 -#else -#define MBED_CAN_RX (p30) -#define MBED_CAN_TX (p29) -#define MBED_CAN_REG (LPC_CAN2) -#endif - -#define MBED_CHECK_TX_BUFFERS (MBED_CAN_REG->SR & 0x4 || MBED_CAN_REG->SR & 0x400 || MBED_CAN_REG->SR & 0x40000) -#define MBED_CHECK_TX_INTERRUPTS(intStatus) (intStatus & 0x2 || intStatus & 0x200 || intStatus & 0x400) - -extern CAN *CANport; - -#endif // CO_CAN_H diff --git a/stack/LPC1768/CO_driver.cpp b/stack/LPC1768/CO_driver.cpp deleted file mode 100644 index e82d1de0..00000000 --- a/stack/LPC1768/CO_driver.cpp +++ /dev/null @@ -1,485 +0,0 @@ -/* - * CAN module object for LPC1768 microcontroller using Mbed SDK. - * - * @file CO_driver.cpp - * @author Benoit Rapidel - * @copyright 2016 Benoit Rapidel - * - * 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. - */ - - -#include "mbed.h" -#include "LPC17xx.h" -#include "CAN.h" - -extern "C" { -#include "CO_driver.h" -#include "CO_Emergency.h" - -#include "CO_CAN.h" -} - -CAN CANport0(MBED_CAN_RX, MBED_CAN_TX); -CAN *CANport = NULL; - - -/* helper functions */ - -CANMessage toCANMessage(CO_CANtx_t *CO_msg) { - CANMessage msg; - msg.id = (uint32_t) CO_msg->ident & 0x07FFU; - msg.len = (uint32_t) CO_msg->DLC; - msg.type = - ((uint32_t) CO_msg->ident & 0x8000U) == 0x8000 ? - CANRemote : CANData; - memcpy(msg.data, CO_msg->data, CO_msg->DLC); - - return msg; -} - -void fromCANMessage(CANMessage *msg, CO_CANrxMsg_t *CO_msg) { - CO_msg->ident = (uint32_t) msg->id & 0x07FFU; - CO_msg->DLC = (uint32_t) msg->len; - CO_msg->ident = - (msg->type == CANRemote) ? CO_msg->ident | 0x8000 : CO_msg->ident; - memcpy(CO_msg->data, msg->data, CO_msg->DLC); -} - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ - /* Put CAN module in configuration mode */ -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - /* Put CAN module in normal mode */ - // CANport->mode(CAN::Reset); - - // can_mode(LPC_CAN2->, CAN::Normal); - // LPC_IOCON->PIO0_4 = PIN_INPUT P - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - uint16_t i; - uint16_t freq_err = 0; - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->CANdriverState = CANdriverState; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = false; //(rxSize <= 32U) ? true : false;/* microcontroller dependent */ - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - CANmodule->em = NULL; - - for(i=0U; ireset(); - - - /* Configure CAN timing */ - int CANbaudRate = CANbitRate * 1000; - freq_err = CANport->frequency(CANbaudRate); - if(freq_err != 1) { - return CO_ERROR_PARAMETERS; - } - - - /* Configure CAN module hardware filters */ - if(CANmodule->useCANrxFilters){ - /* CAN module filters are used, they will be configured with */ - /* CO_CANrxBufferInit() functions, called by separate CANopen */ - /* init functions. */ - /* Configure all masks so, that received message must match filter */ - // TODO - } - else{ - /* CAN module filters are not used, all messages with standard 11-bit */ - /* identifier will be received */ - /* Configure mask 0 so, that all messages with standard identifier are accepted */ - // CANport->filter(0, 0, CANAny); - } - - - /* configure CAN interrupt registers */ - - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){ - /* turn off the module */ -} - - -/******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){ - return (uint16_t) rxMsg->ident; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){ - /* buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - - /* Configure object variables */ - buffer->object = object; - buffer->pFunct = pFunct; - - /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */ - buffer->ident = ident & 0x07FFU; - if(rtr){ - buffer->ident |= 0x0800U; - } - buffer->mask = (mask & 0x07FFU) | 0x0800U; - - /* Set CAN hardware module filter and mask. */ - if(CANmodule->useCANrxFilters){ - // TODO - } - } - else{ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer. - * Microcontroller specific. */ - buffer->ident = ((uint32_t) ident & 0x07FFU); - buffer->DLC = ((uint32_t) noOfBytes & 0xFU); - /* toggle RTR bit if CAN message is remote type */ - if (rtr) buffer->ident |= 0x8000U; - - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } - - return buffer; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ - CO_ReturnError_t err = CO_ERROR_NO; - - CANMessage msg; - - /* Verify overflow */ - if(buffer->bufferFull){ - if(!CANmodule->firstCANtxMessage){ - /* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, buffer->ident); - } - err = CO_ERROR_TX_OVERFLOW; - // USBport.printf("BUFF_FULL OVERFLOW\r\n"); - } - - CO_LOCK_CAN_SEND(); - /* if CAN TX buffer is free, copy message to it */ - if ((MBED_CHECK_TX_BUFFERS) && CANmodule->CANtxCount == 0){ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - /* copy message and txRequest */ - // USBport.printf("SEND\r\n"); - CANport->write(toCANMessage(buffer)); - } - /* if no buffer is free, message will be sent by interrupt */ - else{ - // USBport.printf("BUFF_FULL\r\n"); - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - CO_UNLOCK_CAN_SEND(); - - return err; -} - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ - uint32_t tpdoDeleted = 0U; - - CO_LOCK_CAN_SEND(); - /* Abort message from CAN module, if there is synchronous TPDO. - * Take special care with this functionality. */ - if (((MBED_CAN_REG->GSR & (1 << 2)) == 0) && CANmodule->bufferInhibitFlag){ - /* clear TXREQ */ - MBED_CAN_REG->CMR = (1 << 5) | (1 << 1); // Select TX buffer 1 and run AT command (abort) - MBED_CAN_REG->CMR = (1 << 6) | (1 << 1); // Select TX buffer 2 and run AT command (abort) - MBED_CAN_REG->CMR = (1 << 7) | (1 << 1); // Select TX buffer 3 and run AT command (abort) - - CANmodule->bufferInhibitFlag = false; - tpdoDeleted = 1U; - } - /* delete also pending synchronous TPDOs in TX buffers */ - if(CANmodule->CANtxCount != 0U){ - uint16_t i; - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - for(i = CANmodule->txSize; i > 0U; i--){ - if(buffer->bufferFull){ - if(buffer->syncFlag){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - tpdoDeleted = 2U; - } - } - buffer++; - } - } - CO_UNLOCK_CAN_SEND(); - - - if(tpdoDeleted != 0U){ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted); - } -} - - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - uint16_t rxErrors, txErrors, overflow; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - uint32_t err; - - /* get error counters from module. Id possible, function may use different way to - * determine errors. */ - rxErrors = CANport->rderror(); - txErrors = CANport->tderror(); - overflow = (MBED_CAN_REG->GSR & 0x2); - - err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; - - if(CANmodule->errOld != err){ - CANmodule->errOld = err; - - if(txErrors >= 256U){ /* bus off */ - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - } - else{ /* not bus off */ - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - - if((rxErrors >= 96U) || (txErrors >= 96U)){ /* bus warning */ - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - - if(rxErrors >= 128U){ /* RX bus passive */ - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err); - } - - if(txErrors >= 128U){ /* TX bus passive */ - if(!CANmodule->firstCANtxMessage){ - CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - } - else{ - bool_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE); - if(isError){ - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - - if((rxErrors < 96U) && (txErrors < 96U)){ /* no error */ - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - } - } - - if(overflow != 0U){ /* CAN RX bus overflow */ - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - } - } -} - - -/******************************************************************************/ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ - uint16_t intStatus; - - intStatus = MBED_CAN_REG->ICR; - - /* receive interrupt */ - if (intStatus & 0x1) { - CO_CANrxMsg_t rcvMsgBuf; /* buffer for the received message in CAN module */ - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint32_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - CANMessage msg; - - CANport->read(msg); - fromCANMessage(&msg, &rcvMsgBuf); /* get message from module here */ - rcvMsg = &rcvMsgBuf; - rcvMsgIdent = rcvMsg->ident; - if(CANmodule->useCANrxFilters){ - /* CAN module filters are used. Message with known 11-bit identifier has */ - /* been received */ - index = 0; /* get index of the received message here. Or something similar */ - if(index < CANmodule->rxSize){ - buffer = &CANmodule->rxArray[index]; - /* verify also RTR */ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - } - } - } - else{ - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - break; - } - buffer++; - } - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){ - buffer->pFunct(buffer->object, rcvMsg); - } - - /* Clear interrupt flag */ - /* The interrupt flag is cleaned by CANport.read() function call */ - } - - - /* transmit interrupt */ - else if ((intStatus & 0x2) || (intStatus & 0x200) || (intStatus & 0x400)) { - /* Clear interrupt flag */ - - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = false; - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = false; - /* Are there any new messages waiting to be send */ - if(CANmodule->CANtxCount > 0U){ - uint16_t i; /* index of transmitting message */ - - /* first buffer */ - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0U; i--){ - /* if message buffer is full, send it. */ - if(buffer->bufferFull){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - /* canSend... */ - CANport->write(toCANMessage(buffer)); - break; /* exit for loop */ - } - buffer++; - }/* end of for loop */ - - /* Clear counter if no more messages */ - if(i == 0U){ - CANmodule->CANtxCount = 0U; - } - } - } -} diff --git a/stack/LPC1768/CO_driver.h b/stack/LPC1768/CO_driver.h deleted file mode 100644 index 9f4aac9a..00000000 --- a/stack/LPC1768/CO_driver.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * CAN module object for LPC1768 microcontroller using Mbed SDK. - * - * @file CO_driver.h - * @ingroup CO_driver - * @author Benoit Rapidel - * @copyright 2016 Benoit Rapidel - * - * 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 - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ -#include /* for 'true', 'false' */ - - -/* CAN module base address */ -#define MBED_CAN 1 - - -/* Critical sections */ - #define CO_LOCK_CAN_SEND() - #define CO_UNLOCK_CAN_SEND() - - #define CO_LOCK_EMCY() - #define CO_UNLOCK_EMCY() - - #define CO_LOCK_OD() - #define CO_UNLOCK_OD() - - -/* Data types */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. */ -typedef struct{ - uint32_t ident; - uint8_t DLC ; - uint8_t data[8]; -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint32_t ident; - uint8_t DLC ; - uint8_t data[8]; - volatile bool_t bufferFull; - volatile bool_t syncFlag; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - void *CANdriverState; - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; -}CO_CANmodule_t; - - -/* Endianes */ -#define CO_LITTLE_ENDIAN - - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. */ -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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* Receives and transmits CAN messages. */ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule); - - -#endif diff --git a/stack/LPC177x_8x/CANOpenTask.c b/stack/LPC177x_8x/CANOpenTask.c deleted file mode 100644 index 6c8a3555..00000000 --- a/stack/LPC177x_8x/CANOpenTask.c +++ /dev/null @@ -1,211 +0,0 @@ -/*--------------------------------------------------------------*/ -/* GENESYS ELECTRONICS DESIGN PTY LTD */ -/*--------------------------------------------------------------*/ -/* */ -/* FILE NAME : CANOpenTask.h */ -/* */ -/* REVISION NUMBER: 1.0 */ -/* */ -/* PURPOSE : This is the implementation of the CANOpen main task*/ -/* */ -/* */ -/*--------------------------------------------------------------*/ -/* */ -/* AUTHOR: */ -/* Harshah Sagar */ -/* GENESYS ELECTRONICS DESIGN Pty Ltd */ -/* Unit 5/33 Ryde Road */ -/* Pymble NSW 2073 */ -/* Australia. */ -/* Telephone # 61-02-9496 8900 */ -/*--------------------------------------------------------------*/ -/* Revision Number : */ -/* Revision By : Amit Hergass */ -/* Date : 30-Jun-2014 */ -/* Description : Original Issue */ -/* */ -/* !--------------------------------------------------------! */ -/* ! Revisions to be entered in reverse chronological order ! */ -/* !--------------------------------------------------------! */ -/* */ -/*--------------------------------------------------------------*/ - -#include "FreeRTOS.h" -#include "task.h" - -#include "board.h" -#include "Watchdog.h" -#include "CANopen.h" -#include "application.h" -#include "CANOpenTask.h" - -/* Global variables and objects */ -volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */ -static bool canStackEnabled = true; -void CO_TimerProcess(void); - -#ifdef TASK_WATCHDOG_ENABLED -static hWatchdog CanOpenWdHandler; -#endif -/* main ***********************************************************************/ -void CANOpenTask ( void *pvParameters ) -{ - CO_NMT_reset_cmd_t reset = CO_RESET_NOT; - - /* Configure microcontroller. */ -#ifdef TASK_WATCHDOG_ENABLED - /* wait number of the task iteration delay time (#seconds until WD expires * (1000ms/WD task frequency)) - Give the task 20 seconds to recover*/ - CanOpenWdHandler = watchogTaskRegister( "CANOpen", (20 * (1000 / WATCHDOG_TASK_FREQUENCY_MS))); -#endif - while(true) - { - reset = CO_RESET_NOT; - /* TODO: initialize EEPROM */ - - /* Todo: Loading COD */ - DEBUGOUT("CANOpenTask() Loading COD\n\r"); - - /* Verify, if OD structures have proper alignment of initial values */ - DEBUGOUT("Checking COD in RAM (size=%d)\n\r", &CO_OD_RAM.LastWord - &CO_OD_RAM.FirstWord); - if (CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) - DEBUGOUT("Err COD in RAM\n\r"); - DEBUGOUT("Checking COD in EEPROM (size=%d)\n\r", &CO_OD_EEPROM.LastWord - &CO_OD_EEPROM.FirstWord); - if (CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) - DEBUGOUT("Err COD in EEPROM\n\r"); - DEBUGOUT("Checking COD in ROM (size=%d)\n\r", &CO_OD_ROM.LastWord - &CO_OD_ROM.FirstWord); - if (CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) - DEBUGOUT("Err COD in ROM\n\r"); - - /* Application interface */ - programStart(); - - - /* increase variable each startup. Variable is stored in EEPROM. */ - OD_powerOnCounter++; - - - DEBUGOUT("CO power-on (BTR=%dk Node=0x%x)\n\r", CO_OD_ROM.CANBitRate, CO_OD_ROM.CANNodeID); - - while((reset != CO_RESET_APP)&& (true == canStackEnabled)){ - /* CANopen communication reset - initialize CANopen objects *******************/ - CO_ReturnError_t err; - uint16_t timer1msPrevious=0; - - /* disable timer and CAN interrupts */ - NVIC_DisableIRQ(CAN_IRQn); - - /* initialize CANopen */ - err = CO_init(); - if(err != CO_ERROR_NO){ - DEBUGOUT("CANOpenTask CO_init() Failed!!!\n\r"); - CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); - while(1) - { - vTaskDelay(1); - }; - } - /* initialize variables */ - timer1msPrevious = CO_timer1ms; - reset = CO_RESET_NOT; - - /* Application interface */ - communicationReset(); - - /* start CAN and enable interrupts */ - CO_CANsetNormalMode(ADDR_CAN1); - - - while((reset == CO_RESET_NOT) && (true == canStackEnabled)){ - /* loop for normal program execution ******************************************/ - uint16_t timer1msDiff; - - CO_DISABLE_INTERRUPTS(); - /*execution every 1 millisecond */ - timer1msDiff = CO_timer1ms - timer1msPrevious; - if(0 < timer1msDiff) - { - CO_TimerProcess(); - } - else - { - vTaskDelay(1); - } - timer1msPrevious = CO_timer1ms; - CO_ENABLE_INTERRUPTS(); - - /* Application interface */ - programAsync(timer1msDiff); - - /* CANopen process */ - reset = CO_process(CO, timer1msDiff); - /* Process EEPROM */ - -#ifdef TASK_WATCHDOG_ENABLED - watchogTaskFeed(CanOpenWdHandler); -#endif - } - } - - DEBUGOUT("CANOpenTask Terminated reset= %d ,canStackEnabled= %d !!!\n\r", reset,canStackEnabled); - - /* program exit ***************************************************************/ - - /* Application interface */ - programEnd(); - - /* delete objects from memory */ - CO_delete(); - } - - //Exit the task - vTaskDelete( NULL ); - -} - - -/* timer interrupt every millisecond ************************/ -/*void vApplicationTickHook(void) since the tick is 1ms we can use the FreeRTOS tick hook*/ -void /* interrupt */ CO_TimerInterruptHandler(void){ - - /* clear interrupt flag */ - CO_timer1ms++; -} - -/* function executes every millisecond ************************/ -void CO_TimerProcess(void){ - - CO_process_RPDO(CO); - - /* Application interface */ - program1ms(); - - CO_process_TPDO(CO); - - /* verify timer overflow (is flag set again?) */ - if(0){ - CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0U); - } -} - - -/* CAN interrupt function *****************************************************/ -void /* interrupt */ CAN_IRQHandler(void){ /* CO_CAN1InterruptHandler(void){*/ - CO_CANinterrupt(CO->CANmodule[0]); - /* clear interrupt flag */ -} - -/* CAN_StackEnable() CAN Task Enable/Disable *****************************************************/ -/*enableSwitch: true- Task enables, false- Task disabled */ -void CAN_StackEnable(bool enableSwitch){ - /* CAN Task can only be terminated, not restarted at this stage*/ - if(canStackEnabled) - { - canStackEnabled = enableSwitch; - } -} -/* CAN_GetStackEnable *****************************************************/ -/*Return: true- Task enables, false- Task disabled */ -bool CAN_GetStackEnable(void){ - return canStackEnabled; -} diff --git a/stack/LPC177x_8x/CANOpenTask.h b/stack/LPC177x_8x/CANOpenTask.h deleted file mode 100644 index 028c364b..00000000 --- a/stack/LPC177x_8x/CANOpenTask.h +++ /dev/null @@ -1,36 +0,0 @@ -/*--------------------------------------------------------------*/ -/* GENESYS ELECTRONICS DESIGN PTY LTD */ -/*--------------------------------------------------------------*/ -/* */ -/* FILE NAME : CANOpenTask.h */ -/* */ -/* REVISION NUMBER: 1.0 */ -/* */ -/* PURPOSE : This is the implementation of the CANOpen main task*/ -/* */ -/* */ -/*--------------------------------------------------------------*/ -/* */ -/* AUTHOR: */ -/* Harshah Sagar */ -/* GENESYS ELECTRONICS DESIGN Pty Ltd */ -/* Unit 5/33 Ryde Road */ -/* Pymble NSW 2073 */ -/* Australia. */ -/* Telephone # 61-02-9496 8900 */ -/*--------------------------------------------------------------*/ -/* Revision Number : */ -/* Revision By : Amit Hergass */ -/* Date : 30-Jun-2014 */ -/* Description : Original Issue */ -/* */ -/* !--------------------------------------------------------! */ -/* ! Revisions to be entered in reverse chronological order ! */ -/* !--------------------------------------------------------! */ -/* */ -/*--------------------------------------------------------------*/ - -void CANOpenTask ( void *pvParameters ); -void CAN_StackEnable(bool enableSwitch); -bool CAN_GetStackEnable(void); - diff --git a/stack/LPC177x_8x/CO_driver.c b/stack/LPC177x_8x/CO_driver.c deleted file mode 100644 index 83e09bba..00000000 --- a/stack/LPC177x_8x/CO_driver.c +++ /dev/null @@ -1,842 +0,0 @@ -/* - * CAN module object for NXP LPC177x (Cortex M3) and FreeRTOS. - * - * This file is a template for other microcontrollers. - * - * @file CO_driver.c - * @ingroup CO_driver - * @author Janez Paternoster - * @author Amit H - * @copyright 2004 - 2014 Janez Paternoster - * - * 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. - */ -/*Kernel Includes. ----------------------------------------------------------*/ -#include "FreeRTOS.h" -#include "task.h" - -#include "board.h" - -#include "CO_driver.h" -#include "CO_Emergency.h" -#include "IMAXEON_Config.h" - -#include "CO_OD.h" -/***************************************************************************** - * Private types/enumerations/variables - ****************************************************************************/ - -#define CAN_CTRL_NO 1 - -#if (CAN_CTRL_NO == 0) -#define LPC_CAN (LPC_CAN1) -#else -#define LPC_CAN (LPC_CAN2) -#endif - -#define AF_LUT_USED 1 -#if AF_LUT_USED -#define FULL_CAN_AF_USED 0 -#define REMOVE_CAN_AF_ENTRIES 0 -#endif - -#define CAN_TX_MSG_STD_ID (0x200) -#define CAN_TX_MSG_REMOTE_STD_ID (0x300) -#define CAN_TX_MSG_EXT_ID (0x10000200) -#define CAN_RX_MSG_ID (0x100) - -/***************************************************************************** - * Public types/enumerations/variables - ****************************************************************************/ - -#if AF_LUT_USED -#if FULL_CAN_AF_USED -CAN_STD_ID_ENTRY_T FullCANSection[] = { - {CAN_CTRL_NO, 0, 0x03}, - {CAN_CTRL_NO, 0, 0x05}, - {CAN_CTRL_NO, 0, 0x07}, - {CAN_CTRL_NO, 0, 0x09}, -}; -#endif -CAN_STD_ID_ENTRY_T SFFSection[] = { - {CAN_CTRL_NO, 0, 0x00}, - {CAN_CTRL_NO, 0, 0x01}, - {CAN_CTRL_NO, 0, 0x02}, - {CAN_CTRL_NO, 0, 0x08}, - {CAN_CTRL_NO, 0, 0x10}, - {CAN_CTRL_NO, 0, 0x30}, - {CAN_CTRL_NO, 0, 0x50}, - {CAN_CTRL_NO, 0, 0x70}, - {CAN_CTRL_NO, 0, 0x90}, - {CAN_CTRL_NO, 0, 0xB0}, -}; -CAN_STD_ID_RANGE_ENTRY_T SffGrpSection[] = { - {{CAN_CTRL_NO, 0, 0x100}, {CAN_CTRL_NO, 0, 0x400}}, - {{CAN_CTRL_NO, 0, 0x500}, {CAN_CTRL_NO, 0, 0x6FF}}, - {{CAN_CTRL_NO, 0, 0x700}, {CAN_CTRL_NO, 0, 0x780}}, -}; -CAN_EXT_ID_ENTRY_T EFFSection[] = { - {CAN_CTRL_NO, ((1 << 11) | 0x03)}, - {CAN_CTRL_NO, ((1 << 11) | 0x05)}, - {CAN_CTRL_NO, ((1 << 11) | 0x07)}, - {CAN_CTRL_NO, ((1 << 11) | 0x09)}, -}; -CAN_EXT_ID_RANGE_ENTRY_T EffGrpSection[] = { - {{CAN_CTRL_NO, ((1 << 11) | 0x300)}, {CAN_CTRL_NO, ((1 << 11) | 0x400)}}, - {{CAN_CTRL_NO, ((1 << 11) | 0x500)}, {CAN_CTRL_NO, ((1 << 11) | 0x6FF)}}, - {{CAN_CTRL_NO, ((1 << 11) | 0x700)}, {CAN_CTRL_NO, ((1 << 11) | 0x780)}}, -}; -CANAF_LUT_T AFSections = { -#if FULL_CAN_AF_USED - FullCANSection, sizeof(FullCANSection) / sizeof(CAN_STD_ID_ENTRY_T), -#else - NULL, 0, -#endif - SFFSection, sizeof(SFFSection) / sizeof(CAN_STD_ID_ENTRY_T), - SffGrpSection, sizeof(SffGrpSection) / sizeof(CAN_STD_ID_RANGE_ENTRY_T), - EFFSection, sizeof(EFFSection) / sizeof(CAN_EXT_ID_ENTRY_T), - EffGrpSection, sizeof(EffGrpSection) / sizeof(CAN_EXT_ID_RANGE_ENTRY_T), -}; -#endif /*AF_LUT_USED*/ - -/***************************************************************************** - * Private functions - ****************************************************************************/ -static void PrintCANErrorInfo(uint32_t Status); -static void PrintCANMsg(CAN_MSG_T *pMsg); -static void PrintAFLUT(void); -static void SetupAFLUT(void); -/* Insert/Remove entries to/from AF LUT */ -static void ChangeAFLUT(void); - -/******************************************************************************/ -void CO_CANrxMsgHandler(void *object, const CO_CANrxMsg_t *message){ - - DEBUGOUT("CO_CANrxMsgHandler Default Rx handler called \r\n"); -/* PrintCANMsg((CAN_MSG_T*)message); */ -} - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - - Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_NORMAL_MODE); - - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - uint16_t i; - uint8_t nodeId=0; - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->CANdriverState = CANdriverState; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; -#if AF_LUT_USED - CANmodule->useCANrxFilters = (rxSize <= 32U) ? true : false;/* microcontroller dependent */ -#else - CANmodule->useCANrxFilters = false; -#endif - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - CANmodule->em = NULL; - - - DEBUGOUT("CO_CANmodule_init Baud: %d\r\n",(CANbitRate * 1000)); - - for(i=0U; iuseCANrxFilters){ - DEBUGOUT("\tCAN Rx Acceptance Filters ON \r\n"); -#if AF_LUT_USED - /* CAN module filters are used, they will be configured with */ - /* CO_CANrxBufferInit() functions, called by separate CANopen */ - /* init functions. */ - /* Configure all masks so, that received message must match filter */ - SetupAFLUT(); - /*ChangeAFLUT();*/ - /* print the configured LUT*/ - PrintAFLUT(); -#if FULL_CAN_AF_USED - Chip_CAN_ConfigFullCANInt(LPC_CANAF, ENABLE); - Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_FULL_MODE); -#else - Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_NORMAL_MODE); -#endif /*FULL_CAN_AF_USED*/ - -#else - DEBUGOUT("\tCAN Rx Acceptance Filters NOT OPERATIONAL for the debug stages\r\n"); - Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_BYBASS_MODE); -#endif - } - else - { - /* CAN module filters are not used, all messages with standard 11-bit */ - /* identifier will be received */ - /* Configure mask 0 so, that all messages with standard identifier are accepted */ - Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_BYBASS_MODE); - - DEBUGOUT("\tCAN Rx Acceptance Filters Bypass \r\n"); - } - /* configure CAN interrupt registers */ - NVIC_EnableIRQ(CAN_IRQn); - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){ - /* turn off the module */ - NVIC_DisableIRQ(CAN_IRQn); -} - - -/******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){ - return (uint16_t) rxMsg->ident; -} - -/******************************************************************************/ -uint16_t CO_CAN_Get_My_NodeID(void){ - - uint16_t myNodeId=0; - - myNodeId = Chip_GPIO_ReadPortBit(LPC_GPIO, CAN_NODE_ID_0_PORT, CAN_NODE_ID_0_PIN); - - return myNodeId; -} -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){ - /* buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - - /* Configure object variables */ - buffer->object = object; - buffer->pFunct = pFunct; - - /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */ - buffer->ident = ident & 0x07FFU; - if(rtr){ - buffer->ident |= 0x0800U; - } - buffer->mask = (mask & 0x07FFU) | 0x0800U; - - } - else{ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer. - * Microcontroller specific. */ - buffer->ident = ((uint32_t)ident & 0x07FFU); - buffer->DLC = ((uint32_t)noOfBytes); - buffer->Type = ((uint32_t)(rtr ? (CAN_REMOTE_MSG) : 0U)); - - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } - - return buffer; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ - CO_ReturnError_t err = CO_ERROR_NO; - CAN_BUFFER_ID_T TxBuf; - - /* Verify overflow */ - if(buffer->bufferFull){ - if(!CANmodule->firstCANtxMessage){ - /* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, buffer->ident); - } - err = CO_ERROR_TX_OVERFLOW; - } - - CO_LOCK_CAN_SEND(); - - /* if CAN TX buffer is free, copy message to it */ - TxBuf = Chip_CAN_GetFreeTxBuf(LPC_CAN); - if( TxBuf < CAN_BUFFER_LAST && CANmodule->CANtxCount == 0){ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - /* copy message and txRequest */ - Chip_CAN_Send(LPC_CAN, TxBuf,(CAN_MSG_T*)buffer); - - /*DEBUGOUT("CO_CANsend!!!\r\n");*/ - /*PrintCANMsg((CAN_MSG_T*)buffer);*/ - } - /* if no buffer is free, message will be sent by interrupt */ - else - { - DEBUGOUT("CO_CANsend buffer Full!!!\r\n"); - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - CO_UNLOCK_CAN_SEND(); - - return err; -} - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ - uint32_t tpdoDeleted = 0U; - - CO_LOCK_CAN_SEND(); - - /* Abort message from CAN module, if there is synchronous TPDO. - * Take special care with this functionality. */ - /*Check if any of the buffer is pending transmition and bufferInhibitFlag is true*/ - if(( 0 == (Chip_CAN_GetGlobalStatus(LPC_CAN) & CAN_GSR_TBS)) && CANmodule->bufferInhibitFlag){ - - /* if not already in progress, a pending Transmission Request for - the selected Transmit Buffer is cancelled. */ - Chip_CAN_SetCmd(LPC_CAN, CAN_CMR_STB(CAN_BUFFER_1) | CAN_CMR_AT); - Chip_CAN_SetCmd(LPC_CAN, CAN_CMR_STB(CAN_BUFFER_2) | CAN_CMR_AT); - Chip_CAN_SetCmd(LPC_CAN, CAN_CMR_STB(CAN_BUFFER_3) | CAN_CMR_AT); - - /* clear TXREQ */ - CANmodule->bufferInhibitFlag = false; - tpdoDeleted = 1U; - } - /* delete also pending synchronous TPDOs in TX buffers */ - if(CANmodule->CANtxCount != 0U){ - uint16_t i; - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - for(i = CANmodule->txSize; i > 0U; i--){ - if(buffer->bufferFull){ - if(buffer->syncFlag){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - tpdoDeleted = 2U; - } - } - buffer++; - } - } - CO_UNLOCK_CAN_SEND(); - - - if(tpdoDeleted != 0U){ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted); - } -} - - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - uint16_t rxErrors, txErrors, overflow; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - uint32_t err; - - /* get error counters from module. Id possible, function may use different way to - * determine errors. */ - rxErrors = CAN_GSR_RXERR(Chip_CAN_GetGlobalStatus(LPC_CAN)); - txErrors = CAN_GSR_TXERR(Chip_CAN_GetGlobalStatus(LPC_CAN)); - overflow = (Chip_CAN_GetGlobalStatus(LPC_CAN) & CAN_GSR_DOS) ; /*CAN Data Overrun Status */ CANmodule->txSize; - - err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; - - if(CANmodule->errOld != err){ - CANmodule->errOld = err; - - if(txErrors >= 256U){ /* bus off */ - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - } - else{ /* not bus off */ - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - - if((rxErrors >= 96U) || (txErrors >= 96U)){ /* bus warning */ - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - - if(rxErrors >= 128U){ /* RX bus passive */ - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err); - } - - if(txErrors >= 128U){ /* TX bus passive */ - if(!CANmodule->firstCANtxMessage){ - CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - } - else{ - bool_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE); - if(isError){ - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - - if((rxErrors < 96U) && (txErrors < 96U)){ /* no error */ - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - } - } - - if(overflow != 0U){ /* CAN RX bus overflow */ - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - } - } -} - - -/******************************************************************************/ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ - - uint32_t IntStatus; - CO_CANrxMsg_t RcvMsgBuf; - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint32_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - CAN_BUFFER_ID_T TxBuf; - - /*Read the int status register */ - IntStatus = Chip_CAN_GetIntStatus(LPC_CAN); - - - /* receive interrupt */ - if(IntStatus & CAN_ICR_RI){ - - /* get message from module */ - Chip_CAN_Receive(LPC_CAN,(CAN_MSG_T*)&RcvMsgBuf); - rcvMsg = &RcvMsgBuf; - rcvMsgIdent = rcvMsg->ident; - -#if AF_LUT_USED /*Implement once AF will be used*/ - if(CANmodule->useCANrxFilters){ - - /* Since the HW not providing the filter index, ignore this code and run through the rxArray to find a match.*/ - /* Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - break; - } - buffer++; - } - } - else -#endif - { - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - break; - } - buffer++; - } - - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){ - - buffer->pFunct(buffer->object, rcvMsg); - } - else - { - DEBUGOUT("Unsupported Message Received!!!\r\n"); - PrintCANMsg((CAN_MSG_T*)rcvMsg); - } - - /* Clear interrupt flag */ - /*Giving the Command “Release Receive Buffer” will clear RI. done in Chip_CAN_Receive()*/ - } - /* transmit interrupt */ - else if((IntStatus & CAN_ICR_TI1)||(IntStatus & CAN_ICR_TI2)||(IntStatus & CAN_ICR_TI3)){ - /* Clear interrupt flag */ - - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = false; - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = false; - /* Are there any new messages waiting to be send */ - if(CANmodule->CANtxCount > 0U){ - uint16_t i; /* index of transmitting message */ - - /* first buffer */ - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0U; i--){ - /* if message buffer is full, send it. */ - if(buffer->bufferFull){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - /* canSend... */ - /* if CAN TX buffer is free, copy message to it */ - TxBuf = Chip_CAN_GetFreeTxBuf(LPC_CAN); - if( TxBuf < CAN_BUFFER_LAST){ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - /* copy message and txRequest */ - Chip_CAN_Send(LPC_CAN, TxBuf,(CAN_MSG_T*)buffer); - } - break; /* exit for loop */ - } - buffer++; - }/* end of for loop */ - - /* Clear counter if no more messages */ - if(i == 0U){ - CANmodule->CANtxCount = 0U; - } - } - } - else{ - /* some other interrupt reason */ - } -} - -/***************************************************************************** - * Private functions - ****************************************************************************/ -/* Print error */ -static void PrintCANErrorInfo(uint32_t Status) -{ - if (Status & CAN_ICR_EI) { - DEBUGOUT("Error Warning!\r\n"); - } - if (Status & CAN_ICR_DOI) { - DEBUGOUT("Data Overrun!\r\n"); - } - if (Status & CAN_ICR_EPI) { - DEBUGOUT("Error Passive!\r\n"); - } - if (Status & CAN_ICR_ALI) { - DEBUGOUT("Arbitration lost in the bit: %d(th)\r\n", CAN_ICR_ALCBIT_VAL(Status)); - } - if (Status & CAN_ICR_BEI) { - - DEBUGOUT("CAN Bus error !!!\r\n"); - - if (Status & CAN_ICR_ERRDIR_RECEIVE) { - DEBUGOUT("\t Error Direction: Transmiting\r\n"); - } - else { - DEBUGOUT("\t Error Direction: Receiving\r\n"); - } - - DEBUGOUT("\t Error Location: 0x%2x\r\n", CAN_ICR_ERRBIT_VAL(Status)); - DEBUGOUT("\t Error Type: 0x%1x\r\n", CAN_ICR_ERRC_VAL(Status)); - } -} - -/* Print CAN Message */ -static void PrintCANMsg(CAN_MSG_T *pMsg) -{ - uint8_t i; - DEBUGOUT("\t**************************\r\n"); - DEBUGOUT("\tMessage Information: \r\n"); - DEBUGOUT("\tMessage Type: "); - if (pMsg->ID & CAN_EXTEND_ID_USAGE) { - DEBUGOUT(" Extend ID Message"); - } - else { - DEBUGOUT(" Standard ID Message"); - } - if (pMsg->Type & CAN_REMOTE_MSG) { - DEBUGOUT(", Remote Message"); - } - DEBUGOUT("\r\n"); - DEBUGOUT("\tMessage ID :0x%x\r\n", (pMsg->ID & (~CAN_EXTEND_ID_USAGE))); - DEBUGOUT("\tMessage Data :"); - for (i = 0; i < pMsg->DLC; i++) - DEBUGOUT("%x ", pMsg->Data[i]); - DEBUGOUT("\r\n\t**************************\r\n"); -} - -#if AF_LUT_USED -/* Print entries in AF LUT */ -static void PrintAFLUT(void) -{ - uint16_t i, num; - CAN_STD_ID_ENTRY_T StdEntry; - CAN_EXT_ID_ENTRY_T ExtEntry; - CAN_STD_ID_RANGE_ENTRY_T StdGrpEntry; - CAN_EXT_ID_RANGE_ENTRY_T ExtGrpEntry; - - DEBUGOUT("Print AF LUT... \r\n"); -#if FULL_CAN_AF_USED - /* Full CAN Table */ - DEBUGOUT("\tFULL CAN Table: \r\n"); - num = Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_FULLCAN_SEC); - for (i = 0; i < num; i++) { - Chip_CAN_ReadFullCANEntry(LPC_CANAF, LPC_CANAF_RAM, i, &StdEntry); - DEBUGOUT("\t\t%d: Controller ID: %d, ID: 0x%x, Dis: %1d\r\n", - i, StdEntry.CtrlNo, StdEntry.ID_11, StdEntry.Disable); - } -#endif - /* Standard ID Table */ - DEBUGOUT("\tIndividual Standard ID Table: \r\n"); - num = Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_SFF_SEC); - for (i = 0; i < num; i++) { - Chip_CAN_ReadSTDEntry(LPC_CANAF, LPC_CANAF_RAM, i, &StdEntry); - DEBUGOUT("\t\t%d: Controller ID: %d, ID: 0x%x, Dis: %1d\r\n", - i, StdEntry.CtrlNo, StdEntry.ID_11, StdEntry.Disable); - } - /* Group Standard ID Table */ - DEBUGOUT("\tGroup Standard ID Table: \r\n"); - num = Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_SFF_GRP_SEC); - for (i = 0; i < num; i++) { - Chip_CAN_ReadGroupSTDEntry(LPC_CANAF, LPC_CANAF_RAM, i, &StdGrpEntry); - DEBUGOUT("\t\t%d: Controller ID: %d, ID: 0x%x-0x%x, Dis: %1d\r\n", - i, StdGrpEntry.LowerID.CtrlNo, StdGrpEntry.LowerID.ID_11, - StdGrpEntry.UpperID.ID_11, StdGrpEntry.LowerID.Disable); - } - /* Extended ID Table */ - DEBUGOUT("\tExtended ID Table: \r\n"); - num = Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_EFF_SEC); - for (i = 0; i < num; i++) { - Chip_CAN_ReadEXTEntry(LPC_CANAF, LPC_CANAF_RAM, i, &ExtEntry); - DEBUGOUT("\t\t%d: Controller ID: %d, ID: 0x%x,\r\n", - i, ExtEntry.CtrlNo, ExtEntry.ID_29); - } - /* Group Extended ID Table */ - DEBUGOUT("\tGroup Extended ID Table: \r\n"); - num = Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_EFF_GRP_SEC); - for (i = 0; i < num; i++) { - Chip_CAN_ReadGroupEXTEntry(LPC_CANAF, LPC_CANAF_RAM, i, &ExtGrpEntry); - DEBUGOUT("\t\t%d: Controller ID: %d, ID: 0x%x-0x%x\r\n", - i, ExtGrpEntry.LowerID.CtrlNo, ExtGrpEntry.LowerID.ID_29, - ExtGrpEntry.UpperID.ID_29); - } - -} - -/* Setup AF LUT */ -static void SetupAFLUT(void) -{ - DEBUGOUT("Setup AF LUT... \r\n"); - Chip_CAN_SetAFLUT(LPC_CANAF, LPC_CANAF_RAM, &AFSections); -/* PrintAFLUT();*/ -} - -/* Insert/Remove entries to/from AF LUT */ -static void ChangeAFLUT(void) -{ -#if FULL_CAN_AF_USED - CAN_STD_ID_ENTRY_T FullEntry = {CAN_CTRL_NO, 0, 0x02}; -#endif - CAN_STD_ID_ENTRY_T StdEntry = {CAN_CTRL_NO, 0, 0xC0}; - CAN_EXT_ID_ENTRY_T ExtEntry = {CAN_CTRL_NO, ((1 << 11) | 0x0A)}; - CAN_STD_ID_RANGE_ENTRY_T StdGrpEntry = {{CAN_CTRL_NO, 0, 0x7A0}, {CAN_CTRL_NO, 0, 0x7B0}}; - CAN_EXT_ID_RANGE_ENTRY_T ExtGrpEntry = {{CAN_CTRL_NO, ((1 << 11) | 0x7A0)}, {CAN_CTRL_NO, ((1 << 11) | 0x7B0)}}; - - -#if FULL_CAN_AF_USED - /* Edit Full CAN Table */ - Chip_CAN_InsertFullCANEntry(LPC_CANAF, LPC_CANAF_RAM, &FullEntry); - FullEntry.ID_11 = 2; - Chip_CAN_InsertFullCANEntry(LPC_CANAF, LPC_CANAF_RAM, &FullEntry); - FullEntry.ID_11 = 4; - Chip_CAN_InsertFullCANEntry(LPC_CANAF, LPC_CANAF_RAM, &FullEntry); -#endif /*FULL_CAN_AF_USED*/ - - /* Edit Individual STD ID Table */ - Chip_CAN_InsertSTDEntry(LPC_CANAF, LPC_CANAF_RAM, &StdEntry); - StdEntry.ID_11 = 0x20; - Chip_CAN_InsertSTDEntry(LPC_CANAF, LPC_CANAF_RAM, &StdEntry); - StdEntry.ID_11 = 0x40; - Chip_CAN_InsertSTDEntry(LPC_CANAF, LPC_CANAF_RAM, &StdEntry); - - /* Edit Individual EXT ID Table */ - Chip_CAN_InsertEXTEntry(LPC_CANAF, LPC_CANAF_RAM, &ExtEntry); - ExtEntry.ID_29 = (1 << 11) | 0x02; - Chip_CAN_InsertEXTEntry(LPC_CANAF, LPC_CANAF_RAM, &ExtEntry); - ExtEntry.ID_29 = (1 << 11) | 0x04; - Chip_CAN_InsertEXTEntry(LPC_CANAF, LPC_CANAF_RAM, &ExtEntry); - - /* Edit STD ID Group Table */ - Chip_CAN_InsertGroupSTDEntry(LPC_CANAF, LPC_CANAF_RAM, &StdGrpEntry); - StdGrpEntry.LowerID.ID_11 = 0x200; - StdGrpEntry.UpperID.ID_11 = 0x300; - Chip_CAN_InsertGroupSTDEntry(LPC_CANAF, LPC_CANAF_RAM, &StdGrpEntry); - StdGrpEntry.LowerID.ID_11 = 0x400; - StdGrpEntry.UpperID.ID_11 = 0x500; - Chip_CAN_InsertGroupSTDEntry(LPC_CANAF, LPC_CANAF_RAM, &StdGrpEntry); - - /* Edit EXT ID Group Table */ - Chip_CAN_InsertGroupEXTEntry(LPC_CANAF, LPC_CANAF_RAM, &ExtGrpEntry); - ExtGrpEntry.LowerID.ID_29 = (1 << 11) | 0x200; - ExtGrpEntry.UpperID.ID_29 = (1 << 11) | 0x300; - Chip_CAN_InsertGroupEXTEntry(LPC_CANAF, LPC_CANAF_RAM, &ExtGrpEntry); - ExtGrpEntry.LowerID.ID_29 = (1 << 11) | 0x400; - ExtGrpEntry.UpperID.ID_29 = (1 << 11) | 0x500; - Chip_CAN_InsertGroupEXTEntry(LPC_CANAF, LPC_CANAF_RAM, &ExtGrpEntry); - - PrintAFLUT(); -#if REMOVE_CAN_AF_ENTRIES - DEBUGOUT("Remove entries into the current LUT... \r\n"); - /* Remove entries from the current LUT */ -#if FULL_CAN_AF_USED - Chip_CAN_RemoveFullCANEntry(LPC_CANAF, LPC_CANAF_RAM, 0); - Chip_CAN_RemoveFullCANEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_FULLCAN_SEC) - 1); - Chip_CAN_RemoveFullCANEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_FULLCAN_SEC) / 2); -#endif - Chip_CAN_RemoveSTDEntry(LPC_CANAF, LPC_CANAF_RAM, 0); - Chip_CAN_RemoveSTDEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_SFF_SEC) - 1); - Chip_CAN_RemoveSTDEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_SFF_SEC) / 2); - Chip_CAN_RemoveGroupSTDEntry(LPC_CANAF, LPC_CANAF_RAM, 0); - Chip_CAN_RemoveGroupSTDEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_SFF_GRP_SEC) - 1); - Chip_CAN_RemoveGroupSTDEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_SFF_GRP_SEC) / 2); - Chip_CAN_RemoveEXTEntry(LPC_CANAF, LPC_CANAF_RAM, 0); - Chip_CAN_RemoveEXTEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_EFF_SEC) - 1); - Chip_CAN_RemoveEXTEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_EFF_SEC) / 2); - Chip_CAN_RemoveGroupEXTEntry(LPC_CANAF, LPC_CANAF_RAM, 0); - Chip_CAN_RemoveGroupEXTEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_EFF_GRP_SEC) - 1); - Chip_CAN_RemoveGroupEXTEntry(LPC_CANAF, LPC_CANAF_RAM, Chip_CAN_GetEntriesNum(LPC_CANAF, LPC_CANAF_RAM, CANAF_RAM_EFF_GRP_SEC) / 2); - PrintAFLUT(); -#endif -} - -#endif diff --git a/stack/LPC177x_8x/CO_driver.h b/stack/LPC177x_8x/CO_driver.h deleted file mode 100644 index 23d8ced5..00000000 --- a/stack/LPC177x_8x/CO_driver.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * CAN module object for NXP LPC177x (Cortex M3) and FreeRTOS. - * - * This file is a template for other microcontrollers. - * - * @file CO_driver.h - * @author Janez Paternoster - * @author Amit H - * @copyright 2004 - 2014 Janez Paternoster - * - * 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 - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -#include "FreeRTOS.h" -#include "task.h" -#include "board.h" -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ - - -/* CAN module base address */ - #define ADDR_CAN1 0 - #define ADDR_CAN2 1 - - - #define CAN_NODE_ID_0_PORT 1 - #define CAN_NODE_ID_0_PIN 23 - #define CAN_NODE_ID_1_PORT 1 - #define CAN_NODE_ID_1_PIN 24 - #define CAN_NODE_ID_2_PORT 1 - #define CAN_NODE_ID_2_PIN 25 - #define CAN_NODE_ID_3_PORT 1 - #define CAN_NODE_ID_3_PIN 26 - #define CAN_NODE_ID_4_PORT 1 - #define CAN_NODE_ID_4_PIN 28 - - #define CAN_RUN_LED_PORT 1 - #define CAN_RUN_LED_PIN 20 - - -/* Critical sections */ - #define CO_LOCK_CAN_SEND() taskENTER_CRITICAL() - #define CO_UNLOCK_CAN_SEND() taskEXIT_CRITICAL() - - #define CO_LOCK_EMCY() taskENTER_CRITICAL() - #define CO_UNLOCK_EMCY() taskEXIT_CRITICAL() - - #define CO_LOCK_OD() taskENTER_CRITICAL() - #define CO_UNLOCK_OD() taskEXIT_CRITICAL() - - -/* Data types */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. */ -typedef struct{ - /** CAN identifier. It must be read through CO_CANrxMsg_readIdent() function. */ - uint32_t ident; /*!< Message Identifier. If 30th-bit is set, this is 29-bit ID, othewise 11-bit ID */ - uint32_t Type; /*!< Message Type. which can include: - CAN_REMOTE_MSG type*/ - uint32_t DLC; /*!< Message Data Length: 0~8 */ - uint8_t data[CAN_MSG_MAX_DATA_LEN];/*!< Message Data */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint32_t ident; /*!< Message Identifier. If 30th-bit is set, this is 29-bit ID, othewise 11-bit ID */ - uint32_t Type; /*!< Message Type. which can include: - CAN_REMOTE_MSG type*/ - uint32_t DLC; /*!< Message Data Length: 0~8 */ - uint8_t data[CAN_MSG_MAX_DATA_LEN];/*!< Message Data */ - volatile bool_t bufferFull; - volatile bool_t syncFlag; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - void *CANdriverState; - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; -}CO_CANmodule_t; - - -/* Endianes */ -#define CO_LITTLE_ENDIAN - - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. */ -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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* CAN interrupt receives and transmits CAN messages. */ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule); - - -#endif diff --git a/stack/LPC177x_8x/application.c b/stack/LPC177x_8x/application.c deleted file mode 100644 index f07a9335..00000000 --- a/stack/LPC177x_8x/application.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Header for application interface for CANopenNode stack. - * - * @file application.c - * @ingroup application - * @author Janez Paternoster - * @copyright 2012 - 2013 Janez Paternoster - * - * 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. - */ -/*System includes------------------------------------------------------------*/ -#include -#include -#include -#include -#include -#include -#include -/*Board includes-------------------------------------------------------------*/ -#include "board.h" - -/*App includes---------------------------------------------------------------*/ -#include "COMPSW.H" -#include "CANopen.h" - - -#define CAN_RUN_LED_ON() Chip_GPIO_WritePortBit(LPC_GPIO, CAN_RUN_LED_PORT, CAN_RUN_LED_PIN,false ) -#define CAN_RUN_LED_OFF() Chip_GPIO_WritePortBit(LPC_GPIO, CAN_RUN_LED_PORT, CAN_RUN_LED_PIN,true) -// No HW allocation for Error LED -#define CAN_ERROR_LED_ON() -#define CAN_ERROR_LED_OFF() - - -/*******************************************************************************/ -void programStart(void){ - - // turn OFF the LEDs - CAN_RUN_LED_OFF(); - CAN_ERROR_LED_OFF(); -} - - -/*******************************************************************************/ -void communicationReset(void){ - - // turn OFF the LEDs - CAN_RUN_LED_OFF(); - CAN_ERROR_LED_OFF(); -} - - -/*******************************************************************************/ -void programEnd(void){ - - // turn OFF the LEDs - CAN_RUN_LED_OFF(); - CAN_ERROR_LED_OFF(); -} - - -/*******************************************************************************/ -void programAsync(uint16_t timer1msDiff){ - - if(LED_GREEN_RUN(CO->NMT))CAN_RUN_LED_ON(); else CAN_RUN_LED_OFF(); - if(LED_RED_ERROR(CO->NMT))CAN_ERROR_LED_ON(); else CAN_ERROR_LED_OFF(); -} - - -/*******************************************************************************/ -void program1ms(void){ - -} diff --git a/stack/LPC177x_8x/application.h b/stack/LPC177x_8x/application.h deleted file mode 100644 index a8816e98..00000000 --- a/stack/LPC177x_8x/application.h +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Application interface for CANopenNode stack. - * - * @file application.h - * @ingroup CO_application - * @author Janez Paternoster - * @copyright 2012 - 2013 Janez Paternoster - * - * 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_APPLICATION_H -#define CO_APPLICATION_H - - -/** - * @defgroup CO_application Application interface - * @ingroup CO_CANopen - * @{ - * - * Application interface for CANopenNode stack. Function is called - * from file main_xxx.c (if implemented). - * - * ###Main program flow chart - * - * @code - (Program Start) - | - V - +------------------------------------+ - | programStart() | - +------------------------------------+ - | - |<-------------------------+ - | | - V | - (Initialze CANopen) | - | | - V | - +------------------------------------+ | - | communicationReset() | | - +------------------------------------+ | - | | - V | - (Enable CAN and interrupts) | - | | - |<----------------------+ | - | | | - V | | - +------------------------------------+ | | - | programAsync() | | | - +------------------------------------+ | | - | | | - V | | - (Process CANopen asynchronous) | | - | | | - +- infinite loop -------+ | - | | - +- reset communication ----+ - | - V - +------------------------------------+ - | programEnd() | - +------------------------------------+ - | - V - (delete CANopen) - | - V - (Program end) - @endcode - * - * - * ###Timer program flow chart - * - * @code - (Timer interrupt 1 millisecond) - | - V - (CANopen read RPDOs) - | - V - +------------------------------------+ - | program1ms() | - +------------------------------------+ - | - V - (CANopen write TPDOs) - @endcode - * - * - * ###Receive and transmit high priority interrupt flow chart - * - * @code - (CAN receive event or) - (CAN transmit buffer empty event) - | - V - (Process received CAN message or) - (copy next message to CAN transmit buffer) - @endcode - */ - - -/** - * Called after microcontroller reset. - */ -void programStart(void); - - -/** - * Called after communication reset. - */ -void communicationReset(void); - - -/** - * Called before program end. - */ -void programEnd(void); - - -/** - * Called cyclically from main. - * - * @param timer1msDiff Time difference since last call - */ -void programAsync(uint16_t timer1msDiff); - - -/** - * Called cyclically from 1ms timer task. - */ -void program1ms(void); - - -/** @} */ -#endif diff --git a/stack/LPC177x_8x/readme b/stack/LPC177x_8x/readme deleted file mode 100644 index 7cf38f43..00000000 --- a/stack/LPC177x_8x/readme +++ /dev/null @@ -1,4 +0,0 @@ -NXP LPC177x (Cortex M3) and FreeRTOS. - -Contributed by AmitH(sourceforge) (17.9.2014): -http://sourceforge.net/p/canopennode/discussion/387151/thread/d1b43992 diff --git a/stack/MCF5282/CO_driver.c b/stack/MCF5282/CO_driver.c deleted file mode 100644 index 158afec8..00000000 --- a/stack/MCF5282/CO_driver.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * CAN module object for Freescale MCF5282 ColdFire V2 microcontroller. - * - * @file CO_driver.c - * @author Janez Paternoster - * @author Laurent Grosbois - * @copyright 2004 - 2012 Janez Paternoster - * - * 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. - */ - - -#include "CO_driver.h" -#include "CO_Emergency.h" - - -extern const CO_CANbitRateData_t CO_CANbitRateData[8]; - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ - - /* sets the module as running */ - MCF_FlexCAN_CANMCR &= ~MCF_FlexCAN_CANMCR_STOP; - - /* enter debug mode */ - MCF_FlexCAN_CANMCR |= MCF_FlexCAN_CANMCR_FRZ | MCF_FlexCAN_CANMCR_HALT; - - /* wait for entering in the mode */ - while(!(MCF_FlexCAN_CANMCR&MCF_FlexCAN_CANMCR_FRZACK)){}; -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - /* sets the module as running & exit debug mode */ - MCF_FlexCAN_CANMCR &= ~MCF_FlexCAN_CANMCR_STOP & ~MCF_FlexCAN_CANMCR_FRZ & ~MCF_FlexCAN_CANMCR_HALT; - - /* wait for entering in the mode */ - while(!(MCF_FlexCAN_CANMCR&&MCF_FlexCAN_CANMCR_NOTRDY)){}; - - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - uint16_t i; - uint8_t nb_CANbuff = 16; //16 CAN buffers - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->CANdriverState = CANdriverState; - CANmodule->CANmsgBuffSize = nb_CANbuff; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = false; //no filters or ((rxSize <= xx) ? true : false;) - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - CANmodule->em = NULL; - - for(i=0U; iuseCANrxFilters){ - //CAN module filters are used, they will be configured with - //CO_CANrxBufferInit() functions, called by separate CANopen - //init functions. - //Configure all masks so, that received message must match filter - MCF_FlexCAN_RXGMASK = 0xFFE80000; - MCF_FlexCAN_RX14MASK = 0xFFE80000; - MCF_FlexCAN_RX15MASK = 0xFFE80000; - } - else{ - //CAN module filters are not used, all messages with standard 11-bit - //identifier will be received - //Configure all mask so, that all messages with standard identifier are accepted - MCF_FlexCAN_RXGMASK = 0x00080000; - MCF_FlexCAN_RX14MASK = 0x00080000; - MCF_FlexCAN_RX15MASK = 0x00080000; - }*/ - - - /* CAN Module configuration register */ - MCF_FlexCAN_CANMCR &= ~MCF_FlexCAN_CANMCR_STOP & ~MCF_FlexCAN_CANMCR_FRZ & ~MCF_FlexCAN_CANMCR_HALT; - - - /* configure buffers 0-13 as input buffers */ - for(i=0;i<14;i++) - { - MCF_CANMB_CTRL(i) = MCF_CANMB_CTRL_CODE(0b0100); - } - - /* configure buffers 14-15 as output buffers */ - MCF_CANMB_CTRL14 = MCF_CANMB_CTRL_CODE(0b1000); - MCF_CANMB_CTRL15 = MCF_CANMB_CTRL_CODE(0b1000); - - - /* CAN interrupt registers */ - //Enable all buffer interrupts (can be either Rx or Tx interrupt depending on buffer configuration) - MCF_FlexCAN_IMASK = 0xFF; - MCF_FlexCAN_IFLAG = 0xFF; - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){ - CO_CANsetConfigurationMode(CANmodule->CANdriverState); -} - - -/******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){ - return (uint16_t) (rxMsg->sid>>5); -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){ - /* buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - - /* Configure object variables */ - buffer->object = object; - buffer->pFunct = pFunct; - - /* CAN identifier and CAN mask, bit aligned with CAN module */ - buffer->ident = (uint16_t) ((ident & 0x07FF)<<5); - if(rtr){ - buffer->ident |= 0x0010; - } - buffer->mask = (uint16_t) (((mask & 0x07FF)<<5) | 0x0080); - - /* Set CAN hardware module filter and mask. */ - if(CANmodule->useCANrxFilters){ - //filters are not used. - } - } - else{ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer */ - buffer->ident = (uint16_t) ((ident & 0x07FF)<<5); - if(rtr) buffer->ident |= 0x0010; - - buffer->DLC = noOfBytes; - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } - - return buffer; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ - CO_ReturnError_t err = CO_ERROR_NO; - uint8_t i; - - /* Verify overflow */ - if(buffer->bufferFull){ - if(!CANmodule->firstCANtxMessage){ - /* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, buffer->CMSGSID); - } - err = CO_ERROR_TX_OVERFLOW; - } - - /* Try to find a free sending buffer */ - /* Here, we use buffer 14 & 15 for Tx */ - i=14; //initial sending buffer index - while( (MCF_CANMB_CTRL(i) != MCF_CANMB_CTRL_CODE(0b1000))&& - (MCF_CANMB_CTRL(i) != MCF_CANMB_CTRL_CODE(0b0100))&& - (MCF_CANMB_CTRL(i) != MCF_CANMB_CTRL_CODE(0b1010))&& - i<16)//end sending buffer index+1 - { - i++; - } - - CO_LOCK_CAN_SEND(); - /* if CAN TX buffer is free, copy message to it */ - if(i<16){ - MCF_CANMB_CTRL(i) = 0x0000|MCF_CANMB_CTRL_CODE(0b1000); //Tx MB inactive - MCF_CANMB_SID(i) = buffer->ident; - MCF_CANMB_DATA_WORD_1(i) = (uint16_t) (((buffer->data[0])<<8) | (buffer->data[1])); - MCF_CANMB_DATA_WORD_2(i) = (uint16_t) (((buffer->data[2])<<8) | (buffer->data[3])); - MCF_CANMB_DATA_WORD_3(i) = (uint16_t) (((buffer->data[4])<<8) | (buffer->data[5])); - MCF_CANMB_DATA_WORD_4(i) = (uint16_t) (((buffer->data[6])<<8) | (buffer->data[7])); - MCF_CANMB_CTRL(i) = (uint8_t) (MCF_CANMB_CTRL_CODE(0b1000) | MCF_CANMB_CTRL_LENGTH(buffer->DLC) ); //Tx MB active - } - /* if no buffer is free, message will be sent by interrupt */ - else{ - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - CO_UNLOCK_CAN_SEND(); - - return err; -} - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ - - CO_LOCK_CAN_SEND(); - if(CANmodule->bufferInhibitFlag){ - MCF_CANMB_CTRL14 = MCF_CANMB_CTRL_CODE(0b1000); //clear TXREQ - MCF_CANMB_CTRL15 = MCF_CANMB_CTRL_CODE(0b1000); //clear TXREQ - CO_UNLOCK_CAN_SEND(); - CO_errorReport((CO_emergencyReport_t*)CANmodule->em, ERROR_TPDO_OUTSIDE_WINDOW, 0); - } - else{ - CO_UNLOCK_CAN_SEND(); - } -} - - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - unsigned rxErrors, txErrors, ESTAT; - uint32_t err; - CO_emergencyReport_t* em = (CO_emergencyReport_t*)CANmodule->em; - - rxErrors = MCF_FlexCAN_RXECTR; - txErrors = MCF_FlexCAN_TXECTR; - ESTAT = MCF_FlexCAN_ESTAT & 0xFF00; - - if(txErrors > 0xFFFF) txErrors = 0xFFFF; - if(rxErrors > 0xFF) rxErrors = 0xFF; - - err = (uint32_t) (txErrors << 16 | rxErrors << 8 | ESTAT>>8); - - if(CANmodule->errOld != err){ - CANmodule->errOld = err; - - if(txErrors >= 256){ //bus off - CO_errorReport(em, ERROR_CAN_TX_BUS_OFF, err); - } - else{ //not bus off - CO_errorReset(em, ERROR_CAN_TX_BUS_OFF, err); - - if(rxErrors >= 96 || txErrors >= 96){ //bus warning - CO_errorReport(em, ERROR_CAN_BUS_WARNING, err); - } - - if(rxErrors >= 128){ //RX bus passive - CO_errorReport(em, ERROR_CAN_RX_BUS_PASSIVE, err); - } - else{ - CO_errorReset(em, ERROR_CAN_RX_BUS_PASSIVE, err); - } - - if(txErrors >= 128){ //TX bus passive - if(!CANmodule->firstCANtxMessage){ - CO_errorReport(em, ERROR_CAN_TX_BUS_PASSIVE, err); - } - } - else{ - int16_t wasCleared; - wasCleared = CO_errorReset(em, ERROR_CAN_TX_BUS_PASSIVE, err); - if(wasCleared == 1) CO_errorReset(em, ERROR_CAN_TX_OVERFLOW, err); - } - - if(rxErrors < 96 && txErrors < 96){ //no error - int16_t wasCleared; - wasCleared = CO_errorReset(em, ERROR_CAN_BUS_WARNING, err); - if(wasCleared == 1) CO_errorReset(em, ERROR_CAN_TX_OVERFLOW, err); - } - } - - if(ESTAT&MCF_FlexCAN_ESTAT_TXWARN && ESTAT&MCF_FlexCAN_ESTAT_RXWARN){//bus warning - CO_errorReport(em, ERROR_CAN_BUS_WARNING, err); - } - else{ - CO_errorReset(em, ERROR_CAN_BUS_WARNING, err); - } - } -} - - -/******************************************************************************/ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule, uint16_t ICODE){ - - /* receive interrupt (New CAN message is available in one of the Rx buffers) */ - if(ICODE <= 13){ - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint16_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - - rcvMsg = &MCF_CANMB_MSG(ICODE); //structures are aligned - rcvMsgIdent = (uint16_t) rcvMsg->sid; - if(rcvMsg->RTR) rcvMsgIdent |= 0x0800; - - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - break; - } - buffer++; - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){ - buffer->pFunct(buffer->object, rcvMsg); - } - - } - - - /* transmit interrupt (TX buffer 14 or 15 has finished sending) */ - else if(ICODE >14 ){ - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = false; - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = false; - /* Are there any new messages waiting to be send */ - if(CANmodule->CANtxCount > 0U){ - uint16_t i; /* index of transmitting message */ - CO_CANtx_t *buffer; /* Tx buffer */ - - /* first buffer */ - buffer = &CANmodule->txArray[0]; - /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0U; i--){ - /* if message buffer is full, send it. */ - if(buffer->bufferFull){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - MCF_CANMB_CTRL(ICODE) = 0x0000|MCF_CANMB_CTRL_CODE(0b1000); //Tx MB inactive - MCF_CANMB_SID(ICODE) = buffer->ident; - MCF_CANMB_DATA_WORD_1(ICODE) = (uint16_t) (((buffer->data[0])<<8) | (buffer->data[1])); - MCF_CANMB_DATA_WORD_2(ICODE) = (uint16_t) (((buffer->data[2])<<8) | (buffer->data[3])); - MCF_CANMB_DATA_WORD_3(ICODE) = (uint16_t) (((buffer->data[4])<<8) | (buffer->data[5])); - MCF_CANMB_DATA_WORD_4(ICODE) = (uint16_t) (((buffer->data[6])<<8) | (buffer->data[7])); - MCF_CANMB_CTRL(ICODE) = (uint8_t) (MCF_CANMB_CTRL_CODE(0b1000) | MCF_CANMB_CTRL_LENGTH(buffer->DLC) ); //Tx MB active - break; /* exit for loop */ - } - buffer++; - }/* end of for loop */ - - /* Clear counter if no more messages */ - if(i == 0U){ - CANmodule->CANtxCount = 0U; - } - } - - } -} diff --git a/stack/MCF5282/CO_driver.h b/stack/MCF5282/CO_driver.h deleted file mode 100644 index ed29678a..00000000 --- a/stack/MCF5282/CO_driver.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * CAN module object for Freescale MCF5282 ColdFire V2 microcontroller. - * - * @file CO_driver.h - * @author Janez Paternoster - * @author Laurent Grosbois - * @copyright 2004 - 2014 Janez Paternoster - * - * 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 - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -#include "mcf5282.h" /* processor header file */ -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ - - -/* CAN module base address */ - #define ADDR_CAN1 0 - #define ADDR_CAN2 (_CAN2_BASE_ADDRESS - _CAN1_BASE_ADDRESS) - - -/* Critical sections */ - #define CO_LOCK_CAN_SEND() asm{ move.w #0x2700,sr}; - #define CO_UNLOCK_CAN_SEND() asm{ move.w #0x2000,sr}; - - #define CO_LOCK_EMCY() asm{ move.w #0x2700,sr}; - #define CO_UNLOCK_EMCY() asm{ move.w #0x2000,sr}; - - #define CO_LOCK_OD() asm{ move.w #0x2700,sr}; - #define CO_UNLOCK_OD() asm{ move.w #0x2000,sr}; - - -/* MACRO : get information from Rx buffer */ -#define MCF_CANMB_MSG(x) (*(CO_CANrxMsg_t *)(&__IPSBAR[0x1C0080 + ((x)*0x10)])) - - -/* Data types */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* CAN bit rates - * - * CAN bit rates are initializers for array of eight CO_CANbitRateData_t - * objects. - * - * Macros are not used by driver itself, they may be used by application with - * combination with object CO_CANbitRateData_t. - * Application must declare following global variable depending on CO_FSYS used: - * const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; - * - * There are initializers for eight objects, which corresponds to following - * CAN bit rates (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. - * - * CO_FSYS is internal instruction cycle clock frequency in kHz units. See - * PIC32MX documentation for more information on FSYS. - * - * Available values for FSYS: - * kbps = | 10 | 20 | 50 | 125 | 250 | 500 | 800 | 1000 - * -------+----+----+----+-----+-----+-----+-----+----- - * 4 Mhz | O | O | O | O | p | - | - | - - * 8 Mhz | O | O | O | O | O | p | - | - - * 12 Mhz | O | O | O | O | p | p | - | - - * 16 Mhz | O | O | O | O | O | O | p | p - * 20 Mhz | O | O | O | O | O | O | - | p - * 24 Mhz | O | O | O | O | O | p | O | p - * 32 Mhz | p | O | O | O | O | O | p | O - * 36 Mhz | - | O | O | O | O | O | - | O - * 40 Mhz | - | O | O | O | O | O | p | O - * 48 Mhz | - | O | O | O | O | O | O | p - * 56 Mhz | - | p | O | O | O | p | (p) | p - * 64 Mhz | - | p | O | O | O | O | O | O - * 72 Mhz | - | - | O | O | O | O | O | O - * 80 Mhz | - | - | O | O | O | O | p | O - * ---------------------------------------------------- - * (O=optimal; p=possible; -=not possible) - */ -#ifdef CO_FSYS - /* Macros, which divides K into (SJW + PROP + PhSeg1 + PhSeg2) */ - #define TQ_x_7 1, 2, 3, 1 - #define TQ_x_8 1, 2, 3, 2 - #define TQ_x_9 1, 2, 4, 2 - #define TQ_x_10 1, 3, 4, 2 - #define TQ_x_12 1, 3, 6, 2 - #define TQ_x_14 1, 4, 7, 2 - #define TQ_x_15 1, 4, 8, 2 /* good timing */ - #define TQ_x_16 1, 5, 8, 2 /* good timing */ - #define TQ_x_17 1, 6, 8, 2 /* good timing */ - #define TQ_x_18 1, 7, 8, 2 /* good timing */ - #define TQ_x_19 1, 8, 8, 2 /* good timing */ - #define TQ_x_20 1, 8, 8, 3 /* good timing */ - #define TQ_x_21 1, 8, 8, 4 - #define TQ_x_22 1, 8, 8, 5 - #define TQ_x_23 1, 8, 8, 6 - #define TQ_x_24 1, 8, 8, 7 - #define TQ_x_25 1, 8, 8, 8 - - #if CO_FSYS == 4000 - #define CO_CANbitRateDataInitializers \ - {10, TQ_x_20}, /*CAN=10kbps*/ \ - {5, TQ_x_20}, /*CAN=20kbps*/ \ - {2, TQ_x_20}, /*CAN=50kbps*/ \ - {1, TQ_x_16}, /*CAN=125kbps*/ \ - {1, TQ_x_8 }, /*CAN=250kbps*/ \ - {1, TQ_x_8 }, /*Not possible*/ \ - {1, TQ_x_8 }, /*Not possible*/ \ - {1, TQ_x_8 } /*Not possible*/ - #elif CO_FSYS == 8000 - #define CO_CANbitRateDataInitializers \ - {25, TQ_x_16}, /*CAN=10kbps*/ \ - {10, TQ_x_20}, /*CAN=20kbps*/ \ - {5, TQ_x_16}, /*CAN=50kbps*/ \ - {2, TQ_x_16}, /*CAN=125kbps*/ \ - {1, TQ_x_16}, /*CAN=250kbps*/ \ - {1, TQ_x_8 }, /*CAN=500kbps*/ \ - {1, TQ_x_8 }, /*Not possible*/ \ - {1, TQ_x_8 } /*Not possible*/ - #elif CO_FSYS == 12000 - #define CO_CANbitRateDataInitializers \ - {40, TQ_x_15}, /*CAN=10kbps*/ \ - {20, TQ_x_15}, /*CAN=20kbps*/ \ - {8, TQ_x_15}, /*CAN=50kbps*/ \ - {3, TQ_x_16}, /*CAN=125kbps*/ \ - {2, TQ_x_12}, /*CAN=250kbps*/ \ - {1, TQ_x_12}, /*CAN=500kbps*/ \ - {1, TQ_x_12}, /*Not possible*/ \ - {1, TQ_x_12} /*Not possible*/ - #elif CO_FSYS == 16000 - #define CO_CANbitRateDataInitializers \ - {50, TQ_x_16}, /*CAN=10kbps*/ \ - {25, TQ_x_16}, /*CAN=20kbps*/ \ - {10, TQ_x_16}, /*CAN=50kbps*/ \ - {4, TQ_x_16}, /*CAN=125kbps*/ \ - {2, TQ_x_16}, /*CAN=250kbps*/ \ - {1, TQ_x_16}, /*CAN=500kbps*/ \ - {1, TQ_x_10}, /*CAN=800kbps*/ \ - {1, TQ_x_8 } /*CAN=1000kbps*/ - #elif CO_FSYS == 20000 - #define CO_CANbitRateDataInitializers \ - {50, TQ_x_20}, /*CAN=10kbps*/ \ - {25, TQ_x_20}, /*CAN=20kbps*/ \ - {10, TQ_x_20}, /*CAN=50kbps*/ \ - {5, TQ_x_16}, /*CAN=125kbps*/ \ - {2, TQ_x_20}, /*CAN=250kbps*/ \ - {1, TQ_x_20}, /*CAN=500kbps*/ \ - {1, TQ_x_20}, /*Not possible*/ \ - {1, TQ_x_10} /*CAN=1000kbps*/ - #elif CO_FSYS == 24000 - #define CO_CANbitRateDataInitializers \ - {63, TQ_x_19}, /*CAN=10kbps*/ \ - {40, TQ_x_15}, /*CAN=20kbps*/ \ - {15, TQ_x_16}, /*CAN=50kbps*/ \ - {6, TQ_x_16}, /*CAN=125kbps*/ \ - {3, TQ_x_16}, /*CAN=250kbps*/ \ - {2, TQ_x_12}, /*CAN=500kbps*/ \ - {1, TQ_x_15}, /*CAN=800kbps*/ \ - {1, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FSYS == 32000 - #define CO_CANbitRateDataInitializers \ - {64, TQ_x_25}, /*CAN=10kbps*/ \ - {50, TQ_x_16}, /*CAN=20kbps*/ \ - {20, TQ_x_16}, /*CAN=50kbps*/ \ - {8, TQ_x_16}, /*CAN=125kbps*/ \ - {4, TQ_x_16}, /*CAN=250kbps*/ \ - {2, TQ_x_16}, /*CAN=500kbps*/ \ - {2, TQ_x_10}, /*CAN=800kbps*/ \ - {1, TQ_x_16} /*CAN=1000kbps*/ - #elif CO_FSYS == 36000 - #define CO_CANbitRateDataInitializers \ - {50, TQ_x_18}, /*CAN=10kbps*/ \ - {50, TQ_x_18}, /*CAN=20kbps*/ \ - {20, TQ_x_18}, /*CAN=50kbps*/ \ - {8, TQ_x_18}, /*CAN=125kbps*/ \ - {4, TQ_x_18}, /*CAN=250kbps*/ \ - {2, TQ_x_18}, /*CAN=500kbps*/ \ - {2, TQ_x_18}, /*Not possible*/ \ - {1, TQ_x_18} /*CAN=1000kbps*/ - #elif CO_FSYS == 40000 - #define CO_CANbitRateDataInitializers \ - {50, TQ_x_20}, /*Not possible*/ \ - {50, TQ_x_20}, /*CAN=20kbps*/ \ - {25, TQ_x_16}, /*CAN=50kbps*/ \ - {10, TQ_x_16}, /*CAN=125kbps*/ \ - {5, TQ_x_16}, /*CAN=250kbps*/ \ - {2, TQ_x_20}, /*CAN=500kbps*/ \ - {1, TQ_x_25}, /*CAN=800kbps*/ \ - {1, TQ_x_20} /*CAN=1000kbps*/ - #elif CO_FSYS == 48000 - #define CO_CANbitRateDataInitializers \ - {63, TQ_x_19}, /*Not possible*/ \ - {63, TQ_x_19}, /*CAN=20kbps*/ \ - {30, TQ_x_16}, /*CAN=50kbps*/ \ - {12, TQ_x_16}, /*CAN=125kbps*/ \ - {6, TQ_x_16}, /*CAN=250kbps*/ \ - {3, TQ_x_16}, /*CAN=500kbps*/ \ - {2, TQ_x_15}, /*CAN=800kbps*/ \ - {2, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FSYS == 56000 - #define CO_CANbitRateDataInitializers \ - {61, TQ_x_23}, /*Not possible*/ \ - {61, TQ_x_23}, /*CAN=20kbps*/ \ - {35, TQ_x_16}, /*CAN=50kbps*/ \ - {14, TQ_x_16}, /*CAN=125kbps*/ \ - {7, TQ_x_16}, /*CAN=250kbps*/ \ - {4, TQ_x_14}, /*CAN=500kbps*/ \ - {5, TQ_x_7 }, /*CAN=800kbps*/ \ - {2, TQ_x_14} /*CAN=1000kbps*/ - #elif CO_FSYS == 64000 - #define CO_CANbitRateDataInitializers \ - {64, TQ_x_25}, /*Not possible*/ \ - {64, TQ_x_25}, /*CAN=20kbps*/ \ - {40, TQ_x_16}, /*CAN=50kbps*/ \ - {16, TQ_x_16}, /*CAN=125kbps*/ \ - {8, TQ_x_16}, /*CAN=250kbps*/ \ - {4, TQ_x_16}, /*CAN=500kbps*/ \ - {2, TQ_x_20}, /*CAN=800kbps*/ \ - {2, TQ_x_16} /*CAN=1000kbps*/ - #elif CO_FSYS == 72000 - #define CO_CANbitRateDataInitializers \ - {40, TQ_x_18}, /*Not possible*/ \ - {40, TQ_x_18}, /*Not possible*/ \ - {40, TQ_x_18}, /*CAN=50kbps*/ \ - {16, TQ_x_18}, /*CAN=125kbps*/ \ - {8, TQ_x_18}, /*CAN=250kbps*/ \ - {4, TQ_x_18}, /*CAN=500kbps*/ \ - {3, TQ_x_15}, /*CAN=800kbps*/ \ - {2, TQ_x_18} /*CAN=1000kbps*/ - #elif CO_FSYS == 80000 - #define CO_CANbitRateDataInitializers \ - {40, TQ_x_20}, /*Not possible*/ \ - {40, TQ_x_20}, /*Not possible*/ \ - {40, TQ_x_20}, /*CAN=50kbps*/ \ - {16, TQ_x_20}, /*CAN=125kbps*/ \ - {8, TQ_x_20}, /*CAN=250kbps*/ \ - {4, TQ_x_20}, /*CAN=500kbps*/ \ - {2, TQ_x_25}, /*CAN=800kbps*/ \ - {2, TQ_x_20} /*CAN=1000kbps*/ - #else - #error define_CO_FSYS CO_FSYS not supported - #endif -#endif - - -/* Structure contains timing coefficients for CAN module. - * - * CAN baud rate is calculated from following equations: - * Fsys - System clock (MAX 80MHz for PIC32MX) - * TQ = 2 * BRP / Fsys - Time Quanta - * BaudRate = 1 / (TQ * K) - Can bus Baud Rate - * K = SJW + PROP + PhSeg1 + PhSeg2 - Number of Time Quantas - */ -typedef struct{ - uint8_t BRP; /* (1...64) Baud Rate Prescaler */ - uint8_t SJW; /* (1...4) SJW time */ - uint8_t PROP; /* (1...8) PROP time */ - uint8_t phSeg1; /* (1...8) Phase Segment 1 time */ - uint8_t phSeg2; /* (1...8) Phase Segment 2 time */ -}CO_CANbitRateData_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. */ -typedef struct{ - unsigned timestamp :8; /* 8 bits timestamp, see MCF5282 documentation */ - unsigned code :4; /* Message Buffer code. see MCF52825 documentation */ - unsigned DLC :4; /* Data length code */ - unsigned sid :11;/* Standard Identifier - 11bits */ - unsigned RTR :1; /* Remote Transmission Request bit */ - unsigned :4; - unsigned timestamp16 :16;/* See MCF5282 documentation */ - uint8_t data[8]; /* 8 data bytes */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint8_t DLC; - uint16_t ident; - uint8_t data[8]; - volatile bool_t bufferFull; - volatile bool_t syncFlag; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - void *CANdriverState; - CO_CANrxMsg_t *CANmsgBuff; - uint8_t CANmsgBuffSize; - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; -}CO_CANmodule_t; - - -/* Endianes */ -#define CO_LITTLE_ENDIAN - - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. - * - * MCF5282 FlexCAN configuration: 16 buffers are available. - * Buffers [0..13] are used for reception - * Buffers [14..15] are used for reception - */ -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); /* Valid values are (in kbps): 125, 1000. If value is illegal, bitrate defaults to 125. */ - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* CAN interrupt receives and transmits CAN messages. */ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule, uint16_t ICODE); - - -#endif diff --git a/stack/MCF5282/readme b/stack/MCF5282/readme deleted file mode 100644 index db54c28a..00000000 --- a/stack/MCF5282/readme +++ /dev/null @@ -1,4 +0,0 @@ -Freescale MCF5282 (ColdFire V2) - -Contributed by Laurent Grosbois (mar 2012): -http://sourceforge.net/p/canopennode/code_complete/ci/master/tree/mcf5282_ongoingdev/ diff --git a/stack/PIC24_dsPIC33/CO_driver.c b/stack/PIC24_dsPIC33/CO_driver.c deleted file mode 100644 index 72fe0468..00000000 --- a/stack/PIC24_dsPIC33/CO_driver.c +++ /dev/null @@ -1,809 +0,0 @@ -/* - * CAN module object for Microchip dsPIC33F or PIC24H microcontroller. - * - * @file CO_driver.c - * @author Janez Paternoster - * @author Peter Rozsahegyi (EDS) - * @author Jens Nielsen (CAN receive) - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "CO_driver.h" -#include "CO_Emergency.h" - - -/* Globals */ - extern const CO_CANbitRateData_t CO_CANbitRateData[8]; - -#if CO_CAN1msgBuffSize > 0 - __eds__ CO_CANrxMsg_t CO_CAN1msg[CO_CAN1msgBuffSize] __eds __dma __attribute__((aligned(128))); -#endif -#if CO_CAN2msgBuffSize > 0 - __eds__ CO_CANrxMsg_t CO_CAN2msg[CO_CAN1msgBuffSize] __eds __dma __attribute__((aligned(128))); -#endif - - -/* Macro and Constants - CAN module registers and DMA registers - offset. */ - #define CAN_REG(base, offset) (*((volatile uint16_t *) (((uintptr_t) base) + offset))) - - #define C_CTRL1 0x00 - #define C_CTRL2 0x02 - #define C_VEC 0x04 - #define C_FCTRL 0x06 - #define C_FIFO 0x08 - #define C_INTF 0x0A - #define C_INTE 0x0C - #define C_EC 0x0E - #define C_CFG1 0x10 - #define C_CFG2 0x12 - #define C_FEN1 0x14 - #define C_FMSKSEL1 0x18 - #define C_FMSKSEL2 0x1A - - /* WIN == 0 */ - #define C_RXFUL1 0x20 - #define C_RXFUL2 0x22 - #define C_RXOVF1 0x28 - #define C_RXOVF2 0x2A - #define C_TR01CON 0x30 - #define C_TR23CON 0x32 - #define C_TR45CON 0x34 - #define C_TR67CON 0x36 - #define C_RXD 0x40 - #define C_TXD 0x42 - - /* WIN == 1 */ - #define C_BUFPNT1 0x20 - #define C_BUFPNT2 0x22 - #define C_BUFPNT3 0x24 - #define C_BUFPNT4 0x26 - #define C_RXM0SID 0x30 - #define C_RXM1SID 0x34 - #define C_RXM2SID 0x38 - #define C_RXF0SID 0x40 /* filter1 = +4, ...., filter 15 = +4*15 */ - - - #define DMA_REG(base, offset) (*((volatile uint16_t *) (base + offset))) - - #define DMA_CON 0x0 - #define DMA_REQ 0x2 -#ifndef __HAS_EDS__ - #define DMA_STA 0x4 - #define DMA_STB 0x6 - #define DMA_PAD 0x8 - #define DMA_CNT 0xA -#else - #define DMA_STAL 0x4 - #define DMA_STAH 0x6 - #define DMA_STBL 0x8 - #define DMA_STBH 0xA - #define DMA_PAD 0xC - #define DMA_CNT 0xE -#endif - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ - uint16_t C_CTRL1copy = CAN_REG(CANdriverState, C_CTRL1); - - /* set REQOP = 0x4 */ - C_CTRL1copy &= 0xFCFF; - C_CTRL1copy |= 0x0400; - CAN_REG(CANdriverState, C_CTRL1) = C_CTRL1copy; - - /* while OPMODE != 4 */ - while((CAN_REG(CANdriverState, C_CTRL1) & 0x00E0) != 0x0080); -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - uint16_t C_CTRL1copy = CAN_REG(CANmodule->CANdriverState, C_CTRL1); - - /* set REQOP = 0x0 */ - C_CTRL1copy &= 0xF8FF; - CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1copy; - - /* while OPMODE != 0 */ - while((CAN_REG(CANmodule->CANdriverState, C_CTRL1) & 0x00E0) != 0x0000); - - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - uint16_t i; - volatile uint16_t *pRXF; - - uint16_t DMArxBaseAddress; - uint16_t DMAtxBaseAddress; - __eds__ CO_CANrxMsg_t *CANmsgBuff; - uint8_t CANmsgBuffSize; - uint16_t CANmsgBuffDMAoffset; -#if defined(__HAS_EDS__) - uint16_t CANmsgBuffDMApage; -#endif - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Get global addresses for CAN module 1 or 2. */ - if(CANdriverState == ADDR_CAN1) { - DMArxBaseAddress = CO_CAN1_DMA0; - DMAtxBaseAddress = CO_CAN1_DMA1; - CANmsgBuff = &CO_CAN1msg[0]; - CANmsgBuffSize = CO_CAN1msgBuffSize; - CANmsgBuffDMAoffset = __builtin_dmaoffset(&CO_CAN1msg[0]); - #if defined(__HAS_EDS__) - CANmsgBuffDMApage = __builtin_dmapage(&CO_CAN1msg[0]); - #endif - } -#if CO_CAN2msgBuffSize > 0 - else if(((uintptr_t) CANdriverState) == ADDR_CAN2) { - DMArxBaseAddress = CO_CAN2_DMA0; - DMAtxBaseAddress = CO_CAN2_DMA1; - CANmsgBuff = &CO_CAN2msg[0]; - CANmsgBuffSize = CO_CAN2msgBuffSize; - CANmsgBuffDMAoffset = __builtin_dmaoffset(&CO_CAN2msg[0]); - #if defined(__HAS_EDS__) - CANmsgBuffDMApage = __builtin_dmapage(&CO_CAN2msg[0]); - #endif - } -#endif - else { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->CANdriverState = CANdriverState; - CANmodule->CANmsgBuff = CANmsgBuff; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = (rxSize <= 16U) ? true : false; - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - CANmodule->em = NULL; - - for(i=0U; iuseCANrxFilters){ - /* CAN module filters are used, they will be configured with */ - /* CO_CANrxBufferInit() functions, called by separate CANopen */ - /* init functions. */ - /* All mask bits are 1, so received message must match filter */ - CAN_REG(CANdriverState, C_RXM0SID) = 0xFFE8; - CAN_REG(CANdriverState, C_RXM1SID) = 0xFFE8; - CAN_REG(CANdriverState, C_RXM2SID) = 0xFFE8; - } - else{ - /* CAN module filters are not used, all messages with standard 11-bit */ - /* identifier will be received */ - /* Set masks so, that all messages with standard identifier are accepted */ - CAN_REG(CANdriverState, C_RXM0SID) = 0x0008; - CAN_REG(CANdriverState, C_RXM1SID) = 0x0008; - CAN_REG(CANdriverState, C_RXM2SID) = 0x0008; - } - - /* WIN = 0 - use buffer registers for default */ - CAN_REG(CANdriverState, C_CTRL1) &= 0xFFFE; - - - /* Configure DMA controller */ - /* Set size of buffer in DMA RAM (FIFO Area Starts with Tx/Rx buffer TRB1 (FSA = 1)) */ - /* Use maximum 16 buffers, because we have 16-bit system. */ - if (CANmsgBuffSize >= 16) { - CAN_REG(CANdriverState, C_FCTRL) = 0x8001; - CANmodule->CANmsgBuffSize = 16; - } - else if(CANmsgBuffSize >= 12) { - CAN_REG(CANdriverState, C_FCTRL) = 0x6001; - CANmodule->CANmsgBuffSize = 12; - } - else if(CANmsgBuffSize >= 8) { - CAN_REG(CANdriverState, C_FCTRL) = 0x4001; - CANmodule->CANmsgBuffSize = 8; - } - else if(CANmsgBuffSize >= 6) { - CAN_REG(CANdriverState, C_FCTRL) = 0x2001; - CANmodule->CANmsgBuffSize = 6; - } - else if(CANmsgBuffSize >= 4) { - CAN_REG(CANdriverState, C_FCTRL) = 0x0001; - CANmodule->CANmsgBuffSize = 4; - } - else { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* DMA chanel initialization for ECAN reception */ - DMA_REG(DMArxBaseAddress, DMA_CON) = 0x0020; - DMA_REG(DMArxBaseAddress, DMA_PAD) = (volatile uint16_t) &CAN_REG(CANdriverState, C_RXD); - DMA_REG(DMArxBaseAddress, DMA_CNT) = 7; - DMA_REG(DMArxBaseAddress, DMA_REQ) = (CANdriverState==ADDR_CAN1) ? 34 : 55; - -#ifndef __HAS_EDS__ - DMA_REG(DMArxBaseAddress, DMA_STA) = CANmsgBuffDMAoffset; -#else - DMA_REG(DMArxBaseAddress, DMA_STAL) = CANmsgBuffDMAoffset; - DMA_REG(DMArxBaseAddress, DMA_STAH) = CANmsgBuffDMApage; -#endif - - DMA_REG(DMArxBaseAddress, DMA_CON) = 0x8020; - - /* DMA chanel initialization for ECAN transmission */ - DMA_REG(DMAtxBaseAddress, DMA_CON) = 0x2020; - DMA_REG(DMAtxBaseAddress, DMA_PAD) = (volatile uint16_t) &CAN_REG(CANdriverState, C_TXD); - DMA_REG(DMAtxBaseAddress, DMA_CNT) = 7; - DMA_REG(DMAtxBaseAddress, DMA_REQ) = (CANdriverState==ADDR_CAN1) ? 70 : 71; - -#ifndef __HAS_EDS__ - DMA_REG(DMAtxBaseAddress, DMA_STA) = CANmsgBuffDMAoffset; -#else - DMA_REG(DMAtxBaseAddress, DMA_STAL) = CANmsgBuffDMAoffset; - DMA_REG(DMAtxBaseAddress, DMA_STAH) = CANmsgBuffDMApage; -#endif - - DMA_REG(DMAtxBaseAddress, DMA_CON) = 0xA020; - - - /* CAN interrupt registers */ - /* clear interrupt flags */ - CAN_REG(CANdriverState, C_INTF) = 0x0000; - /* enable receive and transmit interrupt */ - CAN_REG(CANdriverState, C_INTE) = 0x0003; - /* CAN interrupt (combined) must be configured by application */ - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){ - CO_CANsetConfigurationMode(CANmodule->CANdriverState); -} - - -/******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){ - return (rxMsg->ident >> 2) & 0x7FF; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){ - /* buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - uint16_t RXF, RXM; - uint16_t addr = CANmodule->CANdriverState; - - /* Configure object variables */ - buffer->object = object; - buffer->pFunct = pFunct; - - - /* CAN identifier and CAN mask, bit aligned with CAN module registers (in DMA RAM) */ - RXF = (ident & 0x07FF) << 2; - if(rtr){ - RXF |= 0x02; - } - RXM = (mask & 0x07FF) << 2; - RXM |= 0x02; - - /* configure filter and mask */ - if(RXF != buffer->ident || RXM != buffer->mask){ - volatile uint16_t C_CTRL1old = CAN_REG(addr, C_CTRL1); - CAN_REG(addr, C_CTRL1) = C_CTRL1old | 0x0001; /* WIN = 1 - use filter registers */ - buffer->ident = RXF; - buffer->mask = RXM; - - /* Set CAN hardware module filter and mask. */ - if(CANmodule->useCANrxFilters){ - volatile uint16_t *pRXF; - volatile uint16_t *pRXM0, *pRXM1, *pRXM2; - uint16_t selectMask; - - /* align RXF and RXM with C_RXF_SID and C_RXM_SID registers */ - RXF &= 0xFFFD; RXF <<= 3; - RXM &= 0xFFFD; RXM <<= 3; RXM |= 0x0008; - - /* write to filter */ - pRXF = &CAN_REG(addr, C_RXF0SID); /* pointer to first filter register */ - pRXF += index * 2; /* now points to C_RXFiSID (i == index) */ - *pRXF = RXF; /* write value to filter */ - - /* configure mask (There are three masks, each of them can be asigned to any filter. */ - /* First mask has always the value 0xFFE8 - all 11 bits must match). */ - pRXM0 = &CAN_REG(addr, C_RXM0SID); - pRXM1 = &CAN_REG(addr, C_RXM1SID); - pRXM2 = &CAN_REG(addr, C_RXM2SID); - if(RXM == 0xFFE8){ - selectMask = 0; - } - else if(RXM == *pRXM1 || *pRXM1 == 0xFFE8){ - /* RXM is equal to mask 1 or mask 1 was not yet configured. */ - *pRXM1 = RXM; - selectMask = 1; - } - else if(RXM == *pRXM2 || *pRXM2 == 0xFFE8){ - /* RXM is equal to mask 2 or mask 2 was not yet configured. */ - *pRXM2 = RXM; - selectMask = 2; - } - else{ - /* not enough masks */ - ret = CO_ERROR_OUT_OF_MEMORY; - selectMask = 0; - } - if(ret == CO_ERROR_NO){ - /* now write to appropriate mask select register */ - if(index<8){ - uint16_t clearMask = ~(0x0003 << (index << 1)); - selectMask = selectMask << (index << 1); - CAN_REG(addr, C_FMSKSEL1) = - (CAN_REG(addr, C_FMSKSEL1) & clearMask) | selectMask; - } - else{ - uint16_t clearMask = ~(0x0003 << ((index-8) << 1)); - selectMask = selectMask << ((index-8) << 1); - CAN_REG(addr, C_FMSKSEL2) = - (CAN_REG(addr, C_FMSKSEL2) & clearMask) | selectMask; - } - } - } - CAN_REG(addr, C_CTRL1) = C_CTRL1old; - } - } - else{ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, bit aligned with CAN module registers */ - uint16_t TXF; - TXF = (ident & 0x07FF) << 2; - if(rtr){ - TXF |= 0x02; - } - - /* write to buffer */ - buffer->ident = TXF; - buffer->DLC = noOfBytes; - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } - - return buffer; -} - - -/* Copy message to CAN module - internal usage only. - * - * @param CANdriverState CAN module base address - * @param dest Pointer to CAN module transmit buffer - * @param src Pointer to source message - */ -static void CO_CANsendToModule(void *CANdriverState, __eds__ CO_CANrxMsg_t *dest, CO_CANtx_t *src){ - uint8_t DLC; - __eds__ uint8_t *CANdataBuffer; - uint8_t *pData; - volatile uint16_t C_CTRL1old; - - /* CAN-ID + RTR */ - dest->ident = src->ident; - - /* Data lenght */ - DLC = src->DLC; - if(DLC > 8) DLC = 8; - dest->DLC = DLC; - - /* copy data */ - CANdataBuffer = &(dest->data[0]); - pData = src->data; - for(; DLC>0; DLC--) *(CANdataBuffer++) = *(pData++); - - /* control register, transmit request */ - C_CTRL1old = CAN_REG(CANdriverState, C_CTRL1); - CAN_REG(CANdriverState, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */ - CAN_REG(CANdriverState, C_TR01CON) |= 0x08; - CAN_REG(CANdriverState, C_CTRL1) = C_CTRL1old; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ - CO_ReturnError_t err = CO_ERROR_NO; - uint16_t addr = CANmodule->CANdriverState; - volatile uint16_t C_CTRL1old, C_TR01CONcopy; - - /* Verify overflow */ - if(buffer->bufferFull){ - if(!CANmodule->firstCANtxMessage){ - /* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, (buffer->ident >> 2) & 0x7FF); - } - err = CO_ERROR_TX_OVERFLOW; - } - - CO_LOCK_CAN_SEND(); - /* read C_TR01CON */ - C_CTRL1old = CAN_REG(addr, C_CTRL1); - CAN_REG(addr, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */ - C_TR01CONcopy = CAN_REG(addr, C_TR01CON); - CAN_REG(addr, C_CTRL1) = C_CTRL1old; - - /* if CAN TX buffer is free, copy message to it */ - if((C_TR01CONcopy & 0x8) == 0 && CANmodule->CANtxCount == 0){ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - CO_CANsendToModule(addr, CANmodule->CANmsgBuff, buffer); - } - /* if no buffer is free, message will be sent by interrupt */ - else{ - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - CO_UNLOCK_CAN_SEND(); - - return err; -} - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ - uint32_t tpdoDeleted = 0U; - - CO_LOCK_CAN_SEND(); - /* Abort message from CAN module, if there is synchronous TPDO. - * Take special care with this functionality. */ - if(CANmodule->bufferInhibitFlag){ - volatile uint16_t C_CTRL1old = CAN_REG(CANmodule->CANdriverState, C_CTRL1); - CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */ - CAN_REG(CANmodule->CANdriverState, C_TR01CON) &= 0xFFF7; /* clear TXREQ */ - CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old; - CANmodule->bufferInhibitFlag = false; - tpdoDeleted = 1U; - } - /* delete also pending synchronous TPDOs in TX buffers */ - if(CANmodule->CANtxCount != 0U){ - uint16_t i; - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - for(i = CANmodule->txSize; i > 0U; i--){ - if(buffer->bufferFull){ - if(buffer->syncFlag){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - tpdoDeleted = 2U; - } - } - buffer++; - } - } - CO_UNLOCK_CAN_SEND(); - - - if(tpdoDeleted != 0U){ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted); - } -} - - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - uint16_t err; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - - err = CAN_REG(CANmodule->CANdriverState, C_INTF) >> 8; - if(CAN_REG(CANmodule->CANdriverState, C_INTF) & 4){ - err |= 0x80; - } - - if(CANmodule->errOld != err){ - CANmodule->errOld = err; - - /* CAN RX bus overflow */ - if(err & 0xC0){ - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFB;/* clear bits */ - } - - /* CAN TX bus off */ - if(err & 0x20){ - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - } - - /* CAN TX bus passive */ - if(err & 0x10){ - if(!CANmodule->firstCANtxMessage) CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - int8_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE); - if(isError){ - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - - /* CAN RX bus passive */ - if(err & 0x08){ - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err); - } - - /* CAN TX or RX bus warning */ - if(err & 0x19){ - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - } - } -} - - -/******************************************************************************/ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule) { - - /* receive interrupt (New CAN message is available in RX FIFO buffer) */ - if(CAN_REG(CANmodule->CANdriverState, C_INTF) & 0x02) { - uint16_t C_CTRL1old; - uint16_t C_RXFUL1copy; - uint16_t C_FIFOcopy; - uint8_t FNRB, FBP; - - CO_DISABLE_INTERRUPTS(); - C_CTRL1old = CAN_REG(CANmodule->CANdriverState, C_CTRL1); - CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */ - C_RXFUL1copy = CAN_REG(CANmodule->CANdriverState, C_RXFUL1); - CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old; - - /* We will service the buffers indicated by RXFUL copy, clear interrupt - * flag now and let interrupt hit again if more messages are received */ - CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFD; - C_FIFOcopy = CAN_REG(CANmodule->CANdriverState, C_FIFO); - CO_ENABLE_INTERRUPTS(); - - /* FNRB tells us which buffer to read in FIFO */ - FNRB = C_FIFOcopy & 0x3F; - /* FBP tells us the next FIFO entry that will be written */ - FBP = C_FIFOcopy >> 8; - - while(C_RXFUL1copy != 0) { - __eds__ CO_CANrxMsg_t *rcvMsg;/* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint16_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - uint16_t mask; - - mask = 1 << FNRB; - - if((C_RXFUL1copy & mask) == 0) { - /* This should not happen. However, if it does happen - * (in case of debugging), get FNRB from loop. */ - for(FNRB=1; FNRBCANmsgBuffSize; FNRB++) { - mask = 1 << FNRB; - if((C_RXFUL1copy & mask)) { - break; - } - } - } - - /* RXFUL is set for this buffer, service it */ - rcvMsg = &CANmodule->CANmsgBuff[FNRB]; - rcvMsgIdent = rcvMsg->ident; - if(CANmodule->useCANrxFilters) { - /* CAN module filters are used. Message with known 11-bit identifier has */ - /* been received */ - index = rcvMsg->FILHIT; - if(index < CANmodule->rxSize) { - buffer = &CANmodule->rxArray[index]; - /* verify also RTR */ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) { - msgMatched = true; - } - } - } - else { - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--) { - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) { - msgMatched = true; - break; - } - buffer++; - } - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)) { - #ifdef __HAS_EDS__ - CO_CANrxMsg_t _rcvMsg = *rcvMsg; - buffer->pFunct(buffer->object, &_rcvMsg); - #else - buffer->pFunct(buffer->object, rcvMsg); - #endif - } - - /* Clear RXFUL flag */ - CO_DISABLE_INTERRUPTS(); - C_CTRL1old = CAN_REG(CANmodule->CANdriverState, C_CTRL1); - CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */ - CAN_REG(CANmodule->CANdriverState, C_RXFUL1) &= ~(mask); - CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old; - CO_ENABLE_INTERRUPTS(); - C_RXFUL1copy &= ~(mask); - - /* Now update FNRB, it will point to a new buffer after RXFUL was cleared */ - FNRB = (CAN_REG(CANmodule->CANdriverState, C_FIFO) & 0x3F); - } - } - - /* transmit interrupt (TX buffer is free) */ - if(CAN_REG(CANmodule->CANdriverState, C_INTF) & 0x01) { - - /* Clear interrupt flag */ - CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFE; - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = false; - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = false; - /* Are there any new messages waiting to be send */ - if(CANmodule->CANtxCount > 0U){ - uint16_t i; /* index of transmitting message */ - - /* first buffer */ - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0U; i--){ - /* if message buffer is full, send it. */ - if(buffer->bufferFull){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - CO_CANsendToModule(CANmodule->CANdriverState, CANmodule->CANmsgBuff, buffer); - break; /* exit for loop */ - } - buffer++; - }/* end of for loop */ - - /* Clear counter if no more messages */ - if(i == 0U){ - CANmodule->CANtxCount = 0U; - } - } - } -} diff --git a/stack/PIC24_dsPIC33/CO_driver.h b/stack/PIC24_dsPIC33/CO_driver.h deleted file mode 100644 index 9a58a03d..00000000 --- a/stack/PIC24_dsPIC33/CO_driver.h +++ /dev/null @@ -1,513 +0,0 @@ -/* - * CAN module object for Microchip dsPIC33 or PIC24 microcontroller. - * - * @file CO_driver.h - * @author Janez Paternoster - * @author Peter Rozsahegyi (EDS) - * @author Jens Nielsen (CAN receive) - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_DRIVER_H -#define CO_DRIVER_H - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -#if defined(__dsPIC33F__) || defined(__PIC24H__) -#include /* processor header file */ -#elif defined(__dsPIC33E__) || defined(__PIC24E__) -#include /* processor header file */ -#endif -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ -#include /* for 'true' and 'false' */ - - -/* CAN message buffer sizes for CAN module 1 and 2. Valid values - * are 0, 4, 6, 8, 12, 16. Default is one TX and seven RX messages (FIFO). */ - #ifndef CO_CAN1msgBuffSize - #define CO_CAN1msgBuffSize 8 - #endif - #ifndef CO_CAN2msgBuffSize - #define CO_CAN2msgBuffSize 0 //CAN module 2 not used by default - #endif - - -/* Default DMA addresses for CAN modules. */ - #ifndef CO_CAN1_DMA0 - #define CO_CAN1_DMA0 ADDR_DMA0 - #endif - #ifndef CO_CAN1_DMA1 - #define CO_CAN1_DMA1 ADDR_DMA1 - #endif - #ifndef CO_CAN2_DMA0 - #define CO_CAN2_DMA0 ADDR_DMA2 - #endif - #ifndef CO_CAN2_DMA1 - #define CO_CAN2_DMA1 ADDR_DMA3 - #endif - - -/* Define DMA attribute on supported platforms */ - #if defined(__dsPIC33F__) || defined(__PIC24H__) || defined(__DMA_BASE) - #define __dma __attribute__((space(dma))) - #else - #define __dma - #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) - #define __builtin_dmaoffset(V) (uint16_t)V - #endif - #endif - -/* Define EDS attribute on supported platforms */ - #if defined(__HAS_EDS__) - #define __eds __attribute__((eds)) - #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) - #define __builtin_dmapage(V) (uint16_t)0 - #endif - #else - #define __eds - #define __eds__ - #endif - - -/* CAN module base addresses */ - #define ADDR_CAN1 ((uint16_t)&C1CTRL1) - #define ADDR_CAN2 ((uint16_t)&C2CTRL1) - -/* DMA addresses */ - #define ADDR_DMA0 ((uint16_t)&DMA0CON) - #define ADDR_DMA1 ((uint16_t)&DMA1CON) - #define ADDR_DMA2 ((uint16_t)&DMA2CON) - #define ADDR_DMA3 ((uint16_t)&DMA3CON) - #define ADDR_DMA4 ((uint16_t)&DMA4CON) - #define ADDR_DMA5 ((uint16_t)&DMA5CON) - #define ADDR_DMA6 ((uint16_t)&DMA6CON) - #define ADDR_DMA7 ((uint16_t)&DMA7CON) - - -/* Critical sections */ - #define CO_LOCK_CAN_SEND() asm volatile ("disi #0x3FFF") - #define CO_UNLOCK_CAN_SEND() asm volatile ("disi #0x0000") - - #define CO_LOCK_EMCY() asm volatile ("disi #0x3FFF") - #define CO_UNLOCK_EMCY() asm volatile ("disi #0x0000") - - #define CO_LOCK_OD() asm volatile ("disi #0x3FFF") - #define CO_UNLOCK_OD() asm volatile ("disi #0x0000") - - #define CO_DISABLE_INTERRUPTS() asm volatile ("disi #0x3FFF") - #define CO_ENABLE_INTERRUPTS() asm volatile ("disi #0x0000") - - -/* Data types */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* CAN bit rates - * - * CAN bit rates are initializers for array of eight CO_CANbitRateData_t - * objects. - * - * Macros are not used by driver itself, they may be used by application with - * combination with object CO_CANbitRateData_t. - * Application must declare following global variable depending on CO_FCY used: - * const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; - * - * There are initializers for eight objects, which corresponds to following - * CAN bit rates (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. - * - * CO_FCY is internal instruction cycle clock frequency in kHz units. See - * dsPIC33F documentation for more information on FCY. - * - * Possible values for FCY are (in three groups): - * - Optimal CAN bit timing on all Baud Rates: 8000, 12000, 16000, 24000. - * - Not so optimal CAN bit timing on all Baud Rates: 4000, 32000. - * - not all CANopen Baud Rates possible: 2000, 3000, 5000, 6000, 10000, - * 20000, 40000, 48000, 56000, 64000, 70000. - * - * IMPORTANT: For FCY<=12000 there is unresolved bug; CANCKS configuration - * bit on ECAN does not work, so some baudrates are not possible. - */ -#ifdef CO_FCY - /* Macros, which divides K into (SJW + PROP + PhSeg1 + PhSeg2) */ - #define TQ_x_4 1, 1, 1, 1 - #define TQ_x_5 1, 1, 2, 1 - #define TQ_x_6 1, 1, 3, 1 - #define TQ_x_8 1, 2, 3, 2 - #define TQ_x_9 1, 2, 4, 2 - #define TQ_x_10 1, 3, 4, 2 - #define TQ_x_12 1, 3, 6, 2 - #define TQ_x_14 1, 4, 7, 2 - #define TQ_x_15 1, 4, 8, 2 /* good timing */ - #define TQ_x_16 1, 5, 8, 2 /* good timing */ - #define TQ_x_17 1, 6, 8, 2 /* good timing */ - #define TQ_x_18 1, 7, 8, 2 /* good timing */ - #define TQ_x_19 1, 8, 8, 2 /* good timing */ - #define TQ_x_20 1, 8, 8, 3 /* good timing */ - #define TQ_x_21 1, 8, 8, 4 - #define TQ_x_25 1, 8, 8, 8 - - #if CO_FCY == 2000 - #define CO_CANbitRateDataInitializers \ - {1, 5, TQ_x_20}, /*CAN=10kbps*/ \ - {2, 5, TQ_x_20}, /*CAN=20kbps*/ \ - {1, 1, TQ_x_20}, /*CAN=50kbps*/ \ - {2, 1, TQ_x_16}, /*CAN=125kbps*/ \ - {2, 1, TQ_x_8 }, /*CAN=250kbps*/ \ - {2, 1, TQ_x_4 }, /*CAN=500kbps*/ \ - {2, 1, TQ_x_4 }, /*Not possible*/ \ - {2, 1, TQ_x_4 } /*Not possible*/ - #elif CO_FCY == 3000 - #define CO_CANbitRateDataInitializers \ - {2, 15, TQ_x_20}, /*CAN=10kbps*/ \ - {1, 5, TQ_x_15}, /*CAN=20kbps*/ \ - {1, 2, TQ_x_15}, /*CAN=50kbps*/ \ - {1, 1, TQ_x_12}, /*CAN=125kbps*/ \ - {2, 1, TQ_x_12}, /*CAN=250kbps*/ \ - {2, 1, TQ_x_6 }, /*CAN=500kbps*/ \ - {2, 1, TQ_x_6 }, /*Not possible*/ \ - {2, 1, TQ_x_6 } /*Not possible*/ - #elif CO_FCY == 4000 - #define CO_CANbitRateDataInitializers \ - {2, 25, TQ_x_16}, /*CAN=10kbps*/ \ - {1, 5, TQ_x_20}, /*CAN=20kbps*/ \ - {2, 5, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 1, TQ_x_16}, /*CAN=125kbps*/ \ - {2, 1, TQ_x_16}, /*CAN=250kbps*/ \ - {2, 1, TQ_x_8 }, /*CAN=500kbps*/ \ - {2, 1, TQ_x_5 }, /*CAN=800kbps*/ \ - {2, 1, TQ_x_4 } /*CAN=1000kbps*/ - #elif CO_FCY == 5000 - #define CO_CANbitRateDataInitializers \ - {2, 25, TQ_x_20}, /*CAN=10kbps*/ \ - {1, 5, TQ_x_25}, /*CAN=20kbps*/ \ - {2, 5, TQ_x_20}, /*CAN=50kbps*/ \ - {1, 1, TQ_x_20}, /*CAN=125kbps*/ \ - {2, 1, TQ_x_20}, /*CAN=250kbps*/ \ - {2, 1, TQ_x_10}, /*CAN=500kbps*/ \ - {2, 1, TQ_x_10}, /*Not possible*/ \ - {2, 1, TQ_x_5 } /*CAN=1000kbps*/ - #elif CO_FCY == 6000 - #define CO_CANbitRateDataInitializers \ - {1, 20, TQ_x_15}, /*CAN=10kbps*/ \ - {1, 10, TQ_x_15}, /*CAN=20kbps*/ \ - {1, 4, TQ_x_15}, /*CAN=50kbps*/ \ - {2, 3, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 1, TQ_x_12}, /*CAN=250kbps*/ \ - {2, 1, TQ_x_12}, /*CAN=500kbps*/ \ - {2, 1, TQ_x_12}, /*Not possible*/ \ - {2, 1, TQ_x_6 } /*CAN=1000kbps*/ - #elif CO_FCY == 8000 - #define CO_CANbitRateDataInitializers \ - {1, 25, TQ_x_16}, /*CAN=10kbps*/ \ - {2, 25, TQ_x_16}, /*CAN=20kbps*/ \ - {1, 5, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 2, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 1, TQ_x_16}, /*CAN=250kbps*/ \ - {2, 1, TQ_x_16}, /*CAN=500kbps*/ \ - {2, 1, TQ_x_10}, /*CAN=800kbps*/ \ - {2, 1, TQ_x_8 } /*CAN=1000kbps*/ - #elif CO_FCY == 10000 - #define CO_CANbitRateDataInitializers \ - {1, 25, TQ_x_20}, /*CAN=10kbps*/ \ - {2, 25, TQ_x_20}, /*CAN=20kbps*/ \ - {1, 5, TQ_x_20}, /*CAN=50kbps*/ \ - {2, 5, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 1, TQ_x_20}, /*CAN=250kbps*/ \ - {2, 1, TQ_x_20}, /*CAN=500kbps*/ \ - {2, 1, TQ_x_20}, /*Not possible*/ \ - {2, 1, TQ_x_10} /*CAN=1000kbps*/ - #elif CO_FCY == 12000 - #define CO_CANbitRateDataInitializers \ - {2, 63, TQ_x_19}, /*CAN=10kbps*/ \ - {1, 20, TQ_x_15}, /*CAN=20kbps*/ \ - {2, 15, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 3, TQ_x_16}, /*CAN=125kbps*/ \ - {2, 3, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 1, TQ_x_12}, /*CAN=500kbps*/ \ - {2, 1, TQ_x_15}, /*CAN=800kbps*/ \ - {2, 1, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FCY == 16000 - #define CO_CANbitRateDataInitializers \ - {1, 50, TQ_x_16}, /*CAN=10kbps*/ \ - {1, 25, TQ_x_16}, /*CAN=20kbps*/ \ - {1, 10, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 4, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 2, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 1, TQ_x_16}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_10}, /*CAN=800kbps*/ \ - {1, 1, TQ_x_8 } /*CAN=1000kbps*/ - #elif CO_FCY == 20000 - #define CO_CANbitRateDataInitializers \ - {1, 50, TQ_x_20}, /*CAN=10kbps*/ \ - {1, 25, TQ_x_20}, /*CAN=20kbps*/ \ - {1, 10, TQ_x_20}, /*CAN=50kbps*/ \ - {1, 5, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 2, TQ_x_20}, /*CAN=250kbps*/ \ - {1, 1, TQ_x_20}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_20}, /*Not possible*/ \ - {1, 1, TQ_x_10} /*CAN=1000kbps*/ - #elif CO_FCY == 24000 - #define CO_CANbitRateDataInitializers \ - {1, 63, TQ_x_19}, /*CAN=10kbps*/ \ - {1, 40, TQ_x_15}, /*CAN=20kbps*/ \ - {1, 15, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 6, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 3, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 2, TQ_x_12}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_15}, /*CAN=800kbps*/ \ - {1, 1, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FCY == 32000 - #define CO_CANbitRateDataInitializers \ - {1, 64, TQ_x_25}, /*CAN=10kbps*/ \ - {1, 50, TQ_x_16}, /*CAN=20kbps*/ \ - {1, 20, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 8, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 4, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 2, TQ_x_16}, /*CAN=500kbps*/ \ - {1, 2, TQ_x_10}, /*CAN=800kbps*/ \ - {1, 1, TQ_x_16} /*CAN=1000kbps*/ - #elif CO_FCY == 40000 - #define CO_CANbitRateDataInitializers \ - {1, 50, TQ_x_20}, /*Not possible*/ \ - {1, 50, TQ_x_20}, /*CAN=20kbps*/ \ - {1, 25, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 10, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 5, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 2, TQ_x_20}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_25}, /*CAN=800kbps*/ \ - {1, 1, TQ_x_20} /*CAN=1000kbps*/ - #elif CO_FCY == 48000 - #define CO_CANbitRateDataInitializers \ - {1, 63, TQ_x_19}, /*Not possible*/ \ - {1, 63, TQ_x_19}, /*CAN=20kbps*/ \ - {1, 30, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 12, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 6, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 3, TQ_x_16}, /*CAN=500kbps*/ \ - {1, 2, TQ_x_15}, /*CAN=800kbps*/ \ - {1, 2, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FCY == 56000 - #define CO_CANbitRateDataInitializers \ - {1, 61, TQ_x_23}, /*Not possible*/ \ - {1, 61, TQ_x_23}, /*CAN=20kbps*/ \ - {1, 35, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 14, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 7, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 4, TQ_x_14}, /*CAN=500kbps*/ \ - {1, 5, TQ_x_7 }, /*CAN=800kbps*/ \ - {1, 2, TQ_x_14} /*CAN=1000kbps*/ - #elif CO_FCY == 64000 - #define CO_CANbitRateDataInitializers \ - {1, 64, TQ_x_25}, /*Not possible*/ \ - {1, 64, TQ_x_25}, /*CAN=20kbps*/ \ - {1, 40, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 16, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 8, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 4, TQ_x_16}, /*CAN=500kbps*/ \ - {1, 2, TQ_x_20}, /*CAN=800kbps*/ \ - {1, 2, TQ_x_16} /*CAN=1000kbps*/ - #elif CO_FCY == 70000 - #define CO_CANbitRateDataInitializers \ - {1, 64, TQ_x_25}, /*Not possible*/ \ - {1, 64, TQ_x_25}, /*CAN=20kbps*/ \ - {1, 35, TQ_x_20}, /*CAN=50kbps*/ \ - {1, 14, TQ_x_20}, /*CAN=125kbps*/ \ - {1, 7, TQ_x_20}, /*CAN=250kbps*/ \ - {1, 5, TQ_x_14}, /*CAN=500kbps*/ \ - {1, 3, TQ_x_15}, /*Not working*/ \ - {1, 2, TQ_x_17} /*Not working*/ - #else - #error define_CO_FCY CO_FCY not supported - #endif -#endif - - -/* Structure contains timing coefficients for CAN module. - * - * CAN baud rate is calculated from following equations: - * FCAN = FCY * Scale - Input frequency to CAN module (MAX 40MHz for dsPIC33F/PIC24H and 70MHz for dsPIC33E/PIC24E) - * TQ = 2 * BRP / FCAN - Time Quanta - * BaudRate = 1 / (TQ * K) - Can bus Baud Rate - * K = SJW + PROP + PhSeg1 + PhSeg2 - Number of Time Quantas - */ -typedef struct{ - uint8_t scale; /* (1 or 2) Scales FCY clock - dsPIC33F and PIC24H specific */ - uint8_t BRP; /* (1...64) Baud Rate Prescaler */ - uint8_t SJW; /* (1...4) SJW time */ - uint8_t PROP; /* (1...8) PROP time */ - uint8_t phSeg1; /* (1...8) Phase Segment 1 time */ - uint8_t phSeg2; /* (1...8) Phase Segment 2 time */ -}CO_CANbitRateData_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. - * In dsPIC33F and PIC24H this structure is used for both: transmitting and - * receiving to and from CAN module. (Object is ownded by CAN module). - */ -typedef struct{ - uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: - 'UUUSSSSS SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ - uint16_t extIdent; /* Extended identifier, not used here */ - uint16_t DLC :4; /* Data length code (bits 0...3) */ - uint16_t DLCrest :12; /* Not used here (bits 4..15) */ - uint8_t data[8]; /* 8 data bytes */ - uint8_t dummy; /* Not used */ - uint8_t FILHIT; /* Filter hit */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: - 'SSSSSUUU SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ - uint8_t DLC; - uint8_t data[8]; - volatile bool_t bufferFull; - volatile bool_t syncFlag; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - void *CANdriverState; - __eds__ CO_CANrxMsg_t *CANmsgBuff; /* dsPIC33F specific: CAN message buffer for CAN module */ - uint8_t CANmsgBuffSize; /* dsPIC33F specific: Size of the above buffer */ - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint16_t errOld; - void *em; -}CO_CANmodule_t; - - -/* Endianes */ -#define CO_LITTLE_ENDIAN - - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. */ -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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* CAN interrupt receives and transmits CAN messages. - * - * Function must be called directly from _C1Interrupt or _C2Interrupt with - * high priority. - */ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule); - - -#endif diff --git a/stack/PIC32/CO_driver.c b/stack/PIC32/CO_driver.c deleted file mode 100644 index 68a6f28b..00000000 --- a/stack/PIC32/CO_driver.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - * CAN module object for Microchip PIC32MX microcontroller. - * - * @file CO_driver.c - * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "CO_driver.h" -#include "CO_Emergency.h" - - -extern const CO_CANbitRateData_t CO_CANbitRateData[8]; -unsigned int CO_interruptStatus = 0; - - -/** - * Macro and Constants - CAN module registers - */ - #define CAN_REG(base, offset) (*((volatile uint32_t *) (((uintptr_t) base) + _CAN1_BASE_ADDRESS + (offset)))) - - #define CLR 0x04 - #define SET 0x08 - #define INV 0x0C - - #define C_CON 0x000 /* Control Register */ - #define C_CFG 0x010 /* Baud Rate Configuration Register */ - #define C_INT 0x020 /* Interrupt Register */ - #define C_VEC 0x030 /* Interrupt Code Register */ - #define C_TREC 0x040 /* Transmit/Receive Error Counter Register */ - #define C_FSTAT 0x050 /* FIFO Status Register */ - #define C_RXOVF 0x060 /* Receive FIFO Overflow Status Register */ - #define C_TMR 0x070 /* CAN Timer Register */ - #define C_RXM 0x080 /* + (0..3 x 0x10) //Acceptance Filter Mask Register */ - #define C_FLTCON 0x0C0 /* + (0..7(3) x 0x10) //Filter Control Register */ - #define C_RXF 0x140 /* + (0..31(15) x 0x10) //Acceptance Filter Register */ - #define C_FIFOBA 0x340 /* Message Buffer Base Address Register */ - #define C_FIFOCON 0x350 /* + (0..31(15) x 0x40) //FIFO Control Register */ - #define C_FIFOINT 0x360 /* + (0..31(15) x 0x40) //FIFO Interrupt Register */ - #define C_FIFOUA 0x370 /* + (0..31(15) x 0x40) //FIFO User Address Register */ - #define C_FIFOCI 0x380 /* + (0..31(15) x 0x40) //Module Message Index Register */ - - -/* Number of hardware filters */ -/* device PIC32MX530, 550 and 570 has only 16 registers for CAN reception (not 32). */ -#ifdef __PIC32MX -#if (__PIC32_FEATURE_SET__ == 530) || (__PIC32_FEATURE_SET__ == 550) || (__PIC32_FEATURE_SET__ == 570) - #define NO_CAN_RXF 16 -#endif -#endif -#ifndef NO_CAN_RXF - #define NO_CAN_RXF 32 -#endif - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ - uint32_t C_CONcopy = CAN_REG(CANdriverState, C_CON); - - /* switch ON can module */ - C_CONcopy |= 0x00008000; - CAN_REG(CANdriverState, C_CON) = C_CONcopy; - - /* request configuration mode */ - C_CONcopy &= 0xF8FFFFFF; - C_CONcopy |= 0x04000000; - CAN_REG(CANdriverState, C_CON) = C_CONcopy; - - /* wait for configuration mode */ - while((CAN_REG(CANdriverState, C_CON) & 0x00E00000) != 0x00800000); -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - - /* request normal mode */ - CAN_REG(CANmodule->CANdriverState, C_CON+CLR) = 0x07000000; - - /* wait for normal mode */ - while((CAN_REG(CANmodule->CANdriverState, C_CON) & 0x00E00000) != 0x00000000); - - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - uint16_t i; - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->CANdriverState = CANdriverState; - CANmodule->CANmsgBuffSize = 33; /* Must be the same as size of CANmodule->CANmsgBuff array. */ - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = (rxSize <= NO_CAN_RXF) ? true : false; - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - CANmodule->em = NULL; - - for(i=0U; iCANmsgBuff; - for(i=0; i<(CANmodule->CANmsgBuffSize*4); i++){ - *(f++) = 0; - } - - - /* Configure control register (configuration mode, receive timer stamp is enabled, module is on) */ - CAN_REG(CANdriverState, C_CON) = 0x04108000; - - - /* Configure FIFO */ - CAN_REG(CANdriverState, C_FIFOBA) = CO_KVA_TO_PA(CANmodule->CANmsgBuff);/* FIFO base address */ - CAN_REG(CANdriverState, C_FIFOCON) = (NO_CAN_RXF==32) ? 0x001F0000 : 0x000F0000; /* FIFO0: receive FIFO, 32(16) buffers */ - CAN_REG(CANdriverState, C_FIFOCON+0x40) = 0x00000080;/* FIFO1: transmit FIFO, 1 buffer */ - - - /* Configure CAN timing */ - switch(CANbitRate){ - case 10: i=0; break; - case 20: i=1; break; - case 50: i=2; break; - default: - case 125: i=3; break; - case 250: i=4; break; - case 500: i=5; break; - case 800: i=6; break; - case 1000: i=7; break; - } - CAN_REG(CANdriverState, C_CFG) = - ((uint32_t)(CO_CANbitRateData[i].phSeg2 - 1)) << 16 | /* SEG2PH */ - 0x00008000 | /* SEG2PHTS = 1, SAM = 0 */ - ((uint32_t)(CO_CANbitRateData[i].phSeg1 - 1)) << 11 | /* SEG1PH */ - ((uint32_t)(CO_CANbitRateData[i].PROP - 1)) << 8 | /* PRSEG */ - ((uint32_t)(CO_CANbitRateData[i].SJW - 1)) << 6 | /* SJW */ - ((uint32_t)(CO_CANbitRateData[i].BRP - 1)); /* BRP */ - - - /* CAN module hardware filters */ - /* clear all filter control registers (disable filters, mask 0 and FIFO 0 selected for all filters) */ - for(i=0; i<(NO_CAN_RXF/4); i++) - CAN_REG(CANdriverState, C_FLTCON+i*0x10) = 0x00000000; - if(CANmodule->useCANrxFilters){ - /* CAN module filters are used, they will be configured with */ - /* CO_CANrxBufferInit() functions, called by separate CANopen */ - /* init functions. */ - /* Configure all masks so, that received message must match filter */ - CAN_REG(CANdriverState, C_RXM) = 0xFFE80000; - CAN_REG(CANdriverState, C_RXM+0x10) = 0xFFE80000; - CAN_REG(CANdriverState, C_RXM+0x20) = 0xFFE80000; - CAN_REG(CANdriverState, C_RXM+0x30) = 0xFFE80000; - } - else{ - /* CAN module filters are not used, all messages with standard 11-bit */ - /* identifier will be received */ - /* Configure mask 0 so, that all messages with standard identifier are accepted */ - CAN_REG(CANdriverState, C_RXM) = 0x00080000; - /* configure one filter for FIFO 0 and enable it */ - CAN_REG(CANdriverState, C_RXF) = 0x00000000; - CAN_REG(CANdriverState, C_FLTCON) = 0x00000080; - } - - - /* CAN interrupt registers */ - /* Enable 'RX buffer not empty' (RXNEMPTYIE) interrupt in FIFO 0 (third layer interrupt) */ - CAN_REG(CANdriverState, C_FIFOINT) = 0x00010000; - /* Enable 'Tx buffer empty' (TXEMPTYIE) interrupt in FIFO 1 (third layer interrupt) */ - CAN_REG(CANdriverState, C_FIFOINT+0x40) = 0x00000000; /* will be enabled in CO_CANsend */ - /* Enable receive (RBIE) and transmit (TBIE) buffer interrupt (secont layer interrupt) */ - CAN_REG(CANdriverState, C_INT) = 0x00030000; - /* CAN interrupt (first layer) must be configured by application */ - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){ - CO_CANsetConfigurationMode(CANmodule->CANdriverState); -} - - -/******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){ - return rxMsg->ident; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){ - /* buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - - /* Configure object variables */ - buffer->object = object; - buffer->pFunct = pFunct; - - /* CAN identifier and CAN mask, bit aligned with CAN module FIFO buffers (RTR is extra) */ - buffer->ident = ident & 0x07FFU; - if(rtr){ - buffer->ident |= 0x0800U; - } - buffer->mask = (mask & 0x07FFU) | 0x0800U; - - /* Set CAN hardware module filter and mask. */ - if(CANmodule->useCANrxFilters){ - uint32_t RXF, RXM; - volatile uint32_t *pRXF; - volatile uint32_t *pRXM0, *pRXM1, *pRXM2, *pRXM3; - volatile uint8_t *pFLTCON; - uint8_t selectMask; - uint16_t addr = CANmodule->CANdriverState; - - /* get correct part of the filter control register */ - pFLTCON = (volatile uint8_t*)(&CAN_REG(addr, C_FLTCON)); /* pointer to first filter control register */ - pFLTCON += (index/4) * 0x10; /* now points to the correct C_FLTCONi */ - pFLTCON += index%4; /* now points to correct part of the correct C_FLTCONi */ - - /* disable filter and wait if necessary */ - while(*pFLTCON & 0x80) *pFLTCON &= 0x7F; - - /* align RXF and RXM with C_RXF and C_RXM registers */ - RXF = (uint32_t)ident << 21; - RXM = (uint32_t)mask << 21 | 0x00080000; - - /* write to filter */ - pRXF = &CAN_REG(addr, C_RXF); /* pointer to first filter register */ - pRXF += index * (0x10/4); /* now points to C_RXFi (i == index) */ - *pRXF = RXF; /* write value to filter */ - - /* configure mask (There are four masks, each of them can be asigned to any filter. */ - /* First mask has always the value 0xFFE80000 - all 11 bits must match). */ - pRXM0 = &CAN_REG(addr, C_RXM); - pRXM1 = &CAN_REG(addr, C_RXM+0x10); - pRXM2 = &CAN_REG(addr, C_RXM+0x20); - pRXM3 = &CAN_REG(addr, C_RXM+0x30); - if(RXM == *pRXM0){ - selectMask = 0; - } - else if(RXM == *pRXM1 || *pRXM1 == 0xFFE80000){ - /* RXM is equal to mask 1 or mask 1 was not yet configured. */ - *pRXM1 = RXM; - selectMask = 1; - } - else if(RXM == *pRXM2 || *pRXM2 == 0xFFE80000){ - /* RXM is equal to mask 2 or mask 2 was not yet configured. */ - *pRXM2 = RXM; - selectMask = 2; - } - else if(RXM == *pRXM3 || *pRXM3 == 0xFFE80000){ - /* RXM is equal to mask 3 or mask 3 was not yet configured. */ - *pRXM3 = RXM; - selectMask = 3; - } - else{ - /* not enough masks */ - selectMask = 0; - ret = CO_ERROR_OUT_OF_MEMORY; - } - /* write to appropriate filter control register */ - *pFLTCON = 0x80 | (selectMask << 5); /* enable filter and write filter mask select bit */ - } - } - else{ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer */ - buffer->CMSGSID = ident & 0x07FF; - buffer->CMSGEID = (noOfBytes & 0xF) | (rtr?0x0200:0); - - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } - - return buffer; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ - CO_ReturnError_t err = CO_ERROR_NO; - uint16_t addr = CANmodule->CANdriverState; - volatile uint32_t* TX_FIFOcon = &CAN_REG(addr, C_FIFOCON+0x40); - volatile uint32_t* TX_FIFOconSet = &CAN_REG(addr, C_FIFOCON+0x48); - uint32_t* TXmsgBuffer = CO_PA_TO_KVA1(CAN_REG(addr, C_FIFOUA+0x40)); - uint32_t* message = (uint32_t*) buffer; - uint32_t TX_FIFOconCopy; - - /* Verify overflow */ - if(buffer->bufferFull){ - if(!CANmodule->firstCANtxMessage){ - /* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, buffer->CMSGSID); - } - err = CO_ERROR_TX_OVERFLOW; - } - - CO_LOCK_CAN_SEND(); - TX_FIFOconCopy = *TX_FIFOcon; - /* if CAN TX buffer is free, copy message to it */ - if((TX_FIFOconCopy & 0x8) == 0 && CANmodule->CANtxCount == 0){ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - *(TXmsgBuffer++) = *(message++); - *(TXmsgBuffer++) = *(message++); - *(TXmsgBuffer++) = *(message++); - *(TXmsgBuffer++) = *(message++); - /* if message was aborted, don't set UINC */ - if((TX_FIFOconCopy & 0x40) == 0) - *TX_FIFOconSet = 0x2000; /* set UINC */ - *TX_FIFOconSet = 0x0008; /* set TXREQ */ - } - /* if no buffer is free, message will be sent by interrupt */ - else{ - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - /* Enable 'Tx buffer empty' (TXEMPTYIE) interrupt in FIFO 1 (third layer interrupt) */ - CAN_REG(addr, C_FIFOINT+0x48) = 0x01000000; - CO_UNLOCK_CAN_SEND(); - - return err; -} - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ - uint32_t tpdoDeleted = 0U; - volatile uint32_t* TX_FIFOcon = &CAN_REG(CANmodule->CANdriverState, C_FIFOCON+0x40); - volatile uint32_t* TX_FIFOconClr = &CAN_REG(CANmodule->CANdriverState, C_FIFOCON+0x44); - - CO_LOCK_CAN_SEND(); - /* Abort message from CAN module, if there is synchronous TPDO. - * Take special care with this functionality. */ - if((*TX_FIFOcon & 0x8) && CANmodule->bufferInhibitFlag){ - *TX_FIFOconClr = 0x0008; /* clear TXREQ */ - CANmodule->bufferInhibitFlag = false; - tpdoDeleted = 1U; - } - /* delete also pending synchronous TPDOs in TX buffers */ - if(CANmodule->CANtxCount != 0U){ - uint16_t i; - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - for(i = CANmodule->txSize; i > 0U; i--){ - if(buffer->bufferFull){ - if(buffer->syncFlag){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - tpdoDeleted = 2U; - } - } - buffer++; - } - } - CO_UNLOCK_CAN_SEND(); - - - if(tpdoDeleted != 0U){ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted); - } -} - - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - uint16_t rxErrors, txErrors, overflow; - uint32_t TREC; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - uint32_t err; - - TREC = CAN_REG(CANmodule->CANdriverState, C_TREC); - rxErrors = (uint8_t) TREC; - txErrors = (uint8_t) (TREC>>8); - if(TREC&0x00200000) txErrors = 256; /* bus off */ - overflow = (CAN_REG(CANmodule->CANdriverState, C_FIFOINT)&0x8) ? 1 : 0; - - err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; - - if(CANmodule->errOld != err){ - CANmodule->errOld = err; - - if(txErrors >= 256U){ /* bus off */ - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - } - else{ /* not bus off */ - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - - if((rxErrors >= 96U) || (txErrors >= 96U)){ /* bus warning */ - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - - if(rxErrors >= 128U){ /* RX bus passive */ - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err); - } - - if(txErrors >= 128U){ /* TX bus passive */ - if(!CANmodule->firstCANtxMessage){ - CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - } - else{ - bool_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE); - if(isError){ - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - - if((rxErrors < 96U) && (txErrors < 96U)){ /* no error */ - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - } - } - - if(overflow != 0U){ /* CAN RX bus overflow */ - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - } - } -} - - -/******************************************************************************/ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ - uint8_t ICODE; - ICODE = (uint8_t) CAN_REG(CANmodule->CANdriverState, C_VEC) & 0x7F; - - /* receive interrupt (New CAN message is available in RX FIFO 0 buffer) */ - if(ICODE == 0){ - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint16_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - - rcvMsg = (CO_CANrxMsg_t*) CO_PA_TO_KVA1(CAN_REG(CANmodule->CANdriverState, C_FIFOUA)); - rcvMsgIdent = rcvMsg->ident; - if(rcvMsg->RTR) rcvMsgIdent |= 0x0800; - if(CANmodule->useCANrxFilters){ - /* CAN module filters are used. Message with known 11-bit identifier has */ - /* been received */ - index = rcvMsg->FILHIT; - if(index < CANmodule->rxSize){ - buffer = &CANmodule->rxArray[index]; - /* verify also RTR */ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - } - } - } - else{ - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - break; - } - buffer++; - } - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){ - buffer->pFunct(buffer->object, rcvMsg); - } - - /* Update the message buffer pointer */ - CAN_REG(CANmodule->CANdriverState, C_FIFOCON+0x08) = 0x2000; /* set UINC */ - } - - - /* transmit interrupt (TX buffer FIFO 1 is free) */ - else if(ICODE == 1){ - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = false; - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = false; - /* Are there any new messages waiting to be send */ - if(CANmodule->CANtxCount > 0U){ - uint16_t i; /* index of transmitting message */ - - /* first buffer */ - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0U; i--){ - /* if message buffer is full, send it. */ - if(buffer->bufferFull){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - uint32_t* TXmsgBuffer = CO_PA_TO_KVA1(CAN_REG(CANmodule->CANdriverState, C_FIFOUA+0x40)); - uint32_t* message = (uint32_t*) buffer; - volatile uint32_t* TX_FIFOconSet = &CAN_REG(CANmodule->CANdriverState, C_FIFOCON+0x48); - *(TXmsgBuffer++) = *(message++); - *(TXmsgBuffer++) = *(message++); - *(TXmsgBuffer++) = *(message++); - *(TXmsgBuffer++) = *(message++); - *TX_FIFOconSet = 0x2000; /* set UINC */ - *TX_FIFOconSet = 0x0008; /* set TXREQ */ - break; /* exit for loop */ - } - buffer++; - }/* end of for loop */ - - /* Clear counter if no more messages */ - if(i == 0U){ - CANmodule->CANtxCount = 0U; - } - } - - /* if no more messages, disable 'Tx buffer empty' (TXEMPTYIE) interrupt */ - if(CANmodule->CANtxCount == 0U){ - CAN_REG(CANmodule->CANdriverState, C_FIFOINT+0x44) = 0x01000000; - } - } -} diff --git a/stack/PIC32/CO_driver.h b/stack/PIC32/CO_driver.h deleted file mode 100644 index 8dd8a687..00000000 --- a/stack/PIC32/CO_driver.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * CAN module object for Microchip PIC32MX microcontroller. - * - * @file CO_driver.h - * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_DRIVER_H -#define CO_DRIVER_H - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -#include /* processor header file */ -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ -#include /* for 'true', 'false' */ - - -/* CAN module base address */ - #define ADDR_CAN1 0 - #define ADDR_CAN2 (_CAN2_BASE_ADDRESS - _CAN1_BASE_ADDRESS) - - -/* Translate a kernel virtual address in KSEG0 or KSEG1 to a real - * physical address and back. */ - typedef unsigned long CO_paddr_t; /* a physical address */ - typedef unsigned long CO_vaddr_t; /* a virtual address */ - #define CO_KVA_TO_PA(v) ((CO_paddr_t)(v) & 0x1fffffff) - #define CO_PA_TO_KVA0(pa) ((void *) ((pa) | 0x80000000)) - #define CO_PA_TO_KVA1(pa) ((void *) ((pa) | 0xa0000000)) - - -/* Critical sections */ - extern unsigned int CO_interruptStatus; - #define CO_LOCK_CAN_SEND() CO_interruptStatus = __builtin_disable_interrupts() - #define CO_UNLOCK_CAN_SEND() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} - - #define CO_LOCK_EMCY() CO_interruptStatus = __builtin_disable_interrupts() - #define CO_UNLOCK_EMCY() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} - - #define CO_LOCK_OD() CO_interruptStatus = __builtin_disable_interrupts() - #define CO_UNLOCK_OD() if(CO_interruptStatus & 0x00000001) {__builtin_enable_interrupts();} - - -/* Data types */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* CAN bit rates - * - * CAN bit rates are initializers for array of eight CO_CANbitRateData_t - * objects. - * - * Macros are not used by driver itself, they may be used by application with - * combination with object CO_CANbitRateData_t. - * Application must declare following global variable depending on CO_FSYS used: - * const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; - * - * There are initializers for eight objects, which corresponds to following - * CAN bit rates (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. - * - * CO_FSYS is internal instruction cycle clock frequency in kHz units. See - * PIC32MX documentation for more information on FSYS. - * - * Available values for FSYS: - * kbps = | 10 | 20 | 50 | 125 | 250 | 500 | 800 | 1000 - * -------+----+----+----+-----+-----+-----+-----+----- - * 4 Mhz | O | O | O | O | p | - | - | - - * 8 Mhz | O | O | O | O | O | p | - | - - * 12 Mhz | O | O | O | O | p | p | - | - - * 16 Mhz | O | O | O | O | O | O | p | p - * 20 Mhz | O | O | O | O | O | O | - | p - * 24 Mhz | O | O | O | O | O | p | O | p - * 32 Mhz | p | O | O | O | O | O | p | O - * 36 Mhz | - | O | O | O | O | O | - | O - * 40 Mhz | - | O | O | O | O | O | p | O - * 48 Mhz | - | O | O | O | O | O | O | p - * 56 Mhz | - | p | O | O | O | p | (p) | p - * 64 Mhz | - | p | O | O | O | O | O | O - * 72 Mhz | - | - | O | O | O | O | O | O - * 80 Mhz | - | - | O | O | O | O | p | O - * ---------------------------------------------------- - * (O=optimal; p=possible; -=not possible) - */ -#ifdef CO_FSYS - /* Macros, which divides K into (SJW + PROP + PhSeg1 + PhSeg2) */ - #define TQ_x_7 1, 2, 3, 1 - #define TQ_x_8 1, 2, 3, 2 - #define TQ_x_9 1, 2, 4, 2 - #define TQ_x_10 1, 3, 4, 2 - #define TQ_x_12 1, 3, 6, 2 - #define TQ_x_14 1, 4, 7, 2 - #define TQ_x_15 1, 4, 8, 2 /* good timing */ - #define TQ_x_16 1, 5, 8, 2 /* good timing */ - #define TQ_x_17 1, 6, 8, 2 /* good timing */ - #define TQ_x_18 1, 7, 8, 2 /* good timing */ - #define TQ_x_19 1, 8, 8, 2 /* good timing */ - #define TQ_x_20 1, 8, 8, 3 /* good timing */ - #define TQ_x_21 1, 8, 8, 4 - #define TQ_x_22 1, 8, 8, 5 - #define TQ_x_23 1, 8, 8, 6 - #define TQ_x_24 1, 8, 8, 7 - #define TQ_x_25 1, 8, 8, 8 - - #if CO_FSYS == 4000 - #define CO_CANbitRateDataInitializers \ - {10, TQ_x_20}, /*CAN=10kbps*/ \ - {5, TQ_x_20}, /*CAN=20kbps*/ \ - {2, TQ_x_20}, /*CAN=50kbps*/ \ - {1, TQ_x_16}, /*CAN=125kbps*/ \ - {1, TQ_x_8 }, /*CAN=250kbps*/ \ - {1, TQ_x_8 }, /*Not possible*/ \ - {1, TQ_x_8 }, /*Not possible*/ \ - {1, TQ_x_8 } /*Not possible*/ - #elif CO_FSYS == 8000 - #define CO_CANbitRateDataInitializers \ - {25, TQ_x_16}, /*CAN=10kbps*/ \ - {10, TQ_x_20}, /*CAN=20kbps*/ \ - {5, TQ_x_16}, /*CAN=50kbps*/ \ - {2, TQ_x_16}, /*CAN=125kbps*/ \ - {1, TQ_x_16}, /*CAN=250kbps*/ \ - {1, TQ_x_8 }, /*CAN=500kbps*/ \ - {1, TQ_x_8 }, /*Not possible*/ \ - {1, TQ_x_8 } /*Not possible*/ - #elif CO_FSYS == 12000 - #define CO_CANbitRateDataInitializers \ - {40, TQ_x_15}, /*CAN=10kbps*/ \ - {20, TQ_x_15}, /*CAN=20kbps*/ \ - {8, TQ_x_15}, /*CAN=50kbps*/ \ - {3, TQ_x_16}, /*CAN=125kbps*/ \ - {2, TQ_x_12}, /*CAN=250kbps*/ \ - {1, TQ_x_12}, /*CAN=500kbps*/ \ - {1, TQ_x_12}, /*Not possible*/ \ - {1, TQ_x_12} /*Not possible*/ - #elif CO_FSYS == 16000 - #define CO_CANbitRateDataInitializers \ - {50, TQ_x_16}, /*CAN=10kbps*/ \ - {25, TQ_x_16}, /*CAN=20kbps*/ \ - {10, TQ_x_16}, /*CAN=50kbps*/ \ - {4, TQ_x_16}, /*CAN=125kbps*/ \ - {2, TQ_x_16}, /*CAN=250kbps*/ \ - {1, TQ_x_16}, /*CAN=500kbps*/ \ - {1, TQ_x_10}, /*CAN=800kbps*/ \ - {1, TQ_x_8 } /*CAN=1000kbps*/ - #elif CO_FSYS == 20000 - #define CO_CANbitRateDataInitializers \ - {50, TQ_x_20}, /*CAN=10kbps*/ \ - {25, TQ_x_20}, /*CAN=20kbps*/ \ - {10, TQ_x_20}, /*CAN=50kbps*/ \ - {5, TQ_x_16}, /*CAN=125kbps*/ \ - {2, TQ_x_20}, /*CAN=250kbps*/ \ - {1, TQ_x_20}, /*CAN=500kbps*/ \ - {1, TQ_x_20}, /*Not possible*/ \ - {1, TQ_x_10} /*CAN=1000kbps*/ - #elif CO_FSYS == 24000 - #define CO_CANbitRateDataInitializers \ - {63, TQ_x_19}, /*CAN=10kbps*/ \ - {40, TQ_x_15}, /*CAN=20kbps*/ \ - {15, TQ_x_16}, /*CAN=50kbps*/ \ - {6, TQ_x_16}, /*CAN=125kbps*/ \ - {3, TQ_x_16}, /*CAN=250kbps*/ \ - {2, TQ_x_12}, /*CAN=500kbps*/ \ - {1, TQ_x_15}, /*CAN=800kbps*/ \ - {1, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FSYS == 32000 - #define CO_CANbitRateDataInitializers \ - {64, TQ_x_25}, /*CAN=10kbps*/ \ - {50, TQ_x_16}, /*CAN=20kbps*/ \ - {20, TQ_x_16}, /*CAN=50kbps*/ \ - {8, TQ_x_16}, /*CAN=125kbps*/ \ - {4, TQ_x_16}, /*CAN=250kbps*/ \ - {2, TQ_x_16}, /*CAN=500kbps*/ \ - {2, TQ_x_10}, /*CAN=800kbps*/ \ - {1, TQ_x_16} /*CAN=1000kbps*/ - #elif CO_FSYS == 36000 - #define CO_CANbitRateDataInitializers \ - {50, TQ_x_18}, /*CAN=10kbps*/ \ - {50, TQ_x_18}, /*CAN=20kbps*/ \ - {20, TQ_x_18}, /*CAN=50kbps*/ \ - {8, TQ_x_18}, /*CAN=125kbps*/ \ - {4, TQ_x_18}, /*CAN=250kbps*/ \ - {2, TQ_x_18}, /*CAN=500kbps*/ \ - {2, TQ_x_18}, /*Not possible*/ \ - {1, TQ_x_18} /*CAN=1000kbps*/ - #elif CO_FSYS == 40000 - #define CO_CANbitRateDataInitializers \ - {50, TQ_x_20}, /*Not possible*/ \ - {50, TQ_x_20}, /*CAN=20kbps*/ \ - {25, TQ_x_16}, /*CAN=50kbps*/ \ - {10, TQ_x_16}, /*CAN=125kbps*/ \ - {5, TQ_x_16}, /*CAN=250kbps*/ \ - {2, TQ_x_20}, /*CAN=500kbps*/ \ - {1, TQ_x_25}, /*CAN=800kbps*/ \ - {1, TQ_x_20} /*CAN=1000kbps*/ - #elif CO_FSYS == 48000 - #define CO_CANbitRateDataInitializers \ - {63, TQ_x_19}, /*Not possible*/ \ - {63, TQ_x_19}, /*CAN=20kbps*/ \ - {30, TQ_x_16}, /*CAN=50kbps*/ \ - {12, TQ_x_16}, /*CAN=125kbps*/ \ - {6, TQ_x_16}, /*CAN=250kbps*/ \ - {3, TQ_x_16}, /*CAN=500kbps*/ \ - {2, TQ_x_15}, /*CAN=800kbps*/ \ - {2, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FSYS == 56000 - #define CO_CANbitRateDataInitializers \ - {61, TQ_x_23}, /*Not possible*/ \ - {61, TQ_x_23}, /*CAN=20kbps*/ \ - {35, TQ_x_16}, /*CAN=50kbps*/ \ - {14, TQ_x_16}, /*CAN=125kbps*/ \ - {7, TQ_x_16}, /*CAN=250kbps*/ \ - {4, TQ_x_14}, /*CAN=500kbps*/ \ - {5, TQ_x_7 }, /*CAN=800kbps*/ \ - {2, TQ_x_14} /*CAN=1000kbps*/ - #elif CO_FSYS == 64000 - #define CO_CANbitRateDataInitializers \ - {64, TQ_x_25}, /*Not possible*/ \ - {64, TQ_x_25}, /*CAN=20kbps*/ \ - {40, TQ_x_16}, /*CAN=50kbps*/ \ - {16, TQ_x_16}, /*CAN=125kbps*/ \ - {8, TQ_x_16}, /*CAN=250kbps*/ \ - {4, TQ_x_16}, /*CAN=500kbps*/ \ - {2, TQ_x_20}, /*CAN=800kbps*/ \ - {2, TQ_x_16} /*CAN=1000kbps*/ - #elif CO_FSYS == 72000 - #define CO_CANbitRateDataInitializers \ - {40, TQ_x_18}, /*Not possible*/ \ - {40, TQ_x_18}, /*Not possible*/ \ - {40, TQ_x_18}, /*CAN=50kbps*/ \ - {16, TQ_x_18}, /*CAN=125kbps*/ \ - {8, TQ_x_18}, /*CAN=250kbps*/ \ - {4, TQ_x_18}, /*CAN=500kbps*/ \ - {3, TQ_x_15}, /*CAN=800kbps*/ \ - {2, TQ_x_18} /*CAN=1000kbps*/ - #elif CO_FSYS == 80000 - #define CO_CANbitRateDataInitializers \ - {40, TQ_x_20}, /*Not possible*/ \ - {40, TQ_x_20}, /*Not possible*/ \ - {40, TQ_x_20}, /*CAN=50kbps*/ \ - {16, TQ_x_20}, /*CAN=125kbps*/ \ - {8, TQ_x_20}, /*CAN=250kbps*/ \ - {4, TQ_x_20}, /*CAN=500kbps*/ \ - {2, TQ_x_25}, /*CAN=800kbps*/ \ - {2, TQ_x_20} /*CAN=1000kbps*/ - #else - #error define_CO_FSYS CO_FSYS not supported - #endif -#endif - - -/* Structure contains timing coefficients for CAN module. - * - * CAN baud rate is calculated from following equations: - * Fsys - System clock (MAX 80MHz for PIC32MX) - * TQ = 2 * BRP / Fsys - Time Quanta - * BaudRate = 1 / (TQ * K) - Can bus Baud Rate - * K = SJW + PROP + PhSeg1 + PhSeg2 - Number of Time Quantas - */ -typedef struct{ - uint8_t BRP; /* (1...64) Baud Rate Prescaler */ - uint8_t SJW; /* (1...4) SJW time */ - uint8_t PROP; /* (1...8) PROP time */ - uint8_t phSeg1; /* (1...8) Phase Segment 1 time */ - uint8_t phSeg2; /* (1...8) Phase Segment 2 time */ -}CO_CANbitRateData_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. */ -typedef struct{ - unsigned ident :11; /* Standard Identifier */ - unsigned FILHIT :5; /* Filter hit, see PIC32MX documentation */ - unsigned CMSGTS :16; /* CAN message timestamp, see PIC32MX documentation */ - unsigned DLC :4; /* Data length code (bits 0...3) */ - unsigned :5; - unsigned RTR :1; /* Remote Transmission Request bit */ - unsigned :22; - uint8_t data[8]; /* 8 data bytes */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint32_t CMSGSID; /* Equal to register in transmit message buffer. Includes standard Identifier */ - uint32_t CMSGEID; /* Equal to register in transmit message buffer. Includes data length code and RTR */ - uint8_t data[8]; - volatile bool_t bufferFull; - volatile bool_t syncFlag; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - void *CANdriverState; - CO_CANrxMsg_t CANmsgBuff[33]; /* PIC32 specific: CAN message buffer for CAN module. 32 buffers for receive, 1 buffer for transmit */ - uint8_t CANmsgBuffSize; /* PIC32 specific: Size of the above buffer == 33. Take care initial value! */ - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; -}CO_CANmodule_t; - - -/* Endianes */ -#define CO_LITTLE_ENDIAN - - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. - * - * PIC32MX CAN FIFO configuration: Two FIFOs are used. First FIFO is 32 messages - * long and is used for reception. Second is used for transmission and is 1 - * message long. Format of message in fifo is described by CO_CANrxMsg_t for - * both: receiving and transmitting messages. However transmitting messages does - * not use all structure members. - */ -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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* CAN interrupt receives and transmits CAN messages. - * - * Function must be called directly from _C1Interrupt or _C2Interrupt with - * high priority. - */ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule); - - -#endif diff --git a/stack/PIC32/eeprom.c b/stack/PIC32/eeprom.c deleted file mode 100644 index c5829f3c..00000000 --- a/stack/PIC32/eeprom.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Eeprom object for Microchip PIC32MX microcontroller. - * - * @file eeprom.c - * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "CO_driver.h" -#include "CO_SDO.h" -#include "CO_Emergency.h" -#include "eeprom.h" -#include "crc16-ccitt.h" - - -/* Eeprom *********************************************************************/ -#define EE_SS_TRIS() TRISGCLR = 0x0200 -#define EE_SSLow() PORTGCLR = 0x0200 -#define EE_SSHigh() PORTGSET = 0x0200 -#define SPIBUF SPI2ABUF -#define SPICON SPI2ACON -#define SPISTAT SPI2ASTAT -#define SPISTATbits SPI2ASTATbits -#define SPIBRG SPI2ABRG -static void EE_SPIwrite(uint8_t *tx, uint8_t *rx, uint8_t len); -static void EE_writeEnable(); -static void EE_writeByteNoWait(uint8_t data, uint32_t addr); -static uint8_t EE_readByte(uint32_t addr); -static void EE_writeBlock(uint8_t *data, uint32_t addr, uint32_t len); -static void EE_readBlock(uint8_t *data, uint32_t addr, uint32_t len); -static uint8_t EE_verifyBlock(uint8_t *data, uint32_t addr, uint32_t len); -static void EE_writeStatus(uint8_t data); -static uint8_t EE_readStatus(); -#define EE_isWriteInProcess() (EE_readStatus() & 0x01) /* True if write is in process. */ - -static uint32_t tmpU32; - - -/* Store parameters ***********************************************************/ -static CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg){ - CO_EE_t *ee; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - ee = (CO_EE_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - if(!ODF_arg->reading){ - /* don't change the old value */ - CO_memcpy(ODF_arg->data, (const uint8_t*)ODF_arg->ODdataStorage, 4U); - - if(ODF_arg->subIndex == 1){ - if(value == 0x65766173UL){ - EE_MBR_t MBR; - - /* read the master boot record from the last page in eeprom */ - EE_readBlock((uint8_t*)&MBR, EE_SIZE - EE_PAGE_SIZE, sizeof(MBR)); - /* if EEPROM is not yet initilalized, enable it now */ - if(MBR.OD_EEPROMSize != ee->OD_EEPROMSize) - ee->OD_EEPROMWriteEnable = true; - - /* prepare MBR */ - MBR.CRC = crc16_ccitt(ee->OD_ROMAddress, ee->OD_ROMSize, 0); - MBR.OD_EEPROMSize = ee->OD_EEPROMSize; - MBR.OD_ROMSize = ee->OD_ROMSize; - - /* write to eeprom (blocking function) */ - EE_writeStatus(0); /* unprotect data */ - EE_writeBlock((uint8_t*)&MBR, EE_SIZE - EE_PAGE_SIZE, sizeof(MBR)); - EE_writeBlock(ee->OD_ROMAddress, EE_SIZE/2, ee->OD_ROMSize); - EE_writeStatus(0x88); /* protect data */ - - /* verify data and MBR and status register */ - if( EE_verifyBlock(ee->OD_ROMAddress, EE_SIZE/2, ee->OD_ROMSize) == 1 - && EE_verifyBlock((uint8_t*)&MBR, EE_SIZE - EE_PAGE_SIZE, sizeof(MBR)) == 1 - && (EE_readStatus()&0x8C) == 0x88){ - /* write successfull */ - return CO_SDO_AB_NONE; - } - return CO_SDO_AB_HW; - } - else - return CO_SDO_AB_DATA_TRANSF; - } - } - - return ret; -} - - -/* Restore default parameters *************************************************/ -static CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg){ - CO_EE_t *ee; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - ee = (CO_EE_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - if(!ODF_arg->reading){ - /* don't change the old value */ - CO_memcpy(ODF_arg->data, (const uint8_t*)ODF_arg->ODdataStorage, 4U); - - if(ODF_arg->subIndex >= 1U){ - if(value == 0x64616F6CUL){ - EE_MBR_t MBR; - - /* read the master boot record from the last page in eeprom */ - EE_readBlock((uint8_t*)&MBR, EE_SIZE - EE_PAGE_SIZE, sizeof(MBR)); - /* verify MBR for safety */ - if(EE_verifyBlock((uint8_t*)&MBR, EE_SIZE - EE_PAGE_SIZE, sizeof(MBR)) == 0) - return CO_SDO_AB_HW; - - switch(ODF_arg->subIndex){ - case 0x01: MBR.OD_ROMSize = 0; break; /* clear the ROM */ - /* following don't work, if not enabled in object dictionary */ - case 0x77: MBR.OD_ROMSize = ee->OD_ROMSize; break; /* restore the ROM back */ - case 0x7F: MBR.OD_EEPROMSize = 0; break; /* clear EEPROM */ - default: return 0x06090011; /* Sub-index does not exist. */ - } - - /* write changed MBR */ - EE_writeStatus(0); /* unprotect data */ - EE_writeBlock((uint8_t*)&MBR, EE_SIZE - EE_PAGE_SIZE, sizeof(MBR)); - EE_writeStatus(0x88); /* protect data */ - - /* verify MBR and status register */ - if(EE_verifyBlock((uint8_t*)&MBR, EE_SIZE - EE_PAGE_SIZE, sizeof(MBR)) == 1 - && (EE_readStatus()&0x8C) == 0x88){ - /* write successfull */ - return CO_SDO_AB_NONE; - } - else{ - return CO_SDO_AB_HW; - } - } - else - return CO_SDO_AB_DATA_TRANSF; - } - } - - return ret; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_EE_init_1( - CO_EE_t *ee, - uint8_t *OD_EEPROMAddress, - uint32_t OD_EEPROMSize, - uint8_t *OD_ROMAddress, - uint32_t OD_ROMSize) -{ - - /* verify arguments */ - if(ee==NULL || OD_EEPROMAddress==NULL || OD_ROMAddress==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure SPI port for use with eeprom */ - SPICON = 0; /* Stops and restes the SPI */ - SPISTAT = 0; - tmpU32 = SPIBUF; /* Clear the receive buffer */ - SPIBRG = 4; /* Clock = FPB / ((4+1) * 2) */ - SPICON = 0x00018120; /* MSSEN = 0 - Master mode slave select enable bit */ - /* ENHBUF(bit16) = 1 - Enhanced buffer enable bit */ - /* Enable SPI, 8-bit mode */ - /* SMP = 0, CKE = 1, CKP = 0 */ - /* MSTEN = 1 - master mode enable bit */ - - /* Set IOs directions for EEPROM SPI */ - EE_SSHigh(); - EE_SS_TRIS(); - - /* verify variables */ - if(OD_ROMSize > (EE_SIZE/2 - EE_PAGE_SIZE)) OD_ROMSize = EE_SIZE/2 - EE_PAGE_SIZE; - if(OD_EEPROMSize > EE_SIZE/2) OD_EEPROMSize = EE_SIZE/2; - - /* configure object variables */ - ee->OD_EEPROMAddress = OD_EEPROMAddress; - ee->OD_EEPROMSize = OD_EEPROMSize; - ee->OD_ROMAddress = OD_ROMAddress; - ee->OD_ROMSize = OD_ROMSize; - ee->OD_EEPROMCurrentIndex = 0; - ee->OD_EEPROMWriteEnable = false; - - /* read the master boot record from the last page in eeprom */ - EE_MBR_t MBR; - EE_readBlock((uint8_t*)&MBR, EE_SIZE - EE_PAGE_SIZE, sizeof(MBR)); - - /* read the CO_OD_EEPROM from EEPROM, first verify, if data are OK */ - if(MBR.OD_EEPROMSize == OD_EEPROMSize && (MBR.OD_ROMSize == OD_ROMSize || MBR.OD_ROMSize == 0)){ - uint32_t firstWordRAM = *((uint32_t*)OD_EEPROMAddress); - uint32_t firstWordEE, lastWordEE; - EE_readBlock((uint8_t*)&firstWordEE, 0, 4); - EE_readBlock((uint8_t*)&lastWordEE, OD_EEPROMSize-4, 4); - if(firstWordRAM == firstWordEE && firstWordRAM == lastWordEE){ - EE_readBlock(OD_EEPROMAddress, 0, OD_EEPROMSize); - ee->OD_EEPROMWriteEnable = true; - } - else{ - return CO_ERROR_DATA_CORRUPT; - } - } - else{ - return CO_ERROR_DATA_CORRUPT; - } - - /* read the CO_OD_ROM from EEPROM and verify CRC */ - if(MBR.OD_ROMSize == OD_ROMSize){ - EE_readBlock(OD_ROMAddress, EE_SIZE/2, OD_ROMSize); - if(crc16_ccitt(OD_ROMAddress, OD_ROMSize, 0) != MBR.CRC){ - return CO_ERROR_CRC; - } - } - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_EE_init_2( - CO_EE_t *ee, - CO_ReturnError_t eeStatus, - CO_SDO_t *SDO, - CO_EM_t *em) -{ - CO_OD_configure(SDO, OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)ee, 0, 0U); - CO_OD_configure(SDO, OD_H1011_REST_PARAM_FUNC, CO_ODF_1011, (void*)ee, 0, 0U); - if(eeStatus != CO_ERROR_NO){ - CO_errorReport(em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)eeStatus); - } -} - - -/******************************************************************************/ -void CO_EE_process(CO_EE_t *ee){ - if(ee && ee->OD_EEPROMWriteEnable && !EE_isWriteInProcess()){ - /* verify next word */ - if(++ee->OD_EEPROMCurrentIndex == ee->OD_EEPROMSize) ee->OD_EEPROMCurrentIndex = 0; - unsigned int i = ee->OD_EEPROMCurrentIndex; - - /* read eeprom */ - uint8_t RAMdata = ee->OD_EEPROMAddress[i]; - uint8_t EEdata = EE_readByte(i); - - /* if bytes in EEPROM and in RAM are different, then write to EEPROM */ - if(EEdata != RAMdata) - EE_writeByteNoWait(RAMdata, i); - } -} - - -/******************************************************************************/ -/* EEPROM 25LC128 on SPI ******************************************************/ -/******************************************************************************/ -#define EE_CMD_READ (unsigned)0b00000011 -#define EE_CMD_WRITE (unsigned)0b00000010 -#define EE_CMD_WRDI (unsigned)0b00000100 -#define EE_CMD_WREN (unsigned)0b00000110 -#define EE_CMD_RDSR (unsigned)0b00000101 -#define EE_CMD_WRSR (unsigned)0b00000001 - - -/** - * Function - EE_SPIwrite - * - * Write to SPI and at the same time read from SPI. - * - * PIC32 used 16bytes long FIFO buffer with SPI. SPI module is initailized in - * CO_EE_init. - * - * @param tx Ponter to transmitting data. If NULL, zeroes will be transmitted. - * @param rx Ponter to data buffer, where received data wile be stored. - * If null, Received data will be disregarded. - * @param len Length of data buffers. Max 16. - */ -static void EE_SPIwrite(uint8_t *tx, uint8_t *rx, uint8_t len){ - uint32_t i; - - /* write bytes into SPI_TXB fifo buffer */ - if(tx) for(i=0; i> 8); - buf[2] = (uint8_t) addr; - buf[3] = data; - - EE_SSLow(); - EE_SPIwrite(buf, 0, 4); - EE_SSHigh(); -} - - -/* - * Read one byte of data from eeprom. - * - * @param addr Address in eeprom, where data will be written. - * - * @return Data byte read. - */ -static uint8_t EE_readByte(uint32_t addr){ - uint8_t bufTx[4]; - uint8_t bufRx[4]; - - bufTx[0] = EE_CMD_READ; - bufTx[1] = (uint8_t) (addr >> 8); - bufTx[2] = (uint8_t) addr; - bufTx[3] = 0; - - EE_SSLow(); - EE_SPIwrite(bufTx, bufRx, 4); - EE_SSHigh(); - - return bufRx[3]; -} - - -/* - * Write block of data to eeprom. It is blockung function, so it waits, untill - * all data are written. - * - * @param data Pointer to data to be written. - * @param addr Address in eeprom, where data will be written. *If data are - * stored accross multiple pages, address must be aligned with page.* - * @param len Length of the data block. - */ -static void EE_writeBlock(uint8_t *data, uint32_t addr, uint32_t len){ - - #if EE_PAGE_SIZE != 64 - #error incompatibility in function - #endif - - while(EE_isWriteInProcess()); - - while(len){ - uint8_t buf[3]; - uint32_t i; - - EE_writeEnable(); - - buf[0] = EE_CMD_WRITE; - buf[1] = (uint8_t) (addr >> 8); - buf[2] = (uint8_t) addr; - - EE_SSLow(); - EE_SPIwrite(buf, 0, 3); - - for(i=0; i<4; i++){ - if(len > 16){ - EE_SPIwrite(data, 0, 16); - len -= 16; - data += 16; - } - else{ - EE_SPIwrite(data, 0, len); - len = 0; - break; - } - } - EE_SSHigh(); - - /* wait for completion of the write operation */ - i=EE_readStatus(); - while(EE_isWriteInProcess()); - addr += EE_PAGE_SIZE; - } -} - - -/* - * Read block of data from eeprom. - * - * @param data Pointer to data buffer, where data will be stored. - * @param addr Address in eeprom, from where data will be read. - * @param len Length of the data block to be read. - */ -static void EE_readBlock(uint8_t *data, uint32_t addr, uint32_t len){ - uint8_t buf[3]; - - buf[0] = EE_CMD_READ; - buf[1] = (uint8_t) (addr >> 8); - buf[2] = (uint8_t) addr; - - EE_SSLow(); - EE_SPIwrite(buf, 0, 3); - - while(len){ - if(len > 16){ - EE_SPIwrite(0, data, 16); - len -= 16; - data += 16; - } - else{ - EE_SPIwrite(0, data, len); - len = 0; - } - } - - EE_SSHigh(); -} - - -/* - * Compare block of data with data stored in eeprom. - * - * @param data Pointer to data buffer, which will be compared. - * @param addr Address of data in eeprom, which will be compared. - * @param len Length of the data block to be compared. - * - * @return 0 - comparision failed. - * @return 1 - data are equal. - */ -static uint8_t EE_verifyBlock(uint8_t *data, uint32_t addr, uint32_t len){ - uint8_t buf[16]; - uint8_t equal = 1; - - buf[0] = EE_CMD_READ; - buf[1] = (uint8_t) (addr >> 8); - buf[2] = (uint8_t) addr; - - EE_SSLow(); - EE_SPIwrite(buf, 0, 3); - - while(len){ - if(len > 16){ - uint8_t i; - EE_SPIwrite(0, buf, 16); - for(i=0; i<16; i++) if(buf[i] != data[i]) equal = 0; - len -= 16; - data += 16; - } - else{ - uint8_t i; - EE_SPIwrite(0, buf, len); - for(i=0; i. - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef EEPROM_H -#define EEPROM_H - - -/* For documentation see file drvTemplate/eeprom.h */ - - -/* - * PIC32MX specific - * - * 25LC128 eeprom from Microchip is used connected on SPI2A. - * - * Two blocks of CANopen Object Dictionary data are stored in eeprom: - * OD_EEPROM - Stored is from eeprom address 0. Data are stored automatically on - * change. No data corruption control is made. - * OD_ROM - Stored from upper half eeprom address. Data are protected from - * accidental write, can also be hardware protected. Data integrity - * is verified with CRC. - * Data are stored on special CANopen command - Writing 0x65766173 - * into Object dictionary (index 1010, subindex 1). Default values - * are restored after reset, if writing 0x64616F6C into (1011, 1). - */ - - -/* Constants */ -#define EE_SIZE 0x4000 -#define EE_PAGE_SIZE 64 - - -/* Master boot record is stored on the last page in eeprom */ -typedef struct{ - uint32_t CRC; /* CRC code of the OD_ROM block */ - uint32_t OD_EEPROMSize; /* Size of OD_EEPROM block */ - uint32_t OD_ROMSize; /* Size of OD_ROM block */ -}EE_MBR_t; - - -/* Eeprom object */ -typedef struct{ - uint8_t *OD_EEPROMAddress; - uint32_t OD_EEPROMSize; - uint8_t *OD_ROMAddress; - uint32_t OD_ROMSize; - uint32_t OD_EEPROMCurrentIndex; - bool_t OD_EEPROMWriteEnable; - -}CO_EE_t; - - -/* First part of eeprom initialization. - * - * Allocate memory for object, configure SPI port for use with 25LCxxx, read - * eeprom and store to OD_EEPROM and OD_ROM. - */ -CO_ReturnError_t CO_EE_init_1( - CO_EE_t *ee, - uint8_t *OD_EEPROMAddress, - uint32_t OD_EEPROMSize, - uint8_t *OD_ROMAddress, - uint32_t OD_ROMSize); - - -/* Second part of eeprom initialization. */ -void CO_EE_init_2( - CO_EE_t *ee, - CO_ReturnError_t eeStatus, - CO_SDO_t *SDO, - CO_EM_t *em); - - -/* Process eeprom object. */ -void CO_EE_process(CO_EE_t *ee); - - -#endif diff --git a/stack/PIC32/main_PIC32.c b/stack/PIC32/main_PIC32.c deleted file mode 100644 index c06e9058..00000000 --- a/stack/PIC32/main_PIC32.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * CANopen main program file for PIC32 microcontroller. - * - * @file main_PIC32.c - * @author Janez Paternoster - * @copyright 2010 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#define CO_FSYS 64000 /* (8MHz Quartz used) */ -#define CO_PBCLK 32000 /* peripheral bus clock */ - - -#include "CANopen.h" -#include "application.h" -#ifdef USE_EEPROM - #include "eeprom.h" /* 25LC128 eeprom chip connected to SPI2A port. */ -#endif -#include /* for interrupts */ -#include /* for interrupts */ - - -/* Configuration bits */ - #pragma config FVBUSONIO = OFF /* USB VBUS_ON Selection (OFF = pin is controlled by the port function) */ - #pragma config FUSBIDIO = OFF /* USB USBID Selection (OFF = pin is controlled by the port function) */ - #pragma config UPLLEN = OFF /* USB PLL Enable */ - #pragma config UPLLIDIV = DIV_12 /* USB PLL Input Divider */ - #pragma config FCANIO = ON /* CAN IO Pin Selection (ON = default CAN IO Pins) */ - #pragma config FETHIO = ON /* Ethernet IO Pin Selection (ON = default Ethernet IO Pins) */ - #pragma config FMIIEN = ON /* Ethernet MII Enable (ON = MII enabled) */ - #pragma config FSRSSEL = PRIORITY_7 /* SRS (Shadow registers set) Select */ - #pragma config POSCMOD = XT /* Primary Oscillator */ - #pragma config FSOSCEN = OFF /* Secondary oscillator Enable */ - #pragma config FNOSC = PRIPLL /* Oscillator Selection */ - #pragma config FPLLIDIV = DIV_2 /* PLL Input Divider */ - #pragma config FPLLMUL = MUL_16 /* PLL Multiplier */ - #pragma config FPLLODIV = DIV_1 /* PLL Output Divider Value */ - #pragma config FPBDIV = DIV_2 /* Bootup PBCLK divider */ - #pragma config FCKSM = CSDCMD /* Clock Switching and Monitor Selection */ - #pragma config OSCIOFNC = OFF /* CLKO Enable */ - #pragma config IESO = OFF /* Internal External Switch Over */ -#pragma config FWDTEN = OFF /* Watchdog Timer Enable */ - #pragma config WDTPS = PS1024 /* Watchdog Timer Postscale Select (in milliseconds) */ -#pragma config CP = OFF /* Code Protect Enable */ - #pragma config BWP = ON /* Boot Flash Write Protect */ - #pragma config PWP = PWP256K /* Program Flash Write Protect */ -#ifdef CO_ICS_PGx1 - #pragma config ICESEL = ICS_PGx1 /* ICE/ICD Comm Channel Select */ -#else - #pragma config ICESEL = ICS_PGx2 /* ICE/ICD Comm Channel Select (2 for Explorer16 board) */ -#endif - #pragma config DEBUG = ON /* Background Debugger Enable */ - - -/* macros */ - #define CO_TMR_TMR TMR2 /* TMR register */ - #define CO_TMR_PR PR2 /* Period register */ - #define CO_TMR_CON T2CON /* Control register */ - #define CO_TMR_ISR_FLAG IFS0bits.T2IF /* Interrupt Flag bit */ - #define CO_TMR_ISR_PRIORITY IPC2bits.T2IP /* Interrupt Priority */ - #define CO_TMR_ISR_ENABLE IEC0bits.T2IE /* Interrupt Enable bit */ - - #define CO_CAN_ISR() void __ISR(_CAN_1_VECTOR, IPL5SOFT) CO_CAN1InterruptHandler(void) - #define CO_CAN_ISR_FLAG IFS1bits.CAN1IF /* Interrupt Flag bit */ - #define CO_CAN_ISR_PRIORITY IPC11bits.CAN1IP /* Interrupt Priority */ - #define CO_CAN_ISR_ENABLE IEC1bits.CAN1IE /* Interrupt Enable bit */ - - #define CO_CAN_ISR2() void __ISR(_CAN_2_VECTOR, IPL5SOFT) CO_CAN2InterruptHandler(void) - #define CO_CAN_ISR2_FLAG IFS1bits.CAN2IF /* Interrupt Flag bit */ - #define CO_CAN_ISR2_PRIORITY IPC11bits.CAN2IP /* Interrupt Priority */ - #define CO_CAN_ISR2_ENABLE IEC1bits.CAN2IE /* Interrupt Enable bit */ - - #define CO_clearWDT() (WDTCONSET = _WDTCON_WDTCLR_MASK) - -/* Global variables and objects */ - volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */ - const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; - static uint32_t tmpU32; -#ifdef USE_EEPROM - CO_EE_t CO_EEO; /* Eeprom object */ -#endif - - -/* main ***********************************************************************/ -int main (void){ - CO_NMT_reset_cmd_t reset = CO_RESET_NOT; - - /* Configure system for maximum performance. plib is necessary for that.*/ - /* SYSTEMConfig(CO_FSYS*1000, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE); */ - - /* Enable system multi vectored interrupts */ - INTCONbits.MVEC = 1; - __builtin_enable_interrupts(); - - /* Disable JTAG and trace port */ - DDPCONbits.JTAGEN = 0; - DDPCONbits.TROEN = 0; - - - /* Verify, if OD structures have proper alignment of initial values */ - if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) while(1) CO_clearWDT(); - if(CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) while(1) CO_clearWDT(); - if(CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) while(1) CO_clearWDT(); - - - /* initialize EEPROM - part 1 */ -#ifdef USE_EEPROM - CO_ReturnError_t eeStatus = CO_EE_init_1(&CO_EEO, (uint8_t*) &CO_OD_EEPROM, sizeof(CO_OD_EEPROM), - (uint8_t*) &CO_OD_ROM, sizeof(CO_OD_ROM)); -#endif - - - programStart(); - - - /* increase variable each startup. Variable is stored in eeprom. */ - OD_powerOnCounter++; - - - while(reset != CO_RESET_APP){ -/* CANopen communication reset - initialize CANopen objects *******************/ - CO_ReturnError_t err; - uint16_t timer1msPrevious; - uint16_t TMR_TMR_PREV = 0; - uint8_t nodeId; - uint16_t CANBitRate; - - /* disable CAN and CAN interrupts */ - CO_CAN_ISR_ENABLE = 0; - CO_CAN_ISR2_ENABLE = 0; - - /* Read CANopen Node-ID and CAN bit-rate from object dictionary */ - nodeId = OD_CANNodeID; - if(nodeId<1 || nodeId>127) nodeId = 0x10; - CANBitRate = OD_CANBitRate;/* in kbps */ - - /* initialize CANopen */ - err = CO_init(ADDR_CAN1, nodeId, CANBitRate); - if(err != CO_ERROR_NO){ - while(1) CO_clearWDT(); - /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */ - } - - - /* initialize eeprom - part 2 */ -#ifdef USE_EEPROM - CO_EE_init_2(&CO_EEO, eeStatus, CO->SDO[0], CO->em); -#endif - - - /* initialize variables */ - timer1msPrevious = CO_timer1ms; - OD_performance[ODA_performance_mainCycleMaxTime] = 0; - OD_performance[ODA_performance_timerCycleMaxTime] = 0; - reset = CO_RESET_NOT; - - - - /* Configure Timer interrupt function for execution every 1 millisecond */ - CO_TMR_CON = 0; - CO_TMR_TMR = 0; - #if CO_PBCLK > 65000 - #error wrong timer configuration - #endif - CO_TMR_PR = CO_PBCLK - 1; /* Period register */ - CO_TMR_CON = 0x8000; /* start timer (TON=1) */ - CO_TMR_ISR_FLAG = 0; /* clear interrupt flag */ - CO_TMR_ISR_PRIORITY = 3; /* interrupt - set lower priority than CAN (set the same value in interrupt) */ - - /* Configure CAN1 Interrupt (Combined) */ - CO_CAN_ISR_FLAG = 0; /* CAN1 Interrupt - Clear flag */ - CO_CAN_ISR_PRIORITY = 5; /* CAN1 Interrupt - Set higher priority than timer (set the same value in '#define CO_CAN_ISR_PRIORITY') */ - CO_CAN_ISR2_FLAG = 0; /* CAN2 Interrupt - Clear flag */ - CO_CAN_ISR2_PRIORITY = 5; /* CAN Interrupt - Set higher priority than timer (set the same value in '#define CO_CAN_ISR_PRIORITY') */ - - - communicationReset(); - - - /* start CAN and enable interrupts */ - CO_CANsetNormalMode(CO->CANmodule[0]); - CO_TMR_ISR_ENABLE = 1; - CO_CAN_ISR_ENABLE = 1; - -#if CO_NO_CAN_MODULES >= 2 - CO_CANsetNormalMode(CO->CANmodule[1]); - CO_CAN_ISR2_ENABLE = 1; -#endif - - - while(reset == CO_RESET_NOT){ -/* loop for normal program execution ******************************************/ - uint16_t timer1msCopy, timer1msDiff; - - CO_clearWDT(); - - - /* calculate cycle time for performance measurement */ - timer1msCopy = CO_timer1ms; - timer1msDiff = timer1msCopy - timer1msPrevious; - timer1msPrevious = timer1msCopy; - uint16_t t0 = CO_TMR_TMR; - uint16_t t = t0; - if(t >= TMR_TMR_PREV){ - t = t - TMR_TMR_PREV; - t = (timer1msDiff * 100) + (t / (CO_PBCLK / 100)); - } - else if(timer1msDiff){ - t = TMR_TMR_PREV - t; - t = (timer1msDiff * 100) - (t / (CO_PBCLK / 100)); - } - else t = 0; - OD_performance[ODA_performance_mainCycleTime] = t; - if(t > OD_performance[ODA_performance_mainCycleMaxTime]) - OD_performance[ODA_performance_mainCycleMaxTime] = t; - TMR_TMR_PREV = t0; - - - /* Application asynchronous program */ - programAsync(timer1msDiff); - - CO_clearWDT(); - - - /* CANopen process */ - reset = CO_process(CO, timer1msDiff, NULL); - - CO_clearWDT(); - - -#ifdef USE_EEPROM - CO_EE_process(&CO_EEO); -#endif - } - } - - -/* program exit ***************************************************************/ -// CO_DISABLE_INTERRUPTS(); - - /* delete objects from memory */ - programEnd(); - CO_delete(ADDR_CAN1); - - /* reset */ - SYSKEY = 0x00000000; - SYSKEY = 0xAA996655; - SYSKEY = 0x556699AA; - RSWRSTSET = 1; - tmpU32 = RSWRST; - while(1); -} - - -/* timer interrupt function executes every millisecond ************************/ -#ifndef USE_EXTERNAL_TIMER_1MS_INTERRUPT -void __ISR(_TIMER_2_VECTOR, IPL3SOFT) CO_TimerInterruptHandler(void){ - - CO_TMR_ISR_FLAG = 0; - - CO_timer1ms++; - - if(CO->CANmodule[0]->CANnormal) { - bool_t syncWas; - int i; - - /* Process Sync */ - syncWas = CO_process_SYNC(CO, 1000); - - /* Read inputs */ - CO_process_RPDO(CO, syncWas); - - /* Further I/O or nonblocking application code may go here. */ -#if CO_NO_TRACE > 0 - OD_time.epochTimeOffsetMs++; - for(i=0; itrace[i], OD_time.epochTimeOffsetMs); - } -#endif - program1ms(); - - /* Write outputs */ - CO_process_TPDO(CO, syncWas, 1000); - - /* verify timer overflow */ - if(CO_TMR_ISR_FLAG == 1){ - CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0); - CO_TMR_ISR_FLAG = 0; - } - } - - /* calculate cycle time for performance measurement */ - uint16_t t = CO_TMR_TMR / (CO_PBCLK / 100); - OD_performance[ODA_performance_timerCycleTime] = t; - if(t > OD_performance[ODA_performance_timerCycleMaxTime]) - OD_performance[ODA_performance_timerCycleMaxTime] = t; -} -#endif - - -/* CAN interrupt function *****************************************************/ -CO_CAN_ISR(){ - CO_CANinterrupt(CO->CANmodule[0]); - /* Clear combined Interrupt flag */ - CO_CAN_ISR_FLAG = 0; -} - -#if CO_NO_CAN_MODULES >= 2 -CO_CAN_ISR2(){ - CO_CANinterrupt(CO->CANmodule[1]); - /* Clear combined Interrupt flag */ - CO_CAN_ISR2_FLAG = 0; -} -#endif diff --git a/stack/SAM3X/CO_Flash.c b/stack/SAM3X/CO_Flash.c deleted file mode 100644 index d204ad17..00000000 --- a/stack/SAM3X/CO_Flash.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Atmel SAM3 flash support for CANopen stack - * - * @file CO_Flash.c - * @author Janez Paternoster - * @author Olof Larsson - * @copyright 2014 Janez Paternoster - * - * 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. - */ - -//============================================================================ -// INCLUDES -//============================================================================ -#include "CANopen.h" -#include "asf.h" - -//============================================================================ -// DEFINES -//============================================================================ -#define PARAM_STORE_PASSWORD 0x65766173 -#define PARAM_RESTORE_PASSWORD 0x64616F6C - -#define DEBUG 0 -#define CO_DBG_PRINT(...) do { if (DEBUG) printf(__VA_ARGS__); } while (0) - -#define LAST_PAGE_ADDRESS (IFLASH1_ADDR + IFLASH1_SIZE - (2*IFLASH1_PAGE_SIZE)) -#define PAGES_PER_FLASH_AREA 6 -#define CO_OD_FLASH_PARAM_DEFAULT LAST_PAGE_ADDRESS - (1*PAGES_PER_FLASH_AREA*IFLASH1_PAGE_SIZE) -#define CO_OD_FLASH_PARAM_RUNTIME LAST_PAGE_ADDRESS - (2*PAGES_PER_FLASH_AREA*IFLASH1_PAGE_SIZE) -#define IFLASH_PAGE_SIZE IFLASH1_PAGE_SIZE - -#define CO_UNUSED(v) (void)(v) - -//============================================================================ -// LOCAL DATA -//============================================================================ -extern struct sCO_OD_ROM CO_OD_ROM; - -enum CO_OD_H1010_StoreParam_Sub -{ - OD_H1010_STORE_PARAM_COUNT, - OD_H1010_STORE_PARAM_ALL, - OD_H1010_STORE_PARAM_COMM, - OD_H1010_STORE_PARAM_APP, - OD_H1010_STORE_PARAM_MANUFACTURER, - OD_H1010_STORE_PARAM_RESERVED = 0x80 -}; - -enum CO_OD_H1011_RestoreDefaultParam_Sub -{ - OD_H1011_RESTORE_PARAM_COUNT, - OD_H1011_RESTORE_PARAM_ALL, - OD_H1011_RESTORE_PARAM_COMM, - OD_H1011_RESTORE_PARAM_APP, - OD_H1011_RESTORE_PARAM_MANUFACTURER, - OD_H1011_RESTORE_PARAM_RESERVED = 0x80 -}; - -enum CO_StorageFunctionality_Flags -{ - SAVES_PARAM_ON_COMMAND = 0x01, - SAVES_PARAM_AUTONOMOUSLY = 0x02 -}; - -enum CO_RestoreFunctionality_Flags -{ - RESTORES_PARAMETERS = 0x01 -}; - -//============================================================================ -/** -* Store parameters of object dictionary into flash memory. -* \param[in] FlashAddress Use CO_OD_Flash_Adress for the normal parameter -* block and CO_OD_Flash_Default_Param for the -* default parameters -*/ -static CO_SDO_abortCode_t storeParameters(uint32_t FlashAddress, uint8_t ParametersSub) -{ - uint32_t ret; - - CO_UNUSED(ParametersSub); - CO_DBG_PRINT("Store parameters\n"); - - // Initialize flash, 6 wait states for flash writing. - if ((ret = flash_init(FLASH_ACCESS_MODE_128, 6)) != FLASH_RC_OK) - { - CO_DBG_PRINT("Flash initialization error %u\n\r", ret); - return CO_SDO_AB_HW; - } - - // Unlock flash - if ((ret = flash_unlock(FlashAddress, FlashAddress + (IFLASH_PAGE_SIZE*PAGES_PER_FLASH_AREA), 0, 0)) != FLASH_RC_OK) - { - CO_DBG_PRINT("Flash unlock error %u\n\r", ret); - return CO_SDO_AB_HW; - } - - // Erase page - uint32_t erase_flag = 1; - - // Check flash allocation - int32_t bytes_to_write = sizeof(CO_OD_ROM); - - if ((uint32_t)bytes_to_write > (IFLASH_PAGE_SIZE*PAGES_PER_FLASH_AREA)) - { - CO_DBG_PRINT("Flash allocation is %u bytes shy\n\r", (uint32_t)bytes_to_write-(IFLASH_PAGE_SIZE*PAGES_PER_FLASH_AREA)); - return CO_SDO_AB_HW; - } - - // Program data into flash - if (flash_write(FlashAddress, &CO_OD_ROM, min((int32_t)(IFLASH_PAGE_SIZE*PAGES_PER_FLASH_AREA), bytes_to_write), erase_flag) != FLASH_RC_OK) - { - CO_DBG_PRINT("Flash programming error %u\n\r", ret); - return CO_SDO_AB_HW; - } - - return CO_SDO_AB_NONE; -} - -//============================================================================ -/** -* Restore parameters of object dictionary from flash memory. -* \param[in] FlashAddress Use CO_OD_Flash_Adress for the normal parameter -* block and CO_OD_Flash_Default_Param for the -* default parameters -*/ -void flash_read(uint32_t FlashAddress, void* RamAddress, size_t len) -{ - uint8_t *p_flash = (uint8_t *) FlashAddress; - uint32_t idx; - - CO_DBG_PRINT("Restoring parameters..."); - for (idx = 0; idx < min(IFLASH_PAGE_SIZE*PAGES_PER_FLASH_AREA, len); idx++) - { - - ((uint8_t *) RamAddress)[idx] = p_flash[idx]; - } - CO_DBG_PRINT(" %u bytes from 0x%08x\n\r", idx, FlashAddress); -} - -static CO_SDO_abortCode_t restoreParameters(uint32_t FlashAddress, uint8_t ParametersSub) -{ - CO_UNUSED(ParametersSub); - - flash_read(FlashAddress, &CO_OD_ROM, sizeof(CO_OD_ROM)); - - return CO_SDO_AB_NONE; -} - -//============================================================================ -/** -* Access to object dictionary OD_H1010_STORE_PARAM_FUNC -*/ -static CO_SDO_abortCode_t CO_ODF_1010_StoreParam(CO_ODF_arg_t *ODF_arg) -{ - CO_DBG_PRINT("CO_ODF_1010 Sub: %d\n\r", ODF_arg->subIndex); - - uint32_t* value = (uint32_t*)ODF_arg->data; - - if (ODF_arg->reading) - { - if(OD_H1010_STORE_PARAM_ALL == ODF_arg->subIndex) - { - *value = SAVES_PARAM_ON_COMMAND; - } - return CO_SDO_AB_NONE; - } - - if(OD_H1010_STORE_PARAM_ALL != ODF_arg->subIndex) - { - return CO_SDO_AB_NONE; - } - - if (*value != PARAM_STORE_PASSWORD) - { - return CO_SDO_AB_DATA_TRANSF; - } - - return storeParameters(CO_OD_FLASH_PARAM_RUNTIME, ODF_arg->subIndex); -} - -//============================================================================ -/** -* Access to object dictionary OD_H1010_STORE_PARAM_FUNC -*/ -static CO_SDO_abortCode_t CO_ODF_1011_RestoreParam(CO_ODF_arg_t *ODF_arg) -{ - CO_DBG_PRINT("CO_ODF_1010 Sub: %d\n\r", ODF_arg->subIndex); - - uint32_t* value = (uint32_t*)ODF_arg->data; - - if (ODF_arg->reading) - { - if (OD_H1011_RESTORE_PARAM_ALL == ODF_arg->subIndex) - { - *value = RESTORES_PARAMETERS; - } - return CO_SDO_AB_NONE; - } - - if (OD_H1011_RESTORE_PARAM_ALL != ODF_arg->subIndex) - { - return CO_SDO_AB_NONE; - } - - if (*value != PARAM_RESTORE_PASSWORD) - { - return CO_SDO_AB_DATA_TRANSF; - } - - CO_SDO_abortCode_t Result = restoreParameters(CO_OD_FLASH_PARAM_DEFAULT, - ODF_arg->subIndex); - if (Result != CO_SDO_AB_NONE) - { - CO_DBG_PRINT("restoreParameters returned error"); - return Result; - } - - return storeParameters(CO_OD_FLASH_PARAM_RUNTIME, OD_H1011_RESTORE_PARAM_ALL); -} - -//=========================================================================== -/** -* Initialize flash library and data storage in flash -* We use two blocks in flash for data storage. One block is used for the -* default data that will be restored. The default parameters are stored -* at address CO_OD_Flash_Default_Param. The data that will be loaded at -* startup or saved if user modifies data is store at CO_OD_Flash_Adress. -*/ -void CO_FlashInit(void) -{ - // Info on addresses for flash data and default flash data - - CO_DBG_PRINT("Runtime OD flash, address 0x%08x, %u bytes\n\r", CO_OD_FLASH_PARAM_DEFAULT, PAGES_PER_FLASH_AREA*IFLASH1_PAGE_SIZE); - CO_DBG_PRINT("Default OD flash, address 0x%08x, %u bytes\n\r", CO_OD_FLASH_PARAM_DEFAULT, PAGES_PER_FLASH_AREA*IFLASH1_PAGE_SIZE); - - /* Before we can access the data, we need to make sure, that the flash - block are properly initialized. We do this by reading the block into - a local sCO_OD_ROM variable and verifying the FirstWord and LastWord - members. */ - - struct sCO_OD_ROM DefaultObjDicParam; - flash_read(CO_OD_FLASH_PARAM_DEFAULT, &DefaultObjDicParam, sizeof(DefaultObjDicParam)); - - /* If the default parameters are not present in flash, then we know that - we need to create them for later restore. */ - - if ((DefaultObjDicParam.FirstWord != CO_OD_FIRST_LAST_WORD) || - (DefaultObjDicParam.LastWord != CO_OD_FIRST_LAST_WORD)) - { - storeParameters(CO_OD_FLASH_PARAM_RUNTIME, OD_H1010_STORE_PARAM_ALL); - storeParameters(CO_OD_FLASH_PARAM_DEFAULT, OD_H1010_STORE_PARAM_ALL); - } - else - { - restoreParameters(CO_OD_FLASH_PARAM_RUNTIME, OD_H1010_STORE_PARAM_ALL); - } -} - -//=========================================================================== -void CO_FlashRegisterODFunctions(CO_t* CO) -{ - CO_OD_configure(CO->SDO, OD_H1010_STORE_PARAM_FUNC, - CO_ODF_1010_StoreParam, (void*)0, 0, 0); - CO_OD_configure(CO->SDO, OD_H1011_REST_PARAM_FUNC, - CO_ODF_1011_RestoreParam, (void*)0, 0, 0); -} diff --git a/stack/SAM3X/CO_Flash.h b/stack/SAM3X/CO_Flash.h deleted file mode 100644 index ed6a70b0..00000000 --- a/stack/SAM3X/CO_Flash.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Atmel SAM3 flash support for CANopen stack - * - * @file CO_Flash.h - * @author Janez Paternoster - * @author Olof Larsson - * @copyright 2014 Janez Paternoster - * - * 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_FLASH_H -#define CO_FLASH_H - -//============================================================================ -// INCLUDES -//============================================================================ -#include "CANopen.h" - -/** - * Initialize flash library and data storage in flash - * We use two blocks in flash for data storage. One block is used for the - * default data that will be restored. The default parameters are stored - * at address CO_OD_Flash_Default_Param. The data that will be loaded at - * startup or saved if user modifies data. - */ -void CO_FlashInit(void); - -/** - * Register object dictionary functions for parameter storage and restoring - * parameters (Object dictionary index 0x1010 Store Param and 0x1011 Restore - * default param. - */ -void CO_FlashRegisterODFunctions(CO_t* CO); - -#endif diff --git a/stack/SAM3X/CO_driver.c b/stack/SAM3X/CO_driver.c deleted file mode 100644 index b5fa19c9..00000000 --- a/stack/SAM3X/CO_driver.c +++ /dev/null @@ -1,665 +0,0 @@ -/* - * CAN module object for the Atmel SAM3X microcontroller. - * - * @file CO_driver.c - * @author Janez Paternoster - * @author Olof Larsson - * @copyright 2014 Janez Paternoster - * - * 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. - */ - -#include "CO_driver.h" -#include "CO_Emergency.h" - -#include "asf.h" -#include "htc.h" - -#include "sn65hvd234.h" - -#define CO_UNUSED(v) (void)(v) -#define CANMB_TX (CANMB_NUMBER - 1) - -void reset_mailbox_conf(can_mb_conf_t *p_mailbox) -{ - p_mailbox->ul_mb_idx = 0; - p_mailbox->uc_obj_type = 0; - p_mailbox->uc_id_ver = 0; - p_mailbox->uc_length = 0; - p_mailbox->uc_tx_prio = 0; - p_mailbox->ul_status = 0; - p_mailbox->ul_id_msk = 0; - p_mailbox->ul_id = 0; - p_mailbox->ul_fid = 0; - p_mailbox->ul_datal = 0; - p_mailbox->ul_datah = 0; -} - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState) -{ - CO_UNUSED(CANdriverState); -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) -{ - CO_UNUSED(CANmodule->CANdriverState); - - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - uint16_t i; - uint32_t ul_sysclk; - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->CANdriverState = CANdriverState; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = false; - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - CANmodule->em = NULL; - - for(i=0U; iCANdriverState) == CAN0) - { - /* CAN0 Transceiver */ - static sn65hvd234_ctrl_t can0_transceiver; - - /* Initialize CAN0 Transceiver. */ - sn65hvd234_set_rs(&can0_transceiver, PIN_CAN0_TR_RS_IDX); - sn65hvd234_set_en(&can0_transceiver, PIN_CAN0_TR_EN_IDX); - - /* Low power mode is listening only */ - sn65hvd234_disable_low_power(&can0_transceiver); - - /* Enable CAN0 Transceiver */ - sn65hvd234_enable(&can0_transceiver); - - /* Configure CAN timing */ - - /* Enable CAN0 & CAN0 clock. */ - pmc_enable_periph_clk(ID_CAN0); - - ul_sysclk = sysclk_get_cpu_hz(); - - if (can_init(CAN0, ul_sysclk, CANbitRate)) - { - printf("CAN0 initialization is completed\n\r"); - - /* Disable all CAN0 interrupts */ - can_disable_interrupt(CAN0, CAN_DISABLE_ALL_INTERRUPT_MASK); - - /* Configure and enable interrupt of CAN0 */ - NVIC_EnableIRQ(CAN0_IRQn); - } - - can_reset_all_mailbox(CANmodule->CANdriverState); - - /* CAN module filters are not used, all messages with standard 11-bit */ - /* identifier will be received */ - /* Configure mask 0 so that all messages with standard identifier are accepted */ - - /* Init CAN0 mailbox 0-6 as reception mailboxes */ - for (i = 0; i <= (CANMB_NUMBER-2); i++) - { - reset_mailbox_conf(&CANmodule->rxMbConf[i]); - CANmodule->rxMbConf[i].ul_mb_idx = i; - CANmodule->rxMbConf[i].uc_obj_type = CAN_MB_RX_MODE; - - if (i == (CANMB_NUMBER-2)) - CANmodule->rxMbConf[i].uc_obj_type = CAN_MB_RX_OVER_WR_MODE; - - /* Standard mode only, not extended mode */ - CANmodule->rxMbConf[i].ul_id_msk = CAN_MAM_MIDvA_Msk; - CANmodule->rxMbConf[i].ul_id = CAN_MID_MIDvA(0); - can_mailbox_init(CANmodule->CANdriverState, &CANmodule->rxMbConf[i]); - - /* Enable CAN0 mailbox number i interrupt. */ - can_enable_interrupt(CANmodule->CANdriverState, (0x1u << i)); - } - - /* Init last CAN0 mailbox, number 7, as transmit mailbox */ - reset_mailbox_conf(&CANmodule->txMbConf); - CANmodule->txMbConf.ul_mb_idx = (CANMB_TX); - CANmodule->txMbConf.uc_obj_type = CAN_MB_TX_MODE; - CANmodule->txMbConf.uc_tx_prio = 14; - CANmodule->txMbConf.uc_id_ver = 0; - CANmodule->txMbConf.ul_id_msk = 0; - can_mailbox_init(CANmodule->CANdriverState, &CANmodule->txMbConf); - } - - if (CANmodule->CANdriverState == CAN1) - { - /* CAN1 Transceiver */ - static sn65hvd234_ctrl_t can1_transceiver; - - /* Initialize CAN1 Transceiver */ - sn65hvd234_set_rs(&can1_transceiver, PIN_CAN1_TR_RS_IDX); - sn65hvd234_set_en(&can1_transceiver, PIN_CAN1_TR_EN_IDX); - - /* Enable CAN1 Transceiver */ - sn65hvd234_disable_low_power(&can1_transceiver); //Low power mode == listening only mode - sn65hvd234_enable(&can1_transceiver); - - /* Configure CAN timing */ - - /* Enable CAN1 & CAN1 clock */ - pmc_enable_periph_clk(ID_CAN1); - - ul_sysclk = sysclk_get_cpu_hz(); - - if (can_init(CAN1, ul_sysclk, CAN_BPS_250K)) - { - printf("CAN1 initialization is completed\n\r"); - - /* Disable all CAN1 interrupts */ - can_disable_interrupt(CAN1, CAN_DISABLE_ALL_INTERRUPT_MASK); - - /* Configure and enable interrupt of CAN1 */ - NVIC_EnableIRQ(CAN1_IRQn); - } - - can_reset_all_mailbox(CANmodule->CANdriverState); - - /* CAN module filters are not used, all messages with standard 11-bit */ - /* identifier will be received */ - /* Configure mask 0 so that all messages with standard identifier are accepted */ - - /* Init CAN1 mailbox 0-6 as reception mailboxes */ - - for (i = 0; i <= (CANMB_NUMBER-2); i++) - { - reset_mailbox_conf(&CANmodule->rxMbConf[i]); - CANmodule->rxMbConf[i].ul_mb_idx = i; - CANmodule->rxMbConf[i].uc_obj_type = CAN_MB_RX_MODE; - - if (i == (CANMB_NUMBER-2)) - CANmodule->rxMbConf[i].uc_obj_type = CAN_MB_RX_OVER_WR_MODE; - - /* Standard mode only, not extended mode */ - CANmodule->rxMbConf[i].ul_id_msk = CAN_MAM_MIDvA_Msk; - CANmodule->rxMbConf[i].ul_id = CAN_MID_MIDvA(0); - can_mailbox_init(CANmodule->CANdriverState, &CANmodule->rxMbConf[i]); - - /* Enable CAN1 mailbox number i interrupt. */ - can_enable_interrupt(CANmodule->CANdriverState, (0x1u << i)); - } - - /* Init last CAN1 mailbox, number 7, as transmit mailbox */ - reset_mailbox_conf(&CANmodule->txMbConf); - CANmodule->txMbConf.ul_mb_idx = (CANMB_TX); - CANmodule->txMbConf.uc_obj_type = CAN_MB_TX_MODE; - CANmodule->txMbConf.uc_tx_prio = 14; - CANmodule->txMbConf.uc_id_ver = 0; - CANmodule->txMbConf.ul_id_msk = 0; - can_mailbox_init(CANmodule->CANdriverState, &CANmodule->txMbConf); - } - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) -{ - /* Turn the module off */ - can_disable(CANmodule->CANdriverState); -} - - -/******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg) -{ - return (uint16_t) rxMsg->ident; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)) - { - /* Buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - - /* Configure object variables */ - buffer->object = object; - buffer->pFunct = pFunct; - - /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */ - buffer->ident = ident & 0x07FFU; - if(rtr){ - buffer->ident |= 0x0800U; - } - buffer->mask = (mask & 0x07FFU) | 0x0800U; - - /* Set CAN hardware module filter and mask. */ - if(CANmodule->useCANrxFilters) - { - } - } - else - { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)) - { - /* Get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer. */ - buffer->ident = ident; - buffer->rtr = rtr; - - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - buffer->DLC = noOfBytes; - } - - return buffer; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) -{ - CO_ReturnError_t err = CO_ERROR_NO; - - /* Verify overflow */ - if(buffer->bufferFull){ - if(!CANmodule->firstCANtxMessage){ - /* Don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, buffer->ident); - } - err = CO_ERROR_TX_OVERFLOW; - } - - CO_LOCK_CAN_SEND(); - - /* If CAN TX buffer is free, copy message to it */ - if (((can_mailbox_get_status(CANmodule->CANdriverState, CANMB_TX) & CAN_MSR_MRDY) == CAN_MSR_MRDY) && (CANmodule->CANtxCount == 0)) - { - CANmodule->bufferInhibitFlag = buffer->syncFlag; - - /* Copy message and txRequest */ - CANmodule->txMbConf.ul_id = CAN_MID_MIDvA(buffer->ident); - CANmodule->txMbConf.ul_datal = *((uint32_t *) &(buffer->data[0])); - CANmodule->txMbConf.ul_datah = *((uint32_t *) &(buffer->data[4])); - CANmodule->txMbConf.uc_length = buffer->DLC; - - if (buffer->rtr) - can_mailbox_tx_remote_frame(CANmodule->CANdriverState, &CANmodule->txMbConf); - else - can_mailbox_write(CANmodule->CANdriverState, &CANmodule->txMbConf); - - can_global_send_transfer_cmd(CANmodule->CANdriverState, 1 << CANMB_TX); - } - else /* If no buffer is free, message will be sent by interrupt */ - { - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - can_enable_interrupt(CANmodule->CANdriverState, 0x1u << CANMB_TX); - CO_UNLOCK_CAN_SEND(); - - return err; -} - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) -{ - uint32_t tpdoDeleted = 0U; - - CO_LOCK_CAN_SEND(); - /* Abort message from CAN module, if there is synchronous TPDO. - * Take special care with this functionality. */ - if(/*messageIsOnCanBuffer && */CANmodule->bufferInhibitFlag){ - /* clear TXREQ */ - CANmodule->bufferInhibitFlag = false; - tpdoDeleted = 1U; - } - /* delete also pending synchronous TPDOs in TX buffers */ - if(CANmodule->CANtxCount != 0U){ - uint16_t i; - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - for(i = CANmodule->txSize; i > 0U; i--){ - if(buffer->bufferFull){ - if(buffer->syncFlag){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - tpdoDeleted = 2U; - } - } - buffer++; - } - } - CO_UNLOCK_CAN_SEND(); - - if(tpdoDeleted != 0U){ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted); - } -} - - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - uint16_t rxErrors = 0, txErrors = 0, overflow = 0; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - uint32_t err; - - /* get error counters from module. Id possible, function may use different way to - * determine errors. */ - - rxErrors = can_get_rx_error_cnt(CANmodule->CANdriverState); - - txErrors = can_get_tx_error_cnt(CANmodule->CANdriverState); - - //overflow = CANmodule->txSize; - - err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; - - if(CANmodule->errOld != err) - { - CANmodule->errOld = err; - - if(txErrors >= 256U) /* bus off */ - { - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - } - else /* not bus off */ - { - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - - if((rxErrors >= 96U) || (txErrors >= 96U)) - { /* bus warning */ - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - - if(rxErrors >= 128U) /* RX bus passive */ - { - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else - { - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err); - } - - if(txErrors >= 128U) /* TX bus passive */ - { - if(!CANmodule->firstCANtxMessage) - { - CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - } - else - { - bool_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE); - if(isError) - { - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - - if((rxErrors < 96U) && (txErrors < 96U)) /* no error */ - { - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - } - } - - if(overflow != 0U) /* CAN RX bus overflow */ - { - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - } - } -} - - -/******************************************************************************/ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule) -{ - uint32_t ul_status; - - ul_status = can_get_status(CANmodule->CANdriverState); - if (ul_status & GLOBAL_MAILBOX_MASK) - { - for (uint8_t i = 0; i < CANMB_NUMBER; i++) - { - ul_status = can_mailbox_get_status(CANmodule->CANdriverState, i); - if ((ul_status & CAN_MSR_MRDY) == CAN_MSR_MRDY) //Mailbox Ready Bit - { - //Handle interrupt - if (i != CANMB_TX) - { - //Receive interrupt - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - CO_CANrxMsg_t rcvMsgBuf; - uint16_t index; /* index of received message */ - uint32_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - - CANmodule->rxMbConf[i].ul_mb_idx = i; - CANmodule->rxMbConf[i].ul_status = ul_status; - can_mailbox_read(CANmodule->CANdriverState, &CANmodule->rxMbConf[i]); - - - /* Get message from module here */ - memset(rcvMsgBuf.data, 0, 8); - memcpy(rcvMsgBuf.data, &CANmodule->rxMbConf[i].ul_datal, CANmodule->rxMbConf[i].uc_length); - rcvMsgBuf.ident = CANmodule->rxMbConf[i].ul_id; - rcvMsgBuf.DLC = CANmodule->rxMbConf[i].uc_length; - - rcvMsg = &rcvMsgBuf; - - rcvMsgIdent = rcvMsg->ident; - if(CANmodule->useCANrxFilters) - { - /* CAN module filters are used. Message with known 11-bit identifier has */ - /* been received */ - index = 0; /* get index of the received message here. Or something similar */ - if(index < CANmodule->rxSize) - { - buffer = &CANmodule->rxArray[index]; - /* verify also RTR */ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) - { - msgMatched = true; - } - } - } - else - { - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray from CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--) - { - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) - { - msgMatched = true; - break; - } - buffer++; - } - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)) - { - buffer->pFunct(buffer->object, rcvMsg); - } - } - else - { - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = false; - /* Clear flag from previous message */ - CANmodule->bufferInhibitFlag = false; - /* Are there any new messages waiting to be send */ - if(CANmodule->CANtxCount > 0U) - { - uint16_t j; /* Index of transmitting message */ - - /* First buffer */ - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - /* Search through whole array of pointers to transmit message buffers. */ - for(j = CANmodule->txSize; j > 0U; j--) - { - /* If message buffer is full, send it. */ - if(buffer->bufferFull) - { - buffer->bufferFull = false; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->txMbConf.ul_datal = *((uint32_t *) &(buffer->data[0])); - CANmodule->txMbConf.ul_datah = *((uint32_t *) &(buffer->data[4])); - - /* Write transmit information into mailbox. */ - CANmodule->txMbConf.ul_id = CAN_MID_MIDvA(buffer->ident); - CANmodule->txMbConf.uc_length = buffer->DLC; - - if (buffer->rtr) - can_mailbox_tx_remote_frame(CANmodule->CANdriverState, &CANmodule->txMbConf); - else - can_mailbox_write(CANmodule->CANdriverState, &CANmodule->txMbConf); - - can_global_send_transfer_cmd(CANmodule->CANdriverState, 1 << CANMB_TX); - - break; /* Exit for loop */ - } - buffer++; - } /* End of for loop */ - - /* Clear counter if no more messages */ - if(j == 0U){ - CANmodule->CANtxCount = 0U; - } - } - else - { - /* Nothing more to send */ - can_disable_interrupt(CANmodule->CANdriverState, 0x1u << CANMB_TX); - } - } - break; - } - } - } - else - { - if (ul_status & CAN_SR_ERRA); //error active - if (ul_status & CAN_SR_WARN); //warning limit - //CO_EM_CAN_BUS_WARNING - if (ul_status & CAN_SR_ERRP); //error passive - //CO_EM_CAN_TX_BUS_PASSIVE - if (ul_status & CAN_SR_BOFF); //bus off - //CO_EM_CAN_TX_BUS_OFF - if (ul_status & CAN_SR_SLEEP); //controller in sleep mode - if (ul_status & CAN_SR_WAKEUP); //controller woke up - if (ul_status & CAN_SR_TOVF); //timer overflow - if (ul_status & CAN_SR_TSTP); //timestamp - start or end of frame - if (ul_status & CAN_SR_CERR); //CRC error in mailbox - if (ul_status & CAN_SR_SERR); //stuffing error in mailbox - if (ul_status & CAN_SR_AERR); //ack error - if (ul_status & CAN_SR_FERR); //form error - if (ul_status & CAN_SR_BERR); //bit error - } -} diff --git a/stack/SAM3X/CO_driver.h b/stack/SAM3X/CO_driver.h deleted file mode 100644 index c337fccc..00000000 --- a/stack/SAM3X/CO_driver.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * CAN module object for the Atmel SAM3X microcontroller. - * - * @file CO_driver.h - * @author Janez Paternoster - * @author Olof Larsson - * @copyright 2014 Janez Paternoster - * - * 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 - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ - -#include "asf.h" -#include -#include - - - -/* CAN module base address */ - #define ADDR_CAN1 CAN0 - #define ADDR_CAN2 CAN1 - /* - Remember to set: - #define CONF_BOARD_CAN0 - #define CONF_BOARD_CAN1 - in conf_board.h - */ - - -/* Critical sections */ - #define CO_LOCK_CAN_SEND() //taskENTER_CRITICAL() - #define CO_UNLOCK_CAN_SEND() //taskEXIT_CRITICAL() - - #define CO_LOCK_EMCY() //taskENTER_CRITICAL() - #define CO_UNLOCK_EMCY() //taskEXIT_CRITICAL() - - #define CO_LOCK_OD() //taskENTER_CRITICAL() - #define CO_UNLOCK_OD() //taskEXIT_CRITICAL() - - -/* Data types */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. */ -typedef struct{ - /** CAN identifier. It must be read through CO_CANrxMsg_readIdent() function. */ - uint32_t ident; - uint8_t DLC ; - uint8_t data[8]; - can_mb_conf_t mbConf; /* Reference to controller's mailboxes */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint32_t ident; - uint8_t DLC; - uint8_t data[8]; - volatile bool_t bufferFull; - volatile bool_t syncFlag; - bool_t rtr; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - Can *CANdriverState; - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; - can_mb_conf_t rxMbConf[CANMB_NUMBER-1]; /* Reference to controller's mailboxes */ - can_mb_conf_t txMbConf; -}CO_CANmodule_t; - - -/* Endianes */ -#define CO_LITTLE_ENDIAN - - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. */ -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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* CAN interrupt receives and transmits CAN messages. */ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule); - - -#endif diff --git a/stack/SAM3X/readme b/stack/SAM3X/readme deleted file mode 100644 index f0964415..00000000 --- a/stack/SAM3X/readme +++ /dev/null @@ -1,6 +0,0 @@ -Used with Atmel ASF library. - -http://www.atmel.com/asf - -Contributed by Olof Larsson (dec 2014): -http://sourceforge.net/p/canopennode/discussion/387151/thread/8e789d60/ diff --git a/stack/STM32/CO_driver.c b/stack/STM32/CO_driver.c deleted file mode 100644 index 8666ba35..00000000 --- a/stack/STM32/CO_driver.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * CAN module object for ST STM32F103 microcontroller. - * - * @file CO_driver.c - * @author Janez Paternoster - * @author Ondrej Netik - * @author Vijayendra - * @author Jan van Lienden - * @copyright 2013 Janez Paternoster - * - * 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. - */ - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f10x_conf.h" -#include "CO_driver.h" -#include "CO_Emergency.h" -#include "led.h" -#include - -/* Private macro -------------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private variable ----------------------------------------------------------*/ -/* Private function ----------------------------------------------------------*/ -static void CO_CANClkSetting (void); -static void CO_CANconfigGPIO (void); -static void CO_CANsendToModule(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer, uint8_t transmit_mailbox); - -#ifdef CO_USE_LEDS -void InitCanLeds(void) -{ - vLED_InitRCC(); - vLED_InitPort(); -} - -void CanLedsSet(eCoLeds led) -{ - if (led & eCoLed_Green) - vLED_OnPB14Led(); - else - vLED_OffPB14Led(); - - if (led & eCoLed_Red) - vLED_OnPB15Led(); - else - vLED_OffPB15Led(); - -} -#endif /* CO_USE_LEDS */ - -/******************************************************************************* - Macro and Constants - CAN module registers - *******************************************************************************/ - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - CAN_InitTypeDef CAN_InitStruct; - CAN_FilterInitTypeDef CAN_FilterInitStruct; - NVIC_InitTypeDef NVIC_InitStructure; - int i; - uint8_t result; - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - CANmodule->CANdriverState = CANdriverState; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = false; - CANmodule->bufferInhibitFlag = 0; - CANmodule->firstCANtxMessage = 1; - CANmodule->CANtxCount = 0; - CANmodule->errOld = 0; - CANmodule->em = 0; - - // Replaced magic number 0x03 by (CAN_IT_TME | CAN_IT_FMP0) JvL - CAN_ITConfig(CANmodule->CANdriverState, (CAN_IT_TME | CAN_IT_FMP0), DISABLE); - - for (i = 0; i < rxSize; i++) - { - CANmodule->rxArray[i].ident = 0; - CANmodule->rxArray[i].pFunct = 0; - } - for (i = 0; i < txSize; i++) - { - CANmodule->txArray[i].bufferFull = 0; - } - - /* CO - VJ Changed */ - /* Setting Clock of CAN HW */ - CO_CANClkSetting(); - - /* GPIO Config for CAN */ - CO_CANconfigGPIO(); - - /* Init CAN controler */ - CAN_DeInit(CANmodule->CANdriverState); - CAN_StructInit(&CAN_InitStruct); - switch (CANbitRate) - { - case 1000: CAN_InitStruct.CAN_Prescaler = 2; - break; - case 500: CAN_InitStruct.CAN_Prescaler = 4; - break; - default: - case 250: CAN_InitStruct.CAN_Prescaler = 8; - break; - case 125: CAN_InitStruct.CAN_Prescaler = 16; - break; - case 100: CAN_InitStruct.CAN_Prescaler = 20; - break; - case 50: CAN_InitStruct.CAN_Prescaler = 40; - break; - case 20: CAN_InitStruct.CAN_Prescaler = 100; - break; - case 10: CAN_InitStruct.CAN_Prescaler = 200; - break; - } - CAN_InitStruct.CAN_SJW = CAN_SJW_4tq; // changed by VJ, old value = CAN_SJW_1tq; - CAN_InitStruct.CAN_BS1 = CAN_BS1_12tq; // changed by VJ, old value = CAN_BS1_3tq; - CAN_InitStruct.CAN_BS2 = CAN_BS2_5tq; // changed by VJ, old value = CAN_BS2_2tq; - CAN_InitStruct.CAN_NART = ENABLE; // No Automatic retransmision - - /* CO - Changed VJ Start */ - result = CAN_Init(CANmodule->CANdriverState, &CAN_InitStruct); - if (result == 0) - { - // TRACE_DEBUG_WP("res=%d\n\r", result); - return CO_ERROR_TIMEOUT; /* CO- Return Init failed */ - } - /* CO - Changed VJ End */ - - memset(&CAN_FilterInitStruct, 0, sizeof (CAN_FilterInitStruct)); - CAN_FilterInitStruct.CAN_FilterNumber = 0; - CAN_FilterInitStruct.CAN_FilterIdHigh = 0; - CAN_FilterInitStruct.CAN_FilterIdLow = 0; - CAN_FilterInitStruct.CAN_FilterMaskIdHigh = 0; - CAN_FilterInitStruct.CAN_FilterMaskIdLow = 0; - CAN_FilterInitStruct.CAN_FilterFIFOAssignment = 0; // pouzivame jen FIFO0 - CAN_FilterInitStruct.CAN_FilterMode = CAN_FilterMode_IdMask; - CAN_FilterInitStruct.CAN_FilterScale = CAN_FilterScale_32bit; - CAN_FilterInitStruct.CAN_FilterActivation = ENABLE; - CAN_FilterInit(&CAN_FilterInitStruct); - - - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - // preruseni od prijimace == interrupts from receiver - NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_INTERRUPTS; - NVIC_Init(&NVIC_InitStructure); - // preruseni od vysilace == interrupts from transmitter - NVIC_InitStructure.NVIC_IRQChannel = CAN1_TX_INTERRUPTS; - NVIC_Init(&NVIC_InitStructure); - - // CAN_OperatingModeRequest(CANmodule->CANdriverState, CAN_Mode_Normal); // Not needed as after init Can_init functions puts the controller in normal mode - VJ - - CAN_ITConfig(CANmodule->CANdriverState, 0x03, ENABLE); - - return CO_ERROR_NO; -} - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) -{ - CAN_DeInit(CANmodule->CANdriverState); -} - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - int8_t rtr, - void *object, - void (*pFunct)(void *object, CO_CANrxMsg_t *message)) -{ - CO_CANrx_t *rxBuffer; - //CanRxMsg *rxBuffer; - uint16_t RXF, RXM; - - //safety - if (!CANmodule || !object || !pFunct || index >= CANmodule->rxSize) - { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - //buffer, which will be configured - rxBuffer = CANmodule->rxArray + index; - - //Configure object variables - rxBuffer->object = object; - rxBuffer->pFunct = pFunct; - - - //CAN identifier and CAN mask, bit aligned with CAN module registers - RXF = (ident & 0x07FF) << 2; - if (rtr) RXF |= 0x02; - RXM = (mask & 0x07FF) << 2; - RXM |= 0x02; - - //configure filter and mask - if (RXF != rxBuffer->ident || RXM != rxBuffer->mask) - { - rxBuffer->ident = RXF; - rxBuffer->mask = RXM; - } - - return CO_ERROR_NO; -} - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - int8_t rtr, - uint8_t noOfBytes, - int8_t syncFlag) -{ - uint32_t TXF; - CO_CANtx_t *buffer; - - //safety - if (!CANmodule || CANmodule->txSize <= index) return 0; - - //get specific buffer - buffer = &CANmodule->txArray[index]; - - //CAN identifier, bit aligned with CAN module registers - - TXF = ident << 21; - TXF &= 0xFFE00000; - if (rtr) TXF |= 0x02; - - //write to buffer - buffer->ident = TXF; - buffer->DLC = noOfBytes; - buffer->bufferFull = 0; - buffer->syncFlag = syncFlag ? 1 : 0; - - return buffer; -} - -int8_t getFreeTxBuff(CO_CANmodule_t *CANmodule) -{ - uint8_t txBuff = CAN_TXMAILBOX_0; - - //if (CAN_TransmitStatus(CANmodule->CANdriverState, txBuff) == CAN_TxStatus_Ok) - for (txBuff = CAN_TXMAILBOX_0; txBuff <= (CAN_TXMAILBOX_2 + 1); txBuff++) - { - switch (txBuff) - { - case (CAN_TXMAILBOX_0 ): - if (CANmodule->CANdriverState->TSR & CAN_TSR_TME0 ) - return txBuff; - else - break; - case (CAN_TXMAILBOX_1 ): - if (CANmodule->CANdriverState->TSR & CAN_TSR_TME1 ) - return txBuff; - else - break; - case (CAN_TXMAILBOX_2 ): - if (CANmodule->CANdriverState->TSR & CAN_TSR_TME2 ) - return txBuff; - else - break; - default: - break; - } - } - return -1; -} - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) -{ - CO_ReturnError_t err = CO_ERROR_NO; - int8_t txBuff; - - /* Verify overflow */ - if(buffer->bufferFull) - { - if(!CANmodule->firstCANtxMessage)/* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); - err = CO_ERROR_TX_OVERFLOW; - } - - CO_LOCK_CAN_SEND(); - //if CAN TB buffer0 is free, copy message to it - txBuff = getFreeTxBuff(CANmodule); - // #error change this - use only one buffer for transmission - see generic driver - if(txBuff != -1 && CANmodule->CANtxCount == 0) - { - CANmodule->bufferInhibitFlag = buffer->syncFlag; - CO_CANsendToModule(CANmodule, buffer, txBuff); - } - //if no buffer is free, message will be sent by interrupt - else - { - buffer->bufferFull = 1; - CANmodule->CANtxCount++; - // vsechny buffery jsou plny, musime povolit preruseni od vysilace, odvysilat az v preruseni - CAN_ITConfig(CANmodule->CANdriverState, CAN_IT_TME, ENABLE); - } - CO_UNLOCK_CAN_SEND(); - - return err; -} - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) -{ - - /* See generic driver for implemetation. */ -} - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule) -{ - uint32_t err; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - - err = CANmodule->CANdriverState->ESR; - // if(CAN_REG(CANmodule->CANdriverState, C_INTF) & 4) err |= 0x80; - - if(CANmodule->errOld != err) - { - CANmodule->errOld = err; - - //CAN RX bus overflow - if(CANmodule->CANdriverState->RF0R & 0x08) - { - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - CANmodule->CANdriverState->RF0R &=~0x08;//clear bits - } - - //CAN TX bus off - if(err & 0x04) CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - else CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - - //CAN TX or RX bus passive - if(err & 0x02) - { - if(!CANmodule->firstCANtxMessage) CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else - { - // int16_t wasCleared; - /* wasCleared = */CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - /* if(wasCleared == 1) */CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - - - //CAN TX or RX bus warning - if(err & 0x01) - { - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - else - { - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - } - } -} - -/******************************************************************************/ -// Interrupt from Receiver -void CO_CANinterrupt_Rx(CO_CANmodule_t *CANmodule) -{ - CanRxMsg CAN1_RxMsg; - - CAN_Receive(CANmodule->CANdriverState, CAN_FilterFIFO0, &CAN1_RxMsg); - { - uint16_t index; - uint8_t msgMatched = 0; - CO_CANrx_t *msgBuff = CANmodule->rxArray; - for (index = 0; index < CANmodule->rxSize; index++) - { - uint16_t msg = (CAN1_RxMsg.StdId << 2) | (CAN1_RxMsg.RTR ? 2 : 0); - if (((msg ^ msgBuff->ident) & msgBuff->mask) == 0) - { - msgMatched = 1; - break; - } - msgBuff++; - } - //Call specific function, which will process the message - if (msgMatched && msgBuff->pFunct) - msgBuff->pFunct(msgBuff->object, &CAN1_RxMsg); - } -} - -/******************************************************************************/ -// Interrupt from Transeiver -void CO_CANinterrupt_Tx(CO_CANmodule_t *CANmodule) -{ - - int8_t txBuff; - /* Clear interrupt flag */ - CAN_ITConfig(CANmodule->CANdriverState, CAN_IT_TME, DISABLE); // Transmit mailbox empty interrupt - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = 0; - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = 0; - /* Are there any new messages waiting to be send */ - if(CANmodule->CANtxCount > 0) - { - uint16_t i; /* index of transmitting message */ - - /* first buffer */ - CO_CANtx_t *buffer = CANmodule->txArray; - /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0; i--) - { - /* if message buffer is full, send it. */ - if(buffer->bufferFull) - { - buffer->bufferFull = 0; - CANmodule->CANtxCount--; - txBuff = getFreeTxBuff(CANmodule); //VJ - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - CO_CANsendToModule(CANmodule, buffer, txBuff); - break; /* exit for loop */ - } - buffer++; - }/* end of for loop */ - - /* Clear counter if no more messages */ - if(i == 0) CANmodule->CANtxCount = 0; - } -} - -/******************************************************************************/ -void CO_CANinterrupt_Status(CO_CANmodule_t *CANmodule) -{ - // status is evalved with pooling -} - -/******************************************************************************/ -static void CO_CANsendToModule(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer, uint8_t transmit_mailbox) -{ - - CanTxMsg CAN1_TxMsg; - int i; - - /*Test code, VJ using Drivers Start*/ - CAN1_TxMsg.IDE = CAN_ID_STD; - CAN1_TxMsg.DLC = buffer->DLC; - for (i = 0; i < 8; i++) CAN1_TxMsg.Data[i] = buffer->data[i]; - CAN1_TxMsg.StdId = ((buffer->ident) >> 21); - CAN1_TxMsg.RTR = CAN_RTR_DATA; - - CAN_Transmit(CANmodule->CANdriverState, &CAN1_TxMsg); - CAN_ITConfig(CANmodule->CANdriverState, CAN_IT_TME, ENABLE); - - /*Test code, VJ using Drivers End*/ - -} - -/* CO- VJ Changed Start */ -/******************************************************************************/ -static void CO_CANClkSetting (void) -{ - RCC_APB2PeriphClockCmd(CLOCK_GPIO_CAN | RCC_APB2Periph_AFIO, ENABLE); - RCC_APB1PeriphClockCmd(CLOCK_CAN, ENABLE); -} - -/******************************************************************************/ -static void CO_CANconfigGPIO (void) -{ - - GPIO_InitTypeDef GPIO_InitStructure; - - /* Remap */ - GPIO_PinRemapConfig(GPIO_Remapping_CAN, GPIO_CAN_Remap_State); - /* Configure CAN pin: RX */ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CAN_RX; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; - GPIO_Init(GPIO_CAN, &GPIO_InitStructure); - /* Configure CAN pin: TX */ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CAN_TX; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_Init(GPIO_CAN, &GPIO_InitStructure); - -} -/* CO- VJ Change End */ diff --git a/stack/STM32/CO_driver.h b/stack/STM32/CO_driver.h deleted file mode 100644 index a9f17df8..00000000 --- a/stack/STM32/CO_driver.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * CAN module object for ST STM32F103 microcontroller. - * - * @file CO_driver.h - * @author Janez Paternoster - * @author Ondrej Netik - * @author Vijayendra - * @author Jan van Lienden - * @copyright 2013 Janez Paternoster - * - * 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 - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -/* Includes ------------------------------------------------------------------*/ -#include "common.h" -#include "stm32f10x_conf.h" - -/* Exported define -----------------------------------------------------------*/ -#define PACKED_STRUCT __attribute__((packed)) -#define ALIGN_STRUCT_DWORD __attribute__((aligned(4))) - -/* Peripheral addresses */ - #define ADDR_CAN1 CAN1 - #define TMIDxR_TXRQ ((uint32_t)0x00000001) /* Transmit mailbox request */ - -/* Critical sections */ - #define CO_LOCK_CAN_SEND() __set_PRIMASK(1); - #define CO_UNLOCK_CAN_SEND() __set_PRIMASK(0); - - #define CO_LOCK_EMCY() __set_PRIMASK(1); - #define CO_UNLOCK_EMCY() __set_PRIMASK(0); - - #define CO_LOCK_OD() __set_PRIMASK(1); - #define CO_UNLOCK_OD() __set_PRIMASK(0); - - -#define CLOCK_CAN RCC_APB1Periph_CAN1 - -#define CAN_REMAP_2 /* Select CAN1 remap 2 */ -#ifdef CAN1_NO_REMAP /* CAN1 not remapped */ -#define CLOCK_GPIO_CAN RCC_APB2Periph_GPIOA -#define GPIO_Remapping_CAN (0) -#define GPIO_CAN GPIOA -#define GPIO_Pin_CAN_RX GPIO_Pin_11 -#define GPIO_Pin_CAN_TX GPIO_Pin_12 -#define GPIO_CAN_Remap_State DISABLE -#endif -#ifdef CAN_REMAP1 /* CAN1 remap 1 */ -#define CLOCK_GPIO_CAN RCC_APB2Periph_GPIOB -#define GPIO_Remapping_CAN GPIO_Remap1_CAN1 -#define GPIO_CAN GPIOB -#define GPIO_Pin_CAN_RX GPIO_Pin_8 -#define GPIO_Pin_CAN_TX GPIO_Pin_9 -#define GPIO_CAN_Remap_State ENABLE -#endif -#ifdef CAN_REMAP_2 /* CAN1 remap 2 */ -#define CLOCK_GPIO_CAN RCC_APB2Periph_GPIOD -#define GPIO_Remapping_CAN GPIO_Remap2_CAN1 -#define GPIO_CAN GPIOD -#define GPIO_Pin_CAN_RX GPIO_Pin_0 -#define GPIO_Pin_CAN_TX GPIO_Pin_1 -#define GPIO_CAN_Remap_State ENABLE -#endif - -#ifdef STM32F10X_CL -#define CAN1_TX_INTERRUPTS CAN1_TX_IRQn -#define CAN1_RX0_INTERRUPTS CAN1_RX0_IRQn -#else -#define CAN1_TX_INTERRUPTS USB_HP_CAN1_TX_IRQn -#define CAN1_RX0_INTERRUPTS USB_LP_CAN1_RX0_IRQn -#endif - -#define CAN_TXMAILBOX_0 ((uint8_t)0x00) -#define CAN_TXMAILBOX_1 ((uint8_t)0x01) -#define CAN_TXMAILBOX_2 ((uint8_t)0x02) - -/* Timeout for initialization */ - -#define INAK_TIMEOUT ((uint32_t)0x0000FFFF) -/* Data types */ - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - -/* CAN receive message structure as aligned in CAN module. - * prevzato z stm32f10_can.h - velikostne polozky a poradi odpovidaji. */ -typedef struct{ - uint32_t ident; /* Standard Identifier */ - uint32_t ExtId; /* Specifies the extended identifier */ - uint8_t IDE; /* Specifies the type of identifier for the - message that will be received */ - uint8_t RTR; /* Remote Transmission Request bit */ - uint8_t DLC; /* Data length code (bits 0...3) */ - uint8_t data[8]; /* 8 data bytes */ - uint8_t FMI; /* Specifies the index of the filter the message - stored in the mailbox passes through */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, CanRxMsg *message); // Changed by VJ -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint32_t ident; - uint8_t DLC; - uint8_t data[8]; - volatile uint8_t bufferFull; - volatile uint8_t syncFlag; -}CO_CANtx_t;/* ALIGN_STRUCT_DWORD; */ - - -/* CAN module object. */ -typedef struct{ - CAN_TypeDef *CANdriverState; /* STM32F4xx specific */ - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile uint8_t useCANrxFilters; - volatile uint8_t bufferInhibitFlag; - volatile uint8_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; -}CO_CANmodule_t; - -#ifdef CO_USE_LEDS -/* Init CAN Led Interface */ -typedef enum { - eCoLed_None = 0, - eCoLed_Green = 1, - eCoLed_Red = 2, -} eCoLeds; - -/* Exported variables -----------------------------------------------------------*/ - -/* Exported functions -----------------------------------------------------------*/ -void InitCanLeds(void); -void CanLedsOn(eCoLeds led); -void CanLedsOff(eCoLeds led); -void CanLedsSet(eCoLeds led); -#endif /* CO_USE_LEDS */ - - -/* Request CAN configuration or normal mode */ -//void CO_CANsetConfigurationMode(CAN_TypeDef *CANdriverState); -//void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - -/* Initialize CAN module object. */ -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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -//uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - int8_t rtr, - void *object, - void (*pFunct)(void *object, CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - int8_t rtr, - uint8_t noOfBytes, - int8_t syncFlag); - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* CAN interrupts receives and transmits CAN messages. */ -void CO_CANinterrupt_Rx(CO_CANmodule_t *CANmodule); -void CO_CANinterrupt_Tx(CO_CANmodule_t *CANmodule); -void CO_CANinterrupt_Status(CO_CANmodule_t *CANmodule); - - -#endif diff --git a/stack/STM32F3/CO_Flash.c b/stack/STM32F3/CO_Flash.c deleted file mode 100644 index 280b51d9..00000000 --- a/stack/STM32F3/CO_Flash.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * STM32F3 flash support for CANopen stack - * - * @file CO_Flash.c - * @author Janez Paternoster - * @author Olof Larsson - * @author Petteri Mustonen - * @copyright 2014 Janez Paternoster - * - * 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. - */ - -//============================================================================ -// INCLUDES -//============================================================================ -#include "CANopen.h" -#include "stm32f30x.h" - -//============================================================================ -// DEFINES -//============================================================================ -#define PARAM_STORE_PASSWORD 0x65766173 -#define PARAM_RESTORE_PASSWORD 0x64616F6C - -#define DEBUG 0 - -#define LAST_PAGE_ADDRESS 0x0800F800 -#define PAGES_PER_FLASH_AREA 1 -#define FLASH_PAGE_SIZE 0x800 -#define CO_OD_FLASH_PARAM_DEFAULT LAST_PAGE_ADDRESS - (1*PAGES_PER_FLASH_AREA*FLASH_PAGE_SIZE) -#define CO_OD_FLASH_PARAM_RUNTIME LAST_PAGE_ADDRESS - (2*PAGES_PER_FLASH_AREA*FLASH_PAGE_SIZE) - -#define CO_UNUSED(v) (void)(v) - -//============================================================================ -// LOCAL DATA -//============================================================================ -extern struct sCO_OD_ROM CO_OD_ROM; - -enum CO_OD_H1010_StoreParam_Sub -{ - OD_H1010_STORE_PARAM_COUNT, - OD_H1010_STORE_PARAM_ALL, - OD_H1010_STORE_PARAM_COMM, - OD_H1010_STORE_PARAM_APP, - OD_H1010_STORE_PARAM_MANUFACTURER, - OD_H1010_STORE_PARAM_RESERVED = 0x80 -}; - -enum CO_OD_H1011_RestoreDefaultParam_Sub -{ - OD_H1011_RESTORE_PARAM_COUNT, - OD_H1011_RESTORE_PARAM_ALL, - OD_H1011_RESTORE_PARAM_COMM, - OD_H1011_RESTORE_PARAM_APP, - OD_H1011_RESTORE_PARAM_MANUFACTURER, - OD_H1011_RESTORE_PARAM_RESERVED = 0x80 -}; - -enum CO_StorageFunctionality_Flags -{ - SAVES_PARAM_ON_COMMAND = 0x01, - SAVES_PARAM_AUTONOMOUSLY = 0x02 -}; - -enum CO_RestoreFunctionality_Flags -{ - RESTORES_PARAMETERS = 0x01 -}; - -//============================================================================ -/** -* Store parameters of object dictionary into flash memory. -* \param[in] FlashAddress Use CO_OD_Flash_Adress for the normal parameter -* block and CO_OD_Flash_Default_Param for the -* default parameters -*/ -static CO_SDO_abortCode_t storeParameters(uint32_t FlashAddress, uint8_t ParametersSub) -{ - uint32_t addressPtr = 0x00; - uint32_t addressFinal = 0x00; - uint32_t* chunk; - - CO_UNUSED(ParametersSub); - - /* Unlock flash*/ - FLASH_Unlock(); - - /* Check flash allocation */ - int32_t bytes_to_write = sizeof(CO_OD_ROM); - if ((uint32_t)bytes_to_write > (FLASH_PAGE_SIZE*PAGES_PER_FLASH_AREA)) { - return CO_SDO_AB_HW; - } - - addressFinal = FlashAddress + bytes_to_write; - /* Clear pending flakgs (if any) */ - FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR); - - /* Erase page */ - FLASH_ErasePage(FlashAddress); - - /* Program data into flash word by word */ - chunk = (uint32_t*) &CO_OD_ROM; - for (addressPtr = FlashAddress; addressPtr < addressFinal; addressPtr += 4) { - if (FLASH_ProgramWord(addressPtr, *chunk) != FLASH_COMPLETE) { - return CO_SDO_AB_HW; - } - chunk++; - } - FLASH_Lock(); - - return CO_SDO_AB_NONE; -} - -//============================================================================ -/** -* Restore parameters of object dictionary from flash memory. -* \param[in] FlashAddress Use CO_OD_Flash_Adress for the normal parameter -* block and CO_OD_Flash_Default_Param for the -* default parameters -*/ -void flash_read(uint32_t FlashAddress, void* RamAddress, size_t len) -{ - uint8_t* p_flash = (uint8_t *) FlashAddress; - uint8_t* p_ram = (uint8_t *) RamAddress; - uint32_t idx; - - for (idx = 0; idx < len; idx++) { - *p_ram = *(__IO uint8_t *)p_flash; - p_ram++; - p_flash++; - } -} - -static CO_SDO_abortCode_t restoreParameters(uint32_t FlashAddress, uint8_t ParametersSub) -{ - CO_UNUSED(ParametersSub); - - flash_read(FlashAddress, &CO_OD_ROM, sizeof(CO_OD_ROM)); - - return CO_SDO_AB_NONE; -} - -//============================================================================ -/** -* Access to object dictionary OD_H1010_STORE_PARAM_FUNC -*/ -static CO_SDO_abortCode_t CO_ODF_1010_StoreParam(CO_ODF_arg_t *ODF_arg) -{ - - uint32_t* value = (uint32_t*)ODF_arg->data; - - if (ODF_arg->reading) { - if(OD_H1010_STORE_PARAM_ALL == ODF_arg->subIndex) { - *value = SAVES_PARAM_ON_COMMAND; - } - return CO_SDO_AB_NONE; - } - - if(OD_H1010_STORE_PARAM_ALL != ODF_arg->subIndex) { - return CO_SDO_AB_NONE; - } - - if (*value != PARAM_STORE_PASSWORD) { - return CO_SDO_AB_DATA_TRANSF; - } - - return storeParameters(CO_OD_FLASH_PARAM_RUNTIME, ODF_arg->subIndex); -} - -//============================================================================ -/** -* Access to object dictionary OD_H1010_STORE_PARAM_FUNC -*/ -static CO_SDO_abortCode_t CO_ODF_1011_RestoreParam(CO_ODF_arg_t *ODF_arg) -{ - uint32_t* value = (uint32_t*)ODF_arg->data; - - if (ODF_arg->reading) { - if (OD_H1011_RESTORE_PARAM_ALL == ODF_arg->subIndex) { - *value = RESTORES_PARAMETERS; - } - return CO_SDO_AB_NONE; - } - - if (OD_H1011_RESTORE_PARAM_ALL != ODF_arg->subIndex) { - return CO_SDO_AB_NONE; - } - - if (*value != PARAM_RESTORE_PASSWORD) { - return CO_SDO_AB_DATA_TRANSF; - } - - CO_SDO_abortCode_t Result = restoreParameters(CO_OD_FLASH_PARAM_DEFAULT, ODF_arg->subIndex); - - if (Result != CO_SDO_AB_NONE) { - return Result; - } - - return storeParameters(CO_OD_FLASH_PARAM_RUNTIME, OD_H1011_RESTORE_PARAM_ALL); -} - -//=========================================================================== -/** -* Initialize flash library and data storage in flash -* We use two blocks in flash for data storage. One block is used for the -* default data that will be restored. The default parameters are stored -* at address CO_OD_Flash_Default_Param. The data that will be loaded at -* startup or saved if user modifies data is store at CO_OD_Flash_Adress. -*/ -void CO_FlashInit(void) -{ - /* Before we can access the data, we need to make sure, that the flash - block are properly initialized. We do this by reading the block into - a local sCO_OD_ROM variable and verifying the FirstWord and LastWord - members. */ - - struct sCO_OD_ROM DefaultObjDicParam; - flash_read(CO_OD_FLASH_PARAM_DEFAULT, &DefaultObjDicParam, sizeof(DefaultObjDicParam)); - - /* If the default parameters are not present in flash, then we know that - we need to create them for later restore. */ - - if ((DefaultObjDicParam.FirstWord != CO_OD_FIRST_LAST_WORD) || - (DefaultObjDicParam.LastWord != CO_OD_FIRST_LAST_WORD)) { - storeParameters(CO_OD_FLASH_PARAM_RUNTIME, OD_H1010_STORE_PARAM_ALL); - storeParameters(CO_OD_FLASH_PARAM_DEFAULT, OD_H1010_STORE_PARAM_ALL); - } - else { - restoreParameters(CO_OD_FLASH_PARAM_RUNTIME, OD_H1010_STORE_PARAM_ALL); - } -} - -//=========================================================================== -void CO_FlashRegisterODFunctions(CO_t* CO) -{ - CO_OD_configure(*(CO->SDO), OD_H1010_STORE_PARAM_FUNC, - CO_ODF_1010_StoreParam, (void*)0, 0, 0); - - CO_OD_configure(*(CO->SDO), OD_H1011_REST_PARAM_FUNC, - CO_ODF_1011_RestoreParam, (void*)0, 0, 0); -} diff --git a/stack/STM32F3/CO_Flash.h b/stack/STM32F3/CO_Flash.h deleted file mode 100644 index 2e3c7cf9..00000000 --- a/stack/STM32F3/CO_Flash.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * STM32F3 flash support for CANopen stack - * - * @file CO_Flash.h - * @author Janez Paternoster - * @author Olof Larsson - * @author Petteri Mustonen - * @copyright 2014 Janez Paternoster - * - * 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_FLASH_H -#define CO_FLASH_H - -//============================================================================ -// INCLUDES -//============================================================================ -#include "CANopen.h" - -/** - * Initialize flash library and data storage in flash - * We use two blocks in flash for data storage. One block is used for the - * default data that will be restored. The default parameters are stored - * at address CO_OD_Flash_Default_Param. The data that will be loaded at - * startup or saved if user modifies data. - */ -void CO_FlashInit(void); - -/** - * Register object dictionary functions for parameter storage and restoring - * parameters (Object dictionary index 0x1010 Store Param and 0x1011 Restore - * default param. - */ -void CO_FlashRegisterODFunctions(CO_t* CO); - -#endif diff --git a/stack/STM32F3/CO_driver.c b/stack/STM32F3/CO_driver.c deleted file mode 100644 index 713c9ff9..00000000 --- a/stack/STM32F3/CO_driver.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * CAN module object for ST STM32F334 microcontroller. - * - * @file CO_driver.c - * @author Janez Paternoster - * @author Ondrej Netik - * @author Vijayendra - * @author Jan van Lienden - * @author Petteri Mustonen - * @copyright 2013 Janez Paternoster - * - * 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. - */ - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f30x.h" -#include "CO_driver.h" -#include "CO_Emergency.h" -#include - -/* Private macro -------------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private variable ----------------------------------------------------------*/ -/* Private function ----------------------------------------------------------*/ -static void CO_CANClkSetting (void); -static void CO_CANconfigGPIO (void); -static uint8_t CO_CANsendToModule(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - -/******************************************************************************* - Macro and Constants - CAN module registers - *******************************************************************************/ - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ - (void) CANdriverState; -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - CAN_InitTypeDef CAN_InitStruct; - CAN_FilterInitTypeDef CAN_FilterInitStruct; - NVIC_InitTypeDef NVIC_InitStructure; - int i; - uint8_t result; - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - CANmodule->CANdriverState = CANdriverState; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = false; - CANmodule->bufferInhibitFlag = 0; - CANmodule->firstCANtxMessage = 1; - CANmodule->CANtxCount = 0; - CANmodule->errOld = 0; - CANmodule->em = 0; - - CAN_ITConfig(CANmodule->CANdriverState, (CAN_IT_TME | CAN_IT_FMP0), DISABLE); - - for (i = 0; i < rxSize; i++) { - CANmodule->rxArray[i].ident = 0; - CANmodule->rxArray[i].pFunct = 0; - } - - for (i = 0; i < txSize; i++) { - CANmodule->txArray[i].bufferFull = 0; - } - - /* Setting Clock of CAN HW */ - CO_CANClkSetting(); - - /* GPIO Config for CAN */ - CO_CANconfigGPIO(); - - /* Init CAN controler */ - CAN_DeInit(CANmodule->CANdriverState); - CAN_StructInit(&CAN_InitStruct); - - switch (CANbitRate) { - case 1000: CAN_InitStruct.CAN_Prescaler = 2; - break; - case 500: CAN_InitStruct.CAN_Prescaler = 4; - break; - default: - case 250: CAN_InitStruct.CAN_Prescaler = 8; - break; - case 125: CAN_InitStruct.CAN_Prescaler = 16; - break; - case 100: CAN_InitStruct.CAN_Prescaler = 20; - break; - case 50: CAN_InitStruct.CAN_Prescaler = 40; - break; - case 20: CAN_InitStruct.CAN_Prescaler = 100; - break; - case 10: CAN_InitStruct.CAN_Prescaler = 200; - break; - } - - CAN_InitStruct.CAN_SJW = CAN_SJW_1tq; // changed by VJ, old value = CAN_SJW_1tq; - CAN_InitStruct.CAN_BS1 = CAN_BS1_13tq; // changed by VJ, old value = CAN_BS1_3tq; - CAN_InitStruct.CAN_BS2 = CAN_BS2_2tq; // changed by VJ, old value = CAN_BS2_2tq; - CAN_InitStruct.CAN_NART = ENABLE; // No Automatic retransmision - - result = CAN_Init(CANmodule->CANdriverState, &CAN_InitStruct); - if (result == 0) { - return CO_ERROR_TIMEOUT; /* CO- Return Init failed */ - } - - memset(&CAN_FilterInitStruct, 0, sizeof (CAN_FilterInitStruct)); - CAN_FilterInitStruct.CAN_FilterNumber = 0; - CAN_FilterInitStruct.CAN_FilterIdHigh = 0; - CAN_FilterInitStruct.CAN_FilterIdLow = 0; - CAN_FilterInitStruct.CAN_FilterMaskIdHigh = 0; - CAN_FilterInitStruct.CAN_FilterMaskIdLow = 0; - CAN_FilterInitStruct.CAN_FilterFIFOAssignment = 0; // pouzivame jen FIFO0 - CAN_FilterInitStruct.CAN_FilterMode = CAN_FilterMode_IdMask; - CAN_FilterInitStruct.CAN_FilterScale = CAN_FilterScale_32bit; - CAN_FilterInitStruct.CAN_FilterActivation = ENABLE; - CAN_FilterInit(&CAN_FilterInitStruct); - - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - /* interrupts from receiver */ - NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_INTERRUPTS; - NVIC_Init(&NVIC_InitStructure); - /* interrupts from transmitter */ - NVIC_InitStructure.NVIC_IRQChannel = CAN1_TX_INTERRUPTS; - NVIC_Init(&NVIC_InitStructure); - - /* Can_init function of ST Driver puts the controller into the normal mode */ - - CAN_ITConfig(CANmodule->CANdriverState, (CAN_IT_TME | CAN_IT_FMP0), ENABLE); - - return CO_ERROR_NO; -} - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) -{ - CAN_DeInit(CANmodule->CANdriverState); -} - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - int8_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_CANrx_t *rxBuffer; - uint16_t RXF, RXM; - - //safety - if (!CANmodule || !object || !pFunct || index >= CANmodule->rxSize) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* buffer, which will be configured */ - rxBuffer = CANmodule->rxArray + index; - - /* Configure object variables */ - rxBuffer->object = object; - rxBuffer->pFunct = pFunct; - - /* CAN identifier and CAN mask, bit aligned with CAN module registers */ - RXF = (ident & 0x07FF) << 2; - if (rtr) RXF |= 0x02; - RXM = (mask & 0x07FF) << 2; - RXM |= 0x02; - - /* configure filter and mask */ - if (RXF != rxBuffer->ident || RXM != rxBuffer->mask) { - rxBuffer->ident = RXF; - rxBuffer->mask = RXM; - } - - return CO_ERROR_NO; -} - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - int8_t rtr, - uint8_t noOfBytes, - int8_t syncFlag) -{ - uint32_t TXF; - CO_CANtx_t *buffer; - - /* safety */ - if (!CANmodule || CANmodule->txSize <= index) return 0; - - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, bit aligned with CAN module registers */ - TXF = ident << 21; - TXF &= 0xFFE00000; - if (rtr) TXF |= 0x02; - - /* write to buffer */ - buffer->ident = TXF; - buffer->DLC = noOfBytes; - buffer->bufferFull = 0; - buffer->syncFlag = syncFlag ? 1 : 0; - - return buffer; -} - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) -{ - CO_ReturnError_t err = CO_ERROR_NO; - uint8_t txBuff; - - /* Verify overflow */ - if (buffer->bufferFull) { - if(!CANmodule->firstCANtxMessage) /* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); - err = CO_ERROR_TX_OVERFLOW; - } - - CO_LOCK_CAN_SEND(); - - /* First try to transmit the message immediately if mailbox is free. - * Only one TX mailbox is used of the three available in the hardware */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - txBuff = CO_CANsendToModule(CANmodule, buffer); - - /* No free mailbox -> use interrupt for transmission */ - if (txBuff == CAN_TxStatus_NoMailBox) { - buffer->bufferFull = 1; - CANmodule->CANtxCount++; - } - CO_UNLOCK_CAN_SEND(); - - return err; -} - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) -{ - uint32_t tpdoDeleted = 0U; - uint8_t state = 0; - - CO_LOCK_CAN_SEND(); - /* Abort message from CAN module, if there is synchronous TPDO. */ - state = CAN_TransmitStatus(CANmodule->CANdriverState, CO_CAN_TXMAILBOX); - if((state == CAN_TxStatus_Pending) && (CANmodule->bufferInhibitFlag)) { - CAN_CancelTransmit(CANmodule->CANdriverState, CO_CAN_TXMAILBOX); - CANmodule->bufferInhibitFlag = false; - tpdoDeleted = 1U; - } - - /* delete also pending synchronous TPDOs in TX buffers */ - if(CANmodule->CANtxCount != 0U){ - uint16_t i; - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - for(i = CANmodule->txSize; i > 0U; i--){ - if(buffer->bufferFull){ - if(buffer->syncFlag){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - tpdoDeleted = 2U; - } - } - buffer++; - } - } - CO_UNLOCK_CAN_SEND(); - - - if(tpdoDeleted != 0U){ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted); - } -} - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule) -{ - uint32_t err; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - - err = CANmodule->CANdriverState->ESR; - - if(CANmodule->errOld != err) { - CANmodule->errOld = err; - - /* CAN RX bus overflow */ - if(CANmodule->CANdriverState->RF0R & 0x10) { - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - CANmodule->CANdriverState->RF0R &=~0x10;//clear bits - } - - /* CAN TX bus off */ - if(err & 0x04) { - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - } - else { - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - } - - /* CAN TX or RX bus passive */ - if(err & 0x02) { - if(!CANmodule->firstCANtxMessage) CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else { - // int16_t wasCleared; - /* wasCleared = */CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - /* if(wasCleared == 1) */CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - - - /* CAN TX or RX bus warning */ - if(err & 0x01) { - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - else { - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - } - } -} - -/******************************************************************************/ -/* Interrupt from receiver */ -void CO_CANinterrupt_Rx(CO_CANmodule_t *CANmodule) -{ - CanRxMsg CAN1_RxMsg; - uint16_t index; - uint8_t msgMatched = 0; - CO_CANrx_t *msgBuff = CANmodule->rxArray; - - CAN_Receive(CANmodule->CANdriverState, CAN_FilterFIFO0, &CAN1_RxMsg); - - for (index = 0; index < CANmodule->rxSize; index++) { - uint16_t msg = (CAN1_RxMsg.StdId << 2) | (CAN1_RxMsg.RTR ? 2 : 0); - - if (((msg ^ msgBuff->ident) & msgBuff->mask) == 0) { - msgMatched = 1; - break; - } - msgBuff++; - } - - /* Call specific function, which will process the message */ - if (msgMatched && msgBuff->pFunct) { - msgBuff->pFunct(msgBuff->object, (CO_CANrxMsg_t*) &CAN1_RxMsg); - } -} - -/******************************************************************************/ -/* Interrupt from trasmitter */ -void CO_CANinterrupt_Tx(CO_CANmodule_t *CANmodule) -{ - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = 0; - - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = 0; - - /* Are there any new messages waiting to be send */ - if (CANmodule->CANtxCount > 0) { - uint16_t i; /* index of transmitting message */ - - /* first buffer */ - CO_CANtx_t *buffer = CANmodule->txArray; - /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0; i--) { - /* if message buffer is full, send it. */ - if(buffer->bufferFull) { - buffer->bufferFull = 0; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - CO_CANsendToModule(CANmodule, buffer); - break; /* exit for loop */ - } - buffer++; - }/* end of for loop */ - - /* Clear counter if no more messages */ - if(i == 0) CANmodule->CANtxCount = 0; - } -} - -/******************************************************************************/ -static uint8_t CO_CANsendToModule(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) -{ - CAN_TxMailBox_TypeDef* txMbox; - - /* Checks if the transmit mailbox is available */ - if ((CANmodule->CANdriverState->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { - txMbox = &CANmodule->CANdriverState->sTxMailBox[CO_CAN_TXMAILBOX]; - } - else { - return CAN_TxStatus_NoMailBox; - } - - /* ID: always assuming standard 11-bit ID */ - txMbox->TIR &= 1; - txMbox->TIR |= ((buffer->ident) | CAN_RTR_DATA); - - /* DLC */ - buffer->DLC &= (uint8_t)0x0000000F; - txMbox->TDTR &= (uint32_t)0xFFFFFFF0; - txMbox->TDTR |= buffer->DLC; - - /* Data field */ - txMbox->TDLR = (((uint32_t)buffer->data[3] << 24) | - ((uint32_t)buffer->data[2] << 16) | - ((uint32_t)buffer->data[1] << 8) | - ((uint32_t)buffer->data[0])); - - txMbox->TDHR = (((uint32_t)buffer->data[7] << 24) | - ((uint32_t)buffer->data[6] << 16) | - ((uint32_t)buffer->data[5] << 8) | - ((uint32_t)buffer->data[4])); - - /* Request transmission */ - txMbox->TIR |= 1; - - return 0; -} - -/******************************************************************************/ -static void CO_CANClkSetting (void) -{ - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); -} - -/******************************************************************************/ -static void CO_CANconfigGPIO (void) -{ - GPIO_InitTypeDef GPIO_InitStruct; - - GPIO_InitStruct.GPIO_Pin = GPIO_Pin_CAN_RX | GPIO_Pin_CAN_TX; - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_1; - GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; - GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; - - GPIO_Init(GPIO_CAN, &GPIO_InitStruct); - - /* Map to correct alternative function (9 == CAN) */ - GPIO_PinAFConfig(GPIO_CAN, GPIO_PinSource_CAN_RX, GPIO_AF_9); - GPIO_PinAFConfig(GPIO_CAN, GPIO_PinSource_CAN_TX, GPIO_AF_9); -} diff --git a/stack/STM32F3/CO_driver.h b/stack/STM32F3/CO_driver.h deleted file mode 100644 index 71db38bd..00000000 --- a/stack/STM32F3/CO_driver.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * CAN module object for ST STM32F334 microcontroller. - * - * @file CO_driver.h - * @author Janez Paternoster - * @author Ondrej Netik - * @author Vijayendra - * @author Jan van Lienden - * @author Petteri Mustonen - * @copyright 2013 Janez Paternoster - * - * 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 - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -/* Includes ------------------------------------------------------------------*/ -#include -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ -#include "stm32f30x.h" - -#define bool_t bool -#define CO_LITTLE_ENDIAN - -/* Exported define -----------------------------------------------------------*/ -#define PACKED_STRUCT __attribute__((packed)) -#define ALIGN_STRUCT_DWORD __attribute__((aligned(4))) - -/* Peripheral addresses */ -#define ADDR_CAN1 CAN1 - -/* Critical sections */ -#define CO_LOCK_CAN_SEND() __set_PRIMASK(1); -#define CO_UNLOCK_CAN_SEND() __set_PRIMASK(0); - -#define CO_LOCK_EMCY() __set_PRIMASK(1); -#define CO_UNLOCK_EMCY() __set_PRIMASK(0); - -#define CO_LOCK_OD() __set_PRIMASK(1); -#define CO_UNLOCK_OD() __set_PRIMASK(0); - -#define CLOCK_CAN RCC_APB1Periph_CAN1 - -#define CAN_REMAP_1 /* Select CAN1 remap 1 */ -#ifdef CAN1_NO_REMAP /* CAN1 not remapped */ -#define CLOCK_GPIO_CAN RCC_APB2Periph_GPIOA -#define GPIO_Remapping_CAN (0) -#define GPIO_CAN GPIOA -#define GPIO_Pin_CAN_RX GPIO_Pin_11 -#define GPIO_Pin_CAN_TX GPIO_Pin_12 -#define GPIO_PinSource_CAN_RX GPIO_PinSource11 -#define GPIO_PinSource_CAN_TX GPIO_PinSource12 -#define GPIO_CAN_Remap_State DISABLE -#endif -#ifdef CAN_REMAP_1 /* CAN1 remap 1 */ -#define CLOCK_GPIO_CAN RCC_AHBPeriph_GPIOB -#define GPIO_Remapping_CAN GPIO_Remap1_CAN1 -#define GPIO_CAN GPIOB -#define GPIO_Pin_CAN_RX GPIO_Pin_8 -#define GPIO_Pin_CAN_TX GPIO_Pin_9 -#define GPIO_PinSource_CAN_RX GPIO_PinSource8 -#define GPIO_PinSource_CAN_TX GPIO_PinSource9 -#define GPIO_CAN_Remap_State ENABLE -#endif - -#define CAN1_TX_INTERRUPTS CAN1_TX_IRQn -#define CAN1_RX0_INTERRUPTS CAN1_RX0_IRQn - -#define CO_CAN_TXMAILBOX ((uint8_t)0x00) - -/* Timeout for initialization */ - -#define INAK_TIMEOUT ((uint32_t)0x0000FFFF) -/* Data types */ - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - -/* CAN receive message structure as aligned in CAN module. - * prevzato z stm32f10_can.h - velikostne polozky a poradi odpovidaji. */ -typedef struct{ - uint32_t ident; /* Standard Identifier */ - uint32_t ExtId; /* Specifies the extended identifier */ - uint8_t IDE; /* Specifies the type of identifier for the - message that will be received */ - uint8_t RTR; /* Remote Transmission Request bit */ - uint8_t DLC; /* Data length code (bits 0...3) */ - uint8_t data[8]; /* 8 data bytes */ - uint8_t FMI; /* Specifies the index of the filter the message - stored in the mailbox passes through */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); // Changed by VJ -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint32_t ident; - uint8_t DLC; - uint8_t data[8]; - volatile uint8_t bufferFull; - volatile uint8_t syncFlag; -}CO_CANtx_t;/* ALIGN_STRUCT_DWORD; */ - - -/* CAN module object. */ -typedef struct{ - CAN_TypeDef *CANdriverState; /* STM32F4xx specific */ - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool CANnormal; - volatile bool useCANrxFilters; - //volatile uint8_t useCANrxFilters; - volatile uint8_t bufferInhibitFlag; - volatile uint8_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; -}CO_CANmodule_t; - -/* Exported variables -----------------------------------------------------------*/ - -/* Exported functions -----------------------------------------------------------*/ - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - -/* Initialize CAN module object. */ -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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - int8_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - int8_t rtr, - uint8_t noOfBytes, - int8_t syncFlag); - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* CAN interrupts receives and transmits CAN messages. */ -void CO_CANinterrupt_Rx(CO_CANmodule_t *CANmodule); -void CO_CANinterrupt_Tx(CO_CANmodule_t *CANmodule); - -#endif diff --git a/stack/dsPIC30F/CO_driver.c b/stack/dsPIC30F/CO_driver.c deleted file mode 100644 index d1d08b57..00000000 --- a/stack/dsPIC30F/CO_driver.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * CAN module object for Microchip dsPIC30F microcontroller. - * - * @file CO_driver.c - * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "CO_driver.h" -#include "CO_Emergency.h" - - -extern const CO_CANbitRateData_t CO_CANbitRateData[8]; - -/** - * Macro and Constants - CAN module registers - offset. - */ - #define CAN_REG(base, offset) (*((volatile uint16_t *) (((uintptr_t) base) + offset))) - - #define C_RXF0SID 0x00 - #define C_RXF0EIDH 0x02 - #define C_RXF0EIDL 0x04 - #define C_RXF1SID 0x08 - #define C_RXF1EIDH 0x0A - #define C_RXF1EIDL 0x0C - #define C_RXF2SID 0x10 - #define C_RXF2EIDH 0x12 - #define C_RXF2EIDL 0x14 - #define C_RXF3SID 0x18 - #define C_RXF3EIDH 0x1A - #define C_RXF3EIDL 0x1C - #define C_RXF4SID 0x20 - #define C_RXF4EIDH 0x22 - #define C_RXF4EIDL 0x24 - #define C_RXF5SID 0x28 - #define C_RXF5EIDH 0x2A - #define C_RXF5EIDL 0x2C - #define C_RXM0SID 0x30 - #define C_RXM0EIDH 0x32 - #define C_RXM0EIDL 0x34 - #define C_RXM1SID 0x38 - #define C_RXM1EIDH 0x3A - #define C_RXM1EIDL 0x3C - - #define C_TXBUF2 0x40 - #define C_TXBUF1 0x50 - #define C_TXBUF0 0x60 - #define C_TXSID 0x0 - #define C_TXEID 0x2 - #define C_TXDLC 0x4 - #define C_TXB 0x6 - #define C_TXCON 0xE - - #define C_RXBUF1 0x70 - #define C_RXBUF0 0x80 - #define C_RXCON 0xE - /* register alignment as in CO_CANrxMsg_t */ - - #define C_CTRL 0x90 - #define C_CFG1 0x92 - #define C_CFG2 0x94 - #define C_INTF 0x96 - #define C_INTE 0x98 - #define C_EC 0x9A - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ - uint16_t C_CTRLcopy = CAN_REG(CANdriverState, C_CTRL); - - /* set REQOP = 0x4 */ - C_CTRLcopy &= 0xFCFF; - C_CTRLcopy |= 0x0400; - CAN_REG(CANdriverState, C_CTRL) = C_CTRLcopy; - - /* while OPMODE != 4 */ - while((CAN_REG(CANdriverState, C_CTRL) & 0x00E0) != 0x0080); -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - uint16_t C_CTRLcopy = CAN_REG(CANmodule->CANdriverState, C_CTRL); - - /* set REQOP = 0x0 */ - C_CTRLcopy &= 0xF8FF; - CAN_REG(CANmodule->CANdriverState, C_CTRL) = C_CTRLcopy; - - /* while OPMODE != 0 */ - while((CAN_REG(CANmodule->CANdriverState, C_CTRL) & 0x00E0) != 0x0000); - - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - uint16_t i; - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->CANdriverState = CANdriverState; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = false; - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - CANmodule->em = NULL; - - for(i=0U; iCANdriverState); -} - - -/******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){ - return (rxMsg->ident >> 2) & 0x7FF; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){ - /* buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - uint16_t RXF, RXM; - - /* Configure object variables */ - buffer->object = object; - buffer->pFunct = pFunct; - - - /* CAN identifier and CAN mask, bit aligned with CAN module registers */ - RXF = (ident & 0x07FF) << 2; - if(rtr){ - RXF |= 0x02; - } - RXM = (mask & 0x07FF) << 2; - RXM |= 0x02; - - /* configure filter and mask */ - if(RXF != buffer->ident || RXM != buffer->mask){ - buffer->ident = RXF; - buffer->mask = RXM; - } - } - else{ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, bit aligned with CAN module registers */ - uint16_t TXF; - TXF = ident << 5; - TXF &= 0xF800; - TXF |= (ident & 0x003F) << 2; - if(rtr){ - TXF |= 0x02; - } - - /* write to buffer */ - buffer->ident = TXF; - buffer->DLC = noOfBytes; - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } - - return buffer; -} - - -/* Copy message to CAN module - internal usage only. - * - * @param dest Destination address of CAN module transmit buffer. - * @param src Pointer to source message . - */ -static void CO_CANsendToModule(uint16_t dest, CO_CANtx_t *src){ - uint8_t DLC; - volatile uint8_t *CANdataBuffer; - uint8_t *pData; - - /* CAN-ID + RTR */ - CAN_REG(dest, C_TXSID) = src->ident; - - /* Data lenght */ - DLC = src->DLC; - if(DLC > 8) DLC = 8; - CAN_REG(dest, C_TXDLC) = DLC << 3; - - /* copy data */ - CANdataBuffer = (volatile uint8_t*)(dest + C_TXB); - pData = src->data; - for(; DLC>0; DLC--) *(CANdataBuffer++) = *(pData++); - - /* control register, transmit request */ - CAN_REG(dest, C_TXCON) |= 0x08; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ - CO_ReturnError_t err = CO_ERROR_NO; - uint16_t addr = CANmodule->CANdriverState; - - /* Verify overflow */ - if(buffer->bufferFull){ - if(!CANmodule->firstCANtxMessage){ - /* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); - } - err = CO_ERROR_TX_OVERFLOW; - } - - CO_LOCK_CAN_SEND(); - /* if CAN TB buffer is free, copy message to it */ - if((CAN_REG(addr, C_TXBUF0 + C_TXCON) & 0x8) == 0 && CANmodule->CANtxCount == 0){ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - CO_CANsendToModule(addr + C_TXBUF0, buffer); - } - /* if no buffer is free, message will be sent by interrupt */ - else{ - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - CO_UNLOCK_CAN_SEND(); - - return err; -} - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ - - /* See generic driver for implemetation. */ -} - - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - uint8_t err; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - - err = CAN_REG(CANmodule->CANdriverState, C_INTF)>>8; - - if(CANmodule->errOld != err){ - CANmodule->errOld = err; - - /* CAN RX bus overflow */ - if(err & 0xC0){ - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0x3FFF;/* clear bits */ - } - - /* CAN TX bus off */ - if(err & 0x20){ - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - } - - /* CAN TX bus passive */ - if(err & 0x10){ - if(!CANmodule->firstCANtxMessage) CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - int8_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE); - if(isError){ - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - - /* CAN RX bus passive */ - if(err & 0x08){ - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err); - } - - /* CAN TX or RX bus warning */ - if(err & 0x19){ - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - } - } -} - - -/******************************************************************************/ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ - uint16_t ICODE; - ICODE = CAN_REG(CANmodule->CANdriverState, C_CTRL) & 0xE; - - /* receive interrupt 0 (New CAN messagge is available in RX buffer 0) */ - if(ICODE == 0xC){ - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint16_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - - rcvMsg = (CO_CANrxMsg_t*) (CANmodule->CANdriverState + C_RXBUF0); - rcvMsgIdent = rcvMsg->ident; - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - break; - } - buffer++; - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){ - buffer->pFunct(buffer->object, rcvMsg); - } - - /* Clear RXFUL flag */ - rcvMsg->CON &= 0xFF7F; - - /* Clear interrupt flag */ - CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFE; - } - - - /* receive interrupt 1 (New CAN messagge is available in RX buffer 1) */ - else if(ICODE == 0xA){ - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint16_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - - rcvMsg = (CO_CANrxMsg_t*) (CANmodule->CANdriverState + C_RXBUF1); - rcvMsgIdent = rcvMsg->ident; - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - break; - } - buffer++; - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){ - buffer->pFunct(buffer->object, rcvMsg); - } - - /* Clear RXFUL flag */ - rcvMsg->CON &= 0xFF7F; - - /* Clear interrupt flag */ - CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFD; - } - - - /* transmit interrupt (TX buffer is free) */ - else if(ICODE == 0x8){ - /* Clear interrupt flag */ - CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFB; - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = false; - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = false; - /* Are there any new messages waiting to be send and buffer is free */ - if(CANmodule->CANtxCount > 0U && (CAN_REG(CANmodule->CANdriverState, C_TXBUF0 + C_TXCON) & 0x8) == 0){ - uint16_t i; /* index of transmitting message */ - - /* first buffer */ - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0U; i--){ - /* if message buffer is full, send it. */ - if(buffer->bufferFull){ - buffer->bufferFull = false; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - CO_CANsendToModule(CANmodule->CANdriverState + C_TXBUF0, buffer); - break; /* exit for loop */ - } - buffer++; - }/* end of for loop */ - - /* Clear counter if no more messages */ - if(i == 0U){ - CANmodule->CANtxCount = 0U; - } - } - } -} diff --git a/stack/dsPIC30F/CO_driver.h b/stack/dsPIC30F/CO_driver.h deleted file mode 100644 index 3677fedd..00000000 --- a/stack/dsPIC30F/CO_driver.h +++ /dev/null @@ -1,452 +0,0 @@ -/* - * CAN module object for Microchip dsPIC30F microcontroller. - * - * @file CO_driver.h - * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_DRIVER_H -#define CO_DRIVER_H - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -#include /* processor header file */ -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ -#include /* for true and false */ - - -/* CAN module base address */ - #define ADDR_CAN1 0x300 - #define ADDR_CAN2 0x3C0 - - -/* Critical sections */ - #define CO_LOCK_CAN_SEND() asm volatile ("disi #0x3FFF") - #define CO_UNLOCK_CAN_SEND() asm volatile ("disi #0x0000") - - #define CO_LOCK_EMCY() asm volatile ("disi #0x3FFF") - #define CO_UNLOCK_EMCY() asm volatile ("disi #0x0000") - - #define CO_LOCK_OD() asm volatile ("disi #0x3FFF") - #define CO_UNLOCK_OD() asm volatile ("disi #0x0000") - - -/* Data types */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef unsigned char bool_t; - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* CAN bit rates - * - * CAN bit rates are initializers for array of eight CO_CANbitRateData_t - * objects. - * - * Macros are not used by driver itself, they may be used by application with - * combination with object CO_CANbitRateData_t. - * Application must declare following global variable depending on CO_FCY used: - * const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; - * - * There are initializers for eight objects, which corresponds to following - * CAN bit rates (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. - * - * CO_FCY is internal instruction cycle clock frequency in kHz units. It is - * calculated from oscillator frequency (FOSC [in kHz]) and PLL mode: - * - If PLL is not used -> FCY = FOSC / 4, - * - If PLL x 4 is used -> FCY = FOSC, - * - If PLL x 16 is used -> FCY = FOSC * 4 - * - * Possible values for FCY are (in three groups): - * - Optimal CAN bit timing on all Baud Rates: 4000, 6000, 16000, 24000. - * - Not so optimal CAN bit timing on all Baud Rates: 2000, 8000. - * - not all CANopen Baud Rates possible: 1000, 1500, 2500, 3000, 5000, - * 10000, 12000, 20000, 28000, 30000, 1843 (internal FRC, no PLL), - * 7372 (internal FRC + 4*PLL). - */ -#ifdef CO_FCY - /* Macros, which divides K into (SJW + PROP + PhSeg1 + PhSeg2) */ - #define TQ_x_4 1, 1, 1, 1 - #define TQ_x_5 1, 1, 2, 1 - #define TQ_x_6 1, 1, 3, 1 - #define TQ_x_8 1, 2, 3, 2 - #define TQ_x_9 1, 2, 4, 2 - #define TQ_x_10 1, 3, 4, 2 - #define TQ_x_12 1, 3, 6, 2 - #define TQ_x_14 1, 4, 7, 2 - #define TQ_x_15 1, 4, 8, 2 /* good timing */ - #define TQ_x_16 1, 5, 8, 2 /* good timing */ - #define TQ_x_17 1, 6, 8, 2 /* good timing */ - #define TQ_x_18 1, 7, 8, 2 /* good timing */ - #define TQ_x_19 1, 8, 8, 2 /* good timing */ - #define TQ_x_20 1, 8, 8, 3 /* good timing */ - #define TQ_x_21 1, 8, 8, 4 - #define TQ_x_25 1, 8, 8, 8 - - #if CO_FCY == 1000 - #define CO_CANbitRateDataInitializers \ - {4, 10, TQ_x_20}, /*CAN=10kbps*/ \ - {4, 5, TQ_x_20}, /*CAN=20kbps*/ \ - {4, 2, TQ_x_20}, /*CAN=50kbps*/ \ - {4, 1, TQ_x_16}, /*CAN=125kbps*/ \ - {4, 1, TQ_x_8 }, /*CAN=250kbps*/ \ - {4, 1, TQ_x_4 }, /*CAN=500kbps*/ \ - {4, 1, TQ_x_4 }, /*Not possible*/ \ - {4, 1, TQ_x_4 } /*Not possible*/ - #elif CO_FCY == 1500 - #define CO_CANbitRateDataInitializers \ - {4, 15, TQ_x_20}, /*CAN=10kbps*/ \ - {4, 10, TQ_x_15}, /*CAN=20kbps*/ \ - {4, 4, TQ_x_15}, /*CAN=50kbps*/ \ - {4, 2, TQ_x_12}, /*CAN=125kbps*/ \ - {4, 1, TQ_x_12}, /*CAN=250kbps*/ \ - {4, 1, TQ_x_6 }, /*CAN=500kbps*/ \ - {4, 1, TQ_x_6 }, /*Not possible*/ \ - {4, 1, TQ_x_6 } /*Not possible*/ - #elif CO_FCY == 1843 /* internal FRC, no PLL */ - #define CO_CANbitRateDataInitializers \ - {4, 23, TQ_x_16}, /*CAN=10kbps*/ \ - {4, 23, TQ_x_8 }, /*CAN=20kbps*/ \ - {4, 23, TQ_x_8 }, /*Not possible*/ \ - {4, 23, TQ_x_8 }, /*Not possible*/ \ - {4, 23, TQ_x_8 }, /*Not possible*/ \ - {4, 23, TQ_x_8 }, /*Not possible*/ \ - {4, 23, TQ_x_8 }, /*Not possible*/ \ - {4, 23, TQ_x_8 } /*Not possible*/ - #elif CO_FCY == 2000 - #define CO_CANbitRateDataInitializers \ - {4, 25, TQ_x_16}, /*CAN=10kbps*/ \ - {4, 10, TQ_x_20}, /*CAN=20kbps*/ \ - {4, 5, TQ_x_16}, /*CAN=50kbps*/ \ - {4, 2, TQ_x_16}, /*CAN=125kbps*/ \ - {4, 1, TQ_x_16}, /*CAN=250kbps*/ \ - {4, 1, TQ_x_8 }, /*CAN=500kbps*/ \ - {4, 1, TQ_x_5 }, /*CAN=800kbps*/ \ - {4, 1, TQ_x_4 } /*CAN=1000kbps*/ - #elif CO_FCY == 2500 - #define CO_CANbitRateDataInitializers \ - {4, 25, TQ_x_20}, /*CAN=10kbps*/ \ - {4, 10, TQ_x_25}, /*CAN=20kbps*/ \ - {4, 5, TQ_x_20}, /*CAN=50kbps*/ \ - {4, 2, TQ_x_20}, /*CAN=125kbps*/ \ - {4, 1, TQ_x_20}, /*CAN=250kbps*/ \ - {4, 1, TQ_x_10}, /*CAN=500kbps*/ \ - {4, 1, TQ_x_10}, /*Not possible*/ \ - {4, 1, TQ_x_5 } /*CAN=1000kbps*/ - #elif CO_FCY == 3000 - #define CO_CANbitRateDataInitializers \ - {4, 40, TQ_x_15}, /*CAN=10kbps*/ \ - {4, 20, TQ_x_15}, /*CAN=20kbps*/ \ - {4, 8, TQ_x_15}, /*CAN=50kbps*/ \ - {4, 3, TQ_x_16}, /*CAN=125kbps*/ \ - {4, 2, TQ_x_12}, /*CAN=250kbps*/ \ - {4, 1, TQ_x_12}, /*CAN=500kbps*/ \ - {4, 1, TQ_x_12}, /*Not possible*/ \ - {4, 1, TQ_x_6 } /*CAN=1000kbps*/ - #elif CO_FCY == 4000 - #define CO_CANbitRateDataInitializers \ - {4, 50, TQ_x_16}, /*CAN=10kbps*/ \ - {4, 25, TQ_x_16}, /*CAN=20kbps*/ \ - {4, 10, TQ_x_16}, /*CAN=50kbps*/ \ - {4, 4, TQ_x_16}, /*CAN=125kbps*/ \ - {4, 2, TQ_x_16}, /*CAN=250kbps*/ \ - {4, 1, TQ_x_16}, /*CAN=500kbps*/ \ - {4, 1, TQ_x_10}, /*CAN=800kbps*/ \ - {4, 1, TQ_x_8 } /*CAN=1000kbps*/ - #elif CO_FCY == 5000 - #define CO_CANbitRateDataInitializers \ - {4, 50, TQ_x_20}, /*CAN=10kbps*/ \ - {4, 25, TQ_x_20}, /*CAN=20kbps*/ \ - {4, 10, TQ_x_20}, /*CAN=50kbps*/ \ - {4, 5, TQ_x_16}, /*CAN=125kbps*/ \ - {4, 2, TQ_x_20}, /*CAN=250kbps*/ \ - {4, 1, TQ_x_20}, /*CAN=500kbps*/ \ - {4, 1, TQ_x_20}, /*Not possible*/ \ - {4, 1, TQ_x_10} /*CAN=1000kbps*/ - #elif CO_FCY == 6000 - #define CO_CANbitRateDataInitializers \ - {4, 63, TQ_x_19}, /*CAN=10kbps*/ \ - {4, 40, TQ_x_15}, /*CAN=20kbps*/ \ - {4, 15, TQ_x_16}, /*CAN=50kbps*/ \ - {4, 6, TQ_x_16}, /*CAN=125kbps*/ \ - {4, 3, TQ_x_16}, /*CAN=250kbps*/ \ - {4, 2, TQ_x_12}, /*CAN=500kbps*/ \ - {4, 1, TQ_x_15}, /*CAN=800kbps*/ \ - {4, 1, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FCY == 7372 /* internal FRC + 4*PLL */ - #define CO_CANbitRateDataInitializers \ - {1, 23, TQ_x_16}, /*CAN=10kbps*/ \ - {4, 46, TQ_x_16}, /*CAN=20kbps*/ \ - {4, 14, TQ_x_21}, /*CAN=50kbps*/ \ - {4, 13, TQ_x_9 }, /*CAN=125kbps*/ \ - {4, 13, TQ_x_9 }, /*Not possible*/ \ - {4, 13, TQ_x_9 }, /*Not possible*/ \ - {4, 13, TQ_x_9 }, /*Not possible*/ \ - {4, 13, TQ_x_9 } /*Not possible*/ - #elif CO_FCY == 8000 - #define CO_CANbitRateDataInitializers \ - {1, 25, TQ_x_16}, /*CAN=10kbps*/ \ - {1, 10, TQ_x_20}, /*CAN=20kbps*/ \ - {1, 5, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 2, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 1, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 1, TQ_x_8 }, /*CAN=500kbps*/ \ - {1, 1, TQ_x_5 }, /*CAN=800kbps*/ \ - {1, 1, TQ_x_4 } /*CAN=1000kbps*/ - #elif CO_FCY == 10000 - #define CO_CANbitRateDataInitializers \ - {1, 25, TQ_x_20}, /*CAN=10kbps*/ \ - {1, 10, TQ_x_25}, /*CAN=20kbps*/ \ - {1, 5, TQ_x_20}, /*CAN=50kbps*/ \ - {1, 2, TQ_x_20}, /*CAN=125kbps*/ \ - {1, 1, TQ_x_20}, /*CAN=250kbps*/ \ - {1, 1, TQ_x_10}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_10}, /*Not possible*/ \ - {1, 1, TQ_x_5 } /*CAN=1000kbps*/ - #elif CO_FCY == 12000 - #define CO_CANbitRateDataInitializers \ - {1, 40, TQ_x_15}, /*CAN=10kbps*/ \ - {1, 20, TQ_x_15}, /*CAN=20kbps*/ \ - {1, 8, TQ_x_15}, /*CAN=50kbps*/ \ - {1, 3, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 2, TQ_x_12}, /*CAN=250kbps*/ \ - {1, 1, TQ_x_12}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_12}, /*Not possible*/ \ - {1, 1, TQ_x_6 } /*CAN=1000kbps*/ - #elif CO_FCY == 16000 - #define CO_CANbitRateDataInitializers \ - {1, 50, TQ_x_16}, /*CAN=10kbps*/ \ - {1, 25, TQ_x_16}, /*CAN=20kbps*/ \ - {1, 10, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 4, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 2, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 1, TQ_x_16}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_10}, /*CAN=800kbps*/ \ - {1, 1, TQ_x_8 } /*CAN=1000kbps*/ - #elif CO_FCY == 20000 - #define CO_CANbitRateDataInitializers \ - {1, 50, TQ_x_20}, /*CAN=10kbps*/ \ - {1, 25, TQ_x_20}, /*CAN=20kbps*/ \ - {1, 10, TQ_x_20}, /*CAN=50kbps*/ \ - {1, 5, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 2, TQ_x_20}, /*CAN=250kbps*/ \ - {1, 1, TQ_x_20}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_20}, /*Not possible*/ \ - {1, 1, TQ_x_10} /*CAN=1000kbps*/ - #elif CO_FCY == 24000 - #define CO_CANbitRateDataInitializers \ - {1, 63, TQ_x_19}, /*CAN=10kbps*/ \ - {1, 40, TQ_x_15}, /*CAN=20kbps*/ \ - {1, 15, TQ_x_16}, /*CAN=50kbps*/ \ - {1, 6, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 3, TQ_x_16}, /*CAN=250kbps*/ \ - {1, 2, TQ_x_12}, /*CAN=500kbps*/ \ - {1, 1, TQ_x_15}, /*CAN=800kbps*/ \ - {1, 1, TQ_x_12} /*CAN=1000kbps*/ - #elif CO_FCY == 28000 - #define CO_CANbitRateDataInitializers \ - {1, 56, TQ_x_25}, /*CAN=10kbps*/ \ - {1, 35, TQ_x_20}, /*CAN=20kbps*/ \ - {1, 14, TQ_x_20}, /*CAN=50kbps*/ \ - {1, 7, TQ_x_16}, /*CAN=125kbps*/ \ - {1, 4, TQ_x_14}, /*CAN=250kbps*/ \ - {1, 2, TQ_x_14}, /*CAN=500kbps*/ \ - {1, 2, TQ_x_14}, /*Not possible*/ \ - {1, 1, TQ_x_14} /*CAN=1000kbps*/ - #elif CO_FCY == 30000 - #define CO_CANbitRateDataInitializers \ - {1, 60, TQ_x_25}, /*CAN=10kbps*/ \ - {1, 50, TQ_x_15}, /*CAN=20kbps*/ \ - {1, 20, TQ_x_15}, /*CAN=50kbps*/ \ - {1, 8, TQ_x_15}, /*CAN=125kbps*/ \ - {1, 4, TQ_x_15}, /*CAN=250kbps*/ \ - {1, 2, TQ_x_15}, /*CAN=500kbps*/ \ - {1, 2, TQ_x_15}, /*Not possible*/ \ - {1, 1, TQ_x_15} /*CAN=1000kbps*/ - #else - #error define_CO_FCY CO_FCY not supported - #endif -#endif - - -/* Structure contains timing coefficients for CAN module. - * - * CAN baud rate is calculated from following equations: - * FCAN = FCY * Scale - Input frequency to CAN module (MAX 30MHz for dsPIC30F) - * TQ = 2 * BRP / FCAN - Time Quanta - * BaudRate = 1 / (TQ * K) - Can bus Baud Rate - * K = SJW + PROP + PhSeg1 + PhSeg2 - Number of Time Quantas - */ -typedef struct{ - uint8_t scale; /* (1 or 4) Scales FCY clock - dsPIC30F specific */ - uint8_t BRP; /* (1...64) Baud Rate Prescaler */ - uint8_t SJW; /* (1...4) SJW time */ - uint8_t PROP; /* (1...8) PROP time */ - uint8_t phSeg1; /* (1...8) Phase Segment 1 time */ - uint8_t phSeg2; /* (1...8) Phase Segment 2 time */ -}CO_CANbitRateData_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. */ -typedef struct{ - uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: - 'UUUSSSSS SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ - uint16_t extIdent; /* Extended identifier, not used here */ - uint16_t DLC :4; /* Data length code (bits 0...3) */ - uint16_t DLCrest :12; /* Not used here (bits 4..15) */ - uint8_t data[8]; /* 8 data bytes */ - uint16_t CON; /* Control word */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - uint16_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: - 'SSSSSUUU SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ - uint8_t DLC; - uint8_t data[8]; - volatile bool_t bufferFull; - volatile bool_t syncFlag; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - void *CANdriverState; - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; -}CO_CANmodule_t; - - -/* Endianes */ -#define CO_LITTLE_ENDIAN - - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. */ -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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* CAN interrupt receives and transmits CAN messages. - * - * Function must be called directly from _C1Interrupt or _C2Interrupt with - * high priority. dsPIC30F uses two receive buffers and one transmit buffer. - */ -void CO_CANinterrupt(CO_CANmodule_t *CANmodule); - - -#endif diff --git a/stack/eCos/CO_Flash.c b/stack/eCos/CO_Flash.c deleted file mode 100644 index 91e1a4e9..00000000 --- a/stack/eCos/CO_Flash.c +++ /dev/null @@ -1,335 +0,0 @@ -/** - * eCos flash support for CANopen stack - * - * @file CO_Flash.c - * @author Uwe Kindler - * @copyright 2013 Uwe Kindler - * - * 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. - */ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include -#include - -#include "CANopen.h" - - -//============================================================================ -// DEFINES -//============================================================================ -#define CHECK_FLASH_RESULT(_result_) \ - if ((_result_) != CYG_FLASH_ERR_OK) { \ - CO_DBG_PRINT("Flash operation error: %s", cyg_flash_errmsg(_result_)); } -#define PARAM_STORE_PASSWORD 0x65766173 -#define PARAM_RESTORE_PASSWORD 0x64616F6C - - -//============================================================================ -// LOCAL DATA -//============================================================================ -static cyg_flash_info_t flash_info; -static const int CYGNUM_CANOPEN_FLASH_DATA_BLOCK = -3; -static cyg_flashaddr_t CO_OD_Flash_Adress; -static cyg_flashaddr_t CO_OD_Flash_Default_Param; -extern struct sCO_OD_ROM CO_OD_ROM; - - -enum CO_OD_H1010_StoreParam_Sub -{ - OD_H1010_STORE_PARAM_COUNT, - OD_H1010_STORE_PARAM_ALL, - OD_H1010_STORE_PARAM_COMM, - OD_H1010_STORE_PARAM_APP, - OD_H1010_STORE_PARAM_MANUFACTURER, - OD_H1010_STORE_PARAM_RESERVED = 0x80 -}; - -enum CO_OD_H1011_RestoreDefaultParam_Sub -{ - OD_H1011_RESTORE_PARAM_COUNT, - OD_H1011_RESTORE_PARAM_ALL, - OD_H1011_RESTORE_PARAM_COMM, - OD_H1011_RESTORE_PARAM_APP, - OD_H1011_RESTORE_PARAM_MANUFACTURER, - OD_H1011_RESTORE_PARAM_RESERVED = 0x80 -}; - - -enum CO_StorageFunctionality_Flags -{ - SAVES_PARAM_ON_COMMAND = 0x01, - SAVES_PARAM_AUTONOMOUSLY = 0x02 -}; - -enum CO_RestoreFunctionality_Flags -{ - RESTORES_PARAMETERS = 0x01 -}; - - -//============================================================================ -/** - * Store parameters of object dictionary into flash memory. - * \param[in] FlashAddress Use CO_OD_Flash_Adress for the normal parameter - * block and CO_OD_Flash_Default_Param for the - * default parameters - */ -static CO_SDO_abortCode_t storeParameters(cyg_flashaddr_t FlashAddress, - uint8_t ParametersSub) -{ - CO_DBG_PRINT("Store parameters\n"); - - cyg_flashaddr_t ErrorAddress; - - //unlock flash -#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING - int Result = cyg_flash_unlock(FlashAddress, sizeof(struct sCO_OD_ROM), - &ErrorAddress); - CHECK_FLASH_RESULT(Result); - if (CYG_FLASH_ERR_OK != Result) - { - return CO_SDO_AB_HW; - } -#endif - - // erase block - Result = cyg_flash_erase(FlashAddress, sizeof(struct sCO_OD_ROM), - &ErrorAddress); - CHECK_FLASH_RESULT(Result); - if (CYG_FLASH_ERR_OK != Result) - { - return CO_SDO_AB_HW; - } - - // program data into flash - Result = cyg_flash_program(FlashAddress, &CO_OD_ROM, - sizeof(CO_OD_ROM), &ErrorAddress); - CHECK_FLASH_RESULT(Result); - if (CYG_FLASH_ERR_OK != Result) - { - return CO_SDO_AB_HW; - } - - return CO_SDO_AB_NONE; -} - - -//============================================================================ -/** - * Restore parameters of object dictionary from flash memory. - * \param[in] FlashAddress Use CO_OD_Flash_Adress for the normal parameter - * block and CO_OD_Flash_Default_Param for the - * default parameters - */ -static CO_SDO_abortCode_t restoreParameters(cyg_flashaddr_t FlashAddress, - uint8_t ParametersSub) -{ - CO_DBG_PRINT("Restore parameters\n"); - cyg_flashaddr_t ErrorAddress; - int Result = cyg_flash_read(FlashAddress, &CO_OD_ROM, - sizeof(CO_OD_ROM), &ErrorAddress); - CHECK_FLASH_RESULT(Result); - if (CYG_FLASH_ERR_OK != Result) - { - return CO_SDO_AB_HW; - } - return CO_SDO_AB_NONE; -} - - -//============================================================================ -/** - * Access to object dictionary OD_H1010_STORE_PARAM_FUNC - */ -static CO_SDO_abortCode_t CO_ODF_1010_StoreParam(CO_ODF_arg_t *ODF_arg) -{ - CO_DBG_PRINT("CO_ODF_1010 Sub: %d\n", ODF_arg->subIndex); - CO_DBG_PRINT("sizeof(sCO_OD_ROM): %d", sizeof(CO_OD_ROM)); - uint32_t* value = (uint32_t*)ODF_arg->data; - if (ODF_arg->reading) - { - if(OD_H1010_STORE_PARAM_ALL == ODF_arg->subIndex) - { - *value = SAVES_PARAM_ON_COMMAND; - } - return CO_SDO_AB_NONE; - } - - if(OD_H1010_STORE_PARAM_ALL != ODF_arg->subIndex) - { - return CO_SDO_AB_NONE; - } - - if (*value != PARAM_STORE_PASSWORD) - { - return CO_SDO_AB_DATA_TRANSF; - } - - return storeParameters(CO_OD_Flash_Adress, ODF_arg->subIndex); -} - -//============================================================================ -/** - * Access to object dictionary OD_H1010_STORE_PARAM_FUNC - */ -static CO_SDO_abortCode_t CO_ODF_1011_RestoreParam(CO_ODF_arg_t *ODF_arg) -{ - CO_DBG_PRINT("CO_ODF_1010 Sub: %d\n", ODF_arg->subIndex); - CO_DBG_PRINT("sizeof(sCO_OD_ROM): %d", sizeof(CO_OD_ROM)); - uint32_t* value = (uint32_t*)ODF_arg->data; - if (ODF_arg->reading) - { - if (OD_H1011_RESTORE_PARAM_ALL == ODF_arg->subIndex) - { - *value = RESTORES_PARAMETERS; - } - return CO_SDO_AB_NONE; - } - - if (OD_H1011_RESTORE_PARAM_ALL != ODF_arg->subIndex) - { - return CO_SDO_AB_NONE; - } - - if (*value != PARAM_RESTORE_PASSWORD) - { - return CO_SDO_AB_DATA_TRANSF; - } - - CO_SDO_abortCode_t Result = restoreParameters(CO_OD_Flash_Default_Param, - ODF_arg->subIndex); - if (Result != CO_SDO_AB_NONE) - { - CO_DBG_PRINT("restoreParameters returned error"); - return Result; - } - - return storeParameters(CO_OD_Flash_Adress, OD_H1011_RESTORE_PARAM_ALL); -} - - -//=========================================================================== -/** - * Initialize flash library and data storage in flash - * We use two blocks in flash for data storage. One block is used for the - * default data that will be restored. The default parameters are stored - * at address CO_OD_Flash_Default_Param. The data that will be loaded at - * startup or saved if user modifies data is store at CO_OD_Flash_Adress. - */ -void CO_FlashInit(void) -{ - int i = 0; - // - // Initialize flash library - // - int Result = cyg_flash_init(0); - CHECK_FLASH_RESULT(Result); -#ifdef CYGDBG_IO_CANOPEN_DEBUG - cyg_flash_set_global_printf(diag_printf); -#endif - - // - // Read info about flash device (number of blocks. block size) - // - Result = cyg_flash_get_info(0, &flash_info); - CHECK_FLASH_RESULT(Result); - CO_DBG_PRINT("Flash info dev %d: 0x%x - 0x%x, %d blocks\n", 0, flash_info.start, - flash_info.end, flash_info.num_block_infos); - const cyg_flash_block_info_t* block_info = flash_info.block_info; - for (i = 0; i < flash_info.num_block_infos; ++i) - { - CO_DBG_PRINT("Block %d: block size: %d blocks: %d\n", i, - block_info->block_size, block_info->blocks); - block_info++; - } - - // - // Calculate addresses for flash data and default flash data - // - block_info = &flash_info.block_info[flash_info.num_block_infos - 1]; - CO_DBG_PRINT("Last block - block size: %d blocks: %d\n", - block_info->block_size, block_info->blocks); - CO_OD_Flash_Adress = flash_info.end + 1 + - (CYGNUM_CANOPEN_FLASH_DATA_BLOCK * block_info->block_size); - CO_DBG_PRINT("CO_OD_Flash_Adress 0x%8x\n", CO_OD_Flash_Adress); - CO_OD_Flash_Default_Param = CO_OD_Flash_Adress - block_info->block_size; - CO_DBG_PRINT("CO_OD_Flash_Default_Param 0x%8x\n", CO_OD_Flash_Default_Param); - - // - // Before we can access the data, we need to make sure, that the flash - // block are properly initialized. We do this by reading the block into - // a local sCO_OD_ROM variable and verifying the FirstWord and LastWord - // members - // - cyg_flashaddr_t ErrorAddress; - struct sCO_OD_ROM DefaultObjDicParam; - Result = cyg_flash_read(CO_OD_Flash_Default_Param, &DefaultObjDicParam, - sizeof(DefaultObjDicParam), &ErrorAddress); - CHECK_FLASH_RESULT(Result); - - // - // If the default parameters are not present in flash, then we know that - // we need to create them for later restore - // - if ((DefaultObjDicParam.FirstWord != CO_OD_FIRST_LAST_WORD) - ||(DefaultObjDicParam.LastWord != CO_OD_FIRST_LAST_WORD)) - { - storeParameters(CO_OD_Flash_Adress, OD_H1010_STORE_PARAM_ALL); - storeParameters(CO_OD_Flash_Default_Param, OD_H1010_STORE_PARAM_ALL); - } - else - { - restoreParameters(CO_OD_Flash_Adress, OD_H1010_STORE_PARAM_ALL); - } -} - - -//=========================================================================== -void CO_FlashRegisterODFunctions(CO_t* CO) -{ - CO_OD_configure(CO->SDO, OD_H1010_STORE_PARAM_FUNC, - CO_ODF_1010_StoreParam, (void*)0, 0, 0); - CO_OD_configure(CO->SDO, OD_H1011_REST_PARAM_FUNC, - CO_ODF_1011_RestoreParam, (void*)0, 0, 0); -} - -//--------------------------------------------------------------------------- -// EOF CO_flash.c diff --git a/stack/eCos/CO_Flash.h b/stack/eCos/CO_Flash.h deleted file mode 100644 index f5c514c6..00000000 --- a/stack/eCos/CO_Flash.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef CO_FlashH -#define CO_FlashH -/** - * eCos flash support for CANopen stack - * - * @file CO_Flash.h - * @author Uwe Kindler - * @copyright 2013 Uwe Kindler - * - * 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. - */ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include "CANopen.h" - -/** - * Initialize flash library and data storage in flash - * We use two blocks in flash for data storage. One block is used for the - * default data that will be restored. The default parameters are stored - * at address CO_OD_Flash_Default_Param. The data that will be loaded at - * startup or saved if user modifies data. - */ -void CO_FlashInit(void); - -/** - * Register object dictionary functions for parameter storage and restoring - * parameters (Object dictionary index 0x1010 Store Param and 0x1011 Restore - * default param. - */ -void CO_FlashRegisterODFunctions(CO_t* CO); - - -//--------------------------------------------------------------------------- -#endif // CO_FlashH diff --git a/stack/eCos/CO_PollingTimer.c b/stack/eCos/CO_PollingTimer.c deleted file mode 100644 index 8e62ee55..00000000 --- a/stack/eCos/CO_PollingTimer.c +++ /dev/null @@ -1,88 +0,0 @@ -//=========================================================================== -/// \file CO_PollingTimer.c -/// \author Uwe Kindler (UK) -/// \date 2013/08/28 -/// \brief Implementation of simple polling timer -//=========================================================================== - - -//=========================================================================== -// INCLUDES -//=========================================================================== -#include -#include "CO_PollingTimer.h" -#include "ecos_helper.h" - - - -//=========================================================================== -cyg_uint64 CO_TmrGetMilliSec(void) -{ - return convertTicksToMs(cyg_current_time()); -} - - -//=========================================================================== -cyg_uint64 CO_TmrGetElapsedMsecs(cyg_uint64 LastTimeStamp) -{ - return CO_TmrGetMilliSec() - LastTimeStamp; -} - - -//=========================================================================== -bool CO_TmrIsExpired(cyg_uint64 LastTimeStamp) -{ - cyg_uint64 dwTimeNow = CO_TmrGetMilliSec(); - cyg_uint64 dwTimestamp = (LastTimeStamp + 1); - - if (dwTimeNow > dwTimestamp) - { - if ((dwTimeNow - dwTimestamp) < 0x8000000000000000) - { - return true; - } - else - { - return false; - } - } - else // if (dwTimeNow <= dwTimestamp) - { - if ((dwTimestamp - dwTimeNow) > 0x8000000000000000) - { - return true; - } - else - { - return false; - } - } // if (time_now <= timestamp) -} - - -//=========================================================================== -cyg_uint64 CO_TmrStartFrom(cyg_uint64 dwStartTime, cyg_uint64 dwPeriod) -{ - cyg_uint64 TimeStamp = dwStartTime + dwPeriod; - // if resulting time stamp is in the past, then we fix the time stamp value - // and move it to now - if (TimeStamp < CO_TmrGetMilliSec()) - { - return CO_TmrGetMilliSec(); - } - else - { - return TimeStamp; - } -} - -//=========================================================================== -cyg_uint64 CO_TmrStartFromNow(cyg_uint64 dwPeriod) -{ - return CO_TmrGetMilliSec() + dwPeriod; -} - - -//---------------------------------------------------------------------------- -// end of CO_PollingTimer.c - diff --git a/stack/eCos/CO_PollingTimer.h b/stack/eCos/CO_PollingTimer.h deleted file mode 100644 index 87af5e1b..00000000 --- a/stack/eCos/CO_PollingTimer.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef CO_PollingTimerH -#define CO_PollingTimerH -//=========================================================================== -/// \file PollingTimer.h -/// \author Uwe Kindler (UK) -/// \date 2013/08/28 -/// \brief Declaration of simple polling timer class. -//=========================================================================== - - -//=========================================================================== -// INCLUDES -//=========================================================================== -#include - - -/// -/// Query actual time in milliseconds. -/// \return Actual time in milliseconds since system start -/// An implementation for a certain platform needs to implement this -/// static function -/// -cyg_uint64 CO_TmrGetMilliSec(void); - -/** - * Returns the expired time since given timestamp - * \return getMilliSec() - LastTimeStamp - */ -cyg_uint64 CO_TmrGetElapsedMsecs(cyg_uint64 LastTimeStamp); - -/// -/// Returns true if timer is expired -/// -bool CO_TmrIsExpired(cyg_uint64 LastTimeStamp); - - -/// -/// Set timer expiration time starting from given dwStartTime. -/// \param[in] dwStartTime Time in milliseconds when timer starts -/// \param[in] dwPeriod Timer period in milliseconds -/// -cyg_uint64 CO_TmrStartFrom(cyg_uint64 dwStartTime, cyg_uint64 dwPeriod); - -/// -/// Set timer expiration time starting from now. -/// Function sets a new expiration time. Expiration time is calculated from -/// actual time + timer period. -/// \param[in] dwPeriod Timer period in milliseconds -/// -cyg_uint64 CO_TmrStartFromNow(cyg_uint64 dwPeriod); - - -//---------------------------------------------------------------------------- -#endif // CO_PollingTimerH diff --git a/stack/eCos/CO_driver.c b/stack/eCos/CO_driver.c deleted file mode 100644 index c883c4e0..00000000 --- a/stack/eCos/CO_driver.c +++ /dev/null @@ -1,886 +0,0 @@ -/* - * CAN module object for eCos CAN framework - * - * @file CO_driver_eCos.c - * @ingroup CO_driver - * @author Uwe Kindler - * @copyright 2013 Uwe Kindler - * - * 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. - */ - - -//=========================================================================== -// INCLUDES -//=========================================================================== -#include "CO_driver.h" -#include "CO_Emergency.h" -#include "ecos_helper.h" - -#include -#include -#include -#include -#include -#include - -// Package option requirements -#if defined(CYGFUN_KERNEL_API_C) -#if defined(CYGPKG_IO_CAN_DEVICES) -#if defined(CYGOPT_IO_CAN_RUNTIME_MBOX_CFG) -#if defined(CYGOPT_IO_CAN_STD_CAN_ID) -#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) -#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) - - -//=========================================================================== -// DEFINES -//=========================================================================== -#define UNUSED_ENTRY 0xFFFF // indicates unused entry in rx buffer array - - -//=========================================================================== -// DATA TYPES -//=========================================================================== -/** - * Stores thread data of a single thread object - */ -typedef struct st_thread_data -{ - cyg_thread obj; - long stack[CYGNUM_HAL_STACK_SIZE_TYPICAL]; - cyg_handle_t hdl; -} thread_data_t; - - -//=========================================================================== -// LOCAL DATA -//=========================================================================== -static cyg_thread_entry_t can_rx_thread;///< thread entry for RX thread -static thread_data_t can_rx_thread_data = { - hdl : 0 -}; -CO_CANmodule_t* can_module = 0;///< local CAN module object - if it is 0 then the module is not initialized - - -//=========================================================================== -/** - * This is a thin wrapper around CO_errorReport to enable some diagnostic output - */ -void CO_eCos_errorReport(CO_EM_t *em, const uint8_t errorBit, - const uint16_t errorCode, const uint32_t infoCode) -{ - CO_DBG_PRINT("CO_eCos_errorReport: errorBit %x errorCode %x infoCode %x\n", - errorBit, errorCode, infoCode); - CO_errorReport(em, errorBit, errorCode, infoCode); -} - - - -//=========================================================================== -/** - * This is a thin wrapper around CO_errorReset to enable some diagnostic output - */ -void CO_eCos_errorReset(CO_EM_t *em, const uint8_t errorBit, const uint32_t infoCode) -{ - CO_DBG_PRINT("CO_errorReset: errorBit %x infoCode %x\n", errorBit, infoCode); - CO_errorReset(em, errorBit, infoCode); -} - - -//============================================================================= -/** - * Call this function if you have a error return code != ENOERR. This function - * reports the error as an emergency message and prints an optional debug - * message - * \param[in] ErrCode Error code returned by eCos CAN function - * \param[in] CANmodule The CAN module object that caused the error - * \param[in] DebugMessage Optional debug message. If this is not 0, then a - * diagnostic message is printed with CO_DBG_PRINT - */ -static void reportErrorReturnCode(Cyg_ErrNo ErrCode, CO_CANmodule_t *CANmodule, - const char* DebugMessage) -{ - CO_EM_t* EM = (CO_EM_t*)CANmodule->em; - if (ENOERR == ErrCode) - { - return; - } - - CO_errorReport(EM, CO_EM_GENERIC_SOFTWARE_ERROR, - CO_EMC_SOFTWARE_DEVICE, ErrCode); - - if (DebugMessage) - { - CO_DBG_PRINT(DebugMessage, ErrCode); - } -} - - -//============================================================================= -/** - * Set mode of CAN controller (configuration, active...) - * This function properly handles errors when setting mode - */ -static void setCAN_Mode(cyg_can_mode mode, void *CANdriverState) -{ - if (!can_module) - { - return; - } - - cyg_uint32 len = sizeof(mode); - Cyg_ErrNo Result = cyg_io_set_config(can_module->ioHandle, - CYG_IO_SET_CONFIG_CAN_MODE ,&mode, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, can_module, 0); - CO_DBG_PRINT("Set CAN mode %d returned error %x\n", - mode, Result); - } -} - - -//============================================================================= -void CO_CANsetConfigurationMode(void *CANdriverState) -{ - setCAN_Mode(CYGNUM_CAN_MODE_CONFIG, CANdriverState); -} - - -//============================================================================= -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) -{ - setCAN_Mode(CYGNUM_CAN_MODE_START, CANmodule->CANdriverState); - - CANmodule->CANnormal = true; -} - - -//============================================================================= -/** - * Translates CANopen node bitrate into eCos bitrate identifier - */ -cyg_can_baud_rate_t translateBaudRate(uint16_t CANbitRate) -{ - switch (CANbitRate) - { - case 10: return CYGNUM_CAN_KBAUD_10; - case 20: return CYGNUM_CAN_KBAUD_20; - case 50: return CYGNUM_CAN_KBAUD_50; - case 100: return CYGNUM_CAN_KBAUD_100; - case 125: return CYGNUM_CAN_KBAUD_125; - case 250: return CYGNUM_CAN_KBAUD_250; - case 500: return CYGNUM_CAN_KBAUD_500; - case 800: return CYGNUM_CAN_KBAUD_800; - case 1000: return CYGNUM_CAN_KBAUD_1000; - } - - return CYGNUM_CAN_KBAUD_1000; -} - - - -//=========================================================================== -/** - * Prints CAN event via diagnostic output channel - */ -static void print_can_msg(cyg_can_message *pmsg, char *pMsg) -{ - char *pmsg_str; - static char* msg_tbl[] = - { - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X %02X %02X]\n" - }; - - if (pmsg->rtr) - { - CO_DBG_PRINT("%s [ID:%03X] [RTR:%d] [EXT:%d] [DLC:%d]\n", - pMsg, - pmsg->id, - pmsg->rtr, - pmsg->ext, - pmsg->dlc); - - return; - } - - if (pmsg->dlc > 8) - { - pmsg_str = msg_tbl[8]; - } - else - { - pmsg_str = msg_tbl[pmsg->dlc]; - } - - CO_DBG_PRINT(pmsg_str, - pMsg, - pmsg->id, - pmsg->rtr, - pmsg->ext, - pmsg->data.bytes[0], - pmsg->data.bytes[1], - pmsg->data.bytes[2], - pmsg->data.bytes[3], - pmsg->data.bytes[4], - pmsg->data.bytes[5], - pmsg->data.bytes[6], - pmsg->data.bytes[7]); -} - - -//=========================================================================== -/** - * Prints CAN event flags via diagnostic output channel - */ -static void print_can_flags(cyg_uint16 flags, char *pMsg) -{ - char *pmsg_str; - cyg_uint8 i ; - static char* msg_tbl[] = - { - "RX ", - "TX ", - "WRX ", - "WTX ", - "ERRP ", - "BOFF ", - "OVRX ", - "OVTX ", - "CERR ", - "LSTY ", - "ESTY ", - "ALOS ", - "DEVC ", - "PHYF ", - "PHYH ", - "PHYL ", - "ERRA ", - "OVRXHW " - }; - - i = 0; - while (flags && (i < 16)) - { - if (flags & 0x0001) - { - pmsg_str = msg_tbl[i]; - CO_DBG_PRINT(pmsg_str); - } - flags >>=1; - i++; - } - - CO_DBG_PRINT("\n"); -} - - -//=========================================================================== -/** - * The receive thread the reads the messages from the eCos CAN driver and - * calls the receive buffer callback functions to process the received messages - */ -void can_rx_thread(cyg_addrword_t data) -{ - cyg_uint32 len; - cyg_can_event rx_event; - CO_CANmodule_t* CANmodule = (CO_CANmodule_t*)data; - CO_EM_t* EM = (CO_EM_t*)CANmodule->em; - Cyg_ErrNo Result; - CO_DBG_PRINT("can_rx_thread started\n"); - - while (1) - { - // - // First receive CAN event from real CAN hardware and report an error - // if something goes wrong - // - len = sizeof(rx_event); - Result = cyg_io_read(CANmodule->ioHandle, &rx_event, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "cyg_io_read() returned error %x\n"); - continue; - } - - print_can_flags(rx_event.flags, "Received event"); - // - // Check if we received an RX event - if we have an RX event then we - // copy the received message data and call the receive buffer callback - // function - // - if (rx_event.flags & CYGNUM_CAN_EVENT_RX) - { - uint16_t BufferIndex = CANmodule->rxBufferIndexArray[rx_event.msg.id]; - if (UNUSED_ENTRY != BufferIndex) - { - CO_CANrx_t *msgBuff = &CANmodule->rxArray[BufferIndex]; - CO_CANrxMsg_t rcvMsg; - rcvMsg.ID = rx_event.msg.id; - rcvMsg.DLC = rx_event.msg.dlc; - rcvMsg.RTR = rx_event.msg.rtr; - memcpy(rcvMsg.data, rx_event.msg.data.bytes, rx_event.msg.dlc); - print_can_msg(&rx_event.msg, "Rx: "); - msgBuff->pFunct(msgBuff->object, &rcvMsg); - } - } // if (rx_event.flags & CYGNUM_CAN_EVENT_RX) - - if (rx_event.flags & CYGNUM_CAN_EVENT_OVERRUN_RX) - { - CO_eCos_errorReport(EM, CO_EM_RXMSG_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); - } - - if (rx_event.flags & CYGNUM_CAN_EVENT_OVERRUN_RX_HW) - { - CO_eCos_errorReport(EM, CO_EM_RXMSG_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); - } - CO_DBG_PRINT("processing can_rx_thread\n"); - } // while (1) -} - - -//============================================================================ -Cyg_ErrNo canInit(CO_CANmodule_t* CANmodule, uint16_t CANbitRate) -{ - cyg_uint32 len; - cyg_can_info_t can_info; - cyg_can_msgbuf_cfg msgbox_cfg; - - // - // Get a valid device handle for CAN device 0 - // - Cyg_ErrNo Result = cyg_io_lookup("/dev/can0", &CANmodule->ioHandle); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "cyg_io_lookup(/dev/can0) returned error: %x\n"); - return Result; - } - - // - // Set sending CAN messages to non blocking mode because it happens in - // main thread and main thread should never be blocked - // - cyg_uint32 blocking = 0; - len = sizeof(blocking); - Result = cyg_io_set_config(CANmodule->ioHandle, - CYG_IO_SET_CONFIG_WRITE_BLOCKING, &blocking, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYG_IO_SET_CONFIG_WRITE_BLOCKING %x\n"); - return Result; - } - - // - // Set receiving CAN events to blocking mode because it happens in - // dedicated receive thread - // - blocking = 1; - len = sizeof(blocking); - Result = cyg_io_set_config(CANmodule->ioHandle, - CYG_IO_SET_CONFIG_READ_BLOCKING, &blocking, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYG_IO_SET_CONFIG_READ_BLOCKING %x\n"); - return Result; - } - - // - // Set TX timeout to 0 because function shall return immediately if - // send queue is full - // - cyg_can_timeout_info_t timeouts; - timeouts.rx_timeout = convertMsToTicks(1000);// 1000 ms converted to clock ticks - timeouts.tx_timeout = 0; - len = sizeof(timeouts); - Result = cyg_io_set_config(CANmodule->ioHandle, - CYG_IO_SET_CONFIG_CAN_TIMEOUT, &timeouts, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYG_IO_SET_CONFIG_CAN_TIMEOUT %x\n"); - return Result; - } - - // - // Flush output - this is required in case of reset - // - Result = cyg_io_set_config(CANmodule->ioHandle, - CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH, 0, 0); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH returned error: %x\n"); - return Result; - } - - // - // Set baudrate - // - can_info.baud = translateBaudRate(CANbitRate); - len = sizeof(can_info); - Result = cyg_io_set_config(CANmodule->ioHandle, CYG_IO_SET_CONFIG_CAN_INFO, &can_info, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "Setting baudrate returned error: %x\n"); - return Result; - } - - // - // Now reset message buffer configuration - this is mandatory before starting - // message buffer runtime configuration - // - msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL; - len = sizeof(msgbox_cfg); - Result = cyg_io_set_config(CANmodule->ioHandle, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&msgbox_cfg, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYGNUM_CAN_MSGBUF_RESET_ALL returned error: %x\n"); - return Result; - } - - if (!can_rx_thread_data.hdl) - { - // - // create receive thread if it has not been created yet - // - cyg_thread_create(4, can_rx_thread, - (cyg_addrword_t)CANmodule, - "can_rx_thread", - (void *) can_rx_thread_data.stack, - CYGNUM_HAL_STACK_SIZE_TYPICAL * sizeof(long), - &can_rx_thread_data.hdl, - &can_rx_thread_data.obj); - - cyg_thread_resume(can_rx_thread_data.hdl); - } - CO_DBG_PRINT("CAN driver initialised\n"); - return ENOERR; -} - - -/******************************************************************************/ -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) -{ - uint16_t i; - - /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->curentSyncTimeIsInsideWindow = 0; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = 1;// we can make this configurable - CANmodule->bufferInhibitFlag = 0; - CANmodule->firstCANtxMessage = 1; - CANmodule->CANtxCount = 0; - CANmodule->errOld = 0; - CANmodule->em = 0; - memset(CANmodule->rxBufferIndexArray, UNUSED_ENTRY, sizeof(CANmodule->rxBufferIndexArray)); - - for(i=0; irxArray[i].ident = 0; - CANmodule->rxArray[i].pFunct = 0; - } - for(i=0; itxArray[i].bufferFull = 0; - } - - Cyg_ErrNo Result = canInit(CANmodule, CANbitRate); - if (ENOERR != Result) - { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - return CO_ERROR_NO; -} - - -//============================================================================= -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) -{ - setCAN_Mode(CYGNUM_CAN_MODE_STOP, ADDR_CAN1); -} - - -//============================================================================= -uint16_t CO_CANrxMsg_readIdent(CO_CANrxMsg_t *rxMsg) -{ - return rxMsg->ID; -} - - -//============================================================================= -Cyg_ErrNo hwCANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t ident) -{ - CO_DBG_PRINT("hwCANrxBufferInit %x\n", ident); - cyg_can_filter rx_filter; - cyg_uint32 len; - rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ADD; - rx_filter.msg.id = ident & 0x07FF; - rx_filter.msg.ext = CYGNUM_CAN_ID_STD; - len = sizeof(rx_filter); - return cyg_io_set_config(CANmodule->ioHandle, - CYG_IO_SET_CONFIG_CAN_MSGBUF ,&rx_filter, &len); -} - - -//============================================================================= -void updateHardwareFilters(CO_CANmodule_t *CANmodule) -{ - cyg_uint32 len; - cyg_can_msgbuf_cfg msgbox_cfg; - uint16_t i = 0; - - CO_DBG_PRINT("updateHardwareFilters()\n"); - // - // Now reset message buffer configuration - this is mandatory before starting - // message buffer runtime configuration - // - msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL; - len = sizeof(msgbox_cfg); - Cyg_ErrNo Result = cyg_io_set_config(CANmodule->ioHandle, - CYG_IO_SET_CONFIG_CAN_MSGBUF ,&msgbox_cfg, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYGNUM_CAN_MSGBUF_RESET_ALL returned error: %x\n"); - return; - } - - memset(CANmodule->rxBufferIndexArray, UNUSED_ENTRY, sizeof(CANmodule->rxBufferIndexArray)); - // new iterate through all buffers and set all filters - for (i = 0; i < CANmodule->rxSize; ++i) - { - CO_CANrx_t* rxBuffer = &CANmodule->rxArray[i]; - if (!rxBuffer->pFunct) - { - continue; - } - - uint16_t CAN_ID = rxBuffer->ident &= ~0x800; - Result = hwCANrxBufferInit(CANmodule, CAN_ID); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYGNUM_CAN_MSGBUF_RX_FILTER_ADD returned error: %x\n"); - return; - } - CANmodule->rxBufferIndexArray[CAN_ID] = i; - } -} - - -//============================================================================= -int16_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - uint8_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_CANrx_t *rxBuffer; - int16_t ret = CO_ERROR_NO; - bool enable_buffer = true; - - /* safety */ - if(!CANmodule || !object || !pFunct || index >= CANmodule->rxSize){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* buffer, which will be configured */ - rxBuffer = &CANmodule->rxArray[index]; - - /* Configure object variables */ - rxBuffer->object = object; - - /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */ - rxBuffer->ident = ident & 0x07FF; - if(rtr) rxBuffer->ident |= 0x0800; - - if(!CANmodule->useCANrxFilters) - { - return ret; - } - - enable_buffer = (0 != ident) || (index == 0); - - if (!enable_buffer) - { - if (!rxBuffer->pFunct) - { - return ret; - } - - rxBuffer->pFunct = 0; - updateHardwareFilters(CANmodule); - return ret; - } - - rxBuffer->pFunct = pFunct; - CO_DBG_PRINT("Setting hardware filter ID: %x Mask: %x Buffer: %d\n", ident, mask,index); - CYG_ASSERT(ident < 0x800, "Illegal CAN identifier > 0x800"); - if (UNUSED_ENTRY != CANmodule->rxBufferIndexArray[ident]) - { - return CO_ERROR_NO; - } - - CANmodule->rxBufferIndexArray[ident] = index; - Cyg_ErrNo Result = hwCANrxBufferInit(CANmodule, ident); - if (ENOERR != Result) - { - ret = CO_ERROR_OUT_OF_MEMORY; - } - can_module = CANmodule; - - return ret; -} - - -//============================================================================= -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint8_t rtr, - uint8_t noOfBytes, - uint8_t syncFlag) -{ - /* safety */ - if(!CANmodule || CANmodule->txSize <= index) return 0; - - /* get specific buffer */ - CO_CANtx_t *buffer = &CANmodule->txArray[index]; - - buffer->ID = ident; - buffer->DLC = noOfBytes; - buffer->RTR = rtr; - buffer->bufferFull = 0; - buffer->syncFlag = syncFlag ? 1 : 0; - - return buffer; -} - - -//============================================================================= -int16_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) -{ - int16_t Ret = CO_ERROR_NO; - - // messages with syncFlag set (synchronous PDOs) must be transmited inside preset time window - if(CANmodule->curentSyncTimeIsInsideWindow && buffer->syncFlag && !(*CANmodule->curentSyncTimeIsInsideWindow)) - { - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, 0); - return CO_ERROR_TX_PDO_WINDOW; - } - - cyg_uint32 len; - cyg_can_message tx_msg; - - len = sizeof(tx_msg); - tx_msg.id = buffer->ID; - tx_msg.dlc = buffer->DLC; - tx_msg.rtr = buffer->RTR ? CYGNUM_CAN_FRAME_RTR : CYGNUM_CAN_FRAME_DATA; - tx_msg.ext = CYGNUM_CAN_ID_STD; - memcpy(tx_msg.data.bytes, buffer->data, buffer->DLC); - Cyg_ErrNo Result = cyg_io_write(CANmodule->ioHandle, &tx_msg, &len); - if (ENOERR == Result) - { - CANmodule->firstCANtxMessage = 0; - buffer->bufferFull = 0; - } - else - { - CO_eCos_errorReport((CO_EM_t*)CANmodule->em, - CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); - CO_DBG_PRINT("cyg_io_write() returned error %x\n", Result); - Ret = CO_ERROR_TIMEOUT; - } - - return Ret; -} - - -//============================================================================= -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) -{ - // we do nothing here. eCos has a transmit queue and if the messages - // are in the queue then we can't do anything - the message will get - // transmitted -} - - - -//============================================================================= -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - uint16_t rxErrors = 0; - uint16_t txErrors = 0; - CO_EM_t* EM = (CO_EM_t*)CANmodule->em; - Cyg_ErrNo Result; - cyg_uint32 len; - cyg_can_err_count_info err_info; - - len = sizeof(err_info); - Result = cyg_io_get_config(CANmodule->ioHandle, CYG_IO_GET_CONFIG_CAN_ERR_COUNTERS, - &err_info, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYG_IO_GET_CONFIG_CAN_ERR_COUNTERS returned error: %x\n"); - return; - } - - txErrors = err_info.tx_err_count; - rxErrors = err_info.rx_err_count; - - cyg_can_state can_state; - len = sizeof(cyg_can_state); - Result = cyg_io_get_config(CANmodule->ioHandle, CYG_IO_GET_CONFIG_CAN_STATE, - &can_state, &len); - if (ENOERR != Result) - { - reportErrorReturnCode(Result, CANmodule, - "CYG_IO_GET_CONFIG_CAN_STATE returned error: %x\n"); - return; - } - - if (CYGNUM_CAN_STATE_BUS_OFF == can_state) - { - txErrors = 256; - } - - uint32_t err = txErrors << 8 | rxErrors; - if (CANmodule->errOld == err) - { - return; - } - - CANmodule->errOld = err; - - // Bus off - if(txErrors >= 256) - { - CO_eCos_errorReport(EM, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - return; - } - CO_eCos_errorReset(EM, CO_EM_CAN_TX_BUS_OFF, err); - - // bus warning - if ((rxErrors >= 96) || (txErrors >= 96)) - { - CO_eCos_errorReport(EM, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - - // rx bus passive - if (rxErrors >= 128) - { - CO_eCos_errorReport(EM, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else - { - CO_eCos_errorReset(EM, CO_EM_CAN_RX_BUS_PASSIVE, err); - } - - // tx bus passive - if (txErrors >= 128) - { - CO_eCos_errorReport(EM, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else - { - CO_eCos_errorReset(EM, CO_EM_CAN_TX_BUS_PASSIVE, err); - } - - // no error - if ((rxErrors < 96) && (txErrors < 96)) - { - CO_eCos_errorReset(EM, CO_EM_CAN_BUS_WARNING, err); - } -} - -#else // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS -#error "Needs support for CAN timeouts - CYGOPT_IO_CAN_SUPPORT_TIMEOUTS" -#endif - -#else // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING -#error "Needs support for non blocking read / write calls - CYGOPT_IO_CAN_SUPPORT_NONBLOCKING" -#endif - -#else // CYGOPT_IO_CAN_STD_CAN_ID -#error "Needs support for CAN standard 11 Bit identifiers - CYGOPT_IO_CAN_STD_CAN_ID" -#endif - -#else // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -#error "Needs support for CAN message buffer runtime configuration - CYGOPT_IO_CAN_RUNTIME_MBOX_CFG" -#endif - -#else // CYGPKG_IO_CAN_DEVICES -#error "Needs CAN hardware device drivers - CYGPKG_IO_CAN_DEVICES" -#endif - -#else // CYGFUN_KERNEL_API_C) -#error "Needs kernel C API" -#endif diff --git a/stack/eCos/CO_driver.h b/stack/eCos/CO_driver.h deleted file mode 100644 index 0553e337..00000000 --- a/stack/eCos/CO_driver.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * CAN module object for eCos RTOS CAN layer - * - * @file CO_driver.h - * @author Uwe Kindler - * @copyright 2013 Uwe Kindler - * - * 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 - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -//=========================================================================== -// INCLUDES -//=========================================================================== -#include -#include -#include -#include - - -//=========================================================================== -// CONFIGURATION -//=========================================================================== -#define CYGDBG_IO_CANOPEN_DEBUG 1 // define this if you want debug output via diagnostic channel - - -//=========================================================================== -// DEFINES -//=========================================================================== -#if (CYG_BYTEORDER == CYG_MSBFIRST) -#define CO_BIG_ENDIAN 1 -#else -#define CO_LITTLE_ENDIAN 1 -#endif - -// -// Support debug output if this option is enabled in CDL file -// -#ifdef CYGDBG_IO_CANOPEN_DEBUG -#define CO_DBG_PRINT diag_printf -#else -#define CO_DBG_PRINT( fmt, ... ) -#endif - -/* CAN module base address */ -// we don't really care about the addresses here because the eCos port -// uses I/O handles for accessing its CAN devices - #define ADDR_CAN1 0 - #define ADDR_CAN2 1 - - -/* Critical sections */ -// shared data is accessed only from thread level code (not from ISR or DSR) -// so we simply do a scheduler lock here to prevent access from different -// threads - #define CO_LOCK_CAN_SEND() cyg_scheduler_lock() - #define CO_UNLOCK_CAN_SEND() cyg_scheduler_unlock() - - #define CO_LOCK_EMCY() cyg_scheduler_lock() - #define CO_UNLOCK_EMCY() cyg_scheduler_unlock() - - #define CO_LOCK_OD() cyg_scheduler_lock() - #define CO_UNLOCK_OD() cyg_scheduler_unlock() - - - -/* Data types */ - typedef unsigned char bool_t; - typedef cyg_uint8 uint8_t; - typedef cyg_uint16 uint16_t; - typedef cyg_uint32 uint32_t; - typedef cyg_uint64 uint64_t; - typedef cyg_int8 int8_t; - typedef cyg_int16 int16_t; - typedef cyg_int32 int32_t; - typedef cyg_int64 int64_t; - typedef float float32_t; - typedef long double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. */ -typedef struct{ - uint32_t ID; - uint8_t DLC; /* Length of CAN message */ - uint8_t RTR; - uint8_t data[8]; /* 8 data bytes */ -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint16_t ident; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object. */ -typedef struct{ - uint16_t ID; - uint8_t DLC; - uint8_t RTR; - uint8_t data[8]; - volatile uint8_t bufferFull; - volatile uint8_t syncFlag; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - volatile bool_t CANnormal; - volatile uint8_t *curentSyncTimeIsInsideWindow; - volatile uint8_t useCANrxFilters; - volatile uint8_t bufferInhibitFlag; - volatile uint8_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; - void *driverPrivate; - uint16_t rxBufferIndexArray[0x800]; ///< Array of pointers to rx buffers - cyg_io_handle_t ioHandle; -}CO_CANmodule_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. */ -int16_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); - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -int16_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - uint8_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint8_t rtr, - uint8_t noOfBytes, - uint8_t syncFlag); - - -/* Send CAN message. */ -int16_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -#ifdef __cplusplus -} //extern "C" -#endif -#endif diff --git a/stack/eCos/Makefile b/stack/eCos/Makefile deleted file mode 100644 index 5736b7f5..00000000 --- a/stack/eCos/Makefile +++ /dev/null @@ -1,87 +0,0 @@ -# Mostly written by Jonathan Larmour, Red Hat, Inc. -# Reference to ecos.mak added by John Dallaway, eCosCentric Limited, 2003-01-20 -# This file is in the public domain and may be used for any purpose - -# Usage: make INSTALL_DIR=/path/to/ecos/install - -#INSTALL_DIR=$$(INSTALL_DIR) # override on make command line -#INSTALL_DIR=/tmp/lpc-e2294_default_CAN_04_debug_install -#INSTALL_DIR=/tmp/lpc-e2294_ustl_CAN_04_debug_install -INSTALL_DIR=/tmp/lpc-l2294_ustl_CAN_02_debug_install - -# path to CANopen node source code -CANOPENNODE_SRC = /cygdrive/c/CodingXP/CANopenNode_SVN/CANopen_stack - - -# Include directories -INCLUDE_DIRS = $(CANOPENNODE_SRC) \ - -I"src" - -# source files -SOURCES = $(CANOPENNODE_SRC)/CANopen.c \ - $(CANOPENNODE_SRC)/CO_Emergency.c \ - $(CANOPENNODE_SRC)/CO_HBconsumer.c \ - $(CANOPENNODE_SRC)/CO_NMT_Heartbeat.c \ - $(CANOPENNODE_SRC)/CO_PDO.c \ - $(CANOPENNODE_SRC)/CO_SDO.c \ - $(CANOPENNODE_SRC)/CO_SDOmaster.c \ - $(CANOPENNODE_SRC)/CO_SYNC.c \ - $(CANOPENNODE_SRC)/crc16-ccitt.c \ - src/application.cpp \ - src/CO_driver_eCos.c \ - src/main.c \ - src/CO_OD.c \ - src/CO_PollingTimer.c \ - src/CO_Flash.c \ - src/ecos_helper.c - - -OBJSC=${SOURCES:%.c=%.o} -OBJS=${OBJSC:%.cpp=%.o} - -include $(INSTALL_DIR)/include/pkgconf/ecos.mak - -XCC = $(ECOS_COMMAND_PREFIX)gcc -OBJCOPY = $(ECOS_COMMAND_PREFIX)objcopy -XCXX = $(XCC) -XLD = $(XCC) - -CFLAGS = -I$(INSTALL_DIR)/include -I$(INCLUDE_DIRS) -CXXFLAGS = $(CFLAGS) -LDFLAGS = -nostartfiles -L$(INSTALL_DIR)/lib -Ttarget.ld - -# RULES - -.PHONY: all clean - -all: ecos_canopennode ecos_canopennode.bin - -clean: - -rm -f src/*.o - -rm -f $(CANOPENNODE_SRC)/*.o - -%.o: %.c - $(XCC) -c -o $*.o $(CFLAGS) $(ECOS_GLOBAL_CFLAGS) $< - -%.o: %.cxx - $(XCXX) -c -o $*.o $(CFLAGS) $(ECOS_GLOBAL_CFLAGS) $< - -%.o: %.cpp - $(XCXX) -c -o $*.o $(CXXFLAGS) $(ECOS_GLOBAL_CFLAGS) $< - -%.o: %.C - $(XCXX) -c -o $*.o $(CXXFLAGS) $(ECOS_GLOBAL_CFLAGS) $< - -%.o: %.cc - $(XCXX) -c -o $*.o $(CXXFLAGS) $(ECOS_GLOBAL_CFLAGS) $< - - -ecos_canopennode: $(OBJS) - $(XLD) $(LDFLAGS) $(ECOS_GLOBAL_LDFLAGS) $(OBJS) -o $@ - - -ecos_canopennode.bin : ecos_canopennode - $(OBJCOPY) --strip-debug $< $(@:.bin=.img) - $(OBJCOPY) -O srec $< $(@:.bin=.srec) - $(OBJCOPY) -O binary $< $@ - diff --git a/stack/eCos/application.cpp b/stack/eCos/application.cpp deleted file mode 100644 index e4b8c4f4..00000000 --- a/stack/eCos/application.cpp +++ /dev/null @@ -1,69 +0,0 @@ -//=========================================================================== -// INCLUDES -//=========================================================================== -#include "CANopen.h" -#include - - -//=========================================================================== -extern "C" void programStart(void) -{ - diag_printf("programStart\n"); -} - - -//=========================================================================== -extern "C" void communicationReset(void) -{ - diag_printf("communicationReset\n"); -} - - -//=========================================================================== -extern "C" void programEnd(void) -{ - diag_printf("programEnd\n"); -} - - -//=========================================================================== -extern "C" void programAsync(uint16_t timer1msDiff) -{ - static uint32_t MsCount = 0; - static uint8_t SecCount = 0; - static uint8_t Output0 = OD_writeOutput8Bit[0]; - - MsCount += timer1msDiff; - OD_readInput8Bit[1] = MsCount; - if (MsCount >= 1000) - { - diag_printf("programAsync\n"); - MsCount -= 1000; - SecCount++; - } - - OD_readInput8Bit[0] = SecCount; - if (Output0 != OD_writeOutput8Bit[0]) - { - Output0 = OD_writeOutput8Bit[0]; - diag_printf("Output0 changed: %x\n", Output0); - } -} - - -//=========================================================================== -extern "C" void program1ms(void) -{ - static uint32_t MsCount = 0; - MsCount ++; - if (MsCount >= 1000) - { - diag_printf("program1ms\n"); - MsCount -= 1000; - } -} - - -//--------------------------------------------------------------------------- -// EOF application.cpp - diff --git a/stack/eCos/ecos_helper.cpp b/stack/eCos/ecos_helper.cpp deleted file mode 100644 index 5d5893ee..00000000 --- a/stack/eCos/ecos_helper.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//============================================================================ -/// \file ecos_helper.cpp -/// \author Uwe Kindler -/// \date 05.09.2013 -/// \brief Implementation of ecos_helper -//============================================================================ - -//============================================================================ -// INCLUDES -//============================================================================ -#include - - -//============================================================================ -extern "C" cyg_tick_count convertMsToTicks(cyg_tick_count Milliseconds) -{ - static struct Cyg_Clock::converter ms_converter; - static volatile cyg_atomic conv_init = 0; - if (!conv_init) - { - struct Cyg_Clock::converter temp_ms_converter; - Cyg_Clock::real_time_clock->get_other_to_clock_converter( - 1000000, &temp_ms_converter); - Cyg_Scheduler::lock(); - ms_converter = temp_ms_converter; - conv_init = 1; - Cyg_Scheduler::unlock(); - } - - return Cyg_Clock::convert(Milliseconds, &ms_converter); -} - - -//============================================================================ -extern "C" cyg_tick_count convertTicksToMs(cyg_tick_count ClockTicks) -{ - static struct Cyg_Clock::converter ms_converter; - static volatile cyg_atomic conv_init = 0; - if (!conv_init) - { - struct Cyg_Clock::converter temp_ms_converter; - Cyg_Clock::real_time_clock->get_clock_to_other_converter( - 1000000, &temp_ms_converter); - Cyg_Scheduler::lock(); - ms_converter = temp_ms_converter; - conv_init = 1; - Cyg_Scheduler::unlock(); - } - - return Cyg_Clock::convert(ClockTicks, &ms_converter); -} - - - -//--------------------------------------------------------------------------- -// EOF ecos_helper.cpp diff --git a/stack/eCos/ecos_helper.h b/stack/eCos/ecos_helper.h deleted file mode 100644 index 5369c687..00000000 --- a/stack/eCos/ecos_helper.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ecos_helperH -#define ecos_helperH -//============================================================================ -/// \file ecos_helper.h -/// \author Uwe Kindler -/// \date 05.09.2013 -/// \brief Declaration of ecos_helper -//============================================================================ - -//============================================================================ -// INCLUDES -//============================================================================ -#include -#include - - -/** - * Converts milliseconds to eCos clock ticks - */ -cyg_tick_count convertMsToTicks(cyg_tick_count Milliseconds); - -/** - * Converts eCos clock ticks to milliseconds - */ -cyg_tick_count convertTicksToMs(cyg_tick_count ClockTicks); - - -//--------------------------------------------------------------------------- -#endif // ecos_helperH diff --git a/stack/eCos/main.c b/stack/eCos/main.c deleted file mode 100644 index ec3fe48f..00000000 --- a/stack/eCos/main.c +++ /dev/null @@ -1,109 +0,0 @@ -//============================================================================ -// Name : CANopenNodeEcos.cpp -// Author : Uwe Kindler -// Version : -// Copyright : Your copyright notice -// Description : Hello World in C, Ansi-style -//============================================================================ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include // kernel API -#include -#include - -#include "CANopen.h" -#include "application.h" -#include "CO_PollingTimer.h" -#include "CO_Flash.h" - - -//============================================================================ -// Global variables and objects -//============================================================================ -static cyg_uint64 CANopenPollingTimer = 1; -extern struct sCO_OD_ROM CO_OD_ROM; -static uint8_t reset = CO_RESET_NOT; -extern void CO_eCos_errorReport(CO_EM_t *em, const uint8_t errorBit, - const uint16_t errorCode, const uint32_t infoCode); - - -//=========================================================================== -// CANopen stack main entry point -//=========================================================================== -void CO_main(void) -{ - CO_FlashInit(); - while (1) - { - reset = CO_RESET_NOT; - // Application interface - programStart(); - - // increase variable each startup. Variable is stored in EEPROM. - OD_powerOnCounter++; - while (reset < CO_RESET_APP) - { - // CANopen communication reset - initialize CANopen objects - int16_t err; - cyg_uint64 timer1msPrevious = CO_TmrGetMilliSec(); - - // initialize CANopen - err = CO_init(); - if(err) - { - CO_eCos_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, - CO_EMC_SOFTWARE_INTERNAL, err); - while(1); - } - // register object dictionary functions to support store and restore - // of parameters via objects 0x1010 and 0x1011 - CO_FlashRegisterODFunctions(CO); - - // initialize variables - reset = CO_RESET_NOT; - - // Application interface - communicationReset(); - - // start CAN and enable interrupts - CO_CANsetNormalMode(ADDR_CAN1); - - while (CO_RESET_NOT == reset) - { - //diag_print_reg("CAN GSR", CAN_CTRL_1_REG_BASE + CANREG_GSR); - // loop for normal program execution - cyg_uint64 timer1ms = CO_TmrGetMilliSec(); - uint16_t timer1msDiff = timer1ms - timer1msPrevious; - timer1msPrevious = timer1ms; - - // Application interface - programAsync(timer1msDiff); - - // CANopen process - reset = CO_process(CO, timer1msDiff); - if (CO_TmrIsExpired(CANopenPollingTimer)) - { - CANopenPollingTimer = CO_TmrStartFrom(CANopenPollingTimer, 1); - CO_process_RPDO(CO); - program1ms(); - CO_process_TPDO(CO); - } - } - } - } -} - - -//=========================================================================== -// Application main entry point -//=========================================================================== -int main( int argc, char *argv[]) -{ - CO_main();// this function will never return - return 0; -} - -//--------------------------------------------------------------------------- diff --git a/stack/eCos/readme b/stack/eCos/readme deleted file mode 100644 index dd874868..00000000 --- a/stack/eCos/readme +++ /dev/null @@ -1,12 +0,0 @@ -CANopenNode driver for eCos CAN framework. The driver supports any hardware that is supported by the eCos CAN framework. -See http://ecos.sourceware.org/ - -The driver was developed and tested with the Olimex LCP-E2294-1MB board: -https://www.olimex.com/Products/ARM/NXP/LPC-E2294-1MB/ - -and with the Olimex LPC-L2294-1MB board: -https://www.olimex.com/Products/ARM/NXP/LPC-L2294-1MB/ - -The driver also utilizes the eCos generic flash support to implement parameter storage and default parameter restore functionality via objects 0x1010 and 0x1011. - -Contributed by Uwe Kindler: http://sourceforge.net/p/canopennode/discussion/387151/thread/7603e3b5/ diff --git a/stack/socketCAN/CO_Linux_tasks.c b/stack/socketCAN/CO_Linux_tasks.c deleted file mode 100644 index 33b560c0..00000000 --- a/stack/socketCAN/CO_Linux_tasks.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Helper functions for implementing CANopen tasks in Linux using epoll. - * - * @file Linux_tasks.c - * @author Janez Paternoster - * @copyright 2015 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "CANopen.h" -#include -#include -#include -#include - - -#define NSEC_PER_SEC (1000000000) /* The number of nanoseconds per second. */ -#define NSEC_PER_MSEC (1000000) /* The number of nanoseconds per millisecond. */ - - -/* External helper function ***************************************************/ -void CO_errExit(char* msg); -void CO_error(const uint32_t info); - - -/* Mainline task (taskMain) ***************************************************/ -static struct { - int fdTmr; /* file descriptor for taskTmr */ - int fdPipe[2]; /* file descriptors for pipe [0]=read, [1]=write */ - struct itimerspec tmrSpec; - uint16_t tmr1msPrev; - uint16_t *maxTime; -} taskMain; - - -void taskMain_init(int fdEpoll, uint16_t *maxTime) { - struct epoll_event ev; - int flags; - - /* Prepare pipe for triggering events. For example, if new SDO request - * arrives from CAN network, CANrx callback writes a byte into the pipe. - * This immediately triggers (via epoll) processing of SDO server, which - * generates response. Read and write ends of pipe are nonblocking. - * (See 'self pipe trick'.) */ - if(pipe(taskMain.fdPipe) == -1) - CO_errExit("taskMain_init - pipe failed"); - - flags = fcntl(taskMain.fdPipe[0], F_GETFL); - if(flags == -1) - CO_errExit("taskMain_init - fcntl-F_GETFL[0] failed"); - flags |= O_NONBLOCK; - if(fcntl(taskMain.fdPipe[0], F_SETFL, flags) == -1) - CO_errExit("taskMain_init - fcntl-F_SETFL[0] failed"); - - flags = fcntl(taskMain.fdPipe[1], F_GETFL); - if(flags == -1) - CO_errExit("taskMain_init - fcntl-F_GETFL[1] failed"); - flags |= O_NONBLOCK; - if(fcntl(taskMain.fdPipe[1], F_SETFL, flags) == -1) - CO_errExit("taskMain_init - fcntl-F_SETFL[1] failed"); - - /* get file descriptor for timer */ - taskMain.fdTmr = timerfd_create(CLOCK_MONOTONIC, 0); - if(taskMain.fdTmr == -1) - CO_errExit("taskMain_init - timerfd_create failed"); - - /* add events for epoll */ - ev.events = EPOLLIN; - ev.data.fd = taskMain.fdPipe[0]; - if(epoll_ctl(fdEpoll, EPOLL_CTL_ADD, taskMain.fdPipe[0], &ev) == -1) - CO_errExit("taskMain_init - epoll_ctl CANrx failed"); - - ev.events = EPOLLIN; - ev.data.fd = taskMain.fdTmr; - if(epoll_ctl(fdEpoll, EPOLL_CTL_ADD, taskMain.fdTmr, &ev) == -1) - CO_errExit("taskMain_init - epoll_ctl taskTmr failed"); - - /* Prepare timer, use no interval, delay time will be set each cycle. */ - taskMain.tmrSpec.it_interval.tv_sec = 0; - taskMain.tmrSpec.it_interval.tv_nsec = 0; - - taskMain.tmrSpec.it_value.tv_sec = 0; - taskMain.tmrSpec.it_value.tv_nsec = 1; - - if(timerfd_settime(taskMain.fdTmr, 0, &taskMain.tmrSpec, NULL) != 0) - CO_errExit("taskMain_init - timerfd_settime failed"); - - taskMain.tmr1msPrev = 0; - taskMain.maxTime = maxTime; -} - - -void taskMain_close(void) { - close(taskMain.fdPipe[0]); - close(taskMain.fdPipe[1]); - close(taskMain.fdTmr); -} - - -bool_t taskMain_process(int fd, CO_NMT_reset_cmd_t *reset, uint16_t timer1ms) { - bool_t wasProcessed = true; - - /* Signal from pipe, consume all bytes. */ - if(fd == taskMain.fdPipe[0]) { - for(;;) { - char ch; - if(read(taskMain.fdPipe[0], &ch, 1) == -1) { - if (errno == EAGAIN) - break; /* No more bytes. */ - else - CO_error(0x21100000L + errno); - } - } - } - - /* Timer expired. */ - else if(fd == taskMain.fdTmr) { - uint64_t tmrExp; - if(read(taskMain.fdTmr, &tmrExp, sizeof(tmrExp)) != sizeof(uint64_t)) - CO_error(0x21200000L + errno); - } - else { - wasProcessed = false; - } - - /* Process mainline. */ - if(wasProcessed) { - uint16_t timer1msDiff; - uint16_t timerNext = 50; - - /* Calculate time difference */ - timer1msDiff = timer1ms - taskMain.tmr1msPrev; - taskMain.tmr1msPrev = timer1ms; - - /* Calculate maximum interval in milliseconds (informative) */ - if(taskMain.maxTime != NULL) { - if(timer1msDiff > *taskMain.maxTime) { - *taskMain.maxTime = timer1msDiff; - } - } - - - /* CANopen process */ - *reset = CO_process(CO, timer1msDiff, &timerNext); - - - /* Set delay for next sleep. */ - taskMain.tmrSpec.it_value.tv_nsec = (long)(++timerNext) * NSEC_PER_MSEC; - if(timerfd_settime(taskMain.fdTmr, 0, &taskMain.tmrSpec, NULL) == -1) - CO_error(0x21500000L + errno); - - } - - return wasProcessed; -} - - -void taskMain_cbSignal(void) { - if(write(taskMain.fdPipe[1], "x", 1) == -1) - CO_error(0x23100000L + errno); -} - - -/* Realtime task (taskRT) *****************************************************/ -static struct { - int fdRx0; /* file descriptor for CANrx */ - int fdTmr; /* file descriptor for taskTmr */ - struct itimerspec tmrSpec; - struct timespec *tmrVal; - long intervalns; - long intervalus; - uint16_t *maxTime; -} taskRT; - - -void CANrx_taskTmr_init(int fdEpoll, long intervalns, uint16_t *maxTime) { - struct epoll_event ev; - - /* get file descriptors */ - taskRT.fdRx0 = CO->CANmodule[0]->fd; - - taskRT.fdTmr = timerfd_create(CLOCK_MONOTONIC, 0); - if(taskRT.fdTmr == -1) - CO_errExit("CANrx_taskTmr_init - timerfd_create failed"); - - /* add events for epoll */ - ev.events = EPOLLIN; - ev.data.fd = taskRT.fdRx0; - if(epoll_ctl(fdEpoll, EPOLL_CTL_ADD, taskRT.fdRx0, &ev) == -1) - CO_errExit("CANrx_taskTmr_init - epoll_ctl CANrx failed"); - - ev.events = EPOLLIN; - ev.data.fd = taskRT.fdTmr; - if(epoll_ctl(fdEpoll, EPOLL_CTL_ADD, taskRT.fdTmr, &ev) == -1) - CO_errExit("CANrx_taskTmr_init - epoll_ctl taskTmr failed"); - - /* Prepare timer (one shot, each time calculate new expiration time) It is - * necessary not to use taskRT.tmrSpec.it_interval, because it is sliding. */ - taskRT.tmrSpec.it_interval.tv_sec = 0; - taskRT.tmrSpec.it_interval.tv_nsec = 0; - - taskRT.tmrVal = &taskRT.tmrSpec.it_value; - if(clock_gettime(CLOCK_MONOTONIC, taskRT.tmrVal) != 0) - CO_errExit("CANrx_taskTmr_init - clock_gettime failed"); - - if(timerfd_settime(taskRT.fdTmr, TFD_TIMER_ABSTIME, &taskRT.tmrSpec, NULL) != 0) - CO_errExit("CANrx_taskTmr_init - timerfd_settime failed"); - - taskRT.intervalns = intervalns; - taskRT.intervalus = intervalns / 1000; - taskRT.maxTime = maxTime; -} - - -void CANrx_taskTmr_close(void) { - close(taskRT.fdTmr); -} - - -bool_t CANrx_taskTmr_process(int fd) { - bool_t wasProcessed = true; - - /* Get received CAN message. */ - if(fd == taskRT.fdRx0) { - CO_CANrxWait(CO->CANmodule[0]); - } - - /* Execute taskTmr */ - else if(fd == taskRT.fdTmr) { - uint64_t tmrExp; - - /* Wait for timer to expire */ - if(read(taskRT.fdTmr, &tmrExp, sizeof(tmrExp)) != sizeof(uint64_t)) - CO_error(0x22100000L + errno); - - /* Calculate maximum interval in microseconds (informative) */ - if(taskRT.maxTime != NULL) { - struct timespec tmrMeasure; - if(clock_gettime(CLOCK_MONOTONIC, &tmrMeasure) == -1) - CO_error(0x22200000L + errno); - if(tmrMeasure.tv_sec == taskRT.tmrVal->tv_sec) { - long dt = tmrMeasure.tv_nsec - taskRT.tmrVal->tv_nsec; - dt /= 1000; - dt += taskRT.intervalus; - if(dt > 0xFFFF) { - *taskRT.maxTime = 0xFFFF; - }else if(dt > *taskRT.maxTime) { - *taskRT.maxTime = (uint16_t) dt; - } - } - } - - /* Calculate next shot for the timer */ - taskRT.tmrVal->tv_nsec += taskRT.intervalns; - if(taskRT.tmrVal->tv_nsec >= NSEC_PER_SEC) { - taskRT.tmrVal->tv_nsec -= NSEC_PER_SEC; - taskRT.tmrVal->tv_sec++; - } - if(timerfd_settime(taskRT.fdTmr, TFD_TIMER_ABSTIME, &taskRT.tmrSpec, NULL) == -1) - CO_error(0x22300000L + errno); - - - /* Lock PDOs and OD */ - CO_LOCK_OD(); - - if(CO->CANmodule[0]->CANnormal) { - bool_t syncWas; - - /* Process Sync */ - syncWas = CO_process_SYNC(CO, taskRT.intervalus); - - /* Read inputs */ - CO_process_RPDO(CO, syncWas); - - /* Further I/O or nonblocking application code may go here. */ - - /* Write outputs */ - CO_process_TPDO(CO, syncWas, taskRT.intervalus); - } - - /* Unlock */ - CO_UNLOCK_OD(); - } - - else { - wasProcessed = false; - } - - return wasProcessed; -} diff --git a/stack/socketCAN/CO_Linux_tasks.h b/stack/socketCAN/CO_Linux_tasks.h deleted file mode 100644 index fdf9fb82..00000000 --- a/stack/socketCAN/CO_Linux_tasks.h +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Helper functions for implementing CANopen tasks in Linux using epoll. - * - * @file Linux_tasks.h - * @author Janez Paternoster - * @copyright 2015 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_LINUX_TASKS_H -#define CO_LINUX_TASKS_H - - -/** - * Initialize mainline task. - * - * taskMain is non-realtime task for CANopenNode processing. It is nonblocking - * and is executing cyclically in 50 ms intervals or less if necessary. - * It uses Linux epoll, timerfd for interval and pipe for task triggering. - * This task processes CO_process() function from CANopen.c file. - * - * @param fdEpoll File descriptor for Linux epoll API. - * @param maxTime Pointer to variable, where longest interval will be written - * [in milliseconds]. If NULL, calculations won't be made. - */ -void taskMain_init(int fdEpoll, uint16_t *maxTime); - -/** - * Cleanup mainline task. - */ -void taskMain_close(void); - -/** - * Process mainline task. - * - * Function must be called after epoll. - * - * @param fd Available file descriptor from epoll(). - * @param reset return value from CO_process() function. - * @param timer1ms variable, which must increment each millisecond. - * - * @return True, if fd was matched. - */ -bool_t taskMain_process(int fd, CO_NMT_reset_cmd_t *reset, uint16_t timer1ms); - -/** - * Signal function, which triggers mainline task. - * - * It is used from some CANopenNode objects as callback. - */ -void taskMain_cbSignal(void); - - -/** - * Initialize realtime task. - * - * CANrx_taskTmr is realtime task for CANopenNode processing. It is nonblocking - * and is executing on CAN message receive or periodically in 1ms (or something) - * intervals. Inside interval is processed CANopen SYNC message, RPDOs(inputs) - * and TPDOs(outputs). Between inputs and outputs can also be executed some - * realtime application code. - * CANrx_taskTmr uses Linux epoll, CAN socket form CO_driver.c and timerfd for - * interval. - * - * - * @param fdEpoll File descriptor for Linux epoll API. - * @param intervalns Interval of periodic timer in nanoseconds. - * @param maxTime Pointer to variable, where longest interval will be written - * [in milliseconds]. If NULL, calculations won't be made. - */ -void CANrx_taskTmr_init(int fdEpoll, long intervalns, uint16_t *maxTime); - -/** - * Cleanup realtime task. - */ -void CANrx_taskTmr_close(void); - -/** - * Process realtime task. - * - * Function must be called after epoll. - * - * @param fd Available file descriptor from epoll(). - * - * @return True, if fd was matched. - */ -bool_t CANrx_taskTmr_process(int fd); - -/** - * Disable CAN receive thread temporary. - * - * Function is called at SYNC message on CAN bus. - * It disables CAN receive thread until RPDOs are processed. - */ -void CANrx_lockCbSync(bool_t syncReceived); - -#endif diff --git a/stack/socketCAN/CO_driver.c b/stack/socketCAN/CO_driver.c deleted file mode 100644 index 60c861f1..00000000 --- a/stack/socketCAN/CO_driver.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * CAN module object for Linux SocketCAN. - * - * @file CO_driver.c - * @author Janez Paternoster - * @copyright 2015 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "CO_driver.h" -#include "CO_Emergency.h" -#include /* for memcpy */ -#include /* for malloc, free */ -#include -#include - - -/******************************************************************************/ -#ifndef CO_SINGLE_THREAD - pthread_mutex_t CO_EMCY_mtx = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_t CO_OD_mtx = PTHREAD_MUTEX_INITIALIZER; -#endif - - -/** Set socketCAN filters *****************************************************/ -static CO_ReturnError_t setFilters(CO_CANmodule_t *CANmodule){ - CO_ReturnError_t ret = CO_ERROR_NO; - - if(CANmodule->useCANrxFilters){ - int nFiltersIn, nFiltersOut; - struct can_filter *filtersOut; - - nFiltersIn = CANmodule->rxSize; - nFiltersOut = 0; - filtersOut = (struct can_filter *) calloc(nFiltersIn, sizeof(struct can_filter)); - - if(filtersOut == NULL){ - ret = CO_ERROR_OUT_OF_MEMORY; - }else{ - int i; - int idZeroCnt = 0; - - /* Copy filterIn to filtersOut. Accept only first filter with - * can_id=0, omit others. */ - for(i=0; ifilter[i]; - if(fin->can_id == 0){ - idZeroCnt++; - } - if(fin->can_id != 0 || idZeroCnt == 1){ - struct can_filter *fout; - - fout = &filtersOut[nFiltersOut++]; - fout->can_id = fin->can_id; - fout->can_mask = fin->can_mask; - } - } - - if(setsockopt(CANmodule->fd, SOL_CAN_RAW, CAN_RAW_FILTER, - filtersOut, sizeof(struct can_filter) * nFiltersOut) != 0) - { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - free(filtersOut); - } - }else{ - /* Use one socketCAN filter, match any CAN address, including extended and rtr. */ - CANmodule->filter[0].can_id = 0; - CANmodule->filter[0].can_mask = 0; - if(setsockopt(CANmodule->fd, SOL_CAN_RAW, CAN_RAW_FILTER, - &CANmodule->filter[0], sizeof(struct can_filter)) != 0) - { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - } - - return ret; -} - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANdriverState){ -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ - /* set CAN filters */ - if(CANmodule == NULL || setFilters(CANmodule) != CO_ERROR_NO){ - CO_errExit("CO_CANsetNormalMode failed"); - } - CANmodule->CANnormal = true; -} - - -/******************************************************************************/ -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) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - uint16_t i; - - /* verify arguments */ - if(CANmodule==NULL || CANdriverState==NULL || rxArray==NULL || txArray==NULL){ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - if(ret == CO_ERROR_NO){ - CANmodule->CANdriverState = CANdriverState; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = true; - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->error = 0; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - CANmodule->em = NULL; - -#ifdef CO_LOG_CAN_MESSAGES - CANmodule->useCANrxFilters = false; -#endif - - for(i=0U; iwasConfigured == 0){ - struct sockaddr_can sockAddr; - - CANmodule->wasConfigured = 1; - - /* Create and bind socket */ - CANmodule->fd = socket(AF_CAN, SOCK_RAW, CAN_RAW); - if(CANmodule->fd < 0){ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - }else{ - const int * const ifindex_ptr = CANdriverState; - sockAddr.can_family = AF_CAN; - sockAddr.can_ifindex = *ifindex_ptr; - if(bind(CANmodule->fd, (struct sockaddr*)&sockAddr, sizeof(sockAddr)) != 0){ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - } - - /* allocate memory for filter array */ - if(ret == CO_ERROR_NO){ - CANmodule->filter = (struct can_filter *) calloc(rxSize, sizeof(struct can_filter)); - if(CANmodule->filter == NULL){ - ret = CO_ERROR_OUT_OF_MEMORY; - } - } - } - - /* Additional check. */ - if(ret == CO_ERROR_NO && CANmodule->filter == NULL){ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure CAN module hardware filters */ - if(ret == CO_ERROR_NO && CANmodule->useCANrxFilters){ - /* Match filter, standard 11 bit CAN address only, no rtr */ - for(i=0U; ifilter[i].can_id = 0; - CANmodule->filter[i].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG; - } - } - - /* close CAN module filters for now. */ - if(ret == CO_ERROR_NO){ - setsockopt(CANmodule->fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); - } - - return ret; -} - - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){ - close(CANmodule->fd); - free(CANmodule->filter); - CANmodule->filter = NULL; -} - - -/******************************************************************************/ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){ - return (uint16_t) rxMsg->ident; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && - (CANmodule->filter!=NULL) && (index < CANmodule->rxSize)){ - /* buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - - /* Configure object variables */ - buffer->object = object; - buffer->pFunct = pFunct; - - /* Configure CAN identifier and CAN mask, bit aligned with CAN module. */ - buffer->ident = ident & CAN_SFF_MASK; - if(rtr){ - buffer->ident |= CAN_RTR_FLAG; - } - buffer->mask = (mask & CAN_SFF_MASK) | CAN_EFF_FLAG | CAN_RTR_FLAG; - - /* Set CAN hardware module filter and mask. */ - if(CANmodule->useCANrxFilters){ - CANmodule->filter[index].can_id = buffer->ident; - CANmodule->filter[index].can_mask = buffer->mask; - if(CANmodule->CANnormal){ - ret = setFilters(CANmodule); - } - } - } - else{ - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - - /* CAN identifier, bit aligned with CAN module registers */ - buffer->ident = ident & CAN_SFF_MASK; - if(rtr){ - buffer->ident |= CAN_RTR_FLAG; - } - - buffer->DLC = noOfBytes; - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } - - return buffer; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ - CO_ReturnError_t err = CO_ERROR_NO; - ssize_t n; - size_t count = sizeof(struct can_frame); - - n = write(CANmodule->fd, buffer, count); -#ifdef CO_LOG_CAN_MESSAGES - void CO_logMessage(const CanMsg *msg); - CO_logMessage((const CanMsg*) buffer); -#endif - - if(n != count){ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, n); - err = CO_ERROR_TX_OVERFLOW; - } - - return err; -} - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ - /* Messages can not be cleared, because they are allready in kernel */ -} - - -/******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ -#if 0 - unsigned rxErrors, txErrors; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - uint32_t err; - - canGetErrorCounters(CANmodule->CANdriverState, &rxErrors, &txErrors); - if(txErrors > 0xFFFF) txErrors = 0xFFFF; - if(rxErrors > 0xFF) rxErrors = 0xFF; - - err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | CANmodule->error; - - if(CANmodule->errOld != err){ - CANmodule->errOld = err; - - if(txErrors >= 256U){ /* bus off */ - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); - } - else{ /* not bus off */ - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - - if((rxErrors >= 96U) || (txErrors >= 96U)){ /* bus warning */ - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); - } - - if(rxErrors >= 128U){ /* RX bus passive */ - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err); - } - - if(txErrors >= 128U){ /* TX bus passive */ - if(!CANmodule->firstCANtxMessage){ - CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - } - else{ - bool_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE); - if(isError){ - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - - if((rxErrors < 96U) && (txErrors < 96U)){ /* no error */ - bool_t isError = CO_isError(em, CO_EM_CAN_BUS_WARNING); - if(isError){ - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - } - - if(CANmodule->error & 0x02){ /* CAN RX bus overflow */ - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); - } - } -#endif -} - - -/******************************************************************************/ -void CO_CANrxWait(CO_CANmodule_t *CANmodule){ - struct can_frame msg; - int n, size; - - if(CANmodule == NULL){ - errno = EFAULT; - CO_errExit("CO_CANreceive - CANmodule not configured."); - } - - /* Read socket and pre-process message */ - size = sizeof(struct can_frame); - n = read(CANmodule->fd, &msg, size); - - if(CANmodule->CANnormal){ - if(n != size){ - /* This happens only once after error occurred (network down or something). */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_COMMUNICATION, n); - } - else{ - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint32_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer; /* receive message buffer from CO_CANmodule_t object. */ - int i; - bool_t msgMatched = false; - - rcvMsg = (CO_CANrxMsg_t *) &msg; - rcvMsgIdent = rcvMsg->ident; - - /* Search rxArray form CANmodule for the matching CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for(i = CANmodule->rxSize; i > 0U; i--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ - msgMatched = true; - break; - } - buffer++; - } - - /* Call specific function, which will process the message */ - if(msgMatched && (buffer->pFunct != NULL)){ - buffer->pFunct(buffer->object, rcvMsg); - } - -#ifdef CO_LOG_CAN_MESSAGES - void CO_logMessage(const CanMsg *msg); - CO_logMessage((CanMsg*)&rcvMsg); -#endif - } - } -} diff --git a/stack/socketCAN/CO_driver.h b/stack/socketCAN/CO_driver.h deleted file mode 100644 index f6b6fe30..00000000 --- a/stack/socketCAN/CO_driver.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * CAN module object for Linux SocketCAN. - * - * @file CO_driver.h - * @author Janez Paternoster - * @copyright 2015 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_DRIVER_H -#define CO_DRIVER_H - - -/* For documentation see file drvTemplate/CO_driver.h */ - - -#include /* for 'NULL' */ -#include /* for 'int8_t' to 'uint64_t' */ -#include /* for 'true', 'false' */ -#include -#include - -#ifndef CO_SINGLE_THREAD -#include -#endif - -#include -#include -#include - - -/* general configuration */ -// #define CO_LOG_CAN_MESSAGES /* Call external function for each received or transmitted CAN message. */ - #define CO_SDO_BUFFER_SIZE 889 /* Override default SDO buffer size. */ - - -/* Critical sections */ -#ifdef CO_SINGLE_THREAD - #define CO_LOCK_CAN_SEND() - #define CO_UNLOCK_CAN_SEND() - - #define CO_LOCK_EMCY() - #define CO_UNLOCK_EMCY() - - #define CO_LOCK_OD() - #define CO_UNLOCK_OD() - - #define CANrxMemoryBarrier() -#else - #define CO_LOCK_CAN_SEND() /* not needed */ - #define CO_UNLOCK_CAN_SEND() - - extern pthread_mutex_t CO_EMCY_mtx; - #define CO_LOCK_EMCY() {if(pthread_mutex_lock(&CO_EMCY_mtx) != 0) CO_errExit("Mutex lock CO_EMCY_mtx failed");} - #define CO_UNLOCK_EMCY() {if(pthread_mutex_unlock(&CO_EMCY_mtx) != 0) CO_errExit("Mutex unlock CO_EMCY_mtx failed");} - - extern pthread_mutex_t CO_OD_mtx; - #define CO_LOCK_OD() {if(pthread_mutex_lock(&CO_OD_mtx) != 0) CO_errExit("Mutex lock CO_OD_mtx failed");} - #define CO_UNLOCK_OD() {if(pthread_mutex_unlock(&CO_OD_mtx) != 0) CO_errExit("Mutex unlock CO_OD_mtx failed");} - - #define CANrxMemoryBarrier() {__sync_synchronize();} -#endif - -/* Syncronisation functions */ -#define IS_CANrxNew(rxNew) ((uintptr_t)rxNew) -#define SET_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)1L;} -#define CLEAR_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)0L;} - - -/* Data types */ - /* int8_t to uint64_t are defined in stdint.h */ - typedef _Bool bool_t; - typedef float float32_t; - typedef double float64_t; - typedef char char_t; - typedef unsigned char oChar_t; - typedef unsigned char domain_t; - - -/* Return values */ -typedef enum{ - CO_ERROR_NO = 0, - CO_ERROR_ILLEGAL_ARGUMENT = -1, - CO_ERROR_OUT_OF_MEMORY = -2, - CO_ERROR_TIMEOUT = -3, - CO_ERROR_ILLEGAL_BAUDRATE = -4, - CO_ERROR_RX_OVERFLOW = -5, - CO_ERROR_RX_PDO_OVERFLOW = -6, - CO_ERROR_RX_MSG_LENGTH = -7, - CO_ERROR_RX_PDO_LENGTH = -8, - CO_ERROR_TX_OVERFLOW = -9, - CO_ERROR_TX_PDO_WINDOW = -10, - CO_ERROR_TX_UNCONFIGURED = -11, - CO_ERROR_PARAMETERS = -12, - CO_ERROR_DATA_CORRUPT = -13, - CO_ERROR_CRC = -14 -}CO_ReturnError_t; - - -/* CAN receive message structure as aligned in CAN module. */ -typedef struct{ - uint32_t ident; - uint8_t DLC; - uint8_t data[8] __attribute__((aligned(8))); -}CO_CANrxMsg_t; - - -/* Received message object */ -typedef struct{ - uint32_t ident; - uint32_t mask; - void *object; - void (*pFunct)(void *object, const CO_CANrxMsg_t *message); -}CO_CANrx_t; - - -/* Transmit message object as aligned in CAN module. */ -typedef struct{ - uint32_t ident; - uint8_t DLC; - uint8_t data[8] __attribute__((aligned(8))); - volatile bool_t bufferFull; - volatile bool_t syncFlag; -}CO_CANtx_t; - - -/* CAN module object. */ -typedef struct{ - void *CANdriverState; -#ifdef CO_LOG_CAN_MESSAGES - CO_CANtx_t txRecord; -#endif - CO_CANrx_t *rxArray; - uint16_t rxSize; - CO_CANtx_t *txArray; - uint16_t txSize; - uint16_t wasConfigured;/* Zero only on first run of CO_CANmodule_init */ - int fd; /* CAN_RAW socket file descriptor */ - struct can_filter *filter; /* array of CAN filters of size rxSize */ - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint8_t error; - volatile uint16_t CANtxCount; - uint32_t errOld; - void *em; -}CO_CANmodule_t; - - -/* Endianes */ -#ifdef BYTE_ORDER -#if BYTE_ORDER == LITTLE_ENDIAN - #define CO_LITTLE_ENDIAN -#else - #define CO_BIG_ENDIAN -#endif -#endif - - -/* Helper function, must be defined externally. */ -void CO_errExit(char* msg); - - -/* Request CAN configuration or normal mode */ -void CO_CANsetConfigurationMode(void *CANdriverState); -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - - -/* Initialize CAN module object. */ -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); /* not used */ - - -/* Switch off CANmodule. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - - -/* Read CAN identifier */ -uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg); - - -/* Configure CAN message receive buffer. */ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*pFunct)(void *object, const CO_CANrxMsg_t *message)); - - -/* Configure CAN message transmit buffer. */ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag); - - -/* Send CAN message. */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); - - -/* Clear all synchronous TPDOs from CAN module transmit buffers. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - - -/* Verify all errors of CAN module. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); - - -/* Functions receives CAN messages. It is blocking. - * - * @param CANmodule This object. - */ -void CO_CANrxWait(CO_CANmodule_t *CANmodule); - - -#endif From ae48e57c3339f1d0902b50ac8b5da159effc2dc0 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 6 Feb 2020 00:15:54 +0100 Subject: [PATCH 018/520] CANopen.h/.c revision. - example/main.c updated to microsecond time base. - NMT master moved from CANopen.h/.c into 301/CO_NMT_Heartbeat.h/.c. - CANopen.h/.c files revised, changes in interface, compare example/main.c. - Removed CO_init() from CANopen.h/.c. Use separate functions instead. - CO_USE_GLOBALS and global definitions removed from CANopen.c. - CO_USE_OWN_CRC16 removed from CANopen.c. Use CO_driver_target.h. --- 301/CO_NMT_Heartbeat.c | 77 ++- 301/CO_NMT_Heartbeat.h | 44 +- CANopen.c | 1288 +++++++++++++++++----------------------- CANopen.h | 251 ++++---- README.md | 7 +- example/main.c | 22 +- 6 files changed, 783 insertions(+), 906 deletions(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index cb7c0704..4d6b39be 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -85,15 +85,19 @@ CO_ReturnError_t CO_NMT_init( CO_EMpr_t *emPr, uint8_t nodeId, uint16_t firstHBTime_ms, - CO_CANmodule_t *NMT_CANdev, + CO_CANmodule_t *NMT_CANdevRx, uint16_t NMT_rxIdx, uint16_t CANidRxNMT, - CO_CANmodule_t *HB_CANdev, + CO_CANmodule_t *NMT_CANdevTx, + uint16_t NMT_txIdx, + uint16_t CANidTxNMT, + CO_CANmodule_t *HB_CANdevTx, uint16_t HB_txIdx, uint16_t CANidTxHB) { /* verify arguments */ - if(NMT==NULL || emPr==NULL || NMT_CANdev==NULL || HB_CANdev==NULL){ + if (NMT == NULL || emPr == NULL || NMT_CANdevRx == NULL || + NMT_CANdevTx == NULL || HB_CANdevTx == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -121,7 +125,7 @@ CO_ReturnError_t CO_NMT_init( /* configure NMT CAN reception */ CO_CANrxBufferInit( - NMT_CANdev, /* CAN device */ + NMT_CANdevRx, /* CAN device */ NMT_rxIdx, /* rx buffer index */ CANidRxNMT, /* CAN identifier */ 0x7FF, /* mask */ @@ -129,10 +133,20 @@ CO_ReturnError_t CO_NMT_init( (void*)NMT, /* object passed to receive function */ CO_NMT_receive); /* this function will process received message */ + /* configure NMT CAN transmission */ + NMT->NMT_CANdevTx = NMT_CANdevTx; + NMT->NMT_TXbuff = CO_CANtxBufferInit( + NMT_CANdevTx, /* CAN device */ + NMT_txIdx, /* index of specific buffer inside CAN module */ + CANidTxNMT, /* CAN identifier */ + 0, /* rtr */ + 2, /* number of data bytes */ + 0); /* synchronous message flag bit */ + /* configure HB CAN transmission */ - NMT->HB_CANdev = HB_CANdev; + NMT->HB_CANdevTx = HB_CANdevTx; NMT->HB_TXbuff = CO_CANtxBufferInit( - HB_CANdev, /* CAN device */ + HB_CANdevTx, /* CAN device */ HB_txIdx, /* index of specific buffer inside CAN module */ CANidTxHB, /* CAN identifier */ 0, /* rtr */ @@ -182,7 +196,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( NMT->HBproducerTimer = 0; NMT->HB_TXbuff->data[0] = NMT->operatingState; - CO_CANsend(NMT->HB_CANdev, NMT->HB_TXbuff); + CO_CANsend(NMT->HB_CANdevTx, NMT->HB_TXbuff); if (NMT->operatingState == CO_NMT_INITIALIZING) { /* After bootup messages send first heartbeat earlier */ @@ -364,3 +378,52 @@ CO_NMT_internalState_t CO_NMT_getInternalState( } return CO_NMT_INITIALIZING; } + + +/******************************************************************************/ +CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, + CO_NMT_command_t command, + uint8_t nodeID) +{ + CO_ReturnError_t error = CO_ERROR_NO; + + /* verify arguments */ + if (NMT == NULL) { + error = CO_ERROR_TX_UNCONFIGURED; + } + + /* Apply NMT command also to this node, if set so. */ + if (error == CO_ERROR_NO && (nodeID == 0 || nodeID == NMT->nodeId)) { + switch (command) { + case CO_NMT_ENTER_OPERATIONAL: + if ((*NMT->emPr->errorRegister) == 0) { + NMT->operatingState = CO_NMT_OPERATIONAL; + } + break; + case CO_NMT_ENTER_STOPPED: + NMT->operatingState = CO_NMT_STOPPED; + break; + case CO_NMT_ENTER_PRE_OPERATIONAL: + NMT->operatingState = CO_NMT_PRE_OPERATIONAL; + break; + case CO_NMT_RESET_NODE: + NMT->resetCommand = CO_RESET_APP; + break; + case CO_NMT_RESET_COMMUNICATION: + NMT->resetCommand = CO_RESET_COMM; + break; + default: + error = CO_ERROR_ILLEGAL_ARGUMENT; + break; + } + } + + /* Send NMT master message. */ + if (error == CO_ERROR_NO) { + NMT->NMT_TXbuff->data[0] = command; + NMT->NMT_TXbuff->data[1] = nodeID; + error = CO_CANsend(NMT->NMT_CANdevTx, NMT->NMT_TXbuff); + } + + return error; +} diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 1d9805e8..c278347b 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -147,9 +147,11 @@ typedef struct{ uint32_t HBproducerTimer;/**< Internal timer for HB producer */ uint32_t firstHBTime; /**< From CO_NMT_init() */ CO_EMpr_t *emPr; /**< From CO_NMT_init() */ - CO_CANmodule_t *HB_CANdev; /**< From CO_NMT_init() */ + CO_CANmodule_t *NMT_CANdevTx; /**< From CO_NMT_init() */ + CO_CANtx_t *NMT_TXbuff; /**< CAN transmit buffer for NMT master message */ + CO_CANmodule_t *HB_CANdevTx; /**< From CO_NMT_init() */ + CO_CANtx_t *HB_TXbuff; /**< CAN transmit buffer for heartbeat message */ void (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallback() or NULL */ - CO_CANtx_t *HB_TXbuff; /**< CAN transmit buffer */ }CO_NMT_t; @@ -164,10 +166,13 @@ typedef struct{ * @param firstHBTime_ms Time between bootup and first heartbeat message in milliseconds. * If firstHBTime is greater than _Producer Heartbeat time_ * (object dictionary, index 0x1017), latter is used instead. - * @param NMT_CANdev CAN device for NMT reception. + * @param NMT_CANdevRx CAN device for NMT reception. * @param NMT_rxIdx Index of receive buffer in above CAN device. - * @param CANidRxNMT CAN identifier for NMT message. - * @param HB_CANdev CAN device for HB transmission. + * @param CANidRxNMT CAN identifier for NMT receive message. + * @param NMT_CANdevTx CAN device for NMT master transmission. + * @param NMT_txIdx Index of transmit buffer in above CAN device. + * @param CANidTxNMT CAN identifier for NMT transmit message. + * @param HB_CANdevTx CAN device for HB transmission. * @param HB_txIdx Index of transmit buffer in the above CAN device. * @param CANidTxHB CAN identifier for HB message. * @@ -178,10 +183,13 @@ CO_ReturnError_t CO_NMT_init( CO_EMpr_t *emPr, uint8_t nodeId, uint16_t firstHBTime_ms, - CO_CANmodule_t *NMT_CANdev, + CO_CANmodule_t *NMT_CANdevRx, uint16_t NMT_rxIdx, uint16_t CANidRxNMT, - CO_CANmodule_t *HB_CANdev, + CO_CANmodule_t *NMT_CANdevTx, + uint16_t NMT_txIdx, + uint16_t CANidTxNMT, + CO_CANmodule_t *HB_CANdevTx, uint16_t HB_txIdx, uint16_t CANidTxHB); @@ -242,9 +250,29 @@ CO_NMT_internalState_t CO_NMT_getInternalState( CO_NMT_t *NMT); +/** + * Send NMT master command. + * + * This functionality can only be used from NMT master. There is one exception + * where application from slave node may send NMT master command: If CANopen + * object 0x1F80 has value of **0x2**, then NMT slave shall execute the NMT + * service start remote node (CO_NMT_ENTER_OPERATIONAL) with nodeID set to 0. + * + * @param NMT This object. + * @param command NMT command from CO_NMT_command_t. + * @param nodeID Node ID of the remote node. 0 for all nodes including self. + * + * @return 0: Operation completed successfully. + * @return other: same as CO_CANsend(). + */ +CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, + CO_NMT_command_t command, + uint8_t nodeID); + +/** @} */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ #endif diff --git a/CANopen.c b/CANopen.c index 695e18d1..5761035d 100644 --- a/CANopen.c +++ b/CANopen.c @@ -28,433 +28,345 @@ #include "CANopen.h" -/* If defined, global variables will be used, otherwise CANopen objects will - be generated with calloc(). */ -/* #define CO_USE_GLOBALS */ +#include /* for malloc, free */ -/* If defined, the user provides an own implemetation for calculating the - * CRC16 CCITT checksum. */ -/* #define CO_USE_OWN_CRC16 */ -#ifndef CO_USE_GLOBALS - #include /* for malloc, free */ - static uint32_t CO_memoryUsed = 0; /* informative */ -#endif +/* Global variables ***********************************************************/ +extern const CO_OD_entry_t CO_OD[CO_OD_NoOfElements]; /* Object Dictionary */ +static CO_t COO; /* Pointers to CANopen objects */ +CO_t *CO = NULL; /* Pointer to COO */ +static uint32_t CO_memoryUsed = 0; /* informative */ +static CO_CANrx_t *CO_CANmodule_rxArray0; +static CO_CANtx_t *CO_CANmodule_txArray0; +static CO_OD_extension_t *CO_SDO_ODExtensions; +static CO_HBconsNode_t *CO_HBcons_monitoredNodes; -/* Global variables ***********************************************************/ - extern const CO_OD_entry_t CO_OD[CO_OD_NoOfElements]; /* Object Dictionary array */ - static CO_t COO; - CO_t *CO = NULL; - - static CO_CANrx_t *CO_CANmodule_rxArray0; - static CO_CANtx_t *CO_CANmodule_txArray0; - static CO_OD_extension_t *CO_SDO_ODExtensions; - static CO_HBconsNode_t *CO_HBcons_monitoredNodes; #if CO_NO_TRACE > 0 - static uint32_t *CO_traceTimeBuffers[CO_NO_TRACE]; - static int32_t *CO_traceValueBuffers[CO_NO_TRACE]; - #ifdef CO_USE_GLOBALS - #ifndef CO_TRACE_BUFFER_SIZE_FIXED - #define CO_TRACE_BUFFER_SIZE_FIXED 100 - #endif - #endif +static uint32_t *CO_traceTimeBuffers[CO_NO_TRACE]; +static int32_t *CO_traceValueBuffers[CO_NO_TRACE]; +static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #endif -/* Verify features from CO_OD *************************************************/ - /* generate error, if features are not correctly configured for this project */ - #if CO_NO_NMT_MASTER > 1 \ - || CO_NO_SYNC > 1 \ - || CO_NO_EMERGENCY != 1 \ - || CO_NO_SDO_SERVER == 0 \ - || CO_NO_TIME > 1 \ - || CO_NO_SDO_CLIENT > 128 \ - || (CO_NO_RPDO < 1 || CO_NO_RPDO > 0x200) \ - || (CO_NO_TPDO < 1 || CO_NO_TPDO > 0x200) \ - || ODL_consumerHeartbeatTime_arrayLength == 0 \ - || ODL_errorStatusBits_stringLength < 10 \ - || CO_NO_LSS_SERVER > 1 \ - || CO_NO_LSS_CLIENT > 1 \ - || (CO_NO_LSS_SERVER > 0 && CO_NO_LSS_CLIENT > 0) - #error Features from CO_OD.h file are not corectly configured for this project! - #endif - - -/* Indexes for CANopenNode message objects ************************************/ - #ifdef ODL_consumerHeartbeatTime_arrayLength - #define CO_NO_HB_CONS ODL_consumerHeartbeatTime_arrayLength - #else - #define CO_NO_HB_CONS 0 - #endif - #define CO_NO_HB_PROD 1 /* Producer Heartbeat Cont */ - - #define CO_RXCAN_NMT 0 /* index for NMT message */ - #define CO_RXCAN_SYNC 1 /* index for SYNC message */ - #define CO_RXCAN_EMERG (CO_RXCAN_SYNC+CO_NO_SYNC) /* index for Emergency message */ - #define CO_RXCAN_TIME (CO_RXCAN_EMERG+CO_NO_EMERGENCY) /* index for TIME message */ - #define CO_RXCAN_RPDO (CO_RXCAN_TIME+CO_NO_TIME) /* start index for RPDO messages */ - #define CO_RXCAN_SDO_SRV (CO_RXCAN_RPDO+CO_NO_RPDO) /* start index for SDO server message (request) */ - #define CO_RXCAN_SDO_CLI (CO_RXCAN_SDO_SRV+CO_NO_SDO_SERVER) /* start index for SDO client message (response) */ - #define CO_RXCAN_CONS_HB (CO_RXCAN_SDO_CLI+CO_NO_SDO_CLIENT) /* start index for Heartbeat Consumer messages */ - #define CO_RXCAN_LSS (CO_RXCAN_CONS_HB+CO_NO_HB_CONS) /* index for LSS rx message */ - /* total number of received CAN messages */ - #define CO_RXCAN_NO_MSGS (1+CO_NO_SYNC+CO_NO_EMERGENCY+CO_NO_TIME+CO_NO_RPDO+CO_NO_SDO_SERVER+CO_NO_SDO_CLIENT+CO_NO_HB_CONS+CO_NO_LSS_SERVER+CO_NO_LSS_CLIENT) - - #define CO_TXCAN_NMT 0 /* index for NMT master message */ - #define CO_TXCAN_SYNC CO_TXCAN_NMT+CO_NO_NMT_MASTER /* index for SYNC message */ - #define CO_TXCAN_EMERG (CO_TXCAN_SYNC+CO_NO_SYNC) /* index for Emergency message */ - #define CO_TXCAN_TIME (CO_TXCAN_EMERG+CO_NO_EMERGENCY) /* index for TIME message */ - #define CO_TXCAN_TPDO (CO_TXCAN_TIME+CO_NO_TIME) /* start index for TPDO messages */ - #define CO_TXCAN_SDO_SRV (CO_TXCAN_TPDO+CO_NO_TPDO) /* start index for SDO server message (response) */ - #define CO_TXCAN_SDO_CLI (CO_TXCAN_SDO_SRV+CO_NO_SDO_SERVER) /* start index for SDO client message (request) */ - #define CO_TXCAN_HB (CO_TXCAN_SDO_CLI+CO_NO_SDO_CLIENT) /* index for Heartbeat message */ - #define CO_TXCAN_LSS (CO_TXCAN_HB+CO_NO_HB_PROD) /* index for LSS tx message */ - /* total number of transmitted CAN messages */ - #define CO_TXCAN_NO_MSGS (CO_NO_NMT_MASTER+CO_NO_SYNC+CO_NO_EMERGENCY+CO_NO_TIME+CO_NO_TPDO+CO_NO_SDO_SERVER+CO_NO_SDO_CLIENT+CO_NO_HB_PROD+CO_NO_LSS_SERVER+CO_NO_LSS_CLIENT) - - -#ifdef CO_USE_GLOBALS - static CO_CANmodule_t COO_CANmodule; - static CO_CANrx_t COO_CANmodule_rxArray0[CO_RXCAN_NO_MSGS]; - static CO_CANtx_t COO_CANmodule_txArray0[CO_TXCAN_NO_MSGS]; - static CO_SDO_t COO_SDO[CO_NO_SDO_SERVER]; - static CO_OD_extension_t COO_SDO_ODExtensions[CO_OD_NoOfElements]; - static CO_EM_t COO_EM; - static CO_EMpr_t COO_EMpr; - static CO_NMT_t COO_NMT; -#if CO_NO_SYNC == 1 - static CO_SYNC_t COO_SYNC; +/* Verify number of CANopenNode objects from CO_OD.h **************************/ +#if CO_NO_SYNC > 1 \ + || CO_NO_EMERGENCY != 1 \ + || (CO_NO_SDO_SERVER < 1 || CO_NO_SDO_SERVER > 128) \ + || CO_NO_TIME > 1 \ + || CO_NO_SDO_CLIENT > 128 \ + || (CO_NO_RPDO < 1 || CO_NO_RPDO > 0x200) \ + || (CO_NO_TPDO < 1 || CO_NO_TPDO > 0x200) \ + || ODL_consumerHeartbeatTime_arrayLength == 0 \ + || ODL_errorStatusBits_stringLength < 10 \ + || CO_NO_LSS_SERVER > 1 \ + || CO_NO_LSS_CLIENT > 1 \ + || (CO_NO_LSS_SERVER > 0 && CO_NO_LSS_CLIENT > 0) +#error Features from CO_OD.h file are not corectly configured for this project! #endif -#if CO_NO_TIME == 1 - static CO_TIME_t COO_TIME; -#endif - static CO_RPDO_t COO_RPDO[CO_NO_RPDO]; - static CO_TPDO_t COO_TPDO[CO_NO_TPDO]; - static CO_HBconsumer_t COO_HBcons; - static CO_HBconsNode_t COO_HBcons_monitoredNodes[CO_NO_HB_CONS]; -#if CO_NO_LSS_SERVER == 1 - static CO_LSSslave_t CO0_LSSslave; -#endif -#if CO_NO_LSS_CLIENT == 1 - static CO_LSSmaster_t CO0_LSSmaster; -#endif -#if CO_NO_SDO_CLIENT != 0 - static CO_SDOclient_t COO_SDOclient[CO_NO_SDO_CLIENT]; -#endif -#if CO_NO_TRACE > 0 - static CO_trace_t COO_trace[CO_NO_TRACE]; - static uint32_t COO_traceTimeBuffers[CO_NO_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; - static int32_t COO_traceValueBuffers[CO_NO_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; -#endif -#endif - -/* These declarations here are needed in the case the switches for the project - change the visibility in the headers in a way that the compiler doesn't see an declaration anymore */ -#if CO_NO_LSS_SERVER == 0 /* LSS Server means LSS slave */ +/* Indexes of CO_CANrx_t objects in CO_CANmodule_t and total number of them. **/ +#define CO_RXCAN_NMT 0 +#define CO_RXCAN_SYNC (CO_RXCAN_NMT + CO_NO_NMT) +#define CO_RXCAN_EMERG (CO_RXCAN_SYNC + CO_NO_SYNC) +#define CO_RXCAN_TIME (CO_RXCAN_EMERG + CO_NO_EMERGENCY) +#define CO_RXCAN_RPDO (CO_RXCAN_TIME + CO_NO_TIME) +#define CO_RXCAN_SDO_SRV (CO_RXCAN_RPDO + CO_NO_RPDO) +#define CO_RXCAN_SDO_CLI (CO_RXCAN_SDO_SRV + CO_NO_SDO_SERVER) +#define CO_RXCAN_CONS_HB (CO_RXCAN_SDO_CLI + CO_NO_SDO_CLIENT) +#define CO_RXCAN_LSS (CO_RXCAN_CONS_HB + CO_NO_HB_CONS) +#define CO_RXCAN_NO_MSGS (CO_NO_NMT + \ + CO_NO_SYNC + \ + CO_NO_EMERGENCY + \ + CO_NO_TIME + \ + CO_NO_RPDO + \ + CO_NO_SDO_SERVER + \ + CO_NO_SDO_CLIENT + \ + CO_NO_HB_CONS + \ + CO_NO_LSS_SERVER + \ + CO_NO_LSS_CLIENT) + +/* Indexes of CO_CANtx_t objects in CO_CANmodule_t and total number of them. **/ +#define CO_TXCAN_NMT 0 +#define CO_TXCAN_SYNC (CO_TXCAN_NMT + CO_NO_NMT) +#define CO_TXCAN_EMERG (CO_TXCAN_SYNC + CO_NO_SYNC) +#define CO_TXCAN_TIME (CO_TXCAN_EMERG + CO_NO_EMERGENCY) +#define CO_TXCAN_TPDO (CO_TXCAN_TIME + CO_NO_TIME) +#define CO_TXCAN_SDO_SRV (CO_TXCAN_TPDO + CO_NO_TPDO) +#define CO_TXCAN_SDO_CLI (CO_TXCAN_SDO_SRV + CO_NO_SDO_SERVER) +#define CO_TXCAN_HB (CO_TXCAN_SDO_CLI + CO_NO_SDO_CLIENT) +#define CO_TXCAN_LSS (CO_TXCAN_HB + CO_NO_HB_PROD) +#define CO_TXCAN_NO_MSGS (CO_NO_NMT + \ + CO_NO_SYNC + \ + CO_NO_EMERGENCY + \ + CO_NO_TIME + \ + CO_NO_TPDO + \ + CO_NO_SDO_SERVER + \ + CO_NO_SDO_CLIENT + \ + CO_NO_HB_PROD + \ + CO_NO_LSS_SERVER + \ + CO_NO_LSS_CLIENT) -CO_ReturnError_t CO_new(void); -CO_ReturnError_t CO_CANinit( - void *CANptr, - uint16_t bitRate); +/******************************************************************************/ +CO_ReturnError_t CO_new(void) { + int16_t i; + uint16_t errCnt = 0; -CO_ReturnError_t CO_LSSinit( - uint8_t nodeId, - uint16_t bitRate); + /* If CANopen was initialized before, return. */ + if (CO != NULL) { + return CO_ERROR_NO; + } -CO_ReturnError_t CO_CANopenInit( - uint8_t nodeId); + /* Verify parameters from CO_OD */ + if (sizeof(OD_TPDOCommunicationParameter_t) != sizeof(CO_TPDOCommPar_t) || + sizeof(OD_TPDOMappingParameter_t) != sizeof(CO_TPDOMapPar_t) || + sizeof(OD_RPDOCommunicationParameter_t) != sizeof(CO_RPDOCommPar_t) || + sizeof(OD_RPDOMappingParameter_t) != sizeof(CO_RPDOMapPar_t)) { + return CO_ERROR_PARAMETERS; + } -#else /* CO_NO_LSS_SERVER == 0 */ +#if CO_NO_SDO_CLIENT != 0 + if (sizeof(OD_SDOClientParameter_t) != sizeof(CO_SDOclientPar_t)) { + return CO_ERROR_PARAMETERS; + } +#endif -CO_ReturnError_t CO_init( - void *CANptr, - uint8_t nodeId, - uint16_t bitRate); + /* globals */ + CO = &COO; + CO_memoryUsed = 0; + + /* CANmodule */ + CO->CANmodule[0] = (CO_CANmodule_t *)calloc(1, sizeof(CO_CANmodule_t)); + if (CO->CANmodule[0] == NULL) errCnt++; + CO_CANmodule_rxArray0 = + (CO_CANrx_t *)calloc(CO_RXCAN_NO_MSGS, sizeof(CO_CANrx_t)); + if (CO_CANmodule_rxArray0 == NULL) errCnt++; + CO_CANmodule_txArray0 = + (CO_CANtx_t *)calloc(CO_TXCAN_NO_MSGS, sizeof(CO_CANtx_t)); + if (CO_CANmodule_txArray0 == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_CANmodule_t) + + sizeof(CO_CANrx_t) * CO_RXCAN_NO_MSGS + + sizeof(CO_CANtx_t) * CO_TXCAN_NO_MSGS; + + /* SDOserver */ + for (i = 0; i < CO_NO_SDO_SERVER; i++) { + CO->SDO[i] = (CO_SDO_t *)calloc(1, sizeof(CO_SDO_t)); + if (CO->SDO[i] == NULL) errCnt++; + } + CO_SDO_ODExtensions = (CO_OD_extension_t *)calloc( + CO_OD_NoOfElements, sizeof(CO_OD_extension_t)); + if (CO_SDO_ODExtensions == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_SDO_t) * CO_NO_SDO_SERVER + + sizeof(CO_OD_extension_t) * CO_OD_NoOfElements; + + /* Emergency */ + CO->em = (CO_EM_t *)calloc(1, sizeof(CO_EM_t)); + if (CO->em == NULL) errCnt++; + CO->emPr = (CO_EMpr_t *)calloc(1, sizeof(CO_EMpr_t)); + if (CO->emPr == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_EM_t) + sizeof(CO_EMpr_t); + + /* NMT_Heartbeat */ + CO->NMT = (CO_NMT_t *)calloc(1, sizeof(CO_NMT_t)); + if (CO->NMT == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_NMT_t); -#endif /* CO_NO_LSS_SERVER == 0 */ +#if CO_NO_SYNC == 1 + /* SYNC */ + CO->SYNC = (CO_SYNC_t *)calloc(1, sizeof(CO_SYNC_t)); + if (CO->SYNC == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_SYNC_t); +#else + CO->SYNC = NULL; +#endif +#if CO_NO_TIME == 1 + /* TIME */ + CO->TIME = (CO_TIME_t *)calloc(1, sizeof(CO_TIME_t)); + if (CO->TIME == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_TIME_t); +#else + CO->TIME = NULL; +#endif -/* Helper function for NMT master *********************************************/ -#if CO_NO_NMT_MASTER == 1 - CO_CANtx_t *NMTM_txBuff = 0; + /* RPDO */ + for (i = 0; i < CO_NO_RPDO; i++) { + CO->RPDO[i] = (CO_RPDO_t *)calloc(1, sizeof(CO_RPDO_t)); + if (CO->RPDO[i] == NULL) errCnt++; + } + CO_memoryUsed += sizeof(CO_RPDO_t) * CO_NO_RPDO; - CO_ReturnError_t CO_sendNMTcommand(CO_t *co, uint8_t command, uint8_t nodeID){ - if(NMTM_txBuff == 0){ - /* error, CO_CANtxBufferInit() was not called for this buffer. */ - return CO_ERROR_TX_UNCONFIGURED; /* -11 */ - } - NMTM_txBuff->data[0] = command; - NMTM_txBuff->data[1] = nodeID; - - CO_ReturnError_t error = CO_ERROR_NO; - - /* Apply NMT command also to this node, if set so. */ - if(nodeID == 0 || nodeID == co->NMT->nodeId){ - switch(command){ - case CO_NMT_ENTER_OPERATIONAL: - if((*co->NMT->emPr->errorRegister) == 0) { - co->NMT->operatingState = CO_NMT_OPERATIONAL; - } - break; - case CO_NMT_ENTER_STOPPED: - co->NMT->operatingState = CO_NMT_STOPPED; - break; - case CO_NMT_ENTER_PRE_OPERATIONAL: - co->NMT->operatingState = CO_NMT_PRE_OPERATIONAL; - break; - case CO_NMT_RESET_NODE: - co->NMT->resetCommand = CO_RESET_APP; - break; - case CO_NMT_RESET_COMMUNICATION: - co->NMT->resetCommand = CO_RESET_COMM; - break; - default: - error = CO_ERROR_ILLEGAL_ARGUMENT; - break; - - } - } + /* TPDO */ + for (i = 0; i < CO_NO_TPDO; i++) { + CO->TPDO[i] = (CO_TPDO_t *)calloc(1, sizeof(CO_TPDO_t)); + if (CO->TPDO[i] == NULL) errCnt++; + } + CO_memoryUsed += sizeof(CO_TPDO_t) * CO_NO_TPDO; - if(error == CO_ERROR_NO) - return CO_CANsend(co->CANmodule[0], NMTM_txBuff); /* 0 = success */ - else - { - return error; - } + /* Heartbeat consumer */ + CO->HBcons = (CO_HBconsumer_t *)calloc(1, sizeof(CO_HBconsumer_t)); + if (CO->HBcons == NULL) errCnt++; + CO_HBcons_monitoredNodes = + (CO_HBconsNode_t *)calloc(CO_NO_HB_CONS, sizeof(CO_HBconsNode_t)); + if (CO_HBcons_monitoredNodes == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_HBconsumer_t) + + sizeof(CO_HBconsNode_t) * CO_NO_HB_CONS; +#if CO_NO_SDO_CLIENT != 0 + /* SDOclient */ + for (i = 0; i < CO_NO_SDO_CLIENT; i++) { + CO->SDOclient[i] = + (CO_SDOclient_t *)calloc(1, sizeof(CO_SDOclient_t)); + if (CO->SDOclient[i] == NULL) errCnt++; } + CO_memoryUsed += sizeof(CO_SDOclient_t) * CO_NO_SDO_CLIENT; +#endif + +#if CO_NO_LSS_SERVER == 1 + /* LSSslave */ + CO->LSSslave = (CO_LSSslave_t *)calloc(1, sizeof(CO_LSSslave_t)); + if (CO->LSSslave == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_LSSslave_t); #endif +#if CO_NO_LSS_CLIENT == 1 + /* LSSmaster */ + CO->LSSmaster = (CO_LSSmaster_t *)calloc(1, sizeof(CO_LSSmaster_t)); + if (CO->LSSmaster == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_LSSmaster_t); +#endif #if CO_NO_TRACE > 0 -static uint32_t CO_traceBufferSize[CO_NO_TRACE]; + /* Trace */ + for (i = 0; i < CO_NO_TRACE; i++) { + CO->trace[i] = (CO_trace_t *)calloc(1, sizeof(CO_trace_t)); + if (CO->trace[i] == NULL) errCnt++; + } + CO_memoryUsed += sizeof(CO_trace_t) * CO_NO_TRACE; + for (i = 0; i < CO_NO_TRACE; i++) { + CO_traceTimeBuffers[i] = + (uint32_t *)calloc(OD_traceConfig[i].size, sizeof(uint32_t)); + CO_traceValueBuffers[i] = + (int32_t *)calloc(OD_traceConfig[i].size, sizeof(int32_t)); + if (CO_traceTimeBuffers[i] != NULL && + CO_traceValueBuffers[i] != NULL) { + CO_traceBufferSize[i] = OD_traceConfig[i].size; + } else { + CO_traceBufferSize[i] = 0; + } + CO_memoryUsed += CO_traceBufferSize[i] * sizeof(uint32_t) * 2; + } #endif + return (errCnt == 0) ? CO_ERROR_NO : CO_ERROR_OUT_OF_MEMORY; +} + + /******************************************************************************/ -CO_ReturnError_t CO_new(void) -{ +void CO_delete(void *CANptr) { int16_t i; -#ifndef CO_USE_GLOBALS - uint16_t errCnt; -#endif - /* Verify parameters from CO_OD */ - if( sizeof(OD_TPDOCommunicationParameter_t) != sizeof(CO_TPDOCommPar_t) - || sizeof(OD_TPDOMappingParameter_t) != sizeof(CO_TPDOMapPar_t) - || sizeof(OD_RPDOCommunicationParameter_t) != sizeof(CO_RPDOCommPar_t) - || sizeof(OD_RPDOMappingParameter_t) != sizeof(CO_RPDOMapPar_t)) - { - return CO_ERROR_PARAMETERS; + CO_CANsetConfigurationMode(CANptr); + + /* If CANopen was initialized before, return. */ + if (CO == NULL) { + return; } - #if CO_NO_SDO_CLIENT != 0 - if(sizeof(OD_SDOClientParameter_t) != sizeof(CO_SDOclientPar_t)){ - return CO_ERROR_PARAMETERS; + CO_CANmodule_disable(CO->CANmodule[0]); + +#if CO_NO_TRACE > 0 + /* Trace */ + for (i = 0; i < CO_NO_TRACE; i++) { + free(CO->trace[i]); + free(CO_traceTimeBuffers[i]); + free(CO_traceValueBuffers[i]); } - #endif +#endif +#if CO_NO_LSS_CLIENT == 1 + /* LSSmaster */ + free(CO->LSSmaster); +#endif - /* Initialize CANopen object */ -#ifdef CO_USE_GLOBALS - CO = &COO; +#if CO_NO_LSS_SERVER == 1 + /* LSSslave */ + free(CO->LSSslave); +#endif - CO_memset((uint8_t*)CO, 0, sizeof(CO_t)); - CO->CANmodule[0] = &COO_CANmodule; - CO_CANmodule_rxArray0 = &COO_CANmodule_rxArray0[0]; - CO_CANmodule_txArray0 = &COO_CANmodule_txArray0[0]; - for(i=0; iSDO[i] = &COO_SDO[i]; - CO_SDO_ODExtensions = &COO_SDO_ODExtensions[0]; - CO->em = &COO_EM; - CO->emPr = &COO_EMpr; - CO->NMT = &COO_NMT; - #if CO_NO_SYNC == 1 - CO->SYNC = &COO_SYNC; - #endif - #if CO_NO_TIME == 1 - CO->TIME = &COO_TIME; - #endif - for(i=0; iRPDO[i] = &COO_RPDO[i]; - for(i=0; iTPDO[i] = &COO_TPDO[i]; - CO->HBcons = &COO_HBcons; - CO_HBcons_monitoredNodes = &COO_HBcons_monitoredNodes[0]; - #if CO_NO_LSS_SERVER == 1 - CO->LSSslave = &CO0_LSSslave; - #endif - #if CO_NO_LSS_CLIENT == 1 - CO->LSSmaster = &CO0_LSSmaster; - #endif - #if CO_NO_SDO_CLIENT != 0 - for(i=0; iSDOclient[i] = &COO_SDOclient[i]; - } - #endif - #if CO_NO_TRACE > 0 - for(i=0; itrace[i] = &COO_trace[i]; - CO_traceTimeBuffers[i] = &COO_traceTimeBuffers[i][0]; - CO_traceValueBuffers[i] = &COO_traceValueBuffers[i][0]; - CO_traceBufferSize[i] = CO_TRACE_BUFFER_SIZE_FIXED; - } - #endif -#else - if(CO == NULL){ /* Use malloc only once */ - CO = &COO; - CO->CANmodule[0] = (CO_CANmodule_t *) calloc(1, sizeof(CO_CANmodule_t)); - CO_CANmodule_rxArray0 = (CO_CANrx_t *) calloc(CO_RXCAN_NO_MSGS, sizeof(CO_CANrx_t)); - CO_CANmodule_txArray0 = (CO_CANtx_t *) calloc(CO_TXCAN_NO_MSGS, sizeof(CO_CANtx_t)); - for(i=0; iSDO[i] = (CO_SDO_t *) calloc(1, sizeof(CO_SDO_t)); - } - CO_SDO_ODExtensions = (CO_OD_extension_t*) calloc(CO_OD_NoOfElements, sizeof(CO_OD_extension_t)); - CO->em = (CO_EM_t *) calloc(1, sizeof(CO_EM_t)); - CO->emPr = (CO_EMpr_t *) calloc(1, sizeof(CO_EMpr_t)); - CO->NMT = (CO_NMT_t *) calloc(1, sizeof(CO_NMT_t)); - #if CO_NO_SYNC == 1 - CO->SYNC = (CO_SYNC_t *) calloc(1, sizeof(CO_SYNC_t)); - #endif - #if CO_NO_TIME == 1 - CO->TIME = (CO_TIME_t *) calloc(1, sizeof(CO_TIME_t)); - #endif - for(i=0; iRPDO[i] = (CO_RPDO_t *) calloc(1, sizeof(CO_RPDO_t)); - } - for(i=0; iTPDO[i] = (CO_TPDO_t *) calloc(1, sizeof(CO_TPDO_t)); - } - CO->HBcons = (CO_HBconsumer_t *) calloc(1, sizeof(CO_HBconsumer_t)); - CO_HBcons_monitoredNodes = (CO_HBconsNode_t *) calloc(CO_NO_HB_CONS, sizeof(CO_HBconsNode_t)); - #if CO_NO_LSS_SERVER == 1 - CO->LSSslave = (CO_LSSslave_t *) calloc(1, sizeof(CO_LSSslave_t)); - #endif - #if CO_NO_LSS_CLIENT == 1 - CO->LSSmaster = (CO_LSSmaster_t *) calloc(1, sizeof(CO_LSSmaster_t)); - #endif - #if CO_NO_SDO_CLIENT != 0 - for(i=0; iSDOclient[i] = (CO_SDOclient_t *) calloc(1, sizeof(CO_SDOclient_t)); - } - #endif - #if CO_NO_TRACE > 0 - for(i=0; itrace[i] = (CO_trace_t *) calloc(1, sizeof(CO_trace_t)); - CO_traceTimeBuffers[i] = (uint32_t *) calloc(OD_traceConfig[i].size, sizeof(uint32_t)); - CO_traceValueBuffers[i] = (int32_t *) calloc(OD_traceConfig[i].size, sizeof(int32_t)); - if(CO_traceTimeBuffers[i] != NULL && CO_traceValueBuffers[i] != NULL) { - CO_traceBufferSize[i] = OD_traceConfig[i].size; - } else { - CO_traceBufferSize[i] = 0; - } - } - #endif +#if CO_NO_SDO_CLIENT != 0 + /* SDOclient */ + for (i = 0; i < CO_NO_SDO_CLIENT; i++) { + free(CO->SDOclient[i]); } +#endif - CO_memoryUsed = sizeof(CO_CANmodule_t) - + sizeof(CO_CANrx_t) * CO_RXCAN_NO_MSGS - + sizeof(CO_CANtx_t) * CO_TXCAN_NO_MSGS - + sizeof(CO_SDO_t) * CO_NO_SDO_SERVER - + sizeof(CO_OD_extension_t) * CO_OD_NoOfElements - + sizeof(CO_EM_t) - + sizeof(CO_EMpr_t) - + sizeof(CO_NMT_t) - #if CO_NO_SYNC == 1 - + sizeof(CO_SYNC_t) - #endif - #if CO_NO_TIME == 1 - + sizeof(CO_TIME_t) - #endif - + sizeof(CO_RPDO_t) * CO_NO_RPDO - + sizeof(CO_TPDO_t) * CO_NO_TPDO - + sizeof(CO_HBconsumer_t) - + sizeof(CO_HBconsNode_t) * CO_NO_HB_CONS - #if CO_NO_LSS_SERVER == 1 - + sizeof(CO_LSSslave_t) - #endif - #if CO_NO_LSS_CLIENT == 1 - + sizeof(CO_LSSmaster_t) - #endif - #if CO_NO_SDO_CLIENT != 0 - + sizeof(CO_SDOclient_t) * CO_NO_SDO_CLIENT - #endif - + 0; - #if CO_NO_TRACE > 0 - CO_memoryUsed += sizeof(CO_trace_t) * CO_NO_TRACE; - for(i=0; iCANmodule[0] == NULL) errCnt++; - if(CO_CANmodule_rxArray0 == NULL) errCnt++; - if(CO_CANmodule_txArray0 == NULL) errCnt++; - for(i=0; iSDO[i] == NULL) errCnt++; - } - if(CO_SDO_ODExtensions == NULL) errCnt++; - if(CO->em == NULL) errCnt++; - if(CO->emPr == NULL) errCnt++; - if(CO->NMT == NULL) errCnt++; - #if CO_NO_SYNC == 1 - if(CO->SYNC == NULL) errCnt++; - #endif - #if CO_NO_TIME == 1 - if(CO->TIME == NULL) errCnt++; - #endif - for(i=0; iRPDO[i] == NULL) errCnt++; - } - for(i=0; iTPDO[i] == NULL) errCnt++; - } - if(CO->HBcons == NULL) errCnt++; - if(CO_HBcons_monitoredNodes == NULL) errCnt++; - #if CO_NO_LSS_SERVER == 1 - if(CO->LSSslave == NULL) errCnt++; - #endif - #if CO_NO_LSS_CLIENT == 1 - if(CO->LSSmaster == NULL) errCnt++; - #endif - #if CO_NO_SDO_CLIENT != 0 - for(i=0; iSDOclient[i] == NULL) errCnt++; + /* Heartbeat consumer */ + free(CO_HBcons_monitoredNodes); + free(CO->HBcons); + + /* TPDO */ + for (i = 0; i < CO_NO_TPDO; i++) { + free(CO->TPDO[i]); } - #endif - #if CO_NO_TRACE > 0 - for(i=0; itrace[i] == NULL) errCnt++; + + /* RPDO */ + for (i = 0; i < CO_NO_RPDO; i++) { + free(CO->RPDO[i]); } - #endif - if(errCnt != 0) return CO_ERROR_OUT_OF_MEMORY; +#if CO_NO_TIME == 1 + /* TIME */ + free(CO->TIME); +#endif + +#if CO_NO_SYNC == 1 + /* SYNC */ + free(CO->SYNC); #endif - return CO_ERROR_NO; + + /* NMT_Heartbeat */ + free(CO->NMT); + + /* Emergency */ + free(CO->emPr); + free(CO->em); + + /* SDOserver */ + free(CO_SDO_ODExtensions); + for (i = 0; i < CO_NO_SDO_SERVER; i++) { + free(CO->SDO[i]); + } + + /* CANmodule */ + free(CO_CANmodule_txArray0); + free(CO_CANmodule_rxArray0); + free(CO->CANmodule[0]); + + /* globals */ + CO = NULL; + CO_memoryUsed = 0; } /******************************************************************************/ -CO_ReturnError_t CO_CANinit( - void *CANptr, - uint16_t bitRate) +CO_ReturnError_t CO_CANinit(void *CANptr, + uint16_t bitRate) { CO_ReturnError_t err; CO->CANmodule[0]->CANnormal = false; CO_CANsetConfigurationMode(CANptr); - err = CO_CANmodule_init( - CO->CANmodule[0], - CANptr, - CO_CANmodule_rxArray0, - CO_RXCAN_NO_MSGS, - CO_CANmodule_txArray0, - CO_TXCAN_NO_MSGS, - bitRate); + /* CANmodule */ + err = CO_CANmodule_init(CO->CANmodule[0], + CANptr, + CO_CANmodule_rxArray0, + CO_RXCAN_NO_MSGS, + CO_CANmodule_txArray0, + CO_TXCAN_NO_MSGS, + bitRate); return err; } @@ -462,28 +374,28 @@ CO_ReturnError_t CO_CANinit( /******************************************************************************/ #if CO_NO_LSS_SERVER == 1 -CO_ReturnError_t CO_LSSinit( - uint8_t nodeId, - uint16_t bitRate) +CO_ReturnError_t CO_LSSinit(uint8_t nodeId, + uint16_t bitRate) { CO_LSS_address_t lssAddress; CO_ReturnError_t err; + /* LSSslave */ lssAddress.identity.productCode = OD_identity.productCode; lssAddress.identity.revisionNumber = OD_identity.revisionNumber; lssAddress.identity.serialNumber = OD_identity.serialNumber; lssAddress.identity.vendorID = OD_identity.vendorID; - err = CO_LSSslave_init( - CO->LSSslave, - lssAddress, - bitRate, - nodeId, - CO->CANmodule[0], - CO_RXCAN_LSS, - CO_CAN_ID_LSS_SRV, - CO->CANmodule[0], - CO_TXCAN_LSS, - CO_CAN_ID_LSS_CLI); + + err = CO_LSSslave_init(CO->LSSslave, + lssAddress, + bitRate, + nodeId, + CO->CANmodule[0], + CO_RXCAN_LSS, + CO_CAN_ID_LSS_SRV, + CO->CANmodule[0], + CO_TXCAN_LSS, + CO_CAN_ID_LSS_CLI); return err; } @@ -491,464 +403,334 @@ CO_ReturnError_t CO_LSSinit( /******************************************************************************/ -CO_ReturnError_t CO_CANopenInit( - uint8_t nodeId) -{ +CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { int16_t i; CO_ReturnError_t err; /* Verify CANopen Node-ID */ - if(nodeId<1 || nodeId>127) { + if (nodeId < 1 || nodeId > 127) { return CO_ERROR_PARAMETERS; } - for (i=0; iSDO[i], - COB_IDClientToServer, - COB_IDServerToClient, - OD_H1200_SDO_SERVER_PARAM+i, - i==0 ? 0 : CO->SDO[0], - &CO_OD[0], - CO_OD_NoOfElements, - CO_SDO_ODExtensions, - nodeId, - 1000, - CO->CANmodule[0], - CO_RXCAN_SDO_SRV+i, - CO->CANmodule[0], - CO_TXCAN_SDO_SRV+i); + err = CO_SDO_init(CO->SDO[i], + COB_IDClientToServer, + COB_IDServerToClient, + OD_H1200_SDO_SERVER_PARAM + i, + i == 0 ? 0 : CO->SDO[0], + &CO_OD[0], + CO_OD_NoOfElements, + CO_SDO_ODExtensions, + nodeId, + 1000, + CO->CANmodule[0], + CO_RXCAN_SDO_SRV + i, + CO->CANmodule[0], + CO_TXCAN_SDO_SRV + i); + + if (err) return err; } - if(err){return err;} - - - err = CO_EM_init( - CO->em, - CO->emPr, - CO->SDO[0], - &OD_errorStatusBits[0], - ODL_errorStatusBits_stringLength, - &OD_errorRegister, - &OD_preDefinedErrorField[0], - ODL_preDefinedErrorField_arrayLength, - CO->CANmodule[0], - CO_RXCAN_EMERG, - CO->CANmodule[0], - CO_TXCAN_EMERG, - (uint16_t)CO_CAN_ID_EMERGENCY + nodeId); - - if(err){return err;} - - - err = CO_NMT_init( - CO->NMT, - CO->emPr, - nodeId, - 500, - CO->CANmodule[0], - CO_RXCAN_NMT, - CO_CAN_ID_NMT_SERVICE, - CO->CANmodule[0], - CO_TXCAN_HB, - CO_CAN_ID_HEARTBEAT + nodeId); - - if(err){return err;} - - -#if CO_NO_NMT_MASTER == 1 - NMTM_txBuff = CO_CANtxBufferInit(/* return pointer to 8-byte CAN data buffer, which should be populated */ - CO->CANmodule[0], /* pointer to CAN module used for sending this message */ - CO_TXCAN_NMT, /* index of specific buffer inside CAN module */ - 0x0000, /* CAN identifier */ - 0, /* rtr */ - 2, /* number of data bytes */ - 0); /* synchronous message flag bit */ -#endif -#if CO_NO_LSS_CLIENT == 1 - err = CO_LSSmaster_init( - CO->LSSmaster, - CO_LSSmaster_DEFAULT_TIMEOUT, - CO->CANmodule[0], - CO_RXCAN_LSS, - CO_CAN_ID_LSS_CLI, - CO->CANmodule[0], - CO_TXCAN_LSS, - CO_CAN_ID_LSS_SRV); - - if(err){return err;} -#endif + /* Emergency */ + err = CO_EM_init(CO->em, + CO->emPr, + CO->SDO[0], + &OD_errorStatusBits[0], + ODL_errorStatusBits_stringLength, + &OD_errorRegister, + &OD_preDefinedErrorField[0], + ODL_preDefinedErrorField_arrayLength, + CO->CANmodule[0], + CO_RXCAN_EMERG, + CO->CANmodule[0], + CO_TXCAN_EMERG, + (uint16_t)CO_CAN_ID_EMERGENCY + nodeId); + + if (err) return err; + + /* NMT_Heartbeat */ + err = CO_NMT_init(CO->NMT, + CO->emPr, + nodeId, + 500, + CO->CANmodule[0], + CO_RXCAN_NMT, + CO_CAN_ID_NMT_SERVICE, + CO->CANmodule[0], + CO_TXCAN_NMT, + CO_CAN_ID_NMT_SERVICE, + CO->CANmodule[0], + CO_TXCAN_HB, + CO_CAN_ID_HEARTBEAT + nodeId); + + if (err) return err; #if CO_NO_SYNC == 1 - err = CO_SYNC_init( - CO->SYNC, - CO->em, - CO->SDO[0], - &CO->NMT->operatingState, - OD_COB_ID_SYNCMessage, - OD_communicationCyclePeriod, - OD_synchronousCounterOverflowValue, - CO->CANmodule[0], - CO_RXCAN_SYNC, - CO->CANmodule[0], - CO_TXCAN_SYNC); - - if(err){return err;} + /* SYNC */ + err = CO_SYNC_init(CO->SYNC, + CO->em, + CO->SDO[0], + &CO->NMT->operatingState, + OD_COB_ID_SYNCMessage, + OD_communicationCyclePeriod, + OD_synchronousCounterOverflowValue, + CO->CANmodule[0], + CO_RXCAN_SYNC, + CO->CANmodule[0], + CO_TXCAN_SYNC); + + if (err) return err; #endif #if CO_NO_TIME == 1 - err = CO_TIME_init( - CO->TIME, - CO->em, - CO->SDO[0], - &CO->NMT->operatingState, - OD_COB_ID_TIME, - 0, - CO->CANmodule[0], - CO_RXCAN_TIME, - CO->CANmodule[0], - CO_TXCAN_TIME); - - if(err){return err;} + /* TIME */ + err = CO_TIME_init(CO->TIME, + CO->em, + CO->SDO[0], + &CO->NMT->operatingState, + OD_COB_ID_TIME, + 0, + CO->CANmodule[0], + CO_RXCAN_TIME, + CO->CANmodule[0], + CO_TXCAN_TIME); + + if (err) return err; #endif - for(i=0; iCANmodule[0]; uint16_t CANdevRxIdx = CO_RXCAN_RPDO + i; - err = CO_RPDO_init( - CO->RPDO[i], - CO->em, - CO->SDO[0], - CO->SYNC, - &CO->NMT->operatingState, - nodeId, - ((i<4) ? (CO_CAN_ID_RPDO_1+i*0x100) : 0), - 0, - (CO_RPDOCommPar_t*) &OD_RPDOCommunicationParameter[i], - (CO_RPDOMapPar_t*) &OD_RPDOMappingParameter[i], - OD_H1400_RXPDO_1_PARAM+i, - OD_H1600_RXPDO_1_MAPPING+i, - CANdevRx, - CANdevRxIdx); - - if(err){return err;} + err = CO_RPDO_init(CO->RPDO[i], + CO->em, + CO->SDO[0], + CO->SYNC, + &CO->NMT->operatingState, + nodeId, + ((i < 4) ? (CO_CAN_ID_RPDO_1 + i * 0x100) : 0), + 0, + (CO_RPDOCommPar_t*)&OD_RPDOCommunicationParameter[i], + (CO_RPDOMapPar_t *)&OD_RPDOMappingParameter[i], + OD_H1400_RXPDO_1_PARAM + i, + OD_H1600_RXPDO_1_MAPPING + i, + CANdevRx, + CANdevRxIdx); + + if (err) return err; } - for(i=0; iTPDO[i], - CO->em, - CO->SDO[0], - CO->SYNC, - &CO->NMT->operatingState, - nodeId, - ((i<4) ? (CO_CAN_ID_TPDO_1+i*0x100) : 0), - 0, - (CO_TPDOCommPar_t*) &OD_TPDOCommunicationParameter[i], - (CO_TPDOMapPar_t*) &OD_TPDOMappingParameter[i], - OD_H1800_TXPDO_1_PARAM+i, - OD_H1A00_TXPDO_1_MAPPING+i, - CO->CANmodule[0], - CO_TXCAN_TPDO+i); - - if(err){return err;} + /* TPDO */ + for (i = 0; i < CO_NO_TPDO; i++) { + err = CO_TPDO_init(CO->TPDO[i], + CO->em, + CO->SDO[0], + CO->SYNC, + &CO->NMT->operatingState, + nodeId, + ((i < 4) ? (CO_CAN_ID_TPDO_1 + i * 0x100) : 0), + 0, + (CO_TPDOCommPar_t*)&OD_TPDOCommunicationParameter[i], + (CO_TPDOMapPar_t *)&OD_TPDOMappingParameter[i], + OD_H1800_TXPDO_1_PARAM + i, + OD_H1A00_TXPDO_1_MAPPING + i, + CO->CANmodule[0], + CO_TXCAN_TPDO + i); + + if (err) return err; } + /* Heartbeat consumer */ + err = CO_HBconsumer_init(CO->HBcons, + CO->em, + CO->SDO[0], + &OD_consumerHeartbeatTime[0], + CO_HBcons_monitoredNodes, + CO_NO_HB_CONS, + CO->CANmodule[0], + CO_RXCAN_CONS_HB); - err = CO_HBconsumer_init( - CO->HBcons, - CO->em, - CO->SDO[0], - &OD_consumerHeartbeatTime[0], - CO_HBcons_monitoredNodes, - CO_NO_HB_CONS, - CO->CANmodule[0], - CO_RXCAN_CONS_HB); - - if(err){return err;} + if (err) return err; #if CO_NO_SDO_CLIENT != 0 - - for(i=0; iSDOclient[i], - CO->SDO[0], - (CO_SDOclientPar_t*) &OD_SDOClientParameter[i], - CO->CANmodule[0], - CO_RXCAN_SDO_CLI+i, - CO->CANmodule[0], - CO_TXCAN_SDO_CLI+i); - - if(err){return err;} - + /* SDOclient */ + for (i = 0; i < CO_NO_SDO_CLIENT; i++) { + err = CO_SDOclient_init(CO->SDOclient[i], + CO->SDO[0], + (CO_SDOclientPar_t *)&OD_SDOClientParameter[i], + CO->CANmodule[0], + CO_RXCAN_SDO_CLI + i, + CO->CANmodule[0], + CO_TXCAN_SDO_CLI + i); + + if (err) return err; } #endif +#if CO_NO_LSS_CLIENT == 1 + /* LSSmaster */ + err = CO_LSSmaster_init(CO->LSSmaster, + CO_LSSmaster_DEFAULT_TIMEOUT, + CO->CANmodule[0], + CO_RXCAN_LSS, + CO_CAN_ID_LSS_CLI, + CO->CANmodule[0], + CO_TXCAN_LSS, + CO_CAN_ID_LSS_SRV); + + if (err) return err; -#if CO_NO_TRACE > 0 - for(i=0; itrace[i], - CO->SDO[0], - OD_traceConfig[i].axisNo, - CO_traceTimeBuffers[i], - CO_traceValueBuffers[i], - CO_traceBufferSize[i], - &OD_traceConfig[i].map, - &OD_traceConfig[i].format, - &OD_traceConfig[i].trigger, - &OD_traceConfig[i].threshold, - &OD_trace[i].value, - &OD_trace[i].min, - &OD_trace[i].max, - &OD_trace[i].triggerTime, - OD_INDEX_TRACE_CONFIG + i, - OD_INDEX_TRACE + i); - } #endif - return CO_ERROR_NO; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_init( - void *CANptr, - uint8_t nodeId, - uint16_t bitRate) -{ - CO_ReturnError_t err; - - err = CO_new(); - if (err) { - return err; - } - - err = CO_CANinit(CANptr, bitRate); - if (err) { - CO_delete(CANptr); - return err; - } - - err = CO_CANopenInit(nodeId); - if (err) { - CO_delete(CANptr); - return err; +#if CO_NO_TRACE > 0 + /* Trace */ + for (i = 0; i < CO_NO_TRACE; i++) { + CO_trace_init(CO->trace[i], + CO->SDO[0], + OD_traceConfig[i].axisNo, + CO_traceTimeBuffers[i], + CO_traceValueBuffers[i], + CO_traceBufferSize[i], + &OD_traceConfig[i].map, + &OD_traceConfig[i].format, + &OD_traceConfig[i].trigger, + &OD_traceConfig[i].threshold, + &OD_trace[i].value, + &OD_trace[i].min, + &OD_trace[i].max, + &OD_trace[i].triggerTime, + OD_INDEX_TRACE_CONFIG + i, + OD_INDEX_TRACE + i); } - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_delete(void *CANptr){ -#ifndef CO_USE_GLOBALS - int16_t i; #endif - CO_CANsetConfigurationMode(CANptr); - CO_CANmodule_disable(CO->CANmodule[0]); - -#ifndef CO_USE_GLOBALS - #if CO_NO_TRACE > 0 - for(i=0; itrace[i]); - free(CO_traceTimeBuffers[i]); - free(CO_traceValueBuffers[i]); - } - #endif - #if CO_NO_SDO_CLIENT != 0 - for(i=0; iSDOclient[i]); - } - #endif - #if CO_NO_LSS_SERVER == 1 - free(CO->LSSslave); - #endif - #if CO_NO_LSS_CLIENT == 1 - free(CO->LSSmaster); - #endif - free(CO_HBcons_monitoredNodes); - free(CO->HBcons); - for(i=0; iRPDO[i]); - } - for(i=0; iTPDO[i]); - } - #if CO_NO_SYNC == 1 - free(CO->SYNC); - #endif - #if CO_NO_TIME == 1 - free(CO->TIME); - #endif - free(CO->NMT); - free(CO->emPr); - free(CO->em); - free(CO_SDO_ODExtensions); - for(i=0; iSDO[i]); - } - free(CO_CANmodule_txArray0); - free(CO_CANmodule_rxArray0); - free(CO->CANmodule[0]); - CO = NULL; -#endif + return CO_ERROR_NO; } /******************************************************************************/ -CO_NMT_reset_cmd_t CO_process( - CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us) +CO_NMT_reset_cmd_t CO_process(CO_t *co, + uint32_t timeDifference_us, + uint32_t *timerNext_us) { uint8_t i; bool_t NMTisPreOrOperational = false; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; - if(co->NMT->operatingState == CO_NMT_PRE_OPERATIONAL || co->NMT->operatingState == CO_NMT_OPERATIONAL) + if (co->NMT->operatingState == CO_NMT_PRE_OPERATIONAL || + co->NMT->operatingState == CO_NMT_OPERATIONAL) NMTisPreOrOperational = true; - for(i=0; iSDO[i], - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); + /* SDOserver */ + for (i = 0; i < CO_NO_SDO_SERVER; i++) { + CO_SDO_process(co->SDO[i], + NMTisPreOrOperational, + timeDifference_us, + timerNext_us); } - CO_EM_process( - co->emPr, - NMTisPreOrOperational, - timeDifference_us, - OD_inhibitTimeEMCY, - timerNext_us); - + /* Emergency */ + CO_EM_process(co->emPr, + NMTisPreOrOperational, + timeDifference_us, + OD_inhibitTimeEMCY, + timerNext_us); - reset = CO_NMT_process( - co->NMT, - timeDifference_us, - OD_producerHeartbeatTime, - OD_NMTStartup, - OD_errorRegister, - OD_errorBehavior, - timerNext_us); + /* NMT_Heartbeat */ + reset = CO_NMT_process(co->NMT, + timeDifference_us, + OD_producerHeartbeatTime, + OD_NMTStartup, + OD_errorRegister, + OD_errorBehavior, + timerNext_us); - CO_HBconsumer_process( - co->HBcons, - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); #if CO_NO_TIME == 1 - CO_TIME_process( - co->TIME, - timeDifference_us); + /* TIME */ + CO_TIME_process(co->TIME, + timeDifference_us); #endif + /* Heartbeat consumer */ + CO_HBconsumer_process(co->HBcons, + NMTisPreOrOperational, + timeDifference_us, + timerNext_us); + return reset; } /******************************************************************************/ #if CO_NO_SYNC == 1 -bool_t CO_process_SYNC( - CO_t *co, - uint32_t timeDifference_us) +bool_t CO_process_SYNC(CO_t *co, + uint32_t timeDifference_us, + uint32_t *timerNext_us) { bool_t syncWas = false; - - switch(CO_SYNC_process(co->SYNC, timeDifference_us, OD_synchronousWindowLength, NULL)){ - case 1: //immediately after the SYNC message - syncWas = true; - break; - case 2: //outside SYNC window - CO_CANclearPendingSyncPDOs(co->CANmodule[0]); - break; + uint8_t sync_process = CO_SYNC_process(co->SYNC, + timeDifference_us, + OD_synchronousWindowLength, + timerNext_us); + + switch (sync_process) { + case 1: // immediately after the SYNC message + syncWas = true; + break; + case 2: // outside SYNC window + CO_CANclearPendingSyncPDOs(co->CANmodule[0]); + break; } return syncWas; } -#endif +#endif /* CO_NO_SYNC == 1 */ + /******************************************************************************/ -void CO_process_RPDO( - CO_t *co, - bool_t syncWas) +void CO_process_RPDO(CO_t *co, + bool_t syncWas) { int16_t i; - for(i=0; iRPDO[i], syncWas); } } /******************************************************************************/ -void CO_process_TPDO( - CO_t *co, - bool_t syncWas, - uint32_t timeDifference_us) +void CO_process_TPDO(CO_t *co, + bool_t syncWas, + uint32_t timeDifference_us, + uint32_t *timerNext_us) { int16_t i; /* Verify PDO Change Of State and process PDOs */ - for(i=0; iTPDO[i]->sendRequest) + for (i = 0; i < CO_NO_TPDO; i++) { + if (!co->TPDO[i]->sendRequest) co->TPDO[i]->sendRequest = CO_TPDOisCOS(co->TPDO[i]); - CO_TPDO_process(co->TPDO[i], syncWas, timeDifference_us, NULL); - } -} - - -/******************************************************************************/ -#if CO_NO_SYNC == 1 -bool_t CO_process_SYNC_PDO( - CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ - int16_t i; - bool_t syncWas = false; - - switch(CO_SYNC_process(co->SYNC, timeDifference_us, OD_synchronousWindowLength, timerNext_us)){ - case 1: //immediately after the SYNC message - syncWas = true; - break; - case 2: //outside SYNC window - CO_CANclearPendingSyncPDOs(co->CANmodule[0]); - break; - } - - /* Process RPDOs */ - for(i=0; iRPDO[i], syncWas); - } - - /* Verify PDO Change Of State and process TPDOs */ - for(i=0; iTPDO[i]->sendRequest) co->TPDO[i]->sendRequest = CO_TPDOisCOS(co->TPDO[i]); CO_TPDO_process(co->TPDO[i], syncWas, timeDifference_us, timerNext_us); } - - return syncWas; } -#endif diff --git a/CANopen.h b/CANopen.h index 7696773a..3b76094b 100644 --- a/CANopen.h +++ b/CANopen.h @@ -115,78 +115,120 @@ extern "C" { #if CO_NO_SDO_CLIENT != 0 #include "301/CO_SDOclient.h" #endif -#if CO_NO_TRACE > 0 - #include "extra/CO_trace.h" -#endif -#if CO_NO_LSS_SERVER == 1 +#if CO_NO_LSS_SLAVE != 0 #include "305/CO_LSSslave.h" #endif -#if CO_NO_LSS_CLIENT == 1 +#if CO_NO_LSS_MASTER != 0 #include "305/CO_LSSmaster.h" +#endif +#if CO_NO_TRACE != 0 + #include "extra/CO_trace.h" #endif #include "CO_OD.h" + +#ifdef CO_DOXYGEN /** - * CANopen object combines pointers to all CANopen objects. + * @defgroup CO_NO_OBJ Number of CANopenNode communication objects. + * + * Definitions specify, which and how many CANopenNode communication objects + * will be used in current configuration. Usage of some objects is mandatory and + * is fixed. Others are defined in CO_OD.h. + * @{ */ -typedef struct{ - CO_CANmodule_t *CANmodule[1]; /**< CAN module objects */ - CO_SDO_t *SDO[CO_NO_SDO_SERVER]; /**< SDO object */ - CO_EM_t *em; /**< Emergency report object */ - CO_EMpr_t *emPr; /**< Emergency process object */ - CO_NMT_t *NMT; /**< NMT object */ - CO_SYNC_t *SYNC; /**< SYNC object */ - CO_TIME_t *TIME; /**< TIME object */ - CO_RPDO_t *RPDO[CO_NO_RPDO];/**< RPDO objects */ - CO_TPDO_t *TPDO[CO_NO_TPDO];/**< TPDO objects */ - CO_HBconsumer_t *HBcons; /**< Heartbeat consumer object*/ +/* Definitions valid only for documentation. */ +/** Number of NMT objects, fixed to 1 (slave(CANrx) + master(CANtx)) */ +#define CO_NO_NMT (1) +/** Number of SYNC objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ +#define CO_NO_SYNC (0...1) +/** Number of Emergency objects, fixed to 1 (consumer(CANrx) + + * producer(CANtx)) */ +#define CO_NO_EMERGENCY (1) +/** Number of Time-stamp objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ +#define CO_NO_TIME (0...1) +/** Number of RPDO objects, 1 to 512 consumers (CANrx) */ +#define CO_NO_RPDO (1...512) +/** Number of TPDO objects, 1 to 512 producers (CANtx) */ +#define CO_NO_TPDO (1...512) +/** Number of SDO server objects, from 1 to 128 (CANrx + CANtx) */ +#define CO_NO_SDO_SERVER (1...128) +/** Number of SDO client objects, from 0 to 128 (CANrx + CANtx) */ +#define CO_NO_SDO_CLIENT (0...128) +/** Number of HB producer objects, fixed to 1 producer(CANtx) */ +#define CO_NO_HB_PROD (1) +/** Number of HB consumer objects, from 0 to 127 consumers(CANrx) */ +#define CO_NO_HB_CONS (0...127) +/** Number of LSS slave objects, 0 or 1 (CANrx + CANtx) */ +#define CO_NO_LSS_SLAVE (0...1) +/** Number of LSS master objects, 0 or 1 (CANrx + CANtx) */ +#define CO_NO_LSS_MASTER) (0...1) +/** Number of Trace objects, 0 to many */ +#define CO_NO_TRACE) (0...) +/** @} */ +#else /* CO_DOXYGEN */ + +/* Valid Definitions for program. */ +#define CO_NO_NMT 1 /* NMT master/slave count (fixed) */ +#define CO_NO_HB_PROD 1 /* Heartbeat producer count (fixed) */ +#ifdef ODL_consumerHeartbeatTime_arrayLength + #define CO_NO_HB_CONS ODL_consumerHeartbeatTime_arrayLength +#else + #define CO_NO_HB_CONS 0 +#endif +#endif /* CO_DOXYGEN */ + + +/** + * CANopen object with pointers to all CANopenNode objects. + */ +typedef struct { + CO_CANmodule_t *CANmodule[1]; /**< CAN module objects */ + CO_SDO_t *SDO[CO_NO_SDO_SERVER]; /**< SDO object */ + CO_EM_t *em; /**< Emergency report object */ + CO_EMpr_t *emPr; /**< Emergency process object */ + CO_NMT_t *NMT; /**< NMT object */ + CO_SYNC_t *SYNC; /**< SYNC object */ + CO_TIME_t *TIME; /**< TIME object */ + CO_RPDO_t *RPDO[CO_NO_RPDO]; /**< RPDO objects */ + CO_TPDO_t *TPDO[CO_NO_TPDO]; /**< TPDO objects */ + CO_HBconsumer_t *HBcons; /**< Heartbeat consumer object*/ +#if CO_NO_SDO_CLIENT != 0 + CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */ +#endif #if CO_NO_LSS_SERVER == 1 - CO_LSSslave_t *LSSslave; /**< LSS server/slave object */ + CO_LSSslave_t *LSSslave; /**< LSS slave object */ #endif #if CO_NO_LSS_CLIENT == 1 - CO_LSSmaster_t *LSSmaster; /**< LSS master/client object */ -#endif -#if CO_NO_SDO_CLIENT != 0 - CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */ + CO_LSSmaster_t *LSSmaster; /**< LSS master object */ #endif #if CO_NO_TRACE > 0 - CO_trace_t *trace[CO_NO_TRACE]; /**< Trace object for monitoring variables */ + CO_trace_t *trace[CO_NO_TRACE]; /**< Trace object for recording variables */ #endif -}CO_t; +} CO_t; /** CANopen object */ - extern CO_t *CO; +extern CO_t *CO; /** - * Function CO_sendNMTcommand() is simple function, which sends CANopen message. - * This part of code is an example of custom definition of simple CANopen - * object. Follow the code in CANopen.c file. If macro CO_NO_NMT_MASTER is 1, - * function CO_sendNMTcommand can be used to send NMT master message. + * Allocate and initialize memory for CANopen object * - * @param co CANopen object. - * @param command NMT command. - * @param nodeID Node ID. + * Function must be called the first time, after program starts. * - * @return 0: Operation completed successfully. - * @return other: same as CO_CANsend(). + * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, + * CO_ERROR_OUT_OF_MEMORY */ -#if CO_NO_NMT_MASTER == 1 - CO_ReturnError_t CO_sendNMTcommand(CO_t *co, uint8_t command, uint8_t nodeID); -#endif +CO_ReturnError_t CO_new(void); -#if CO_NO_LSS_SERVER == 1 /** - * Allocate and initialize memory for CANopen object - * - * Function must be called in the communication reset section. + * Delete CANopen object and free memory. Must be called at program exit. * - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, - * CO_ERROR_OUT_OF_MEMORY + * @param CANptr Pointer to the user-defined CAN base structure, passed to + * CO_CANmodule_init(). */ -CO_ReturnError_t CO_new(void); +void CO_delete(void *CANptr); /** @@ -194,28 +236,30 @@ CO_ReturnError_t CO_new(void); * * Function must be called in the communication reset section. * - * @param CANptr Pointer to the CAN module, passed to CO_CANmodule_init(). + * @param CANptr Pointer to the user-defined CAN base structure, passed to + * CO_CANmodule_init(). * @param bitRate CAN bit rate. * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, * CO_ERROR_ILLEGAL_BAUDRATE, CO_ERROR_OUT_OF_MEMORY */ -CO_ReturnError_t CO_CANinit( - void *CANptr, - uint16_t bitRate); +CO_ReturnError_t CO_CANinit(void *CANptr, + uint16_t bitRate); +#if CO_NO_LSS_SERVER == 1 /** * Initialize CANopen LSS slave * * Function must be called in the communication reset section. * - * @param nodeId Node ID of the CANopen device (1 ... 127) or CO_LSS_NODE_ID_ASSIGNMENT + * @param nodeId Node ID of the CANopen device (1 ... 127) or + * CO_LSS_NODE_ID_ASSIGNMENT * @param bitRate CAN bit rate. * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT */ -CO_ReturnError_t CO_LSSinit( - uint8_t nodeId, - uint16_t bitRate); +CO_ReturnError_t CO_LSSinit(uint8_t nodeId, + uint16_t bitRate); +#endif /* CO_NO_LSS_SERVER == 1 */ /** @@ -226,37 +270,7 @@ CO_ReturnError_t CO_LSSinit( * @param nodeId Node ID of the CANopen device (1 ... 127). * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT */ -CO_ReturnError_t CO_CANopenInit( - uint8_t nodeId); - - -#else /* CO_NO_LSS_SERVER == 1 */ -/** - * Initialize CANopenNode. - * - * Function must be called in the communication reset section. - * - * @param CANptr Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). - * @param nodeId Node ID of the CANopen device (1 ... 127). - * @param bitRate CAN bit rate. - * - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, - * CO_ERROR_OUT_OF_MEMORY, CO_ERROR_ILLEGAL_BAUDRATE - */ -CO_ReturnError_t CO_init( - void *CANptr, - uint8_t nodeId, - uint16_t bitRate); - -#endif /* CO_NO_LSS_SERVER == 1 */ - - -/** - * Delete CANopen object and free memory. Must be called at program exit. - * - * @param CANptr Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). - */ -void CO_delete(void *CANptr); +CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); /** @@ -266,7 +280,8 @@ void CO_delete(void *CANptr); * objects. * * @param co CANopen object. - * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timeDifference_us Time difference from previous function call in + * microseconds. * @param timerNext_us [out] info to OS - maximum delay after function * should be called next time in [microseconds]. Value can be used for OS * sleep time. Initial value must be set to something, 50000us typically. @@ -276,10 +291,9 @@ void CO_delete(void *CANptr); * * @return #CO_NMT_reset_cmd_t from CO_NMT_process(). */ -CO_NMT_reset_cmd_t CO_process( - CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +CO_NMT_reset_cmd_t CO_process(CO_t *co, + uint32_t timeDifference_us, + uint32_t *timerNext_us); #if CO_NO_SYNC == 1 @@ -290,15 +304,18 @@ CO_NMT_reset_cmd_t CO_process( * interval (1ms typically). It processes SYNC CANopen objects. * * @param co CANopen object. - * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timeDifference_us Time difference from previous function call in + * microseconds. + * @param timerNext_us [out] info to OS - see CO_process(). * * @return True, if CANopen SYNC message was just received or transmitted. */ -bool_t CO_process_SYNC( - CO_t *co, - uint32_t timeDifference_us); +bool_t CO_process_SYNC(CO_t *co, + uint32_t timeDifference_us, + uint32_t *timerNext_us); #endif + /** * Process CANopen RPDO objects. * @@ -306,11 +323,11 @@ bool_t CO_process_SYNC( * interval (1ms typically). It processes receive PDO CANopen objects. * * @param co CANopen object. - * @param syncWas True, if CANopen SYNC message was just received or transmitted. + * @param syncWas True, if CANopen SYNC message was just received or + * transmitted. */ -void CO_process_RPDO( - CO_t *co, - bool_t syncWas); +void CO_process_RPDO(CO_t *co, bool_t syncWas); + /** * Process CANopen TPDO objects. @@ -319,42 +336,22 @@ void CO_process_RPDO( * interval (1ms typically). It processes transmit PDO CANopen objects. * * @param co CANopen object. - * @param syncWas True, if CANopen SYNC message was just received or transmitted. - * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param syncWas True, if CANopen SYNC message was just received or + * transmitted. + * @param timeDifference_us Time difference from previous function call in + * microseconds. + * @param timerNext_us [out] info to OS - see CO_process(). */ -void CO_process_TPDO( - CO_t *co, - bool_t syncWas, - uint32_t timeDifference_us); +void CO_process_TPDO(CO_t *co, + bool_t syncWas, + uint32_t timeDifference_us, + uint32_t *timerNext_us); -#if CO_NO_SYNC == 1 -/** - * Process CANopen SYNC and PDO objects. - * - * Function must be called cyclically from real time thread with constant. - * interval (1ms typically). It processes SYNC and PDO CANopen objects. - * - * @param co This object. - * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param timerNext_us [out] info to OS - maximum delay after function - * should be called next time in [microseconds]. Value can be used for OS - * sleep time. Initial value must be set to something, 1000us typically. - * Output will be equal or lower to initial value. If there is new object - * to process, delay should be suspended and this function should be - * called immediately. Parameter is ignored if NULL. - * - * @return True, if CANopen SYNC message was just received or transmitted. - */ -bool_t CO_process_SYNC_PDO( - CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us); -#endif +/** @} */ #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ -/** @} */ #endif /* CANopen_H */ diff --git a/README.md b/README.md index c97195d6..fdaabff6 100644 --- a/README.md +++ b/README.md @@ -230,10 +230,9 @@ Change Log - [Unreleased split-driver](https://github.com/CANopenNode/CANopenNode/tree/split-driver): [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/master...split-driver) - All drivers removed from this project, except Neuberger-socketCAN for Linux. - Driver interface clarified, common CO_driver.h, specific CO_driver_target.h. - - Directory structure rearranged. - - Time base is now microsecond in all functions. - - All CANopen objects calculates next timer info for OS. - - Heartbeat consumer optimized and fixed. + - Directory structure rearranged. Change of the project files will be necessary. + - Time base is now microsecond in all functions. All CANopen objects calculates next timer info for OS. CANopen.h/.c files revised. Compare the example/main.c file to view some differences in interface. + - Heartbeat consumer optimized and fixed. CO_NMT_sendCommand() master function moved from CANopen.c into CO_NMT_Heartbeat.c. - Basic Linux socketCAN example. - [Unreleased master](https://github.com/CANopenNode/CANopenNode): [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...master) - License changed to Apache 2.0. diff --git a/example/main.c b/example/main.c index ca5d697a..10f1be47 100644 --- a/example/main.c +++ b/example/main.c @@ -32,7 +32,7 @@ #define INCREMENT_1MS(var) (var++) /* Increment 1ms variable in tmrTask */ /** - * User-defined CAN base structure, passed as argument to CO_init. + * User-defined CAN base structure, passed as argument to CO_CANinit. */ struct CANbase { uintptr_t baseAddress; /**< Base address of the CAN module */ @@ -44,11 +44,18 @@ struct CANbase { /* main ***********************************************************************/ int main (void){ + CO_ReturnError_t err; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; /* Configure microcontroller. */ + /* Allocate memory */ + err = CO_new(); + if (err != CO_ERROR_NO) { + while(1); + } + /* initialize EEPROM */ @@ -58,7 +65,6 @@ int main (void){ while(reset != CO_RESET_APP){ /* CANopen communication reset - initialize CANopen objects *******************/ - CO_ReturnError_t err; uint16_t timer1msPrevious; /* disable CAN and CAN interrupts */ @@ -67,13 +73,15 @@ int main (void){ }; /* initialize CANopen */ - err = CO_init(&canBase, 10/* NodeID */, 125 /* bit rate */); + err = CO_CANinit(&canBase, 125 /* bit rate */); + if (err == CO_ERROR_NO) { + err = CO_CANopenInit(10/* NodeID */); + } if(err != CO_ERROR_NO){ while(1); /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */ } - /* Configure Timer interrupt function for execution every 1 millisecond */ @@ -96,7 +104,7 @@ int main (void){ /* CANopen process */ - reset = CO_process(CO, timer1msDiff, NULL); + reset = CO_process(CO, timer1msDiff*1000, NULL); /* Nonblocking application code may go here. */ @@ -131,7 +139,7 @@ void tmrTask_thread(void){ bool_t syncWas; /* Process Sync */ - syncWas = CO_process_SYNC(CO, TMR_TASK_INTERVAL); + syncWas = CO_process_SYNC(CO, TMR_TASK_INTERVAL, NULL); /* Read inputs */ CO_process_RPDO(CO, syncWas); @@ -139,7 +147,7 @@ void tmrTask_thread(void){ /* Further I/O or nonblocking application code may go here. */ /* Write outputs */ - CO_process_TPDO(CO, syncWas, TMR_TASK_INTERVAL); + CO_process_TPDO(CO, syncWas, TMR_TASK_INTERVAL, NULL); /* verify timer overflow */ if(0) { From 9c0b16f981bb36c0c1995178e0599de404706c37 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 6 Feb 2020 02:26:59 +0100 Subject: [PATCH 019/520] minor corrections --- CANopen.c | 2 +- CANopen.h | 2 +- README.md | 16 +++++++--------- example/main.c | 2 +- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/CANopen.c b/CANopen.c index 5761035d..e2a3f25f 100644 --- a/CANopen.c +++ b/CANopen.c @@ -269,7 +269,7 @@ void CO_delete(void *CANptr) { CO_CANsetConfigurationMode(CANptr); - /* If CANopen was initialized before, return. */ + /* If CANopen isn't initialized, return. */ if (CO == NULL) { return; } diff --git a/CANopen.h b/CANopen.h index 3b76094b..d5bf0c3a 100644 --- a/CANopen.h +++ b/CANopen.h @@ -313,7 +313,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, bool_t CO_process_SYNC(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us); -#endif +#endif /* CO_NO_SYNC == 1 */ /** diff --git a/README.md b/README.md index fdaabff6..cfff9f90 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,8 @@ then NMT operational state is not allowed. Usage of the CANopenNode ------------------------ CANopenNode itself doesn't have complete working code for any microcontroller. -It is only the library with the stack It has example, which should compile -on any system with template driver (drvTemplate), which actually doesn't +It is only the library with the stack. It has example, which should compile +on any system with blank template driver, which actually doesn't access CAN hardware. CANopenNode should be used as a git submodule included in a project with specific hardware and specific application. @@ -64,7 +64,7 @@ Documentation, support and contributions ---------------------------------------- Code is documented in header files. Running [doxygen](http://www.doxygen.nl/) or `make doc` in project base folder will produce complete html documentation. -Just open CANopenNode/doc/html/index.html in browser. +Just open CANopenNode/doc/html/index.html in the browser. Report issues on https://github.com/CANopenNode/CANopenNode/issues @@ -137,8 +137,6 @@ Flowchart of a typical CANopenNode implementation | - Can request node | | enumeration | ----------------------- - - ~~~ @@ -202,10 +200,10 @@ external application. There are two: Device support -------------- -CANopenNode can be implemented on many different devices. It is -necessary to implement interface to specific hardware, so called 'driver'. -Currently driver files are part of CANopenNode, but they will be split from -it in the future. +CANopenNode can be implemented on many different devices. It is necessary +to implement interface to specific hardware. Interface to Linux socketCAN is +part of this projects, while interfaces to other controllers are separate +projects. There are interfaces to: Zephyr RTOS, PIC, Mbed-os RTOS + STM32, etc. Most up to date information on device support can be found on [CANopenNode/wiki](https://github.com/CANopenNode/CANopenNode/wiki). diff --git a/example/main.c b/example/main.c index 10f1be47..ee1e4a56 100644 --- a/example/main.c +++ b/example/main.c @@ -104,7 +104,7 @@ int main (void){ /* CANopen process */ - reset = CO_process(CO, timer1msDiff*1000, NULL); + reset = CO_process(CO, (uint32_t)timer1msDiff*1000, NULL); /* Nonblocking application code may go here. */ From e55674bf6f34903192f7d4236d5d1c5242384ba2 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 12 Feb 2020 17:27:58 +0100 Subject: [PATCH 020/520] Documentation updated, ChangeLog deviceSupport and gettingStarted added. CANopen.h fixed. --- .gitignore | 2 +- 301/CO_TIME.h | 5 +- CANopen.h | 8 +- Doxyfile | 1 + README.md | 112 ++++++++--------------- doc/CHANGELOG.md | 83 +++++++++++++++++ doc/LSSusage.md | 88 ++++++++++++++++++ doc/deviceSupport.md | 94 +++++++++++++++++++ doc/gettingStarted.md | 208 ++++++++++++++++++++++++++++++++++++++++++ doc/index.html | 1 + doc/traceUsage.md | 42 +++++++++ 11 files changed, 561 insertions(+), 83 deletions(-) create mode 100644 doc/CHANGELOG.md create mode 100644 doc/LSSusage.md create mode 100644 doc/deviceSupport.md create mode 100644 doc/gettingStarted.md create mode 120000 doc/index.html create mode 100644 doc/traceUsage.md diff --git a/.gitignore b/.gitignore index adacc76c..ec369297 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ canopennode *.o -doc/ +doc/html/ #eclipse .cproject diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 7b789053..dda323a8 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -1,7 +1,7 @@ /** * CANopen Time-stamp protocol. * - * @file CO_TIME.c + * @file CO_TIME.h * @ingroup CO_TIME * @author Julien PEYREGNE * @copyright 2019 - 2020 Janez Paternoster @@ -152,9 +152,10 @@ uint8_t CO_TIME_process( CO_TIME_t *TIME, uint32_t timeDifference_us); +/** @} */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ #endif diff --git a/CANopen.h b/CANopen.h index d5bf0c3a..765c7dbb 100644 --- a/CANopen.h +++ b/CANopen.h @@ -115,10 +115,10 @@ extern "C" { #if CO_NO_SDO_CLIENT != 0 #include "301/CO_SDOclient.h" #endif -#if CO_NO_LSS_SLAVE != 0 +#if CO_NO_LSS_SERVER != 0 #include "305/CO_LSSslave.h" #endif -#if CO_NO_LSS_MASTER != 0 +#if CO_NO_LSS_CLIENT != 0 #include "305/CO_LSSmaster.h" #endif #if CO_NO_TRACE != 0 @@ -161,9 +161,9 @@ extern "C" { /** Number of LSS slave objects, 0 or 1 (CANrx + CANtx) */ #define CO_NO_LSS_SLAVE (0...1) /** Number of LSS master objects, 0 or 1 (CANrx + CANtx) */ -#define CO_NO_LSS_MASTER) (0...1) +#define CO_NO_LSS_MASTER (0...1) /** Number of Trace objects, 0 to many */ -#define CO_NO_TRACE) (0...) +#define CO_NO_TRACE (0...) /** @} */ #else /* CO_DOXYGEN */ diff --git a/Doxyfile b/Doxyfile index 1ab67ed2..6a86b043 100644 --- a/Doxyfile +++ b/Doxyfile @@ -781,6 +781,7 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = README.md \ + doc \ CANopen.h \ 301 \ 305 \ diff --git a/README.md b/README.md index cfff9f90..d87d8332 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ CANopenNode =========== -CANopenNode is free and open source CANopen Stack. +CANopenNode is free and open source CANopen protocol stack. CANopen is the internationally standardized (EN 50325-4) ([CiA301](http://can-cia.org/standardization/technical-documents)) @@ -10,12 +10,10 @@ information on CANopen see http://www.can-cia.org/ CANopenNode is written in ANSI C in object-oriented way. It runs on different microcontrollers, as standalone application or with RTOS. -Stack includes master functionalities. For Linux implementation with -CANopen master functionalities see -https://github.com/CANopenNode/CANopenSocket. +Linux implementation with CANopen master functionalities is included. Variables (communication, device, custom) are ordered in CANopen Object -Dictionary and are accessible from both: C code and from CAN network. +Dictionary and are accessible from both: C code and from CANopen network. CANopenNode homepage is https://github.com/CANopenNode/CANopenNode @@ -51,19 +49,13 @@ receive Process Data Objects (PDO). If Error Register (object 0x1001) is set, then NMT operational state is not allowed. -Usage of the CANopenNode ------------------------- -CANopenNode itself doesn't have complete working code for any microcontroller. -It is only the library with the stack. It has example, which should compile -on any system with blank template driver, which actually doesn't -access CAN hardware. CANopenNode should be used as a git submodule included -in a project with specific hardware and specific application. - - Documentation, support and contributions ---------------------------------------- +Documentation with [Getting started](doc/gettingStarted.md), +[LSS usage](doc/LSSusage.md) and [Trace usage](doc/traceUsage.md) is in `doc` +directory. Code is documented in header files. Running [doxygen](http://www.doxygen.nl/) -or `make doc` in project base folder will produce complete html documentation. +or `make doc` in project base directory will produce complete html documentation. Just open CANopenNode/doc/html/index.html in the browser. Report issues on https://github.com/CANopenNode/CANopenNode/issues @@ -71,16 +63,11 @@ Report issues on https://github.com/CANopenNode/CANopenNode/issues Older and still active discussion group is on Sourceforge http://sourceforge.net/p/canopennode/discussion/387151/ -For some implementations of CANopenNode on real hardware see -[Device support](#device-support) section. -[CANopenSocket](https://github.com/CANopenNode/CANopenSocket) is nice -implementation for Linux devices. It includes command line interface for -master access of the CANopen network. There is also some Getting started. - Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Some basic formatting rules should be followed: Linux style with indentation of 4 spaces. There -is also a configuration file for `clang-format` tool. +is also a `codingStyle` file with example and a configuration file for +`clang-format` tool. Flowchart of a typical CANopenNode implementation @@ -110,9 +97,9 @@ Flowchart of a typical CANopenNode implementation | data to target | | - Copy inputs (RPDOs, | | - Emergency, | | CANopen objects. | | HW) to Object Dict. | | - Network state, | | | | - May call application| | - Heartbeat. | -| | | for some processing.| | - May cyclically call | -| | | - Copy variables from | | application code. | -| | | Object Dictionary to| | | +| | | for some processing.| | - LSS slave | +| | | - Copy variables from | | - May cyclically call | +| | | Object Dictionary to| | application code. | | | | outputs (TPDOs, HW).| | | ----------------------- ----------------------- ----------------------- @@ -129,7 +116,7 @@ Flowchart of a typical CANopenNode implementation ----------------------- ----------------------- - | LSS client (optional) | + | LSS Master (optional) | | | | - Can be called by | | external application| @@ -175,6 +162,12 @@ File structure - **CO_Linux_threads.h/.c** - Helper functions for implementing CANopen threads in Linux. - **CO_notify_pipe.h/.c** - Notify pipe for Linux threads. - **CO_OD_storage.h/.c** - Object Dictionary storage object for Linux SocketCAN. + - **doc/** - Directory with documentation + - **CHANGELOG.md** - Change Log file. + - **deviceSupport.md** - Information about supported devices. + - **gettingStarted.md, LSSusage.md, traceUsage.md** - Getting started and usage. + - **index.html** - Soft link to html/index.html. + - **html** - Directory with documentation - must be generated by Doxygen. - **CANopen.h/.c** - Initialization and processing of CANopen objects. - **codingStyle** - Example of the coding style. - **.clang-format** - Definition file for the coding style. @@ -184,69 +177,36 @@ File structure - **README.md** - This file. -### Object dictionary editor +Object dictionary editor +------------------------ Object Dictionary is one of the most important parts of CANopen. Its implementation in CANopenNode is quite outdated and there are efforts to rewrite it. Anyway, currently it is fully operational and works well. -To customize the Object Dictionary it is necessary to use the -external application. There are two: - - [libedssharp](https://github.com/robincornelius/libedssharp) - - recommended, can be used with mono. - - [Object_Dictionary_Editor](http://sourceforge.net/p/canopennode/code_complete/) - - originally part of CANopenNode. It is still operational, but requiers - very old version of Firefox to run. +To customize the Object Dictionary it is necessary to use external application: +[libedssharp](https://github.com/robincornelius/libedssharp). It can be used in +Windows or Linux with Mono. + +Please note: since rearrangement in directory structure it is necessary to +manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and +`301/CO_SDOserver.h`. Device support -------------- -CANopenNode can be implemented on many different devices. It is necessary -to implement interface to specific hardware. Interface to Linux socketCAN is -part of this projects, while interfaces to other controllers are separate -projects. There are interfaces to: Zephyr RTOS, PIC, Mbed-os RTOS + STM32, etc. - -Most up to date information on device support can be found on -[CANopenNode/wiki](https://github.com/CANopenNode/CANopenNode/wiki). - +CANopenNode can run on many different devices. Each device (or microcontroller) +must have own interface to CANopenNode. CANopenNode can run with or without +operating system. -### Note for contributors -For the driver developers, who wish to share and cooperate, I recommend the following approach: -1. Make own git repo for the Device specific demo project on the Github or somewhere. -2. Add https://github.com/CANopenNode/CANopenNode into your project (or at side of your project). - For example, include it in your project as a git submodule: - `git submodule add https://github.com/CANopenNode/CANopenNode` -3. Add specific driver and other files. -4. **Add a note** about your specific implementation here on - [CANopenNode/wiki](https://github.com/CANopenNode/CANopenNode/wiki) with some - basic description and status. Write a note, even it has an Alpha status. -5. Make a demo folder, which contains project files, etc., necessary to run the demo. -6. Write a good README.md file, where you describe your project, specify demo board, tools used, etc. +It is not practical to have all device interfaces in a single project. For that +reason CANopenNode project only includes interface to Linux socketCAN. +Interfaces to other microcontrollers are in separate projects. See +[deviceSupport.md](doc/deviceSupport.md) for list of known device interfaces. Change Log ---------- -- [Unreleased split-driver](https://github.com/CANopenNode/CANopenNode/tree/split-driver): [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/master...split-driver) - - All drivers removed from this project, except Neuberger-socketCAN for Linux. - - Driver interface clarified, common CO_driver.h, specific CO_driver_target.h. - - Directory structure rearranged. Change of the project files will be necessary. - - Time base is now microsecond in all functions. All CANopen objects calculates next timer info for OS. CANopen.h/.c files revised. Compare the example/main.c file to view some differences in interface. - - Heartbeat consumer optimized and fixed. CO_NMT_sendCommand() master function moved from CANopen.c into CO_NMT_Heartbeat.c. - - Basic Linux socketCAN example. -- [Unreleased master](https://github.com/CANopenNode/CANopenNode): [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...master) - - License changed to Apache 2.0. - - CANopen TIME protocol added. - - Various fixes. -- **[v1.2](https://github.com/CANopenNode/CANopenNode/tree/v1.2)** - 2019-10-08: [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v1.1...v1.2) - - CANopen LSS master/slave protocol added for configuration for bitrate and node ID. - - Memory barrier implemented for setting/clearing flags for CAN received message. - - Neuberger-socketCAN driver added. - - Emergency consumer added with callbacks. Emergency revised. - - Heartbeat consumer revised, callbacks added. -- **[v1.1](https://github.com/CANopenNode/CANopenNode/tree/v1.1)** - 2019-10-08: Bugfixes. [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v1.0...v1.1) -- **[v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0)** - 2017-08-01: Stable. [Full Changelog](https://github.com/CANopenNode/CANopenNode/compare/v0.5...v1.0) -- **[v0.5](https://github.com/CANopenNode/CANopenNode/tree/v0.5)** - 2015-10-20: Git repository started on GitHub. -- **[v0.4](https://sourceforge.net/p/canopennode/code_complete/ci/master/tree/)** - 2012-02-26: Git repository started on Sourceforge. -- **[v0.1](https://sourceforge.net/projects/canopennode/files/canopennode/CANopenNode-0.80/)** - 2004-06-29: First edition of CANopenNode on SourceForge. +See [CHANGELOG.md](doc/CHANGELOG.md) License diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md new file mode 100644 index 00000000..637412a0 --- /dev/null +++ b/doc/CHANGELOG.md @@ -0,0 +1,83 @@ +Change Log +========== + +[Unreleased split-driver] +------------------------- +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/master...split-driver) +- See {TODO diff} for example of change in user application interface. +### Removed +- All drivers removed from this project, except Neuberger-socketCAN for Linux. +### Changed +- Directory structure rearranged. Before was all CANopen object files in `stack` directory, now they are in separate directories according to standard (`301`, `305`, `extra`, `socketCAN` for Linux driver). Include directives for that files now contain directory path. `CO_SDO` renamed to `CO_SDOserver` and `CO_SDOmaster` renamed to `CO_SDOclient`. Change of the project files will be necessary. +- Driver interface clarified. Before was pair of CO_driver.h/.c files for each microcontroller, now there is common CO_driver.h file. Drivers for other microcontrollers will be separate projects. Each driver must have own CO_driver_target.h file and function definitions from C_driver.h file. See documentation in CO_driver.h, example/CO_driver_target.h and example/CO_driver.c. There was no other mayor changes in driver interface. +- Time base is now microsecond in all functions. +- CANopen.h/.c files simplified and changed. `CO_USE_GLOBALS` and `CO_init()` removed. Interface to those functions changed. +- `CO_NMT_sendCommand()` master function renamed and moved from CANopen.c into CO_NMT_Heartbeat.c. +- Heartbeat consumer `CO_HBconsumer_process()` optimized. +- Rename in CO_driver_target.h: `IS_CANrxNew` -> `CO_FLAG_READ`, `SET_CANrxNew` -> `CO_FLAG_SET`, `CLEAR_CANrxNew` -> `CO_FLAG_CLEAR` +- CO_driver.h file, function `CO_CANrxBufferInit()`, last argument (callback) changed from `(*pFunct)(void *object, const CO_CANrxMsg_t *message)` to `void (*CANrx_callback)(void *object, void *message)`. New functions are defined in `CO_driver_target.h` file: `CO_CANrxMsg_readIdent()`, `CO_CANrxMsg_readDLC()` and `CO_CANrxMsg_readData()`. +- It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. +### Fixed +- Bugfix in `CO_HBconsumer_process()`: argument `timeDifference_us` was set to 0 inside for loop, fixed now. +### Added +- Documentation added to `doc` directory: CHANGELOG.md, deviceSupport.md, gettingStarted.md, LSSusage.md and traceUsage.md. +- All CANopen objects calculates next timer info for OS. +- Basic Linux socketCAN example. + +[Unreleased master] +------------------- +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...master) +### Changed +- License changed to Apache 2.0. +- NMT self start functionality (OD object 1F80) implemented to strictly folow standard. Default value for object 1F80 have to be updated in OD editor. See README.md. +### Fixed +- Various fixes. +### Added +- CANopen TIME protocol added. + +[v1.2] - 2019-10-08 +------------------- +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.1...v1.2) +### Fixed +- Memory barrier implemented for setting/clearing flags for CAN received message. +- CO_Emergency and CO_HBconsumer files revised. +### Added +- CANopen LSS master/slave protocol added for configuration of bitrate and node ID. +- Neuberger-socketCAN driver added. +- Emergency consumer added. +- Callbacks added to Emergency and Heartbeat consumer. + +[v1.1] - 2019-10-08 +------------------- +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.0...v1.1) +- Bugfixes. Some non-critical warnings in stack, some formatting warnings in tracing stuff. + +[v1.0] - 2017-08-01 +------------------- +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v0.5...v1.0) +- Stable. + +[v0.5] - 2015-10-20 +------------------- +- Git repository started on GitHub. + +[v0.4] - 2012-02-26 +------------------- +- Git repository started on Sourceforge git. + +[v0.1] - 2004-06-29 +------------------- +- First edition of CANopenNode on SourceForge, files section. (V0.80 on SourceForge). + +------ + +Changelog written according to recomendations from https://keepachangelog.com/ + +[Unreleased split-driver]: https://github.com/CANopenNode/CANopenNode/tree/split-driver +[Unreleased master]: https://github.com/CANopenNode/CANopenNode +[v1.2]: https://github.com/CANopenNode/CANopenNode/tree/v1.2 +[v1.1]: https://github.com/CANopenNode/CANopenNode/tree/v1.1 +[v1.0]: https://github.com/CANopenNode/CANopenNode/tree/v1.0 +[v0.5]: https://github.com/CANopenNode/CANopenNode/tree/v0.5 +[v0.4]: https://sourceforge.net/p/canopennode/code_complete/ci/master/tree/ +[v0.1]: https://sourceforge.net/projects/canopennode/files/canopennode/CANopenNode-0.80/ diff --git a/doc/LSSusage.md b/doc/LSSusage.md new file mode 100644 index 00000000..b7046b6f --- /dev/null +++ b/doc/LSSusage.md @@ -0,0 +1,88 @@ +LSS usage +========= + +LSS (Layer settings service) is an extension to CANopen described in CiA DSP 305. The +interface is described in CiA DS 309 2.1.0 (ASCII mapping). +LSS allows the user to change node ID and bitrate, as well as setting the node ID on an +unconfigured node. + +LSS uses the the OD Identity register as an unique value to select a node. Therefore +the LSS address always consists of four 32 bit values. This also means that LSS relies +on this register to actually be unique. + +To use LSS, a compatible node is needed. Note that canopend only includes LSS master +functionality. + +The following example show some typical use cases for LSS: + + - Changing the node ID for a known slave, store the new node ID to eeprom, apply new node ID. + The node currently has the node ID 22. + + $ ./canopencomm lss_switch_sel 0x00000428 0x00000431 0x00000002 0x5C17EEBC + $ ./canopencomm lss_set_node 4 + $ ./canopencomm lss_store + $ ./canopencomm lss_switch_glob 0 + $ ./canopencomm 22 reset communication + + Note that the node ID change is not done until reset communication/node + + - Changing the node ID for a known slave, store the new node ID to eeprom, apply new node ID. + The node currently has an invalid node ID. + + $ ./canopencomm lss_switch_sel 0x00000428 0x00000431 0x00000002 0x5C17EEBC + $ ./canopencomm lss_set_node 4 + $ ./canopencomm lss_store + $ ./canopencomm lss_switch_glob 0 + + Note that the node ID is automatically applied. + + - Search for a node via LSS fastscan, store the new node ID to eeprom, apply new node ID + + $ ./canopencomm [1] _lss_fastscan + + [1] 0x00000428 0x00000432 0x00000002 0x6C81413C + + $ ./canopencomm lss_set_node 4 + $ ./canopencomm lss_store + $ ./canopencomm lss_switch_glob 0 + + To increase scanning speed, you can use + + $ ./canopencomm [1] _lss_fastscan 25 + + where 25 is the scan step delay in ms. Be aware that the scan will become unreliable when + the delay is set to low. + + - Auto enumerate all nodes via LSS fastscan. Enumeration automatically begins at node ID 2 + and node ID is automatically stored to eeprom. Like with _lss_fastscan, an optional + parameter can be used to change default delay time. + + $ ./canopencomm lss_allnodes + + [1] OK, found 3 nodes starting at node ID 2. + + - To get further control over the fastscan process, the lss_allnodes command supports + an extended parameter set. If you want to use this set, all parameters are mandatory. + Auto enumerate all nodes via LSS fastscan. Set delay time to 25ms, set enumeration start + to node ID 7, do not store LSS address in eeprom, enumerate only devices with vendor ID + "0x428", ignore product code and software revision, scan for serial number + + $ ./canopencomm lss_allnodes 25 7 0 2 0x428 1 0 1 0 0 0 + + [1] OK, found 2 nodes starting at node ID 7. + + The parameters are as following: + - 25 scan step delay time in ms + - 7 enumeration start + - 0 store node IDs to eeprom; 0 = no, 1 = yes + - 2 vendor ID scan selector; 0 = fastscan, 2 = match value in next parameter + - 0x428 vendor ID to match + - 1 product code scan selector; 0 = fastscan, 1 = ignore, 2 = match value in next parameter + - 0 product code to match (ignored in this example) + - 1 software version scan selector; 0 = fastscan, 1 = ignore, 2 = match value in next parameter + - 0 software version to match (ignored in this example) + - 0 serial number scan selector; 0 = fastscan, 1 = ignore, 2 = match value in next parameter + - 0 serial number to match (not used in this example) + + Note that only unconfigured nodes (those without a valid node ID) will take part in + fastscan! diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md new file mode 100644 index 00000000..19a13870 --- /dev/null +++ b/doc/deviceSupport.md @@ -0,0 +1,94 @@ +Device Support +============== + +CANopenNode can run on many different devices. There are possible many different implementations on many different hardware, with many different development tools, by many different developers. It is not possible for single project maintainer to keep all the hardware interfaces updated. For that reason all hardware specific files are not part of the CANopenNode project. + +It is necessary to implement interface to specific hardware. Interface to Linux socketCAN is part of this projects. Interfaces to other controllers are separate projects. There are interfaces to: Zephyr RTOS, PIC, Mbed-os RTOS + STM32, etc. + + +Note for device driver contributors +----------------------------------- +Most up-to-date implementations of CANopenNode are: socketCAN for Linux, which is part of CANopenNode and [CANopenPIC](https://github.com/CANopenNode/CANopenPIC) for PIC32 microcontroller (bare-metal). Those can be used for reference. There is also an example directory, which doesn't include specific device interface. It should compile on any system and can be used as a template. Device interface is documented in common CO_driver.h file. + +There are many advantages of sharing the base code such as this. For the driver developers, who wish to share and cooperate, I recommend the following approach: +1. Make own git repo for the Device specific demo project on the Github or somewhere. +2. Add https://github.com/CANopenNode/CANopenNode into your project (or at side of your project). For example, include it in your project as a git submodule: `git submodule add https://github.com/CANopenNode/CANopenNode` +3. Add specific driver and other files. +4. Add description of new device into this file (deviceSupport.md) and make a pull request to CANopenNode. Alternatively create an issue for new device on https://github.com/CANopenNode/CANopenNode/issues. +5. Make a demo folder, which contains project files, etc., necessary to run the demo. +6. Write a good README.md file, where you describe your project, specify demo board, tools used, etc. + + +Linux +----- +* CANopenNode integration with Linux socketCAN with master command interface. SocketCAN is part of the Linux kernel. +* https://github.com/CANopenNode/CANopenNode (this project). +* CANopenNode version: (will be v2.0) +* Status: stable +* Features: OD storage, SDO client +* Systems: Linux PC, Raspberry PI, etc. +* Development tools: Linux +* Information updated 2020-02-14 + + +PIC32, dsPIC30, dsPIC33 +----------------------- +* CANopenNode integration with 16 and 32 bit PIC microcontrollers from Microchip. +* https://github.com/CANopenNode/CANopenPIC +* CANopenNode version: (near v2.0) +* Status: stable +* Features: OD storage, SDO client demo for PIC32, error counters +* Development tools: MPLAB X +* Demo hardware: Explorer 16 from Microchip +* Information updated 2020-02-14 + + +Zephyr RTOS +----------- +* CANopenNode integration with Zephyr RTOS +* https://github.com/zephyrproject-rtos/zephyr/tree/master/subsys/canbus/canopen +* Example integration: https://docs.zephyrproject.org/latest/samples/subsys/canbus/canopen/README.html +* CANopenNode version: +* Status: stable +* Features: OD storage, LED indicators, SDO server demo for Zephyr RTOS +* Development tools: Zephyr SDK +* Demo hardware: Any development board with CAN interface and Zephyr support (see https://docs.zephyrproject.org/latest/boards/index.html) +* Information updated 2020-01-21 + + +Mbed-os RTOS + STM32 (F091RC, L496ZG) +------------------------------------- +* CANopenNode integration with Mbed-os RTOS +* https://github.com/Alphatronics/mbed-os-example-canopen +* CANopenNode version: +* Status: Stable +* Features: OD storage, LED indicators, GPIO +* Development tools: Mbed CLI (gcc 7) +* Demo hardware: STM32 Nucleo F091RC (or similar) development board with CAN interface (see https://os.mbed.com/platforms/ST-Nucleo-F091RC) +* Information updated 2020-01-21 + + +Kinetis K20 (ARM) +----------------- +* CANopenNode driver for Teensy3 (Kinetis K20 ARM) +* https://github.com/c0d3runn3r/CANopenNode/tree/add-k20-driver, https://github.com/CANopenNode/CANopenNode/pull/28 +* CANopenNode version: 83f18edc (before V1.0) +* Status: ? +* Features: ? +* Development tools: (see [readme](https://github.com/c0d3runn3r/CANopenNode/tree/add-k20-driver/stack/ARM_Kinetis_K20_teensy)) +* Demo hardware: Teensyduino, [Teensy3](https://www.pjrc.com/store/teensy32.html) +* Information updated 2020-02-14 + + +Other old versions +------------------ +* LPC1768 (MBED) (released in 2016) - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), [known example from 2016](https://github.com/exmachina-dev/CANopenMbed) +* RTOS eCos - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), ([released in 2013, old repo](http://sourceforge.net/p/canopennode/code_complete/)) +* Atmel SAM3X - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), ([released in old repo](http://sourceforge.net/p/canopennode/code_complete/)) +* ST STM32 - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), ([released in old repo](http://sourceforge.net/p/canopennode/code_complete/)) +* NXP LPC177x_8x - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), ([released in old repo](http://sourceforge.net/p/canopennode/code_complete/)) +* Freescale MCF5282 - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), ([released in old repo](http://sourceforge.net/p/canopennode/code_complete/)) +* BECK IPC Embedded Web-Controller SC243 ([last release 2015, old repo](http://sourceforge.net/p/canopennode/code_complete/)) +* Old Object_Dictionary_Editor, originally part of CANopenNode. It requires very old version of Firefox to run. Available on [Sourceforge](http://sourceforge.net/p/canopennode/code_complete/). +* AD ADSP-CM408 mixed signal controller Contributed by Analog devices, Inc. ([released in 2014](http://sourceforge.net/projects/canopennode-for-adsp-cm408f/)) +* Microchip PIC18F ([last release 2006](https://sourceforge.net/projects/canopennode/files/canopennode/)) diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md new file mode 100644 index 00000000..bbb8a30f --- /dev/null +++ b/doc/gettingStarted.md @@ -0,0 +1,208 @@ +Getting Started +=============== + +CANopen +------- +Before getting started with CANopenNode you should be familiar with the CANopen. +CANopen is the internationally standardized CAN-based higher-layer protocol for embedded control system. +It is specified by CiA301 (or by EN 50325-4) standard. It can be freely downloaded from https://can-cia.org/groups/specifications/. +Some information about CAN and CANopen can be found on https://can-cia.org/can-knowledge/ website. Very efficient way to get familiar with CANopen is by reading a book, for example [Embedded Networking with CAN and CANopen](https://can-newsletter.org/engineering/engineering-miscellaneous/nr_e_cia_can_books_3-2008_emb_can_pfeiffer_120529). + +CANopen itself is not a typical master/slave protocol. It is more like producer/consumer protocol. It is also possible to operate CANopen network without a master. For example, pre-configured process data objects (PDO) are transmitted from producers. Each PDO may be consumed by multiple nodes. Other useful CANopen functionalities of each CANopen device are also: Heartbeat producer and consumer, Emergency producer, Sync producer or consumer, Time producer or consumer, SDO server (Service data objects - serve variables from Object dictionary), NMT slave (network management - start or stop parts of communication), LSS slave (configuration of Node-Id and Bitrate). + +CANopen network usually has one device with master functionalities for network configuration. It may have additional CANopen functionalities, such as: NMT master, LSS master, SDO client, Emergency consumer. Master functionalities in CANopenNode are implemented with Ascii command line interface according to standard CiA309-3. + + +CANopenNode on Linux +-------------------- +CANopenNode should run on any Linux machine. Examples below was tested on Debian based machines, including **Ubuntu** and **Raspberry PI**. It is possible to run tests described below without real CAN interface, because Linux kernel already contains virtual CAN interface. + +---- + +TODO update all below. (This is currently part of https://github.com/CANopenNode/CANopenSocket, but will become part of CANopenNode.) + +CANopenSocket consists of two applications: **canopend**, which runs in background, and **canopencomm**, command interface for SDO and NMT master. + + +### canopend +**canopend** is an implementation of CANopen device with master functionality. It runs within three threads. Realtime thread processes CANopen SYNC and PDO objects. Mainline thread processes other non time critical objects. Both are nonblocking. Command interface thread is blocking. It accepts commands from socket connection from external application and executes master SDO and NMT tasks. + + +### canopencomm +**canopencomm** is the other end of the Command interface. It accepts text commands form arguments or from standard input or from file. It sends commands to *canopend* via socket, line after line. Received result is printed to standard output. It is implementation of the CiA 309 standard. + + +Getting started +--------------- +We will run two instances of *CANopend*. First will be basic node with ID=4, +second, with nodeID = 3, will have master functionality. + + +### Get the project + +Clone the project from git repository and get submodules: + + $ git clone https://github.com/CANopenNode/CANopenSocket.git + $ cd CANopenSocket + $ git submodule init + $ git submodule update + +(If you want to work on submodule CANopenNode, you can `cd CANopenNode`, +and apply git commands directly on it. Initially is in head detached state, +so you have to `git checkout master` first. Then you can control submodule +separately, for example `git remote add {yourName} {url-of-your-git-repository}`, +and `git pull {yourName} {yourbranch}`) + + +### First terminal: CAN dump + +Prepare CAN virtual (or real) device: + + $ sudo modprobe vcan + $ sudo ip link add dev vcan0 type vcan + $ sudo ip link set up vcan0 + +Run candump from [can-utils](https://github.com/linux-can/can-utils): + + $ sudo apt-get install can-utils + $ candump vcan0 + +It will show all CAN traffic on vcan0. + + +### Second terminal: canopend + +Start second terminal, compile and start *canopend*. + + $ cd CANopenSocket/canopend + $ make + $ app/canopend --help + $ app/canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto + +You should now see CAN messages on CAN dump terminal. Wait few seconds and +press CTRL-C. + + vcan0 704 [1] 00 # Bootup message. + vcan0 084 [8] 00 50 01 2F F3 FF FF FF # Emergency message. + vcan0 704 [1] 7F # Heartbeat messages + vcan0 704 [1] 7F # one per second. + +Heartbeat messages shows pre-operational state (0x7F). If you follow byte 4 of the +Emergency message into [CANopenNode/stack/CO_Emergency.h], +CO_EM_errorStatusBits, you will see under 0x2F "CO_EM_NON_VOLATILE_MEMORY", +which is generic, critical error with access to non volatile device memory. +This byte is CANopenNode specific. You can observe also first two bytes, +which shows standard error code (0x5000 - Device Hardware) or third byte, +which shows error register. If error register is different than zero, then +node is not able to enter operational and PDOs can not be exchanged with it. + +You can follow the reason of the problem inside the source code. However, +there are missing non-default storage files. Add them and run it again. + + $ echo - > od4_storage + $ echo - > od4_storage_auto + $ app/canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto + + vcan0 704 [1] 00 + vcan0 184 [2] 00 00 # PDO message + vcan0 704 [1] 05 + +Now there is operational state (0x05) and there shows one PDO on CAN +address 0x184. To learn more about PDOs, how to configure communication +and mapping parameters and how to use them see other sources of CANopen +documentation (For example article of PDO re-mapping procedure in [CAN +newsletter magazine, June 2016](http://can-newsletter.org/engineering/engineering-miscellaneous/160601_can-newsletter-magazine-june-2016) ). + +Start also second instance of *canopend* (master on nodeID=3) in the same +window (*canopend terminal*). Use default od_storage files and default +socket for command interface. + + $ # press CTRL-Z + $ bg + $ app/canopend vcan0 -i 3 -c "" + + +### Third terminal: canopencomm + +Start third terminal, compile and start canopencomm. + + $ cd CANopenSocket/canopencomm + $ make + $ ./canopencomm --help + +#### SDO master + +Play with it and also observe CAN dump terminal. First Heartbeat at +index 0x1017, subindex 0, 16-bit integer, on nodeID 4. + + $ ./canopencomm [1] 4 read 0x1017 0 i16 + $ ./canopencomm [1] 4 write 0x1017 0 i16 5000 + +In CAN dump you can see some SDO communication. You will notice, that +Heartbeats from node 4 are coming in 5 second interval now. You can do +the same also for node 3. Now store Object dictionary, so it will preserve +variables on next start of the program. + + $ ./canopencomm 4 w 0x1010 1 u32 0x65766173 + +You can read more about Object dictionary variables for this +CANopenNode in [canopend/CANopenSocket.html]. + + +#### NMT master +If node is operational (started), it can exchange all objects, including +PDO, SDO, etc. In pre-operational, PDOs are disabled, SDOs works. In stopped +only NMT messages are accepted. + + $ ./canopencomm 4 preop + $ ./canopencomm 4 start + $ ./canopencomm 4 stop + $ ./canopencomm 4 r 0x1017 0 i16 # time out + $ ./canopencomm 4 reset communication + $ ./canopencomm 4 reset node + $ ./canopencomm 3 reset node + +In *canopend terminal* you see, that both devices finished. Further commands +are not possible. If you set so, last command can also reset computer. + +#### Combining NMT commands into a single file + +Create a `commands.txt` file, and for its content enter your commands. +Example: + + [1] 3 start + [2] 4 start + +Make canopencomm use that file: + + $ ./canopencomm -f commands.txt + [1] OK + [2] OK + + +### Next steps +Now you can learn more skills on CANopen from some other sources: +books, data sheet of some CANopen device, standard CiA 301(it's free), etc. +Then you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware). + + +Accessing real CANopen devices is the same as described above for virtual CAN interface. +Some tested USB to CAN interfaces, which are natively integrated into Linux are: + + - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with: `sudo slcand -f -o -c -s8 /dev/ttyACM0 can0; sudo ip link set up can0` + - [EMS CPC-USB](http://www.ems-wuensche.com/product/datasheet/html/can-usb-adapter-converter-interface-cpcusb.html) - Start with: `sudo ip link set up can0 type can bitrate 250000` + - [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Needs newer Linux kernel, supports CAN flexible data rate. + - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can). + - Beaglebone or Paspberry PI or similar has CAN capes available. On RPI worked + also the above USB interfaces, but it was necessary to compile the kernel. + + +With [CANopenNode](https://github.com/CANopenNode/CANopenNode) you can also design your +own device. There are many very useful and high quality specifications for different +[device profiles](http://www.can-cia.org/standardization/specifications/), +some of them are public and free to download. + + +Here we played with virtual CAN interface and result shows as pixels on +screen. If you connect real CAN interface to your computer, things may +become dangerous. Keep control and safety on your machines! diff --git a/doc/index.html b/doc/index.html new file mode 120000 index 00000000..13211f4d --- /dev/null +++ b/doc/index.html @@ -0,0 +1 @@ +html/md_README.html \ No newline at end of file diff --git a/doc/traceUsage.md b/doc/traceUsage.md new file mode 100644 index 00000000..63992a46 --- /dev/null +++ b/doc/traceUsage.md @@ -0,0 +1,42 @@ +Trace usage +=========== + +CANopenNode includes optional trace functionality (non-standard). It monitors +choosen variables from Object Dictionary. On change of state of variable it +makes a record with timestamp into circular buffer. String with points can later +be read via SDO. + +Trace is disabled by default. It can be enabled using Object Dictionary editor. +Include also *CO_trace.h/.c* into project, compile and run. + +Here is en example of monitoring variable, connected with buttons +(OD_readInput8Bit, index 0x6000, subindex 0x01). It was tested on PIC32: + +``` +# Enable trace first: +./canopencomm 0x30 w 0x2400 0 u8 1 + +# Press and hold the button on Explorer16 and execute SDO read command: +./canopencomm 0x30 r 0x6000 1 u8 +[1] 0x08 +# It displays same value, as was transmitted via PDO and visible on candump. + +# Now get the complete history for that buttons with timestamp for each change +# and store it as a text to the file: +./canopencomm 0x30 r 0x2401 5 vs > plot1.csv +cat plot1.csv +``` +If large data blocks are transmitted via CAN bus, then more efficient SDO block +transfer can be enabled with command `./canopencomm set sdo_block 1` + +For more info on using trace functionality see CANopenNode/example/IO.html +file. There is also a description of all Object Dictionary variables. + +Trace functionality can also be configured on CANopenSocket directly. In that +case CANopenSocket must first receive PDO data from remote node(s) and store it +to the local Object Dictionary variable. CANopenSocket's trace then monitors +that variable. Text buffer is then read with the similar command as above. But +local SDO data access from CANopenSocket itself doesn't occupy CAN bus, so large +data is transfered realy fast. Besides that, Linux machine has much more RAM to +store the monitored data. Except timestamp is less accurate. + From 2fa91d2c695219f244c552090621db82f93b14d8 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 24 Feb 2020 09:42:20 +0100 Subject: [PATCH 021/520] Fixed: BUG in CO_HBconsumer.c #168 Misleading Comments in CO_SDO.h #169 --- 301/CO_HBconsumer.c | 10 +++++----- 301/CO_SDOserver.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 5ee4347e..1cd904e5 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -201,7 +201,7 @@ void CO_HBconsumer_initCallbackHeartbeatStarted( { CO_HBconsNode_t *monitoredNode; - if (HBcons==NULL || idx>HBcons->numberOfMonitoredNodes) { + if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { return; } @@ -220,7 +220,7 @@ void CO_HBconsumer_initCallbackTimeout( { CO_HBconsNode_t *monitoredNode; - if (HBcons==NULL || idx>HBcons->numberOfMonitoredNodes) { + if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { return; } @@ -239,7 +239,7 @@ void CO_HBconsumer_initCallbackRemoteReset( { CO_HBconsNode_t *monitoredNode; - if (HBcons==NULL || idx>HBcons->numberOfMonitoredNodes) { + if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { return; } @@ -397,7 +397,7 @@ CO_HBconsumer_state_t CO_HBconsumer_getState( { CO_HBconsNode_t *monitoredNode; - if (HBcons==NULL || idx>HBcons->numberOfMonitoredNodes) { + if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { return CO_HBconsumer_UNCONFIGURED; } @@ -413,7 +413,7 @@ int8_t CO_HBconsumer_getNmtState( { CO_HBconsNode_t *monitoredNode; - if (HBcons==NULL || nmtState==NULL || idx>HBcons->numberOfMonitoredNodes) { + if (HBcons==NULL || nmtState==NULL || idx>=HBcons->numberOfMonitoredNodes) { return -1; } *nmtState = CO_NMT_INITIALIZING; diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 3e1ea83a..213b5e4b 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -505,11 +505,11 @@ typedef struct { * See CO_OD_entry_t. */ typedef struct{ - /** See #CO_SDO_OD_attributes_t */ + /** Pointer to data. If object type is Domain, pData is null */ void *pData; - /** Length of variable in bytes. If object type is Domain, length is zero */ + /** See #CO_SDO_OD_attributes_t */ uint16_t attribute; - /** Pointer to data. If object type is Domain, pData is null */ + /** Length of variable in bytes. If object type is Domain, length is zero */ uint16_t length; }CO_OD_entryRecord_t; From a513d84e451151d8f231f3fa2ebfac4b6b914760 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 25 Feb 2020 12:05:07 +0100 Subject: [PATCH 022/520] Move Makefile into example/ Renamed to example/CO_driver_blank.c and example/main_blank.c Copied socketCAN/main.c from CANopenSocket project. --- .gitignore | 2 + README.md | 11 +- doc/CHANGELOG.md | 1 + example/{CO_driver.c => CO_driver_blank.c} | 0 Makefile => example/Makefile | 17 +- example/{main.c => main_blank.c} | 13 +- socketCAN/main.c | 558 +++++++++++++++++++++ 7 files changed, 577 insertions(+), 25 deletions(-) rename example/{CO_driver.c => CO_driver_blank.c} (100%) rename Makefile => example/Makefile (81%) rename example/{main.c => main_blank.c} (91%) create mode 100644 socketCAN/main.c diff --git a/.gitignore b/.gitignore index ec369297..7b22621e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ doc/html/ .project .settings/ +#kdevelop +*.kdev4 diff --git a/README.md b/README.md index d87d8332..660b7794 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Documentation with [Getting started](doc/gettingStarted.md), [LSS usage](doc/LSSusage.md) and [Trace usage](doc/traceUsage.md) is in `doc` directory. Code is documented in header files. Running [doxygen](http://www.doxygen.nl/) -or `make doc` in project base directory will produce complete html documentation. +in project base directory will produce complete html documentation. Just open CANopenNode/doc/html/index.html in the browser. Report issues on https://github.com/CANopenNode/CANopenNode/issues @@ -146,9 +146,12 @@ File structure - **CO_LSSslave.h/.c** - CANopen Layer Setting Service - slave protocol. - **extra/** - **CO_trace.h/.c** - CANopen trace object for recording variables over time. - - **example/** - Directory with basic example. - - **main.c** - Mainline and other threads - example template. + - **example/** - Directory with basic example, should compile on any system. + - **CO_driver_target.h** - Example hardware definitions for CANopenNode. + - **CO_driver_blank.c** - Example blank interface for CANopenNode. - **CO_OD.h/.c** - CANopen Object dictionary. Automatically generated files. + - **main_blank.c** - Mainline and other threads - example template. + - **Makefile** - Makefile for example. - **IO.eds** - Standard CANopen EDS file, which may be used from CANopen configuration tool. Automatically generated file. - _ **project.xml** - XML file contains all data for CANopen Object dictionary. @@ -162,6 +165,7 @@ File structure - **CO_Linux_threads.h/.c** - Helper functions for implementing CANopen threads in Linux. - **CO_notify_pipe.h/.c** - Notify pipe for Linux threads. - **CO_OD_storage.h/.c** - Object Dictionary storage object for Linux SocketCAN. + - **main.c** - Mainline for socketCAN - **doc/** - Directory with documentation - **CHANGELOG.md** - Change Log file. - **deviceSupport.md** - Information about supported devices. @@ -172,7 +176,6 @@ File structure - **codingStyle** - Example of the coding style. - **.clang-format** - Definition file for the coding style. - **Doxyfile** - Configuration file for the documentation generator *doxygen*. - - **Makefile** - Basic makefile. - **LICENSE** - License. - **README.md** - This file. diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 637412a0..4cdf7138 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -19,6 +19,7 @@ Change Log - It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. ### Fixed - Bugfix in `CO_HBconsumer_process()`: argument `timeDifference_us` was set to 0 inside for loop, fixed now. +- BUG in CO_HBconsumer.c #168 ### Added - Documentation added to `doc` directory: CHANGELOG.md, deviceSupport.md, gettingStarted.md, LSSusage.md and traceUsage.md. - All CANopen objects calculates next timer info for OS. diff --git a/example/CO_driver.c b/example/CO_driver_blank.c similarity index 100% rename from example/CO_driver.c rename to example/CO_driver_blank.c diff --git a/Makefile b/example/Makefile similarity index 81% rename from Makefile rename to example/Makefile index 73baf712..c6cc940f 100644 --- a/Makefile +++ b/example/Makefile @@ -1,9 +1,9 @@ -# Makefile for CANopenNode, basic compile with no CAN device. +# Makefile for CANopenNode, basic compile with blank CAN device. -DRV_SRC = example -CANOPEN_SRC =. -APPL_SRC = example +DRV_SRC = . +CANOPEN_SRC = .. +APPL_SRC = . LINK_TARGET = canopennode @@ -16,7 +16,7 @@ INCLUDE_DIRS = \ SOURCES = \ - $(DRV_SRC)/CO_driver.c \ + $(DRV_SRC)/CO_driver_blank.c \ $(DRV_SRC)/eeprom.c \ $(CANOPEN_SRC)/301/CO_SDOserver.c \ $(CANOPEN_SRC)/301/CO_Emergency.c \ @@ -32,7 +32,7 @@ SOURCES = \ $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ $(APPL_SRC)/CO_OD.c \ - $(APPL_SRC)/main.c + $(APPL_SRC)/main_blank.c OBJS = $(SOURCES:%.c=%.o) @@ -41,16 +41,13 @@ CFLAGS = -Wall $(INCLUDE_DIRS) LDFLAGS = -.PHONY: all clean doc +.PHONY: all clean all: clean $(LINK_TARGET) clean: rm -f $(OBJS) $(LINK_TARGET) -doc: - doxygen - %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ diff --git a/example/main.c b/example/main_blank.c similarity index 91% rename from example/main.c rename to example/main_blank.c index ee1e4a56..5019ba88 100644 --- a/example/main.c +++ b/example/main_blank.c @@ -31,12 +31,6 @@ #define TMR_TASK_INTERVAL (1000) /* Interval of tmrTask thread in microseconds */ #define INCREMENT_1MS(var) (var++) /* Increment 1ms variable in tmrTask */ -/** - * User-defined CAN base structure, passed as argument to CO_CANinit. - */ -struct CANbase { - uintptr_t baseAddress; /**< Base address of the CAN module */ -}; /* Global variables and objects */ volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */ @@ -68,14 +62,11 @@ int main (void){ uint16_t timer1msPrevious; /* disable CAN and CAN interrupts */ - struct CANbase canBase = { - .baseAddress = 0u, /* CAN module address */ - }; /* initialize CANopen */ - err = CO_CANinit(&canBase, 125 /* bit rate */); + err = CO_CANinit(NULL /* CAN module address */, 125 /* bit rate */); if (err == CO_ERROR_NO) { - err = CO_CANopenInit(10/* NodeID */); + err = CO_CANopenInit(10 /* NodeID */); } if(err != CO_ERROR_NO){ while(1); diff --git a/socketCAN/main.c b/socketCAN/main.c new file mode 100644 index 00000000..329d6780 --- /dev/null +++ b/socketCAN/main.c @@ -0,0 +1,558 @@ +/* + * CANopen main program file for Linux SocketCAN. + * + * @file main + * @author Janez Paternoster + * @copyright 2015 - 2020 Janez Paternoster + * + * This file is part of CANopenSocket, a Linux implementation of CANopen + * stack with master functionality. Project home page is + * . CANopenSocket is based + * on CANopenNode: . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "CANopen.h" +#include "CO_OD_storage.h" +#include "CO_Linux_tasks.h" +#include "CO_time.h" +#include "application.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CO_SINGLE_THREAD +#include "CO_command.h" +#include +#endif + + +#define NSEC_PER_SEC (1000000000) /* The number of nanoseconds per second. */ +#define NSEC_PER_MSEC (1000000) /* The number of nanoseconds per millisecond. */ +#define TMR_TASK_INTERVAL_NS (1000000) /* Interval of taskTmr in nanoseconds */ +#define TMR_TASK_OVERFLOW_US (5000) /* Overflow detect limit for taskTmr in microseconds */ +#define INCREMENT_1MS(var) (var++) /* Increment 1ms variable in taskTmr */ + + +/* Global variable increments each millisecond. */ +volatile uint16_t CO_timer1ms = 0U; + +/* Mutex is locked, when CAN is not valid (configuration state). May be used + * from other threads. RT threads may use CO->CANmodule[0]->CANnormal instead. */ +#ifndef CO_SINGLE_THREAD +pthread_mutex_t CO_CAN_VALID_mtx = PTHREAD_MUTEX_INITIALIZER; +#endif + +/* Other variables and objects */ +static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ +static int mainline_epoll_fd; /* epoll file descriptor for mainline */ +static CO_OD_storage_t odStor; /* Object Dictionary storage object for CO_OD_ROM */ +static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ +static char *odStorFile_rom = "od_storage"; /* Name of the file */ +static char *odStorFile_eeprom = "od_storage_auto"; /* Name of the file */ +static CO_time_t CO_time; /* Object for current time */ +static in_port_t CO_command_socket_tcp_port = 60000; /* default port when used in tcp gateway mode */ + + +/* Realtime thread */ +#ifndef CO_SINGLE_THREAD +static void* rt_thread(void* arg); +static pthread_t rt_thread_id; +static int rt_thread_epoll_fd; +#endif + + +/* Signal handler */ +volatile sig_atomic_t CO_endProgram = 0; +static void sigHandler(int sig) { + CO_endProgram = 1; +} + + +/* Helper functions ***********************************************************/ +void CO_errExit(char* msg) { + perror(msg); + exit(EXIT_FAILURE); +} + +/* send CANopen generic emergency message */ +void CO_error(const uint32_t info) { + CO_errorReport(CO->em, CO_EM_GENERIC_SOFTWARE_ERROR, CO_EMC_SOFTWARE_INTERNAL, info); + fprintf(stderr, "canopend generic error: 0x%X\n", info); +} + + +static void printUsage(char *progName) { +fprintf(stderr, +"Usage: %s [options]\n", progName); +fprintf(stderr, +"\n" +"Options:\n" +" -i CANopen Node-id (1..127). If not specified, value from\n" +" Object dictionary (0x2101) is used.\n" +" -p Realtime priority of RT task (RT disabled by default).\n" +" -r Enable reboot on CANopen NMT reset_node command. \n" +" -s Set Filename for OD storage ('od_storage' is default).\n" +" -a Set Filename for automatic storage variables from\n" +" Object dictionary. ('od_storage_auto' is default).\n"); +#ifndef CO_SINGLE_THREAD +fprintf(stderr, +" -c Enable command interface for master functionality. \n" +" If socket path is specified as empty string \"\",\n" +" default '%s' will be used.\n" +" Note that location of socket path may affect security.\n" +" See 'canopencomm/canopencomm --help' for more info.\n" +, CO_command_socketPath); +fprintf(stderr, +" -t Enable command interface for master functionality over tcp, \n" +" listen to .\n" +" Note that using this mode may affect security.\n" +); +#endif +fprintf(stderr, +"\n" +"See also: https://github.com/CANopenNode/CANopenSocket\n" +"\n"); +} + + +/******************************************************************************/ +/** Mainline and RT thread **/ +/******************************************************************************/ +int main (int argc, char *argv[]) { + CO_NMT_reset_cmd_t reset = CO_RESET_NOT; + CO_ReturnError_t odStorStatus_rom, odStorStatus_eeprom; + int CANdevice0Index = 0; + int opt; + bool_t firstRun = true; + + char* CANdevice = NULL; /* CAN device, configurable by arguments. */ + bool_t nodeIdFromArgs = false; /* True, if program arguments are used for CANopen Node Id */ + int nodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ + bool_t rebootEnable = false; /* Configurable by arguments */ +#ifndef CO_SINGLE_THREAD + typedef enum CMD_MODE {CMD_NONE, CMD_LOCAL, CMD_REMOTE} cmdMode_t; + cmdMode_t commandEnable = CMD_NONE; /* Configurable by arguments */ +#endif + + if(argc < 2 || strcmp(argv[1], "--help") == 0){ + printUsage(argv[0]); + exit(EXIT_SUCCESS); + } + + + /* Get program options */ + while((opt = getopt(argc, argv, "i:p:rc:t:s:a:")) != -1) { + switch (opt) { + case 'i': + nodeId = strtol(optarg, NULL, 0); + nodeIdFromArgs = true; + break; + case 'p': rtPriority = strtol(optarg, NULL, 0); break; + case 'r': rebootEnable = true; break; +#ifndef CO_SINGLE_THREAD + case 'c': + /* In case of empty string keep default name, just enable interface. */ + if(strlen(optarg) != 0) { + CO_command_socketPath = optarg; + } + commandEnable = CMD_LOCAL; + break; + case 't': + /* In case of empty string keep default port, just enable interface. */ + if(strlen(optarg) != 0) { + //CO_command_socket_tcp_port = optarg; + int scanResult = sscanf(optarg, "%hu", &CO_command_socket_tcp_port); + if(scanResult != 1){ //expect one argument to be extracted + printf("ERROR: -t argument \'%s\' is not a valid tcp port\n", optarg); + exit(EXIT_FAILURE); + } + } + commandEnable = CMD_REMOTE; + break; +#endif + case 's': odStorFile_rom = optarg; break; + case 'a': odStorFile_eeprom = optarg; break; + default: + printUsage(argv[0]); + exit(EXIT_FAILURE); + } + } + + if(optind < argc) { + CANdevice = argv[optind]; + CANdevice0Index = if_nametoindex(CANdevice); + } + + if(nodeIdFromArgs && (nodeId < 1 || nodeId > 127)) { + fprintf(stderr, "Wrong node ID (%d)\n", nodeId); + printUsage(argv[0]); + exit(EXIT_FAILURE); + } + + if(rtPriority != -1 && (rtPriority < sched_get_priority_min(SCHED_FIFO) + || rtPriority > sched_get_priority_max(SCHED_FIFO))) { + fprintf(stderr, "Wrong RT priority (%d)\n", rtPriority); + printUsage(argv[0]); + exit(EXIT_FAILURE); + } + + if(CANdevice0Index == 0) { + char s[120]; + snprintf(s, 120, "Can't find CAN device \"%s\"", CANdevice); + CO_errExit(s); + } + + + printf("%s - starting CANopen device with Node ID %d(0x%02X)", argv[0], nodeId, nodeId); + + + /* Verify, if OD structures have proper alignment of initial values */ + if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) { + fprintf(stderr, "Program init - %s - Error in CO_OD_RAM.\n", argv[0]); + exit(EXIT_FAILURE); + } + if(CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) { + fprintf(stderr, "Program init - %s - Error in CO_OD_EEPROM.\n", argv[0]); + exit(EXIT_FAILURE); + } + if(CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) { + fprintf(stderr, "Program init - %s - Error in CO_OD_ROM.\n", argv[0]); + exit(EXIT_FAILURE); + } + + + /* initialize Object Dictionary storage */ + odStorStatus_rom = CO_OD_storage_init(&odStor, (uint8_t*) &CO_OD_ROM, sizeof(CO_OD_ROM), odStorFile_rom); + odStorStatus_eeprom = CO_OD_storage_init(&odStorAuto, (uint8_t*) &CO_OD_EEPROM, sizeof(CO_OD_EEPROM), odStorFile_eeprom); + + + /* Catch signals SIGINT and SIGTERM */ + if(signal(SIGINT, sigHandler) == SIG_ERR) + CO_errExit("Program init - SIGINIT handler creation failed"); + if(signal(SIGTERM, sigHandler) == SIG_ERR) + CO_errExit("Program init - SIGTERM handler creation failed"); + + /* increase variable each startup. Variable is automatically stored in non-volatile memory. */ + printf(", count=%u ...\n", ++OD_powerOnCounter); + + + while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { +/* CANopen communication reset - initialize CANopen objects *******************/ + CO_ReturnError_t err; + + printf("%s - communication reset ...\n", argv[0]); + + +#ifndef CO_SINGLE_THREAD + /* Wait other threads (command interface). */ + pthread_mutex_lock(&CO_CAN_VALID_mtx); +#endif + + /* Wait rt_thread. */ + if(!firstRun) { + CO_LOCK_OD(); + CO->CANmodule[0]->CANnormal = false; + CO_UNLOCK_OD(); + } + + + /* Enter CAN configuration. */ + CO_CANsetConfigurationMode(CANdevice0Index); + + + /* initialize CANopen */ + if(!nodeIdFromArgs) { + /* use value from Object dictionary, if not set by program arguments */ + nodeId = OD_CANNodeID; + } + err = CO_init(CANdevice0Index, nodeId, 0); + if(err != CO_ERROR_NO) { + char s[120]; + snprintf(s, 120, "Communication reset - CANopen initialization failed, err=%d", err); + CO_errExit(s); + } + + + /* initialize OD objects 1010 and 1011 and verify errors. */ + CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U); + CO_OD_configure(CO->SDO[0], OD_H1011_REST_PARAM_FUNC, CO_ODF_1011, (void*)&odStor, 0, 0U); + if(odStorStatus_rom != CO_ERROR_NO) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_rom); + } + if(odStorStatus_eeprom != CO_ERROR_NO) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_eeprom + 1000); + } + + + /* Configure callback functions for task control */ + CO_EM_initCallback(CO->em, taskMain_cbSignal); + CO_SDO_initCallback(CO->SDO[0], taskMain_cbSignal); + CO_SDOclient_initCallback(CO->SDOclient, taskMain_cbSignal); + + + /* Initialize time */ + CO_time_init(&CO_time, CO->SDO[0], &OD_time.epochTimeBaseMs, &OD_time.epochTimeOffsetMs, 0x2130); + + + /* First time only initialization. */ + if(firstRun) { + firstRun = false; + + /* Configure epoll for mainline */ + mainline_epoll_fd = epoll_create(4); + if(mainline_epoll_fd == -1) + CO_errExit("Program init - epoll_create mainline failed"); + + /* Init mainline */ + taskMain_init(mainline_epoll_fd, &OD_performance[ODA_performance_mainCycleMaxTime]); + + +#ifdef CO_SINGLE_THREAD + /* Init taskRT */ + CANrx_taskTmr_init(mainline_epoll_fd, TMR_TASK_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); + + OD_performance[ODA_performance_timerCycleTime] = TMR_TASK_INTERVAL_NS/1000; /* informative */ + + /* Set priority for mainline */ + if(rtPriority > 0) { + struct sched_param param; + + param.sched_priority = rtPriority; + if(sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) + CO_errExit("Program init - mainline set scheduler failed"); + } +#else + /* Configure epoll for rt_thread */ + rt_thread_epoll_fd = epoll_create(2); + if(rt_thread_epoll_fd == -1) + CO_errExit("Program init - epoll_create rt_thread failed"); + + /* Init taskRT */ + CANrx_taskTmr_init(rt_thread_epoll_fd, TMR_TASK_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); + + OD_performance[ODA_performance_timerCycleTime] = TMR_TASK_INTERVAL_NS/1000; /* informative */ + + /* Create rt_thread */ + if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) + CO_errExit("Program init - rt_thread creation failed"); + + /* Set priority for rt_thread */ + if(rtPriority > 0) { + struct sched_param param; + + param.sched_priority = rtPriority; + if(pthread_setschedparam(rt_thread_id, SCHED_FIFO, ¶m) != 0) + CO_errExit("Program init - rt_thread set scheduler failed"); + } +#endif + +#ifndef CO_SINGLE_THREAD + /* Initialize socket command interface */ + switch(commandEnable) { + case CMD_LOCAL: + if(CO_command_init() != 0) { + CO_errExit("Socket command interface initialization failed"); + } + printf("%s - Command interface on socket '%s' started ...\n", argv[0], CO_command_socketPath); + break; + case CMD_REMOTE: + if(CO_command_init_tcp(CO_command_socket_tcp_port) != 0) { + CO_errExit("Socket command interface initialization failed"); + } + printf("%s - Command interface on tcp port '%hu' started ...\n", argv[0], CO_command_socket_tcp_port); + break; + default: + break; + } +#endif + + /* Execute optional additional application code */ + app_programStart(); + } + + + /* Execute optional additional application code */ + app_communicationReset(); + + + /* start CAN */ + CO_CANsetNormalMode(CO->CANmodule[0]); +#ifndef CO_SINGLE_THREAD + pthread_mutex_unlock(&CO_CAN_VALID_mtx); +#endif + + + reset = CO_RESET_NOT; + + printf("%s - running ...\n", argv[0]); + + + while(reset == CO_RESET_NOT && CO_endProgram == 0) { +/* loop for normal program execution ******************************************/ + int ready; + struct epoll_event ev; + + ready = epoll_wait(mainline_epoll_fd, &ev, 1, -1); + + if(ready != 1) { + if(errno != EINTR) { + CO_error(0x11100000L + errno); + } + } + +#ifdef CO_SINGLE_THREAD + else if(CANrx_taskTmr_process(ev.data.fd)) { + /* code was processed in the above function. Additional code process below */ + INCREMENT_1MS(CO_timer1ms); + /* Detect timer large overflow */ + if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_TASK_OVERFLOW_US && rtPriority > 0) { + CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0x22400000L | OD_performance[ODA_performance_timerCycleMaxTime]); + } + } +#endif + + else if(taskMain_process(ev.data.fd, &reset, CO_timer1ms)) { + uint16_t timer1msDiff; + static uint16_t tmr1msPrev = 0; + + /* Calculate time difference */ + timer1msDiff = CO_timer1ms - tmr1msPrev; + tmr1msPrev = CO_timer1ms; + + /* code was processed in the above function. Additional code process below */ + + /* Execute optional additional application code */ + app_programAsync(timer1msDiff); + + CO_OD_storage_autoSave(&odStorAuto, CO_timer1ms, 60000); + } + + else { + /* No file descriptor was processed. */ + CO_error(0x11200000L); + } + } + } + + +/* program exit ***************************************************************/ + /* join threads */ +#ifndef CO_SINGLE_THREAD + switch (commandEnable) + { + case CMD_LOCAL: + if (CO_command_clear() != 0) { + CO_errExit("Socket command interface removal failed"); + } + break; + case CMD_REMOTE: + //nothing to do yet + break; + default: + break; + } +#endif + + CO_endProgram = 1; +#ifndef CO_SINGLE_THREAD + if(pthread_join(rt_thread_id, NULL) != 0) { + CO_errExit("Program end - pthread_join failed"); + } +#endif + + /* Execute optional additional application code */ + app_programEnd(); + + /* Store CO_OD_EEPROM */ + CO_OD_storage_autoSave(&odStorAuto, 0, 0); + CO_OD_storage_autoSaveClose(&odStorAuto); + + /* delete objects from memory */ + CANrx_taskTmr_close(); + taskMain_close(); + CO_delete(CANdevice0Index); + + printf("%s on %s (nodeId=0x%02X) - finished.\n\n", argv[0], CANdevice, nodeId); + + /* Flush all buffers (and reboot) */ + if(rebootEnable && reset == CO_RESET_APP) { + sync(); + if(reboot(LINUX_REBOOT_CMD_RESTART) != 0) { + CO_errExit("Program end - reboot failed"); + } + } + + exit(EXIT_SUCCESS); +} + + +#ifndef CO_SINGLE_THREAD +/* Realtime thread for CAN receive and taskTmr ********************************/ +static void* rt_thread(void* arg) { + + /* Endless loop */ + while(CO_endProgram == 0) { + int ready; + struct epoll_event ev; + + ready = epoll_wait(rt_thread_epoll_fd, &ev, 1, -1); + + if(ready != 1) { + if(errno != EINTR) { + CO_error(0x12100000L + errno); + } + } + + else if(CANrx_taskTmr_process(ev.data.fd)) { + int i; + + /* code was processed in the above function. Additional code process below */ + INCREMENT_1MS(CO_timer1ms); + + /* Monitor variables with trace objects */ + CO_time_process(&CO_time); +#if CO_NO_TRACE > 0 + for(i=0; itrace[i], *CO_time.epochTimeOffsetMs); + } +#endif + + /* Execute optional additional application code */ + app_program1ms(); + + /* Detect timer large overflow */ + if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_TASK_OVERFLOW_US && rtPriority > 0 && CO->CANmodule[0]->CANnormal) { + CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0x22400000L | OD_performance[ODA_performance_timerCycleMaxTime]); + } + } + + else { + /* No file descriptor was processed. */ + CO_error(0x12200000L); + } + } + + return NULL; +} +#endif From c40130b70e532d2cd2ca057dc2c3289f54e549a7 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 26 Feb 2020 13:04:25 +0100 Subject: [PATCH 023/520] socketCAN: add Makefile and do basic changes --- README.md | 1 + socketCAN/CO_Linux_threads.c | 10 +-- socketCAN/Makefile | 68 +++++++++++++++ socketCAN/main.c | 163 ++++++++++++++++++++++------------- 4 files changed, 176 insertions(+), 66 deletions(-) create mode 100644 socketCAN/Makefile diff --git a/README.md b/README.md index 660b7794..266c8cf8 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,7 @@ File structure - **CO_notify_pipe.h/.c** - Notify pipe for Linux threads. - **CO_OD_storage.h/.c** - Object Dictionary storage object for Linux SocketCAN. - **main.c** - Mainline for socketCAN + - **Makefile** - Makefile for socketCAN. - **doc/** - Directory with documentation - **CHANGELOG.md** - Change Log file. - **deviceSupport.md** - Information about supported devices. diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index be24d2fa..242b05d4 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -87,18 +87,18 @@ void threadMain_close(void) void threadMain_process(CO_NMT_reset_cmd_t *reset) { - uint16_t finished; + uint32_t finished; uint16_t diff; uint64_t now; now = CO_LinuxThreads_clock_gettime_ms(); diff = (uint16_t)(now - threadMain.start); - /* we use timerNext_ms in CO_process() as indication if processing is + /* we use timerNext_us in CO_process() as indication if processing is * finished. We ignore any calculated values for maximum delay times. */ do { finished = 1; - *reset = CO_process(CO, diff, &finished); + *reset = CO_process(CO, (uint32_t)diff*1000, &finished); diff = 0; } while ((*reset == CO_RESET_NOT) && (finished == 0)); @@ -150,13 +150,13 @@ void CANrx_threadTmr_process(void) for (i = 0; i <= missed; i++) { /* Process Sync */ - syncWas = CO_process_SYNC(CO, threadRT.us_interval); + syncWas = CO_process_SYNC(CO, threadRT.us_interval, NULL); /* Read inputs */ CO_process_RPDO(CO, syncWas); /* Write outputs */ - CO_process_TPDO(CO, syncWas, threadRT.us_interval); + CO_process_TPDO(CO, syncWas, threadRT.us_interval, NULL); } } diff --git a/socketCAN/Makefile b/socketCAN/Makefile new file mode 100644 index 00000000..6b088c9c --- /dev/null +++ b/socketCAN/Makefile @@ -0,0 +1,68 @@ +# Makefile for CANopenNode with socketCAN + + +DRV_SRC = . +CANOPEN_SRC = .. +OD_SRC = ../example +APPL_SRC = . + + +LINK_TARGET = canopensocket + + +INCLUDE_DIRS = \ + -I$(DRV_SRC) \ + -I$(CANOPEN_SRC) \ + -I$(OD_SRC) \ + -I$(APPL_SRC) + + +SOURCES = \ + $(DRV_SRC)/CO_driver.c \ + $(DRV_SRC)/CO_error.c \ + $(DRV_SRC)/CO_notify_pipe.c \ + $(DRV_SRC)/CO_Linux_threads.c \ + $(DRV_SRC)/CO_OD_storage.c \ + $(CANOPEN_SRC)/301/CO_SDOserver.c \ + $(CANOPEN_SRC)/301/CO_Emergency.c \ + $(CANOPEN_SRC)/301/CO_NMT_Heartbeat.c \ + $(CANOPEN_SRC)/301/CO_HBconsumer.c \ + $(CANOPEN_SRC)/301/CO_SYNC.c \ + $(CANOPEN_SRC)/301/CO_PDO.c \ + $(CANOPEN_SRC)/301/CO_TIME.c \ + $(CANOPEN_SRC)/301/CO_SDOclient.c \ + $(CANOPEN_SRC)/301/crc16-ccitt.c \ + $(CANOPEN_SRC)/305/CO_LSSslave.c \ + $(CANOPEN_SRC)/305/CO_LSSmaster.c \ + $(CANOPEN_SRC)/extra/CO_trace.c \ + $(CANOPEN_SRC)/CANopen.c \ + $(OD_SRC)/CO_OD.c \ + $(APPL_SRC)/main.c + + +# This can be a single or multi threaded application. If multithreaded is +# used, then two nonblocking threads will be used: fast rt-thread for CAN +# reception + PDO + SYNC processing and slow mainline for other processing. +# For multithreaded operation: +# - Add flag -DCO_MULTI_THREAD to the CFLAGS. +# - Add flag -pthread to LDFLAGS. + + +OBJS = $(SOURCES:%.c=%.o) +CC ?= gcc +CFLAGS = -Wall -g $(INCLUDE_DIRS) -DCO_MULTI_THREAD +LDFLAGS = -pthread + + +.PHONY: all clean + +all: clean $(LINK_TARGET) + +clean: + rm -f $(OBJS) $(LINK_TARGET) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LINK_TARGET): $(OBJS) + $(CC) $(LDFLAGS) $^ -o $@ diff --git a/socketCAN/main.c b/socketCAN/main.c index 329d6780..f2f72400 100644 --- a/socketCAN/main.c +++ b/socketCAN/main.c @@ -26,9 +26,7 @@ #include "CANopen.h" #include "CO_OD_storage.h" -#include "CO_Linux_tasks.h" -#include "CO_time.h" -#include "application.h" +#include "CO_Linux_threads.h" #include #include #include @@ -41,25 +39,40 @@ #include #include -#ifndef CO_SINGLE_THREAD +#ifdef CO_USE_APPLICATION +/* Call external application functions. */ +#include "application.h" +#endif + +#if CO_NO_TRACE > 0 +#include "CO_time_trace.h" +#endif + +#ifdef CO_USE_309 +/* Use DS309-3 standard - ASCII command interface to CANopen: NMT + LSS master, SDO client */ #include "CO_command.h" +#endif + +#ifdef CO_MULTI_THREAD +/* Use two nonblocking threads: fast rt-thread for CAN reception + PDO + SYNC + * processing and slow mainline for other processing. */ #include #endif #define NSEC_PER_SEC (1000000000) /* The number of nanoseconds per second. */ #define NSEC_PER_MSEC (1000000) /* The number of nanoseconds per millisecond. */ -#define TMR_TASK_INTERVAL_NS (1000000) /* Interval of taskTmr in nanoseconds */ -#define TMR_TASK_OVERFLOW_US (5000) /* Overflow detect limit for taskTmr in microseconds */ -#define INCREMENT_1MS(var) (var++) /* Increment 1ms variable in taskTmr */ +#define TMR_THREAD_INTERVAL_NS (1000000) /* Interval of threadTmr in nanoseconds */ +#define TMR_THREAD_OVERFLOW_US (5000) /* Overflow detect limit for threadTmr in microseconds */ +#define INCREMENT_1MS(var) (var++) /* Increment 1ms variable in threadTmr */ /* Global variable increments each millisecond. */ volatile uint16_t CO_timer1ms = 0U; +#ifdef CO_MULTI_THREAD /* Mutex is locked, when CAN is not valid (configuration state). May be used * from other threads. RT threads may use CO->CANmodule[0]->CANnormal instead. */ -#ifndef CO_SINGLE_THREAD pthread_mutex_t CO_CAN_VALID_mtx = PTHREAD_MUTEX_INITIALIZER; #endif @@ -70,12 +83,15 @@ static CO_OD_storage_t odStor; /* Object Dictionary storage obj static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ static char *odStorFile_rom = "od_storage"; /* Name of the file */ static char *odStorFile_eeprom = "od_storage_auto"; /* Name of the file */ -static CO_time_t CO_time; /* Object for current time */ +#ifdef CO_USE_309 static in_port_t CO_command_socket_tcp_port = 60000; /* default port when used in tcp gateway mode */ - +#endif +#if CO_NO_TRACE > 0 +static CO_time_t CO_time; /* Object for current time */ +#endif /* Realtime thread */ -#ifndef CO_SINGLE_THREAD +#ifdef CO_MULTI_THREAD static void* rt_thread(void* arg); static pthread_t rt_thread_id; static int rt_thread_epoll_fd; @@ -110,12 +126,12 @@ fprintf(stderr, "Options:\n" " -i CANopen Node-id (1..127). If not specified, value from\n" " Object dictionary (0x2101) is used.\n" -" -p Realtime priority of RT task (RT disabled by default).\n" +" -p Realtime priority of RT thread (RT disabled by default).\n" " -r Enable reboot on CANopen NMT reset_node command. \n" " -s Set Filename for OD storage ('od_storage' is default).\n" " -a Set Filename for automatic storage variables from\n" " Object dictionary. ('od_storage_auto' is default).\n"); -#ifndef CO_SINGLE_THREAD +#ifdef CO_USE_309 fprintf(stderr, " -c Enable command interface for master functionality. \n" " If socket path is specified as empty string \"\",\n" @@ -141,8 +157,9 @@ fprintf(stderr, /******************************************************************************/ int main (int argc, char *argv[]) { CO_NMT_reset_cmd_t reset = CO_RESET_NOT; + CO_ReturnError_t err; CO_ReturnError_t odStorStatus_rom, odStorStatus_eeprom; - int CANdevice0Index = 0; + intptr_t CANdevice0Index = 0; int opt; bool_t firstRun = true; @@ -150,7 +167,7 @@ int main (int argc, char *argv[]) { bool_t nodeIdFromArgs = false; /* True, if program arguments are used for CANopen Node Id */ int nodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ bool_t rebootEnable = false; /* Configurable by arguments */ -#ifndef CO_SINGLE_THREAD +#ifdef CO_USE_309 typedef enum CMD_MODE {CMD_NONE, CMD_LOCAL, CMD_REMOTE} cmdMode_t; cmdMode_t commandEnable = CMD_NONE; /* Configurable by arguments */ #endif @@ -170,7 +187,7 @@ int main (int argc, char *argv[]) { break; case 'p': rtPriority = strtol(optarg, NULL, 0); break; case 'r': rebootEnable = true; break; -#ifndef CO_SINGLE_THREAD +#ifdef CO_USE_309 case 'c': /* In case of empty string keep default name, just enable interface. */ if(strlen(optarg) != 0) { @@ -227,6 +244,14 @@ int main (int argc, char *argv[]) { printf("%s - starting CANopen device with Node ID %d(0x%02X)", argv[0], nodeId, nodeId); + /* Allocate memory for CANopen objects */ + err = CO_new(); + if (err != CO_ERROR_NO) { + fprintf(stderr, "Program init - %s - CO_new() failed.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Verify, if OD structures have proper alignment of initial values */ if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) { fprintf(stderr, "Program init - %s - Error in CO_OD_RAM.\n", argv[0]); @@ -259,12 +284,11 @@ int main (int argc, char *argv[]) { while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { /* CANopen communication reset - initialize CANopen objects *******************/ - CO_ReturnError_t err; printf("%s - communication reset ...\n", argv[0]); -#ifndef CO_SINGLE_THREAD +#ifdef CO_MULTI_THREAD /* Wait other threads (command interface). */ pthread_mutex_lock(&CO_CAN_VALID_mtx); #endif @@ -278,7 +302,7 @@ int main (int argc, char *argv[]) { /* Enter CAN configuration. */ - CO_CANsetConfigurationMode(CANdevice0Index); + CO_CANsetConfigurationMode((void *)CANdevice0Index); /* initialize CANopen */ @@ -286,7 +310,12 @@ int main (int argc, char *argv[]) { /* use value from Object dictionary, if not set by program arguments */ nodeId = OD_CANNodeID; } - err = CO_init(CANdevice0Index, nodeId, 0); + + err = CO_CANinit((void *)CANdevice0Index, 0 /* bit rate not used */); + if (err == CO_ERROR_NO) { + err = CO_CANopenInit(nodeId); + } + if(err != CO_ERROR_NO) { char s[120]; snprintf(s, 120, "Communication reset - CANopen initialization failed, err=%d", err); @@ -305,15 +334,16 @@ int main (int argc, char *argv[]) { } - /* Configure callback functions for task control */ - CO_EM_initCallback(CO->em, taskMain_cbSignal); - CO_SDO_initCallback(CO->SDO[0], taskMain_cbSignal); - CO_SDOclient_initCallback(CO->SDOclient, taskMain_cbSignal); + /* Configure callback functions for thread control */ +// CO_EM_initCallback(CO->em, threadMain_cbSignal); +// CO_SDO_initCallback(CO->SDO[0], threadMain_cbSignal); +// CO_SDOclient_initCallback(CO->SDOclient, threadMain_cbSignal); +#if CO_NO_TRACE > 0 /* Initialize time */ CO_time_init(&CO_time, CO->SDO[0], &OD_time.epochTimeBaseMs, &OD_time.epochTimeOffsetMs, 0x2130); - +#endif /* First time only initialization. */ if(firstRun) { @@ -325,33 +355,19 @@ int main (int argc, char *argv[]) { CO_errExit("Program init - epoll_create mainline failed"); /* Init mainline */ - taskMain_init(mainline_epoll_fd, &OD_performance[ODA_performance_mainCycleMaxTime]); - - -#ifdef CO_SINGLE_THREAD - /* Init taskRT */ - CANrx_taskTmr_init(mainline_epoll_fd, TMR_TASK_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); - - OD_performance[ODA_performance_timerCycleTime] = TMR_TASK_INTERVAL_NS/1000; /* informative */ + threadMain_init(mainline_epoll_fd, &OD_performance[ODA_performance_mainCycleMaxTime]); - /* Set priority for mainline */ - if(rtPriority > 0) { - struct sched_param param; - param.sched_priority = rtPriority; - if(sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) - CO_errExit("Program init - mainline set scheduler failed"); - } -#else +#ifdef CO_MULTI_THREAD /* Configure epoll for rt_thread */ rt_thread_epoll_fd = epoll_create(2); if(rt_thread_epoll_fd == -1) CO_errExit("Program init - epoll_create rt_thread failed"); - /* Init taskRT */ - CANrx_taskTmr_init(rt_thread_epoll_fd, TMR_TASK_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); + /* Init threadRT */ + CANrx_threadTmr_init(rt_thread_epoll_fd, TMR_THREAD_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); - OD_performance[ODA_performance_timerCycleTime] = TMR_TASK_INTERVAL_NS/1000; /* informative */ + OD_performance[ODA_performance_timerCycleTime] = TMR_THREAD_INTERVAL_NS/1000; /* informative */ /* Create rt_thread */ if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) @@ -365,9 +381,23 @@ int main (int argc, char *argv[]) { if(pthread_setschedparam(rt_thread_id, SCHED_FIFO, ¶m) != 0) CO_errExit("Program init - rt_thread set scheduler failed"); } +#else + /* Init threadRT */ + CANrx_threadTmr_init(mainline_epoll_fd, TMR_THREAD_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); + + OD_performance[ODA_performance_timerCycleTime] = TMR_THREAD_INTERVAL_NS/1000; /* informative */ + + /* Set priority for mainline */ + if(rtPriority > 0) { + struct sched_param param; + + param.sched_priority = rtPriority; + if(sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) + CO_errExit("Program init - mainline set scheduler failed"); + } #endif -#ifndef CO_SINGLE_THREAD +#ifdef CO_USE_309 /* Initialize socket command interface */ switch(commandEnable) { case CMD_LOCAL: @@ -387,18 +417,23 @@ int main (int argc, char *argv[]) { } #endif +#ifdef CO_USE_APPLICATION /* Execute optional additional application code */ app_programStart(); +#endif } +#ifdef CO_USE_APPLICATION /* Execute optional additional application code */ app_communicationReset(); +#endif /* start CAN */ CO_CANsetNormalMode(CO->CANmodule[0]); -#ifndef CO_SINGLE_THREAD + +#ifdef CO_MULTI_THREAD pthread_mutex_unlock(&CO_CAN_VALID_mtx); #endif @@ -421,18 +456,18 @@ int main (int argc, char *argv[]) { } } -#ifdef CO_SINGLE_THREAD - else if(CANrx_taskTmr_process(ev.data.fd)) { +#ifndef CO_MULTI_THREAD + else if(CANrx_threadTmr_process(ev.data.fd)) { /* code was processed in the above function. Additional code process below */ INCREMENT_1MS(CO_timer1ms); /* Detect timer large overflow */ - if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_TASK_OVERFLOW_US && rtPriority > 0) { + if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_THREAD_OVERFLOW_US && rtPriority > 0) { CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0x22400000L | OD_performance[ODA_performance_timerCycleMaxTime]); } } #endif - else if(taskMain_process(ev.data.fd, &reset, CO_timer1ms)) { + else if(threadMain_process(ev.data.fd, &reset, CO_timer1ms)) { uint16_t timer1msDiff; static uint16_t tmr1msPrev = 0; @@ -442,8 +477,10 @@ int main (int argc, char *argv[]) { /* code was processed in the above function. Additional code process below */ +#ifdef CO_USE_APPLICATION /* Execute optional additional application code */ app_programAsync(timer1msDiff); +#endif CO_OD_storage_autoSave(&odStorAuto, CO_timer1ms, 60000); } @@ -458,7 +495,7 @@ int main (int argc, char *argv[]) { /* program exit ***************************************************************/ /* join threads */ -#ifndef CO_SINGLE_THREAD +#ifdef CO_USE_309 switch (commandEnable) { case CMD_LOCAL: @@ -475,23 +512,25 @@ int main (int argc, char *argv[]) { #endif CO_endProgram = 1; -#ifndef CO_SINGLE_THREAD +#ifdef CO_MULTI_THREAD if(pthread_join(rt_thread_id, NULL) != 0) { CO_errExit("Program end - pthread_join failed"); } #endif +#ifdef CO_USE_APPLICATION /* Execute optional additional application code */ app_programEnd(); +#endif /* Store CO_OD_EEPROM */ CO_OD_storage_autoSave(&odStorAuto, 0, 0); CO_OD_storage_autoSaveClose(&odStorAuto); /* delete objects from memory */ - CANrx_taskTmr_close(); - taskMain_close(); - CO_delete(CANdevice0Index); + CANrx_threadTmr_close(); + threadMain_close(); + CO_delete((void *)CANdevice0Index); printf("%s on %s (nodeId=0x%02X) - finished.\n\n", argv[0], CANdevice, nodeId); @@ -507,8 +546,8 @@ int main (int argc, char *argv[]) { } -#ifndef CO_SINGLE_THREAD -/* Realtime thread for CAN receive and taskTmr ********************************/ +#ifdef CO_MULTI_THREAD +/* Realtime thread for CAN receive and threadTmr ******************************/ static void* rt_thread(void* arg) { /* Endless loop */ @@ -524,25 +563,27 @@ static void* rt_thread(void* arg) { } } - else if(CANrx_taskTmr_process(ev.data.fd)) { + else if(CANrx_threadTmr_process(ev.data.fd)) { int i; /* code was processed in the above function. Additional code process below */ INCREMENT_1MS(CO_timer1ms); +#if CO_NO_TRACE > 0 /* Monitor variables with trace objects */ CO_time_process(&CO_time); -#if CO_NO_TRACE > 0 for(i=0; itrace[i], *CO_time.epochTimeOffsetMs); } #endif +#ifdef CO_USE_APPLICATION /* Execute optional additional application code */ app_program1ms(); +#endif /* Detect timer large overflow */ - if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_TASK_OVERFLOW_US && rtPriority > 0 && CO->CANmodule[0]->CANnormal) { + if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_THREAD_OVERFLOW_US && rtPriority > 0 && CO->CANmodule[0]->CANnormal) { CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0x22400000L | OD_performance[ODA_performance_timerCycleMaxTime]); } } @@ -555,4 +596,4 @@ static void* rt_thread(void* arg) { return NULL; } -#endif +#endif /* CO_MULTI_THREAD */ From 8fb48173c65db56757721d42339d25d749439ac8 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 26 Feb 2020 17:09:56 +0100 Subject: [PATCH 024/520] Add CO_CANopenInitCallback() into CANopen.h/.c. Change CO_*_initCallback() functions - add 'void *object' argument. --- 301/CO_Emergency.c | 9 ++++++--- 301/CO_Emergency.h | 9 ++++++--- 301/CO_SDOclient.c | 11 +++++++---- 301/CO_SDOclient.h | 8 ++++++-- 301/CO_SDOserver.c | 7 +++++-- 301/CO_SDOserver.h | 8 ++++++-- CANopen.c | 17 +++++++++++++++++ CANopen.h | 15 +++++++++++++++ doc/CHANGELOG.md | 1 + socketCAN/CO_Linux_threads.c | 33 +++------------------------------ 10 files changed, 72 insertions(+), 46 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index b7f93738..f383c936 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -160,6 +160,7 @@ CO_ReturnError_t CO_EM_init( em->bufFull = 0U; em->wrongErrorReport = 0U; em->pFunctSignal = NULL; + em->functSignalObject = NULL; em->pFunctSignalRx = NULL; emPr->em = em; emPr->errorRegister = errorRegister; @@ -205,9 +206,11 @@ CO_ReturnError_t CO_EM_init( /******************************************************************************/ void CO_EM_initCallback( CO_EM_t *em, - void (*pFunctSignal)(void)) + void *object, + void (*pFunctSignal)(void *object)) { if(em != NULL){ + em->functSignalObject = object; em->pFunctSignal = pFunctSignal; } } @@ -391,7 +394,7 @@ void CO_errorReport(CO_EM_t *em, const uint8_t errorBit, const uint16_t errorCod /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */ if(em->pFunctSignal != NULL) { - em->pFunctSignal(); + em->pFunctSignal(em->functSignalObject); } } } @@ -450,7 +453,7 @@ void CO_errorReset(CO_EM_t *em, const uint8_t errorBit, const uint32_t infoCode) /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */ if(em->pFunctSignal != NULL) { - em->pFunctSignal(); + em->pFunctSignal(em->functSignalObject); } } } diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 87e293a6..0d8fabab 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -262,9 +262,10 @@ typedef struct{ uint8_t *bufReadPtr; /**< Read pointer in the above buffer */ uint8_t bufFull; /**< True if above buffer is full */ uint8_t wrongErrorReport; /**< Error in arguments to CO_errorReport() */ - /** From CO_EM_initCallback() or NULL */ - void (*pFunctSignal)(void); + void (*pFunctSignal)(void *object); + /** From CO_EM_initCallback() or NULL */ + void *functSignalObject; /** From CO_EM_initCallbackRx() or NULL */ void (*pFunctSignalRx)(const uint16_t ident, const uint16_t errorCode, @@ -394,11 +395,13 @@ CO_ReturnError_t CO_EM_init( * which processes mainline CANopen functions. * * @param em This object. + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_EM_initCallback( CO_EM_t *em, - void (*pFunctSignal)(void)); + void *object, + void (*pFunctSignal)(void *object)); /** diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 3815cca9..d0287431 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -162,7 +162,7 @@ static void CO_SDOclient_receive(void *object, void *msg){ /* Optional signal to RTOS, which can resume task, which handles SDO client. */ if(CO_FLAG_READ(SDO_C->CANrxNew) && SDO_C->pFunctSignal != NULL) { - SDO_C->pFunctSignal(); + SDO_C->pFunctSignal(SDO_C->functSignalObject); } } } @@ -195,6 +195,7 @@ CO_ReturnError_t CO_SDOclient_init( SDO_C->SDOClientPar = SDOClientPar; SDO_C->pFunctSignal = NULL; + SDO_C->functSignalObject = NULL; SDO_C->CANdevRx = CANdevRx; SDO_C->CANdevRxIdx = CANdevRxIdx; @@ -214,9 +215,11 @@ CO_ReturnError_t CO_SDOclient_init( /******************************************************************************/ void CO_SDOclient_initCallback( CO_SDOclient_t *SDOclient, - void (*pFunctSignal)(void)) + void *object, + void (*pFunctSignal)(void *object)) { if(SDOclient != NULL){ + SDOclient->functSignalObject = object; SDOclient->pFunctSignal = pFunctSignal; } } @@ -360,7 +363,7 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( /* Optional signal to RTOS. We can immediately continue SDO Client */ if(SDO_C->pFunctSignal != NULL) { - SDO_C->pFunctSignal(); + SDO_C->pFunctSignal(SDO_C->functSignalObject); } return CO_SDOcli_ok_communicationEnd; @@ -814,7 +817,7 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( /* Optional signal to RTOS. We can immediately continue SDO Client */ if(SDO_C->pFunctSignal != NULL) { - SDO_C->pFunctSignal(); + SDO_C->pFunctSignal(SDO_C->functSignalObject); } return CO_SDOcli_ok_communicationEnd; diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 28df959e..ac74c8cc 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -134,7 +134,9 @@ typedef struct{ /** 8 data bytes of the received message */ uint8_t CANrxData[8]; /** From CO_SDOclient_initCallback() or NULL */ - void (*pFunctSignal)(void); + void (*pFunctSignal)(void *object); + /** From CO_SDOclient_initCallback() or NULL */ + void *functSignalObject; /** From CO_SDOclient_init() */ CO_CANmodule_t *CANdevTx; /** CAN transmit buffer inside CANdevTx for CAN tx message */ @@ -200,11 +202,13 @@ CO_ReturnError_t CO_SDOclient_init( * which processes mainline CANopen functions. * * @param SDOclient This object. + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_SDOclient_initCallback( CO_SDOclient_t *SDOclient, - void (*pFunctSignal)(void)); + void *object, + void (*pFunctSignal)(void *object)); /** diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index bd5c278a..8c0506c0 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -240,7 +240,7 @@ static void CO_SDO_receive(void *object, void *msg){ /* Optional signal to RTOS, which can resume task, which handles SDO server. */ if(CO_FLAG_READ(SDO->CANrxNew) && SDO->pFunctSignal != NULL) { - SDO->pFunctSignal(); + SDO->pFunctSignal(SDO->functSignalObject); } } } @@ -322,6 +322,7 @@ CO_ReturnError_t CO_SDO_init( SDO->state = CO_SDO_ST_IDLE; CO_FLAG_CLEAR(SDO->CANrxNew); SDO->pFunctSignal = NULL; + SDO->functSignalObject = NULL; /* Configure Object dictionary entry at index 0x1200 */ @@ -361,9 +362,11 @@ CO_ReturnError_t CO_SDO_init( /******************************************************************************/ void CO_SDO_initCallback( CO_SDO_t *SDO, - void (*pFunctSignal)(void)) + void *object, + void (*pFunctSignal)(void *object)) { if(SDO != NULL){ + SDO->functSignalObject = object; SDO->pFunctSignal = pFunctSignal; } } diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 213b5e4b..fb49a5d0 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -630,7 +630,9 @@ typedef struct{ /** Variable indicates, if new SDO message received from CAN bus */ volatile void *CANrxNew; /** From CO_SDO_initCallback() or NULL */ - void (*pFunctSignal)(void); + void (*pFunctSignal)(void *object); + /** From CO_SDO_initCallback() or NULL */ + void *functSignalObject; /** From CO_SDO_init() */ CO_CANmodule_t *CANdevTx; /** CAN transmit buffer inside CANdev for CAN tx message */ @@ -788,11 +790,13 @@ CO_ReturnError_t CO_SDO_init( * which processes mainline CANopen functions. * * @param SDO This object. + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_SDO_initCallback( CO_SDO_t *SDO, - void (*pFunctSignal)(void)); + void *object, + void (*pFunctSignal)(void *object)); /** diff --git a/CANopen.c b/CANopen.c index e2a3f25f..9e3b8d46 100644 --- a/CANopen.c +++ b/CANopen.c @@ -626,6 +626,23 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { } +/******************************************************************************/ +void CO_CANopenInitCallback(void *object, + void (*pFunctSignal)(void *object)) +{ + CO_SDO_initCallback(CO->SDO[0], object, pFunctSignal); + CO_EM_initCallback(CO->em, object, pFunctSignal); +#if CO_NO_SDO_CLIENT != 0 + for (i = 0; i < CO_NO_SDO_CLIENT; i++) { + CO_SDOclient_initCallback(CO->SDOclient[i], object, pFunctSignal); + } +#endif +#if CO_NO_LSS_CLIENT == 1 + CO_LSSmaster_initCallback(CO->LSSmaster, object, pFunctSignal); +#endif +} + + /******************************************************************************/ CO_NMT_reset_cmd_t CO_process(CO_t *co, uint32_t timeDifference_us, diff --git a/CANopen.h b/CANopen.h index 765c7dbb..10bc4960 100644 --- a/CANopen.h +++ b/CANopen.h @@ -273,6 +273,21 @@ CO_ReturnError_t CO_LSSinit(uint8_t nodeId, CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); +/** + * Initialize callback functions. + * + * Function initializes optional callback functions, which executes after + * internal state of some CANopen object changes. For example, after CAN message + * is received or error condition is changed. Function may wake up external + * task, which processes mainline CANopen functions. + * + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL + * @param pFunctSignal Pointer to the callback function. Not called if NULL. + */ +void CO_CANopenInitCallback(void *object, + void (*pFunctSignal)(void *object)); + + /** * Process CANopen objects. * diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 4cdf7138..92160184 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -17,6 +17,7 @@ Change Log - Rename in CO_driver_target.h: `IS_CANrxNew` -> `CO_FLAG_READ`, `SET_CANrxNew` -> `CO_FLAG_SET`, `CLEAR_CANrxNew` -> `CO_FLAG_CLEAR` - CO_driver.h file, function `CO_CANrxBufferInit()`, last argument (callback) changed from `(*pFunct)(void *object, const CO_CANrxMsg_t *message)` to `void (*CANrx_callback)(void *object, void *message)`. New functions are defined in `CO_driver_target.h` file: `CO_CANrxMsg_readIdent()`, `CO_CANrxMsg_readDLC()` and `CO_CANrxMsg_readData()`. - It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. +- Added `void *object` argument CO_*_initCallback() functions. Added CO_CANopenInitCallback() into CANopen.h/.c. ### Fixed - Bugfix in `CO_HBconsumer_process()`: argument `timeDifference_us` was set to 0 inside for loop, fixed now. - BUG in CO_HBconsumer.c #168 diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index 242b05d4..8ac31257 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -44,45 +44,18 @@ static uint64_t CO_LinuxThreads_clock_gettime_ms(void) static struct { uint64_t start; /* time value CO_process() was called last time in ms */ - void (*pFunct)(void* object); /* Callback function */ - void *object; } threadMain; -/** - * This function notifies the user application after an event happened - * - * This is necessary because not all stack callbacks support object pointers. - * It is not used for those callbacks that have this pointer! - */ -static void threadMain_resumeCallback(void) -{ - if (threadMain.pFunct != NULL) { - threadMain.pFunct(threadMain.object); - } -} - void threadMain_init(void (*callback)(void*), void *object) { threadMain.start = CO_LinuxThreads_clock_gettime_ms(); - threadMain.pFunct = callback; - threadMain.object = object; - - CO_SDO_initCallback(CO->SDO[0], threadMain_resumeCallback); - CO_EM_initCallback(CO->em, threadMain_resumeCallback); -#if CO_NO_LSS_CLIENT == 1 - CO_LSSmaster_initCallback(CO->LSSmaster, threadMain.object, threadMain.pFunct); -#endif -#if CO_NO_SDO_CLIENT != 0 - for (int i = 0; i < CO_NO_SDO_CLIENT; i++) { - CO_SDOclient_initCallback(CO->SDOclient[i], threadMain_resumeCallback); - } -#endif + + CO_CANopenInitCallback(object, callback); } void threadMain_close(void) { - threadMain.pFunct = NULL; - threadMain.object = NULL; + CO_CANopenInitCallback(NULL, NULL); } void threadMain_process(CO_NMT_reset_cmd_t *reset) From 22e66b7bb44615902198815609a87d05bbc7c4ef Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 27 Feb 2020 13:27:05 +0100 Subject: [PATCH 025/520] socketCAN/CO_Linux_threads - CANrx_threadTmr_init(uint16_t interval_in_milliseconds (changed to) uint32_t interval_in_microseconds) - other timing updated --- doc/CHANGELOG.md | 7 +++++-- socketCAN/CO_Linux_threads.c | 37 ++++++++++++++++++------------------ socketCAN/CO_Linux_threads.h | 27 +++++++++++++------------- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 92160184..e7e69b50 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -18,13 +18,16 @@ Change Log - CO_driver.h file, function `CO_CANrxBufferInit()`, last argument (callback) changed from `(*pFunct)(void *object, const CO_CANrxMsg_t *message)` to `void (*CANrx_callback)(void *object, void *message)`. New functions are defined in `CO_driver_target.h` file: `CO_CANrxMsg_readIdent()`, `CO_CANrxMsg_readDLC()` and `CO_CANrxMsg_readData()`. - It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. - Added `void *object` argument CO_*_initCallback() functions. Added CO_CANopenInitCallback() into CANopen.h/.c. +### Changed SocketCAN +- ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN +- driver API updated +- CO_Linux_threads.h, function `void CANrx_threadTmr_init(uint16_t interval_in_milliseconds (changed to) uint32_t interval_in_microseconds)` ### Fixed - Bugfix in `CO_HBconsumer_process()`: argument `timeDifference_us` was set to 0 inside for loop, fixed now. - BUG in CO_HBconsumer.c #168 ### Added - Documentation added to `doc` directory: CHANGELOG.md, deviceSupport.md, gettingStarted.md, LSSusage.md and traceUsage.md. -- All CANopen objects calculates next timer info for OS. -- Basic Linux socketCAN example. +- All CANopen objects calculates next timer info for OS. Useful for energy saving. [Unreleased master] ------------------- diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index 8ac31257..27368459 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -2,9 +2,10 @@ * Helper functions for implementing CANopen threads in Linux * * @file Linux_threads.c - * @ingroup CO_driver - * @author Janez Paternoster, Martin Wagner - * @copyright 2004 - 2015 Janez Paternoster, 2017 - 2020 Neuberger Gebaeudeautomation GmbH + * @author Janez Paternoster + * @author Martin Wagner + * @copyright 2004 - 2015 Janez Paternoster + * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH * * * This file is part of CANopenNode, an opensource CANopen Stack. @@ -27,28 +28,28 @@ #include #include #include +#include -#include "301/CO_driver.h" #include "CANopen.h" -/* Helper function - get monotonic clock time in ms */ -static uint64_t CO_LinuxThreads_clock_gettime_ms(void) +/* Helper function - get monotonic clock time in microseconds */ +static uint64_t CO_LinuxThreads_clock_gettime_us(void) { struct timespec ts; (void)clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; } -/* Mainline thread (threadMain) ***************************************************/ +/* Mainline thread (threadMain) ***********************************************/ static struct { - uint64_t start; /* time value CO_process() was called last time in ms */ + uint64_t start; /* time value CO_process() was called last time in us */ } threadMain; void threadMain_init(void (*callback)(void*), void *object) { - threadMain.start = CO_LinuxThreads_clock_gettime_ms(); + threadMain.start = CO_LinuxThreads_clock_gettime_us(); CO_CANopenInitCallback(object, callback); } @@ -61,17 +62,17 @@ void threadMain_close(void) void threadMain_process(CO_NMT_reset_cmd_t *reset) { uint32_t finished; - uint16_t diff; + uint32_t diff; uint64_t now; - now = CO_LinuxThreads_clock_gettime_ms(); - diff = (uint16_t)(now - threadMain.start); + now = CO_LinuxThreads_clock_gettime_us(); + diff = (uint32_t)(now - threadMain.start); /* we use timerNext_us in CO_process() as indication if processing is * finished. We ignore any calculated values for maximum delay times. */ do { finished = 1; - *reset = CO_process(CO, (uint32_t)diff*1000, &finished); + *reset = CO_process(CO, diff, &finished); diff = 0; } while ((*reset == CO_RESET_NOT) && (finished == 0)); @@ -79,22 +80,22 @@ void threadMain_process(CO_NMT_reset_cmd_t *reset) threadMain.start = now; } -/* Realtime thread (threadRT) *****************************************************/ +/* Realtime thread (threadRT) *************************************************/ static struct { uint32_t us_interval; /* configured interval in us */ int interval_fd; /* timer fd */ } threadRT; -void CANrx_threadTmr_init(uint16_t interval) +void CANrx_threadTmr_init(uint32_t interval_us) { struct itimerspec itval; - threadRT.us_interval = interval * 1000; + threadRT.us_interval = interval_us; /* set up non-blocking interval timer */ threadRT.interval_fd = timerfd_create(CLOCK_MONOTONIC, 0); (void)fcntl(threadRT.interval_fd, F_SETFL, O_NONBLOCK); itval.it_interval.tv_sec = 0; - itval.it_interval.tv_nsec = interval * 1000000; + itval.it_interval.tv_nsec = interval_us * 1000; itval.it_value = itval.it_interval; (void)timerfd_settime(threadRT.interval_fd, 0, &itval, NULL); } diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index 2bbff23e..7374639d 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -2,9 +2,10 @@ * Helper functions for implementing CANopen threads in Linux. * * @file CO_Linux_threads.h - * @ingroup CO_driver - * @author Janez Paternoster, Martin Wagner - * @copyright 2004 - 2015 Janez Paternoster, 2018 - 2020 Neuberger Gebaeudeautomation GmbH + * @author Janez Paternoster + * @author Martin Wagner + * @copyright 2004 - 2015 Janez Paternoster + * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH * * * This file is part of CANopenNode, an opensource CANopen Stack. @@ -24,19 +25,19 @@ * limitations under the License. */ -#ifndef CO_LINUX_TASKS_H -#define CO_LINUX_TASKS_H +#ifndef CO_LINUX_THREADS_H +#define CO_LINUX_THREADS_H #ifdef __cplusplus extern "C" { #endif -/* This driver is loosely based upon the CO socketCAN driver - * The "threads" inside this driver do not fork threads themselve, but require +/* + * The "threads" specified here do not fork threads themselves, but require * that two threads are provided by the calling application. * - * Like the CO socketCAN driver implementation, this driver uses the global CO - * object and has one thread-local struct for variables. */ + * It uses the global CO object and has one thread-local struct for variables. + */ /** * Initialize mainline thread. @@ -78,10 +79,10 @@ extern void threadMain_process(CO_NMT_reset_cmd_t *reset); * @remark If realtime is required, this thread must be registred as such in the Linux * kernel. * - * @param interval Interval of periodic timer in ms, recommended value for - * realtime response: 1ms + * @param interval Interval of periodic timer in microseconds, recommended value + * for realtime response: 1000 us */ -extern void CANrx_threadTmr_init(uint16_t interval); +extern void CANrx_threadTmr_init(uint32_t interval_us); /** * Terminate realtime thread. @@ -100,4 +101,4 @@ extern void CANrx_threadTmr_process(); } #endif /*__cplusplus*/ -#endif +#endif /* CO_LINUX_THREADS_H */ From 3fc564b72fc336969c4c738f5180128b71c9728a Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 27 Feb 2020 15:25:59 +0100 Subject: [PATCH 026/520] Remove CO_CANopenInitCallback() from CANopen.h/.c (revert) --- CANopen.c | 17 ----------------- CANopen.h | 15 --------------- doc/CHANGELOG.md | 2 +- socketCAN/CO_Linux_threads.c | 6 ++++-- 4 files changed, 5 insertions(+), 35 deletions(-) diff --git a/CANopen.c b/CANopen.c index 9e3b8d46..e2a3f25f 100644 --- a/CANopen.c +++ b/CANopen.c @@ -626,23 +626,6 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { } -/******************************************************************************/ -void CO_CANopenInitCallback(void *object, - void (*pFunctSignal)(void *object)) -{ - CO_SDO_initCallback(CO->SDO[0], object, pFunctSignal); - CO_EM_initCallback(CO->em, object, pFunctSignal); -#if CO_NO_SDO_CLIENT != 0 - for (i = 0; i < CO_NO_SDO_CLIENT; i++) { - CO_SDOclient_initCallback(CO->SDOclient[i], object, pFunctSignal); - } -#endif -#if CO_NO_LSS_CLIENT == 1 - CO_LSSmaster_initCallback(CO->LSSmaster, object, pFunctSignal); -#endif -} - - /******************************************************************************/ CO_NMT_reset_cmd_t CO_process(CO_t *co, uint32_t timeDifference_us, diff --git a/CANopen.h b/CANopen.h index 10bc4960..765c7dbb 100644 --- a/CANopen.h +++ b/CANopen.h @@ -273,21 +273,6 @@ CO_ReturnError_t CO_LSSinit(uint8_t nodeId, CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); -/** - * Initialize callback functions. - * - * Function initializes optional callback functions, which executes after - * internal state of some CANopen object changes. For example, after CAN message - * is received or error condition is changed. Function may wake up external - * task, which processes mainline CANopen functions. - * - * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL - * @param pFunctSignal Pointer to the callback function. Not called if NULL. - */ -void CO_CANopenInitCallback(void *object, - void (*pFunctSignal)(void *object)); - - /** * Process CANopen objects. * diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index e7e69b50..1ad534f1 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -17,7 +17,7 @@ Change Log - Rename in CO_driver_target.h: `IS_CANrxNew` -> `CO_FLAG_READ`, `SET_CANrxNew` -> `CO_FLAG_SET`, `CLEAR_CANrxNew` -> `CO_FLAG_CLEAR` - CO_driver.h file, function `CO_CANrxBufferInit()`, last argument (callback) changed from `(*pFunct)(void *object, const CO_CANrxMsg_t *message)` to `void (*CANrx_callback)(void *object, void *message)`. New functions are defined in `CO_driver_target.h` file: `CO_CANrxMsg_readIdent()`, `CO_CANrxMsg_readDLC()` and `CO_CANrxMsg_readData()`. - It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. -- Added `void *object` argument CO_*_initCallback() functions. Added CO_CANopenInitCallback() into CANopen.h/.c. +- Added `void *object` argument to CO_*_initCallback() functions. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN - driver API updated diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index 27368459..e147a283 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -51,12 +51,14 @@ void threadMain_init(void (*callback)(void*), void *object) { threadMain.start = CO_LinuxThreads_clock_gettime_us(); - CO_CANopenInitCallback(object, callback); + CO_SDO_initCallback(CO->SDO[0], object, callback); + CO_EM_initCallback(CO->em, object, callback); } void threadMain_close(void) { - CO_CANopenInitCallback(NULL, NULL); + CO_SDO_initCallback(CO->SDO[0], NULL, NULL); + CO_EM_initCallback(CO->em, NULL, NULL); } void threadMain_process(CO_NMT_reset_cmd_t *reset) From 78487ba89f74319826eab0a64a333b7c441e1126 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 27 Feb 2020 16:24:53 +0100 Subject: [PATCH 027/520] Clarify EM, SDOserver, SDOclient and LSSmaster callback functions. callback functions called also from SDO_blockTransferInProgress. Clarify timerNext_us parameter to CO_process() function. --- 301/CO_Emergency.h | 8 +++++--- 301/CO_SDOclient.c | 11 ++++++++--- 301/CO_SDOclient.h | 10 ++++++---- 301/CO_SDOserver.c | 5 ++++- 301/CO_SDOserver.h | 7 ++++--- 305/CO_LSSmaster.c | 2 +- 305/CO_LSSmaster.h | 7 ++++--- CANopen.h | 15 ++++++++++----- doc/CHANGELOG.md | 2 +- 9 files changed, 43 insertions(+), 24 deletions(-) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 0d8fabab..555280c7 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -390,9 +390,11 @@ CO_ReturnError_t CO_EM_init( /** * Initialize Emergency callback function. * - * Function initializes optional callback function, which executes after - * error condition is changed. Function may wake up external task, - * which processes mainline CANopen functions. + * Function initializes optional callback function, which should immediately + * start processing of CO_EM_process() function. + * Callback is called from CO_errorReport() or CO_errorReset() function. Those + * functions are fast and may be called from any thread. Callback should + * immediately start mainline thread, which calls CO_EM_process() function. * * @param em This object. * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index d0287431..fbfeb148 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -708,9 +708,14 @@ CO_SDOclient_return_t CO_SDOclientDownload( else if (SDO_C->block_seqno >= SDO_C->block_blksize) { SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK; } - else if (timerNext_us != NULL) { - /* Set timerNext_us to 0 to inform OS to call this function again without delay. */ - *timerNext_us = 0; + else { + /* Inform OS to call this function again without delay. */ + if (timerNext_us != NULL) { + *timerNext_us = 0; + } + if (SDO_C->pFunctSignal != NULL) { + SDO_C->pFunctSignal(SDO_C->functSignalObject); + } } /* tx data */ diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index ac74c8cc..eb7da311 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -195,11 +195,13 @@ CO_ReturnError_t CO_SDOclient_init( /** - * Initialize SDOclientRx callback function. + * Initialize SDOclient callback function. * - * Function initializes optional callback function, which is called after new - * message is received from the CAN bus. Function may wake up external task, - * which processes mainline CANopen functions. + * Function initializes optional callback function, which should immediately + * start processing of CO_SDOclientDownload() or CO_SDOclientUpload() function. + * Callback is called after SDOclient message is received from the CAN bus or + * when new call without delay is necessary (exchange data with own SDO server + * or SDO block transfer is in progress). * * @param SDOclient This object. * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 8c0506c0..b74184a5 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1438,10 +1438,13 @@ int8_t CO_SDO_process( /* send response */ CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - /* Set timerNext_us to 0 to inform OS to call this function again without delay. */ + /* Inform OS to call this function again without delay. */ if (timerNext_us != NULL) { *timerNext_us = 0; } + if (SDO->pFunctSignal != NULL) { + SDO->pFunctSignal(SDO->functSignalObject); + } /* don't call CO_FLAG_CLEAR, so return directly */ return 1; diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index fb49a5d0..9f1ddfe3 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -785,9 +785,10 @@ CO_ReturnError_t CO_SDO_init( /** * Initialize SDOrx callback function. * - * Function initializes optional callback function, which is called after new - * message is received from the CAN bus. Function may wake up external task, - * which processes mainline CANopen functions. + * Function initializes optional callback function, which should immediately + * start processing of CO_SDO_process() function. + * Callback is called after SDOserver message is received from the CAN bus or + * when new call without delay is necessary (SDO block transfer is in progress). * * @param SDO This object. * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 49136335..75a54c59 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -96,7 +96,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) CO_FLAG_SET(LSSmaster->CANrxNew); - /* Optional signal to RTOS, which can resume task, which handles SDO client. */ + /* Optional signal to RTOS, which can resume task, which handles further processing. */ if(LSSmaster->pFunctSignal != NULL) { LSSmaster->pFunctSignal(LSSmaster->functSignalObject); } diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 48cfd8f8..f2d4404a 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -187,9 +187,10 @@ void CO_LSSmaster_changeTimeout( /** * Initialize LSSmasterRx callback function. * - * Function initializes optional callback function, which is called after new - * message is received from the CAN bus. Function may wake up external task, - * which processes mainline CANopen functions. + * Function initializes optional callback function, which should immediately + * start further LSS processing. Callback is called after LSS message is + * received from the CAN bus. It should signal the RTOS to resume corresponding + * task. * * @param LSSmaster This object. * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL diff --git a/CANopen.h b/CANopen.h index 765c7dbb..67b4335a 100644 --- a/CANopen.h +++ b/CANopen.h @@ -282,12 +282,17 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); * @param co CANopen object. * @param timeDifference_us Time difference from previous function call in * microseconds. - * @param timerNext_us [out] info to OS - maximum delay after function + * @param timerNext_us [out] info to OS - maximum delay time after this function * should be called next time in [microseconds]. Value can be used for OS - * sleep time. Initial value must be set to something, 50000us typically. - * Output will be equal or lower to initial value. If there is new object - * to process, delay should be suspended and this function should be - * called immediately. Parameter is ignored if NULL. + * sleep time. Initial value must be set to maximum interval time. + * Output will be equal or lower to initial value. Calculation is based + * on various timers which expire in known time. Parameter should be + * used in combination with callbacks configured with + * CO_EM_initCallback() and CO_SDO_initCallback(). Those callbacks should + * also trigger calling of CO_process() function. + * + * This is experimental feature and can be used for energy saving in case + * of low traffic on CAN bus. Parameter is ignored if NULL. * * @return #CO_NMT_reset_cmd_t from CO_NMT_process(). */ diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 1ad534f1..b437ab05 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -17,7 +17,7 @@ Change Log - Rename in CO_driver_target.h: `IS_CANrxNew` -> `CO_FLAG_READ`, `SET_CANrxNew` -> `CO_FLAG_SET`, `CLEAR_CANrxNew` -> `CO_FLAG_CLEAR` - CO_driver.h file, function `CO_CANrxBufferInit()`, last argument (callback) changed from `(*pFunct)(void *object, const CO_CANrxMsg_t *message)` to `void (*CANrx_callback)(void *object, void *message)`. New functions are defined in `CO_driver_target.h` file: `CO_CANrxMsg_readIdent()`, `CO_CANrxMsg_readDLC()` and `CO_CANrxMsg_readData()`. - It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. -- Added `void *object` argument to CO_*_initCallback() functions. +- Added `void *object` argument to CO_*_initCallback() functions. API clarified. Callback functions called also from SDO_blockTransferInProgress. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN - driver API updated From d40c1e1c960875734a1c185ac8cb949ae5274f2b Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 28 Feb 2020 10:08:11 +0100 Subject: [PATCH 028/520] Manual merge from updates in master branch - socketCAN --- socketCAN/CO_Linux_threads.c | 6 ++- socketCAN/CO_driver.c | 100 +++++++++++++++++++---------------- socketCAN/CO_driver_target.h | 25 +++++---- socketCAN/CO_error.c | 13 +++-- socketCAN/CO_error.h | 4 +- socketCAN/CO_msgs.h | 95 +++++++++++++++++++++++++++++++++ 6 files changed, 175 insertions(+), 68 deletions(-) create mode 100644 socketCAN/CO_msgs.h diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index e147a283..d6b84e0e 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -125,9 +125,13 @@ void CANrx_threadTmr_process(void) if(CO->CANmodule[0]->CANnormal) { for (i = 0; i <= missed; i++) { + +#if CO_NO_SYNC == 1 /* Process Sync */ syncWas = CO_process_SYNC(CO, threadRT.us_interval, NULL); - +#else + syncWas = false; +#endif /* Read inputs */ CO_process_RPDO(CO, syncWas); diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 9f6f76c4..82b48756 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -36,9 +36,13 @@ #include "301/CO_driver.h" -#if defined CO_DRIVER_ERROR_REPORTING && __has_include("syslog/log.h") - #include "syslog/log.h" - #include "msgs.h" +#if defined CO_DRIVER_ERROR_REPORTING + #if __has_include("syslog1/log.h") + #include "syslog/log.h" + #include "msgs.h" + #else + #include "CO_msgs.h" + #endif #else #define log_printf(macropar_prio, macropar_message, ...) #endif @@ -52,7 +56,7 @@ pthread_mutex_t CO_EMCY_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; #ifndef CO_DRIVER_MULTI_INTERFACE -static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, int32_t CANbaseAddress); +static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, const void *CANptr); #endif #ifdef CO_DRIVER_MULTI_INTERFACE @@ -175,7 +179,7 @@ static CO_ReturnError_t setRxFilters(CO_CANmodule_t *CANmodule) /******************************************************************************/ void CO_CANsetConfigurationMode(void *CANptr) { - /* Can't do anything because no object is provided */ + /* Can't do anything because no reference to CANmodule_t is provided */ } @@ -272,7 +276,7 @@ CO_ReturnError_t CO_CANmodule_init( rxArray[i].object = NULL; rxArray[i].CANrx_callback = NULL; #ifdef CO_DRIVER_MULTI_INTERFACE - rxArray[i].CANbaseAddress = -1; + rxArray[i].CANptr = NULL; rxArray[i].timestamp.tv_sec = 0; rxArray[i].timestamp.tv_nsec = 0; #endif @@ -280,8 +284,7 @@ CO_ReturnError_t CO_CANmodule_init( #ifndef CO_DRIVER_MULTI_INTERFACE /* add one interface */ - intptr_t CANaddr = (intptr_t)CANptr; - ret = CO_CANmodule_addInterface(CANmodule, (int32_t)CANaddr); + ret = CO_CANmodule_addInterface(CANmodule, CANptr); if (ret != CO_ERROR_NO) { CO_CANmodule_disable(CANmodule); } @@ -298,7 +301,7 @@ static #endif CO_ReturnError_t CO_CANmodule_addInterface( CO_CANmodule_t *CANmodule, - int32_t CANbaseAddress) + const void *CANptr) { int32_t ret; int32_t tmp; @@ -312,7 +315,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( can_err_mask_t err_mask; #endif - if (CANmodule->CANnormal) { + if (CANmodule->CANnormal != false) { /* can't change config now! */ return CO_ERROR_INVALID_STATE; } @@ -327,8 +330,8 @@ CO_ReturnError_t CO_CANmodule_addInterface( } interface = &CANmodule->CANinterfaces[CANmodule->CANinterfaceCount - 1]; - interface->CANbaseAddress = CANbaseAddress; - ifName = if_indextoname(CANbaseAddress, interface->ifName); + interface->CANptr = CANptr; + ifName = if_indextoname((uintptr_t)interface->CANptr, interface->ifName); if (ifName == NULL) { log_printf(LOG_DEBUG, DBG_ERRNO, "if_indextoname()"); return CO_ERROR_ILLEGAL_ARGUMENT; @@ -376,7 +379,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( /* bind socket */ memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.can_family = AF_CAN; - sockAddr.can_ifindex = CANbaseAddress; + sockAddr.can_ifindex = (uintptr_t)interface->CANptr; ret = bind(interface->fd, (struct sockaddr*)&sockAddr, sizeof(sockAddr)); if(ret < 0){ log_printf(LOG_ERR, CAN_BINDING_FAILED, interface->ifName); @@ -506,7 +509,7 @@ CO_ReturnError_t CO_CANrxBufferInit( buffer->object = object; buffer->CANrx_callback = CANrx_callback; #ifdef CO_DRIVER_MULTI_INTERFACE - buffer->CANbaseAddress = -1; + buffer->CANptr = NULL; buffer->timestamp.tv_nsec = 0; buffer->timestamp.tv_sec = 0; #endif @@ -538,36 +541,35 @@ CO_ReturnError_t CO_CANrxBufferInit( /******************************************************************************/ bool_t CO_CANrxBuffer_getInterface( CO_CANmodule_t *CANmodule, - uint32_t ident, - int32_t *CANbaseAddressRx, + uint16_t ident, + const void **const CANptrRx, struct timespec *timestamp) { - if (CANmodule != NULL){ - uint32_t index; - CO_CANrx_t *buffer; + CO_CANrx_t *buffer; - index = CO_CANgetIndexFromIdent(CANmodule->rxIdentToIndex, ident); - if ((index == CO_INVALID_COB_ID) || (index > CANmodule->rxSize)) { - return false; - } - buffer = &CANmodule->rxArray[index]; + if (CANmodule == NULL){ + return false; + } - /* return values */ - if (CANbaseAddressRx != NULL) { - *CANbaseAddressRx = buffer->CANbaseAddress; - } - if (timestamp != NULL) { - *timestamp = buffer->timestamp; - } + const uint32_t index = CO_CANgetIndexFromIdent(CANmodule->rxIdentToIndex, ident); + if ((index == CO_INVALID_COB_ID) || (index > CANmodule->rxSize)) { + return false; + } + buffer = &CANmodule->rxArray[index]; - if (buffer->CANbaseAddress >= 0) { - return true; - } - else { - return false; - } + /* return values */ + if (CANptrRx != NULL) { + *CANptrRx = buffer->CANptr; + } + if (timestamp != NULL) { + *timestamp = buffer->timestamp; + } + if (buffer->CANptr != NULL) { + return true; + } + else { + return false; } - return false; } #endif @@ -592,7 +594,7 @@ CO_CANtx_t *CO_CANtxBufferInit( CO_CANsetIdentToIndex(CANmodule->txIdentToIndex, index, ident, buffer->ident); #endif - buffer->CANbaseAddress = -1; + buffer->CANptr = NULL; /* CAN identifier and rtr */ buffer->ident = ident & CAN_SFF_MASK; @@ -612,8 +614,8 @@ CO_CANtx_t *CO_CANtxBufferInit( /******************************************************************************/ CO_ReturnError_t CO_CANtxBuffer_setInterface( CO_CANmodule_t *CANmodule, - uint32_t ident, - int32_t CANbaseAddressTx) + uint16_t ident, + const void *CANptrTx) { if (CANmodule != NULL) { uint32_t index; @@ -622,7 +624,7 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface( if ((index == CO_INVALID_COB_ID) || (index > CANmodule->txSize)) { return CO_ERROR_PARAMETERS; } - CANmodule->txArray[index].CANbaseAddress = CANbaseAddressTx; + CANmodule->txArray[index].CANptr = CANptrTx; return CO_ERROR_NO; } @@ -743,8 +745,8 @@ CO_ReturnError_t CO_CANCheckSend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) for (i = 0; i < CANmodule->CANinterfaceCount; i++) { CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; - if (buffer->CANbaseAddress < 0 || - buffer->CANbaseAddress == interface->CANbaseAddress) { + if ((buffer->CANptr == NULL) || + buffer->CANptr == interface->CANptr) { CO_ReturnError_t tmp; @@ -890,7 +892,9 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff { int32_t retval; int32_t ret; - int32_t CANbaseAddress __attribute__((unused)); +#ifdef CO_DRIVER_MULTI_INTERFACE + const void *CANptr; +#endif CO_ReturnError_t err; CO_CANinterface_t *interface = NULL; struct epoll_event ev[1]; @@ -949,8 +953,10 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff interface = &CANmodule->CANinterfaces[i]; if (ev[0].data.fd == interface->fd) { +#ifdef CO_DRIVER_MULTI_INTERFACE /* get interface handle */ - CANbaseAddress = interface->CANbaseAddress; + CANdriverState = interface->CANptr; +#endif /* get message */ err = CO_CANread(CANmodule, interface, &msg, ×tamp); if (err != CO_ERROR_NO) { @@ -989,7 +995,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff #ifdef CO_DRIVER_MULTI_INTERFACE /* Store message info */ CANmodule->rxArray[msgIndex].timestamp = timestamp; - CANmodule->rxArray[msgIndex].CANbaseAddress = CANbaseAddress; + CANmodule->rxArray[msgIndex].CANptr = CANptr; #endif } retval = msgIndex; diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 53ef9dc2..5577ac9c 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -129,7 +129,6 @@ static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg) { } - /* Received message object */ typedef struct { uint32_t ident; @@ -138,7 +137,7 @@ typedef struct { void (*CANrx_callback)(void *object, void *message); #ifdef CO_DRIVER_MULTI_INTERFACE /* info about last received message */ - int32_t CANbaseAddress; /* CAN Interface identifier */ + const void *CANptr; /* CAN Interface identifier */ struct timespec timestamp; /* time of reception */ #endif } CO_CANrx_t; @@ -231,12 +230,12 @@ static inline void CO_UNLOCK_OD() { * Function must be called after CO_CANmodule_init. * * @param CANmodule This object will be initialized. - * @param CANbaseAddress CAN module base address. + * @param CANptr CAN module interface index (return value if_nametoindex(), NO pointer!). * @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, - int32_t CANbaseAddress); + const void *CANptr); /* * Check on which interface the last message for one message buffer was received @@ -246,7 +245,7 @@ CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, * * @param CANmodule This object. * @param ident 11-bit standard CAN Identifier. - * @param [out] CANbaseAddressRx message was received on this interface + * @param [out] CANptrRx 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 @@ -254,8 +253,8 @@ CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, * @retval true base address and timestamp are valid */ bool_t CO_CANrxBuffer_getInterface(CO_CANmodule_t *CANmodule, - uint32_t ident, - int32_t *CANbaseAddressRx, + uint16_t ident, + const void **const CANptrRx, struct timespec *timestamp); /* @@ -264,26 +263,26 @@ bool_t CO_CANrxBuffer_getInterface(CO_CANmodule_t *CANmodule, * 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 "-1" is used, a message is transmitted on + * 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 CANbaseAddressTx use this interface. -1 = not specified + * @param CANptrTx 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, - int32_t CANbaseAddressTx); -#endif + uint16_t ident, + const void *CANptrTx); +#endif /* CO_DRIVER_MULTI_INTERFACE */ /* * 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) + * - automatic mode (call callback that is set by #CO_CANrxBufferInit() function) * - manual mode (evaluate message filters, return received message) * * Both modes can be combined. diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index 25d3bc1a..f0a0db36 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -32,10 +32,13 @@ #include "301/CO_driver.h" #include "CO_error.h" - -#if defined CO_DRIVER_ERROR_REPORTING && __has_include("syslog/log.h") - #include "syslog/log.h" - #include "msgs.h" +#if defined CO_DRIVER_ERROR_REPORTING + #if __has_include("syslog/log.h") + #include "syslog/log.h" + #include "msgs.h" + #else + #include "CO_msgs.h" + #endif #else #define log_printf(macropar_prio, macropar_message, ...) #endif @@ -192,7 +195,7 @@ void CO_CANerror_init( } CANerrorhandler->fd = fd; - CANerrorhandler->ifName = ifName; + memcpy(CANerrorhandler->ifName, ifName, sizeof(CANerrorhandler->ifName)); CANerrorhandler->noackCounter = 0; CANerrorhandler->listenOnly = false; CANerrorhandler->timestamp.tv_sec = 0; diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 732c1a80..0db38c0b 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -71,11 +71,11 @@ typedef enum { */ typedef struct { int fd; /**< interface FD */ - const char *ifName; /**< interface name as string */ + char ifName[IFNAMSIZ]; /**< interface name as string */ uint32_t noackCounter; - volatile unsigned char listenOnly; /**< set to listen only mode */ + volatile bool_t listenOnly; /**< set to listen only mode */ struct timespec timestamp; /**< listen only mode started at this time */ } CO_CANinterfaceErrorhandler_t; diff --git a/socketCAN/CO_msgs.h b/socketCAN/CO_msgs.h new file mode 100644 index 00000000..9a3d8369 --- /dev/null +++ b/socketCAN/CO_msgs.h @@ -0,0 +1,95 @@ +/** + * CAN module object for Linux socketCAN. + * + * This file is a template for other microcontrollers. + * + * @file CO_msgs.h + * @ingroup CO_driver + * @author Martin Wagner + * @copyright 2020 Neuberger Gebaeudeautomation GmbH + * + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CO_MSGS_H +#define CO_MSGS_H + +#include +#include +#include "CO_msgs.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * message printing function + */ +#define log_printf(macropar_prio, macropar_message, ...) \ + if (macropar_prio < LOG_DEBUG) { \ + printf(macropar_message, ##__VA_ARGS__); \ + } + +/* + * message logging function. You need to open the log previous to this. + */ +//#define log_printf(macropar_prio, macropar_message, ...) syslog(macropar_prio, macropar_message, ##__VA_ARGS__); + + + +/* + * Message definitions for Linux CANopen socket driver (notice and errors) + */ +#define CAN_NOT_FOUND "CAN Interface \"%s\" not found" +#define CAN_INIT_FAILED "CAN Interface \"%s\" Init failed" +#define CAN_NAMETOINDEX "Interface \"%s\" -> Index %d" +#define CAN_SOCKET_BUF_SIZE "CAN Interface \"%s\" Buffer set to %d messages (%d Bytes)" +#define CAN_BINDING_FAILED "Binding CAN Interface \"%s\" failed" +#define CAN_ERROR_FILTER_FAILED "Setting CAN Interface \"%s\" error filter failed" +#define CAN_FILTER_FAILED "Setting CAN Interface \"%s\" message filter failed" +#define CAN_RX_SOCKET_QUEUE_OVERFLOW "CAN Interface \"%s\" has lost %d messages" +#define CAN_BUSOFF "CAN Interface \"%s\" changed to \"Bus Off\". Switching to Listen Only mode..." +#define CAN_NOACK "CAN Interface \"%s\" no \"ACK\" received. Switching to Listen Only mode..." +#define CAN_RX_PASSIVE "CAN Interface \"%s\" changed state to \"Rx Passive\"" +#define CAN_TX_PASSIVE "CAN Interface \"%s\" changed state to \"Tx Passive\"" +#define CAN_TX_LEVEL_ACTIVE "CAN Interface \"%s\" changed state to \"Active\"" +#define CAN_RX_BUF_OVERFLOW "CAN Interface \"%s\" Rx buffer overflow. Message dropped" +#define CAN_TX_BUF_OVERFLOW "CAN Interface \"%s\" Tx buffer overflow. Message dropped" +#define CAN_RX_LEVEL_WARNING "CAN Interface \"%s\" reached Rx Warning Level" +#define CAN_TX_LEVEL_WARNING "CAN Interface \"%s\" reached Tx Warning Level" + +/* + * Debug + */ +#define DBG_ERRNO "(%s) OS error \"%s\" in %s", __func__, strerror(errno) +#define DBG_CAN_TX_FAILED "(%s) Transmitting CAN msg OID 0x%08x failed(%s)", __func__ +#define DBG_CAN_RX_PARAM_FAILED "(%s) Setting CAN rx buffer failed (%s)", __func__ +#define DBG_CAN_RX_FAILED "(%s) Receiving CAN msg failed (%s)", __func__ +#define DBG_CAN_ERROR_GENERAL "(%s) Socket error msg ID: 0x%08x, Data[0..7]: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x (%s)", __func__ +#define DBG_CAN_RX_EPOLL "(%s) CAN Epoll error (0x%02x - %s)", __func__ +#define DBG_CAN_SET_LISTEN_ONLY "(%s) %s Set Listen Only", __func__ +#define DBG_CAN_CLR_LISTEN_ONLY "(%s) %s Leave Listen Only", __func__ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/** @} */ +#endif From f21cde9ab0261f8aa44695b7a912172204ef79fd Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 28 Feb 2020 16:37:41 +0100 Subject: [PATCH 029/520] doxygen socketCAN + some simplifications. --- Doxyfile | 1 + socketCAN/CO_Linux_threads.h | 18 +++++++-- socketCAN/CO_OD_storage.h | 26 ++++++++++-- socketCAN/CO_driver.c | 28 ++++++------- socketCAN/CO_driver_target.h | 7 ++-- socketCAN/CO_error.c | 12 ------ socketCAN/CO_error.h | 51 +++++++++++++++++++++--- socketCAN/{CO_msgs.h => CO_error_msgs.h} | 40 +++++++------------ socketCAN/CO_notify_pipe.c | 5 +-- socketCAN/CO_notify_pipe.h | 19 ++++----- 10 files changed, 125 insertions(+), 82 deletions(-) rename socketCAN/{CO_msgs.h => CO_error_msgs.h} (85%) diff --git a/Doxyfile b/Doxyfile index 6a86b043..458bef71 100644 --- a/Doxyfile +++ b/Doxyfile @@ -786,6 +786,7 @@ INPUT = README.md \ 301 \ 305 \ extra \ + socketCAN # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index 7374639d..75695274 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -2,6 +2,7 @@ * Helper functions for implementing CANopen threads in Linux. * * @file CO_Linux_threads.h + * @ingroup CO_socketCAN * @author Janez Paternoster * @author Martin Wagner * @copyright 2004 - 2015 Janez Paternoster @@ -32,10 +33,17 @@ extern "C" { #endif -/* +/** + * @defgroup CO_socketCAN socketCAN + * @{ + * + * Linux specific interface to CANopenNode + * + * CANopenNode runs in two threads: timer based realtime thread for CAN receive, + * SYNC and PDO and mainline thread for other processing. + * * The "threads" specified here do not fork threads themselves, but require * that two threads are provided by the calling application. - * * It uses the global CO object and has one thread-local struct for variables. */ @@ -79,8 +87,8 @@ extern void threadMain_process(CO_NMT_reset_cmd_t *reset); * @remark If realtime is required, this thread must be registred as such in the Linux * kernel. * - * @param interval Interval of periodic timer in microseconds, recommended value - * for realtime response: 1000 us + * @param interval_us Interval of periodic timer in microseconds, recommended + * value for realtime response: 1000 us */ extern void CANrx_threadTmr_init(uint32_t interval_us); @@ -97,6 +105,8 @@ extern void CANrx_threadTmr_close(void); */ extern void CANrx_threadTmr_process(); +/** @} */ + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/socketCAN/CO_OD_storage.h b/socketCAN/CO_OD_storage.h index 965a7ad2..2d2c5257 100644 --- a/socketCAN/CO_OD_storage.h +++ b/socketCAN/CO_OD_storage.h @@ -2,6 +2,7 @@ * CANopen Object Dictionary storage object for Linux SocketCAN. * * @file CO_OD_storage.h + * @ingroup CO_socketCAN * @author Janez Paternoster * @copyright 2015 - 2020 Janez Paternoster * @@ -32,14 +33,27 @@ #include +#ifdef __cplusplus +extern "C" { +#endif -/* For documentation see file drvTemplate/CO_OD_storage.h */ +/** + * @defgroup CO_OD_storage OD_storage + * @ingroup CO_socketCAN + * @{ + * + * Object Dictionary storage implementation for CANopenNode on Linux + */ /** - * Callbacks for using inside @ref CO_OD_configure() function (for OD objects 1010 and 1011). + * Callback for use inside @ref CO_OD_configure() function for OD object 1010 */ CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg); + +/** + * Callback for use inside @ref CO_OD_configure() function for OD object 1011 + */ CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg); @@ -148,4 +162,10 @@ CO_ReturnError_t CO_OD_storage_autoSave( */ void CO_OD_storage_autoSaveClose(CO_OD_storage_t *odStor); -#endif +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CO_OD_STORAGE_H */ diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 82b48756..f4b5b5fb 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -35,23 +35,14 @@ #include #include "301/CO_driver.h" - -#if defined CO_DRIVER_ERROR_REPORTING - #if __has_include("syslog1/log.h") - #include "syslog/log.h" - #include "msgs.h" - #else - #include "CO_msgs.h" - #endif -#else - #define log_printf(macropar_prio, macropar_message, ...) -#endif +#include "CO_error.h" #if __has_include("301/CO_Emergency.h") #include "301/CO_Emergency.h" #define USE_EMERGENCY_OBJECT #endif + pthread_mutex_t CO_EMCY_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -59,6 +50,7 @@ pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, const void *CANptr); #endif + #ifdef CO_DRIVER_MULTI_INTERFACE static const uint32_t CO_INVALID_COB_ID = 0xffffffff; @@ -106,10 +98,10 @@ static uint32_t CO_CANgetIndexFromIdent( return lookup[ident]; } -#endif +#endif /* CO_DRIVER_MULTI_INTERFACE */ -/** Disable socketCAN rx *****************************************************/ +/** Disable socketCAN rx ******************************************************/ static CO_ReturnError_t disableRx(CO_CANmodule_t *CANmodule) { int ret; @@ -132,6 +124,7 @@ static CO_ReturnError_t disableRx(CO_CANmodule_t *CANmodule) return retval; } + /** Set up or update socketCAN rx filters *************************************/ static CO_ReturnError_t setRxFilters(CO_CANmodule_t *CANmodule) { @@ -403,7 +396,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(can err)"); return CO_ERROR_SYSCALL; } -#endif +#endif /* CO_DRIVER_ERROR_REPORTING */ /* Add socket to epoll */ ev.events = EPOLLIN; @@ -572,7 +565,7 @@ bool_t CO_CANrxBuffer_getInterface( } } -#endif +#endif /* CO_DRIVER_MULTI_INTERFACE */ /******************************************************************************/ @@ -631,7 +624,7 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface( return CO_ERROR_PARAMETERS; } -#endif +#endif /* CO_DRIVER_MULTI_INTERFACE */ /******************************************************************************/ static CO_ReturnError_t CO_CANCheckSendInterface( @@ -779,6 +772,7 @@ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule) * Therefore, error counter evaluation is included in rx function.*/ } + /******************************************************************************/ static CO_ReturnError_t CO_CANread( CO_CANmodule_t *CANmodule, @@ -843,6 +837,7 @@ static CO_ReturnError_t CO_CANread( return CO_ERROR_NO; } + static int32_t CO_CANrxMsg( CO_CANmodule_t *CANmodule, struct can_frame *msg, @@ -887,6 +882,7 @@ static int32_t CO_CANrxMsg( return retval; } + /******************************************************************************/ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buffer) { diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 5577ac9c..1141525c 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -149,9 +149,8 @@ typedef struct { uint8_t padding[3]; /* ensure alignment */ uint8_t data[8]; volatile bool_t bufferFull; /* not used */ - volatile bool_t syncFlag; - /* info about transmit message */ - int32_t CANbaseAddress; /* CAN Interface identifier to use */ + volatile bool_t syncFlag; /* info about transmit message */ + const void *CANptr; /* CAN Interface identifier to use */ } CO_CANtx_t; @@ -160,7 +159,7 @@ typedef struct { /* socketCAN interface object */ typedef struct { - int32_t CANbaseAddress; /* CAN Interface identifier */ + const void *CANptr; /* CAN Interface identifier */ char ifName[IFNAMSIZ]; /* CAN Interface name */ int fd; /* socketCAN file descriptor */ #ifdef CO_DRIVER_ERROR_REPORTING diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index f0a0db36..a7db9380 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -2,7 +2,6 @@ * CAN module object for Linux socketCAN Error handling. * * @file CO_error.c - * @ingroup CO_driver * @author Martin Wagner * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH * @@ -32,17 +31,6 @@ #include "301/CO_driver.h" #include "CO_error.h" -#if defined CO_DRIVER_ERROR_REPORTING - #if __has_include("syslog/log.h") - #include "syslog/log.h" - #include "msgs.h" - #else - #include "CO_msgs.h" - #endif -#else - #define log_printf(macropar_prio, macropar_message, ...) -#endif - /** * Reset CAN interface and set to listen only mode diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 0db38c0b..9a0b56a9 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -1,8 +1,8 @@ /** - * CAN module object for Linux socketCAN Error handling. + * CANopenNode Linux socketCAN Error handling. * * @file CO_error.h - * @ingroup CO_driver + * @ingroup CO_socketCAN * @author Martin Wagner * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH * @@ -30,10 +30,46 @@ #include +#if __has_include("CO_error_custom.h") + #include "CO_error_custom.h" +#else + #include "CO_error_msgs.h" +#endif + #ifdef __cplusplus extern "C" { #endif +/** + * @defgroup CO_socketCAN_ERROR socketCAN_ERROR + * @ingroup CO_socketCAN + * @{ + * + * CANopen Errors and logging of messages + */ + +/** + * Message logging function. + * + * Default usage is to print messages into system log with syslog() call. By + * default system stores messages in /var/log/syslog file. + * Log can optionally be configured before, for example to filter out less + * critical errors than LOG_NOTICE, specify program name, print also process PID + * and print also to standard error, use: + * @code + * setlogmask (LOG_UPTO (LOG_NOTICE)); + * openlog ("exampleprog", LOG_PID | LOG_PERROR); + * @endcode + * + * @param priority one of LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, + * LOG_NOTICE, LOG_INFO, LOG_DEBUG + * @param format format string as in printf + */ +#ifdef CO_DOXYGEN +void log_printf(int priority, const char *format, ...); +#endif + + /** * driver interface state * @@ -75,10 +111,11 @@ typedef struct { uint32_t noackCounter; - volatile bool_t listenOnly; /**< set to listen only mode */ + volatile unsigned char listenOnly; /**< set to listen only mode */ struct timespec timestamp; /**< listen only mode started at this time */ } CO_CANinterfaceErrorhandler_t; + /** * Initialize CAN error handler * @@ -93,6 +130,7 @@ void CO_CANerror_init( int fd, const char *ifname); + /** * Reset CAN error handler * @@ -101,6 +139,7 @@ void CO_CANerror_init( void CO_CANerror_disable( CO_CANinterfaceErrorhandler_t *CANerrorhandler); + /** * Message received event * @@ -123,6 +162,7 @@ void CO_CANerror_rxMsg( CO_CANinterfaceState_t CO_CANerror_txMsg( CO_CANinterfaceErrorhandler_t *CANerrorhandler); + /** * Error message received event * @@ -137,9 +177,10 @@ CO_CANinterfaceState_t CO_CANerror_rxMsgError( const struct can_frame *msg); +/** @} */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* CO_ERROR_H */ diff --git a/socketCAN/CO_msgs.h b/socketCAN/CO_error_msgs.h similarity index 85% rename from socketCAN/CO_msgs.h rename to socketCAN/CO_error_msgs.h index 9a3d8369..c15a55c6 100644 --- a/socketCAN/CO_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -1,10 +1,7 @@ -/** - * CAN module object for Linux socketCAN. - * - * This file is a template for other microcontrollers. +/* + * Definitions for CANopenNode Linux socketCAN Error handling. * - * @file CO_msgs.h - * @ingroup CO_driver + * @file CO_Error_msgs.h * @author Martin Wagner * @copyright 2020 Neuberger Gebaeudeautomation GmbH * @@ -27,30 +24,23 @@ */ -#ifndef CO_MSGS_H -#define CO_MSGS_H - -#include -#include -#include "CO_msgs.h" +#ifndef CO_ERROR_MSGS_H +#define CO_ERROR_MSGS_H #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ +#endif -/* - * message printing function - */ -#define log_printf(macropar_prio, macropar_message, ...) \ - if (macropar_prio < LOG_DEBUG) { \ - printf(macropar_message, ##__VA_ARGS__); \ - } /* - * message logging function. You need to open the log previous to this. + * Message logging function. */ -//#define log_printf(macropar_prio, macropar_message, ...) syslog(macropar_prio, macropar_message, ##__VA_ARGS__); +#ifndef log_printf +#include +#define log_printf(macropar_prio, macropar_message, ...) \ + syslog(macropar_prio, macropar_message, ##__VA_ARGS__) +#endif /* @@ -74,8 +64,9 @@ extern "C" { #define CAN_RX_LEVEL_WARNING "CAN Interface \"%s\" reached Rx Warning Level" #define CAN_TX_LEVEL_WARNING "CAN Interface \"%s\" reached Tx Warning Level" + /* - * Debug + * Message definitions for debugging */ #define DBG_ERRNO "(%s) OS error \"%s\" in %s", __func__, strerror(errno) #define DBG_CAN_TX_FAILED "(%s) Transmitting CAN msg OID 0x%08x failed(%s)", __func__ @@ -91,5 +82,4 @@ extern "C" { } #endif /* __cplusplus */ -/** @} */ -#endif +#endif /* CO_ERROR_MSGS_H */ diff --git a/socketCAN/CO_notify_pipe.c b/socketCAN/CO_notify_pipe.c index a3988285..b9825827 100644 --- a/socketCAN/CO_notify_pipe.c +++ b/socketCAN/CO_notify_pipe.c @@ -7,10 +7,6 @@ #include "CO_notify_pipe.h" -struct CO_NotifyPipe { - int m_receiveFd; - int m_sendFd; -}; CO_NotifyPipe_t *CO_NotifyPipeCreate(void) { @@ -31,6 +27,7 @@ CO_NotifyPipe_t *CO_NotifyPipeCreate(void) return p; } + void CO_NotifyPipeFree(CO_NotifyPipe_t *p) { if (p == NULL) { diff --git a/socketCAN/CO_notify_pipe.h b/socketCAN/CO_notify_pipe.h index 52a46cc0..cf8dcb6f 100644 --- a/socketCAN/CO_notify_pipe.h +++ b/socketCAN/CO_notify_pipe.h @@ -2,7 +2,7 @@ * Notify pipe for Linux threads. * * @file CO_notify_pipe.h - * @ingroup CO_driver + * @ingroup CO_socketCAN * @author Martin Wagner * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * @@ -33,21 +33,26 @@ extern "C" { /** * @defgroup CO_pipe Pipe - * @ingroup CO_driver + * @ingroup CO_socketCAN * @{ * * This is needed to wake up the can socket when blocking in select */ /** - * Object + * Notify pipe object */ -typedef struct CO_NotifyPipe CO_NotifyPipe_t; +typedef struct { + int m_receiveFd; /**< File descriptor for receive */ + int m_sendFd; /**< File descriptor for send */ +} CO_NotifyPipe_t; + /** * Create Pipe * - * @return != null if successfully created + * @return pointer to CO_NotifyPipe_t object if successfully created or + * NULL on failure. */ CO_NotifyPipe_t *CO_NotifyPipeCreate(void); @@ -79,7 +84,3 @@ void CO_NotifyPipeSend(CO_NotifyPipe_t *p); #endif /*__cplusplus*/ #endif /* CO_NOTIFY_PIPE_H_ */ - -/** -* @} @} -**/ From 9d17b0d67114f89987d8ea4cd3a9c643bbd44903 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 29 Feb 2020 18:09:29 +0100 Subject: [PATCH 030/520] socketCAN driver: - Always enable CANptr and timestamp info in CO_CANrx_t. - Update documentation --- CANopen.h | 2 +- Doxyfile | 2 +- doc/CHANGELOG.md | 1 + socketCAN/CO_Linux_threads.c | 4 +- socketCAN/CO_Linux_threads.h | 59 ++++++++++------ socketCAN/CO_OD_storage.h | 4 +- socketCAN/CO_driver.c | 35 ++++----- socketCAN/CO_driver_target.h | 133 +++++++++++++++++++++-------------- socketCAN/CO_error.c | 1 + socketCAN/CO_error.h | 17 +++-- socketCAN/CO_notify_pipe.h | 4 +- 11 files changed, 149 insertions(+), 113 deletions(-) diff --git a/CANopen.h b/CANopen.h index 67b4335a..11db15fe 100644 --- a/CANopen.h +++ b/CANopen.h @@ -129,7 +129,7 @@ extern "C" { #ifdef CO_DOXYGEN /** - * @defgroup CO_NO_OBJ Number of CANopenNode communication objects. + * @defgroup CO_NO_OBJ Configuration * * Definitions specify, which and how many CANopenNode communication objects * will be used in current configuration. Usage of some objects is mandatory and diff --git a/Doxyfile b/Doxyfile index 458bef71..37c12f21 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2057,7 +2057,7 @@ PREDEFINED = CO_DOXYGEN \ CO_NO_SDO_CLIENT=1 \ CO_NO_NMT_MASTER=1 \ CO_NO_LSS_SERVER \ - CO_NO_LSS_CLIENT \ + CO_NO_LSS_CLIENT=1 \ CO_NO_TRACE=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index b437ab05..9a688221 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -37,6 +37,7 @@ Change Log - NMT self start functionality (OD object 1F80) implemented to strictly folow standard. Default value for object 1F80 have to be updated in OD editor. See README.md. ### Fixed - Various fixes. +- neuberger-socketCAN fixed. ### Added - CANopen TIME protocol added. diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index d6b84e0e..8051a349 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -111,9 +111,9 @@ void CANrx_threadTmr_close(void) void CANrx_threadTmr_process(void) { int32_t result; - int32_t i; + uint64_t i; bool_t syncWas; - unsigned long long missed; + uint64_t missed; result = CO_CANrxWait(CO->CANmodule[0], threadRT.interval_fd, NULL); if (result < 0) { diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index 75695274..f903c2c8 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -33,75 +33,90 @@ extern "C" { #endif + /** * @defgroup CO_socketCAN socketCAN * @{ * * Linux specific interface to CANopenNode * - * CANopenNode runs in two threads: timer based realtime thread for CAN receive, - * SYNC and PDO and mainline thread for other processing. + * CANopenNode runs in two threads: + * - timer based real-time thread for CAN receive, SYNC and PDO, see + * CANrx_threadTmr_process() + * - mainline thread for other processing, see threadMain_process() * * The "threads" specified here do not fork threads themselves, but require * that two threads are provided by the calling application. - * It uses the global CO object and has one thread-local struct for variables. */ + /** * Initialize mainline thread. * - * threadMain is non-realtime thread for CANopenNode processing. It is nonblocking - * and should be called cyclically in 50 ms intervals or less if necessary. This - * is indicated by the callback function. - * This thread processes CO_process() function from CANopen.c file. - * * @param callback this function is called to indicate #threadMain_process() has * work to do * @param object this pointer is given to _callback()_ */ extern void threadMain_init(void (*callback)(void*), void *object); + /** * Cleanup mainline thread. */ extern void threadMain_close(void); + /** * Process mainline thread. * - * Function must be called cyclically and after callback + * threadMain is non-realtime thread for CANopenNode processing. It is + * initialized by threadMain_init(). There is no configuration for CANopen + * objects. There is also no configuration for epool or interval timer or notify + * pipe. These must be specified externally. + * + * threadMain_process() calls CO_process() function for processing mainline + * CANopen objects. It is non-blocking and should be called cyclically in 50 ms + * intervals (typically). Function must also be called immediately after + * callback provided in threadMain_init() is called. * * @param reset return value from CO_process() function. */ extern void threadMain_process(CO_NMT_reset_cmd_t *reset); + /** * Initialize realtime thread. * - * CANrx_threadTmr is realtime thread for CANopenNode processing. It is nonblocking - * and must be executed at CAN message receive or periodically in 1ms (or something) - * intervals. Inside interval is processed CANopen SYNC message, RPDOs(inputs) - * and TPDOs(outputs). - * CANrx_threadTmr uses CAN socket from CO_driver.c - * - * @remark If realtime is required, this thread must be registred as such in the Linux - * kernel. - * * @param interval_us Interval of periodic timer in microseconds, recommended * value for realtime response: 1000 us */ extern void CANrx_threadTmr_init(uint32_t interval_us); + /** * Terminate realtime thread. */ extern void CANrx_threadTmr_close(void); + /** - * Process realtime thread. - * - * This function must be called inside an infinite loop. It blocks until either - * some event happens or a timer runs out. + * Process real-time thread. + * + * CANrx_threadTmr is realtime thread for CANopenNode processing. It is + * initialized by CANrx_threadTmr_init(). There is no configuration for CANopen + * objects. But configuration for epool event notification facility is included + * in CO_CANmodule_init() from CO_driver.c. Epool is configured to monitor the + * following file descriptors: notify pipe, CANrx sockets from all interfaces + * and interval timer. + * + * CANrx_threadTmr_process() blocks on epoll_wait(). This is implemented inside + * CO_CANrxWait() from CO_driver.c. New CAN message is processed in + * CANrx_threadTmr_process() function, which calls CO_process_SYNC(), + * CO_process_RPDO() and CO_process_TPDO() functions for each expired timer + * interval. This function must be called inside an infinite loop. + * + * @remark If realtime is required, this thread must be registered as such in + * the Linux kernel. */ extern void CANrx_threadTmr_process(); diff --git a/socketCAN/CO_OD_storage.h b/socketCAN/CO_OD_storage.h index 2d2c5257..24b4f2a6 100644 --- a/socketCAN/CO_OD_storage.h +++ b/socketCAN/CO_OD_storage.h @@ -2,7 +2,7 @@ * CANopen Object Dictionary storage object for Linux SocketCAN. * * @file CO_OD_storage.h - * @ingroup CO_socketCAN + * @ingroup CO_socketCAN_OD_storage * @author Janez Paternoster * @copyright 2015 - 2020 Janez Paternoster * @@ -38,7 +38,7 @@ extern "C" { #endif /** - * @defgroup CO_OD_storage OD_storage + * @defgroup CO_socketCAN_OD_storage OD storage * @ingroup CO_socketCAN * @{ * diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index f4b5b5fb..451e0097 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #include "301/CO_driver.h" #include "CO_error.h" @@ -268,11 +270,9 @@ CO_ReturnError_t CO_CANmodule_init( rxArray[i].mask = 0xFFFFFFFFU; rxArray[i].object = NULL; rxArray[i].CANrx_callback = NULL; -#ifdef CO_DRIVER_MULTI_INTERFACE rxArray[i].CANptr = NULL; rxArray[i].timestamp.tv_sec = 0; rxArray[i].timestamp.tv_nsec = 0; -#endif } #ifndef CO_DRIVER_MULTI_INTERFACE @@ -344,7 +344,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(ovfl)"); return CO_ERROR_SYSCALL; } -#ifdef CO_DRIVER_MULTI_INTERFACE + /* enable software time stamp mode (hardware timestamps do not work properly * on all devices)*/ tmp = (SOF_TIMESTAMPING_SOFTWARE | @@ -354,7 +354,6 @@ CO_ReturnError_t CO_CANmodule_addInterface( log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(timestamping)"); return CO_ERROR_SYSCALL; } -#endif //todo - modify rx buffer size? first one needs root //ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&bytes, sLen); @@ -501,11 +500,9 @@ CO_ReturnError_t CO_CANrxBufferInit( /* Configure object variables */ buffer->object = object; buffer->CANrx_callback = CANrx_callback; -#ifdef CO_DRIVER_MULTI_INTERFACE buffer->CANptr = NULL; buffer->timestamp.tv_nsec = 0; buffer->timestamp.tv_sec = 0; -#endif /* CAN identifier and CAN mask, bit aligned with CAN module */ buffer->ident = ident & CAN_SFF_MASK; @@ -626,7 +623,7 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface( #endif /* CO_DRIVER_MULTI_INTERFACE */ -/******************************************************************************/ +/* send CAN message ***********************************************************/ static CO_ReturnError_t CO_CANCheckSendInterface( CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer, @@ -773,12 +770,12 @@ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule) } -/******************************************************************************/ +/* Read CAN message from socket and verify some errors ************************/ static CO_ReturnError_t CO_CANread( CO_CANmodule_t *CANmodule, CO_CANinterface_t *interface, - struct can_frame *msg, - struct timespec *timestamp) + struct can_frame *msg, /* CAN message, return value */ + struct timespec *timestamp) /* timestamp of CAN message, return value */ { int32_t n; uint32_t dropped; @@ -838,10 +835,11 @@ static CO_ReturnError_t CO_CANread( } -static int32_t CO_CANrxMsg( +/* find msg inside rxArray and call corresponding CANrx_callback **************/ +static int32_t CO_CANrxMsg( /* return index of received message in rxArray or -1 */ CO_CANmodule_t *CANmodule, - struct can_frame *msg, - CO_CANrxMsg_t *buffer) + struct can_frame *msg, /* CAN message input */ + CO_CANrxMsg_t *buffer) /* If not NULL, msg will be copied to buffer */ { int32_t retval; const CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ @@ -888,9 +886,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff { int32_t retval; int32_t ret; -#ifdef CO_DRIVER_MULTI_INTERFACE const void *CANptr; -#endif CO_ReturnError_t err; CO_CANinterface_t *interface = NULL; struct epoll_event ev[1]; @@ -938,7 +934,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff /* one of the sockets is ready */ if ((ev[0].data.fd == CO_NotifyPipeGetFd(CANmodule->pipe)) || (ev[0].data.fd == fdTimer)) { - /* timer/pipe socket */ + /* timer or notify pipe */ return -1; } else { @@ -949,10 +945,8 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff interface = &CANmodule->CANinterfaces[i]; if (ev[0].data.fd == interface->fd) { -#ifdef CO_DRIVER_MULTI_INTERFACE /* get interface handle */ - CANdriverState = interface->CANptr; -#endif + CANptr = interface->CANptr; /* get message */ err = CO_CANread(CANmodule, interface, &msg, ×tamp); if (err != CO_ERROR_NO) { @@ -983,16 +977,15 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff int32_t msgIndex; #ifdef CO_DRIVER_ERROR_REPORTING + /* clear listenOnly and noackCounter if necessary */ CO_CANerror_rxMsg(&interface->errorhandler); #endif msgIndex = CO_CANrxMsg(CANmodule, &msg, buffer); if (msgIndex > -1) { -#ifdef CO_DRIVER_MULTI_INTERFACE /* Store message info */ CANmodule->rxArray[msgIndex].timestamp = timestamp; CANmodule->rxArray[msgIndex].CANptr = CANptr; -#endif } retval = msgIndex; } diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 1141525c..a1782b62 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -1,7 +1,8 @@ -/* +/** * Linux socketCAN specific definitions for CANopenNode. * * @file CO_driver_target.h + * @ingroup CO_socketCAN_driver_target * @author Janez Paternoster * @author Martin Wagner * @copyright 2004 - 2020 Janez Paternoster @@ -25,15 +26,41 @@ */ +/* This file contains device and application specific definitions. + * It is included from CO_driver.h, which contains documentation + * for common definitions below. */ + #ifndef CO_DRIVER_TARGET #define CO_DRIVER_TARGET -/* This file contains device and application specific definitions. - * It is included from CO_driver.h, which contains documentation - * for definitions below. */ +#include +#include +#include +#include +#include +#include +#include + +#if __has_include("CO_driver_custom.h") + #include "CO_driver_custom.h" +#endif +#include "CO_notify_pipe.h" +#include "CO_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_socketCAN_driver_target CO_driver_target.h + * @ingroup CO_socketCAN + * @{ + * + * Linux socketCAN specific @ref CO_driver definitions for CANopenNode. + */ -/* - * @name multi interface support +/** + * Multi interface support * * Enable this to use interface combining at driver level. This * adds functions to broadcast/selective transmit messages on the @@ -51,40 +78,32 @@ * This is not intended to realize interface redundancy!!! */ /* #define CO_DRIVER_MULTI_INTERFACE */ +#ifdef CO_DOXYGEN +#define CO_DRIVER_MULTI_INTERFACE +#endif -/* - * @name CAN bus error reporting +/** + * CAN bus error reporting * * CO_DRIVER_ERROR_REPORTING enabled adds 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 functionality to be implemented... + * you need to enable error reporting in your kernel driver using: + * @code{.sh} + * ip link set canX type can berr-reporting on + * @endcode + * Of course, the kernel driver for your hardware needs this functionality to be + * implemented... */ -#ifndef CO_DRIVER_ERROR_REPORTING_DISABLE +/* #define CO_DRIVER_ERROR_REPORTING */ +#ifdef CO_DOXYGEN #define CO_DRIVER_ERROR_REPORTING #endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include "CO_notify_pipe.h" -#ifdef CO_DRIVER_ERROR_REPORTING - #include "CO_error.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif +/* skip this section for Doxygen, because it is documented in CO_driver.h */ +#ifndef CO_DOXYGEN /* Basic definitions */ #ifdef __BYTE_ORDER @@ -135,11 +154,9 @@ typedef struct { uint32_t mask; void *object; void (*CANrx_callback)(void *object, void *message); -#ifdef CO_DRIVER_MULTI_INTERFACE - /* info about last received message */ - const void *CANptr; /* CAN Interface identifier */ - struct timespec timestamp; /* time of reception */ -#endif + const void *CANptr; /* CAN Interface identifier from last + message */ + struct timespec timestamp; /* time of reception of last message */ } CO_CANrx_t; /* Transmit message object as aligned in socketCAN. */ @@ -182,7 +199,8 @@ typedef struct { volatile bool_t CANnormal; void *em; CO_NotifyPipe_t *pipe; /* Notification Pipe */ - int fdEpoll; /* epoll FD */ + int fdEpoll; /* epoll FD for pipe, CANrx sockets in all + interfaces and fdTimerRead */ int fdTimerRead; /* timer handle from CANrxWait() */ #ifdef CO_DRIVER_MULTI_INTERFACE /* Lookup tables Cob ID to rx/tx array index. @@ -221,9 +239,11 @@ static inline void CO_UNLOCK_OD() { #define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} #define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} +#endif /* CO_DOXYGEN */ + #ifdef CO_DRIVER_MULTI_INTERFACE -/* +/** * Add socketCAN interface to can driver * * Function must be called after CO_CANmodule_init. @@ -236,7 +256,7 @@ static inline void CO_UNLOCK_OD() { CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, const void *CANptr); -/* +/** * 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 @@ -256,7 +276,7 @@ bool_t CO_CANrxBuffer_getInterface(CO_CANmodule_t *CANmodule, const void **const CANptrRx, struct timespec *timestamp); -/* +/** * Set which interface should be used for message buffer transmission * * It is in the responsibility of the user to ensure that the correct interface @@ -277,26 +297,33 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface(CO_CANmodule_t *CANmodule, #endif /* CO_DRIVER_MULTI_INTERFACE */ -/* - * Functions receives CAN messages. It is blocking. +/** + * Functions receives CAN messages (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) + * This function waits for received CAN message, CAN error frame, notification + * pipe or fdTimer expiration. In case of CAN message it searches _rxArray_ from + * CO_CANmodule_t and if matched it calls the corresponding CANrx_callback, + * optionally copies received CAN message to _buffer_ and returns index of + * matched _rxArray_. * - * Both modes can be combined. + * This function can be used in two ways, which can be combined: + * - automatic mode: If CANrx_callback is specified for matched _rxArray_, then + * calls its callback. + * - manual mode: evaluate message filters, return received message * * @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 + * @param fdTimer File descriptor with activated timeout. If set to -1, then + * timer will not be used. File descriptor must be read + * externally if retval == -1! Read must be nonblocking and + * provides number of timer expirations since last read. + * @param [out] buffer Storage for received message or _NULL_ if not used. + * @retval >= 0 index of received message in array from CO_CANmodule_t + * _rxArray_, copy of CAN message is available in _buffer_. + * @retval -1 no message received (timer expired or notification pipe or error) */ -int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, - int fdTimer, - CO_CANrxMsg_t *buffer); +int32_t CO_CANrxWait(CO_CANmodule_t* CANmodule, int fdTimer, CO_CANrxMsg_t* buffer); + +/** @} */ #ifdef __cplusplus } diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index a7db9380..3faf65c2 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "301/CO_driver.h" diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 9a0b56a9..3594ff7b 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -2,7 +2,7 @@ * CANopenNode Linux socketCAN Error handling. * * @file CO_error.h - * @ingroup CO_socketCAN + * @ingroup CO_socketCAN_ERROR * @author Martin Wagner * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH * @@ -41,11 +41,11 @@ extern "C" { #endif /** - * @defgroup CO_socketCAN_ERROR socketCAN_ERROR + * @defgroup CO_socketCAN_ERROR CAN errors & Log * @ingroup CO_socketCAN * @{ * - * CANopen Errors and logging of messages + * CANopen Errors and System message log */ /** @@ -108,9 +108,7 @@ typedef enum { typedef struct { int fd; /**< interface FD */ char ifName[IFNAMSIZ]; /**< interface name as string */ - - uint32_t noackCounter; - + uint32_t noackCounter; /**< counts no ACK on CAN transmission */ volatile unsigned char listenOnly; /**< set to listen only mode */ struct timespec timestamp; /**< listen only mode started at this time */ } CO_CANinterfaceErrorhandler_t; @@ -143,7 +141,8 @@ void CO_CANerror_disable( /** * Message received event * - * when a message is received at least one other CAN module is connected + * When a message is received at least one other CAN module is connected. + * Function clears listenOnly and noackCounter error flags. * * @param CANerrorhandler CAN error object. */ @@ -154,7 +153,7 @@ void CO_CANerror_rxMsg( /** * Check if interface is ready for message transmission * - * message musn't be transmitted if not ready + * Message mustn't be transmitted if not ready. * * @param CANerrorhandler CAN error object. * @return CO_INTERFACE_ACTIVE message transmission ready @@ -166,7 +165,7 @@ CO_CANinterfaceState_t CO_CANerror_txMsg( /** * Error message received event * - * this handles all received error messages + * This handles all received error messages. * * @param CANerrorhandler CAN error object. * @param msg received error message diff --git a/socketCAN/CO_notify_pipe.h b/socketCAN/CO_notify_pipe.h index cf8dcb6f..d1002d37 100644 --- a/socketCAN/CO_notify_pipe.h +++ b/socketCAN/CO_notify_pipe.h @@ -2,7 +2,7 @@ * Notify pipe for Linux threads. * * @file CO_notify_pipe.h - * @ingroup CO_socketCAN + * @ingroup CO_socketCAN_notify_pipe * @author Martin Wagner * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * @@ -32,7 +32,7 @@ extern "C" { #endif /** - * @defgroup CO_pipe Pipe + * @defgroup CO_socketCAN_notify_pipe Notify pipe * @ingroup CO_socketCAN * @{ * From 02a734a83275a71df94e9f142610a47268405d93 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 2 Mar 2020 01:43:11 +0100 Subject: [PATCH 031/520] Move socketCAN/Makefile into base directory Partially update sockeCAN/main.c and rename to sockeCAN/CO_main_basic.c. Fix some warnings in socketCAN. --- .gitignore | 3 +- socketCAN/Makefile => Makefile | 25 +++---- example/Makefile | 13 ++-- socketCAN/CO_driver.c | 2 +- socketCAN/CO_error.c | 11 ++- socketCAN/CO_error.h | 4 + socketCAN/{main.c => CO_main_basic.c} | 102 ++++++++------------------ socketCAN/CO_notify_pipe.c | 7 +- 8 files changed, 70 insertions(+), 97 deletions(-) rename socketCAN/Makefile => Makefile (63%) rename socketCAN/{main.c => CO_main_basic.c} (85%) diff --git a/.gitignore b/.gitignore index 7b22621e..650a268e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -canopennode +/example/canopennode_blank +/canopend *.o doc/html/ diff --git a/socketCAN/Makefile b/Makefile similarity index 63% rename from socketCAN/Makefile rename to Makefile index 6b088c9c..0b3353b4 100644 --- a/socketCAN/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ -# Makefile for CANopenNode with socketCAN +# Makefile for CANopenNode with Linux socketCAN -DRV_SRC = . -CANOPEN_SRC = .. -OD_SRC = ../example -APPL_SRC = . +DRV_SRC = socketCAN +CANOPEN_SRC = . +OD_SRC = example +APPL_SRC = socketCAN -LINK_TARGET = canopensocket +LINK_TARGET = canopend INCLUDE_DIRS = \ @@ -37,20 +37,13 @@ SOURCES = \ $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ $(OD_SRC)/CO_OD.c \ - $(APPL_SRC)/main.c - - -# This can be a single or multi threaded application. If multithreaded is -# used, then two nonblocking threads will be used: fast rt-thread for CAN -# reception + PDO + SYNC processing and slow mainline for other processing. -# For multithreaded operation: -# - Add flag -DCO_MULTI_THREAD to the CFLAGS. -# - Add flag -pthread to LDFLAGS. + $(APPL_SRC)/CO_main_basic.c OBJS = $(SOURCES:%.c=%.o) CC ?= gcc -CFLAGS = -Wall -g $(INCLUDE_DIRS) -DCO_MULTI_THREAD +OPT = -Og +CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = -pthread diff --git a/example/Makefile b/example/Makefile index c6cc940f..c89dd380 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,17 +1,19 @@ -# Makefile for CANopenNode, basic compile with blank CAN device. +# Makefile for CANopenNode, basic compile with blank CAN device DRV_SRC = . CANOPEN_SRC = .. +OD_SRC = . APPL_SRC = . -LINK_TARGET = canopennode +LINK_TARGET = canopennode_blank INCLUDE_DIRS = \ -I$(DRV_SRC) \ -I$(CANOPEN_SRC) \ + -I$(OD_SRC) \ -I$(APPL_SRC) @@ -31,13 +33,14 @@ SOURCES = \ $(CANOPEN_SRC)/305/CO_LSSmaster.c \ $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ - $(APPL_SRC)/CO_OD.c \ + $(OD_SRC)/CO_OD.c \ $(APPL_SRC)/main_blank.c OBJS = $(SOURCES:%.c=%.o) -CC = gcc -CFLAGS = -Wall $(INCLUDE_DIRS) +CC ?= gcc +OPT = -g +CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 451e0097..6ee0db2a 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -886,7 +886,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff { int32_t retval; int32_t ret; - const void *CANptr; + const void *CANptr = NULL; CO_ReturnError_t err; CO_CANinterface_t *interface = NULL; struct epoll_event ev[1]; diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index 3faf65c2..165c8e08 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -26,10 +26,10 @@ #include #include #include +#include #include #include -#include "301/CO_driver.h" #include "CO_error.h" @@ -38,7 +38,7 @@ */ static CO_CANinterfaceState_t CO_CANerrorSetListenOnly( CO_CANinterfaceErrorhandler_t *CANerrorhandler, - bool_t resetIf) + unsigned char resetIf) { char command[100]; @@ -48,12 +48,17 @@ static CO_CANinterfaceState_t CO_CANerrorSetListenOnly( CANerrorhandler->listenOnly = true; if (resetIf) { + int ret; snprintf(command, sizeof(command), "ip link set %s down && " "ip link set %s up " "&", CANerrorhandler->ifName, CANerrorhandler->ifName); - system(command); + ret = system(command); + if(ret < 0){ + log_printf(LOG_DEBUG, DBG_ERRNO, "system()"); + } + } return CO_INTERFACE_LISTEN_ONLY; diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 3594ff7b..41008a4e 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -29,6 +29,10 @@ #define CO_ERROR_H #include +#include +#include +#include +#include #if __has_include("CO_error_custom.h") #include "CO_error_custom.h" diff --git a/socketCAN/main.c b/socketCAN/CO_main_basic.c similarity index 85% rename from socketCAN/main.c rename to socketCAN/CO_main_basic.c index f2f72400..57a74978 100644 --- a/socketCAN/main.c +++ b/socketCAN/CO_main_basic.c @@ -1,7 +1,7 @@ /* * CANopen main program file for Linux SocketCAN. * - * @file main + * @file main.c * @author Janez Paternoster * @copyright 2015 - 2020 Janez Paternoster * @@ -24,9 +24,6 @@ */ -#include "CANopen.h" -#include "CO_OD_storage.h" -#include "CO_Linux_threads.h" #include #include #include @@ -39,40 +36,37 @@ #include #include -#ifdef CO_USE_APPLICATION +#include "CANopen.h" +#include "CO_OD_storage.h" +#include "CO_notify_pipe.h" +#include "CO_error.h" +#include "CO_Linux_threads.h" + /* Call external application functions. */ -#include "application.h" +#if __has_include("CO_application.h") +#include "CO_application.h" +#define CO_USE_APPLICATION #endif +/* Add trace functionality for recording variables over time */ #if CO_NO_TRACE > 0 #include "CO_time_trace.h" #endif -#ifdef CO_USE_309 -/* Use DS309-3 standard - ASCII command interface to CANopen: NMT + LSS master, SDO client */ +/* Use DS309-3 standard - ASCII command interface to CANopen: NMT master, + * LSS master and SDO client */ +#ifdef CO_309 #include "CO_command.h" #endif -#ifdef CO_MULTI_THREAD -/* Use two nonblocking threads: fast rt-thread for CAN reception + PDO + SYNC - * processing and slow mainline for other processing. */ -#include +/* Interval of real-time thread in microseconds */ +#ifndef TMR_THREAD_INTERVAL_US +#define TMR_THREAD_INTERVAL_US 1000 #endif - -#define NSEC_PER_SEC (1000000000) /* The number of nanoseconds per second. */ -#define NSEC_PER_MSEC (1000000) /* The number of nanoseconds per millisecond. */ -#define TMR_THREAD_INTERVAL_NS (1000000) /* Interval of threadTmr in nanoseconds */ -#define TMR_THREAD_OVERFLOW_US (5000) /* Overflow detect limit for threadTmr in microseconds */ -#define INCREMENT_1MS(var) (var++) /* Increment 1ms variable in threadTmr */ - - -/* Global variable increments each millisecond. */ -volatile uint16_t CO_timer1ms = 0U; - -#ifdef CO_MULTI_THREAD +#ifdef CO_309 /* Mutex is locked, when CAN is not valid (configuration state). May be used - * from other threads. RT threads may use CO->CANmodule[0]->CANnormal instead. */ + * from command interface. RT threads may use CO->CANmodule[0]->CANnormal instead. */ pthread_mutex_t CO_CAN_VALID_mtx = PTHREAD_MUTEX_INITIALIZER; #endif @@ -83,7 +77,7 @@ static CO_OD_storage_t odStor; /* Object Dictionary storage obj static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ static char *odStorFile_rom = "od_storage"; /* Name of the file */ static char *odStorFile_eeprom = "od_storage_auto"; /* Name of the file */ -#ifdef CO_USE_309 +#ifdef CO_309 static in_port_t CO_command_socket_tcp_port = 60000; /* default port when used in tcp gateway mode */ #endif #if CO_NO_TRACE > 0 @@ -126,12 +120,13 @@ fprintf(stderr, "Options:\n" " -i CANopen Node-id (1..127). If not specified, value from\n" " Object dictionary (0x2101) is used.\n" -" -p Realtime priority of RT thread (RT disabled by default).\n" +" -p Real-time priority of RT thread (1 .. 99). If not set or\n" +" set to -1, then normal scheduler is used for RT thread.\n" " -r Enable reboot on CANopen NMT reset_node command. \n" " -s Set Filename for OD storage ('od_storage' is default).\n" " -a Set Filename for automatic storage variables from\n" " Object dictionary. ('od_storage_auto' is default).\n"); -#ifdef CO_USE_309 +#ifdef CO_309 fprintf(stderr, " -c Enable command interface for master functionality. \n" " If socket path is specified as empty string \"\",\n" @@ -147,7 +142,7 @@ fprintf(stderr, #endif fprintf(stderr, "\n" -"See also: https://github.com/CANopenNode/CANopenSocket\n" +"See also: https://github.com/CANopenNode/CANopenNode\n" "\n"); } @@ -167,7 +162,7 @@ int main (int argc, char *argv[]) { bool_t nodeIdFromArgs = false; /* True, if program arguments are used for CANopen Node Id */ int nodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ bool_t rebootEnable = false; /* Configurable by arguments */ -#ifdef CO_USE_309 +#ifdef CO_309 typedef enum CMD_MODE {CMD_NONE, CMD_LOCAL, CMD_REMOTE} cmdMode_t; cmdMode_t commandEnable = CMD_NONE; /* Configurable by arguments */ #endif @@ -187,7 +182,7 @@ int main (int argc, char *argv[]) { break; case 'p': rtPriority = strtol(optarg, NULL, 0); break; case 'r': rebootEnable = true; break; -#ifdef CO_USE_309 +#ifdef CO_309 case 'c': /* In case of empty string keep default name, just enable interface. */ if(strlen(optarg) != 0) { @@ -288,7 +283,7 @@ int main (int argc, char *argv[]) { printf("%s - communication reset ...\n", argv[0]); -#ifdef CO_MULTI_THREAD +#ifdef CO_309 /* Wait other threads (command interface). */ pthread_mutex_lock(&CO_CAN_VALID_mtx); #endif @@ -335,6 +330,7 @@ int main (int argc, char *argv[]) { /* Configure callback functions for thread control */ +// void CO_CANopenInitCallback(void *object, void (*pFunctSignal)(void *object)); // CO_EM_initCallback(CO->em, threadMain_cbSignal); // CO_SDO_initCallback(CO->SDO[0], threadMain_cbSignal); // CO_SDOclient_initCallback(CO->SDOclient, threadMain_cbSignal); @@ -367,8 +363,6 @@ int main (int argc, char *argv[]) { /* Init threadRT */ CANrx_threadTmr_init(rt_thread_epoll_fd, TMR_THREAD_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); - OD_performance[ODA_performance_timerCycleTime] = TMR_THREAD_INTERVAL_NS/1000; /* informative */ - /* Create rt_thread */ if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) CO_errExit("Program init - rt_thread creation failed"); @@ -381,23 +375,9 @@ int main (int argc, char *argv[]) { if(pthread_setschedparam(rt_thread_id, SCHED_FIFO, ¶m) != 0) CO_errExit("Program init - rt_thread set scheduler failed"); } -#else - /* Init threadRT */ - CANrx_threadTmr_init(mainline_epoll_fd, TMR_THREAD_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); - - OD_performance[ODA_performance_timerCycleTime] = TMR_THREAD_INTERVAL_NS/1000; /* informative */ - - /* Set priority for mainline */ - if(rtPriority > 0) { - struct sched_param param; - - param.sched_priority = rtPriority; - if(sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) - CO_errExit("Program init - mainline set scheduler failed"); - } #endif -#ifdef CO_USE_309 +#ifdef CO_309 /* Initialize socket command interface */ switch(commandEnable) { case CMD_LOCAL: @@ -421,7 +401,7 @@ int main (int argc, char *argv[]) { /* Execute optional additional application code */ app_programStart(); #endif - } + } /* if(firstRun) */ #ifdef CO_USE_APPLICATION @@ -433,7 +413,7 @@ int main (int argc, char *argv[]) { /* start CAN */ CO_CANsetNormalMode(CO->CANmodule[0]); -#ifdef CO_MULTI_THREAD +#ifdef CO_309 pthread_mutex_unlock(&CO_CAN_VALID_mtx); #endif @@ -456,17 +436,6 @@ int main (int argc, char *argv[]) { } } -#ifndef CO_MULTI_THREAD - else if(CANrx_threadTmr_process(ev.data.fd)) { - /* code was processed in the above function. Additional code process below */ - INCREMENT_1MS(CO_timer1ms); - /* Detect timer large overflow */ - if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_THREAD_OVERFLOW_US && rtPriority > 0) { - CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0x22400000L | OD_performance[ODA_performance_timerCycleMaxTime]); - } - } -#endif - else if(threadMain_process(ev.data.fd, &reset, CO_timer1ms)) { uint16_t timer1msDiff; static uint16_t tmr1msPrev = 0; @@ -495,7 +464,7 @@ int main (int argc, char *argv[]) { /* program exit ***************************************************************/ /* join threads */ -#ifdef CO_USE_309 +#ifdef CO_309 switch (commandEnable) { case CMD_LOCAL: @@ -566,9 +535,6 @@ static void* rt_thread(void* arg) { else if(CANrx_threadTmr_process(ev.data.fd)) { int i; - /* code was processed in the above function. Additional code process below */ - INCREMENT_1MS(CO_timer1ms); - #if CO_NO_TRACE > 0 /* Monitor variables with trace objects */ CO_time_process(&CO_time); @@ -582,10 +548,6 @@ static void* rt_thread(void* arg) { app_program1ms(); #endif - /* Detect timer large overflow */ - if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_THREAD_OVERFLOW_US && rtPriority > 0 && CO->CANmodule[0]->CANnormal) { - CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0x22400000L | OD_performance[ODA_performance_timerCycleMaxTime]); - } } else { diff --git a/socketCAN/CO_notify_pipe.c b/socketCAN/CO_notify_pipe.c index b9825827..7f053d58 100644 --- a/socketCAN/CO_notify_pipe.c +++ b/socketCAN/CO_notify_pipe.c @@ -6,6 +6,7 @@ #include #include "CO_notify_pipe.h" +#include "CO_error.h" CO_NotifyPipe_t *CO_NotifyPipeCreate(void) @@ -50,8 +51,12 @@ int CO_NotifyPipeGetFd(CO_NotifyPipe_t *p) void CO_NotifyPipeSend(CO_NotifyPipe_t *p) { + ssize_t ret; if (p == NULL) { return; } - write(p->m_sendFd,"1",1); + ret = write(p->m_sendFd,"1",1); + if(ret < 0){ + log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); + } } From a98492ecaf1f3fc4a90255764fef32388cf06356 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 6 Mar 2020 11:33:25 +0100 Subject: [PATCH 032/520] Add heapMemoryUsed info from CO_new() --- CANopen.c | 10 ++++++---- CANopen.h | 9 ++++++++- example/main_blank.c | 35 +++++++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/CANopen.c b/CANopen.c index e2a3f25f..b9281b9f 100644 --- a/CANopen.c +++ b/CANopen.c @@ -35,7 +35,6 @@ extern const CO_OD_entry_t CO_OD[CO_OD_NoOfElements]; /* Object Dictionary */ static CO_t COO; /* Pointers to CANopen objects */ CO_t *CO = NULL; /* Pointer to COO */ -static uint32_t CO_memoryUsed = 0; /* informative */ static CO_CANrx_t *CO_CANmodule_rxArray0; static CO_CANtx_t *CO_CANmodule_txArray0; @@ -109,9 +108,10 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; /******************************************************************************/ -CO_ReturnError_t CO_new(void) { +CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { int16_t i; uint16_t errCnt = 0; + uint32_t CO_memoryUsed = 0; /* If CANopen was initialized before, return. */ if (CO != NULL) { @@ -134,7 +134,6 @@ CO_ReturnError_t CO_new(void) { /* globals */ CO = &COO; - CO_memoryUsed = 0; /* CANmodule */ CO->CANmodule[0] = (CO_CANmodule_t *)calloc(1, sizeof(CO_CANmodule_t)); @@ -259,6 +258,10 @@ CO_ReturnError_t CO_new(void) { } #endif + if(heapMemoryUsed != NULL) { + *heapMemoryUsed = CO_memoryUsed; + } + return (errCnt == 0) ? CO_ERROR_NO : CO_ERROR_OUT_OF_MEMORY; } @@ -346,7 +349,6 @@ void CO_delete(void *CANptr) { /* globals */ CO = NULL; - CO_memoryUsed = 0; } diff --git a/CANopen.h b/CANopen.h index 11db15fe..5ea7a12e 100644 --- a/CANopen.h +++ b/CANopen.h @@ -216,10 +216,17 @@ extern CO_t *CO; * * Function must be called the first time, after program starts. * + * @remark + * With some microcontrollers it is necessary to specify Heap size within + * linker configuration. + * + * @param [out] heapMemoryUsed Information about heap memory used. Ignored if + * NULL. + * * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, * CO_ERROR_OUT_OF_MEMORY */ -CO_ReturnError_t CO_new(void); +CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed); /** diff --git a/example/main_blank.c b/example/main_blank.c index 5019ba88..d37718dd 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -25,12 +25,17 @@ */ +#include + #include "CANopen.h" #define TMR_TASK_INTERVAL (1000) /* Interval of tmrTask thread in microseconds */ #define INCREMENT_1MS(var) (var++) /* Increment 1ms variable in tmrTask */ +#define log_printf(macropar_message, ...) \ + printf(macropar_message, ##__VA_ARGS__) + /* Global variables and objects */ volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */ @@ -40,14 +45,19 @@ int main (void){ CO_ReturnError_t err; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; + uint32_t heapMemoryUsed; /* Configure microcontroller. */ /* Allocate memory */ - err = CO_new(); + err = CO_new(&heapMemoryUsed); if (err != CO_ERROR_NO) { - while(1); + log_printf("Error: Can't allocate memory\n"); + return 0; + } + else { + log_printf("Allocated %d bytes for CANopen objects\n", heapMemoryUsed); } /* initialize EEPROM */ @@ -56,20 +66,27 @@ int main (void){ /* increase variable each startup. Variable is stored in EEPROM. */ OD_powerOnCounter++; + log_printf("CANopenNode - Reset application, count = %d\n", OD_powerOnCounter); + while(reset != CO_RESET_APP){ /* CANopen communication reset - initialize CANopen objects *******************/ uint16_t timer1msPrevious; + log_printf("CANopenNode - Reset communication\n"); + /* disable CAN and CAN interrupts */ /* initialize CANopen */ err = CO_CANinit(NULL /* CAN module address */, 125 /* bit rate */); - if (err == CO_ERROR_NO) { - err = CO_CANopenInit(10 /* NodeID */); + if (err != CO_ERROR_NO) { + log_printf("Error: CAN initialization failed: %d\n", err); + return 0; } - if(err != CO_ERROR_NO){ - while(1); + err = CO_CANopenInit(10 /* NodeID */); + if(err != CO_ERROR_NO) { + log_printf("Error: CANopen initialization failed: %d\n", err); + return 0; /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */ } @@ -85,6 +102,9 @@ int main (void){ reset = CO_RESET_NOT; timer1msPrevious = CO_timer1ms; + log_printf("CANopenNode - Running...\n"); + fflush(stdout); + while(reset == CO_RESET_NOT){ /* loop for normal program execution ******************************************/ uint16_t timer1msCopy, timer1msDiff; @@ -100,6 +120,8 @@ int main (void){ /* Nonblocking application code may go here. */ /* Process EEPROM */ + + /* optional sleep for short time */ } } @@ -111,6 +133,7 @@ int main (void){ /* delete objects from memory */ CO_delete((void*) 0/* CAN module address */); + log_printf("CANopenNode finished\n"); /* reset */ return 0; From b49907f1330a1d3438d29910c127ecd9689e02bd Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 6 Mar 2020 11:34:30 +0100 Subject: [PATCH 033/520] Update docs --- README.md | 87 ++++++++++++++++++++++++++++---------------- doc/deviceSupport.md | 42 +++++++++++++++------ 2 files changed, 87 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 266c8cf8..7a2a1726 100644 --- a/README.md +++ b/README.md @@ -18,35 +18,34 @@ Dictionary and are accessible from both: C code and from CANopen network. CANopenNode homepage is https://github.com/CANopenNode/CANopenNode -CANopen Features ----------------- - - NMT slave to start, stop, reset device. Simple NMT master. - - Heartbeat producer/consumer error control. - - PDO linking and dynamic mapping for fast exchange of process variables. - - SDO expedited, segmented and block transfer for service access to all parameters. - - SDO master. - - Emergency message. - - Sync producer/consumer. - - Time protocol (producer/consumer). +Characteristics +--------------- +### CANopen + - [NMT](https://www.can-cia.org/can-knowledge/canopen/network-management/) + slave to start, stop, reset device. Simple NMT master. + - [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/) + producer/consumer error control. + - [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) linking + and dynamic mapping for fast exchange of process variables. + - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) expedited, + segmented and block transfer for service access to all parameters. + - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client. + - [Emergency](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) + producer/consumer. + - [Sync](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) + producer/consumer. + - [Time-stamp](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) + protocol producer/consumer. + - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) master and + slave, LSS fastscan + +### Other + - [Suitable for 16-bit microcontrollers and above](#device-support) + - [Multithreaded, real-time](#flowchart-of-a-typical-canopennode-implementation) + - [Object Dictionary editor](#object-dictionary-editor) - Non-volatile storage. - - LSS master and slave, LSS fastscan - -### RTR -RTR (remote transmission request) is a feature of CAN bus. Usage of RTR -is not recommended for CANopen and it is not implemented in CANopenNode. - -### Self start -Object **0x1F80** from Object Dictionary enables the NMT slaves to start -automatically or allows it to start the whole network. It is specified in -DSP302-2 standard. Standard allows two values for slaves for object 0x1F80: -- Object 0x1F80, value = **0x8** - "NMT slave shall enter the NMT state - Operational after the NMT state Initialization autonomously (self starting)" -- Object 0x1F80, value = **0x2** - "NMT slave shall execute the NMT service - start remote node with node-ID set to 0" - -Note: When node is stated (in NMT operational state), it is allowed to send or -receive Process Data Objects (PDO). If Error Register (object 0x1001) is set, -then NMT operational state is not allowed. + - [Power saving possible](#power-saving) (experimental) + - [Bootloader possible](https://github.com/CANopenNode/CANopenNode/issues/111) (for firmware update) Documentation, support and contributions @@ -65,9 +64,9 @@ http://sourceforge.net/p/canopennode/discussion/387151/ Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Some basic formatting -rules should be followed: Linux style with indentation of 4 spaces. There -is also a `codingStyle` file with example and a configuration file for -`clang-format` tool. +rules should be followed: Linux style with indentation of 4 spaces or +optionally 2 spaces. There is also a `codingStyle` file with example and +a configuration file for `clang-format` tool. Flowchart of a typical CANopenNode implementation @@ -208,6 +207,32 @@ Interfaces to other microcontrollers are in separate projects. See [deviceSupport.md](doc/deviceSupport.md) for list of known device interfaces. +Some details +------------ +### RTR +RTR (remote transmission request) is a feature of CAN bus. Usage of RTR +is not recommended for CANopen and it is not implemented in CANopenNode. + +### Self start +Object **0x1F80** from Object Dictionary enables the NMT slaves to start +automatically or allows it to start the whole network. It is specified in +DSP302-2 standard. Standard allows two values for slaves for object 0x1F80: +- Object 0x1F80, value = **0x8** - "NMT slave shall enter the NMT state + Operational after the NMT state Initialization autonomously (self starting)" +- Object 0x1F80, value = **0x2** - "NMT slave shall execute the NMT service + start remote node with node-ID set to 0" + +### Error control +When node is stated (in NMT operational state), it is allowed to send or +receive Process Data Objects (PDO). If Error Register (object 0x1001) is set, +then NMT operational state is not allowed. + +### Power saving +All CANopen objects calculates next timer info for OS. Calculation is based on +various timers which expire in known time. Can be used to put microcontroller +into sleep and wake at the calculated time. This is experimental. + + Change Log ---------- See [CHANGELOG.md](doc/CHANGELOG.md) diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index 19a13870..ad3ec5da 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -3,7 +3,7 @@ Device Support CANopenNode can run on many different devices. There are possible many different implementations on many different hardware, with many different development tools, by many different developers. It is not possible for single project maintainer to keep all the hardware interfaces updated. For that reason all hardware specific files are not part of the CANopenNode project. -It is necessary to implement interface to specific hardware. Interface to Linux socketCAN is part of this projects. Interfaces to other controllers are separate projects. There are interfaces to: Zephyr RTOS, PIC, Mbed-os RTOS + STM32, etc. +It is necessary to implement interface to specific hardware. Interface to Linux socketCAN is part of this projects. Interfaces to other controllers are separate projects. There are interfaces to: Zephyr RTOS, PIC, Mbed-os RTOS + STM32, NXP, etc. Note for device driver contributors @@ -25,7 +25,7 @@ Linux * https://github.com/CANopenNode/CANopenNode (this project). * CANopenNode version: (will be v2.0) * Status: stable -* Features: OD storage, SDO client +* Features: OD storage, error counters, master (SDO client, LSS master, NMT master) * Systems: Linux PC, Raspberry PI, etc. * Development tools: Linux * Information updated 2020-02-14 @@ -68,21 +68,41 @@ Mbed-os RTOS + STM32 (F091RC, L496ZG) * Information updated 2020-01-21 -Kinetis K20 (ARM) ------------------ -* CANopenNode driver for Teensy3 (Kinetis K20 ARM) -* https://github.com/c0d3runn3r/CANopenNode/tree/add-k20-driver, https://github.com/CANopenNode/CANopenNode/pull/28 -* CANopenNode version: 83f18edc (before V1.0) -* Status: ? -* Features: ? +Kinetis K20 (NXP Arm) +--------------------- +* CANopenNode driver for Teensy3 (Kinetis K20 Arm) +* Driver source: https://github.com/c0d3runn3r/CANopenNode/tree/add-k20-driver/stack/ARM_Kinetis_K20_teensy +* Discussion: https://github.com/CANopenNode/CANopenNode/pull/28 +* CANopenNode version: v1.0, 2017-08-01 +* Status: seems to be stable +* Features: error counters, ? * Development tools: (see [readme](https://github.com/c0d3runn3r/CANopenNode/tree/add-k20-driver/stack/ARM_Kinetis_K20_teensy)) * Demo hardware: Teensyduino, [Teensy3](https://www.pjrc.com/store/teensy32.html) -* Information updated 2020-02-14 +* Information updated 2020-03-02 + + +S32DS (NXP S32 Design studio for Arm or Powerpc) +------------------------------------------------ +* CANopenNode driver for S32DS and supported devices +* Driver source: https://github.com/bubi-soft/CANopenNode/tree/S32_SDK_support/stack/S32_SDK +* Documentation: included in driver, example available +* CANopenNode version: v1.0, 2017-08-01 +* Status: seems to be stable +* Features: error counters, ? +* Development tools: [NXP S32 Design studio for Arm or Powerpc](https://www.nxp.com/design/software/development-software/s32-design-studio-ide:S32-DESIGN-STUDIO-IDE?&fsrch=1&sr=1&pageNum=1) +* Demo hardware: [S32K144EVB-Q100](https://www.nxp.com/design/development-boards/automotive-development-platforms/s32k-mcu-platforms/s32k144-evaluation-board:S32K144EVB), [DEVKIT-MPC5748G](https://www.nxp.com/design/development-boards/automotive-development-platforms/mpc57xx-mcu-platforms/mpc5748g-development-board-for-secure-gateway:DEVKIT-MPC5748G) +* Information updated 2020-03-02 + + +Other +----- +* [STM32CubeMX HAL](https://github.com/w1ne/CANOpenNode-CubeMX-HAL), 2019-05-03, demo project for Atollic studio, tested on Nucleo STM32L452xx board. +* K64F_FreeRTOS, Kinetis SDK, 2018-02-13, [zip file](https://github.com/CANopenNode/CANopenNode/pull/28#issuecomment-365392867) +* LPC1768 (MBED) (released in 2016) - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), [known example from 2016](https://github.com/exmachina-dev/CANopenMbed) Other old versions ------------------ -* LPC1768 (MBED) (released in 2016) - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), [known example from 2016](https://github.com/exmachina-dev/CANopenMbed) * RTOS eCos - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), ([released in 2013, old repo](http://sourceforge.net/p/canopennode/code_complete/)) * Atmel SAM3X - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), ([released in old repo](http://sourceforge.net/p/canopennode/code_complete/)) * ST STM32 - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), ([released in old repo](http://sourceforge.net/p/canopennode/code_complete/)) From 3fc79b807ee6dcce8445218c1314bbaee9dcb8cf Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 7 Mar 2020 13:32:14 +0100 Subject: [PATCH 034/520] Remove pFunctSignal from mainline processing functions. Use timerNext_us. Interface to CO_SDOclientDownloadInitiate and CO_SDOclientUploadInitiate changed (added optional *timerNext_us argument). Little corrections in documentation for CO_SDOclient.h --- 301/CO_SDOclient.c | 17 +++++++------- 301/CO_SDOclient.h | 55 ++++++++++++++++++++++++++++------------------ 301/CO_SDOserver.c | 3 --- 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index fbfeb148..ddd07923 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -334,7 +334,8 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( uint8_t *dataTx, uint32_t dataSize, uint16_t SDOtimeoutTime_ms, - uint8_t blockEnable) + uint8_t blockEnable, + uint32_t *timerNext_us) { /* verify parameters */ if(SDO_C == NULL || dataTx == 0 || dataSize == 0) { @@ -362,8 +363,8 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( if(SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ /* Optional signal to RTOS. We can immediately continue SDO Client */ - if(SDO_C->pFunctSignal != NULL) { - SDO_C->pFunctSignal(SDO_C->functSignalObject); + if(timerNext_us != NULL) { + *timerNext_us = 0; } return CO_SDOcli_ok_communicationEnd; @@ -713,9 +714,6 @@ CO_SDOclient_return_t CO_SDOclientDownload( if (timerNext_us != NULL) { *timerNext_us = 0; } - if (SDO_C->pFunctSignal != NULL) { - SDO_C->pFunctSignal(SDO_C->functSignalObject); - } } /* tx data */ @@ -767,7 +765,8 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( uint8_t *dataRx, uint32_t dataRxSize, uint16_t SDOtimeoutTime_ms, - uint8_t blockEnable) + uint8_t blockEnable, + uint32_t *timerNext_us) { /* verify parameters */ if(SDO_C == NULL || dataRx == 0 || dataRxSize < 4) { @@ -821,8 +820,8 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( if(SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ /* Optional signal to RTOS. We can immediately continue SDO Client */ - if(SDO_C->pFunctSignal != NULL) { - SDO_C->pFunctSignal(SDO_C->functSignalObject); + if(timerNext_us != NULL) { + *timerNext_us = 0; } return CO_SDOcli_ok_communicationEnd; diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index eb7da311..398e2c81 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -69,17 +69,20 @@ typedef enum{ /** - * SDO Client Parameter. The same as record from Object dictionary (index 0x1280+). + * SDO Client Parameter. The same as record from Object dictionary + * (index 0x1280+). */ typedef struct{ /** Equal to 3 */ uint8_t maxSubIndex; - /** Communication object identifier for client transmission. Meaning of the specific bits: + /** Communication object identifier for client transmission. + * Meaning of the specific bits: - Bit 0...10: 11-bit CAN identifier. - Bit 11..30: reserved, set to 0. - Bit 31: if 1, SDO client object is not used. */ uint32_t COB_IDClientToServer; - /** Communication object identifier for message received from server. Meaning of the specific bits: + /** Communication object identifier for message received from server. + * Meaning of the specific bits: - Bit 0...10: 11-bit CAN identifier. - Bit 11..30: reserved, set to 0. - Bit 31: if 1, SDO client object is not used. */ @@ -145,8 +148,9 @@ typedef struct{ uint16_t CANdevTxIdx; /** Toggle bit toggled with each subsequent in segmented transfer */ uint8_t toggle; - /** Server threshold for switch back to segmented transfer, if data size is small. - Set in CO_SDOclient_init(). Can be changed by application. 0 Disables switching. */ + /** Server threshold for switch back to segmented transfer, if data size is + * small. Set in CO_SDOclient_init(). Can be changed by application. + * 0 Disables switching. */ uint8_t pst; /** Maximum number of segments in one block. Set in CO_SDOclient_init(). Can be changed by application to 2 .. 127. */ @@ -204,7 +208,8 @@ CO_ReturnError_t CO_SDOclient_init( * or SDO block transfer is in progress). * * @param SDOclient This object. - * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignal(). Can + * be NULL. * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_SDOclient_initCallback( @@ -258,6 +263,7 @@ CO_SDOclient_return_t CO_SDOclient_setup( * @param dataSize Size of data in dataTx. * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. + * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * * @return #CO_SDOclient_return_t */ @@ -268,7 +274,8 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( uint8_t *dataTx, uint32_t dataSize, uint16_t SDOtimeoutTime_ms, - uint8_t blockEnable); + uint8_t blockEnable, + uint32_t *timerNext_us); /** @@ -279,10 +286,11 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( * Function is non-blocking. * * @param SDO_C This object. - * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param pSDOabortCode Pointer to external variable written by this function - * in case of error in communication. - * @param timerNext_us [out] info to OS - see CO_process(). + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. + * @param [out] pSDOabortCode Pointer to external variable written by this + * function in case of error in communication. + * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * * @return #CO_SDOclient_return_t */ @@ -303,13 +311,14 @@ CO_SDOclient_return_t CO_SDOclientDownload( * @param SDO_C This object. * @param index Index of object in object dictionary in remote node. * @param subIndex Subindex of object in object dictionary in remote node. - * @param dataRx Pointer to data buffer, into which received data will be written. - * Buffer must be valid until end of communication. Note that data are aligned - * in little-endian format, because CANopen itself uses - * little-endian. Take care, when using processors with big-endian. + * @param dataRx Pointer to data buffer, into which received data will be + * written. Buffer must be valid until end of communication. Note that data are + * aligned in little-endian format, because CANopen itself uses little-endian. + * Take care, when using processors with big-endian. * @param dataRxSize Size of dataRx. * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. + * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * * @return #CO_SDOclient_return_t */ @@ -320,7 +329,8 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( uint8_t *dataRx, uint32_t dataRxSize, uint16_t SDOtimeoutTime_ms, - uint8_t blockEnable); + uint8_t blockEnable, + uint32_t *timerNext_us); /** @@ -331,12 +341,13 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( * Function is non-blocking. * * @param SDO_C This object. - * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param pDataSize pointer to external variable, where size of received + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. + * @param [out] pDataSize pointer to external variable, where size of received * data will be written. - * @param pSDOabortCode Pointer to external variable written by this function - * in case of error in communication. - * @param timerNext_us [out] info to OS - see CO_process(). + * @param [out] pSDOabortCode Pointer to external variable written by this + * function in case of error in communication. + * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * * @return #CO_SDOclient_return_t */ @@ -354,6 +365,8 @@ CO_SDOclient_return_t CO_SDOclientUpload( * Function must be called after finish of each SDO client communication cycle. * It disables reception of SDO client CAN messages. It is necessary, because * CO_SDOclient_receive function may otherwise write into undefined SDO buffer. + * + * @param SDO_C This object. */ void CO_SDOclientClose(CO_SDOclient_t *SDO_C); diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index b74184a5..511d8a25 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1442,9 +1442,6 @@ int8_t CO_SDO_process( if (timerNext_us != NULL) { *timerNext_us = 0; } - if (SDO->pFunctSignal != NULL) { - SDO->pFunctSignal(SDO->functSignalObject); - } /* don't call CO_FLAG_CLEAR, so return directly */ return 1; From 02e2cc58600724ad302b665631bd9e9ad9e954cf Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 7 Mar 2020 15:40:12 +0100 Subject: [PATCH 035/520] Stack configuration added do CO_driver.h Change macro CO_USE_LEDS -> CO_CONFIG_NMT_LEDS 1 Change macro CO_SDO_BUFFER_SIZE -> CO_CONFIG_SDO_BUFFER_SIZE --- 301/CO_NMT_Heartbeat.c | 8 ++++---- 301/CO_NMT_Heartbeat.h | 4 ++-- 301/CO_SDOserver.c | 30 +++++++++++++++--------------- 301/CO_SDOserver.h | 22 +++------------------- 301/CO_driver.h | 34 ++++++++++++++++++++++++++++++++-- CANopen.h | 2 +- doc/CHANGELOG.md | 3 ++- example/CO_driver_target.h | 11 ++++++++++- socketCAN/CO_driver_target.h | 8 +++++++- 9 files changed, 76 insertions(+), 46 deletions(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 4d6b39be..f5b2b27c 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -102,7 +102,7 @@ CO_ReturnError_t CO_NMT_init( } /* blinking bytes and LEDS */ -#ifdef CO_USE_LEDS +#if CO_CONFIG_NMT_LEDS > 0 NMT->LEDtimer = 0; NMT->LEDflickering = 0; NMT->LEDblinking = 0; @@ -112,7 +112,7 @@ CO_ReturnError_t CO_NMT_init( NMT->LEDquadrupleFlash = 0; NMT->LEDgreenRun = -1; NMT->LEDredError = 1; -#endif /* CO_USE_LEDS */ +#endif /* CO_CONFIG_NMT_LEDS */ /* Configure object variables */ NMT->operatingState = CO_NMT_INITIALIZING; @@ -217,7 +217,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( CANpassive = 1; -#ifdef CO_USE_LEDS +#if CO_CONFIG_NMT_LEDS > 0 NMT->LEDtimer += timeDifference_us; if (NMT->LEDtimer >= 50000) { NMT->LEDtimer -= 50000; @@ -290,7 +290,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( else NMT->LEDredError = -1; -#endif /* CO_USE_LEDS */ +#endif /* CO_CONFIG_NMT_LEDS */ /* in case of error enter pre-operational state */ diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index c278347b..14e7786e 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -129,7 +129,7 @@ typedef enum{ * @ref CO_NMT_statusLEDdiodes. Object is initialized by CO_NMT_init(). */ typedef struct{ -#ifdef CO_USE_LEDS +#if CO_CONFIG_NMT_LEDS > 0 uint32_t LEDtimer; /**< 50ms led timer */ int8_t LEDflickering; /**< See @ref CO_NMT_statusLEDdiodes */ int8_t LEDblinking; /**< See @ref CO_NMT_statusLEDdiodes */ @@ -139,7 +139,7 @@ typedef struct{ int8_t LEDquadrupleFlash; /**< See @ref CO_NMT_statusLEDdiodes */ int8_t LEDgreenRun; /**< See @ref CO_NMT_statusLEDdiodes */ int8_t LEDredError; /**< See @ref CO_NMT_statusLEDdiodes */ -#endif /* CO_USE_LEDS */ +#endif /* CO_CONFIG_NMT_LEDS */ uint8_t operatingState; /**< See @ref CO_NMT_internalState_t */ uint8_t resetCommand; /**< If different than zero, device will reset */ diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 511d8a25..c86f5035 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -39,8 +39,8 @@ #define CCS_ABORT 0x80U -#if CO_SDO_BUFFER_SIZE < 7 - #error CO_SDO_BUFFER_SIZE must be greater than 7 +#if CO_CONFIG_SDO_BUFFER_SIZE < 7 + #error CO_CONFIG_SDO_BUFFER_SIZE must be greater than 7 #endif @@ -214,7 +214,7 @@ static void CO_SDO_receive(void *object, void *msg){ /* copy data */ for(i=1; i<8; i++) { SDO->ODF_arg.data[SDO->bufferOffset++] = data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer - if(SDO->bufferOffset >= CO_SDO_BUFFER_SIZE) { + if(SDO->bufferOffset >= CO_CONFIG_SDO_BUFFER_SIZE) { /* buffer full, break reception */ SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; CO_FLAG_SET(SDO->CANrxNew); @@ -450,7 +450,7 @@ uint16_t CO_OD_getLength(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ if(object->maxSubIndex == 0U){ /* Object type is Var */ if(object->pData == 0){ /* data type is domain */ - return CO_SDO_BUFFER_SIZE; + return CO_CONFIG_SDO_BUFFER_SIZE; } else{ return object->length; @@ -462,7 +462,7 @@ uint16_t CO_OD_getLength(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ } else if(object->pData == 0){ /* data type is domain */ - return CO_SDO_BUFFER_SIZE; + return CO_CONFIG_SDO_BUFFER_SIZE; } else{ return object->length; @@ -471,7 +471,7 @@ uint16_t CO_OD_getLength(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ else{ /* Object type is Record */ if(((const CO_OD_entryRecord_t*)(object->pData))[subIndex].pData == 0){ /* data type is domain */ - return CO_SDO_BUFFER_SIZE; + return CO_CONFIG_SDO_BUFFER_SIZE; } else{ return ((const CO_OD_entryRecord_t*)(object->pData))[subIndex].length; @@ -604,7 +604,7 @@ uint32_t CO_SDO_initTransfer(CO_SDO_t *SDO, uint16_t index, uint8_t subIndex){ SDO->ODF_arg.offset = 0U; /* verify length */ - if(SDO->ODF_arg.dataLength > CO_SDO_BUFFER_SIZE){ + if(SDO->ODF_arg.dataLength > CO_CONFIG_SDO_BUFFER_SIZE){ return CO_SDO_AB_DEVICE_INCOMPAT; /* general internal incompatibility in the device */ } @@ -853,7 +853,7 @@ int8_t CO_SDO_process( /* upload */ else{ - abortCode = CO_SDO_readOD(SDO, CO_SDO_BUFFER_SIZE); + abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE); if(abortCode != 0U){ CO_SDO_abort(SDO, abortCode); return -1; @@ -985,7 +985,7 @@ int8_t CO_SDO_process( return -1; } - SDO->ODF_arg.dataLength = CO_SDO_BUFFER_SIZE; + SDO->ODF_arg.dataLength = CO_CONFIG_SDO_BUFFER_SIZE; SDO->bufferOffset = 0; } } @@ -1028,7 +1028,7 @@ int8_t CO_SDO_process( SDO->CANtxBuff->data[3] = SDO->CANrxData[3]; /* blksize */ - SDO->blksize = (CO_SDO_BUFFER_SIZE > (7*127)) ? 127 : (CO_SDO_BUFFER_SIZE / 7); + SDO->blksize = (CO_CONFIG_SDO_BUFFER_SIZE > (7*127)) ? 127 : (CO_CONFIG_SDO_BUFFER_SIZE / 7); SDO->CANtxBuff->data[4] = SDO->blksize; /* is CRC enabled */ @@ -1087,12 +1087,12 @@ int8_t CO_SDO_process( return -1; } - SDO->ODF_arg.dataLength = CO_SDO_BUFFER_SIZE; + SDO->ODF_arg.dataLength = CO_CONFIG_SDO_BUFFER_SIZE; SDO->bufferOffset = 0; } /* blksize */ - len = CO_SDO_BUFFER_SIZE - SDO->bufferOffset; + len = CO_CONFIG_SDO_BUFFER_SIZE - SDO->bufferOffset; SDO->blksize = (len > (7*127)) ? 127 : (len / 7); SDO->CANtxBuff->data[2] = SDO->blksize; @@ -1100,7 +1100,7 @@ int8_t CO_SDO_process( if(lastSegmentInSubblock) { SDO->state = CO_SDO_ST_DOWNLOAD_BL_END; } - else if(SDO->bufferOffset >= CO_SDO_BUFFER_SIZE) { + else if(SDO->bufferOffset >= CO_CONFIG_SDO_BUFFER_SIZE) { CO_SDO_abort(SDO, CO_SDO_AB_DEVICE_INCOMPAT); return -1; } @@ -1222,7 +1222,7 @@ int8_t CO_SDO_process( SDO->ODF_arg.dataLength = CO_OD_getLength(SDO, SDO->entryNo, SDO->ODF_arg.subIndex) - len; /* read next data from Object dictionary function */ - abortCode = CO_SDO_readOD(SDO, CO_SDO_BUFFER_SIZE); + abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE); if(abortCode != 0U){ CO_SDO_abort(SDO, abortCode); return -1; @@ -1375,7 +1375,7 @@ int8_t CO_SDO_process( SDO->ODF_arg.dataLength = CO_OD_getLength(SDO, SDO->entryNo, SDO->ODF_arg.subIndex) - len; /* read next data from Object dictionary function */ - abortCode = CO_SDO_readOD(SDO, CO_SDO_BUFFER_SIZE); + abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE); if(abortCode != 0U){ CO_SDO_abort(SDO, abortCode); return -1; diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 9f1ddfe3..1e8e0b97 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -311,7 +311,7 @@ typedef enum{ * download it must store the data in own location. In case of upload it must * write the data (maximum size is specified by length) into data buffer and * specify actual length. With domain data type it is possible to transfer - * data, which are longer than #CO_SDO_BUFFER_SIZE. In that case + * data, which are longer than #CO_CONFIG_SDO_BUFFER_SIZE. In that case * Object dictionary function is called multiple times between SDO transfer. * * ####Parameter to function: @@ -323,22 +323,6 @@ typedef enum{ */ -/** - * SDO buffer size. - * - * Size of the internal SDO buffer. - * - * Size must be at least equal to size of largest variable in @ref CO_SDO_objectDictionary. - * If data type is domain, data length is not limited to SDO buffer size. If - * block transfer is implemented, value should be set to 889. - * - * Value can be in range from 7 to 889 bytes. - */ - #ifndef CO_SDO_BUFFER_SIZE - #define CO_SDO_BUFFER_SIZE 32 - #endif - - /** * Object Dictionary attributes. Bit masks for attribute in CO_OD_entry_t. */ @@ -589,8 +573,8 @@ typedef struct{ typedef struct{ /** 8 data bytes of the received message. */ uint8_t CANrxData[8]; - /** SDO data buffer of size #CO_SDO_BUFFER_SIZE. */ - uint8_t databuffer[CO_SDO_BUFFER_SIZE]; + /** SDO data buffer of size #CO_CONFIG_SDO_BUFFER_SIZE. */ + uint8_t databuffer[CO_CONFIG_SDO_BUFFER_SIZE]; /** Internal flag indicates, that this object has own OD */ bool_t ownOD; /** Pointer to the @ref CO_SDO_objectDictionary (array) */ diff --git a/301/CO_driver.h b/301/CO_driver.h index c4bff4fc..bd5a0e47 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -87,6 +87,38 @@ extern "C" { * (or interrupts), CAN module, etc.). */ + +/** + * @defgroup CO_STACK_CONFIG Stack configuration + * + * Definitions specify, which parts of the stack will be enabled. Values can be + * overridden by CO_driver_target.h file for example. + * @{ + */ +/** + * Usage of CANopen LEDS. + * + * If >0, calculate CANopen blinking variables, which can be used for LEDs */ +#ifndef CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT_LEDS 0 +#endif +/** + * Size of the internal SDO buffer. + * + * Size must be at least equal to size of largest variable in + * @ref CO_SDO_objectDictionary. If data type is domain, data length is not + * limited to SDO buffer size. If block transfer is implemented, value should be + * set to 889. + * + * Value can be in range from 7 to 889 bytes. + */ +#ifndef CO_CONFIG_SDO_BUFFER_SIZE +#define CO_CONFIG_SDO_BUFFER_SIZE 32 +#endif + +/** @} */ + + /* Macros and declarations in following part are only used for documentation. */ #ifdef CO_DOXYGEN /** @@ -108,8 +140,6 @@ extern "C" { */ /** CO_LITTLE_ENDIAN or CO_BIG_ENDIAN must be defined */ #define CO_LITTLE_ENDIAN -/** Enable LED blinking calculation, optional */ -#define CO_USE_LEDS /** NULL, for general usage */ #define NULL (0) /** Logical true, for general use */ diff --git a/CANopen.h b/CANopen.h index 5ea7a12e..c504a2c5 100644 --- a/CANopen.h +++ b/CANopen.h @@ -129,7 +129,7 @@ extern "C" { #ifdef CO_DOXYGEN /** - * @defgroup CO_NO_OBJ Configuration + * @defgroup CO_NO_OBJ CANopen configuration * * Definitions specify, which and how many CANopenNode communication objects * will be used in current configuration. Usage of some objects is mandatory and diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 9a688221..c9413a8d 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -28,6 +28,7 @@ Change Log ### Added - Documentation added to `doc` directory: CHANGELOG.md, deviceSupport.md, gettingStarted.md, LSSusage.md and traceUsage.md. - All CANopen objects calculates next timer info for OS. Useful for energy saving. +- Stack configuration added to CO_driver.h. Can be overridden by custom definitions. [Unreleased master] ------------------- @@ -77,7 +78,7 @@ Change Log ------ -Changelog written according to recomendations from https://keepachangelog.com/ +Changelog written according to recommendations from https://keepachangelog.com/ [Unreleased split-driver]: https://github.com/CANopenNode/CANopenNode/tree/split-driver [Unreleased master]: https://github.com/CANopenNode/CANopenNode diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index bb3d84e9..70b153c5 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -34,13 +34,22 @@ #include #include +#if __has_include("CO_driver_custom.h") +#include "CO_driver_custom.h" +#endif + #ifdef __cplusplus extern "C" { #endif +/* Stack configuration override */ +#ifndef CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT_LEDS 1 +#endif + + /* Basic definitions */ #define CO_LITTLE_ENDIAN -#define CO_USE_LEDS /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index a1782b62..ec10b6a4 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -42,7 +42,7 @@ #include #if __has_include("CO_driver_custom.h") - #include "CO_driver_custom.h" +#include "CO_driver_custom.h" #endif #include "CO_notify_pipe.h" #include "CO_error.h" @@ -51,6 +51,12 @@ extern "C" { #endif +/* Stack configuration override */ +#ifndef CO_CONFIG_SDO_BUFFER_SIZE +#define CO_CONFIG_SDO_BUFFER_SIZE 889 +#endif + + /** * @defgroup CO_socketCAN_driver_target CO_driver_target.h * @ingroup CO_socketCAN From 42f2554f2fe6524de8b765eda957fd0d3da96cec Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 11 Mar 2020 17:44:33 +0100 Subject: [PATCH 036/520] Add emergency receive callback also for own emergency messages. --- 301/CO_Emergency.c | 14 ++++++++++++++ 301/CO_Emergency.h | 8 +++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index f383c936..a0df65c3 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -292,6 +292,19 @@ void CO_EM_process( /* add error register */ em->bufReadPtr[2] = *emPr->errorRegister; + /* report also own emergency messages */ + if (em->pFunctSignalRx != NULL) { + uint16_t errorCode; + uint32_t infoCode; + CO_memcpySwap2(&errorCode, &em->bufReadPtr[0]); + CO_memcpySwap4(&infoCode, &em->bufReadPtr[4]); + em->pFunctSignalRx(0, + errorCode, + em->bufReadPtr[2], + em->bufReadPtr[3], + infoCode); + } + /* copy data to CAN emergency message */ CO_memcpy(emPr->CANtxBuff->data, em->bufReadPtr, 8U); CO_memcpy((uint8_t*)&preDEF, em->bufReadPtr, 4U); @@ -326,6 +339,7 @@ void CO_EM_process( /* send CAN message */ CO_CANsend(emPr->CANdev, emPr->CANtxBuff); + } else if (timerNext_us != NULL) { /* check again after inhibit time elapsed */ diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 555280c7..42515988 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -410,11 +410,13 @@ void CO_EM_initCallback( * Initialize Emergency received callback function. * * Function initializes optional callback function, which executes after - * error condition is received. Function may wake up external task, - * which processes mainline CANopen functions. + * error condition is received. + * + * _ident_ argument from callback contains CAN-ID of the emergency message. If + * _ident_ == 0, then emergency message was sent from this device. * * @remark Depending on the CAN driver implementation, this function is called - * inside an ISR + * inside an ISR or inside a mainline. Must be thread safe. * * @param em This object. * @param pFunctSignalRx Pointer to the callback function. Not called if NULL. From fb2274fc9f8a8923a6a3b5a0514edf53238b78b6 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 11 Mar 2020 17:48:48 +0100 Subject: [PATCH 037/520] socketCAN driver, CO_CANrxBufferInit(): remove check COB ID already used. If two or more CANrx buffers have the same _ident_, then buffer with lowest _index_ has precedence and other CANrx buffers will be ignored. --- 301/CO_driver.h | 23 ++++++++++++++++- socketCAN/CO_driver.c | 58 +++++++++++++++++-------------------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/301/CO_driver.h b/301/CO_driver.h index bd5a0e47..d6f208b5 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -95,6 +95,7 @@ extern "C" { * overridden by CO_driver_target.h file for example. * @{ */ + /** * Usage of CANopen LEDS. * @@ -102,6 +103,7 @@ extern "C" { #ifndef CO_CONFIG_NMT_LEDS #define CO_CONFIG_NMT_LEDS 0 #endif + /** * Size of the internal SDO buffer. * @@ -116,6 +118,23 @@ extern "C" { #define CO_CONFIG_SDO_BUFFER_SIZE 32 #endif +/** + * Configuration of Standard CiA 309 usage. + * + * CiA 309 standard covers CANopen access from other networks. It enables + * usage of the NMT master, SDO client and LSS master as a gateway device. + * + * Value can be one of the following: + * - 0: Disabled. + * - 1: Interface enabled + * - 2: Modbus/TCP mapping (Not implemented) + * - 3: ASCII mapping + * - 4: Profinet (Not implemented) + */ +#ifndef CO_CONFIG_309 +#define CO_CONFIG_309 0 +#endif + /** @} */ @@ -538,7 +557,9 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); * * @param CANmodule This object. * @param index Index of the specific buffer in _rxArray_. - * @param ident 11-bit standard CAN Identifier. + * @param ident 11-bit standard CAN Identifier. If two or more CANrx buffers + * have the same _ident_, then buffer with lowest _index_ has precedence and + * other CANrx buffers will be ignored. * @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). diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 6ee0db2a..7211e4fb 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -475,51 +475,39 @@ CO_ReturnError_t CO_CANrxBufferInit( CO_ReturnError_t ret = CO_ERROR_NO; if((CANmodule!=NULL) && (index < CANmodule->rxSize)){ - uint32_t i; CO_CANrx_t *buffer; - /* check if COB ID is already used */ - for (i = 0; i < CANmodule->rxSize; i ++) { - buffer = &CANmodule->rxArray[i]; - - if (i!=index && ident>0 && ident==buffer->ident) { - log_printf(LOG_DEBUG, DBG_CAN_RX_PARAM_FAILED, "duplicate entry"); - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - } - - if (ret == CO_ERROR_NO) { - /* buffer, which will be configured */ - buffer = &CANmodule->rxArray[index]; + /* buffer, which will be configured */ + buffer = &CANmodule->rxArray[index]; #ifdef CO_DRIVER_MULTI_INTERFACE - CO_CANsetIdentToIndex(CANmodule->rxIdentToIndex, index, ident, - buffer->ident); + CO_CANsetIdentToIndex(CANmodule->rxIdentToIndex, index, ident, + buffer->ident); #endif - /* Configure object variables */ - buffer->object = object; - buffer->CANrx_callback = CANrx_callback; - buffer->CANptr = NULL; - buffer->timestamp.tv_nsec = 0; - buffer->timestamp.tv_sec = 0; - - /* CAN identifier and CAN mask, bit aligned with CAN module */ - buffer->ident = ident & CAN_SFF_MASK; - if(rtr){ - buffer->ident |= CAN_RTR_FLAG; - } - buffer->mask = (mask & CAN_SFF_MASK) | CAN_EFF_FLAG | CAN_RTR_FLAG; + /* Configure object variables */ + buffer->object = object; + buffer->CANrx_callback = CANrx_callback; + buffer->CANptr = NULL; + buffer->timestamp.tv_nsec = 0; + buffer->timestamp.tv_sec = 0; - /* Set CAN hardware module filter and mask. */ - CANmodule->rxFilter[index].can_id = buffer->ident; - CANmodule->rxFilter[index].can_mask = buffer->mask; - if(CANmodule->CANnormal){ - ret = setRxFilters(CANmodule); - } + /* CAN identifier and CAN mask, bit aligned with CAN module */ + buffer->ident = ident & CAN_SFF_MASK; + if(rtr){ + buffer->ident |= CAN_RTR_FLAG; + } + buffer->mask = (mask & CAN_SFF_MASK) | CAN_EFF_FLAG | CAN_RTR_FLAG; + + /* Set CAN hardware module filter and mask. */ + CANmodule->rxFilter[index].can_id = buffer->ident; + CANmodule->rxFilter[index].can_mask = buffer->mask; + if(CANmodule->CANnormal){ + ret = setRxFilters(CANmodule); } } else { + log_printf(LOG_DEBUG, DBG_CAN_RX_PARAM_FAILED, "illegal argument"); ret = CO_ERROR_ILLEGAL_ARGUMENT; } From e6b4c1f5b16c9af3223a7f963afc771114d1c701 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 12 Mar 2020 08:38:58 +0100 Subject: [PATCH 038/520] socketCAN now compiles and runs. --- Makefile | 2 +- doc/gettingStarted.md | 2 +- socketCAN/CO_Linux_threads.c | 172 +++++++++++++++++++++- socketCAN/CO_Linux_threads.h | 66 +++++++-- socketCAN/CO_OD_storage.c | 17 +-- socketCAN/CO_OD_storage.h | 16 +-- socketCAN/CO_error.h | 4 +- socketCAN/CO_error_msgs.h | 12 ++ socketCAN/CO_main_basic.c | 271 ++++++++++++++--------------------- 9 files changed, 355 insertions(+), 207 deletions(-) diff --git a/Makefile b/Makefile index 0b3353b4..600aab17 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ SOURCES = \ OBJS = $(SOURCES:%.c=%.o) CC ?= gcc -OPT = -Og +OPT = -g CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = -pthread diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index bbb8a30f..16dcf381 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -192,7 +192,7 @@ Some tested USB to CAN interfaces, which are natively integrated into Linux are: - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with: `sudo slcand -f -o -c -s8 /dev/ttyACM0 can0; sudo ip link set up can0` - [EMS CPC-USB](http://www.ems-wuensche.com/product/datasheet/html/can-usb-adapter-converter-interface-cpcusb.html) - Start with: `sudo ip link set up can0 type can bitrate 250000` - [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Needs newer Linux kernel, supports CAN flexible data rate. - - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can). + - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can) (Kconfig files). - Beaglebone or Paspberry PI or similar has CAN capes available. On RPI worked also the above USB interfaces, but it was necessary to compile the kernel. diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index 8051a349..dcc11856 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -25,13 +25,17 @@ * limitations under the License. */ -#include -#include +#include #include #include +#include +#include +#include +#include #include "CANopen.h" + /* Helper function - get monotonic clock time in microseconds */ static uint64_t CO_LinuxThreads_clock_gettime_us(void) { @@ -41,7 +45,8 @@ static uint64_t CO_LinuxThreads_clock_gettime_us(void) return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; } -/* Mainline thread (threadMain) ***********************************************/ + +/* Mainline thread - basic (threadMain) ***************************************/ static struct { uint64_t start; /* time value CO_process() was called last time in us */ @@ -69,6 +74,7 @@ void threadMain_process(CO_NMT_reset_cmd_t *reset) now = CO_LinuxThreads_clock_gettime_us(); diff = (uint32_t)(now - threadMain.start); + threadMain.start = now; /* we use timerNext_us in CO_process() as indication if processing is * finished. We ignore any calculated values for maximum delay times. */ @@ -78,10 +84,160 @@ void threadMain_process(CO_NMT_reset_cmd_t *reset) diff = 0; } while ((*reset == CO_RESET_NOT) && (finished == 0)); - /* prepare next call */ - threadMain.start = now; } + +/* Mainline thread - Blocking (threadMainWait) ********************************/ +static struct +{ + uint64_t start; /* time value CO_process() was called last time in us */ + int epoll_fd; /* epoll file descriptor */ + int event_fd; /* notification event file descriptor */ + int timer_fd; /* interval timer file descriptor */ + uint32_t interval_us; /* interval for threadMainWait_process */ + struct itimerspec tm; /* structure for timer configuration */ +} threadMainWait; + +static void threadMainWait_callback(void *object) +{ + /* send event to wake threadMainWait_process() */ + uint64_t u = 1; + ssize_t s; + s = write(threadMainWait.event_fd, &u, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) { + log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); + } +} + +void threadMainWait_init(uint32_t interval_us) +{ + int32_t ret; + struct epoll_event ev; + + /* Configure callback functions */ + CO_SDO_initCallback(CO->SDO[0], NULL, threadMainWait_callback); + CO_EM_initCallback(CO->em, NULL, threadMainWait_callback); + + /* Initial value for time calculation */ + threadMainWait.start = CO_LinuxThreads_clock_gettime_us(); + + /* Configure epoll for mainline */ + threadMainWait.epoll_fd = epoll_create(1); + if (threadMainWait.epoll_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_create()"); + exit(EXIT_FAILURE); + } + + /* Configure eventfd for notifications and add it to epoll */ + threadMainWait.event_fd = eventfd(0, 0); + if (threadMainWait.event_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "eventfd()"); + exit(EXIT_FAILURE); + } + ev.events = EPOLLIN; + ev.data.fd = threadMainWait.event_fd; + ret = epoll_ctl(threadMainWait.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0){ + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(event_fd)"); + exit(EXIT_FAILURE); + } + + /* Configure timer for interval_us and add it to epoll */ + threadMainWait.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (threadMainWait.timer_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_create()"); + exit(EXIT_FAILURE); + } + threadMainWait.interval_us = interval_us; + threadMainWait.tm.it_interval.tv_sec = interval_us / 1000000; + threadMainWait.tm.it_interval.tv_nsec = (interval_us % 1000000) * 1000; + threadMainWait.tm.it_value.tv_sec = 0; + threadMainWait.tm.it_value.tv_nsec = 1; + ret = timerfd_settime(threadMainWait.timer_fd, 0, &threadMainWait.tm, NULL); + if (ret < 0){ + log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_settime"); + exit(EXIT_FAILURE); + } + ev.events = EPOLLIN; + ev.data.fd = threadMainWait.timer_fd; + ret = epoll_ctl(threadMainWait.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0){ + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(timer_fd)"); + exit(EXIT_FAILURE); + } +} + +void threadMainWait_close(void) +{ + CO_SDO_initCallback(CO->SDO[0], NULL, NULL); + CO_EM_initCallback(CO->em, NULL, NULL); + + close(threadMainWait.epoll_fd); + close(threadMainWait.event_fd); + close(threadMainWait.timer_fd); + threadMainWait.epoll_fd = -1; + threadMainWait.event_fd = -1; + threadMainWait.timer_fd = -1; +} + +uint32_t threadMainWait_process(CO_NMT_reset_cmd_t *reset) +{ + int ready, ret; + struct epoll_event ev; + uint64_t ull; + ssize_t s; + uint32_t diff, timerNext_us; + + /* wait for event or timer expiration and read data from file descriptors */ + ready = epoll_wait(threadMainWait.epoll_fd, &ev, 1, -1); + if (ready != 1 && errno != EINTR) { + log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_wait"); + } + else if (ev.data.fd == threadMainWait.event_fd) { + s = read(threadMainWait.event_fd, &ull, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) { + log_printf(LOG_DEBUG, DBG_ERRNO, "read(event_fd)"); + } + } + else if (ev.data.fd == threadMainWait.timer_fd) { + s = read(threadMainWait.timer_fd, &ull, sizeof(uint64_t)); + if (s != sizeof(uint64_t) && errno != EAGAIN) { + log_printf(LOG_DEBUG, DBG_ERRNO, "read(timer_fd)"); + } + } + + /* calculate time difference since last call */ + ull = CO_LinuxThreads_clock_gettime_us(); + diff = (uint32_t)(ull - threadMainWait.start); + threadMainWait.start = ull; + + /* stack will lower this, if necessary */ + timerNext_us = threadMainWait.interval_us; + + /* process CANopen objects */ + *reset = CO_process(CO, diff, &timerNext_us); + + /* lower next timer interval if necessary */ + if (timerNext_us < threadMainWait.interval_us) { + /* add one microsecond extra delay and make sure it is not zero */ + timerNext_us += 1; + if (threadMainWait.interval_us < 1000000) { + threadMainWait.tm.it_value.tv_nsec = timerNext_us * 1000; + } else { + threadMainWait.tm.it_value.tv_sec = timerNext_us / 1000000; + threadMainWait.tm.it_value.tv_nsec = (timerNext_us % 1000000) * 1000; + } + ret = timerfd_settime(threadMainWait.timer_fd, 0, + &threadMainWait.tm, NULL); + if (ret < 0){ + log_printf(LOG_DEBUG, DBG_ERRNO, "timerfd_settime"); + } + } + + return diff; +} + + /* Realtime thread (threadRT) *************************************************/ static struct { uint32_t us_interval; /* configured interval in us */ @@ -108,12 +264,12 @@ void CANrx_threadTmr_close(void) threadRT.interval_fd = -1; } -void CANrx_threadTmr_process(void) +uint32_t CANrx_threadTmr_process(void) { int32_t result; uint64_t i; bool_t syncWas; - uint64_t missed; + uint64_t missed = 0; result = CO_CANrxWait(CO->CANmodule[0], threadRT.interval_fd, NULL); if (result < 0) { @@ -143,4 +299,6 @@ void CANrx_threadTmr_process(void) CO_UNLOCK_OD(); } } + + return (uint32_t) missed; } diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index f903c2c8..e1e27951 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -38,12 +38,17 @@ extern "C" { * @defgroup CO_socketCAN socketCAN * @{ * - * Linux specific interface to CANopenNode + * Linux specific interface to CANopenNode. + * + * CANopenNode runs on top of SocketCAN interface, which is part of the Linux + * kernel. For more info on Linux SocketCAN see + * https://www.kernel.org/doc/html/latest/networking/can.html * * CANopenNode runs in two threads: * - timer based real-time thread for CAN receive, SYNC and PDO, see * CANrx_threadTmr_process() - * - mainline thread for other processing, see threadMain_process() + * - mainline thread for other processing, see threadMain_process() or + * threadMainWait_process() * * The "threads" specified here do not fork threads themselves, but require * that two threads are provided by the calling application. @@ -51,28 +56,29 @@ extern "C" { /** - * Initialize mainline thread. + * Initialize mainline thread - basic. * * @param callback this function is called to indicate #threadMain_process() has * work to do * @param object this pointer is given to _callback()_ */ -extern void threadMain_init(void (*callback)(void*), void *object); +void threadMain_init(void (*callback)(void*), void *object); /** - * Cleanup mainline thread. + * Cleanup mainline thread - basic. */ -extern void threadMain_close(void); +void threadMain_close(void); /** - * Process mainline thread. + * Process mainline thread - basic. * * threadMain is non-realtime thread for CANopenNode processing. It is * initialized by threadMain_init(). There is no configuration for CANopen - * objects. There is also no configuration for epool or interval timer or notify - * pipe. These must be specified externally. + * objects. There is also no configuration for epool or interval timer or + * eventfd. These must be specified externally. For more complete function see + * threadMainWait_process(), they are included. * * threadMain_process() calls CO_process() function for processing mainline * CANopen objects. It is non-blocking and should be called cyclically in 50 ms @@ -81,7 +87,39 @@ extern void threadMain_close(void); * * @param reset return value from CO_process() function. */ -extern void threadMain_process(CO_NMT_reset_cmd_t *reset); +void threadMain_process(CO_NMT_reset_cmd_t *reset); + + +/** + * Initialize mainline thread - blocking. + * + * @param interval_us interval of the threadMainWait_process() + */ +void threadMainWait_init(uint32_t interval_us); + + +/** + * Cleanup mainline thread - blocking. + */ +void threadMainWait_close(void); + + +/** + * Process mainline thread - blocking. + * + * threadMainWait is non-realtime thread for CANopenNode processing. It is + * initialized by threadMainWait_init(). There is no configuration for CANopen + * objects. But there is configuration for epool, interval timer and eventfd. + * Function must be called inside loop. It blocks for correct time and unblocks + * automatically in case of event. It calls CO_process() function for processing + * mainline CANopen objects. + * For more basic function see threadMain_process() alternative. + * + * @param reset return value from CO_process() function. + * + * @return time difference since last call in microseconds + */ +uint32_t threadMainWait_process(CO_NMT_reset_cmd_t *reset); /** @@ -90,13 +128,13 @@ extern void threadMain_process(CO_NMT_reset_cmd_t *reset); * @param interval_us Interval of periodic timer in microseconds, recommended * value for realtime response: 1000 us */ -extern void CANrx_threadTmr_init(uint32_t interval_us); +void CANrx_threadTmr_init(uint32_t interval_us); /** * Terminate realtime thread. */ -extern void CANrx_threadTmr_close(void); +void CANrx_threadTmr_close(void); /** @@ -117,8 +155,10 @@ extern void CANrx_threadTmr_close(void); * * @remark If realtime is required, this thread must be registered as such in * the Linux kernel. + * + * @return Number of interval timer passes since last call. */ -extern void CANrx_threadTmr_process(); +void CANrx_threadTmr_process(void); /** @} */ diff --git a/socketCAN/CO_OD_storage.c b/socketCAN/CO_OD_storage.c index be71bfae..dc6fee6c 100644 --- a/socketCAN/CO_OD_storage.c +++ b/socketCAN/CO_OD_storage.c @@ -241,8 +241,7 @@ CO_ReturnError_t CO_OD_storage_init( odStor->odSize = odSize; odStor->filename = filename; odStor->fp = NULL; - odStor->tmr1msPrev = 0; - odStor->lastSavedMs = 0; + odStor->lastSavedUs = 0; buf = malloc(odStor->odSize); if(buf == NULL) { @@ -292,8 +291,8 @@ CO_ReturnError_t CO_OD_storage_init( /******************************************************************************/ CO_ReturnError_t CO_OD_storage_autoSave( CO_OD_storage_t *odStor, - uint16_t timer1ms, - uint16_t delay) + uint32_t timer1usDiff, + uint32_t delay_us) { CO_ReturnError_t ret = CO_ERROR_NO; @@ -303,10 +302,8 @@ CO_ReturnError_t CO_OD_storage_autoSave( } /* don't save file more often than delay */ - if(odStor->lastSavedMs < delay) { - odStor->lastSavedMs += timer1ms - odStor->tmr1msPrev; - } - else { + odStor->lastSavedUs += timer1usDiff; + if (odStor->lastSavedUs > delay_us) { void *buf = NULL; bool_t saveData = false; @@ -360,14 +357,12 @@ CO_ReturnError_t CO_OD_storage_autoSave( fflush(odStor->fp); - odStor->lastSavedMs = 0; + odStor->lastSavedUs = 0; } free(buf); } - odStor->tmr1msPrev = timer1ms; - return ret; } diff --git a/socketCAN/CO_OD_storage.h b/socketCAN/CO_OD_storage.h index 24b4f2a6..c0212e81 100644 --- a/socketCAN/CO_OD_storage.h +++ b/socketCAN/CO_OD_storage.h @@ -108,8 +108,7 @@ typedef struct { char *filename; /**< From CO_OD_storage_init() */ /** If CO_OD_storage_autoSave() is used, file stays opened and fp is stored here. */ FILE *fp; - uint16_t tmr1msPrev; /**< used with CO_OD_storage_autoSave. */ - uint32_t lastSavedMs; /**< used with CO_OD_storage_autoSave. */ + uint32_t lastSavedUs; /**< used with CO_OD_storage_autoSave. */ } CO_OD_storage_t; @@ -143,16 +142,17 @@ CO_ReturnError_t CO_OD_storage_init( * CRC bytes. File remains opened. * * @param odStor OD storage object. - * @param timer1ms Variable, which must increment each millisecond. - * @param delay Delay (inhibit) time between writes to disk in milliseconds (60000 for example). + * @param timer1usDiff Time difference in microseconds since last call. + * @param delay_us Delay (inhibit) time between writes to disk in microseconds + * (60000 for example). * - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_DATA_CORRUPT (Data in file corrupt), - * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY (malloc failed). + * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_DATA_CORRUPT (Data in file + * corrupt), CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY (malloc failed). */ CO_ReturnError_t CO_OD_storage_autoSave( CO_OD_storage_t *odStor, - uint16_t timer1ms, - uint16_t delay); + uint32_t timer1usDiff, + uint32_t delay_us); /** diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 41008a4e..7f9fb433 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -59,10 +59,10 @@ extern "C" { * default system stores messages in /var/log/syslog file. * Log can optionally be configured before, for example to filter out less * critical errors than LOG_NOTICE, specify program name, print also process PID - * and print also to standard error, use: + * and print also to standard error, set 'user' type of program, use: * @code * setlogmask (LOG_UPTO (LOG_NOTICE)); - * openlog ("exampleprog", LOG_PID | LOG_PERROR); + * openlog ("exampleprog", LOG_PID | LOG_PERROR, LOG_USER); * @endcode * * @param priority one of LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index c15a55c6..d8c7ae6d 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -77,6 +77,18 @@ extern "C" { #define DBG_CAN_SET_LISTEN_ONLY "(%s) %s Set Listen Only", __func__ #define DBG_CAN_CLR_LISTEN_ONLY "(%s) %s Leave Listen Only", __func__ +/* mainline */ +#define DBG_EMERGENCY_RX "CANopen Emergency message from node 0x%02X: errorCode=0x%04X, errorRegister=0x%02X, errorBit=0x%02X, infoCode=0x%08X" +#define DBG_NOT_TCP_PORT "(%s) -t argument \'%s\' is not a valid tcp port", __func__ +#define DBG_WRONG_NODE_ID "(%s) Wrong node ID \"%d\"", __func__ +#define DBG_WRONG_PRIORITY "(%s) Wrong RT priority \"%d\"", __func__ +#define DBG_NO_CAN_DEVICE "(%s) Can't find CAN device \"%s\"", __func__ +#define DBG_OBJECT_DICTIONARY "(%s) Error in Object Dictionary \"%s\"", __func__ +#define DBG_CAN_OPEN "(%s) CANopen error in %s, err=%d", __func__ +#define DBG_CAN_OPEN_INFO "(%s) CANopen device, Node ID = %d(0x%02X), %s", __func__ +#define DBG_COMMAND_LOCAL_INFO "(%s) Command interface on socket \"%s\" started", __func__ +#define DBG_COMMAND_TCP_INFO "(%s) Command interface on tcp port \"%hu\" started", __func__ + #ifdef __cplusplus } diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 57a74978..dc9d30c4 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -55,16 +55,20 @@ /* Use DS309-3 standard - ASCII command interface to CANopen: NMT master, * LSS master and SDO client */ -#ifdef CO_309 +#if CO_CONFIG_309 > 0 #include "CO_command.h" #endif -/* Interval of real-time thread in microseconds */ +/* Interval of mainline and real-time thread in microseconds */ +#ifndef MAIN_THREAD_INTERVAL_US +#define MAIN_THREAD_INTERVAL_US 100000 +#endif #ifndef TMR_THREAD_INTERVAL_US #define TMR_THREAD_INTERVAL_US 1000 #endif -#ifdef CO_309 + +#if CO_CONFIG_309 > 0 /* Mutex is locked, when CAN is not valid (configuration state). May be used * from command interface. RT threads may use CO->CANmodule[0]->CANnormal instead. */ pthread_mutex_t CO_CAN_VALID_mtx = PTHREAD_MUTEX_INITIALIZER; @@ -72,25 +76,21 @@ pthread_mutex_t CO_CAN_VALID_mtx = PTHREAD_MUTEX_INITIALIZER; /* Other variables and objects */ static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ -static int mainline_epoll_fd; /* epoll file descriptor for mainline */ +static int nodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ static CO_OD_storage_t odStor; /* Object Dictionary storage object for CO_OD_ROM */ static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ static char *odStorFile_rom = "od_storage"; /* Name of the file */ static char *odStorFile_eeprom = "od_storage_auto"; /* Name of the file */ -#ifdef CO_309 +#if CO_CONFIG_309 > 0 static in_port_t CO_command_socket_tcp_port = 60000; /* default port when used in tcp gateway mode */ #endif #if CO_NO_TRACE > 0 static CO_time_t CO_time; /* Object for current time */ #endif +/* Helper functions ***********************************************************/ /* Realtime thread */ -#ifdef CO_MULTI_THREAD -static void* rt_thread(void* arg); -static pthread_t rt_thread_id; -static int rt_thread_epoll_fd; -#endif - +static void* rt_thread(void* arg); /* Signal handler */ volatile sig_atomic_t CO_endProgram = 0; @@ -98,24 +98,25 @@ static void sigHandler(int sig) { CO_endProgram = 1; } - -/* Helper functions ***********************************************************/ -void CO_errExit(char* msg) { - perror(msg); - exit(EXIT_FAILURE); -} - -/* send CANopen generic emergency message */ -void CO_error(const uint32_t info) { - CO_errorReport(CO->em, CO_EM_GENERIC_SOFTWARE_ERROR, CO_EMC_SOFTWARE_INTERNAL, info); - fprintf(stderr, "canopend generic error: 0x%X\n", info); +/* callback for emergency messages */ +static void EmergencyRxCallback(const uint16_t ident, + const uint16_t errorCode, + const uint8_t errorRegister, + const uint8_t errorBit, + const uint32_t infoCode) +{ + int16_t nodeIdRx = ident ? (ident&0x7F) : nodeId; + + log_printf(LOG_NOTICE, DBG_EMERGENCY_RX, nodeIdRx, errorCode, + errorRegister, errorBit, infoCode); } +/* Print usage */ static void printUsage(char *progName) { -fprintf(stderr, +printf( "Usage: %s [options]\n", progName); -fprintf(stderr, +printf( "\n" "Options:\n" " -i CANopen Node-id (1..127). If not specified, value from\n" @@ -126,31 +127,30 @@ fprintf(stderr, " -s Set Filename for OD storage ('od_storage' is default).\n" " -a Set Filename for automatic storage variables from\n" " Object dictionary. ('od_storage_auto' is default).\n"); -#ifdef CO_309 -fprintf(stderr, +#if CO_CONFIG_309 > 0 +printf( " -c Enable command interface for master functionality. \n" " If socket path is specified as empty string \"\",\n" " default '%s' will be used.\n" " Note that location of socket path may affect security.\n" " See 'canopencomm/canopencomm --help' for more info.\n" , CO_command_socketPath); -fprintf(stderr, -" -t Enable command interface for master functionality over tcp, \n" -" listen to .\n" +printf( +" -t Enable command interface for master functionality over\n" +" tcp, listen to .\n" " Note that using this mode may affect security.\n" ); #endif -fprintf(stderr, +printf( "\n" "See also: https://github.com/CANopenNode/CANopenNode\n" "\n"); } -/******************************************************************************/ -/** Mainline and RT thread **/ -/******************************************************************************/ +/*Mainline thread *************************************************************/ int main (int argc, char *argv[]) { + pthread_t rt_thread_id; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_ReturnError_t err; CO_ReturnError_t odStorStatus_rom, odStorStatus_eeprom; @@ -160,20 +160,21 @@ int main (int argc, char *argv[]) { char* CANdevice = NULL; /* CAN device, configurable by arguments. */ bool_t nodeIdFromArgs = false; /* True, if program arguments are used for CANopen Node Id */ - int nodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ bool_t rebootEnable = false; /* Configurable by arguments */ -#ifdef CO_309 +#if CO_CONFIG_309 > 0 typedef enum CMD_MODE {CMD_NONE, CMD_LOCAL, CMD_REMOTE} cmdMode_t; cmdMode_t commandEnable = CMD_NONE; /* Configurable by arguments */ #endif + /* configure system log */ + setlogmask(LOG_UPTO (LOG_DEBUG)); /* LOG_DEBUG - log all meessages */ + openlog(argv[0], LOG_PID | LOG_PERROR, LOG_USER); /* print also to standard error */ + + /* Get program options */ if(argc < 2 || strcmp(argv[1], "--help") == 0){ printUsage(argv[0]); exit(EXIT_SUCCESS); } - - - /* Get program options */ while((opt = getopt(argc, argv, "i:p:rc:t:s:a:")) != -1) { switch (opt) { case 'i': @@ -182,7 +183,7 @@ int main (int argc, char *argv[]) { break; case 'p': rtPriority = strtol(optarg, NULL, 0); break; case 'r': rebootEnable = true; break; -#ifdef CO_309 +#if CO_CONFIG_309 > 0 case 'c': /* In case of empty string keep default name, just enable interface. */ if(strlen(optarg) != 0) { @@ -196,8 +197,8 @@ int main (int argc, char *argv[]) { //CO_command_socket_tcp_port = optarg; int scanResult = sscanf(optarg, "%hu", &CO_command_socket_tcp_port); if(scanResult != 1){ //expect one argument to be extracted - printf("ERROR: -t argument \'%s\' is not a valid tcp port\n", optarg); - exit(EXIT_FAILURE); + log_printf(LOG_CRIT, DBG_NOT_TCP_PORT, optarg); + exit(EXIT_FAILURE); } } commandEnable = CMD_REMOTE; @@ -217,47 +218,46 @@ int main (int argc, char *argv[]) { } if(nodeIdFromArgs && (nodeId < 1 || nodeId > 127)) { - fprintf(stderr, "Wrong node ID (%d)\n", nodeId); + log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, nodeId); printUsage(argv[0]); exit(EXIT_FAILURE); } if(rtPriority != -1 && (rtPriority < sched_get_priority_min(SCHED_FIFO) || rtPriority > sched_get_priority_max(SCHED_FIFO))) { - fprintf(stderr, "Wrong RT priority (%d)\n", rtPriority); + log_printf(LOG_CRIT, DBG_WRONG_PRIORITY, rtPriority); printUsage(argv[0]); exit(EXIT_FAILURE); } if(CANdevice0Index == 0) { - char s[120]; - snprintf(s, 120, "Can't find CAN device \"%s\"", CANdevice); - CO_errExit(s); + log_printf(LOG_CRIT, DBG_NO_CAN_DEVICE, CANdevice); + exit(EXIT_FAILURE); } - printf("%s - starting CANopen device with Node ID %d(0x%02X)", argv[0], nodeId, nodeId); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, nodeId, nodeId, "starting"); /* Allocate memory for CANopen objects */ - err = CO_new(); + err = CO_new(NULL); if (err != CO_ERROR_NO) { - fprintf(stderr, "Program init - %s - CO_new() failed.\n", argv[0]); + log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_new()", err); exit(EXIT_FAILURE); } /* Verify, if OD structures have proper alignment of initial values */ if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) { - fprintf(stderr, "Program init - %s - Error in CO_OD_RAM.\n", argv[0]); + log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, "CO_OD_RAM"); exit(EXIT_FAILURE); } if(CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) { - fprintf(stderr, "Program init - %s - Error in CO_OD_EEPROM.\n", argv[0]); + log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, "CO_OD_EEPROM"); exit(EXIT_FAILURE); } if(CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) { - fprintf(stderr, "Program init - %s - Error in CO_OD_ROM.\n", argv[0]); + log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, "CO_OD_ROM"); exit(EXIT_FAILURE); } @@ -268,22 +268,23 @@ int main (int argc, char *argv[]) { /* Catch signals SIGINT and SIGTERM */ - if(signal(SIGINT, sigHandler) == SIG_ERR) - CO_errExit("Program init - SIGINIT handler creation failed"); - if(signal(SIGTERM, sigHandler) == SIG_ERR) - CO_errExit("Program init - SIGTERM handler creation failed"); - - /* increase variable each startup. Variable is automatically stored in non-volatile memory. */ - printf(", count=%u ...\n", ++OD_powerOnCounter); + if(signal(SIGINT, sigHandler) == SIG_ERR) { + log_printf(LOG_CRIT, DBG_ERRNO, "signal(SIGINT, sigHandler)"); + exit(EXIT_FAILURE); + } + if(signal(SIGTERM, sigHandler) == SIG_ERR) { + log_printf(LOG_CRIT, DBG_ERRNO, "signal(SIGTERM, sigHandler)"); + exit(EXIT_FAILURE); + } while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { /* CANopen communication reset - initialize CANopen objects *******************/ - printf("%s - communication reset ...\n", argv[0]); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, nodeId, nodeId, "communication reset"); -#ifdef CO_309 +#if CO_CONFIG_309 > 0 /* Wait other threads (command interface). */ pthread_mutex_lock(&CO_CAN_VALID_mtx); #endif @@ -307,16 +308,19 @@ int main (int argc, char *argv[]) { } err = CO_CANinit((void *)CANdevice0Index, 0 /* bit rate not used */); - if (err == CO_ERROR_NO) { - err = CO_CANopenInit(nodeId); + if(err != CO_ERROR_NO) { + log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANinit()", err); + exit(EXIT_FAILURE); } + err = CO_CANopenInit(nodeId); if(err != CO_ERROR_NO) { - char s[120]; - snprintf(s, 120, "Communication reset - CANopen initialization failed, err=%d", err); - CO_errExit(s); + log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); + exit(EXIT_FAILURE); } + /* initialize callbacks */ + CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); /* initialize OD objects 1010 and 1011 and verify errors. */ CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U); @@ -329,13 +333,6 @@ int main (int argc, char *argv[]) { } - /* Configure callback functions for thread control */ -// void CO_CANopenInitCallback(void *object, void (*pFunctSignal)(void *object)); -// CO_EM_initCallback(CO->em, threadMain_cbSignal); -// CO_SDO_initCallback(CO->SDO[0], threadMain_cbSignal); -// CO_SDOclient_initCallback(CO->SDOclient, threadMain_cbSignal); - - #if CO_NO_TRACE > 0 /* Initialize time */ CO_time_init(&CO_time, CO->SDO[0], &OD_time.epochTimeBaseMs, &OD_time.epochTimeOffsetMs, 0x2130); @@ -345,52 +342,43 @@ int main (int argc, char *argv[]) { if(firstRun) { firstRun = false; - /* Configure epoll for mainline */ - mainline_epoll_fd = epoll_create(4); - if(mainline_epoll_fd == -1) - CO_errExit("Program init - epoll_create mainline failed"); - /* Init mainline */ - threadMain_init(mainline_epoll_fd, &OD_performance[ODA_performance_mainCycleMaxTime]); + /* Init threadMainWait structure and file descriptors */ + threadMainWait_init(MAIN_THREAD_INTERVAL_US); -#ifdef CO_MULTI_THREAD - /* Configure epoll for rt_thread */ - rt_thread_epoll_fd = epoll_create(2); - if(rt_thread_epoll_fd == -1) - CO_errExit("Program init - epoll_create rt_thread failed"); + /* Init threadRT structure and file descriptors */ + CANrx_threadTmr_init(TMR_THREAD_INTERVAL_US); - /* Init threadRT */ - CANrx_threadTmr_init(rt_thread_epoll_fd, TMR_THREAD_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]); - - /* Create rt_thread */ - if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) - CO_errExit("Program init - rt_thread creation failed"); - - /* Set priority for rt_thread */ + /* Create rt_thread and set priority */ + if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "pthread_create(rt_thread)"); + exit(EXIT_FAILURE); + } if(rtPriority > 0) { struct sched_param param; param.sched_priority = rtPriority; - if(pthread_setschedparam(rt_thread_id, SCHED_FIFO, ¶m) != 0) - CO_errExit("Program init - rt_thread set scheduler failed"); + if (pthread_setschedparam(rt_thread_id, SCHED_FIFO, ¶m) != 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "pthread_setschedparam()"); + exit(EXIT_FAILURE); + } } -#endif -#ifdef CO_309 +#if CO_CONFIG_309 > 0 /* Initialize socket command interface */ switch(commandEnable) { case CMD_LOCAL: if(CO_command_init() != 0) { CO_errExit("Socket command interface initialization failed"); } - printf("%s - Command interface on socket '%s' started ...\n", argv[0], CO_command_socketPath); + log_printf(LOG_INFO, DBG_COMMAND_LOCAL_INFO, CO_command_socketPath); break; case CMD_REMOTE: if(CO_command_init_tcp(CO_command_socket_tcp_port) != 0) { CO_errExit("Socket command interface initialization failed"); } - printf("%s - Command interface on tcp port '%hu' started ...\n", argv[0], CO_command_socket_tcp_port); + log_printf(LOG_INFO, DBG_COMMAND_TCP_INFO, CO_command_socket_tcp_port); break; default: break; @@ -413,58 +401,32 @@ int main (int argc, char *argv[]) { /* start CAN */ CO_CANsetNormalMode(CO->CANmodule[0]); -#ifdef CO_309 +#if CO_CONFIG_309 > 0 pthread_mutex_unlock(&CO_CAN_VALID_mtx); #endif reset = CO_RESET_NOT; - printf("%s - running ...\n", argv[0]); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, nodeId, nodeId, "running ..."); while(reset == CO_RESET_NOT && CO_endProgram == 0) { /* loop for normal program execution ******************************************/ - int ready; - struct epoll_event ev; - - ready = epoll_wait(mainline_epoll_fd, &ev, 1, -1); - - if(ready != 1) { - if(errno != EINTR) { - CO_error(0x11100000L + errno); - } - } - - else if(threadMain_process(ev.data.fd, &reset, CO_timer1ms)) { - uint16_t timer1msDiff; - static uint16_t tmr1msPrev = 0; - - /* Calculate time difference */ - timer1msDiff = CO_timer1ms - tmr1msPrev; - tmr1msPrev = CO_timer1ms; - - /* code was processed in the above function. Additional code process below */ + uint32_t timer1usDiff = threadMainWait_process(&reset); #ifdef CO_USE_APPLICATION - /* Execute optional additional application code */ - app_programAsync(timer1msDiff); + app_programAsync(timer1usDiff); #endif - CO_OD_storage_autoSave(&odStorAuto, CO_timer1ms, 60000); - } - - else { - /* No file descriptor was processed. */ - CO_error(0x11200000L); - } + CO_OD_storage_autoSave(&odStorAuto, timer1usDiff, 60000000); } } /* program exit ***************************************************************/ /* join threads */ -#ifdef CO_309 +#if CO_CONFIG_309 > 0 switch (commandEnable) { case CMD_LOCAL: @@ -481,11 +443,10 @@ int main (int argc, char *argv[]) { #endif CO_endProgram = 1; -#ifdef CO_MULTI_THREAD - if(pthread_join(rt_thread_id, NULL) != 0) { - CO_errExit("Program end - pthread_join failed"); + if (pthread_join(rt_thread_id, NULL) != 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "pthread_join()"); + exit(EXIT_FAILURE); } -#endif #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ @@ -498,16 +459,17 @@ int main (int argc, char *argv[]) { /* delete objects from memory */ CANrx_threadTmr_close(); - threadMain_close(); + threadMainWait_close(); CO_delete((void *)CANdevice0Index); - printf("%s on %s (nodeId=0x%02X) - finished.\n\n", argv[0], CANdevice, nodeId); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, nodeId, nodeId, "finished"); /* Flush all buffers (and reboot) */ if(rebootEnable && reset == CO_RESET_APP) { sync(); if(reboot(LINUX_REBOOT_CMD_RESTART) != 0) { - CO_errExit("Program end - reboot failed"); + log_printf(LOG_CRIT, DBG_ERRNO, "reboot()"); + exit(EXIT_FAILURE); } } @@ -515,47 +477,28 @@ int main (int argc, char *argv[]) { } -#ifdef CO_MULTI_THREAD /* Realtime thread for CAN receive and threadTmr ******************************/ static void* rt_thread(void* arg) { /* Endless loop */ while(CO_endProgram == 0) { - int ready; - struct epoll_event ev; - ready = epoll_wait(rt_thread_epoll_fd, &ev, 1, -1); - - if(ready != 1) { - if(errno != EINTR) { - CO_error(0x12100000L + errno); - } - } - - else if(CANrx_threadTmr_process(ev.data.fd)) { - int i; + CANrx_threadTmr_process(); #if CO_NO_TRACE > 0 - /* Monitor variables with trace objects */ - CO_time_process(&CO_time); - for(i=0; itrace[i], *CO_time.epochTimeOffsetMs); - } + /* Monitor variables with trace objects */ + CO_time_process(&CO_time); + for(i=0; itrace[i], *CO_time.epochTimeOffsetMs); + } #endif #ifdef CO_USE_APPLICATION - /* Execute optional additional application code */ - app_program1ms(); + /* Execute optional additional application code */ + app_program1ms(); #endif - } - - else { - /* No file descriptor was processed. */ - CO_error(0x12200000L); - } } return NULL; } -#endif /* CO_MULTI_THREAD */ From 1624b7443d4e314fbe952ccc7328a570b4cc7649 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 12 Mar 2020 10:42:19 +0100 Subject: [PATCH 039/520] Ignore sync message in Emergency receive function CO_EM_receive(). --- 301/CO_Emergency.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index a0df65c3..824c3c38 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -43,17 +43,20 @@ static void CO_EM_receive(void *object, void *msg) { if(em!=NULL && em->pFunctSignalRx!=NULL){ uint16_t ident = CO_CANrxMsg_readIdent(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); - uint16_t errorCode; - uint32_t infoCode; - - CO_memcpySwap2(&errorCode, &data[0]); - CO_memcpySwap4(&infoCode, &data[4]); - em->pFunctSignalRx(ident, - errorCode, - data[2], - data[3], - infoCode); + if (ident != 0x80) { + /* ignore sync messages (necessary if sync object is not used) */ + uint8_t *data = CO_CANrxMsg_readData(msg); + uint16_t errorCode; + uint32_t infoCode; + + CO_memcpySwap2(&errorCode, &data[0]); + CO_memcpySwap4(&infoCode, &data[4]); + em->pFunctSignalRx(ident, + errorCode, + data[2], + data[3], + infoCode); + } } } From 2f204a0c71be256f814dedfa291452d466462698 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 12 Mar 2020 12:18:05 +0100 Subject: [PATCH 040/520] Verify return value from CO_CANrxBufferInit() and CO_CANtxBufferInit(). --- 301/CO_Emergency.c | 9 +++++++-- 301/CO_HBconsumer.c | 23 +++++++++++---------- 301/CO_NMT_Heartbeat.c | 10 +++++++-- 301/CO_SDOclient.c | 6 +++++- 301/CO_SDOserver.c | 10 +++++++-- 301/CO_SYNC.c | 46 +++++++++++++++++++++++++++++++----------- 301/CO_TIME.c | 17 +++++++++++----- 305/CO_LSSmaster.c | 10 +++++++-- 305/CO_LSSslave.c | 10 +++++++-- 9 files changed, 102 insertions(+), 39 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 824c3c38..1a330a9e 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -147,6 +147,7 @@ CO_ReturnError_t CO_EM_init( uint16_t CANidTxEM) { uint8_t i; + CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ if(em==NULL || emPr==NULL || SDO==NULL || errorStatusBits==NULL || errorStatusBitsSize<6U || @@ -182,7 +183,7 @@ CO_ReturnError_t CO_EM_init( CO_OD_configure(SDO, OD_H1014_COBID_EMERGENCY, CO_ODF_1014, (void*)&SDO->nodeId, 0, 0U); /* configure SDO server CAN reception */ - CO_CANrxBufferInit( + ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ CO_CAN_ID_EMERGENCY, /* CAN identifier */ @@ -202,7 +203,11 @@ CO_ReturnError_t CO_EM_init( 8U, /* number of data bytes */ 0); /* synchronous message flag bit */ - return CO_ERROR_NO; + if (emPr->CANtxBuff == NULL) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; } diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 1cd904e5..5dfeb8d5 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -98,6 +98,7 @@ CO_ReturnError_t CO_HBconsumer_init( uint16_t CANdevRxIdxStart) { uint8_t i; + CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ if(HBcons==NULL || em==NULL || SDO==NULL || HBconsTime==NULL || @@ -119,13 +120,13 @@ CO_ReturnError_t CO_HBconsumer_init( for(i=0; inumberOfMonitoredNodes; i++) { uint8_t nodeId = (HBcons->HBconsTime[i] >> 16U) & 0xFFU; uint16_t time = HBcons->HBconsTime[i] & 0xFFFFU; - CO_HBconsumer_initEntry(HBcons, i, nodeId, time); + ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); } /* Configure Object dictionary entry at index 0x1016 */ CO_OD_configure(SDO, OD_H1016_CONSUMER_HB_TIME, CO_ODF_1016, (void*)HBcons, 0, 0); - return CO_ERROR_NO; + return ret; } @@ -139,7 +140,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if(HBcons==NULL){ + if (HBcons == NULL || idx >= HBcons->numberOfMonitoredNodes) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -157,7 +158,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( } /* Configure one monitored node */ - if (ret == CO_ERROR_NO && idx < HBcons->numberOfMonitoredNodes ) { + if (ret == CO_ERROR_NO) { uint16_t COB_ID; CO_HBconsNode_t * monitoredNode = &HBcons->monitoredNodes[idx]; @@ -179,13 +180,13 @@ CO_ReturnError_t CO_HBconsumer_initEntry( /* configure Heartbeat consumer CAN reception */ if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { - CO_CANrxBufferInit(HBcons->CANdevRx, - HBcons->CANdevRxIdxStart + idx, - COB_ID, - 0x7FF, - 0, - (void*)&HBcons->monitoredNodes[idx], - CO_HBcons_receive); + ret = CO_CANrxBufferInit(HBcons->CANdevRx, + HBcons->CANdevRxIdxStart + idx, + COB_ID, + 0x7FF, + 0, + (void*)&HBcons->monitoredNodes[idx], + CO_HBcons_receive); } } return ret; diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index f5b2b27c..3bbc1729 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -101,6 +101,8 @@ CO_ReturnError_t CO_NMT_init( return CO_ERROR_ILLEGAL_ARGUMENT; } + CO_ReturnError_t ret = CO_ERROR_NO; + /* blinking bytes and LEDS */ #if CO_CONFIG_NMT_LEDS > 0 NMT->LEDtimer = 0; @@ -124,7 +126,7 @@ CO_ReturnError_t CO_NMT_init( NMT->pFunctNMT = NULL; /* configure NMT CAN reception */ - CO_CANrxBufferInit( + ret = CO_CANrxBufferInit( NMT_CANdevRx, /* CAN device */ NMT_rxIdx, /* rx buffer index */ CANidRxNMT, /* CAN identifier */ @@ -153,7 +155,11 @@ CO_ReturnError_t CO_NMT_init( 1, /* number of data bytes */ 0); /* synchronous message flag bit */ - return CO_ERROR_NO; + if (NMT->NMT_TXbuff == NULL || NMT->HB_TXbuff == NULL) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; } diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index ddd07923..dbbc7874 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -271,7 +271,7 @@ CO_SDOclient_return_t CO_SDOclient_setup( /* configure SDO client CAN reception, if differs. */ if(SDO_C->COB_IDClientToServerPrev != idCtoS || SDO_C->COB_IDServerToClientPrev != idStoC) { - CO_CANrxBufferInit( + CO_ReturnError_t ret = CO_CANrxBufferInit( SDO_C->CANdevRx, /* CAN device */ SDO_C->CANdevRxIdx, /* rx buffer index */ (uint16_t)idStoC, /* CAN identifier */ @@ -291,6 +291,10 @@ CO_SDOclient_return_t CO_SDOclient_setup( SDO_C->COB_IDClientToServerPrev = idCtoS; SDO_C->COB_IDServerToClientPrev = idStoC; + + if (ret != CO_ERROR_NO || SDO_C->CANtxBuff == NULL) { + return CO_SDOcli_wrongArguments; + } } return CO_SDOcli_ok_communicationEnd; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index c86f5035..1b9062e4 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -287,6 +287,8 @@ CO_ReturnError_t CO_SDO_init( CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx) { + CO_ReturnError_t ret = CO_ERROR_NO; + /* verify arguments */ if(SDO==NULL || CANdevRx==NULL || CANdevTx==NULL){ return CO_ERROR_ILLEGAL_ARGUMENT; @@ -336,7 +338,7 @@ CO_ReturnError_t CO_SDO_init( COB_IDServerToClient = 0; } /* configure SDO server CAN reception */ - CO_CANrxBufferInit( + ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ COB_IDClientToServer, /* CAN identifier */ @@ -355,7 +357,11 @@ CO_ReturnError_t CO_SDO_init( 8, /* number of data bytes */ 0); /* synchronous message flag bit */ - return CO_ERROR_NO; + if (SDO->CANtxBuff == NULL) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; } diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index a5347884..8c720d6a 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -105,7 +105,7 @@ static CO_SDO_abortCode_t CO_ODF_1005(CO_ODF_arg_t *ODF_arg){ } } - /* configure sync producer and consumer */ + /* configure sync producer */ if(ret == CO_SDO_AB_NONE){ SYNC->COB_ID = (uint16_t)(value & 0x7FFU); @@ -123,20 +123,33 @@ static CO_SDO_abortCode_t CO_ODF_1005(CO_ODF_arg_t *ODF_arg){ 0, /* rtr */ len, /* number of data bytes */ 0); /* synchronous message flag bit */ - SYNC->isProducer = true; + + if (SYNC->CANtxBuff == NULL) { + ret = CO_SDO_AB_DATA_DEV_STATE; + SYNC->isProducer = false; + } else { + SYNC->isProducer = true; + } } else{ SYNC->isProducer = false; } + } - CO_CANrxBufferInit( - SYNC->CANdevRx, /* CAN device */ - SYNC->CANdevRxIdx, /* rx buffer index */ - SYNC->COB_ID, /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void*)SYNC, /* object passed to receive function */ - CO_SYNC_receive); /* this function will process received message */ + /* configure sync consumer */ + if (ret == CO_SDO_AB_NONE) { + CO_ReturnError_t CANret = CO_CANrxBufferInit( + SYNC->CANdevRx, /* CAN device */ + SYNC->CANdevRxIdx, /* rx buffer index */ + SYNC->COB_ID, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)SYNC, /* object passed to receive function */ + CO_SYNC_receive); /* this function will process received message */ + + if (CANret != CO_ERROR_NO) { + ret = CO_SDO_AB_DATA_DEV_STATE; + } } } @@ -212,6 +225,10 @@ static CO_SDO_abortCode_t CO_ODF_1019(CO_ODF_arg_t *ODF_arg){ 0, /* rtr */ len, /* number of data bytes */ 0); /* synchronous message flag bit */ + + if (SYNC->CANtxBuff == NULL) { + ret = CO_SDO_AB_DATA_DEV_STATE; + } } } @@ -234,6 +251,7 @@ CO_ReturnError_t CO_SYNC_init( uint16_t CANdevTxIdx) { uint8_t len = 0; + CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ if(SYNC==NULL || em==NULL || SDO==NULL || operatingState==NULL || @@ -273,7 +291,7 @@ CO_ReturnError_t CO_SYNC_init( CO_OD_configure(SDO, OD_H1019_SYNC_CNT_OVERFLOW, CO_ODF_1019, (void*)SYNC, 0, 0); /* configure SYNC CAN reception */ - CO_CANrxBufferInit( + ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ SYNC->COB_ID, /* CAN identifier */ @@ -293,7 +311,11 @@ CO_ReturnError_t CO_SYNC_init( len, /* number of data bytes */ 0); /* synchronous message flag bit */ - return CO_ERROR_NO; + if (SYNC->CANtxBuff == NULL) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; } diff --git a/301/CO_TIME.c b/301/CO_TIME.c index a4644a38..db352182 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -68,6 +68,8 @@ CO_ReturnError_t CO_TIME_init( CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx) { + CO_ReturnError_t ret = CO_ERROR_NO; + /* verify arguments */ if(TIME==NULL || em==NULL || SDO==NULL || operatingState==NULL || CANdevRx==NULL || CANdevTx==NULL){ @@ -96,8 +98,8 @@ CO_ReturnError_t CO_TIME_init( /* configure TIME consumer message reception */ TIME->CANdevRx = CANdevRx; TIME->CANdevRxIdx = CANdevRxIdx; - if(TIME->isConsumer) - CO_CANrxBufferInit( + if (TIME->isConsumer) { + ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ TIME->COB_ID, /* CAN identifier */ @@ -105,12 +107,12 @@ CO_ReturnError_t CO_TIME_init( 0, /* rtr */ (void*)TIME, /* object passed to receive function */ CO_TIME_receive); /* this function will process received message */ - + } /* configure TIME producer message transmission */ TIME->CANdevTx = CANdevTx; TIME->CANdevTxIdx = CANdevTxIdx; - if(TIME->isProducer) + if (TIME->isProducer) { TIME->TXbuff = CO_CANtxBufferInit( CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ @@ -119,7 +121,12 @@ CO_ReturnError_t CO_TIME_init( TIME_MSG_LENGTH, /* number of data bytes */ 0); /* synchronous message flag bit */ - return CO_ERROR_NO; + if (TIME->TXbuff == NULL) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + } + + return ret; } /******************************************************************************/ diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 75a54c59..0fa9635d 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -137,6 +137,8 @@ CO_ReturnError_t CO_LSSmaster_init( uint16_t CANdevTxIdx, uint32_t CANidLssMaster) { + CO_ReturnError_t ret = CO_ERROR_NO; + /* verify arguments */ if (LSSmaster==NULL || CANdevRx==NULL || CANdevTx==NULL){ return CO_ERROR_ILLEGAL_ARGUMENT; @@ -152,7 +154,7 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->functSignalObject = NULL; /* configure LSS CAN Slave response message reception */ - CO_CANrxBufferInit( + ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ CANidLssSlave, /* CAN identifier */ @@ -171,7 +173,11 @@ CO_ReturnError_t CO_LSSmaster_init( 8, /* number of data bytes */ 0); /* synchronous message flag bit */ - return CO_ERROR_NO; + if (LSSmaster->TXbuff == NULL) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; } diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index e9ec5808..bfa5e734 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -378,6 +378,8 @@ CO_ReturnError_t CO_LSSslave_init( uint16_t CANdevTxIdx, uint32_t CANidLssSlave) { + CO_ReturnError_t ret = CO_ERROR_NO; + /* verify arguments */ if (LSSslave==NULL || CANdevRx==NULL || CANdevTx==NULL || !CO_LSS_NODE_ID_VALID(pendingNodeID)) { @@ -408,7 +410,7 @@ CO_ReturnError_t CO_LSSslave_init( LSSslave->functLSScfgStore = NULL; /* configure LSS CAN Master message reception */ - CO_CANrxBufferInit( + ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ CANidLssMaster, /* CAN identifier */ @@ -427,7 +429,11 @@ CO_ReturnError_t CO_LSSslave_init( 8, /* number of data bytes */ 0); /* synchronous message flag bit */ - return CO_ERROR_NO; + if (LSSslave->TXbuff == NULL) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; } From 1ce3732e600dfb4dc1314cc22ffce57cc4e23878 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 12 Mar 2020 16:20:40 +0100 Subject: [PATCH 041/520] SocketCAN: change CO_DRIVER_MULTI_INTERFACE and CO_DRIVER_ERROR_REPORTING - Replace macro USE_EMERGENCY_OBJECT with CO_DRIVER_USE_EMERGENCY 1 - Now define sets macro to 0 or 1. It is easier to set custom value. --- 301/CO_NMT_Heartbeat.h | 2 +- doc/CHANGELOG.md | 3 +++ socketCAN/CO_driver.c | 45 ++++++++++++++++++------------------ socketCAN/CO_driver_target.h | 36 ++++++++++++++++++++--------- 4 files changed, 51 insertions(+), 35 deletions(-) diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 14e7786e..238b014d 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -129,7 +129,7 @@ typedef enum{ * @ref CO_NMT_statusLEDdiodes. Object is initialized by CO_NMT_init(). */ typedef struct{ -#if CO_CONFIG_NMT_LEDS > 0 +#if CO_CONFIG_NMT_LEDS > 0 || defined CO_DOXYGEN uint32_t LEDtimer; /**< 50ms led timer */ int8_t LEDflickering; /**< See @ref CO_NMT_statusLEDdiodes */ int8_t LEDblinking; /**< See @ref CO_NMT_statusLEDdiodes */ diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index c9413a8d..e808a274 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -18,10 +18,13 @@ Change Log - CO_driver.h file, function `CO_CANrxBufferInit()`, last argument (callback) changed from `(*pFunct)(void *object, const CO_CANrxMsg_t *message)` to `void (*CANrx_callback)(void *object, void *message)`. New functions are defined in `CO_driver_target.h` file: `CO_CANrxMsg_readIdent()`, `CO_CANrxMsg_readDLC()` and `CO_CANrxMsg_readData()`. - It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. - Added `void *object` argument to CO_*_initCallback() functions. API clarified. Callback functions called also from SDO_blockTransferInProgress. +- Add emergency receive callback also for own emergency messages. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN - driver API updated - CO_Linux_threads.h, function `void CANrx_threadTmr_init(uint16_t interval_in_milliseconds (changed to) uint32_t interval_in_microseconds)` +- CO_CANrxBufferInit(): remove check COB ID already used. +- change macros CO_DRIVER_MULTI_INTERFACE and CO_DRIVER_ERROR_REPORTING. To enable(disable), set to 1(0). ### Fixed - Bugfix in `CO_HBconsumer_process()`: argument `timeDifference_us` was set to 0 inside for loop, fixed now. - BUG in CO_HBconsumer.c #168 diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 7211e4fb..ff63fd38 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -39,21 +39,20 @@ #include "301/CO_driver.h" #include "CO_error.h" -#if __has_include("301/CO_Emergency.h") - #include "301/CO_Emergency.h" - #define USE_EMERGENCY_OBJECT +#if CO_DRIVER_USE_EMERGENCY > 0 +#include "301/CO_Emergency.h" #endif pthread_mutex_t CO_EMCY_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; -#ifndef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE == 0 static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, const void *CANptr); #endif -#ifdef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE > 0 static const uint32_t CO_INVALID_COB_ID = 0xffffffff; @@ -249,7 +248,7 @@ CO_ReturnError_t CO_CANmodule_init( CANmodule->CANnormal = false; CANmodule->em = NULL; //this is set inside CO_Emergency.c init function! CANmodule->fdTimerRead = -1; -#ifdef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE > 0 for (i = 0; i < CO_CAN_MSG_SFF_MAX_COB_ID; i++) { CANmodule->rxIdentToIndex[i] = CO_INVALID_COB_ID; CANmodule->txIdentToIndex[i] = CO_INVALID_COB_ID; @@ -275,7 +274,7 @@ CO_ReturnError_t CO_CANmodule_init( rxArray[i].timestamp.tv_nsec = 0; } -#ifndef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE == 0 /* add one interface */ ret = CO_CANmodule_addInterface(CANmodule, CANptr); if (ret != CO_ERROR_NO) { @@ -289,7 +288,7 @@ CO_ReturnError_t CO_CANmodule_init( /** enable socketCAN *********************************************************/ -#ifndef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE == 0 static #endif CO_ReturnError_t CO_CANmodule_addInterface( @@ -304,7 +303,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( CO_CANinterface_t *interface; struct sockaddr_can sockAddr; struct epoll_event ev; -#ifdef CO_DRIVER_ERROR_REPORTING +#if CO_DRIVER_ERROR_REPORTING > 0 can_err_mask_t err_mask; #endif @@ -379,7 +378,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( return CO_ERROR_SYSCALL; } -#ifdef CO_DRIVER_ERROR_REPORTING +#if CO_DRIVER_ERROR_REPORTING > 0 CO_CANerror_init(&interface->errorhandler, interface->fd, interface->ifName); /* set up error frame generation. What actually is available depends on your * CAN kernel driver */ @@ -427,7 +426,7 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) for (i = 0; i < CANmodule->CANinterfaceCount; i++) { CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; -#ifdef CO_DRIVER_ERROR_REPORTING +#if CO_DRIVER_ERROR_REPORTING > 0 CO_CANerror_disable(&interface->errorhandler); #endif @@ -480,7 +479,7 @@ CO_ReturnError_t CO_CANrxBufferInit( /* buffer, which will be configured */ buffer = &CANmodule->rxArray[index]; -#ifdef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE > 0 CO_CANsetIdentToIndex(CANmodule->rxIdentToIndex, index, ident, buffer->ident); #endif @@ -514,7 +513,7 @@ CO_ReturnError_t CO_CANrxBufferInit( return ret; } -#ifdef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE > 0 /******************************************************************************/ bool_t CO_CANrxBuffer_getInterface( @@ -568,7 +567,7 @@ CO_CANtx_t *CO_CANtxBufferInit( /* get specific buffer */ buffer = &CANmodule->txArray[index]; -#ifdef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE > 0 CO_CANsetIdentToIndex(CANmodule->txIdentToIndex, index, ident, buffer->ident); #endif @@ -587,7 +586,7 @@ CO_CANtx_t *CO_CANtxBufferInit( return buffer; } -#ifdef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE > 0 /******************************************************************************/ CO_ReturnError_t CO_CANtxBuffer_setInterface( @@ -618,7 +617,7 @@ static CO_ReturnError_t CO_CANCheckSendInterface( CO_CANinterface_t *interface) { CO_ReturnError_t err = CO_ERROR_NO; -#ifdef CO_DRIVER_ERROR_REPORTING +#if CO_DRIVER_ERROR_REPORTING > 0 CO_CANinterfaceState_t ifState; #endif ssize_t n; @@ -627,7 +626,7 @@ static CO_ReturnError_t CO_CANCheckSendInterface( return CO_ERROR_PARAMETERS; } -#ifdef CO_DRIVER_ERROR_REPORTING +#if CO_DRIVER_ERROR_REPORTING > 0 ifState = CO_CANerror_txMsg(&interface->errorhandler); switch (ifState) { case CO_INTERFACE_ACTIVE: @@ -663,7 +662,7 @@ static CO_ReturnError_t CO_CANCheckSendInterface( } while (errno != 0); if(n != CAN_MTU){ -#ifdef USE_EMERGENCY_OBJECT +#if CO_DRIVER_USE_EMERGENCY > 0 CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); #endif log_printf(LOG_ERR, DBG_CAN_TX_FAILED, buffer->ident, interface->ifName); @@ -702,7 +701,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) err = CO_CANCheckSend(CANmodule, buffer); if (err == CO_ERROR_TX_BUSY) { /* send doesn't have "busy" */ -#ifdef USE_EMERGENCY_OBJECT +#if CO_DRIVER_USE_EMERGENCY > 0 CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); #endif log_printf(LOG_ERR, DBG_CAN_TX_FAILED, buffer->ident, "CANx"); @@ -787,7 +786,7 @@ static CO_ReturnError_t CO_CANread( n = recvmsg(interface->fd, &msghdr, 0); if (n != CAN_MTU) { -#ifdef USE_EMERGENCY_OBJECT +#if CO_DRIVER_USE_EMERGENCY > 0 CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, n); #endif @@ -807,7 +806,7 @@ static CO_ReturnError_t CO_CANread( else if (cmsg->cmsg_type == SO_RXQ_OVFL) { dropped = *(uint32_t*)CMSG_DATA(cmsg); if (dropped > CANmodule->rxDropCount) { -#ifdef USE_EMERGENCY_OBJECT +#if CO_DRIVER_USE_EMERGENCY > 0 CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_COMMUNICATION, 0); #endif @@ -956,7 +955,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff if (msg.can_id & CAN_ERR_FLAG) { /* error msg */ -#ifdef CO_DRIVER_ERROR_REPORTING +#if CO_DRIVER_ERROR_REPORTING > 0 CO_CANerror_rxMsgError(&interface->errorhandler, &msg); #endif } @@ -964,7 +963,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff /* data msg */ int32_t msgIndex; -#ifdef CO_DRIVER_ERROR_REPORTING +#if CO_DRIVER_ERROR_REPORTING > 0 /* clear listenOnly and noackCounter if necessary */ CO_CANerror_rxMsg(&interface->errorhandler); #endif diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index ec10b6a4..e3b62a08 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -73,19 +73,20 @@ extern "C" { * given interfaces as well as combining all received message into * one queue. * - * If CO_DRIVER_MULTI_INTERFACE is disabled, then CO_CANmodule_init() + * If CO_DRIVER_MULTI_INTERFACE is set to 0, then CO_CANmodule_init() * adds single socketCAN interface specified by CANptr argument. In case of * failure, CO_CANmodule_init() returns CO_ERROR_SYSCALL. * - * If CO_DRIVER_MULTI_INTERFACE is enabled, then CO_CANmodule_init() + * If CO_DRIVER_MULTI_INTERFACE is set to 1, then CO_CANmodule_init() * ignores CANptr argument. Interfaces must be added by * CO_CANmodule_addInterface() function after CO_CANmodule_init(). * + * Macro is set to 0 (disabled) by default. It can be overridden. + * * This is not intended to realize interface redundancy!!! */ -/* #define CO_DRIVER_MULTI_INTERFACE */ -#ifdef CO_DOXYGEN -#define CO_DRIVER_MULTI_INTERFACE +#ifndef CO_DRIVER_MULTI_INTERFACE +#define CO_DRIVER_MULTI_INTERFACE 0 #endif /** @@ -96,6 +97,8 @@ extern "C" { * CANopen with "0" connected nodes as a use case, as this is normally * forbidden in CAN. * + * Macro is set to 1 (enabled) by default. It can be overridden. + * * you need to enable error reporting in your kernel driver using: * @code{.sh} * ip link set canX type can berr-reporting on @@ -103,9 +106,20 @@ extern "C" { * Of course, the kernel driver for your hardware needs this functionality to be * implemented... */ -/* #define CO_DRIVER_ERROR_REPORTING */ -#ifdef CO_DOXYGEN -#define CO_DRIVER_ERROR_REPORTING +#ifndef CO_DRIVER_ERROR_REPORTING +#define CO_DRIVER_ERROR_REPORTING 1 +#endif + +/** + * Use CANopen Emergency object on CAN RX or TX overflow. + * + * If CO_DRIVER_USE_EMERGENCY is set to 1, then CANopen Emergency message will + * be sent, if CAN rx or tx bufers are overflowed. + * + * Macro is set to 1 (enabled) by default. It can be overridden. + */ +#ifndef CO_DRIVER_USE_EMERGENCY +#define CO_DRIVER_USE_EMERGENCY 1 #endif /* skip this section for Doxygen, because it is documented in CO_driver.h */ @@ -185,7 +199,7 @@ typedef struct { const void *CANptr; /* CAN Interface identifier */ char ifName[IFNAMSIZ]; /* CAN Interface name */ int fd; /* socketCAN file descriptor */ -#ifdef CO_DRIVER_ERROR_REPORTING +#if CO_DRIVER_ERROR_REPORTING > 0 || defined CO_DOXYGEN CO_CANinterfaceErrorhandler_t errorhandler; #endif } CO_CANinterface_t; @@ -208,7 +222,7 @@ typedef struct { int fdEpoll; /* epoll FD for pipe, CANrx sockets in all interfaces and fdTimerRead */ int fdTimerRead; /* timer handle from CANrxWait() */ -#ifdef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE > 0 || defined CO_DOXYGEN /* Lookup tables Cob ID to rx/tx array index. * Only feasible for SFF Messages. */ uint32_t rxIdentToIndex[CO_CAN_MSG_SFF_MAX_COB_ID]; @@ -248,7 +262,7 @@ static inline void CO_UNLOCK_OD() { #endif /* CO_DOXYGEN */ -#ifdef CO_DRIVER_MULTI_INTERFACE +#if CO_DRIVER_MULTI_INTERFACE > 0 || defined CO_DOXYGEN /** * Add socketCAN interface to can driver * From 18bc8d43130f43a8372bb8420f49143b4854c4ee Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 13 Mar 2020 16:05:27 +0100 Subject: [PATCH 042/520] HBconsumer: add CO_HBconsumer_initCallbackNmtChanged(), callbaks optional - Make HBconsumer callbacks optional via CO_CONFIG_HB_CONS_CALLBACKS definition. - Add additional callback CO_HBconsumer_initCallbackNmtChanged() --- 301/CO_HBconsumer.c | 50 ++++++++++++++++++++-- 301/CO_HBconsumer.h | 83 ++++++++++++++++++++++++++++-------- 301/CO_driver.h | 18 ++++++++ socketCAN/CO_driver_target.h | 3 ++ 4 files changed, 134 insertions(+), 20 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 5dfeb8d5..7ebdb24e 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -165,6 +165,9 @@ CO_ReturnError_t CO_HBconsumer_initEntry( monitoredNode->nodeId = nodeId; monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; monitoredNode->NMTstate = CO_NMT_INITIALIZING; +#if CO_CONFIG_HB_CONS_CALLBACKS & 1 + monitoredNode->NMTstatePrev = CO_NMT_INITIALIZING; +#endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); /* is channel used */ @@ -193,6 +196,26 @@ CO_ReturnError_t CO_HBconsumer_initEntry( } +#if CO_CONFIG_HB_CONS_CALLBACKS & 1 +/******************************************************************************/ +void CO_HBconsumer_initCallbackNmtChanged( + CO_HBconsumer_t *HBcons, + void *object, + void (*pFunctSignal)(uint8_t nodeId, + CO_NMT_internalState_t NMTstate, + void *object)) +{ + if (HBcons==NULL) { + return; + } + + HBcons->pFunctSignalNmtChanged = pFunctSignal; + HBcons->pFunctSignalObjectNmtChanged = object; +} +#endif /* CO_CONFIG_HB_CONS_CALLBACKS & 1 */ + + +#if CO_CONFIG_HB_CONS_CALLBACKS & 2 /******************************************************************************/ void CO_HBconsumer_initCallbackHeartbeatStarted( CO_HBconsumer_t *HBcons, @@ -248,6 +271,7 @@ void CO_HBconsumer_initCallbackRemoteReset( monitoredNode->pFunctSignalRemoteReset = pFunctSignal; monitoredNode->functSignalObjectRemoteReset = object; } +#endif /* CO_CONFIG_HB_CONS_CALLBACKS & 2 */ /******************************************************************************/ @@ -273,12 +297,14 @@ void CO_HBconsumer_process( /* Verify if received message is heartbeat or bootup */ if (CO_FLAG_READ(monitoredNode->CANrxNew)) { if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) { - /* bootup message, call callback */ + /* bootup message*/ +#if CO_CONFIG_HB_CONS_CALLBACKS & 2 if (monitoredNode->pFunctSignalRemoteReset != NULL) { monitoredNode->pFunctSignalRemoteReset( monitoredNode->nodeId, i, monitoredNode->functSignalObjectRemoteReset); } +#endif if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) { CO_errorReport(HBcons->em, CO_EM_HB_CONSUMER_REMOTE_RESET, @@ -288,13 +314,15 @@ void CO_HBconsumer_process( } else { - /* heartbeat message, call callback */ + /* heartbeat message */ +#if CO_CONFIG_HB_CONS_CALLBACKS & 2 if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE && monitoredNode->pFunctSignalHbStarted != NULL) { monitoredNode->pFunctSignalHbStarted( monitoredNode->nodeId, i, monitoredNode->functSignalObjectHbStarted); } +#endif monitoredNode->HBstate = CO_HBconsumer_ACTIVE; /* reset timer */ monitoredNode->timeoutTimer = 0; @@ -308,12 +336,14 @@ void CO_HBconsumer_process( monitoredNode->timeoutTimer += timeDifference_us_copy; if (monitoredNode->timeoutTimer >= monitoredNode->time_us) { - /* timeout expired, call callback */ + /* timeout expired */ +#if CO_CONFIG_HB_CONS_CALLBACKS & 2 if (monitoredNode->pFunctSignalTimeout!=NULL) { monitoredNode->pFunctSignalTimeout( monitoredNode->nodeId, i, monitoredNode->functSignalObjectTimeout); } +#endif CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, i); monitoredNode->NMTstate = CO_NMT_INITIALIZING; @@ -336,6 +366,17 @@ void CO_HBconsumer_process( if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { allMonitoredOperationalCurrent = CO_NMT_INITIALIZING; } +#if CO_CONFIG_HB_CONS_CALLBACKS & 1 + /* Verify, if NMT state of monitored node changed */ + if(monitoredNode->NMTstate != monitoredNode->NMTstatePrev) { + if (HBcons->pFunctSignalNmtChanged != NULL) { + HBcons->pFunctSignalNmtChanged( + monitoredNode->nodeId, monitoredNode->NMTstate, + HBcons->pFunctSignalObjectNmtChanged); + } + monitoredNode->NMTstatePrev = monitoredNode->NMTstate; + } +#endif monitoredNode++; } } @@ -343,6 +384,9 @@ void CO_HBconsumer_process( /* (pre)operational state changed, clear variables */ for(i=0; inumberOfMonitoredNodes; i++) { monitoredNode->NMTstate = CO_NMT_INITIALIZING; +#if CO_CONFIG_HB_CONS_CALLBACKS & 1 + monitoredNode->NMTstatePrev = CO_NMT_INITIALIZING; +#endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index c3c439e5..6d765021 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -64,23 +64,41 @@ typedef enum { /** * One monitored node inside CO_HBconsumer_t. */ -typedef struct{ - uint8_t nodeId; /**< Node Id of the monitored node */ - CO_NMT_internalState_t NMTstate; /**< Of the remote node (Heartbeat payload) */ - CO_HBconsumer_state_t HBstate; /**< Current heartbeat state */ - uint32_t timeoutTimer; /**< Time since last heartbeat received */ - uint32_t time_us; /**< Consumer heartbeat time from OD */ - volatile void *CANrxNew; /**< Indication if new Heartbeat message received from the CAN bus */ - /** Callback for heartbeat state change to active event */ - void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void *object); /**< From CO_HBconsumer_initTimeoutCallback() or NULL */ - void *functSignalObjectHbStarted;/**< Pointer to object */ - /** Callback for consumer timeout event */ - void (*pFunctSignalTimeout)(uint8_t nodeId, uint8_t idx, void *object); /**< From CO_HBconsumer_initTimeoutCallback() or NULL */ - void *functSignalObjectTimeout;/**< Pointer to object */ - /** Callback for remote reset event */ - void (*pFunctSignalRemoteReset)(uint8_t nodeId, uint8_t idx, void *object); /**< From CO_HBconsumer_initRemoteResetCallback() or NULL */ - void *functSignalObjectRemoteReset;/**< Pointer to object */ -}CO_HBconsNode_t; +typedef struct { + /** Node Id of the monitored node */ + uint8_t nodeId; + /** Of the remote node (Heartbeat payload) */ + CO_NMT_internalState_t NMTstate; +#if (CO_CONFIG_HB_CONS_CALLBACKS & 1) || defined CO_DOXYGEN + /** Previous value of the remote node (Heartbeat payload) */ + CO_NMT_internalState_t NMTstatePrev; +#endif + /** Current heartbeat state */ + CO_HBconsumer_state_t HBstate; + /** Time since last heartbeat received */ + uint32_t timeoutTimer; + /** Consumer heartbeat time from OD */ + uint32_t time_us; + /** Indication if new Heartbeat message received from the CAN bus */ + volatile void *CANrxNew; +#if (CO_CONFIG_HB_CONS_CALLBACKS & 2) || defined CO_DOXYGEN + /** Callback for heartbeat state change to active event. + * From CO_HBconsumer_initCallbackHeartbeatStarted() or NULL. */ + void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void *object); + /** Pointer to object */ + void *functSignalObjectHbStarted; + /** Callback for consumer timeout event. + * From CO_HBconsumer_initCallbackTimeout() or NULL. */ + void (*pFunctSignalTimeout)(uint8_t nodeId, uint8_t idx, void *object); + /** Pointer to object */ + void *functSignalObjectTimeout; + /** Callback for remote reset event. + * From CO_HBconsumer_initCallbackRemoteReset() or NULL. */ + void (*pFunctSignalRemoteReset)(uint8_t nodeId, uint8_t idx, void *object); + /** Pointer to object */ + void *functSignalObjectRemoteReset; +#endif +} CO_HBconsNode_t; /** @@ -103,6 +121,15 @@ typedef struct{ bool_t NMTisPreOrOperationalPrev; /**< previous state of var */ CO_CANmodule_t *CANdevRx; /**< From CO_HBconsumer_init() */ uint16_t CANdevRxIdxStart; /**< From CO_HBconsumer_init() */ +#if (CO_CONFIG_HB_CONS_CALLBACKS & 1) || defined CO_DOXYGEN + /** Callback for remote NMT changed event. + * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ + void (*pFunctSignalNmtChanged)(uint8_t nodeId, + CO_NMT_internalState_t state, + void *object); + /** Pointer to object */ + void *pFunctSignalObjectNmtChanged; +#endif }CO_HBconsumer_t; @@ -155,6 +182,27 @@ CO_ReturnError_t CO_HBconsumer_initEntry( uint8_t nodeId, uint16_t consumerTime_ms); +#if (CO_CONFIG_HB_CONS_CALLBACKS & 1) || defined CO_DOXYGEN +/** + * Initialize Heartbeat consumer NMT changed callback function. + * + * Function initializes optional callback function, which is called when NMT + * state from the remote node changes. + * + * @param HBcons This object. + * @param object Pointer to object, which will be passed to pFunctSignal(). + * Can be NULL. + * @param pFunctSignal Pointer to the callback function. Not called if NULL. + */ +void CO_HBconsumer_initCallbackNmtChanged( + CO_HBconsumer_t *HBcons, + void *object, + void (*pFunctSignal)(uint8_t nodeId, + CO_NMT_internalState_t state, + void *object)); +#endif + +#if (CO_CONFIG_HB_CONS_CALLBACKS & 2) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer started callback function. * @@ -209,6 +257,7 @@ void CO_HBconsumer_initCallbackRemoteReset( uint8_t idx, void *object, void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); +#endif /** * Process Heartbeat consumer object. diff --git a/301/CO_driver.h b/301/CO_driver.h index d6f208b5..b051c8aa 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -118,6 +118,24 @@ extern "C" { #define CO_CONFIG_SDO_BUFFER_SIZE 32 #endif +/** + * Configuration of Heartbeat Consumer Callbacks usage. + * + * - value = 0: Don't include any Heartbeat consumer callback functions in the + * code. + * - value = 1: Use function CO_HBconsumer_initCallbackNmtChanged(). It enables + * application to configure one callback, which will notify about NMT state + * change of the monitored node. + * - value = 2: Use functions CO_HBconsumer_initCallbackHeartbeatStarted(), + * CO_HBconsumer_initCallbackTimeout() and + * CO_HBconsumer_initCallbackRemoteReset(). Those functions enable application + * to configure set of three callbacks, different for each monitored node. + * - value = 3: Use all functions, from 1 and 2. + */ +#ifndef CO_CONFIG_HB_CONS_CALLBACKS +#define CO_CONFIG_HB_CONS_CALLBACKS 0 +#endif + /** * Configuration of Standard CiA 309 usage. * diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index e3b62a08..48f06aac 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -55,6 +55,9 @@ extern "C" { #ifndef CO_CONFIG_SDO_BUFFER_SIZE #define CO_CONFIG_SDO_BUFFER_SIZE 889 #endif +#ifndef CO_CONFIG_HB_CONS_CALLBACKS +#define CO_CONFIG_HB_CONS_CALLBACKS 1 +#endif /** From 41c075a18207d44d65d1eee63f3767efafa9c124 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 13 Mar 2020 16:14:50 +0100 Subject: [PATCH 043/520] SocketCAN main.c: Add NMT changes of current and remote nodes into log. --- socketCAN/CO_error_msgs.h | 2 ++ socketCAN/CO_main_basic.c | 62 ++++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index d8c7ae6d..c5852ffe 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -79,6 +79,8 @@ extern "C" { /* mainline */ #define DBG_EMERGENCY_RX "CANopen Emergency message from node 0x%02X: errorCode=0x%04X, errorRegister=0x%02X, errorBit=0x%02X, infoCode=0x%08X" +#define DBG_NMT_CHANGE "CANopen NMT state changed to: \"%s\" (%d)" +#define DBG_HB_CONS_NMT_CHANGE "CANopen Remote node ID = 0x%02X: NMT state changed to: \"%s\" (%d)" #define DBG_NOT_TCP_PORT "(%s) -t argument \'%s\' is not a valid tcp port", __func__ #define DBG_WRONG_NODE_ID "(%s) Wrong node ID \"%d\"", __func__ #define DBG_WRONG_PRIORITY "(%s) Wrong RT priority \"%d\"", __func__ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index dc9d30c4..31fa7e9a 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -76,7 +76,7 @@ pthread_mutex_t CO_CAN_VALID_mtx = PTHREAD_MUTEX_INITIALIZER; /* Other variables and objects */ static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ -static int nodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ +static int CO_ownNodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ static CO_OD_storage_t odStor; /* Object Dictionary storage object for CO_OD_ROM */ static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ static char *odStorFile_rom = "od_storage"; /* Name of the file */ @@ -105,12 +105,38 @@ static void EmergencyRxCallback(const uint16_t ident, const uint8_t errorBit, const uint32_t infoCode) { - int16_t nodeIdRx = ident ? (ident&0x7F) : nodeId; + int16_t nodeIdRx = ident ? (ident&0x7F) : CO_ownNodeId; log_printf(LOG_NOTICE, DBG_EMERGENCY_RX, nodeIdRx, errorCode, errorRegister, errorBit, infoCode); } +/* return string description of NMT state. */ +static char *NmtState2Str(CO_NMT_internalState_t state) +{ + switch(state) { + case CO_NMT_INITIALIZING: return "initializing"; + case CO_NMT_PRE_OPERATIONAL: return "pre-operational"; + case CO_NMT_OPERATIONAL: return "operational"; + case CO_NMT_STOPPED: return "stopped"; + default: return "unknown"; + } +} + +/* callback for NMT change messages */ +static void NmtChangeCallback(CO_NMT_internalState_t state) +{ + log_printf(LOG_NOTICE, DBG_NMT_CHANGE, NmtState2Str(state), state); +} + +/* callback for monitoring Heartbeat remote NMT state change */ +static void HeartbeatNmtChangedCallback(uint8_t nodeId, + CO_NMT_internalState_t state, + void *object) +{ + log_printf(LOG_NOTICE, DBG_HB_CONS_NMT_CHANGE, + nodeId, NmtState2Str(state), state); +} /* Print usage */ static void printUsage(char *progName) { @@ -148,7 +174,9 @@ printf( } -/*Mainline thread *************************************************************/ +/******************************************************************************* + * Mainline thread + ******************************************************************************/ int main (int argc, char *argv[]) { pthread_t rt_thread_id; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; @@ -167,7 +195,7 @@ int main (int argc, char *argv[]) { #endif /* configure system log */ - setlogmask(LOG_UPTO (LOG_DEBUG)); /* LOG_DEBUG - log all meessages */ + setlogmask(LOG_UPTO (LOG_DEBUG)); /* LOG_DEBUG - log all messages */ openlog(argv[0], LOG_PID | LOG_PERROR, LOG_USER); /* print also to standard error */ /* Get program options */ @@ -178,7 +206,7 @@ int main (int argc, char *argv[]) { while((opt = getopt(argc, argv, "i:p:rc:t:s:a:")) != -1) { switch (opt) { case 'i': - nodeId = strtol(optarg, NULL, 0); + CO_ownNodeId = strtol(optarg, NULL, 0); nodeIdFromArgs = true; break; case 'p': rtPriority = strtol(optarg, NULL, 0); break; @@ -217,8 +245,8 @@ int main (int argc, char *argv[]) { CANdevice0Index = if_nametoindex(CANdevice); } - if(nodeIdFromArgs && (nodeId < 1 || nodeId > 127)) { - log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, nodeId); + if(nodeIdFromArgs && (CO_ownNodeId < 1 || CO_ownNodeId > 127)) { + log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_ownNodeId); printUsage(argv[0]); exit(EXIT_FAILURE); } @@ -236,7 +264,7 @@ int main (int argc, char *argv[]) { } - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, nodeId, nodeId, "starting"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, CO_ownNodeId, "starting"); /* Allocate memory for CANopen objects */ @@ -281,7 +309,7 @@ int main (int argc, char *argv[]) { while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { /* CANopen communication reset - initialize CANopen objects *******************/ - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, nodeId, nodeId, "communication reset"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, CO_ownNodeId, "communication reset"); #if CO_CONFIG_309 > 0 @@ -304,7 +332,7 @@ int main (int argc, char *argv[]) { /* initialize CANopen */ if(!nodeIdFromArgs) { /* use value from Object dictionary, if not set by program arguments */ - nodeId = OD_CANNodeID; + CO_ownNodeId = OD_CANNodeID; } err = CO_CANinit((void *)CANdevice0Index, 0 /* bit rate not used */); @@ -313,7 +341,7 @@ int main (int argc, char *argv[]) { exit(EXIT_FAILURE); } - err = CO_CANopenInit(nodeId); + err = CO_CANopenInit(CO_ownNodeId); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); exit(EXIT_FAILURE); @@ -321,6 +349,10 @@ int main (int argc, char *argv[]) { /* initialize callbacks */ CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); + CO_NMT_initCallback(CO->NMT, NmtChangeCallback); + CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, + HeartbeatNmtChangedCallback); + /* initialize OD objects 1010 and 1011 and verify errors. */ CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U); @@ -408,7 +440,7 @@ int main (int argc, char *argv[]) { reset = CO_RESET_NOT; - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, nodeId, nodeId, "running ..."); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, CO_ownNodeId, "running ..."); while(reset == CO_RESET_NOT && CO_endProgram == 0) { @@ -462,7 +494,7 @@ int main (int argc, char *argv[]) { threadMainWait_close(); CO_delete((void *)CANdevice0Index); - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, nodeId, nodeId, "finished"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, CO_ownNodeId, "finished"); /* Flush all buffers (and reboot) */ if(rebootEnable && reset == CO_RESET_APP) { @@ -477,7 +509,9 @@ int main (int argc, char *argv[]) { } -/* Realtime thread for CAN receive and threadTmr ******************************/ +/******************************************************************************* + * Realtime thread for CAN receive and threadTmr + ******************************************************************************/ static void* rt_thread(void* arg) { /* Endless loop */ From 0ee8acaa67339b48d345d73ce578f9f133958ccb Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 16 Mar 2020 15:30:19 +0100 Subject: [PATCH 044/520] Unify indentation in three files. --- README.md | 6 +- socketCAN/CO_Linux_threads.c | 371 +++++++++++++++++------------------ socketCAN/CO_error.c | 6 +- socketCAN/CO_error.h | 10 +- 4 files changed, 196 insertions(+), 197 deletions(-) diff --git a/README.md b/README.md index 7a2a1726..98b68c6a 100644 --- a/README.md +++ b/README.md @@ -64,9 +64,9 @@ http://sourceforge.net/p/canopennode/discussion/387151/ Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Some basic formatting -rules should be followed: Linux style with indentation of 4 spaces or -optionally 2 spaces. There is also a `codingStyle` file with example and -a configuration file for `clang-format` tool. +rules should be followed: Linux style with indentation of 4 spaces. There is +also a `codingStyle` file with example and a configuration file for +`clang-format` tool. Flowchart of a typical CANopenNode implementation diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index dcc11856..bf23293b 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -39,266 +39,265 @@ /* Helper function - get monotonic clock time in microseconds */ static uint64_t CO_LinuxThreads_clock_gettime_us(void) { - struct timespec ts; + struct timespec ts; - (void)clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; } /* Mainline thread - basic (threadMain) ***************************************/ static struct { - uint64_t start; /* time value CO_process() was called last time in us */ + uint64_t start; /* time value CO_process() was called last time in us */ } threadMain; void threadMain_init(void (*callback)(void*), void *object) { - threadMain.start = CO_LinuxThreads_clock_gettime_us(); + threadMain.start = CO_LinuxThreads_clock_gettime_us(); - CO_SDO_initCallback(CO->SDO[0], object, callback); - CO_EM_initCallback(CO->em, object, callback); + CO_SDO_initCallback(CO->SDO[0], object, callback); + CO_EM_initCallback(CO->em, object, callback); } void threadMain_close(void) { - CO_SDO_initCallback(CO->SDO[0], NULL, NULL); - CO_EM_initCallback(CO->em, NULL, NULL); + CO_SDO_initCallback(CO->SDO[0], NULL, NULL); + CO_EM_initCallback(CO->em, NULL, NULL); } void threadMain_process(CO_NMT_reset_cmd_t *reset) { - uint32_t finished; - uint32_t diff; - uint64_t now; - - now = CO_LinuxThreads_clock_gettime_us(); - diff = (uint32_t)(now - threadMain.start); - threadMain.start = now; - - /* we use timerNext_us in CO_process() as indication if processing is - * finished. We ignore any calculated values for maximum delay times. */ - do { - finished = 1; - *reset = CO_process(CO, diff, &finished); - diff = 0; - } while ((*reset == CO_RESET_NOT) && (finished == 0)); - + uint32_t finished; + uint32_t diff; + uint64_t now; + + now = CO_LinuxThreads_clock_gettime_us(); + diff = (uint32_t)(now - threadMain.start); + threadMain.start = now; + + /* we use timerNext_us in CO_process() as indication if processing is + * finished. We ignore any calculated values for maximum delay times. */ + do { + finished = 1; + *reset = CO_process(CO, diff, &finished); + diff = 0; + } while ((*reset == CO_RESET_NOT) && (finished == 0)); } /* Mainline thread - Blocking (threadMainWait) ********************************/ static struct { - uint64_t start; /* time value CO_process() was called last time in us */ - int epoll_fd; /* epoll file descriptor */ - int event_fd; /* notification event file descriptor */ - int timer_fd; /* interval timer file descriptor */ - uint32_t interval_us; /* interval for threadMainWait_process */ - struct itimerspec tm; /* structure for timer configuration */ + uint64_t start; /* time value CO_process() was called last time in us */ + int epoll_fd; /* epoll file descriptor */ + int event_fd; /* notification event file descriptor */ + int timer_fd; /* interval timer file descriptor */ + uint32_t interval_us; /* interval for threadMainWait_process */ + struct itimerspec tm; /* structure for timer configuration */ } threadMainWait; static void threadMainWait_callback(void *object) { - /* send event to wake threadMainWait_process() */ - uint64_t u = 1; - ssize_t s; - s = write(threadMainWait.event_fd, &u, sizeof(uint64_t)); - if (s != sizeof(uint64_t)) { - log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); - } + /* send event to wake threadMainWait_process() */ + uint64_t u = 1; + ssize_t s; + s = write(threadMainWait.event_fd, &u, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) { + log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); + } } void threadMainWait_init(uint32_t interval_us) { - int32_t ret; - struct epoll_event ev; - - /* Configure callback functions */ - CO_SDO_initCallback(CO->SDO[0], NULL, threadMainWait_callback); - CO_EM_initCallback(CO->em, NULL, threadMainWait_callback); - - /* Initial value for time calculation */ - threadMainWait.start = CO_LinuxThreads_clock_gettime_us(); - - /* Configure epoll for mainline */ - threadMainWait.epoll_fd = epoll_create(1); - if (threadMainWait.epoll_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_create()"); - exit(EXIT_FAILURE); - } - - /* Configure eventfd for notifications and add it to epoll */ - threadMainWait.event_fd = eventfd(0, 0); - if (threadMainWait.event_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "eventfd()"); - exit(EXIT_FAILURE); - } - ev.events = EPOLLIN; - ev.data.fd = threadMainWait.event_fd; - ret = epoll_ctl(threadMainWait.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0){ - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(event_fd)"); - exit(EXIT_FAILURE); - } - - /* Configure timer for interval_us and add it to epoll */ - threadMainWait.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); - if (threadMainWait.timer_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_create()"); - exit(EXIT_FAILURE); - } - threadMainWait.interval_us = interval_us; - threadMainWait.tm.it_interval.tv_sec = interval_us / 1000000; - threadMainWait.tm.it_interval.tv_nsec = (interval_us % 1000000) * 1000; - threadMainWait.tm.it_value.tv_sec = 0; - threadMainWait.tm.it_value.tv_nsec = 1; - ret = timerfd_settime(threadMainWait.timer_fd, 0, &threadMainWait.tm, NULL); - if (ret < 0){ - log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_settime"); - exit(EXIT_FAILURE); - } - ev.events = EPOLLIN; - ev.data.fd = threadMainWait.timer_fd; - ret = epoll_ctl(threadMainWait.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0){ - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(timer_fd)"); - exit(EXIT_FAILURE); - } + int32_t ret; + struct epoll_event ev; + + /* Configure callback functions */ + CO_SDO_initCallback(CO->SDO[0], NULL, threadMainWait_callback); + CO_EM_initCallback(CO->em, NULL, threadMainWait_callback); + + /* Initial value for time calculation */ + threadMainWait.start = CO_LinuxThreads_clock_gettime_us(); + + /* Configure epoll for mainline */ + threadMainWait.epoll_fd = epoll_create(1); + if (threadMainWait.epoll_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_create()"); + exit(EXIT_FAILURE); + } + + /* Configure eventfd for notifications and add it to epoll */ + threadMainWait.event_fd = eventfd(0, 0); + if (threadMainWait.event_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "eventfd()"); + exit(EXIT_FAILURE); + } + ev.events = EPOLLIN; + ev.data.fd = threadMainWait.event_fd; + ret = epoll_ctl(threadMainWait.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0){ + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(event_fd)"); + exit(EXIT_FAILURE); + } + + /* Configure timer for interval_us and add it to epoll */ + threadMainWait.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (threadMainWait.timer_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_create()"); + exit(EXIT_FAILURE); + } + threadMainWait.interval_us = interval_us; + threadMainWait.tm.it_interval.tv_sec = interval_us / 1000000; + threadMainWait.tm.it_interval.tv_nsec = (interval_us % 1000000) * 1000; + threadMainWait.tm.it_value.tv_sec = 0; + threadMainWait.tm.it_value.tv_nsec = 1; + ret = timerfd_settime(threadMainWait.timer_fd, 0, &threadMainWait.tm, NULL); + if (ret < 0){ + log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_settime"); + exit(EXIT_FAILURE); + } + ev.events = EPOLLIN; + ev.data.fd = threadMainWait.timer_fd; + ret = epoll_ctl(threadMainWait.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0){ + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(timer_fd)"); + exit(EXIT_FAILURE); + } } void threadMainWait_close(void) { - CO_SDO_initCallback(CO->SDO[0], NULL, NULL); - CO_EM_initCallback(CO->em, NULL, NULL); - - close(threadMainWait.epoll_fd); - close(threadMainWait.event_fd); - close(threadMainWait.timer_fd); - threadMainWait.epoll_fd = -1; - threadMainWait.event_fd = -1; - threadMainWait.timer_fd = -1; + CO_SDO_initCallback(CO->SDO[0], NULL, NULL); + CO_EM_initCallback(CO->em, NULL, NULL); + + close(threadMainWait.epoll_fd); + close(threadMainWait.event_fd); + close(threadMainWait.timer_fd); + threadMainWait.epoll_fd = -1; + threadMainWait.event_fd = -1; + threadMainWait.timer_fd = -1; } uint32_t threadMainWait_process(CO_NMT_reset_cmd_t *reset) { - int ready, ret; - struct epoll_event ev; - uint64_t ull; - ssize_t s; - uint32_t diff, timerNext_us; - - /* wait for event or timer expiration and read data from file descriptors */ - ready = epoll_wait(threadMainWait.epoll_fd, &ev, 1, -1); - if (ready != 1 && errno != EINTR) { - log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_wait"); - } - else if (ev.data.fd == threadMainWait.event_fd) { - s = read(threadMainWait.event_fd, &ull, sizeof(uint64_t)); - if (s != sizeof(uint64_t)) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(event_fd)"); + int ready, ret; + struct epoll_event ev; + uint64_t ull; + ssize_t s; + uint32_t diff, timerNext_us; + + /* wait for event or timer expiration and read data from file descriptors */ + ready = epoll_wait(threadMainWait.epoll_fd, &ev, 1, -1); + if (ready != 1 && errno != EINTR) { + log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_wait"); } - } - else if (ev.data.fd == threadMainWait.timer_fd) { - s = read(threadMainWait.timer_fd, &ull, sizeof(uint64_t)); - if (s != sizeof(uint64_t) && errno != EAGAIN) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(timer_fd)"); + else if (ev.data.fd == threadMainWait.event_fd) { + s = read(threadMainWait.event_fd, &ull, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) { + log_printf(LOG_DEBUG, DBG_ERRNO, "read(event_fd)"); + } } - } - - /* calculate time difference since last call */ - ull = CO_LinuxThreads_clock_gettime_us(); - diff = (uint32_t)(ull - threadMainWait.start); - threadMainWait.start = ull; - - /* stack will lower this, if necessary */ - timerNext_us = threadMainWait.interval_us; - - /* process CANopen objects */ - *reset = CO_process(CO, diff, &timerNext_us); - - /* lower next timer interval if necessary */ - if (timerNext_us < threadMainWait.interval_us) { - /* add one microsecond extra delay and make sure it is not zero */ - timerNext_us += 1; - if (threadMainWait.interval_us < 1000000) { - threadMainWait.tm.it_value.tv_nsec = timerNext_us * 1000; - } else { - threadMainWait.tm.it_value.tv_sec = timerNext_us / 1000000; - threadMainWait.tm.it_value.tv_nsec = (timerNext_us % 1000000) * 1000; + else if (ev.data.fd == threadMainWait.timer_fd) { + s = read(threadMainWait.timer_fd, &ull, sizeof(uint64_t)); + if (s != sizeof(uint64_t) && errno != EAGAIN) { + log_printf(LOG_DEBUG, DBG_ERRNO, "read(timer_fd)"); + } } - ret = timerfd_settime(threadMainWait.timer_fd, 0, - &threadMainWait.tm, NULL); - if (ret < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "timerfd_settime"); + + /* calculate time difference since last call */ + ull = CO_LinuxThreads_clock_gettime_us(); + diff = (uint32_t)(ull - threadMainWait.start); + threadMainWait.start = ull; + + /* stack will lower this, if necessary */ + timerNext_us = threadMainWait.interval_us; + + /* process CANopen objects */ + *reset = CO_process(CO, diff, &timerNext_us); + + /* lower next timer interval if necessary */ + if (timerNext_us < threadMainWait.interval_us) { + /* add one microsecond extra delay and make sure it is not zero */ + timerNext_us += 1; + if (threadMainWait.interval_us < 1000000) { + threadMainWait.tm.it_value.tv_nsec = timerNext_us * 1000; + } else { + threadMainWait.tm.it_value.tv_sec = timerNext_us / 1000000; + threadMainWait.tm.it_value.tv_nsec = (timerNext_us % 1000000) * 1000; + } + ret = timerfd_settime(threadMainWait.timer_fd, 0, + &threadMainWait.tm, NULL); + if (ret < 0){ + log_printf(LOG_DEBUG, DBG_ERRNO, "timerfd_settime"); + } } - } - return diff; + return diff; } /* Realtime thread (threadRT) *************************************************/ static struct { - uint32_t us_interval; /* configured interval in us */ - int interval_fd; /* timer fd */ + uint32_t us_interval; /* configured interval in us */ + int interval_fd; /* timer fd */ } threadRT; void CANrx_threadTmr_init(uint32_t interval_us) { - struct itimerspec itval; - - threadRT.us_interval = interval_us; - /* set up non-blocking interval timer */ - threadRT.interval_fd = timerfd_create(CLOCK_MONOTONIC, 0); - (void)fcntl(threadRT.interval_fd, F_SETFL, O_NONBLOCK); - itval.it_interval.tv_sec = 0; - itval.it_interval.tv_nsec = interval_us * 1000; - itval.it_value = itval.it_interval; - (void)timerfd_settime(threadRT.interval_fd, 0, &itval, NULL); + struct itimerspec itval; + + threadRT.us_interval = interval_us; + /* set up non-blocking interval timer */ + threadRT.interval_fd = timerfd_create(CLOCK_MONOTONIC, 0); + (void)fcntl(threadRT.interval_fd, F_SETFL, O_NONBLOCK); + itval.it_interval.tv_sec = 0; + itval.it_interval.tv_nsec = interval_us * 1000; + itval.it_value = itval.it_interval; + (void)timerfd_settime(threadRT.interval_fd, 0, &itval, NULL); } void CANrx_threadTmr_close(void) { - (void)close(threadRT.interval_fd); - threadRT.interval_fd = -1; + (void)close(threadRT.interval_fd); + threadRT.interval_fd = -1; } uint32_t CANrx_threadTmr_process(void) { - int32_t result; - uint64_t i; - bool_t syncWas; - uint64_t missed = 0; + int32_t result; + uint64_t i; + bool_t syncWas; + uint64_t missed = 0; - result = CO_CANrxWait(CO->CANmodule[0], threadRT.interval_fd, NULL); - if (result < 0) { - result = read(threadRT.interval_fd, &missed, sizeof(missed)); - if (result > 0) { - /* at least one timer interval occured */ - CO_LOCK_OD(); + result = CO_CANrxWait(CO->CANmodule[0], threadRT.interval_fd, NULL); + if (result < 0) { + result = read(threadRT.interval_fd, &missed, sizeof(missed)); + if (result > 0) { + /* at least one timer interval occured */ + CO_LOCK_OD(); - if(CO->CANmodule[0]->CANnormal) { + if(CO->CANmodule[0]->CANnormal) { - for (i = 0; i <= missed; i++) { + for (i = 0; i <= missed; i++) { #if CO_NO_SYNC == 1 - /* Process Sync */ - syncWas = CO_process_SYNC(CO, threadRT.us_interval, NULL); + /* Process Sync */ + syncWas = CO_process_SYNC(CO, threadRT.us_interval, NULL); #else - syncWas = false; + syncWas = false; #endif - /* Read inputs */ - CO_process_RPDO(CO, syncWas); + /* Read inputs */ + CO_process_RPDO(CO, syncWas); - /* Write outputs */ - CO_process_TPDO(CO, syncWas, threadRT.us_interval, NULL); + /* Write outputs */ + CO_process_TPDO(CO, syncWas, threadRT.us_interval, NULL); + } } - } - CO_UNLOCK_OD(); + CO_UNLOCK_OD(); + } } - } - return (uint32_t) missed; + return (uint32_t) missed; } diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index 165c8e08..640aa17b 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -272,17 +272,17 @@ CO_CANinterfaceState_t CO_CANerror_rxMsgError( result = CO_CANerrorBusoff(CANerrorhandler, msg); if (result != CO_INTERFACE_ACTIVE) { - return result; + return result; } result = CO_CANerrorCrtl(CANerrorhandler, msg); if (result != CO_INTERFACE_ACTIVE) { - return result; + return result; } result = CO_CANerrorNoack(CANerrorhandler, msg); if (result != CO_INTERFACE_ACTIVE) { - return result; + return result; } return CO_INTERFACE_ACTIVE; diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 7f9fb433..1f5fab6e 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -110,11 +110,11 @@ typedef enum { * socketCAN interface error handling */ typedef struct { - int fd; /**< interface FD */ - char ifName[IFNAMSIZ]; /**< interface name as string */ - uint32_t noackCounter; /**< counts no ACK on CAN transmission */ - volatile unsigned char listenOnly; /**< set to listen only mode */ - struct timespec timestamp; /**< listen only mode started at this time */ + int fd; /**< interface FD */ + char ifName[IFNAMSIZ]; /**< interface name as string */ + uint32_t noackCounter; /**< counts no ACK on CAN transmission */ + volatile unsigned char listenOnly; /**< set to listen only mode */ + struct timespec timestamp; /**< listen only mode started at this time */ } CO_CANinterfaceErrorhandler_t; From 9f8e726e7e2db9893b71b19d567f6195d6c8dcd8 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 17 Mar 2020 17:39:22 +0100 Subject: [PATCH 045/520] SocketCAN, CO_driver.c: replace CO_notifyPype with simpler eventfd(). --- Makefile | 1 - README.md | 8 ++-- socketCAN/CO_Linux_threads.c | 2 +- socketCAN/CO_driver.c | 28 +++++++----- socketCAN/CO_driver_target.h | 11 +++-- socketCAN/CO_main_basic.c | 1 - socketCAN/CO_notify_pipe.c | 62 -------------------------- socketCAN/CO_notify_pipe.h | 86 ------------------------------------ 8 files changed, 27 insertions(+), 172 deletions(-) delete mode 100644 socketCAN/CO_notify_pipe.c delete mode 100644 socketCAN/CO_notify_pipe.h diff --git a/Makefile b/Makefile index 600aab17..30d85989 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,6 @@ INCLUDE_DIRS = \ SOURCES = \ $(DRV_SRC)/CO_driver.c \ $(DRV_SRC)/CO_error.c \ - $(DRV_SRC)/CO_notify_pipe.c \ $(DRV_SRC)/CO_Linux_threads.c \ $(DRV_SRC)/CO_OD_storage.c \ $(CANOPEN_SRC)/301/CO_SDOserver.c \ diff --git a/README.md b/README.md index 98b68c6a..f69461d4 100644 --- a/README.md +++ b/README.md @@ -161,21 +161,21 @@ File structure - **CO_driver_target.h** - Linux socketCAN specific definitions for CANopenNode. - **CO_driver.c** - Interface between Linux socketCAN and CANopenNode. - **CO_error.h/.c** - Linux socketCAN Error handling object. + - **CO_error_msgs.h** - Error definition strings and logging function. - **CO_Linux_threads.h/.c** - Helper functions for implementing CANopen threads in Linux. - - **CO_notify_pipe.h/.c** - Notify pipe for Linux threads. - **CO_OD_storage.h/.c** - Object Dictionary storage object for Linux SocketCAN. - - **main.c** - Mainline for socketCAN - - **Makefile** - Makefile for socketCAN. + - **CO_main_basic.c** - Mainline for socketCAN (basic usage). - **doc/** - Directory with documentation - **CHANGELOG.md** - Change Log file. - **deviceSupport.md** - Information about supported devices. - **gettingStarted.md, LSSusage.md, traceUsage.md** - Getting started and usage. - - **index.html** - Soft link to html/index.html. + - **index.html** - Soft link to html/md_README.html. - **html** - Directory with documentation - must be generated by Doxygen. - **CANopen.h/.c** - Initialization and processing of CANopen objects. - **codingStyle** - Example of the coding style. - **.clang-format** - Definition file for the coding style. - **Doxyfile** - Configuration file for the documentation generator *doxygen*. + - **Makefile** - Makefile for Linux socketCAN. - **LICENSE** - License. - **README.md** - This file. diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index bf23293b..8077690b 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -128,7 +128,7 @@ void threadMainWait_init(uint32_t interval_us) } /* Configure eventfd for notifications and add it to epoll */ - threadMainWait.event_fd = eventfd(0, 0); + threadMainWait.event_fd = eventfd(0, EFD_NONBLOCK); if (threadMainWait.event_fd < 0) { log_printf(LOG_CRIT, DBG_ERRNO, "eventfd()"); exit(EXIT_FAILURE); diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index ff63fd38..818a595e 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -221,19 +222,19 @@ CO_ReturnError_t CO_CANmodule_init( return CO_ERROR_SYSCALL; } - /* Create notification pipe */ - CANmodule->pipe = CO_NotifyPipeCreate(); - if (CANmodule->pipe==NULL) { - log_printf(LOG_DEBUG, DBG_ERRNO, "pipe"); + /* Create notification event */ + CANmodule->fdEvent = eventfd(0, EFD_NONBLOCK); + if (CANmodule->fdEvent < 0) { + log_printf(LOG_DEBUG, DBG_ERRNO, "eventfd"); CO_CANmodule_disable(CANmodule); return CO_ERROR_OUT_OF_MEMORY; } /* ...and add it to epoll */ ev.events = EPOLLIN; - ev.data.fd = CO_NotifyPipeGetFd(CANmodule->pipe); + ev.data.fd = CANmodule->fdEvent; ret = epoll_ctl(CANmodule->fdEpoll, EPOLL_CTL_ADD, ev.data.fd, &ev); if(ret < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_ctl(pipe)"); + log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_ctl(eventfd)"); CO_CANmodule_disable(CANmodule); return CO_ERROR_SYSCALL; } @@ -440,13 +441,18 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) CANmodule->CANinterfaceCount = 0; /* cancel rx */ - if (CANmodule->pipe != NULL) { - CO_NotifyPipeSend(CANmodule->pipe); + if (CANmodule->fdEvent != -1) { + uint64_t u = 1; + ssize_t s; + s = write(CANmodule->fdEvent, &u, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) { + log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); + } /* give some time for delivery */ wait.tv_sec = 0; wait.tv_nsec = 50 /* ms */ * 1000000; nanosleep(&wait, NULL); - CO_NotifyPipeFree(CANmodule->pipe); + close(CANmodule->fdEvent); } if (CANmodule->fdEpoll >= 0) { @@ -919,9 +925,9 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff } else if ((ev[0].events & EPOLLIN) != 0) { /* one of the sockets is ready */ - if ((ev[0].data.fd == CO_NotifyPipeGetFd(CANmodule->pipe)) || + if ((ev[0].data.fd == CANmodule->fdEvent) || (ev[0].data.fd == fdTimer)) { - /* timer or notify pipe */ + /* timer or notification event */ return -1; } else { diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 48f06aac..b5c3b9e9 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -44,7 +44,6 @@ #if __has_include("CO_driver_custom.h") #include "CO_driver_custom.h" #endif -#include "CO_notify_pipe.h" #include "CO_error.h" #ifdef __cplusplus @@ -221,8 +220,8 @@ typedef struct { uint16_t txSize; volatile bool_t CANnormal; void *em; - CO_NotifyPipe_t *pipe; /* Notification Pipe */ - int fdEpoll; /* epoll FD for pipe, CANrx sockets in all + int fdEvent; /* notification event file descriptor */ + int fdEpoll; /* epoll FD for event, CANrx sockets in all interfaces and fdTimerRead */ int fdTimerRead; /* timer handle from CANrxWait() */ #if CO_DRIVER_MULTI_INTERFACE > 0 || defined CO_DOXYGEN @@ -324,8 +323,8 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface(CO_CANmodule_t *CANmodule, * Functions receives CAN messages (blocking) * * This function waits for received CAN message, CAN error frame, notification - * pipe or fdTimer expiration. In case of CAN message it searches _rxArray_ from - * CO_CANmodule_t and if matched it calls the corresponding CANrx_callback, + * event or fdTimer expiration. In case of CAN message it searches _rxArray_ + from* CO_CANmodule_t and if matched it calls the corresponding CANrx_callback, * optionally copies received CAN message to _buffer_ and returns index of * matched _rxArray_. * @@ -342,7 +341,7 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface(CO_CANmodule_t *CANmodule, * @param [out] buffer Storage for received message or _NULL_ if not used. * @retval >= 0 index of received message in array from CO_CANmodule_t * _rxArray_, copy of CAN message is available in _buffer_. - * @retval -1 no message received (timer expired or notification pipe or error) + * @retval -1 no message received (timer expired or notification event or error) */ int32_t CO_CANrxWait(CO_CANmodule_t* CANmodule, int fdTimer, CO_CANrxMsg_t* buffer); diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 31fa7e9a..f0cab2da 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -38,7 +38,6 @@ #include "CANopen.h" #include "CO_OD_storage.h" -#include "CO_notify_pipe.h" #include "CO_error.h" #include "CO_Linux_threads.h" diff --git a/socketCAN/CO_notify_pipe.c b/socketCAN/CO_notify_pipe.c deleted file mode 100644 index 7f053d58..00000000 --- a/socketCAN/CO_notify_pipe.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Snipped from https://stackoverflow.com/a/2486353 */ - -#include -#include -#include -#include - -#include "CO_notify_pipe.h" -#include "CO_error.h" - - -CO_NotifyPipe_t *CO_NotifyPipeCreate(void) -{ - int pipefd[2]; - CO_NotifyPipe_t *p; - int ret = pipe(pipefd); - - if (ret < 0) { - return NULL; - } - p = calloc(1, sizeof(CO_NotifyPipe_t)); - if (p == NULL) { - return NULL; - } - p->m_receiveFd = pipefd[0]; - p->m_sendFd = pipefd[1]; - fcntl(p->m_sendFd,F_SETFL,O_NONBLOCK); - return p; -} - - -void CO_NotifyPipeFree(CO_NotifyPipe_t *p) -{ - if (p == NULL) { - return; - } - close(p->m_sendFd); - close(p->m_receiveFd); - free(p); -} - - -int CO_NotifyPipeGetFd(CO_NotifyPipe_t *p) -{ - if (p == NULL) { - return -1; - } - return p->m_receiveFd; -} - - -void CO_NotifyPipeSend(CO_NotifyPipe_t *p) -{ - ssize_t ret; - if (p == NULL) { - return; - } - ret = write(p->m_sendFd,"1",1); - if(ret < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); - } -} diff --git a/socketCAN/CO_notify_pipe.h b/socketCAN/CO_notify_pipe.h deleted file mode 100644 index d1002d37..00000000 --- a/socketCAN/CO_notify_pipe.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Notify pipe for Linux threads. - * - * @file CO_notify_pipe.h - * @ingroup CO_socketCAN_notify_pipe - * @author Martin Wagner - * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CO_NOTIFY_PIPE_H_ -#define CO_NOTIFY_PIPE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_socketCAN_notify_pipe Notify pipe - * @ingroup CO_socketCAN - * @{ - * - * This is needed to wake up the can socket when blocking in select - */ - -/** - * Notify pipe object - */ -typedef struct { - int m_receiveFd; /**< File descriptor for receive */ - int m_sendFd; /**< File descriptor for send */ -} CO_NotifyPipe_t; - - -/** - * Create Pipe - * - * @return pointer to CO_NotifyPipe_t object if successfully created or - * NULL on failure. - */ -CO_NotifyPipe_t *CO_NotifyPipeCreate(void); - -/** - * Delete Pipe - * - * @param p pointer to object - */ -void CO_NotifyPipeFree(CO_NotifyPipe_t *p); - -/** - * Get file descriptor for select - * - * @param p pointer to object - */ -int CO_NotifyPipeGetFd(CO_NotifyPipe_t *p); - -/** - * Send event - * - * @param p pointer to object - */ -void CO_NotifyPipeSend(CO_NotifyPipe_t *p); - -/** @} */ - -#ifdef __cplusplus -} -#endif /*__cplusplus*/ - -#endif /* CO_NOTIFY_PIPE_H_ */ From 0b2476ec95875cb9b3a194f2380ffb5a7fffcbec Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 18 Mar 2020 10:12:53 +0100 Subject: [PATCH 046/520] Fix timeout and "timerNext_us" in SDO server and client. --- 301/CO_SDOclient.c | 6 ++++-- 301/CO_SDOserver.c | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index dbbc7874..a62f92b1 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -621,6 +621,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( } } SDO_C->timeoutTimer = 0; + timeDifference_us = 0; CO_FLAG_CLEAR(SDO_C->CANrxNew); } @@ -636,7 +637,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( return CO_SDOcli_endedWithTimeout; } else if (timerNext_us != NULL) { - /* check again after inhibit time elapsed */ + /* check again after timeout time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; if (*timerNext_us > diff) { *timerNext_us = diff; @@ -1132,6 +1133,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( } } SDO_C->timeoutTimer = 0; + timeDifference_us = 0; CO_FLAG_CLEAR(SDO_C->CANrxNew); } @@ -1149,7 +1151,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( return CO_SDOcli_endedWithTimeout; } else if (timerNext_us != NULL) { - /* check again after inhibit time elapsed */ + /* check again after timeout time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; if (*timerNext_us > diff) { *timerNext_us = diff; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 1b9062e4..6e6af7b8 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -803,8 +803,10 @@ int8_t CO_SDO_process( uint8_t CCS = SDO->CANrxData[0] >> 5; /* Client command specifier */ /* reset timeout */ - if(SDO->state != CO_SDO_ST_UPLOAD_BL_SUBBLOCK) + if(SDO->state != CO_SDO_ST_UPLOAD_BL_SUBBLOCK) { SDO->timeoutTimer = 0; + timeDifference_us = 0; + } /* clear response buffer */ SDO->CANtxBuff->data[0] = SDO->CANtxBuff->data[1] = SDO->CANtxBuff->data[2] = SDO->CANtxBuff->data[3] = 0; @@ -890,6 +892,13 @@ int8_t CO_SDO_process( return -1; } } + else if (timerNext_us != NULL) { + /* check again after timeout time elapsed */ + uint32_t diff = SDO->SDOtimeoutTime_us - SDO->timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } /* return immediately if still idle */ if(state == CO_SDO_ST_IDLE){ @@ -932,9 +941,11 @@ int8_t CO_SDO_process( return -1; } - /* finish the communication */ + /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; sendResponse = true; + if (timerNext_us != NULL) + *timerNext_us = 0; } /* Segmented transfer */ @@ -1009,8 +1020,10 @@ int8_t CO_SDO_process( return -1; } - /* finish */ + /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; + if (timerNext_us != NULL) + *timerNext_us = 0; } /* download segment response and alternate toggle bit */ @@ -1152,10 +1165,12 @@ int8_t CO_SDO_process( return -1; } - /* send response */ + /* finish the communication and run mainline processing again */ SDO->CANtxBuff->data[0] = 0xA1; SDO->state = CO_SDO_ST_IDLE; sendResponse = true; + if (timerNext_us != NULL) + *timerNext_us = 0; break; } @@ -1171,9 +1186,12 @@ int8_t CO_SDO_process( SDO->CANtxBuff->data[4U+i] = SDO->ODF_arg.data[i]; SDO->CANtxBuff->data[0] = 0x43U | ((4U-SDO->ODF_arg.dataLength) << 2U); - SDO->state = CO_SDO_ST_IDLE; + /* finish the communication and run mainline processing again */ + SDO->state = CO_SDO_ST_IDLE; sendResponse = true; + if (timerNext_us != NULL) + *timerNext_us = 0; } /* Segmented transfer */ @@ -1255,7 +1273,11 @@ int8_t CO_SDO_process( /* verify end of transfer */ if((SDO->bufferOffset == SDO->ODF_arg.dataLength) && (SDO->ODF_arg.lastSegment)){ SDO->CANtxBuff->data[0] |= 0x01; + + /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; + if (timerNext_us != NULL) + *timerNext_us = 0; } /* send response */ @@ -1460,13 +1482,16 @@ int8_t CO_SDO_process( return -1; } + /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; + if (timerNext_us != NULL) + *timerNext_us = 0; break; } case CO_SDO_ST_IDLE: { - /* Nothing to do it seems */ + /* Nothing to do, this never happens. */ break; } From 794c0f903af9d7a925708f6ef39b4d0a5288129a Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 18 Mar 2020 21:06:15 +0100 Subject: [PATCH 047/520] Added file CO_config.h for stack configuration. Added CO_HBconsumer_initCallback() --- 301/CO_HBconsumer.c | 56 +++++++++++--- 301/CO_HBconsumer.h | 42 +++++++--- 301/CO_NMT_Heartbeat.c | 4 +- 301/CO_NMT_Heartbeat.h | 2 +- 301/CO_config.h | 146 +++++++++++++++++++++++++++++++++++ 301/CO_driver.h | 89 +++++---------------- README.md | 1 + doc/CHANGELOG.md | 4 +- example/CO_driver_target.h | 4 +- socketCAN/CO_Linux_threads.c | 1 + socketCAN/CO_driver_target.h | 9 ++- 11 files changed, 260 insertions(+), 98 deletions(-) create mode 100644 301/CO_config.h diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 7ebdb24e..2a34c344 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -49,6 +49,13 @@ static void CO_HBcons_receive(void *object, void *msg){ HBconsNode->NMTstate = (CO_NMT_internalState_t)data[0]; CO_FLAG_SET(HBconsNode->CANrxNew); } + +#if CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK + /* Optional signal to RTOS, which can resume task, which handles HBcons. */ + if(HBconsNode->pFunctSignalCanRx != NULL) { + HBconsNode->pFunctSignalCanRx(HBconsNode->functSignalObjectCanRx); + } +#endif } @@ -116,11 +123,22 @@ CO_ReturnError_t CO_HBconsumer_init( HBcons->NMTisPreOrOperationalPrev = false; HBcons->CANdevRx = CANdevRx; HBcons->CANdevRxIdxStart = CANdevRxIdxStart; +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK + HBcons->pFunctSignalNmtChanged = NULL; +#endif for(i=0; inumberOfMonitoredNodes; i++) { uint8_t nodeId = (HBcons->HBconsTime[i] >> 16U) & 0xFFU; uint16_t time = HBcons->HBconsTime[i] & 0xFFFFU; ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); +#if CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK + HBcons->monitoredNodes[i].pFunctSignalCanRx = NULL; +#endif +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK + HBcons->monitoredNodes[i].pFunctSignalHbStarted = NULL; + HBcons->monitoredNodes[i].pFunctSignalTimeout = NULL; + HBcons->monitoredNodes[i].pFunctSignalRemoteReset = NULL; +#endif } /* Configure Object dictionary entry at index 0x1016 */ @@ -165,7 +183,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( monitoredNode->nodeId = nodeId; monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; monitoredNode->NMTstate = CO_NMT_INITIALIZING; -#if CO_CONFIG_HB_CONS_CALLBACKS & 1 +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK monitoredNode->NMTstatePrev = CO_NMT_INITIALIZING; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -196,7 +214,25 @@ CO_ReturnError_t CO_HBconsumer_initEntry( } -#if CO_CONFIG_HB_CONS_CALLBACKS & 1 +#if CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK +/******************************************************************************/ +void CO_HBconsumer_initCallback( + CO_HBconsumer_t *HBcons, + void *object, + void (*pFunctSignal)(void *object)) +{ + if (HBcons != NULL) { + uint8_t i; + for(i=0; inumberOfMonitoredNodes; i++) { + HBcons->monitoredNodes[i].pFunctSignalCanRx = pFunctSignal; + HBcons->monitoredNodes[i].functSignalObjectCanRx = object; + } + } +} +#endif + + +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK /******************************************************************************/ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, @@ -212,10 +248,10 @@ void CO_HBconsumer_initCallbackNmtChanged( HBcons->pFunctSignalNmtChanged = pFunctSignal; HBcons->pFunctSignalObjectNmtChanged = object; } -#endif /* CO_CONFIG_HB_CONS_CALLBACKS & 1 */ +#endif -#if CO_CONFIG_HB_CONS_CALLBACKS & 2 +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK /******************************************************************************/ void CO_HBconsumer_initCallbackHeartbeatStarted( CO_HBconsumer_t *HBcons, @@ -271,7 +307,7 @@ void CO_HBconsumer_initCallbackRemoteReset( monitoredNode->pFunctSignalRemoteReset = pFunctSignal; monitoredNode->functSignalObjectRemoteReset = object; } -#endif /* CO_CONFIG_HB_CONS_CALLBACKS & 2 */ +#endif /* CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK */ /******************************************************************************/ @@ -298,7 +334,7 @@ void CO_HBconsumer_process( if (CO_FLAG_READ(monitoredNode->CANrxNew)) { if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) { /* bootup message*/ -#if CO_CONFIG_HB_CONS_CALLBACKS & 2 +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK if (monitoredNode->pFunctSignalRemoteReset != NULL) { monitoredNode->pFunctSignalRemoteReset( monitoredNode->nodeId, i, @@ -315,7 +351,7 @@ void CO_HBconsumer_process( } else { /* heartbeat message */ -#if CO_CONFIG_HB_CONS_CALLBACKS & 2 +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE && monitoredNode->pFunctSignalHbStarted != NULL) { monitoredNode->pFunctSignalHbStarted( @@ -337,7 +373,7 @@ void CO_HBconsumer_process( if (monitoredNode->timeoutTimer >= monitoredNode->time_us) { /* timeout expired */ -#if CO_CONFIG_HB_CONS_CALLBACKS & 2 +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK if (monitoredNode->pFunctSignalTimeout!=NULL) { monitoredNode->pFunctSignalTimeout( monitoredNode->nodeId, i, @@ -366,7 +402,7 @@ void CO_HBconsumer_process( if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { allMonitoredOperationalCurrent = CO_NMT_INITIALIZING; } -#if CO_CONFIG_HB_CONS_CALLBACKS & 1 +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK /* Verify, if NMT state of monitored node changed */ if(monitoredNode->NMTstate != monitoredNode->NMTstatePrev) { if (HBcons->pFunctSignalNmtChanged != NULL) { @@ -384,7 +420,7 @@ void CO_HBconsumer_process( /* (pre)operational state changed, clear variables */ for(i=0; inumberOfMonitoredNodes; i++) { monitoredNode->NMTstate = CO_NMT_INITIALIZING; -#if CO_CONFIG_HB_CONS_CALLBACKS & 1 +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK monitoredNode->NMTstatePrev = CO_NMT_INITIALIZING; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 6d765021..de1e33a7 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -69,10 +69,6 @@ typedef struct { uint8_t nodeId; /** Of the remote node (Heartbeat payload) */ CO_NMT_internalState_t NMTstate; -#if (CO_CONFIG_HB_CONS_CALLBACKS & 1) || defined CO_DOXYGEN - /** Previous value of the remote node (Heartbeat payload) */ - CO_NMT_internalState_t NMTstatePrev; -#endif /** Current heartbeat state */ CO_HBconsumer_state_t HBstate; /** Time since last heartbeat received */ @@ -81,7 +77,17 @@ typedef struct { uint32_t time_us; /** Indication if new Heartbeat message received from the CAN bus */ volatile void *CANrxNew; -#if (CO_CONFIG_HB_CONS_CALLBACKS & 2) || defined CO_DOXYGEN +#if (CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK) || defined CO_DOXYGEN + /** From CO_HBconsumer_initCallback() or NULL */ + void (*pFunctSignalCanRx)(void *object); + /** From CO_HBconsumer_initCallback() or NULL */ + void *functSignalObjectCanRx; +#endif +#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK) || defined CO_DOXYGEN + /** Previous value of the remote node (Heartbeat payload) */ + CO_NMT_internalState_t NMTstatePrev; +#endif +#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK) || defined CO_DOXYGEN /** Callback for heartbeat state change to active event. * From CO_HBconsumer_initCallbackHeartbeatStarted() or NULL. */ void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void *object); @@ -121,7 +127,7 @@ typedef struct{ bool_t NMTisPreOrOperationalPrev; /**< previous state of var */ CO_CANmodule_t *CANdevRx; /**< From CO_HBconsumer_init() */ uint16_t CANdevRxIdxStart; /**< From CO_HBconsumer_init() */ -#if (CO_CONFIG_HB_CONS_CALLBACKS & 1) || defined CO_DOXYGEN +#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK) || defined CO_DOXYGEN /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ void (*pFunctSignalNmtChanged)(uint8_t nodeId, @@ -182,7 +188,25 @@ CO_ReturnError_t CO_HBconsumer_initEntry( uint8_t nodeId, uint16_t consumerTime_ms); -#if (CO_CONFIG_HB_CONS_CALLBACKS & 1) || defined CO_DOXYGEN +#if (CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK) || defined CO_DOXYGEN +/** + * Initialize Heartbeat consumer callback function. + * + * Function initializes optional callback function, which should immediately + * start processing of CO_HBconsumer_process() function. + * Callback is called after HBconsumer message is received from the CAN bus. + * + * @param HBcons This object. + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL + * @param pFunctSignal Pointer to the callback function. Not called if NULL. + */ +void CO_HBconsumer_initCallback( + CO_HBconsumer_t *HBcons, + void *object, + void (*pFunctSignal)(void *object)); +#endif + +#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer NMT changed callback function. * @@ -202,7 +226,7 @@ void CO_HBconsumer_initCallbackNmtChanged( void *object)); #endif -#if (CO_CONFIG_HB_CONS_CALLBACKS & 2) || defined CO_DOXYGEN +#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer started callback function. * @@ -257,7 +281,7 @@ void CO_HBconsumer_initCallbackRemoteReset( uint8_t idx, void *object, void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); -#endif +#endif /* CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK */ /** * Process Heartbeat consumer object. diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 3bbc1729..9c9ffa52 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -104,7 +104,7 @@ CO_ReturnError_t CO_NMT_init( CO_ReturnError_t ret = CO_ERROR_NO; /* blinking bytes and LEDS */ -#if CO_CONFIG_NMT_LEDS > 0 +#if CO_CONFIG_NMT & CO_CONFIG_NMT_LEDS NMT->LEDtimer = 0; NMT->LEDflickering = 0; NMT->LEDblinking = 0; @@ -223,7 +223,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( CANpassive = 1; -#if CO_CONFIG_NMT_LEDS > 0 +#if CO_CONFIG_NMT & CO_CONFIG_NMT_LEDS NMT->LEDtimer += timeDifference_us; if (NMT->LEDtimer >= 50000) { NMT->LEDtimer -= 50000; diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 238b014d..98fd8f8b 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -129,7 +129,7 @@ typedef enum{ * @ref CO_NMT_statusLEDdiodes. Object is initialized by CO_NMT_init(). */ typedef struct{ -#if CO_CONFIG_NMT_LEDS > 0 || defined CO_DOXYGEN +#if (CO_CONFIG_NMT & CO_CONFIG_NMT_LEDS) || defined CO_DOXYGEN uint32_t LEDtimer; /**< 50ms led timer */ int8_t LEDflickering; /**< See @ref CO_NMT_statusLEDdiodes */ int8_t LEDblinking; /**< See @ref CO_NMT_statusLEDdiodes */ diff --git a/301/CO_config.h b/301/CO_config.h new file mode 100644 index 00000000..54fe84dd --- /dev/null +++ b/301/CO_config.h @@ -0,0 +1,146 @@ +/** + * Configuration macros for CANopenNode. + * + * @file CO_config.h + * @ingroup CO_driver + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CO_CONFIG_FLAGS_H +#define CO_CONFIG_FLAGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_STACK_CONFIG Stack configuration + * @ingroup CO_driver + * + * Stack configuration macros specify, which parts of the stack will be enabled. + * + * Default values for stack configuration macros are set in CO_driver.h file. + * They can be overridden by CO_driver_target.h file. If specified so, they can + * further be overridden by CO_driver_custom.h file. + * + * Stack configuration macro is specified as bits, where each bit + * enables/disables some part of the configurable CANopenNode object. Flags are + * used for enabling or checking specific bit. Multiple flags can be ORed + * together. + * + * Configuration macros may be in relation with @ref CO_NO_OBJ macros from + * CANopen.h file. Former enables/disables stack functionalities, latter + * enables/disables objects in object dictionary. Note that some objects in + * object dictionary may need some configuration macros to be enabled. + * @{ + */ + + +/** + * Enable custom callback after CAN receive + * + * Flag enables optional callback functions, which are part of some CANopenNode + * objects. Callbacks can optionally be registered by application, which + * configures threads in operating system. Callback are called after CAN message + * is received and preprocessed by higher priority thread. Callback may + * immediately start mainline processing function, which further processes + * received CAN message. + * + * If callback functions are used, they must be initialized separately, after + * the object initialization. + * + * This flag is common to multiple configuration macros. + */ +#define CO_CONFIG_FLAG_CANRX_CALLBACK 0x0100 + + +/** + * Configuration of NMT + * + * Possible flags, can be ORed: + * - CO_CONFIG_NMT_LEDS - Calculate CANopen blinking variables, which can + * be used for LEDs. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_NMT CO_CONFIG_NMT_LEDS +#endif +#define CO_CONFIG_NMT_LEDS 0x01 + +/** + * Configuration of Heartbeat Consumer + * + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CANRX_CALLBACK - Enable custom callback after CAN receive. + * Callback is configured by CO_HBconsumer_initCallback(). + * - CO_CONFIG_HB_CONS_CHANGE_CALLBACK - Enable custom callback after NMT + * state of the monitored node changes. Callback is configured by + * CO_HBconsumer_initCallbackNmtChanged(). + * - CO_CONFIG_HB_CONS_MULTI_CALLBACK - Enable multiple custom callbacks, which + * can be configured for each monitored node. Callback are configured by + * CO_HBconsumer_initCallbackHeartbeatStarted(), + * CO_HBconsumer_initCallbackTimeout() and + * CO_HBconsumer_initCallbackRemoteReset() functions. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CANRX_CALLBACK | CO_CONFIG_HB_CONS_CHANGE_CALLBACK | CO_CONFIG_HB_CONS_MULTI_CALLBACK +#endif +#define CO_CONFIG_HB_CONS_CHANGE_CALLBACK 0x01 +#define CO_CONFIG_HB_CONS_MULTI_CALLBACK 0x02 + + +/** + * Size of the internal SDO buffer. + * + * Size must be at least equal to size of largest variable in + * @ref CO_SDO_objectDictionary. If data type is domain, data length is not + * limited to SDO buffer size. If block transfer is implemented, value should be + * set to 889. + * + * Value can be in range from 7 to 889 bytes. + */ +#ifndef CO_CONFIG_SDO_BUFFER_SIZE +#define CO_CONFIG_SDO_BUFFER_SIZE 32 +#endif + +/** + * Configuration of Standard CiA 309 usage. + * + * CiA 309 standard covers CANopen access from other networks. It enables + * usage of the NMT master, SDO client and LSS master as a gateway device. + * + * Value can be one of the following: + * - 0: Disabled. + * - 1: Interface enabled + * - 2: Modbus/TCP mapping (Not implemented) + * - 3: ASCII mapping + * - 4: Profinet (Not implemented) + */ +#ifndef CO_CONFIG_309 +#define CO_CONFIG_309 0 +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CO_CONFIG_FLAGS_H */ diff --git a/301/CO_driver.h b/301/CO_driver.h index b051c8aa..b7dca97d 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -28,11 +28,32 @@ #define CO_DRIVER_H #include "CO_driver_target.h" +#include "CO_config.h" #ifdef __cplusplus extern "C" { #endif + +/* Default stack configuration for most common configuration. + * For more information see file CO_config.h. */ +#ifndef CO_CONFIG_NMT +#define CO_CONFIG_NMT 0 +#endif + +#ifndef CO_CONFIG_SDO_BUFFER_SIZE +#define CO_CONFIG_SDO_BUFFER_SIZE 32 +#endif + +#ifndef CO_CONFIG_HB_CONS +#define CO_CONFIG_HB_CONS 0 +#endif + +#ifndef CO_CONFIG_309 +#define CO_CONFIG_309 0 +#endif + + /** * @defgroup CO_driver Driver * @ingroup CO_CANopen_301 @@ -88,74 +109,6 @@ extern "C" { */ -/** - * @defgroup CO_STACK_CONFIG Stack configuration - * - * Definitions specify, which parts of the stack will be enabled. Values can be - * overridden by CO_driver_target.h file for example. - * @{ - */ - -/** - * Usage of CANopen LEDS. - * - * If >0, calculate CANopen blinking variables, which can be used for LEDs */ -#ifndef CO_CONFIG_NMT_LEDS -#define CO_CONFIG_NMT_LEDS 0 -#endif - -/** - * Size of the internal SDO buffer. - * - * Size must be at least equal to size of largest variable in - * @ref CO_SDO_objectDictionary. If data type is domain, data length is not - * limited to SDO buffer size. If block transfer is implemented, value should be - * set to 889. - * - * Value can be in range from 7 to 889 bytes. - */ -#ifndef CO_CONFIG_SDO_BUFFER_SIZE -#define CO_CONFIG_SDO_BUFFER_SIZE 32 -#endif - -/** - * Configuration of Heartbeat Consumer Callbacks usage. - * - * - value = 0: Don't include any Heartbeat consumer callback functions in the - * code. - * - value = 1: Use function CO_HBconsumer_initCallbackNmtChanged(). It enables - * application to configure one callback, which will notify about NMT state - * change of the monitored node. - * - value = 2: Use functions CO_HBconsumer_initCallbackHeartbeatStarted(), - * CO_HBconsumer_initCallbackTimeout() and - * CO_HBconsumer_initCallbackRemoteReset(). Those functions enable application - * to configure set of three callbacks, different for each monitored node. - * - value = 3: Use all functions, from 1 and 2. - */ -#ifndef CO_CONFIG_HB_CONS_CALLBACKS -#define CO_CONFIG_HB_CONS_CALLBACKS 0 -#endif - -/** - * Configuration of Standard CiA 309 usage. - * - * CiA 309 standard covers CANopen access from other networks. It enables - * usage of the NMT master, SDO client and LSS master as a gateway device. - * - * Value can be one of the following: - * - 0: Disabled. - * - 1: Interface enabled - * - 2: Modbus/TCP mapping (Not implemented) - * - 3: ASCII mapping - * - 4: Profinet (Not implemented) - */ -#ifndef CO_CONFIG_309 -#define CO_CONFIG_309 0 -#endif - -/** @} */ - - /* Macros and declarations in following part are only used for documentation. */ #ifdef CO_DOXYGEN /** diff --git a/README.md b/README.md index f69461d4..01730516 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ Flowchart of a typical CANopenNode implementation File structure -------------- - **301/** - CANopen application layer and communication profile. + - **CO_config.h** - Configuration macros for CANopenNode. - **CO_driver.h** - Interface between CAN hardware and CANopenNode. - **CO_Emergency.h/.c** - CANopen Emergency protocol. - **CO_HBconsumer.h/.c** - CANopen Heartbeat consumer protocol. diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index e808a274..2e6096ff 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -17,7 +17,7 @@ Change Log - Rename in CO_driver_target.h: `IS_CANrxNew` -> `CO_FLAG_READ`, `SET_CANrxNew` -> `CO_FLAG_SET`, `CLEAR_CANrxNew` -> `CO_FLAG_CLEAR` - CO_driver.h file, function `CO_CANrxBufferInit()`, last argument (callback) changed from `(*pFunct)(void *object, const CO_CANrxMsg_t *message)` to `void (*CANrx_callback)(void *object, void *message)`. New functions are defined in `CO_driver_target.h` file: `CO_CANrxMsg_readIdent()`, `CO_CANrxMsg_readDLC()` and `CO_CANrxMsg_readData()`. - It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. -- Added `void *object` argument to CO_*_initCallback() functions. API clarified. Callback functions called also from SDO_blockTransferInProgress. +- Added `void *object` argument to CO_*_initCallback() functions. API clarified. - Add emergency receive callback also for own emergency messages. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN @@ -31,7 +31,7 @@ Change Log ### Added - Documentation added to `doc` directory: CHANGELOG.md, deviceSupport.md, gettingStarted.md, LSSusage.md and traceUsage.md. - All CANopen objects calculates next timer info for OS. Useful for energy saving. -- Stack configuration added to CO_driver.h. Can be overridden by custom definitions. +- Added file CO_config.h for stack configuration. Can be overridden by target specific or by custom definitions. [Unreleased master] ------------------- diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 70b153c5..9b08fbf1 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -43,8 +43,8 @@ extern "C" { #endif /* Stack configuration override */ -#ifndef CO_CONFIG_NMT_LEDS -#define CO_CONFIG_NMT_LEDS 1 +#ifndef CO_CONFIG_NMT +#define CO_CONFIG_NMT CO_CONFIG_NMT_LEDS #endif diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index 8077690b..04e476e7 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -116,6 +116,7 @@ void threadMainWait_init(uint32_t interval_us) /* Configure callback functions */ CO_SDO_initCallback(CO->SDO[0], NULL, threadMainWait_callback); CO_EM_initCallback(CO->em, NULL, threadMainWait_callback); + CO_HBconsumer_initCallback(CO->HBcons, NULL, threadMainWait_callback); /* Initial value for time calculation */ threadMainWait.start = CO_LinuxThreads_clock_gettime_us(); diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index b5c3b9e9..26b5b09f 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -50,13 +50,14 @@ extern "C" { #endif -/* Stack configuration override */ +/* Stack configuration override from CO_driver.h. + * For more information see file CO_config.h. */ +#ifndef CO_CONFIG_HB_CONS +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CANRX_CALLBACK | CO_CONFIG_HB_CONS_CHANGE_CALLBACK +#endif #ifndef CO_CONFIG_SDO_BUFFER_SIZE #define CO_CONFIG_SDO_BUFFER_SIZE 889 #endif -#ifndef CO_CONFIG_HB_CONS_CALLBACKS -#define CO_CONFIG_HB_CONS_CALLBACKS 1 -#endif /** From b8e821d0dd663b4db6e80768473dfb4232710e50 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 18 Mar 2020 21:15:33 +0100 Subject: [PATCH 048/520] Add CO_NMT_UNKNOWN state for Heartbeat consumer. --- 301/CO_HBconsumer.c | 16 ++++++++-------- 301/CO_NMT_Heartbeat.h | 1 + socketCAN/CO_error_msgs.h | 2 +- socketCAN/CO_main_basic.c | 8 ++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 2a34c344..ebcc386c 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -119,7 +119,7 @@ CO_ReturnError_t CO_HBconsumer_init( HBcons->monitoredNodes = monitoredNodes; HBcons->numberOfMonitoredNodes = numberOfMonitoredNodes; HBcons->allMonitoredActive = false; - HBcons->allMonitoredOperational = CO_NMT_INITIALIZING; + HBcons->allMonitoredOperational = CO_NMT_UNKNOWN; HBcons->NMTisPreOrOperationalPrev = false; HBcons->CANdevRx = CANdevRx; HBcons->CANdevRxIdxStart = CANdevRxIdxStart; @@ -182,9 +182,9 @@ CO_ReturnError_t CO_HBconsumer_initEntry( CO_HBconsNode_t * monitoredNode = &HBcons->monitoredNodes[idx]; monitoredNode->nodeId = nodeId; monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; - monitoredNode->NMTstate = CO_NMT_INITIALIZING; + monitoredNode->NMTstate = CO_NMT_UNKNOWN; #if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK - monitoredNode->NMTstatePrev = CO_NMT_INITIALIZING; + monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -382,7 +382,7 @@ void CO_HBconsumer_process( #endif CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, i); - monitoredNode->NMTstate = CO_NMT_INITIALIZING; + monitoredNode->NMTstate = CO_NMT_UNKNOWN; monitoredNode->HBstate = CO_HBconsumer_TIMEOUT; } @@ -400,7 +400,7 @@ void CO_HBconsumer_process( allMonitoredActiveCurrent = false; } if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { - allMonitoredOperationalCurrent = CO_NMT_INITIALIZING; + allMonitoredOperationalCurrent = CO_NMT_UNKNOWN; } #if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK /* Verify, if NMT state of monitored node changed */ @@ -419,9 +419,9 @@ void CO_HBconsumer_process( else if (NMTisPreOrOperational || HBcons->NMTisPreOrOperationalPrev) { /* (pre)operational state changed, clear variables */ for(i=0; inumberOfMonitoredNodes; i++) { - monitoredNode->NMTstate = CO_NMT_INITIALIZING; + monitoredNode->NMTstate = CO_NMT_UNKNOWN; #if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK - monitoredNode->NMTstatePrev = CO_NMT_INITIALIZING; + monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { @@ -430,7 +430,7 @@ void CO_HBconsumer_process( monitoredNode++; } allMonitoredActiveCurrent = false; - allMonitoredOperationalCurrent = CO_NMT_INITIALIZING; + allMonitoredOperationalCurrent = CO_NMT_UNKNOWN; } /* Clear emergencies when all monitored nodes becomes active. diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 98fd8f8b..3ea9ac56 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -93,6 +93,7 @@ extern "C" { * Internal network state of the CANopen node */ typedef enum{ + CO_NMT_UNKNOWN = -1, /**< Device state is unknown (for heartbeat consumer) */ CO_NMT_INITIALIZING = 0, /**< Device is initializing */ CO_NMT_PRE_OPERATIONAL = 127, /**< Device is in pre-operational state */ CO_NMT_OPERATIONAL = 5, /**< Device is in operational state */ diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index c5852ffe..2008dc40 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -87,7 +87,7 @@ extern "C" { #define DBG_NO_CAN_DEVICE "(%s) Can't find CAN device \"%s\"", __func__ #define DBG_OBJECT_DICTIONARY "(%s) Error in Object Dictionary \"%s\"", __func__ #define DBG_CAN_OPEN "(%s) CANopen error in %s, err=%d", __func__ -#define DBG_CAN_OPEN_INFO "(%s) CANopen device, Node ID = %d(0x%02X), %s", __func__ +#define DBG_CAN_OPEN_INFO "(%s) CANopen device, Node ID = 0x%02X, %s", __func__ #define DBG_COMMAND_LOCAL_INFO "(%s) Command interface on socket \"%s\" started", __func__ #define DBG_COMMAND_TCP_INFO "(%s) Command interface on tcp port \"%hu\" started", __func__ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index f0cab2da..78afdc9c 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -263,7 +263,7 @@ int main (int argc, char *argv[]) { } - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, CO_ownNodeId, "starting"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "starting"); /* Allocate memory for CANopen objects */ @@ -308,7 +308,7 @@ int main (int argc, char *argv[]) { while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { /* CANopen communication reset - initialize CANopen objects *******************/ - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, CO_ownNodeId, "communication reset"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "communication reset"); #if CO_CONFIG_309 > 0 @@ -439,7 +439,7 @@ int main (int argc, char *argv[]) { reset = CO_RESET_NOT; - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, CO_ownNodeId, "running ..."); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "running ..."); while(reset == CO_RESET_NOT && CO_endProgram == 0) { @@ -493,7 +493,7 @@ int main (int argc, char *argv[]) { threadMainWait_close(); CO_delete((void *)CANdevice0Index); - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, CO_ownNodeId, "finished"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "finished"); /* Flush all buffers (and reboot) */ if(rebootEnable && reset == CO_RESET_APP) { From d9c44c69d1f331e42f43d7a2d98326ff23ffae85 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 18 Mar 2020 22:54:17 +0100 Subject: [PATCH 049/520] Change non-descriptive CO_***_initCallback() into CO_***_initCallbackPre(). Change CO_NMT_initCallback() into CO_NMT_initCallbackChange(). Change type of NMT->operatingState from uint8_t into enum CO_NMT_internalState_t. --- .gitignore | 1 + 301/CO_Emergency.c | 2 +- 301/CO_Emergency.h | 6 +++--- 301/CO_HBconsumer.c | 4 +++- 301/CO_HBconsumer.h | 10 ++++++---- 301/CO_NMT_Heartbeat.c | 16 ++++++++-------- 301/CO_NMT_Heartbeat.h | 6 +++--- 301/CO_PDO.c | 4 ++-- 301/CO_PDO.h | 8 ++++---- 301/CO_SDOclient.c | 2 +- 301/CO_SDOclient.h | 6 +++--- 301/CO_SDOserver.c | 2 +- 301/CO_SDOserver.h | 6 +++--- 301/CO_SYNC.c | 4 ++-- 301/CO_SYNC.h | 4 ++-- 301/CO_TIME.c | 4 ++-- 301/CO_TIME.h | 4 ++-- 301/CO_config.h | 16 ++++++++++------ 305/CO_LSSmaster.c | 2 +- 305/CO_LSSmaster.h | 4 ++-- CANopen.h | 5 +++-- socketCAN/CO_Linux_threads.c | 21 ++++++++++++--------- socketCAN/CO_main_basic.c | 2 +- 23 files changed, 76 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index 650a268e..4c60d24c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /example/canopennode_blank /canopend *.o +/od_storage* doc/html/ diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 1a330a9e..bdf8d83e 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -212,7 +212,7 @@ CO_ReturnError_t CO_EM_init( /******************************************************************************/ -void CO_EM_initCallback( +void CO_EM_initCallbackPre( CO_EM_t *em, void *object, void (*pFunctSignal)(void *object)) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 42515988..25c49f3f 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -262,9 +262,9 @@ typedef struct{ uint8_t *bufReadPtr; /**< Read pointer in the above buffer */ uint8_t bufFull; /**< True if above buffer is full */ uint8_t wrongErrorReport; /**< Error in arguments to CO_errorReport() */ - /** From CO_EM_initCallback() or NULL */ + /** From CO_EM_initCallbackPre() or NULL */ void (*pFunctSignal)(void *object); - /** From CO_EM_initCallback() or NULL */ + /** From CO_EM_initCallbackPre() or NULL */ void *functSignalObject; /** From CO_EM_initCallbackRx() or NULL */ void (*pFunctSignalRx)(const uint16_t ident, @@ -400,7 +400,7 @@ CO_ReturnError_t CO_EM_init( * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_EM_initCallback( +void CO_EM_initCallbackPre( CO_EM_t *em, void *object, void (*pFunctSignal)(void *object)); diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index ebcc386c..5b998f4d 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -216,7 +216,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( #if CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK /******************************************************************************/ -void CO_HBconsumer_initCallback( +void CO_HBconsumer_initCallbackPre( CO_HBconsumer_t *HBcons, void *object, void (*pFunctSignal)(void *object)) @@ -446,6 +446,7 @@ void CO_HBconsumer_process( } +#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_QUERY_FUNCT /******************************************************************************/ int8_t CO_HBconsumer_getIdxByNodeId( CO_HBconsumer_t *HBcons, @@ -507,3 +508,4 @@ int8_t CO_HBconsumer_getNmtState( } return -1; } +#endif /* CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_QUERY_FUNCT */ diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index de1e33a7..21b1a475 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -78,9 +78,9 @@ typedef struct { /** Indication if new Heartbeat message received from the CAN bus */ volatile void *CANrxNew; #if (CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK) || defined CO_DOXYGEN - /** From CO_HBconsumer_initCallback() or NULL */ + /** From CO_HBconsumer_initCallbackPre() or NULL */ void (*pFunctSignalCanRx)(void *object); - /** From CO_HBconsumer_initCallback() or NULL */ + /** From CO_HBconsumer_initCallbackPre() or NULL */ void *functSignalObjectCanRx; #endif #if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK) || defined CO_DOXYGEN @@ -200,7 +200,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_HBconsumer_initCallback( +void CO_HBconsumer_initCallbackPre( CO_HBconsumer_t *HBcons, void *object, void (*pFunctSignal)(void *object)); @@ -299,6 +299,8 @@ void CO_HBconsumer_process( uint32_t timeDifference_us, uint32_t *timerNext_us); + +#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_QUERY_FUNCT) || defined CO_DOXYGEN /** * Get the heartbeat producer object index by node ID * @@ -336,7 +338,7 @@ int8_t CO_HBconsumer_getNmtState( CO_HBconsumer_t *HBcons, uint8_t idx, CO_NMT_internalState_t *nmtState); - +#endif /* CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_QUERY_FUNCT */ #ifdef __cplusplus } diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 9c9ffa52..b52590a5 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -48,7 +48,7 @@ static void CO_NMT_receive(void *object, void *msg){ if((DLC == 2) && ((nodeId == 0) || (nodeId == NMT->nodeId))){ uint8_t command = data[0]; - uint8_t currentOperatingState = NMT->operatingState; + CO_NMT_internalState_t currentOperatingState = NMT->operatingState; switch(command){ case CO_NMT_ENTER_OPERATIONAL: @@ -73,7 +73,7 @@ static void CO_NMT_receive(void *object, void *msg){ } if(NMT->pFunctNMT!=NULL && currentOperatingState!=NMT->operatingState){ - NMT->pFunctNMT((CO_NMT_internalState_t) NMT->operatingState); + NMT->pFunctNMT(NMT->operatingState); } } } @@ -164,14 +164,14 @@ CO_ReturnError_t CO_NMT_init( /******************************************************************************/ -void CO_NMT_initCallback( +void CO_NMT_initCallbackChange( CO_NMT_t *NMT, void (*pFunctNMT)(CO_NMT_internalState_t state)) { if(NMT != NULL){ NMT->pFunctNMT = pFunctNMT; if(NMT->pFunctNMT != NULL){ - NMT->pFunctNMT((CO_NMT_internalState_t) NMT->operatingState); + NMT->pFunctNMT(NMT->operatingState); } } } @@ -189,7 +189,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( { uint8_t CANpassive; - uint8_t currentOperatingState = NMT->operatingState; + CO_NMT_internalState_t currentOperatingState = NMT->operatingState; uint32_t HBtime = (uint32_t)HBtime_ms * 1000; NMT->HBproducerTimer += timeDifference_us; @@ -201,7 +201,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( * not for synchronization, it is for health report. */ NMT->HBproducerTimer = 0; - NMT->HB_TXbuff->data[0] = NMT->operatingState; + NMT->HB_TXbuff->data[0] = (uint8_t) NMT->operatingState; CO_CANsend(NMT->HB_CANdevTx, NMT->HB_TXbuff); if (NMT->operatingState == CO_NMT_INITIALIZING) { @@ -351,7 +351,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( if (currentOperatingState != NMT->operatingState) { if (NMT->pFunctNMT != NULL) { - NMT->pFunctNMT((CO_NMT_internalState_t) NMT->operatingState); + NMT->pFunctNMT(NMT->operatingState); } /* execute next CANopen processing immediately */ if (timerNext_us != NULL) { @@ -380,7 +380,7 @@ CO_NMT_internalState_t CO_NMT_getInternalState( CO_NMT_t *NMT) { if(NMT != NULL){ - return (CO_NMT_internalState_t) NMT->operatingState; + return NMT->operatingState; } return CO_NMT_INITIALIZING; } diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 3ea9ac56..9ca84fc3 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -142,7 +142,7 @@ typedef struct{ int8_t LEDredError; /**< See @ref CO_NMT_statusLEDdiodes */ #endif /* CO_CONFIG_NMT_LEDS */ - uint8_t operatingState; /**< See @ref CO_NMT_internalState_t */ + CO_NMT_internalState_t operatingState; /**< Current NMT operating state. */ uint8_t resetCommand; /**< If different than zero, device will reset */ uint8_t nodeId; /**< CANopen Node ID of this device */ uint32_t HBproducerTimer;/**< Internal timer for HB producer */ @@ -152,7 +152,7 @@ typedef struct{ CO_CANtx_t *NMT_TXbuff; /**< CAN transmit buffer for NMT master message */ CO_CANmodule_t *HB_CANdevTx; /**< From CO_NMT_init() */ CO_CANtx_t *HB_TXbuff; /**< CAN transmit buffer for heartbeat message */ - void (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallback() or NULL */ + void (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallbackChange() or NULL */ }CO_NMT_t; @@ -208,7 +208,7 @@ CO_ReturnError_t CO_NMT_init( * @param NMT This object. * @param pFunctNMT Pointer to the callback function. Not called if NULL. */ -void CO_NMT_initCallback( +void CO_NMT_initCallbackChange( CO_NMT_t *NMT, void (*pFunctNMT)(CO_NMT_internalState_t state)); diff --git a/301/CO_PDO.c b/301/CO_PDO.c index ce466f11..48c18dd1 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -718,7 +718,7 @@ CO_ReturnError_t CO_RPDO_init( CO_EM_t *em, CO_SDO_t *SDO, CO_SYNC_t *SYNC, - uint8_t *operatingState, + CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, uint8_t restrictionFlags, @@ -769,7 +769,7 @@ CO_ReturnError_t CO_TPDO_init( CO_EM_t *em, CO_SDO_t *SDO, CO_SYNC_t *SYNC, - uint8_t *operatingState, + CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, uint8_t restrictionFlags, diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 21f7b7da..237ebf39 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -168,7 +168,7 @@ typedef struct{ CO_SYNC_t *SYNC; /**< From CO_RPDO_init() */ const CO_RPDOCommPar_t *RPDOCommPar;/**< From CO_RPDO_init() */ const CO_RPDOMapPar_t *RPDOMapPar; /**< From CO_RPDO_init() */ - uint8_t *operatingState; /**< From CO_RPDO_init() */ + CO_NMT_internalState_t *operatingState; /**< From CO_RPDO_init() */ uint8_t nodeId; /**< From CO_RPDO_init() */ uint16_t defaultCOB_ID; /**< From CO_RPDO_init() */ uint8_t restrictionFlags;/**< From CO_RPDO_init() */ @@ -198,7 +198,7 @@ typedef struct{ CO_SYNC_t *SYNC; /**< From CO_TPDO_init() */ const CO_TPDOCommPar_t *TPDOCommPar;/**< From CO_TPDO_init() */ const CO_TPDOMapPar_t *TPDOMapPar; /**< From CO_TPDO_init() */ - uint8_t *operatingState; /**< From CO_TPDO_init() */ + CO_NMT_internalState_t *operatingState; /**< From CO_TPDO_init() */ uint8_t nodeId; /**< From CO_TPDO_init() */ uint16_t defaultCOB_ID; /**< From CO_TPDO_init() */ uint8_t restrictionFlags;/**< From CO_TPDO_init() */ @@ -261,7 +261,7 @@ CO_ReturnError_t CO_RPDO_init( CO_EM_t *em, CO_SDO_t *SDO, CO_SYNC_t *SYNC, - uint8_t *operatingState, + CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, uint8_t restrictionFlags, @@ -308,7 +308,7 @@ CO_ReturnError_t CO_TPDO_init( CO_EM_t *em, CO_SDO_t *SDO, CO_SYNC_t *SYNC, - uint8_t *operatingState, + CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, uint8_t restrictionFlags, diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index a62f92b1..85363931 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -213,7 +213,7 @@ CO_ReturnError_t CO_SDOclient_init( /******************************************************************************/ -void CO_SDOclient_initCallback( +void CO_SDOclient_initCallbackPre( CO_SDOclient_t *SDOclient, void *object, void (*pFunctSignal)(void *object)) diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 398e2c81..3522ee4b 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -136,9 +136,9 @@ typedef struct{ volatile void *CANrxNew; /** 8 data bytes of the received message */ uint8_t CANrxData[8]; - /** From CO_SDOclient_initCallback() or NULL */ + /** From CO_SDOclient_initCallbackPre() or NULL */ void (*pFunctSignal)(void *object); - /** From CO_SDOclient_initCallback() or NULL */ + /** From CO_SDOclient_initCallbackPre() or NULL */ void *functSignalObject; /** From CO_SDOclient_init() */ CO_CANmodule_t *CANdevTx; @@ -212,7 +212,7 @@ CO_ReturnError_t CO_SDOclient_init( * be NULL. * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_SDOclient_initCallback( +void CO_SDOclient_initCallbackPre( CO_SDOclient_t *SDOclient, void *object, void (*pFunctSignal)(void *object)); diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 6e6af7b8..bde3fb36 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -366,7 +366,7 @@ CO_ReturnError_t CO_SDO_init( /******************************************************************************/ -void CO_SDO_initCallback( +void CO_SDO_initCallbackPre( CO_SDO_t *SDO, void *object, void (*pFunctSignal)(void *object)) diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 1e8e0b97..26bdb1e9 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -613,9 +613,9 @@ typedef struct{ bool_t endOfTransfer; /** Variable indicates, if new SDO message received from CAN bus */ volatile void *CANrxNew; - /** From CO_SDO_initCallback() or NULL */ + /** From CO_SDO_initCallbackPre() or NULL */ void (*pFunctSignal)(void *object); - /** From CO_SDO_initCallback() or NULL */ + /** From CO_SDO_initCallbackPre() or NULL */ void *functSignalObject; /** From CO_SDO_init() */ CO_CANmodule_t *CANdevTx; @@ -778,7 +778,7 @@ CO_ReturnError_t CO_SDO_init( * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_SDO_initCallback( +void CO_SDO_initCallbackPre( CO_SDO_t *SDO, void *object, void (*pFunctSignal)(void *object)); diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 8c720d6a..00176e26 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -39,7 +39,7 @@ */ static void CO_SYNC_receive(void *object, void *msg) { CO_SYNC_t *SYNC; - uint8_t operState; + CO_NMT_internalState_t operState; SYNC = (CO_SYNC_t*)object; /* this is the correct pointer type of the first argument */ operState = *SYNC->operatingState; @@ -241,7 +241,7 @@ CO_ReturnError_t CO_SYNC_init( CO_SYNC_t *SYNC, CO_EM_t *em, CO_SDO_t *SDO, - uint8_t *operatingState, + CO_NMT_internalState_t *operatingState, uint32_t COB_ID_SYNCMessage, uint32_t communicationCyclePeriod, uint8_t synchronousCounterOverflowValue, diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index ebe163ec..8d8f1fb8 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -66,7 +66,7 @@ extern "C" { */ typedef struct{ CO_EM_t *em; /**< From CO_SYNC_init() */ - uint8_t *operatingState; /**< From CO_SYNC_init() */ + CO_NMT_internalState_t *operatingState; /**< From CO_SYNC_init() */ /** True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ variable from Object dictionary (index 0x1005). */ bool_t isProducer; @@ -127,7 +127,7 @@ CO_ReturnError_t CO_SYNC_init( CO_SYNC_t *SYNC, CO_EM_t *em, CO_SDO_t *SDO, - uint8_t *operatingState, + CO_NMT_internalState_t *operatingState, uint32_t COB_ID_SYNCMessage, uint32_t communicationCyclePeriod, uint8_t synchronousCounterOverflowValue, diff --git a/301/CO_TIME.c b/301/CO_TIME.c index db352182..88f76415 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -37,7 +37,7 @@ */ static void CO_TIME_receive(void *object, void *msg){ CO_TIME_t *TIME; - uint8_t operState; + CO_NMT_internalState_t operState; uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); @@ -60,7 +60,7 @@ CO_ReturnError_t CO_TIME_init( CO_TIME_t *TIME, CO_EM_t *em, CO_SDO_t *SDO, - uint8_t *operatingState, + CO_NMT_internalState_t *operatingState, uint32_t COB_ID_TIMEMessage, uint32_t TIMECyclePeriod, CO_CANmodule_t *CANdevRx, diff --git a/301/CO_TIME.h b/301/CO_TIME.h index dda323a8..8c6d5421 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -78,7 +78,7 @@ extern "C" { */ typedef struct{ CO_EM_t *em; /**< From CO_TIME_init() */ - uint8_t *operatingState; /**< From CO_TIME_init() */ + CO_NMT_internalState_t *operatingState; /**< From CO_TIME_init() */ /** True, if device is TIME consumer. Calculated from _COB ID TIME Message_ variable from Object dictionary (index 0x1012). */ bool_t isConsumer; @@ -129,7 +129,7 @@ CO_ReturnError_t CO_TIME_init( CO_TIME_t *TIME, CO_EM_t *em, CO_SDO_t *SDO, - uint8_t *operatingState, + CO_NMT_internalState_t *operatingState, uint32_t COB_ID_TIMEMessage, uint32_t TIMECyclePeriod, CO_CANmodule_t *CANdevRx, diff --git a/301/CO_config.h b/301/CO_config.h index 54fe84dd..0aac444c 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -59,10 +59,11 @@ extern "C" { * * Flag enables optional callback functions, which are part of some CANopenNode * objects. Callbacks can optionally be registered by application, which - * configures threads in operating system. Callback are called after CAN message - * is received and preprocessed by higher priority thread. Callback may - * immediately start mainline processing function, which further processes - * received CAN message. + * configures threads in operating system. Callbacks are called after something + * has been preprocessed by higher priority thread and must be further + * processed by lower priority thread. For example when CAN message is received + * and preprocessed, callback should wake up mainline processing function. + * See also @ref CO_process() function. * * If callback functions are used, they must be initialized separately, after * the object initialization. @@ -89,7 +90,7 @@ extern "C" { * * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_CANRX_CALLBACK - Enable custom callback after CAN receive. - * Callback is configured by CO_HBconsumer_initCallback(). + * Callback is configured by CO_HBconsumer_initCallbackPre(). * - CO_CONFIG_HB_CONS_CHANGE_CALLBACK - Enable custom callback after NMT * state of the monitored node changes. Callback is configured by * CO_HBconsumer_initCallbackNmtChanged(). @@ -98,12 +99,15 @@ extern "C" { * CO_HBconsumer_initCallbackHeartbeatStarted(), * CO_HBconsumer_initCallbackTimeout() and * CO_HBconsumer_initCallbackRemoteReset() functions. + * - CO_CONFIG_HB_CONS_QUERY_FUNCT - Enable functions for query HB state or + * NMT state of the specific monitored node. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CANRX_CALLBACK | CO_CONFIG_HB_CONS_CHANGE_CALLBACK | CO_CONFIG_HB_CONS_MULTI_CALLBACK +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CANRX_CALLBACK | CO_CONFIG_HB_CONS_CHANGE_CALLBACK | CO_CONFIG_HB_CONS_MULTI_CALLBACK | CO_CONFIG_HB_CONS_QUERY_FUNCT #endif #define CO_CONFIG_HB_CONS_CHANGE_CALLBACK 0x01 #define CO_CONFIG_HB_CONS_MULTI_CALLBACK 0x02 +#define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x04 /** diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 0fa9635d..0ecf3392 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -193,7 +193,7 @@ void CO_LSSmaster_changeTimeout( /******************************************************************************/ -void CO_LSSmaster_initCallback( +void CO_LSSmaster_initCallbackPre( CO_LSSmaster_t *LSSmaster, void *object, void (*pFunctSignal)(void *object)) diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index f2d4404a..16793feb 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -119,7 +119,7 @@ typedef struct{ volatile void *CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */ uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ - void (*pFunctSignal)(void *object); /**< From CO_LSSmaster_initCallback() or NULL */ + void (*pFunctSignal)(void *object); /**< From CO_LSSmaster_initCallbackPre() or NULL */ void *functSignalObject;/**< Pointer to object */ CO_CANmodule_t *CANdevTx; /**< From #CO_LSSslave_init() */ @@ -196,7 +196,7 @@ void CO_LSSmaster_changeTimeout( * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_LSSmaster_initCallback( +void CO_LSSmaster_initCallbackPre( CO_LSSmaster_t *LSSmaster, void *object, void (*pFunctSignal)(void *object)); diff --git a/CANopen.h b/CANopen.h index c504a2c5..efd14472 100644 --- a/CANopen.h +++ b/CANopen.h @@ -295,8 +295,9 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); * Output will be equal or lower to initial value. Calculation is based * on various timers which expire in known time. Parameter should be * used in combination with callbacks configured with - * CO_EM_initCallback() and CO_SDO_initCallback(). Those callbacks should - * also trigger calling of CO_process() function. + * CO_***_initCallbackPre() functions. Those callbacks should also + * trigger calling of CO_process() function. + * See also @ref CO_CONFIG_FLAG_CANRX_CALLBACK configuration macro. * * This is experimental feature and can be used for energy saving in case * of low traffic on CAN bus. Parameter is ignored if NULL. diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index 04e476e7..eb8f1932 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -56,14 +56,16 @@ void threadMain_init(void (*callback)(void*), void *object) { threadMain.start = CO_LinuxThreads_clock_gettime_us(); - CO_SDO_initCallback(CO->SDO[0], object, callback); - CO_EM_initCallback(CO->em, object, callback); + CO_SDO_initCallbackPre(CO->SDO[0], object, callback); + CO_EM_initCallbackPre(CO->em, object, callback); + CO_HBconsumer_initCallbackPre(CO->HBcons, object, callback); } void threadMain_close(void) { - CO_SDO_initCallback(CO->SDO[0], NULL, NULL); - CO_EM_initCallback(CO->em, NULL, NULL); + CO_SDO_initCallbackPre(CO->SDO[0], NULL, NULL); + CO_EM_initCallbackPre(CO->em, NULL, NULL); + CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, NULL); } void threadMain_process(CO_NMT_reset_cmd_t *reset) @@ -114,9 +116,9 @@ void threadMainWait_init(uint32_t interval_us) struct epoll_event ev; /* Configure callback functions */ - CO_SDO_initCallback(CO->SDO[0], NULL, threadMainWait_callback); - CO_EM_initCallback(CO->em, NULL, threadMainWait_callback); - CO_HBconsumer_initCallback(CO->HBcons, NULL, threadMainWait_callback); + CO_SDO_initCallbackPre(CO->SDO[0], NULL, threadMainWait_callback); + CO_EM_initCallbackPre(CO->em, NULL, threadMainWait_callback); + CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, threadMainWait_callback); /* Initial value for time calculation */ threadMainWait.start = CO_LinuxThreads_clock_gettime_us(); @@ -169,8 +171,9 @@ void threadMainWait_init(uint32_t interval_us) void threadMainWait_close(void) { - CO_SDO_initCallback(CO->SDO[0], NULL, NULL); - CO_EM_initCallback(CO->em, NULL, NULL); + CO_SDO_initCallbackPre(CO->SDO[0], NULL, NULL); + CO_EM_initCallbackPre(CO->em, NULL, NULL); + CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, NULL); close(threadMainWait.epoll_fd); close(threadMainWait.event_fd); diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 78afdc9c..88c785be 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -348,7 +348,7 @@ int main (int argc, char *argv[]) { /* initialize callbacks */ CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); - CO_NMT_initCallback(CO->NMT, NmtChangeCallback); + CO_NMT_initCallbackChange(CO->NMT, NmtChangeCallback); CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, HeartbeatNmtChangedCallback); From c88194e813356fb0560f22c696bc943919acf133 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 19 Mar 2020 18:07:23 +0100 Subject: [PATCH 050/520] Add Stack configuration macros to most of CANopenNode objects. Add CO_NMT_initCallbackPre() --- 301/CO_Emergency.c | 40 ++++++++++--- 301/CO_Emergency.h | 12 +++- 301/CO_HBconsumer.c | 42 ++++++------- 301/CO_HBconsumer.h | 24 ++++---- 301/CO_NMT_Heartbeat.c | 56 ++++++++++++++++-- 301/CO_NMT_Heartbeat.h | 40 ++++++++++++- 301/CO_SDOclient.c | 6 ++ 301/CO_SDOclient.h | 4 ++ 301/CO_SDOserver.c | 24 +++++--- 301/CO_SDOserver.h | 14 +++-- 301/CO_config.h | 110 +++++++++++++++++++++++++++++------ 301/CO_driver.h | 20 ++++++- 305/CO_LSSmaster.c | 7 +++ 305/CO_LSSmaster.h | 8 ++- CANopen.c | 10 ++-- CANopen.h | 37 ++++++++++-- Doxyfile | 4 +- example/CO_driver_target.h | 31 +++++++++- socketCAN/CO_Linux_threads.c | 15 +++-- socketCAN/CO_Linux_threads.h | 13 ++++- socketCAN/CO_driver_target.h | 25 +++++++- socketCAN/CO_main_basic.c | 9 +-- 22 files changed, 433 insertions(+), 118 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index bdf8d83e..3f2d6521 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -29,6 +29,7 @@ #include "301/CO_Emergency.h" +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER /* * Read received message from CAN module. * @@ -59,6 +60,7 @@ static void CO_EM_receive(void *object, void *msg) { } } } +#endif /* * Function for accessing _Pre-Defined Error Field_ (index 0x1003) from SDO server. @@ -151,7 +153,11 @@ CO_ReturnError_t CO_EM_init( /* verify arguments */ if(em==NULL || emPr==NULL || SDO==NULL || errorStatusBits==NULL || errorStatusBitsSize<6U || - errorRegister==NULL || preDefErr==NULL || CANdevTx==NULL || CANdevRx==NULL){ + errorRegister==NULL || preDefErr==NULL || CANdevTx==NULL +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + || CANdevRx==NULL +#endif + ){ return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -163,9 +169,13 @@ CO_ReturnError_t CO_EM_init( em->bufReadPtr = em->buf; em->bufFull = 0U; em->wrongErrorReport = 0U; - em->pFunctSignal = NULL; - em->functSignalObject = NULL; +#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE + em->pFunctSignalPre = NULL; + em->functSignalObjectPre = NULL; +#endif +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER em->pFunctSignalRx = NULL; +#endif emPr->em = em; emPr->errorRegister = errorRegister; emPr->preDefErr = preDefErr; @@ -182,6 +192,7 @@ CO_ReturnError_t CO_EM_init( CO_OD_configure(SDO, OD_H1003_PREDEF_ERR_FIELD, CO_ODF_1003, (void*)emPr, 0, 0U); CO_OD_configure(SDO, OD_H1014_COBID_EMERGENCY, CO_ODF_1014, (void*)&SDO->nodeId, 0, 0U); +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER /* configure SDO server CAN reception */ ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ @@ -191,6 +202,7 @@ CO_ReturnError_t CO_EM_init( 0, /* rtr */ (void*)em, /* object passed to receive function */ CO_EM_receive); /* this function will process received message */ +#endif /* configure emergency message CAN transmission */ emPr->CANdev = CANdevTx; @@ -211,6 +223,7 @@ CO_ReturnError_t CO_EM_init( } +#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ void CO_EM_initCallbackPre( CO_EM_t *em, @@ -218,12 +231,14 @@ void CO_EM_initCallbackPre( void (*pFunctSignal)(void *object)) { if(em != NULL){ - em->functSignalObject = object; - em->pFunctSignal = pFunctSignal; + em->functSignalObjectPre = object; + em->pFunctSignalPre = pFunctSignal; } } +#endif +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER /******************************************************************************/ void CO_EM_initCallbackRx( CO_EM_t *em, @@ -237,6 +252,7 @@ void CO_EM_initCallbackRx( em->pFunctSignalRx = pFunctSignalRx; } } +#endif /******************************************************************************/ @@ -300,6 +316,7 @@ void CO_EM_process( /* add error register */ em->bufReadPtr[2] = *emPr->errorRegister; +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER /* report also own emergency messages */ if (em->pFunctSignalRx != NULL) { uint16_t errorCode; @@ -312,6 +329,7 @@ void CO_EM_process( em->bufReadPtr[3], infoCode); } +#endif /* copy data to CAN emergency message */ CO_memcpy(emPr->CANtxBuff->data, em->bufReadPtr, 8U); @@ -414,10 +432,12 @@ void CO_errorReport(CO_EM_t *em, const uint8_t errorBit, const uint16_t errorCod if(em->bufWritePtr == em->bufReadPtr) em->bufFull = 1; CO_UNLOCK_EMCY(); +#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */ - if(em->pFunctSignal != NULL) { - em->pFunctSignal(em->functSignalObject); + if(em->pFunctSignalPre != NULL) { + em->pFunctSignalPre(em->functSignalObjectPre); } +#endif } } } @@ -473,10 +493,12 @@ void CO_errorReset(CO_EM_t *em, const uint8_t errorBit, const uint32_t infoCode) if(em->bufWritePtr == em->bufReadPtr) em->bufFull = 1; CO_UNLOCK_EMCY(); +#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */ - if(em->pFunctSignal != NULL) { - em->pFunctSignal(em->functSignalObject); + if(em->pFunctSignalPre != NULL) { + em->pFunctSignalPre(em->functSignalObjectPre); } +#endif } } } diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 25c49f3f..e4275594 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -262,16 +262,20 @@ typedef struct{ uint8_t *bufReadPtr; /**< Read pointer in the above buffer */ uint8_t bufFull; /**< True if above buffer is full */ uint8_t wrongErrorReport; /**< Error in arguments to CO_errorReport() */ +#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_EM_initCallbackPre() or NULL */ - void (*pFunctSignal)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_EM_initCallbackPre() or NULL */ - void *functSignalObject; + void *functSignalObjectPre; +#endif +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN /** From CO_EM_initCallbackRx() or NULL */ void (*pFunctSignalRx)(const uint16_t ident, const uint16_t errorCode, const uint8_t errorRegister, const uint8_t errorBit, const uint32_t infoCode); +#endif }CO_EM_t; @@ -387,6 +391,7 @@ CO_ReturnError_t CO_EM_init( uint16_t CANidTxEM); +#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** * Initialize Emergency callback function. * @@ -404,8 +409,10 @@ void CO_EM_initCallbackPre( CO_EM_t *em, void *object, void (*pFunctSignal)(void *object)); +#endif +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN /** * Initialize Emergency received callback function. * @@ -428,6 +435,7 @@ void CO_EM_initCallbackRx( const uint8_t errorRegister, const uint8_t errorBit, const uint32_t infoCode)); +#endif /** diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 5b998f4d..e1dbefb7 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -50,10 +50,10 @@ static void CO_HBcons_receive(void *object, void *msg){ CO_FLAG_SET(HBconsNode->CANrxNew); } -#if CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles HBcons. */ - if(HBconsNode->pFunctSignalCanRx != NULL) { - HBconsNode->pFunctSignalCanRx(HBconsNode->functSignalObjectCanRx); + if(HBconsNode->pFunctSignalPre != NULL) { + HBconsNode->pFunctSignalPre(HBconsNode->functSignalObjectPre); } #endif } @@ -123,7 +123,7 @@ CO_ReturnError_t CO_HBconsumer_init( HBcons->NMTisPreOrOperationalPrev = false; HBcons->CANdevRx = CANdevRx; HBcons->CANdevRxIdxStart = CANdevRxIdxStart; -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE HBcons->pFunctSignalNmtChanged = NULL; #endif @@ -131,10 +131,10 @@ CO_ReturnError_t CO_HBconsumer_init( uint8_t nodeId = (HBcons->HBconsTime[i] >> 16U) & 0xFFU; uint16_t time = HBcons->HBconsTime[i] & 0xFFFFU; ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); -#if CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK - HBcons->monitoredNodes[i].pFunctSignalCanRx = NULL; +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE + HBcons->monitoredNodes[i].pFunctSignalPre = NULL; #endif -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI HBcons->monitoredNodes[i].pFunctSignalHbStarted = NULL; HBcons->monitoredNodes[i].pFunctSignalTimeout = NULL; HBcons->monitoredNodes[i].pFunctSignalRemoteReset = NULL; @@ -183,7 +183,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( monitoredNode->nodeId = nodeId; monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; monitoredNode->NMTstate = CO_NMT_UNKNOWN; -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -214,7 +214,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( } -#if CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ void CO_HBconsumer_initCallbackPre( CO_HBconsumer_t *HBcons, @@ -224,15 +224,15 @@ void CO_HBconsumer_initCallbackPre( if (HBcons != NULL) { uint8_t i; for(i=0; inumberOfMonitoredNodes; i++) { - HBcons->monitoredNodes[i].pFunctSignalCanRx = pFunctSignal; - HBcons->monitoredNodes[i].functSignalObjectCanRx = object; + HBcons->monitoredNodes[i].pFunctSignalPre = pFunctSignal; + HBcons->monitoredNodes[i].functSignalObjectPre = object; } } } #endif -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE /******************************************************************************/ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, @@ -251,7 +251,7 @@ void CO_HBconsumer_initCallbackNmtChanged( #endif -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI /******************************************************************************/ void CO_HBconsumer_initCallbackHeartbeatStarted( CO_HBconsumer_t *HBcons, @@ -307,7 +307,7 @@ void CO_HBconsumer_initCallbackRemoteReset( monitoredNode->pFunctSignalRemoteReset = pFunctSignal; monitoredNode->functSignalObjectRemoteReset = object; } -#endif /* CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK */ +#endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI */ /******************************************************************************/ @@ -334,7 +334,7 @@ void CO_HBconsumer_process( if (CO_FLAG_READ(monitoredNode->CANrxNew)) { if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) { /* bootup message*/ -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI if (monitoredNode->pFunctSignalRemoteReset != NULL) { monitoredNode->pFunctSignalRemoteReset( monitoredNode->nodeId, i, @@ -351,7 +351,7 @@ void CO_HBconsumer_process( } else { /* heartbeat message */ -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE && monitoredNode->pFunctSignalHbStarted != NULL) { monitoredNode->pFunctSignalHbStarted( @@ -373,7 +373,7 @@ void CO_HBconsumer_process( if (monitoredNode->timeoutTimer >= monitoredNode->time_us) { /* timeout expired */ -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI if (monitoredNode->pFunctSignalTimeout!=NULL) { monitoredNode->pFunctSignalTimeout( monitoredNode->nodeId, i, @@ -402,7 +402,7 @@ void CO_HBconsumer_process( if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { allMonitoredOperationalCurrent = CO_NMT_UNKNOWN; } -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE /* Verify, if NMT state of monitored node changed */ if(monitoredNode->NMTstate != monitoredNode->NMTstatePrev) { if (HBcons->pFunctSignalNmtChanged != NULL) { @@ -420,7 +420,7 @@ void CO_HBconsumer_process( /* (pre)operational state changed, clear variables */ for(i=0; inumberOfMonitoredNodes; i++) { monitoredNode->NMTstate = CO_NMT_UNKNOWN; -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -446,7 +446,7 @@ void CO_HBconsumer_process( } -#if CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_QUERY_FUNCT +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT /******************************************************************************/ int8_t CO_HBconsumer_getIdxByNodeId( CO_HBconsumer_t *HBcons, @@ -508,4 +508,4 @@ int8_t CO_HBconsumer_getNmtState( } return -1; } -#endif /* CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_QUERY_FUNCT */ +#endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT */ diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 21b1a475..3c57d03f 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -77,17 +77,17 @@ typedef struct { uint32_t time_us; /** Indication if new Heartbeat message received from the CAN bus */ volatile void *CANrxNew; -#if (CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_HBconsumer_initCallbackPre() or NULL */ - void (*pFunctSignalCanRx)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_HBconsumer_initCallbackPre() or NULL */ - void *functSignalObjectCanRx; + void *functSignalObjectPre; #endif -#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) || defined CO_DOXYGEN /** Previous value of the remote node (Heartbeat payload) */ CO_NMT_internalState_t NMTstatePrev; #endif -#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) || defined CO_DOXYGEN /** Callback for heartbeat state change to active event. * From CO_HBconsumer_initCallbackHeartbeatStarted() or NULL. */ void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void *object); @@ -127,7 +127,7 @@ typedef struct{ bool_t NMTisPreOrOperationalPrev; /**< previous state of var */ CO_CANmodule_t *CANdevRx; /**< From CO_HBconsumer_init() */ uint16_t CANdevRxIdxStart; /**< From CO_HBconsumer_init() */ -#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) || defined CO_DOXYGEN /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ void (*pFunctSignalNmtChanged)(uint8_t nodeId, @@ -188,7 +188,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( uint8_t nodeId, uint16_t consumerTime_ms); -#if (CO_CONFIG_HB_CONS & CO_CONFIG_FLAG_CANRX_CALLBACK) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer callback function. * @@ -206,7 +206,7 @@ void CO_HBconsumer_initCallbackPre( void (*pFunctSignal)(void *object)); #endif -#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_CHANGE_CALLBACK) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer NMT changed callback function. * @@ -226,7 +226,7 @@ void CO_HBconsumer_initCallbackNmtChanged( void *object)); #endif -#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer started callback function. * @@ -281,7 +281,7 @@ void CO_HBconsumer_initCallbackRemoteReset( uint8_t idx, void *object, void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); -#endif /* CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_MULTI_CALLBACK */ +#endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI */ /** * Process Heartbeat consumer object. @@ -300,7 +300,7 @@ void CO_HBconsumer_process( uint32_t *timerNext_us); -#if (CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_QUERY_FUNCT) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT) || defined CO_DOXYGEN /** * Get the heartbeat producer object index by node ID * @@ -338,7 +338,7 @@ int8_t CO_HBconsumer_getNmtState( CO_HBconsumer_t *HBcons, uint8_t idx, CO_NMT_internalState_t *nmtState); -#endif /* CO_CONFIG_HB_CONS & CO_CONFIG_HB_CONS_QUERY_FUNCT */ +#endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT */ #ifdef __cplusplus } diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index b52590a5..33109ec7 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -48,7 +48,9 @@ static void CO_NMT_receive(void *object, void *msg){ if((DLC == 2) && ((nodeId == 0) || (nodeId == NMT->nodeId))){ uint8_t command = data[0]; +#if (CO_CONFIG_NMT) & (CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_FLAG_CALLBACK_PRE) CO_NMT_internalState_t currentOperatingState = NMT->operatingState; +#endif switch(command){ case CO_NMT_ENTER_OPERATIONAL: @@ -72,9 +74,17 @@ static void CO_NMT_receive(void *object, void *msg){ break; } +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE if(NMT->pFunctNMT!=NULL && currentOperatingState!=NMT->operatingState){ NMT->pFunctNMT(NMT->operatingState); } +#endif +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles NMT. */ + if(NMT->pFunctSignalPre != NULL && currentOperatingState!=NMT->operatingState) { + NMT->pFunctSignalPre(NMT->functSignalObjectPre); + } +#endif } } @@ -96,15 +106,18 @@ CO_ReturnError_t CO_NMT_init( uint16_t CANidTxHB) { /* verify arguments */ - if (NMT == NULL || emPr == NULL || NMT_CANdevRx == NULL || - NMT_CANdevTx == NULL || HB_CANdevTx == NULL) { + if (NMT == NULL || emPr == NULL || NMT_CANdevRx == NULL || HB_CANdevTx == NULL +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER + || NMT_CANdevTx == NULL +#endif + ) { return CO_ERROR_ILLEGAL_ARGUMENT; } CO_ReturnError_t ret = CO_ERROR_NO; /* blinking bytes and LEDS */ -#if CO_CONFIG_NMT & CO_CONFIG_NMT_LEDS +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_LEDS NMT->LEDtimer = 0; NMT->LEDflickering = 0; NMT->LEDblinking = 0; @@ -123,7 +136,13 @@ CO_ReturnError_t CO_NMT_init( NMT->resetCommand = 0; NMT->HBproducerTimer = 0; NMT->emPr = emPr; +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE + NMT->pFunctSignalPre = NULL; + NMT->functSignalObjectPre = NULL; +#endif +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE NMT->pFunctNMT = NULL; +#endif /* configure NMT CAN reception */ ret = CO_CANrxBufferInit( @@ -135,6 +154,7 @@ CO_ReturnError_t CO_NMT_init( (void*)NMT, /* object passed to receive function */ CO_NMT_receive); /* this function will process received message */ +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER /* configure NMT CAN transmission */ NMT->NMT_CANdevTx = NMT_CANdevTx; NMT->NMT_TXbuff = CO_CANtxBufferInit( @@ -144,6 +164,10 @@ CO_ReturnError_t CO_NMT_init( 0, /* rtr */ 2, /* number of data bytes */ 0); /* synchronous message flag bit */ + if (NMT->NMT_TXbuff == NULL) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } +#endif /* configure HB CAN transmission */ NMT->HB_CANdevTx = HB_CANdevTx; @@ -155,7 +179,7 @@ CO_ReturnError_t CO_NMT_init( 1, /* number of data bytes */ 0); /* synchronous message flag bit */ - if (NMT->NMT_TXbuff == NULL || NMT->HB_TXbuff == NULL) { + if (NMT->HB_TXbuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; } @@ -163,8 +187,23 @@ CO_ReturnError_t CO_NMT_init( } +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE +void CO_NMT_initCallbackPre( + CO_NMT_t *NMT, + void *object, + void (*pFunctSignal)(void *object)) +{ + if (NMT != NULL) { + NMT->pFunctSignalPre = pFunctSignal; + NMT->functSignalObjectPre = object; + } +} +#endif + + +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE /******************************************************************************/ -void CO_NMT_initCallbackChange( +void CO_NMT_initCallbackChanged( CO_NMT_t *NMT, void (*pFunctNMT)(CO_NMT_internalState_t state)) { @@ -175,6 +214,7 @@ void CO_NMT_initCallbackChange( } } } +#endif /******************************************************************************/ @@ -223,7 +263,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( CANpassive = 1; -#if CO_CONFIG_NMT & CO_CONFIG_NMT_LEDS +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_LEDS NMT->LEDtimer += timeDifference_us; if (NMT->LEDtimer >= 50000) { NMT->LEDtimer -= 50000; @@ -350,9 +390,11 @@ CO_NMT_reset_cmd_t CO_NMT_process( } if (currentOperatingState != NMT->operatingState) { +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE if (NMT->pFunctNMT != NULL) { NMT->pFunctNMT(NMT->operatingState); } +#endif /* execute next CANopen processing immediately */ if (timerNext_us != NULL) { *timerNext_us = 0; @@ -386,6 +428,7 @@ CO_NMT_internalState_t CO_NMT_getInternalState( } +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER /******************************************************************************/ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, CO_NMT_command_t command, @@ -433,3 +476,4 @@ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, return error; } +#endif diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 9ca84fc3..0666543b 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -130,7 +130,7 @@ typedef enum{ * @ref CO_NMT_statusLEDdiodes. Object is initialized by CO_NMT_init(). */ typedef struct{ -#if (CO_CONFIG_NMT & CO_CONFIG_NMT_LEDS) || defined CO_DOXYGEN +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_LEDS) || defined CO_DOXYGEN uint32_t LEDtimer; /**< 50ms led timer */ int8_t LEDflickering; /**< See @ref CO_NMT_statusLEDdiodes */ int8_t LEDblinking; /**< See @ref CO_NMT_statusLEDdiodes */ @@ -148,11 +148,21 @@ typedef struct{ uint32_t HBproducerTimer;/**< Internal timer for HB producer */ uint32_t firstHBTime; /**< From CO_NMT_init() */ CO_EMpr_t *emPr; /**< From CO_NMT_init() */ +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN CO_CANmodule_t *NMT_CANdevTx; /**< From CO_NMT_init() */ CO_CANtx_t *NMT_TXbuff; /**< CAN transmit buffer for NMT master message */ +#endif CO_CANmodule_t *HB_CANdevTx; /**< From CO_NMT_init() */ CO_CANtx_t *HB_TXbuff; /**< CAN transmit buffer for heartbeat message */ - void (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallbackChange() or NULL */ +#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN + /** From CO_NMT_initCallbackPre() or NULL */ + void (*pFunctSignalPre)(void *object); + /** From CO_NMT_initCallbackPre() or NULL */ + void *functSignalObjectPre; +#endif +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) || defined CO_DOXYGEN + void (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallbackChanged() or NULL */ +#endif }CO_NMT_t; @@ -194,6 +204,27 @@ CO_ReturnError_t CO_NMT_init( uint16_t HB_txIdx, uint16_t CANidTxHB); + +#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +/** + * Initialize NMT callback function after message preprocessed. + * + * Function initializes optional callback function, which should immediately + * start processing of CO_NMT_process() function. + * Callback is called after NMT message is received from the CAN bus. + * + * @param NMT This object. + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL + * @param pFunctSignal Pointer to the callback function. Not called if NULL. + */ +void CO_NMT_initCallbackPre( + CO_NMT_t *NMT, + void *object, + void (*pFunctSignal)(void *object)); +#endif + + +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) || defined CO_DOXYGEN /** * Initialize NMT callback function. * @@ -208,9 +239,10 @@ CO_ReturnError_t CO_NMT_init( * @param NMT This object. * @param pFunctNMT Pointer to the callback function. Not called if NULL. */ -void CO_NMT_initCallbackChange( +void CO_NMT_initCallbackChanged( CO_NMT_t *NMT, void (*pFunctNMT)(CO_NMT_internalState_t state)); +#endif /** @@ -251,6 +283,7 @@ CO_NMT_internalState_t CO_NMT_getInternalState( CO_NMT_t *NMT); +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN /** * Send NMT master command. * @@ -269,6 +302,7 @@ CO_NMT_internalState_t CO_NMT_getInternalState( CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, CO_NMT_command_t command, uint8_t nodeID); +#endif /** @} */ diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 85363931..ff65ae6a 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -160,10 +160,12 @@ static void CO_SDOclient_receive(void *object, void *msg){ } } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles SDO client. */ if(CO_FLAG_READ(SDO_C->CANrxNew) && SDO_C->pFunctSignal != NULL) { SDO_C->pFunctSignal(SDO_C->functSignalObject); } +#endif } } @@ -194,8 +196,10 @@ CO_ReturnError_t CO_SDOclient_init( SDO_C->SDO = SDO; SDO_C->SDOClientPar = SDOClientPar; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE SDO_C->pFunctSignal = NULL; SDO_C->functSignalObject = NULL; +#endif SDO_C->CANdevRx = CANdevRx; SDO_C->CANdevRxIdx = CANdevRxIdx; @@ -212,6 +216,7 @@ CO_ReturnError_t CO_SDOclient_init( } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ void CO_SDOclient_initCallbackPre( CO_SDOclient_t *SDOclient, @@ -223,6 +228,7 @@ void CO_SDOclient_initCallbackPre( SDOclient->pFunctSignal = pFunctSignal; } } +#endif /******************************************************************************/ diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 3522ee4b..79dc5f58 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -136,10 +136,12 @@ typedef struct{ volatile void *CANrxNew; /** 8 data bytes of the received message */ uint8_t CANrxData[8]; +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_SDOclient_initCallbackPre() or NULL */ void (*pFunctSignal)(void *object); /** From CO_SDOclient_initCallbackPre() or NULL */ void *functSignalObject; +#endif /** From CO_SDOclient_init() */ CO_CANmodule_t *CANdevTx; /** CAN transmit buffer inside CANdevTx for CAN tx message */ @@ -198,6 +200,7 @@ CO_ReturnError_t CO_SDOclient_init( uint16_t CANdevTxIdx); +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** * Initialize SDOclient callback function. * @@ -216,6 +219,7 @@ void CO_SDOclient_initCallbackPre( CO_SDOclient_t *SDOclient, void *object, void (*pFunctSignal)(void *object)); +#endif /** diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index bde3fb36..d556d199 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -42,6 +42,9 @@ #if CO_CONFIG_SDO_BUFFER_SIZE < 7 #error CO_CONFIG_SDO_BUFFER_SIZE must be greater than 7 #endif +#if ((CO_CONFIG_SDO) & CO_CONFIG_SDO_BLOCK) && !((CO_CONFIG_SDO) & CO_CONFIG_SDO_SEGMENTED) + #error CO_CONFIG_SDO_BLOCK is enabled, CO_CONFIG_SDO_SEGMENTED must be enabled also. +#endif /* Helper functions. **********************************************************/ @@ -238,10 +241,12 @@ static void CO_SDO_receive(void *object, void *msg){ } } +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles SDO server. */ - if(CO_FLAG_READ(SDO->CANrxNew) && SDO->pFunctSignal != NULL) { - SDO->pFunctSignal(SDO->functSignalObject); + if(CO_FLAG_READ(SDO->CANrxNew) && SDO->pFunctSignalPre != NULL) { + SDO->pFunctSignalPre(SDO->functSignalObjectPre); } +#endif } } @@ -323,9 +328,10 @@ CO_ReturnError_t CO_SDO_init( SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; SDO->state = CO_SDO_ST_IDLE; CO_FLAG_CLEAR(SDO->CANrxNew); - SDO->pFunctSignal = NULL; - SDO->functSignalObject = NULL; - +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE + SDO->pFunctSignalPre = NULL; + SDO->functSignalObjectPre = NULL; +#endif /* Configure Object dictionary entry at index 0x1200 */ if(ObjDictIndex_SDOServerParameter == OD_H1200_SDO_SERVER_PARAM){ @@ -365,17 +371,19 @@ CO_ReturnError_t CO_SDO_init( } +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ void CO_SDO_initCallbackPre( CO_SDO_t *SDO, void *object, - void (*pFunctSignal)(void *object)) + void (*pFunctSignalPre)(void *object)) { if(SDO != NULL){ - SDO->functSignalObject = object; - SDO->pFunctSignal = pFunctSignal; + SDO->functSignalObjectPre = object; + SDO->pFunctSignalPre = pFunctSignalPre; } } +#endif /******************************************************************************/ diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 26bdb1e9..0e3abf87 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -613,10 +613,12 @@ typedef struct{ bool_t endOfTransfer; /** Variable indicates, if new SDO message received from CAN bus */ volatile void *CANrxNew; +#if ((CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_SDO_initCallbackPre() or NULL */ - void (*pFunctSignal)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_SDO_initCallbackPre() or NULL */ - void *functSignalObject; + void *functSignalObjectPre; +#endif /** From CO_SDO_init() */ CO_CANmodule_t *CANdevTx; /** CAN transmit buffer inside CANdev for CAN tx message */ @@ -766,6 +768,7 @@ CO_ReturnError_t CO_SDO_init( uint16_t CANdevTxIdx); +#if ((CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** * Initialize SDOrx callback function. * @@ -775,13 +778,14 @@ CO_ReturnError_t CO_SDO_init( * when new call without delay is necessary (SDO block transfer is in progress). * * @param SDO This object. - * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL - * @param pFunctSignal Pointer to the callback function. Not called if NULL. + * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ void CO_SDO_initCallbackPre( CO_SDO_t *SDO, void *object, - void (*pFunctSignal)(void *object)); + void (*pFunctSignalPre)(void *object)); +#endif /** diff --git a/301/CO_config.h b/301/CO_config.h index 0aac444c..98682d11 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -70,31 +70,91 @@ extern "C" { * * This flag is common to multiple configuration macros. */ -#define CO_CONFIG_FLAG_CANRX_CALLBACK 0x0100 +#define CO_CONFIG_FLAG_CALLBACK_PRE 0x0100 /** - * Configuration of NMT + * Configuration of NMT_Heartbeat object * * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received NMT CAN message. + * Callback is configured by CO_NMT_initCallbackPre(). + * - CO_CONFIG_NMT_CALLBACK_CHANGE - Enable custom callback after NMT + * state changes. Callback is configured by + * CO_NMT_initCallbackChanged(). + * - CO_CONFIG_NMT_MASTER - Enable simple NMT master * - CO_CONFIG_NMT_LEDS - Calculate CANopen blinking variables, which can - * be used for LEDs. + * be used for LEDs. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_NMT CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS #endif -#define CO_CONFIG_NMT_LEDS 0x01 +#define CO_CONFIG_NMT_CALLBACK_CHANGE 0x01 +#define CO_CONFIG_NMT_MASTER 0x02 +#define CO_CONFIG_NMT_LEDS 0x04 + + +/** + * Configuration of SDO server object + * + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received SDO CAN message. + * Callback is configured by CO_SDO_initCallbackPre(). + * - CO_CONFIG_SDO_SEGMENTED - Enable SDO server segmented transfer. + * - CO_CONFIG_SDO_BLOCK - Enable SDO server block transfer. If set, then + * CO_CONFIG_SDO_SEGMENTED must also be set. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK +#endif +/* TODO with new OD */ +#define CO_CONFIG_SDO_SEGMENTED 0x01 +#define CO_CONFIG_SDO_BLOCK 0x02 + + +/** + * Size of the internal SDO buffer. + * + * Size must be at least equal to size of largest variable in + * @ref CO_SDO_objectDictionary. If data type is domain, data length is not + * limited to SDO buffer size. If block transfer is implemented, value should be + * set to 889. + * + * Value can be in range from 7 to 889 bytes. + */ +#ifndef CO_CONFIG_SDO_BUFFER_SIZE +#define CO_CONFIG_SDO_BUFFER_SIZE 32 +#endif + + +/** + * Configuration of Emergency object + * + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * emergency condition by CO_errorReport() or CO_errorReset() call. + * Callback is configured by CO_EM_initCallbackPre(). + * - CO_CONFIG_EM_CONSUMER - Enable emergency consumer. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_EM_CONSUMER +#endif +#define CO_CONFIG_EM_CONSUMER 0x01 + /** * Configuration of Heartbeat Consumer * * Possible flags, can be ORed: - * - #CO_CONFIG_FLAG_CANRX_CALLBACK - Enable custom callback after CAN receive. + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received heartbeat CAN message. * Callback is configured by CO_HBconsumer_initCallbackPre(). - * - CO_CONFIG_HB_CONS_CHANGE_CALLBACK - Enable custom callback after NMT + * - CO_CONFIG_HB_CONS_CALLBACK_CHANGE - Enable custom callback after NMT * state of the monitored node changes. Callback is configured by * CO_HBconsumer_initCallbackNmtChanged(). - * - CO_CONFIG_HB_CONS_MULTI_CALLBACK - Enable multiple custom callbacks, which + * - CO_CONFIG_HB_CONS_CALLBACK_MULTI - Enable multiple custom callbacks, which * can be configured for each monitored node. Callback are configured by * CO_HBconsumer_initCallbackHeartbeatStarted(), * CO_HBconsumer_initCallbackTimeout() and @@ -103,27 +163,39 @@ extern "C" { * NMT state of the specific monitored node. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CANRX_CALLBACK | CO_CONFIG_HB_CONS_CHANGE_CALLBACK | CO_CONFIG_HB_CONS_MULTI_CALLBACK | CO_CONFIG_HB_CONS_QUERY_FUNCT +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT #endif -#define CO_CONFIG_HB_CONS_CHANGE_CALLBACK 0x01 -#define CO_CONFIG_HB_CONS_MULTI_CALLBACK 0x02 +#define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x01 +#define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x02 #define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x04 /** - * Size of the internal SDO buffer. + * Configuration of SDO client object * - * Size must be at least equal to size of largest variable in - * @ref CO_SDO_objectDictionary. If data type is domain, data length is not - * limited to SDO buffer size. If block transfer is implemented, value should be - * set to 889. + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received SDO CAN message. + * Callback is configured by CO_SDOclient_initCallbackPre(). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE +#endif + + +/** + * Configuration of LSS master object * - * Value can be in range from 7 to 889 bytes. + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received SDO CAN message. + * Callback is configured by CO_LSSmaster_initCallbackPre(). */ -#ifndef CO_CONFIG_SDO_BUFFER_SIZE -#define CO_CONFIG_SDO_BUFFER_SIZE 32 +#ifdef CO_DOXYGEN +#define CO_CONFIG_LSS_MST CO_CONFIG_FLAG_CALLBACK_PRE #endif + /** * Configuration of Standard CiA 309 usage. * diff --git a/301/CO_driver.h b/301/CO_driver.h index b7dca97d..9cc998a4 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -35,20 +35,36 @@ extern "C" { #endif -/* Default stack configuration for most common configuration. - * For more information see file CO_config.h. */ +/* Default stack configuration for most common configuration, may be overridden + * by CO_driver_target.h. For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT #define CO_CONFIG_NMT 0 #endif +#ifndef CO_CONFIG_SDO +#define CO_CONFIG_SDO CO_CONFIG_SDO_SEGMENTED +#endif + #ifndef CO_CONFIG_SDO_BUFFER_SIZE #define CO_CONFIG_SDO_BUFFER_SIZE 32 #endif +#ifndef CO_CONFIG_EM +#define CO_CONFIG_EM 0 +#endif + #ifndef CO_CONFIG_HB_CONS #define CO_CONFIG_HB_CONS 0 #endif +#ifndef CO_CONFIG_SDO_CLI +#define CO_CONFIG_SDO_CLI 0 +#endif + +#ifndef CO_CONFIG_LSS_MST +#define CO_CONFIG_LSS_MST 0 +#endif + #ifndef CO_CONFIG_309 #define CO_CONFIG_309 0 #endif diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 0ecf3392..f48f20e5 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -96,10 +96,12 @@ static void CO_LSSmaster_receive(void *object, void *msg) CO_FLAG_SET(LSSmaster->CANrxNew); +#if (CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles further processing. */ if(LSSmaster->pFunctSignal != NULL) { LSSmaster->pFunctSignal(LSSmaster->functSignalObject); } +#endif } } @@ -150,8 +152,10 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); CO_memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); +#if (CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE LSSmaster->pFunctSignal = NULL; LSSmaster->functSignalObject = NULL; +#endif /* configure LSS CAN Slave response message reception */ ret = CO_CANrxBufferInit( @@ -192,6 +196,7 @@ void CO_LSSmaster_changeTimeout( } +#if (CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ void CO_LSSmaster_initCallbackPre( CO_LSSmaster_t *LSSmaster, @@ -203,6 +208,8 @@ void CO_LSSmaster_initCallbackPre( LSSmaster->pFunctSignal = pFunctSignal; } } +#endif + /* * Helper function - initiate switch state diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 16793feb..2d2066b3 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -118,11 +118,11 @@ typedef struct{ volatile void *CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */ uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ - +#if ((CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN void (*pFunctSignal)(void *object); /**< From CO_LSSmaster_initCallbackPre() or NULL */ void *functSignalObject;/**< Pointer to object */ - - CO_CANmodule_t *CANdevTx; /**< From #CO_LSSslave_init() */ +#endif + CO_CANmodule_t *CANdevTx; /**< From CO_LSSmaster_init() */ CO_CANtx_t *TXbuff; /**< CAN transmit buffer */ }CO_LSSmaster_t; @@ -184,6 +184,7 @@ void CO_LSSmaster_changeTimeout( uint16_t timeout_ms); +#if ((CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** * Initialize LSSmasterRx callback function. * @@ -200,6 +201,7 @@ void CO_LSSmaster_initCallbackPre( CO_LSSmaster_t *LSSmaster, void *object, void (*pFunctSignal)(void *object)); +#endif /** diff --git a/CANopen.c b/CANopen.c index b9281b9f..dbd823d7 100644 --- a/CANopen.c +++ b/CANopen.c @@ -68,7 +68,7 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #define CO_RXCAN_NMT 0 #define CO_RXCAN_SYNC (CO_RXCAN_NMT + CO_NO_NMT) #define CO_RXCAN_EMERG (CO_RXCAN_SYNC + CO_NO_SYNC) -#define CO_RXCAN_TIME (CO_RXCAN_EMERG + CO_NO_EMERGENCY) +#define CO_RXCAN_TIME (CO_RXCAN_EMERG + CO_NO_EM_CONS) #define CO_RXCAN_RPDO (CO_RXCAN_TIME + CO_NO_TIME) #define CO_RXCAN_SDO_SRV (CO_RXCAN_RPDO + CO_NO_RPDO) #define CO_RXCAN_SDO_CLI (CO_RXCAN_SDO_SRV + CO_NO_SDO_SERVER) @@ -76,7 +76,7 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #define CO_RXCAN_LSS (CO_RXCAN_CONS_HB + CO_NO_HB_CONS) #define CO_RXCAN_NO_MSGS (CO_NO_NMT + \ CO_NO_SYNC + \ - CO_NO_EMERGENCY + \ + CO_NO_EM_CONS + \ CO_NO_TIME + \ CO_NO_RPDO + \ CO_NO_SDO_SERVER + \ @@ -87,7 +87,7 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; /* Indexes of CO_CANtx_t objects in CO_CANmodule_t and total number of them. **/ #define CO_TXCAN_NMT 0 -#define CO_TXCAN_SYNC (CO_TXCAN_NMT + CO_NO_NMT) +#define CO_TXCAN_SYNC (CO_TXCAN_NMT + CO_NO_NMT_MST) #define CO_TXCAN_EMERG (CO_TXCAN_SYNC + CO_NO_SYNC) #define CO_TXCAN_TIME (CO_TXCAN_EMERG + CO_NO_EMERGENCY) #define CO_TXCAN_TPDO (CO_TXCAN_TIME + CO_NO_TIME) @@ -95,7 +95,7 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #define CO_TXCAN_SDO_CLI (CO_TXCAN_SDO_SRV + CO_NO_SDO_SERVER) #define CO_TXCAN_HB (CO_TXCAN_SDO_CLI + CO_NO_SDO_CLIENT) #define CO_TXCAN_LSS (CO_TXCAN_HB + CO_NO_HB_PROD) -#define CO_TXCAN_NO_MSGS (CO_NO_NMT + \ +#define CO_TXCAN_NO_MSGS (CO_NO_NMT_MST + \ CO_NO_SYNC + \ CO_NO_EMERGENCY + \ CO_NO_TIME + \ @@ -656,7 +656,6 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, OD_inhibitTimeEMCY, timerNext_us); - /* NMT_Heartbeat */ reset = CO_NMT_process(co->NMT, timeDifference_us, @@ -666,7 +665,6 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, OD_errorBehavior, timerNext_us); - #if CO_NO_TIME == 1 /* TIME */ CO_TIME_process(co->TIME, diff --git a/CANopen.h b/CANopen.h index efd14472..c141b93d 100644 --- a/CANopen.h +++ b/CANopen.h @@ -137,13 +137,18 @@ extern "C" { * @{ */ /* Definitions valid only for documentation. */ -/** Number of NMT objects, fixed to 1 (slave(CANrx) + master(CANtx)) */ +/** Number of NMT objects, fixed to 1 slave(CANrx) */ #define CO_NO_NMT (1) +/** Number of NMT master objects, 0 or 1 master(CANtx). It depends on + * @ref CO_CONFIG_EM setting. */ +#define CO_NO_NMT_MST (0...1) /** Number of SYNC objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ #define CO_NO_SYNC (0...1) -/** Number of Emergency objects, fixed to 1 (consumer(CANrx) + - * producer(CANtx)) */ +/** Number of Emergency producer objects, fixed to 1 producer(CANtx) */ #define CO_NO_EMERGENCY (1) +/** Number of Emergency consumer objects, 0 or 1 consumer(CANrx). It depends on + * @ref CO_CONFIG_EM setting. */ +#define CO_NO_EM_CONS (0...1) /** Number of Time-stamp objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ #define CO_NO_TIME (0...1) /** Number of RPDO objects, 1 to 512 consumers (CANrx) */ @@ -165,11 +170,31 @@ extern "C" { /** Number of Trace objects, 0 to many */ #define CO_NO_TRACE (0...) /** @} */ + #else /* CO_DOXYGEN */ /* Valid Definitions for program. */ -#define CO_NO_NMT 1 /* NMT master/slave count (fixed) */ -#define CO_NO_HB_PROD 1 /* Heartbeat producer count (fixed) */ +/* NMT slave count (fixed) */ +#define CO_NO_NMT 1 + +/* NMT master count depends on stack configuration */ +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER +#define CO_NO_NMT_MST 1 +#else +#define CO_NO_NMT_MST 0 +#endif + +/* Emergency consumer depends on stack configuration */ +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +#define CO_NO_EM_CONS 1 +#else +#define CO_NO_EM_CONS 0 +#endif + +/* Heartbeat producer count (fixed) */ +#define CO_NO_HB_PROD 1 + +/* Heartbeat consumer count depends on Object Dictionary configuration */ #ifdef ODL_consumerHeartbeatTime_arrayLength #define CO_NO_HB_CONS ODL_consumerHeartbeatTime_arrayLength #else @@ -297,7 +322,7 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); * used in combination with callbacks configured with * CO_***_initCallbackPre() functions. Those callbacks should also * trigger calling of CO_process() function. - * See also @ref CO_CONFIG_FLAG_CANRX_CALLBACK configuration macro. + * See also @ref CO_CONFIG_FLAG_CALLBACK_PRE configuration macro. * * This is experimental feature and can be used for energy saving in case * of low traffic on CAN bus. Parameter is ignored if NULL. diff --git a/Doxyfile b/Doxyfile index 37c12f21..993bc354 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2052,11 +2052,11 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = CO_DOXYGEN \ +PREDEFINED = CO_DOXYGEN=1 \ CO_NO_SYNC=1 \ CO_NO_SDO_CLIENT=1 \ CO_NO_NMT_MASTER=1 \ - CO_NO_LSS_SERVER \ + CO_NO_LSS_SERVER=1 \ CO_NO_LSS_CLIENT=1 \ CO_NO_TRACE=1 diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 9b08fbf1..a043ef2c 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -34,7 +34,7 @@ #include #include -#if __has_include("CO_driver_custom.h") +#ifdef CO_DRIVER_CUSTOM #include "CO_driver_custom.h" #endif @@ -42,9 +42,34 @@ extern "C" { #endif -/* Stack configuration override */ +/* Stack configuration override from CO_driver.h. Compile full stack. + * For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS +#endif + +#ifndef CO_CONFIG_SDO +#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK +#endif + +#ifndef CO_CONFIG_SDO_BUFFER_SIZE +#define CO_CONFIG_SDO_BUFFER_SIZE 889 +#endif + +#ifndef CO_CONFIG_EM +#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_EM_CONSUMER +#endif + +#ifndef CO_CONFIG_HB_CONS +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT +#endif + +#ifndef CO_CONFIG_SDO_CLI +#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE +#endif + +#ifndef CO_CONFIG_LSS_MST +#define CO_CONFIG_LSS_MST CO_CONFIG_FLAG_CALLBACK_PRE #endif diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index eb8f1932..cee5b056 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -56,6 +56,7 @@ void threadMain_init(void (*callback)(void*), void *object) { threadMain.start = CO_LinuxThreads_clock_gettime_us(); + CO_NMT_initCallbackPre(CO->NMT, object, callback); CO_SDO_initCallbackPre(CO->SDO[0], object, callback); CO_EM_initCallbackPre(CO->em, object, callback); CO_HBconsumer_initCallbackPre(CO->HBcons, object, callback); @@ -63,6 +64,7 @@ void threadMain_init(void (*callback)(void*), void *object) void threadMain_close(void) { + CO_NMT_initCallbackPre(CO->NMT, NULL, NULL); CO_SDO_initCallbackPre(CO->SDO[0], NULL, NULL); CO_EM_initCallbackPre(CO->em, NULL, NULL); CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, NULL); @@ -110,18 +112,22 @@ static void threadMainWait_callback(void *object) } } -void threadMainWait_init(uint32_t interval_us) +void threadMainWait_init(void) { - int32_t ret; - struct epoll_event ev; - /* Configure callback functions */ + CO_NMT_initCallbackPre(CO->NMT, NULL, threadMainWait_callback); CO_SDO_initCallbackPre(CO->SDO[0], NULL, threadMainWait_callback); CO_EM_initCallbackPre(CO->em, NULL, threadMainWait_callback); CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, threadMainWait_callback); /* Initial value for time calculation */ threadMainWait.start = CO_LinuxThreads_clock_gettime_us(); +} + +void threadMainWait_initOnce(uint32_t interval_us) +{ + int32_t ret; + struct epoll_event ev; /* Configure epoll for mainline */ threadMainWait.epoll_fd = epoll_create(1); @@ -171,6 +177,7 @@ void threadMainWait_init(uint32_t interval_us) void threadMainWait_close(void) { + CO_NMT_initCallbackPre(CO->NMT, NULL, NULL); CO_SDO_initCallbackPre(CO->SDO[0], NULL, NULL); CO_EM_initCallbackPre(CO->em, NULL, NULL); CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, NULL); diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index e1e27951..0bd535f9 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -93,9 +93,20 @@ void threadMain_process(CO_NMT_reset_cmd_t *reset); /** * Initialize mainline thread - blocking. * + * Function must be called always in communication reset section, after + * CO_CANopenInit(). + */ +void threadMainWait_init(void); + + +/** + * Initialize once mainline thread - blocking. + * + * Function must be called only once, before node starts operating. + * * @param interval_us interval of the threadMainWait_process() */ -void threadMainWait_init(uint32_t interval_us); +void threadMainWait_initOnce(uint32_t interval_us); /** diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 26b5b09f..a817259f 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -52,13 +52,34 @@ extern "C" { /* Stack configuration override from CO_driver.h. * For more information see file CO_config.h. */ -#ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CANRX_CALLBACK | CO_CONFIG_HB_CONS_CHANGE_CALLBACK +#ifndef CO_CONFIG_NMT +#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS +#endif + +#ifndef CO_CONFIG_SDO +#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK #endif + #ifndef CO_CONFIG_SDO_BUFFER_SIZE #define CO_CONFIG_SDO_BUFFER_SIZE 889 #endif +#ifndef CO_CONFIG_EM +#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_EM_CONSUMER +#endif + +#ifndef CO_CONFIG_HB_CONS +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#endif + +#ifndef CO_CONFIG_SDO_CLI +#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE +#endif + +#ifndef CO_CONFIG_LSS_MST +#define CO_CONFIG_LSS_MST CO_CONFIG_FLAG_CALLBACK_PRE +#endif + /** * @defgroup CO_socketCAN_driver_target CO_driver_target.h diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 88c785be..94c92825 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -123,7 +123,7 @@ static char *NmtState2Str(CO_NMT_internalState_t state) } /* callback for NMT change messages */ -static void NmtChangeCallback(CO_NMT_internalState_t state) +static void NmtChangedCallback(CO_NMT_internalState_t state) { log_printf(LOG_NOTICE, DBG_NMT_CHANGE, NmtState2Str(state), state); } @@ -346,9 +346,10 @@ int main (int argc, char *argv[]) { exit(EXIT_FAILURE); } - /* initialize callbacks */ + /* initialize part of threadMain and callbacks */ + threadMainWait_init(); CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); - CO_NMT_initCallbackChange(CO->NMT, NmtChangeCallback); + CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, HeartbeatNmtChangedCallback); @@ -375,7 +376,7 @@ int main (int argc, char *argv[]) { /* Init threadMainWait structure and file descriptors */ - threadMainWait_init(MAIN_THREAD_INTERVAL_US); + threadMainWait_initOnce(MAIN_THREAD_INTERVAL_US); /* Init threadRT structure and file descriptors */ From 3fd799f919bb9dbc94fe646ace4860789095aee3 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 19 Mar 2020 18:58:58 +0100 Subject: [PATCH 051/520] Heartbeat is send immediately after NMT state changes. --- 301/CO_NMT_Heartbeat.c | 19 +++++++++++++------ 301/CO_NMT_Heartbeat.h | 1 + doc/CHANGELOG.md | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 33109ec7..4fc8730b 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -131,6 +131,7 @@ CO_ReturnError_t CO_NMT_init( /* Configure object variables */ NMT->operatingState = CO_NMT_INITIALIZING; + NMT->operatingStatePrev = CO_NMT_INITIALIZING; NMT->nodeId = nodeId; NMT->firstHBTime = (int32_t)firstHBTime_ms * 1000; NMT->resetCommand = 0; @@ -234,11 +235,17 @@ CO_NMT_reset_cmd_t CO_NMT_process( NMT->HBproducerTimer += timeDifference_us; - /* Heartbeat producer message & Bootup message */ - if ((HBtime != 0 && NMT->HBproducerTimer >= HBtime) || NMT->operatingState == CO_NMT_INITIALIZING) { - - /* Start from the beginning. If OS is slow, time sliding may occur. However, heartbeat is - * not for synchronization, it is for health report. */ + /* Send heartbeat producer message if: + * - First start, send bootup message or + * - HB producer and Timer expired or + * - HB producer and NMT->operatingState changed, but not from initialised */ + if ((NMT->operatingState == CO_NMT_INITIALIZING) || + (HBtime != 0 && (NMT->HBproducerTimer >= HBtime || + NMT->operatingState != NMT->operatingStatePrev) + )) + { + /* Start from the beginning. If OS is slow, time sliding may occur. However, + * heartbeat is not for synchronization, it is for health report. */ NMT->HBproducerTimer = 0; NMT->HB_TXbuff->data[0] = (uint8_t) NMT->operatingState; @@ -255,7 +262,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( else NMT->operatingState = CO_NMT_PRE_OPERATIONAL; } } - + NMT->operatingStatePrev = NMT->operatingState; /* CAN passive flag */ CANpassive = 0; diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 0666543b..a94cda66 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -143,6 +143,7 @@ typedef struct{ #endif /* CO_CONFIG_NMT_LEDS */ CO_NMT_internalState_t operatingState; /**< Current NMT operating state. */ + CO_NMT_internalState_t operatingStatePrev; /**< Previous NMT operating state. */ uint8_t resetCommand; /**< If different than zero, device will reset */ uint8_t nodeId; /**< CANopen Node ID of this device */ uint32_t HBproducerTimer;/**< Internal timer for HB producer */ diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 2e6096ff..66cf0663 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -19,6 +19,7 @@ Change Log - It is necessary to manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and `301/CO_SDOserver.h`. - Added `void *object` argument to CO_*_initCallback() functions. API clarified. - Add emergency receive callback also for own emergency messages. +- Heartbeat is send immediately after NMT state changes. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN - driver API updated From 6e28914ca949e33887104ce50dadbe584dd6a807 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 20 Mar 2020 16:44:37 +0100 Subject: [PATCH 052/520] Make calculation of timerNext_us optional. --- 301/CO_Emergency.c | 4 ++- 301/CO_HBconsumer.c | 2 ++ 301/CO_NMT_Heartbeat.c | 6 ++++ 301/CO_PDO.c | 2 ++ 301/CO_SDOclient.c | 12 ++++++++ 301/CO_SDOserver.c | 16 +++++++++++ 301/CO_SYNC.c | 12 ++++---- 301/CO_config.h | 56 ++++++++++++++++++++++++++++++++---- 301/CO_driver.h | 8 ++++++ example/CO_driver_target.h | 18 ++++++++---- socketCAN/CO_driver_target.h | 18 ++++++++---- 11 files changed, 132 insertions(+), 22 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 3f2d6521..47d7d66b 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -308,7 +308,6 @@ void CO_EM_process( (em->bufReadPtr != em->bufWritePtr || em->bufFull)) { uint32_t preDEF; /* preDefinedErrorField */ - uint16_t diff; if (emPr->inhibitEmTimer >= emInhTime_us) { /* inhibit time elapsed, send message */ @@ -367,13 +366,16 @@ void CO_EM_process( CO_CANsend(emPr->CANdev, emPr->CANtxBuff); } +#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT else if (timerNext_us != NULL) { + uint32_t diff; /* check again after inhibit time elapsed */ diff = emInhTime_us - emPr->inhibitEmTimer; if (*timerNext_us > diff) { *timerNext_us = diff; } } +#endif } return; diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index e1dbefb7..67d9cff2 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -386,6 +386,7 @@ void CO_HBconsumer_process( monitoredNode->HBstate = CO_HBconsumer_TIMEOUT; } +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_TIMERNEXT else if (timerNext_us != NULL) { /* Calculate timerNext_us for next timeout checking. */ uint32_t diff = monitoredNode->time_us @@ -394,6 +395,7 @@ void CO_HBconsumer_process( *timerNext_us = diff; } } +#endif } if(monitoredNode->HBstate != CO_HBconsumer_ACTIVE) { diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 4fc8730b..8ce755c5 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -275,12 +275,14 @@ CO_NMT_reset_cmd_t CO_NMT_process( if (NMT->LEDtimer >= 50000) { NMT->LEDtimer -= 50000; +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL) { uint32_t diff = 50000 - NMT->LEDtimer; if (*timerNext_us > diff) { *timerNext_us = diff; } } +#endif if (++NMT->LEDflickering >= 1) NMT->LEDflickering = -1; @@ -402,12 +404,15 @@ CO_NMT_reset_cmd_t CO_NMT_process( NMT->pFunctNMT(NMT->operatingState); } #endif +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT /* execute next CANopen processing immediately */ if (timerNext_us != NULL) { *timerNext_us = 0; } +#endif } +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT /* Calculate, when next Heartbeat needs to be send and lower timerNext_us if necessary. */ if (HBtime != 0 && timerNext_us != NULL) { if (NMT->HBproducerTimer < HBtime) { @@ -419,6 +424,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( *timerNext_us = 0; } } +#endif return (CO_NMT_reset_cmd_t) NMT->resetCommand; } diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 48c18dd1..41dcaff2 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -991,6 +991,7 @@ void CO_TPDO_process( TPDO->eventTimer = ((uint32_t) TPDO->TPDOCommPar->eventTimer) * 1000; } } +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT if(timerNext_us != NULL){ if(TPDO->sendRequest && *timerNext_us > TPDO->inhibitTimer){ *timerNext_us = TPDO->inhibitTimer; /* Schedule for just beyond inhibit window */ @@ -998,6 +999,7 @@ void CO_TPDO_process( *timerNext_us = TPDO->eventTimer; /* Schedule for next maximum event time */ } } +#endif } /* Synchronous PDOs */ diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index ff65ae6a..c0be479f 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -372,10 +372,12 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ if(SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT /* Optional signal to RTOS. We can immediately continue SDO Client */ if(timerNext_us != NULL) { *timerNext_us = 0; } +#endif return CO_SDOcli_ok_communicationEnd; } @@ -642,6 +644,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( CO_SDOclient_abort(SDO_C, *pSDOabortCode); return CO_SDOcli_endedWithTimeout; } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; @@ -649,6 +652,7 @@ CO_SDOclient_return_t CO_SDOclientDownload( *timerNext_us = diff; } } +#endif /* TX data ******************************************************************************************* */ if(SDO_C->CANtxBuff->bufferFull) { @@ -720,12 +724,14 @@ CO_SDOclient_return_t CO_SDOclientDownload( else if (SDO_C->block_seqno >= SDO_C->block_blksize) { SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK; } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT else { /* Inform OS to call this function again without delay. */ if (timerNext_us != NULL) { *timerNext_us = 0; } } +#endif /* tx data */ SDO_C->timeoutTimer = 0; @@ -830,10 +836,12 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ if(SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT /* Optional signal to RTOS. We can immediately continue SDO Client */ if(timerNext_us != NULL) { *timerNext_us = 0; } +#endif return CO_SDOcli_ok_communicationEnd; } @@ -1156,6 +1164,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( CO_SDOclient_abort(SDO_C, *pSDOabortCode); return CO_SDOcli_endedWithTimeout; } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; @@ -1163,11 +1172,13 @@ CO_SDOclient_return_t CO_SDOclientUpload( *timerNext_us = diff; } } +#endif /* block TMO */ if (SDO_C->timeoutTimerBLOCK >= SDO_C->SDOtimeoutTimeHalf_us) { SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_ACK; } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT else if (timerNext_us != NULL) { /* check again after inhibit time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTimeHalf_us - SDO_C->timeoutTimerBLOCK; @@ -1175,6 +1186,7 @@ CO_SDOclient_return_t CO_SDOclientUpload( *timerNext_us = diff; } } +#endif /* TX data ******************************************************************************** */ diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index d556d199..d702ef7c 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -900,6 +900,7 @@ int8_t CO_SDO_process( return -1; } } +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO->SDOtimeoutTime_us - SDO->timeoutTimer; @@ -907,6 +908,7 @@ int8_t CO_SDO_process( *timerNext_us = diff; } } +#endif /* return immediately if still idle */ if(state == CO_SDO_ST_IDLE){ @@ -952,8 +954,10 @@ int8_t CO_SDO_process( /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; sendResponse = true; +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL) *timerNext_us = 0; +#endif } /* Segmented transfer */ @@ -1030,8 +1034,10 @@ int8_t CO_SDO_process( /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL) *timerNext_us = 0; +#endif } /* download segment response and alternate toggle bit */ @@ -1177,8 +1183,10 @@ int8_t CO_SDO_process( SDO->CANtxBuff->data[0] = 0xA1; SDO->state = CO_SDO_ST_IDLE; sendResponse = true; +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL) *timerNext_us = 0; +#endif break; } @@ -1198,8 +1206,10 @@ int8_t CO_SDO_process( /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; sendResponse = true; +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL) *timerNext_us = 0; +#endif } /* Segmented transfer */ @@ -1284,8 +1294,10 @@ int8_t CO_SDO_process( /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL) *timerNext_us = 0; +#endif } /* send response */ @@ -1474,10 +1486,12 @@ int8_t CO_SDO_process( /* send response */ CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT /* Inform OS to call this function again without delay. */ if (timerNext_us != NULL) { *timerNext_us = 0; } +#endif /* don't call CO_FLAG_CLEAR, so return directly */ return 1; @@ -1492,8 +1506,10 @@ int8_t CO_SDO_process( /* finish the communication and run mainline processing again */ SDO->state = CO_SDO_ST_IDLE; +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL) *timerNext_us = 0; +#endif break; } diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 00176e26..cb32a2ed 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -343,7 +343,6 @@ uint8_t CO_SYNC_process( /* SYNC producer */ if(SYNC->isProducer && SYNC->periodTime){ - uint32_t diff; if(SYNC->timer >= SYNC->periodTime){ if(++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1; SYNC->timer = 0; @@ -351,17 +350,16 @@ uint8_t CO_SYNC_process( SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; SYNC->CANtxBuff->data[0] = SYNC->counter; CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff); - diff = SYNC->periodTime; - }else{ - /* Calculate when next SYNC needs to be sent */ - diff = SYNC->periodTime - SYNC->timer; } - /* Set lower timerNext_us if necessary. */ +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT + /* Calculate when next SYNC needs to be sent */ if(timerNext_us != NULL){ + uint32_t diff = SYNC->periodTime - SYNC->timer; if(*timerNext_us > diff){ *timerNext_us = diff; } } +#endif } /* Synchronous PDOs are allowed only inside time window */ @@ -385,12 +383,14 @@ uint8_t CO_SYNC_process( if(SYNC->timer > SYNC->periodTimeoutTime) { CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); } +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT else if(timerNext_us != NULL) { uint32_t diff = SYNC->periodTimeoutTime - SYNC->timer; if(*timerNext_us > diff){ *timerNext_us = diff; } } +#endif } } else { diff --git a/301/CO_config.h b/301/CO_config.h index 98682d11..c2aa99bc 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -73,12 +73,25 @@ extern "C" { #define CO_CONFIG_FLAG_CALLBACK_PRE 0x0100 +/** + * Enable calculation of timerNext_us variable. + * + * Calculation of the timerNext_us variable is useful for smooth operation on + * operating system. See also @ref CO_process() function. + * + * This flag is common to multiple configuration macros. + */ +#define CO_CONFIG_FLAG_TIMERNEXT 0x0200 + + /** * Configuration of NMT_Heartbeat object * * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received NMT CAN message. + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_NMT_process(). * Callback is configured by CO_NMT_initCallbackPre(). * - CO_CONFIG_NMT_CALLBACK_CHANGE - Enable custom callback after NMT * state changes. Callback is configured by @@ -88,7 +101,7 @@ extern "C" { * be used for LEDs. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS #endif #define CO_CONFIG_NMT_CALLBACK_CHANGE 0x01 #define CO_CONFIG_NMT_MASTER 0x02 @@ -101,13 +114,15 @@ extern "C" { * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received SDO CAN message. + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_SDO_process(). * Callback is configured by CO_SDO_initCallbackPre(). * - CO_CONFIG_SDO_SEGMENTED - Enable SDO server segmented transfer. * - CO_CONFIG_SDO_BLOCK - Enable SDO server block transfer. If set, then * CO_CONFIG_SDO_SEGMENTED must also be set. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK +#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK #endif /* TODO with new OD */ #define CO_CONFIG_SDO_SEGMENTED 0x01 @@ -136,10 +151,12 @@ extern "C" { * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * emergency condition by CO_errorReport() or CO_errorReset() call. * Callback is configured by CO_EM_initCallbackPre(). + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_EM_process(). * - CO_CONFIG_EM_CONSUMER - Enable emergency consumer. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_EM_CONSUMER +#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_EM_CONSUMER #endif #define CO_CONFIG_EM_CONSUMER 0x01 @@ -151,6 +168,8 @@ extern "C" { * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received heartbeat CAN message. * Callback is configured by CO_HBconsumer_initCallbackPre(). + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_HBconsumer_process(). * - CO_CONFIG_HB_CONS_CALLBACK_CHANGE - Enable custom callback after NMT * state of the monitored node changes. Callback is configured by * CO_HBconsumer_initCallbackNmtChanged(). @@ -163,13 +182,37 @@ extern "C" { * NMT state of the specific monitored node. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT #endif #define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x01 #define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x02 #define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x04 +/** + * Configuration of PDO + * + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_TPDO_process(). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT +#endif + + +/** + * Configuration of SYNC + * + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_SYNC_process(). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SYNC CO_CONFIG_FLAG_TIMERNEXT +#endif + + /** * Configuration of SDO client object * @@ -177,9 +220,12 @@ extern "C" { * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received SDO CAN message. * Callback is configured by CO_SDOclient_initCallbackPre(). + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_SDOclientDownloadInitiate(), CO_SDOclientDownload(), + * CO_SDOclientUploadInitiate(), CO_SDOclientUpload(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE +#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT #endif diff --git a/301/CO_driver.h b/301/CO_driver.h index 9cc998a4..cc0940a0 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -57,6 +57,14 @@ extern "C" { #define CO_CONFIG_HB_CONS 0 #endif +#ifndef CO_CONFIG_PDO +#define CO_CONFIG_PDO 0 +#endif + +#ifndef CO_CONFIG_SYNC +#define CO_CONFIG_SYNC 0 +#endif + #ifndef CO_CONFIG_SDO_CLI #define CO_CONFIG_SDO_CLI 0 #endif diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index a043ef2c..b6cec5c6 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -45,11 +45,11 @@ extern "C" { /* Stack configuration override from CO_driver.h. Compile full stack. * For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS #endif #ifndef CO_CONFIG_SDO -#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK +#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK #endif #ifndef CO_CONFIG_SDO_BUFFER_SIZE @@ -57,15 +57,23 @@ extern "C" { #endif #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_EM_CONSUMER +#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_EM_CONSUMER #endif #ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT +#endif + +#ifndef CO_CONFIG_PDO +#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT +#endif + +#ifndef CO_CONFIG_SYNC +#define CO_CONFIG_SYNC CO_CONFIG_FLAG_TIMERNEXT #endif #ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE +#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT #endif #ifndef CO_CONFIG_LSS_MST diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index a817259f..c916403b 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -53,11 +53,11 @@ extern "C" { /* Stack configuration override from CO_driver.h. * For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS #endif #ifndef CO_CONFIG_SDO -#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK +#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK #endif #ifndef CO_CONFIG_SDO_BUFFER_SIZE @@ -65,15 +65,23 @@ extern "C" { #endif #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_EM_CONSUMER +#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_EM_CONSUMER #endif #ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#endif + +#ifndef CO_CONFIG_PDO +#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT +#endif + +#ifndef CO_CONFIG_SYNC +#define CO_CONFIG_SYNC CO_CONFIG_FLAG_TIMERNEXT #endif #ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE +#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT #endif #ifndef CO_CONFIG_LSS_MST From ffd5027cb2f00e96617ecf6bda90a5e8c60167f0 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 20 Mar 2020 18:47:16 +0100 Subject: [PATCH 053/520] Make SYNC optional in TPDO and RPDO. --- 301/CO_PDO.c | 62 ++++++++++++++++++++++++++++++++---- 301/CO_PDO.h | 31 +++++++++++------- 301/CO_config.h | 4 ++- 301/CO_driver.h | 2 +- CANopen.c | 4 +-- example/CO_driver_target.h | 2 +- socketCAN/CO_driver_target.h | 2 +- 7 files changed, 83 insertions(+), 24 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 41dcaff2..eb554ad4 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -28,7 +28,9 @@ #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" #include "301/CO_NMT_Heartbeat.h" +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE #include "301/CO_SYNC.h" +#endif #include "301/CO_PDO.h" /* @@ -51,6 +53,7 @@ static void CO_PDO_receive(void *object, void *msg){ (*RPDO->operatingState == CO_NMT_OPERATIONAL) && (DLC >= RPDO->dataLength)) { +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE if(RPDO->SYNC && RPDO->synchronous && RPDO->SYNC->CANrxToggle) { /* copy data into second buffer and set 'new message' flag */ RPDO->CANrxData[1][0] = data[0]; @@ -65,6 +68,7 @@ static void CO_PDO_receive(void *object, void *msg){ CO_FLAG_SET(RPDO->CANrxNew[1]); } else { +#endif /* copy data into default buffer and set 'new message' flag */ RPDO->CANrxData[0][0] = data[0]; RPDO->CANrxData[0][1] = data[1]; @@ -76,7 +80,9 @@ static void CO_PDO_receive(void *object, void *msg){ RPDO->CANrxData[0][7] = data[7]; CO_FLAG_SET(RPDO->CANrxNew[0]); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE } +#endif } } @@ -105,13 +111,17 @@ static void CO_RPDOconfigCom(CO_RPDO_t* RPDO, uint32_t COB_IDUsedByRPDO){ /* is used default COB-ID? */ if(ID == RPDO->defaultCOB_ID) ID += RPDO->nodeId; RPDO->valid = true; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE RPDO->synchronous = (RPDO->RPDOCommPar->transmissionType <= 240) ? true : false; +#endif } else{ ID = 0; RPDO->valid = false; CO_FLAG_CLEAR(RPDO->CANrxNew[0]); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE CO_FLAG_CLEAR(RPDO->CANrxNew[1]); +#endif } r = CO_CANrxBufferInit( RPDO->CANdevRx, /* CAN device */ @@ -124,7 +134,9 @@ static void CO_RPDOconfigCom(CO_RPDO_t* RPDO, uint32_t COB_IDUsedByRPDO){ if(r != CO_ERROR_NO){ RPDO->valid = false; CO_FLAG_CLEAR(RPDO->CANrxNew[0]); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE CO_FLAG_CLEAR(RPDO->CANrxNew[1]); +#endif } } @@ -467,6 +479,7 @@ static CO_SDO_abortCode_t CO_ODF_RPDOcom(CO_ODF_arg_t *ODF_arg){ } else if(ODF_arg->subIndex == 2){ /* Transmission_type */ uint8_t *value = (uint8_t*) ODF_arg->data; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE bool_t synchronousPrev = RPDO->synchronous; /* values from 241...253 are not valid */ @@ -479,6 +492,11 @@ static CO_SDO_abortCode_t CO_ODF_RPDOcom(CO_ODF_arg_t *ODF_arg){ if(RPDO->synchronous != synchronousPrev) { CO_FLAG_CLEAR(RPDO->CANrxNew[1]); } +#else + /* values from 0...253 are not valid */ + if(*value <= 253) + return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ +#endif } return CO_SDO_AB_NONE; @@ -541,16 +559,24 @@ static CO_SDO_abortCode_t CO_ODF_TPDOcom(CO_ODF_arg_t *ODF_arg){ /* configure TPDO */ CO_TPDOconfigCom(TPDO, value, TPDO->CANtxBuff->syncFlag); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE TPDO->syncCounter = 255; +#endif } else if(ODF_arg->subIndex == 2){ /* Transmission_type */ uint8_t *value = (uint8_t*) ODF_arg->data; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE /* values from 241...253 are not valid */ if(*value >= 241 && *value <= 253) return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ TPDO->CANtxBuff->syncFlag = (*value <= 240) ? 1 : 0; TPDO->syncCounter = 255; +#else + /* values from 0...253 are not valid */ + if(*value <= 253) + return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ +#endif } else if(ODF_arg->subIndex == 3){ /* Inhibit_Time */ /* if PDO is valid, value can not be changed */ @@ -717,7 +743,7 @@ CO_ReturnError_t CO_RPDO_init( CO_RPDO_t *RPDO, CO_EM_t *em, CO_SDO_t *SDO, - CO_SYNC_t *SYNC, + void *SYNC, CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, @@ -738,7 +764,9 @@ CO_ReturnError_t CO_RPDO_init( /* Configure object variables */ RPDO->em = em; RPDO->SDO = SDO; - RPDO->SYNC = SYNC; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + RPDO->SYNC = (CO_SYNC_t *)SYNC; +#endif RPDO->RPDOCommPar = RPDOCommPar; RPDO->RPDOMapPar = RPDOMapPar; RPDO->operatingState = operatingState; @@ -752,7 +780,9 @@ CO_ReturnError_t CO_RPDO_init( /* configure communication and mapping */ CO_FLAG_CLEAR(RPDO->CANrxNew[0]); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE CO_FLAG_CLEAR(RPDO->CANrxNew[1]); +#endif RPDO->CANdevRx = CANdevRx; RPDO->CANdevRxIdx = CANdevRxIdx; @@ -768,7 +798,7 @@ CO_ReturnError_t CO_TPDO_init( CO_TPDO_t *TPDO, CO_EM_t *em, CO_SDO_t *SDO, - CO_SYNC_t *SYNC, + void *SYNC, CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, @@ -789,7 +819,9 @@ CO_ReturnError_t CO_TPDO_init( /* Configure object variables */ TPDO->em = em; TPDO->SDO = SDO; - TPDO->SYNC = SYNC; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + TPDO->SYNC = (CO_SYNC_t *)SYNC; +#endif TPDO->TPDOCommPar = TPDOCommPar; TPDO->TPDOMapPar = TPDOMapPar; TPDO->operatingState = operatingState; @@ -804,12 +836,13 @@ CO_ReturnError_t CO_TPDO_init( /* configure communication and mapping */ TPDO->CANdevTx = CANdevTx; TPDO->CANdevTxIdx = CANdevTxIdx; - TPDO->syncCounter = 255; TPDO->inhibitTimer = 0; TPDO->eventTimer = ((uint32_t) TPDOCommPar->eventTimer) * 1000; if(TPDOCommPar->transmissionType>=254) TPDO->sendRequest = 1; CO_TPDOconfigMap(TPDO, TPDOMapPar->numberOfMappedObjects); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + TPDO->syncCounter = 255; CO_TPDOconfigCom(TPDO, TPDOCommPar->COB_IDUsedByTPDO, ((TPDOCommPar->transmissionType<=240) ? 1 : 0)); if((TPDOCommPar->transmissionType>240 && @@ -817,6 +850,11 @@ CO_ReturnError_t CO_TPDO_init( TPDOCommPar->SYNCStartValue>240){ TPDO->valid = false; } +#else + CO_TPDOconfigCom(TPDO, TPDOCommPar->COB_IDUsedByTPDO, 0); + if(TPDOCommPar->transmissionType<254) + TPDO->valid = false; +#endif return CO_ERROR_NO; } @@ -898,13 +936,21 @@ int16_t CO_TPDOsend(CO_TPDO_t *TPDO){ //#define RPDO_CALLS_EXTENSION /******************************************************************************/ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ + bool_t process_rpdo = true; + +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + if(RPDO->synchronous && !syncWas) + process_rpdo = false; +#endif if(!RPDO->valid || !(*RPDO->operatingState == CO_NMT_OPERATIONAL)) { CO_FLAG_CLEAR(RPDO->CANrxNew[0]); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE CO_FLAG_CLEAR(RPDO->CANrxNew[1]); +#endif } - else if(!RPDO->synchronous || syncWas) + else if(process_rpdo) { #if defined(RPDO_CALLS_EXTENSION) bool_t update = false; @@ -912,10 +958,12 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ uint8_t bufNo = 0; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE /* Determine, which of the two rx buffers, contains relevant message. */ if(RPDO->SYNC && RPDO->synchronous && !RPDO->SYNC->CANrxToggle) { bufNo = 1; } +#endif while(CO_FLAG_READ(RPDO->CANrxNew[bufNo])){ int16_t i; @@ -1002,6 +1050,7 @@ void CO_TPDO_process( #endif } +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE /* Synchronous PDOs */ else if(TPDO->SYNC && syncWas){ /* send synchronous acyclic PDO */ @@ -1031,6 +1080,7 @@ void CO_TPDO_process( } } } +#endif } else{ diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 237ebf39..7a668869 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -165,7 +165,6 @@ typedef struct{ typedef struct{ CO_EM_t *em; /**< From CO_RPDO_init() */ CO_SDO_t *SDO; /**< From CO_RPDO_init() */ - CO_SYNC_t *SYNC; /**< From CO_RPDO_init() */ const CO_RPDOCommPar_t *RPDOCommPar;/**< From CO_RPDO_init() */ const CO_RPDOMapPar_t *RPDOMapPar; /**< From CO_RPDO_init() */ CO_NMT_internalState_t *operatingState; /**< From CO_RPDO_init() */ @@ -174,16 +173,22 @@ typedef struct{ uint8_t restrictionFlags;/**< From CO_RPDO_init() */ /** True, if PDO is enabled and valid */ bool_t valid; - /** True, if PDO synchronous (transmissionType <= 240) */ - bool_t synchronous; /** Data length of the received PDO message. Calculated from mapping */ uint8_t dataLength; /** Pointers to 8 data objects, where PDO will be copied */ uint8_t *mapPointer[8]; +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN + CO_SYNC_t *SYNC; /**< From CO_RPDO_init() */ + /** True, if PDO synchronous (transmissionType <= 240) */ + bool_t synchronous; /** Variable indicates, if new PDO message received from CAN bus. */ volatile void *CANrxNew[2]; /** 8 data bytes of the received message. */ uint8_t CANrxData[2][8]; +#else + volatile void *CANrxNew[1]; + uint8_t CANrxData[1][8]; +#endif CO_CANmodule_t *CANdevRx; /**< From CO_RPDO_init() */ uint16_t CANdevRxIdx; /**< From CO_RPDO_init() */ }CO_RPDO_t; @@ -195,7 +200,6 @@ typedef struct{ typedef struct{ CO_EM_t *em; /**< From CO_TPDO_init() */ CO_SDO_t *SDO; /**< From CO_TPDO_init() */ - CO_SYNC_t *SYNC; /**< From CO_TPDO_init() */ const CO_TPDOCommPar_t *TPDOCommPar;/**< From CO_TPDO_init() */ const CO_TPDOMapPar_t *TPDOMapPar; /**< From CO_TPDO_init() */ CO_NMT_internalState_t *operatingState; /**< From CO_TPDO_init() */ @@ -210,16 +214,19 @@ typedef struct{ uint8_t sendRequest; /** Pointers to 8 data objects, where PDO will be copied */ uint8_t *mapPointer[8]; + /** Inhibit timer used for inhibit PDO sending translated to microseconds */ + uint32_t inhibitTimer; + /** Event timer used for PDO sending translated to microseconds */ + uint32_t eventTimer; /** Each flag bit is connected with one mapPointer. If flag bit is true, CO_TPDO_process() functiuon will send PDO if Change of State is detected on value pointed by that mapPointer */ uint8_t sendIfCOSFlags; +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN /** SYNC counter used for PDO sending */ uint8_t syncCounter; - /** Inhibit timer used for inhibit PDO sending translated to microseconds */ - uint32_t inhibitTimer; - /** Event timer used for PDO sending translated to microseconds */ - uint32_t eventTimer; + CO_SYNC_t *SYNC; /**< From CO_TPDO_init() */ +#endif CO_CANmodule_t *CANdevTx; /**< From CO_TPDO_init() */ CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer inside CANdev */ uint16_t CANdevTxIdx; /**< From CO_TPDO_init() */ @@ -234,7 +241,7 @@ typedef struct{ * @param RPDO This object will be initialized. * @param em Emergency object. * @param SDO SDO server object. - * @param SYNC SYNC object. + * @param SYNC void pointer to SYNC object or NULL. * @param operatingState Pointer to variable indicating CANopen device NMT internal state. * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. * @param defaultCOB_ID Default COB ID for this PDO (without NodeId). @@ -260,7 +267,7 @@ CO_ReturnError_t CO_RPDO_init( CO_RPDO_t *RPDO, CO_EM_t *em, CO_SDO_t *SDO, - CO_SYNC_t *SYNC, + void *SYNC, CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, @@ -281,7 +288,7 @@ CO_ReturnError_t CO_RPDO_init( * @param TPDO This object will be initialized. * @param em Emergency object. * @param SDO SDO object. - * @param SYNC SYNC object. + * @param SYNC void pointer to SYNC object or NULL. * @param operatingState Pointer to variable indicating CANopen device NMT internal state. * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. * @param defaultCOB_ID Default COB ID for this PDO (without NodeId). @@ -307,7 +314,7 @@ CO_ReturnError_t CO_TPDO_init( CO_TPDO_t *TPDO, CO_EM_t *em, CO_SDO_t *SDO, - CO_SYNC_t *SYNC, + void *SYNC, CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, diff --git a/301/CO_config.h b/301/CO_config.h index c2aa99bc..d1f52476 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -195,10 +195,12 @@ extern "C" { * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_TPDO_process(). + * - CO_CONFIG_PDO_SYNC_ENABLE - Enable SYNC object inside PDO objects. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE #endif +#define CO_CONFIG_PDO_SYNC_ENABLE 0x01 /** diff --git a/301/CO_driver.h b/301/CO_driver.h index cc0940a0..49bf72d5 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -58,7 +58,7 @@ extern "C" { #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO 0 +#define CO_CONFIG_PDO CO_CONFIG_PDO_SYNC_ENABLE #endif #ifndef CO_CONFIG_SYNC diff --git a/CANopen.c b/CANopen.c index dbd823d7..c80b7057 100644 --- a/CANopen.c +++ b/CANopen.c @@ -524,7 +524,7 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { err = CO_RPDO_init(CO->RPDO[i], CO->em, CO->SDO[0], - CO->SYNC, + (void *)CO->SYNC, &CO->NMT->operatingState, nodeId, ((i < 4) ? (CO_CAN_ID_RPDO_1 + i * 0x100) : 0), @@ -544,7 +544,7 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { err = CO_TPDO_init(CO->TPDO[i], CO->em, CO->SDO[0], - CO->SYNC, + (void *)CO->SYNC, &CO->NMT->operatingState, nodeId, ((i < 4) ? (CO_CAN_ID_TPDO_1 + i * 0x100) : 0), diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index b6cec5c6..0ede4fb5 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -65,7 +65,7 @@ extern "C" { #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE #endif #ifndef CO_CONFIG_SYNC diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index c916403b..4cefd1f0 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -73,7 +73,7 @@ extern "C" { #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE #endif #ifndef CO_CONFIG_SYNC From 43f86073ee301066aee2a1fd4481d78b1d17db73 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 3 Apr 2020 11:43:14 +0200 Subject: [PATCH 054/520] Minor corrections in documentation. --- 301/CO_Emergency.h | 2 +- 301/CO_HBconsumer.h | 2 +- 301/CO_NMT_Heartbeat.h | 2 +- 301/CO_PDO.h | 2 +- 301/CO_SDOserver.h | 2 +- 301/CO_SYNC.h | 2 +- 305/CO_LSSmaster.h | 4 ++-- 305/CO_LSSslave.h | 6 +++--- README.md | 4 ++-- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index e4275594..ab8a02a6 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -449,7 +449,7 @@ void CO_EM_initCallbackRx( * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param emInhTime _Inhibit time EMCY_ in [100*us] (object dictionary, index 0x1015). - * @param timerNext_us [out] info to OS - see CO_process(). + * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_EM_process( CO_EMpr_t *emPr, diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 3c57d03f..a8ded661 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -291,7 +291,7 @@ void CO_HBconsumer_initCallbackRemoteReset( * @param HBcons This object. * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param timerNext_us [out] info to OS - see CO_process(). + * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_HBconsumer_process( CO_HBconsumer_t *HBcons, diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index a94cda66..2fd306c0 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -259,7 +259,7 @@ void CO_NMT_initCallbackChanged( * @param errorBehavior pointer to _Error behavior_ array (object dictionary, index 0x1029). * Object controls, if device should leave NMT operational state. * Length of array must be 6. If pointer is NULL, no calculation is made. - * @param timerNext_us [out] info to OS - see CO_process(). + * @param [out] timerNext_us info to OS - see CO_process(). * * @return #CO_NMT_reset_cmd_t */ diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 7a668869..64b0fe85 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -381,7 +381,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas); * @param TPDO This object. * @param syncWas True, if CANopen SYNC message was just received or transmitted. * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param timerNext_us [out] info to OS - see CO_process_SYNC_PDO(). + * @param [out] timerNext_us info to OS - see CO_process_SYNC_PDO(). */ void CO_TPDO_process( CO_TPDO_t *TPDO, diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 0e3abf87..ab2fa70f 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -797,7 +797,7 @@ void CO_SDO_initCallbackPre( * @param NMTisPreOrOperational Different than zero, if #CO_NMT_internalState_t is * NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param timerNext_us [out] info to OS - see CO_process(). + * @param [out] timerNext_us info to OS - see CO_process(). * * @return 0: SDO server is idle. * @return 1: SDO server is in transfer state. diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 8d8f1fb8..e6a5db53 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -146,7 +146,7 @@ CO_ReturnError_t CO_SYNC_init( * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param ObjDict_synchronousWindowLength _Synchronous window length_ variable from * Object dictionary (index 0x1007). - * @param timerNext_us [out] info to OS - see CO_process_SYNC_PDO(). + * @param [out] timerNext_us info to OS - see CO_process_SYNC_PDO(). * * @return 0: No special meaning. * @return 1: New SYNC message recently received or was just transmitted. diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 2d2066b3..8ccc764a 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -353,7 +353,7 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( * @param LSSmaster This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. Zero when request is started. - * @param lssAddress [out] read result when function returns successfully + * @param [out] lssAddress read result when function returns successfully * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ @@ -376,7 +376,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( * @param LSSmaster This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. Zero when request is started. - * @param nodeId [out] read result when function returns successfully + * @param [out] nodeId read result when function returns successfully * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index d38b8bfc..26252982 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -301,8 +301,8 @@ CO_ReturnError_t CO_LSSslave_init( * @param LSSslave This object. * @param activeBitRate Currently active bit rate * @param activeNodeId Currently active node ID - * @param pendingBitRate [out] Requested bit rate - * @param pendingNodeId [out] Requested node id + * @param [out] pendingBitRate Requested bit rate + * @param [out] pendingNodeId Requested node id */ void CO_LSSslave_process( CO_LSSslave_t *LSSslave, @@ -333,7 +333,7 @@ CO_LSS_state_t CO_LSSslave_getState( * * @param LSSslave This object. * @param timeDifference_us The amount of time elapsed since the last call - * @param LEDon [out] LED state + * @param [out] LEDon LED state * * @return true if LSS is involved (unconfigured node or selected node) */ diff --git a/README.md b/README.md index 01730516..e7d56c66 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Characteristics - [Multithreaded, real-time](#flowchart-of-a-typical-canopennode-implementation) - [Object Dictionary editor](#object-dictionary-editor) - Non-volatile storage. - - [Power saving possible](#power-saving) (experimental) + - [Power saving possible](#power-saving) - [Bootloader possible](https://github.com/CANopenNode/CANopenNode/issues/111) (for firmware update) @@ -231,7 +231,7 @@ then NMT operational state is not allowed. ### Power saving All CANopen objects calculates next timer info for OS. Calculation is based on various timers which expire in known time. Can be used to put microcontroller -into sleep and wake at the calculated time. This is experimental. +into sleep and wake at the calculated time. Change Log From 5bb2d1632305fb168e76e94dcf60702e134a5f0e Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 7 Apr 2020 09:41:00 +0200 Subject: [PATCH 055/520] fix SDO block download process continuity after sequence breaks This is the same as pull request #171, but applied to split-driver branch. Original author: Oleg Now additional state CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2 is used to send response without resetting SDO sequence. Refactoring timeout halding logic in sub-block transfer. Also add missed unsigned indicators for several constants. issue #170 --- 301/CO_SDOserver.c | 50 ++++++++++++++++++++++++++++------------------ 301/CO_SDOserver.h | 5 ++++- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index d702ef7c..1d0a78ee 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -206,6 +206,10 @@ static void CO_SDO_receive(void *object, void *msg){ SDO->CANrxData[0] = data[0]; seqno = SDO->CANrxData[0] & 0x7fU; SDO->timeoutTimer = 0; + /* clear timeout in sub-block transfer indication if set before */ + if (SDO->timeoutSubblockDownolad) { + SDO->timeoutSubblockDownolad = false; + } /* check correct sequence number. */ if(seqno == (SDO->sequence + 1U)) { @@ -225,7 +229,7 @@ static void CO_SDO_receive(void *object, void *msg){ } } - /* break reception if last segment or block sequence is too large */ + /* break reception if last segment, block ends or block sequence is too large */ if(((SDO->CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) { SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; CO_FLAG_SET(SDO->CANrxNew); @@ -235,8 +239,8 @@ static void CO_SDO_receive(void *object, void *msg){ /* Ignore message, if it is duplicate or if sequence didn't started yet. */ } else { - /* seqno is totally wrong, break reception. */ - SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; + /* seqno is wrong, send response without resetting sequence */ + SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2; CO_FLAG_SET(SDO->CANrxNew); } } @@ -791,7 +795,6 @@ int8_t CO_SDO_process( uint32_t *timerNext_us) { CO_SDO_state_t state = CO_SDO_ST_IDLE; - bool_t timeoutSubblockDownolad = false; bool_t sendResponse = false; /* return if idle */ @@ -891,9 +894,12 @@ int8_t CO_SDO_process( SDO->timeoutTimer += timeDifference_us; } if (SDO->timeoutTimer >= SDO->SDOtimeoutTime_us) { - if((SDO->state == CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) && (SDO->sequence != 0) && (!SDO->CANtxBuff->bufferFull)){ - timeoutSubblockDownolad = true; - state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; + if((SDO->state == CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) && (!SDO->timeoutSubblockDownolad) && (!SDO->CANtxBuff->bufferFull)){ + /* set indication timeout in sub-block transfer and reset timeout */ + SDO->timeoutSubblockDownolad = true; + SDO->timeoutTimer = 0; + /* send response without resetting sequence */ + state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2; } else{ CO_SDO_abort(SDO, CO_SDO_AB_TIMEOUT); /* SDO protocol timed out */ @@ -974,8 +980,8 @@ int8_t CO_SDO_process( return -1; } } - SDO->bufferOffset = 0; - SDO->sequence = 0; + SDO->bufferOffset = 0U; + SDO->sequence = 0U; SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENTED; sendResponse = true; } @@ -1015,7 +1021,7 @@ int8_t CO_SDO_process( } SDO->ODF_arg.dataLength = CO_CONFIG_SDO_BUFFER_SIZE; - SDO->bufferOffset = 0; + SDO->bufferOffset = 0U; } } @@ -1081,8 +1087,9 @@ int8_t CO_SDO_process( } } - SDO->bufferOffset = 0; - SDO->sequence = 0; + SDO->bufferOffset = 0U; + SDO->sequence = 0U; + SDO->timeoutSubblockDownolad = false; SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK; /* send response */ @@ -1095,15 +1102,20 @@ int8_t CO_SDO_process( break; } - case CO_SDO_ST_DOWNLOAD_BL_SUB_RESP:{ - /* no new message received, SDO timeout occured, try to response */ - lastSegmentInSubblock = (!timeoutSubblockDownolad && + case CO_SDO_ST_DOWNLOAD_BL_SUB_RESP: + case CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2:{ + /* check if last segment received */ + lastSegmentInSubblock = (!SDO->timeoutSubblockDownolad && ((SDO->CANrxData[0] & 0x80U) == 0x80U)) ? true : false; /* prepare response */ SDO->CANtxBuff->data[0] = 0xA2; SDO->CANtxBuff->data[1] = SDO->sequence; - SDO->sequence = 0; + + /* reset sequence on reception break */ + if (state == CO_SDO_ST_DOWNLOAD_BL_SUB_RESP) { + SDO->sequence = 0U; + } /* empty buffer in domain data type if not last segment */ if((SDO->ODF_arg.ODdataStorage == 0) && (SDO->bufferOffset != 0) && !lastSegmentInSubblock){ @@ -1121,7 +1133,7 @@ int8_t CO_SDO_process( } SDO->ODF_arg.dataLength = CO_CONFIG_SDO_BUFFER_SIZE; - SDO->bufferOffset = 0; + SDO->bufferOffset = 0U; } /* blksize */ @@ -1360,8 +1372,8 @@ int8_t CO_SDO_process( return -1; } - SDO->bufferOffset = 0; - SDO->sequence = 0; + SDO->bufferOffset = 0U; + SDO->sequence = 0U; SDO->endOfTransfer = false; CO_FLAG_CLEAR(SDO->CANrxNew); SDO->state = CO_SDO_ST_UPLOAD_BL_SUBBLOCK; diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index ab2fa70f..fdad86ad 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -442,7 +442,8 @@ typedef enum { CO_SDO_ST_DOWNLOAD_BL_INITIATE = 0x14U, CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK = 0x15U, CO_SDO_ST_DOWNLOAD_BL_SUB_RESP = 0x16U, - CO_SDO_ST_DOWNLOAD_BL_END = 0x17U, + CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2 = 0x17U, + CO_SDO_ST_DOWNLOAD_BL_END = 0x18U, CO_SDO_ST_UPLOAD_INITIATE = 0x21U, CO_SDO_ST_UPLOAD_SEGMENTED = 0x22U, CO_SDO_ST_UPLOAD_BL_INITIATE = 0x24U, @@ -609,6 +610,8 @@ typedef struct{ uint16_t crc; /** Length of data in the last segment in block upload */ uint8_t lastLen; + /** Indication timeout in sub-block transfer */ + bool_t timeoutSubblockDownolad; /** Indication end of block transfer */ bool_t endOfTransfer; /** Variable indicates, if new SDO message received from CAN bus */ From 06e6f343c933e5fcb6d0ba91ec55a65b954efb09 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 27 Apr 2020 12:18:47 +0200 Subject: [PATCH 056/520] Update changelog --- doc/CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 66cf0663..0ae2cdd4 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,9 +1,9 @@ Change Log ========== -[Unreleased split-driver] +[Unreleased master] ------------------------- -- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/master...split-driver) +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.3...master) - See {TODO diff} for example of change in user application interface. ### Removed - All drivers removed from this project, except Neuberger-socketCAN for Linux. @@ -34,9 +34,9 @@ Change Log - All CANopen objects calculates next timer info for OS. Useful for energy saving. - Added file CO_config.h for stack configuration. Can be overridden by target specific or by custom definitions. -[Unreleased master] +[v1.3] - 2020-04-27 ------------------- -- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...master) +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...v1.3) ### Changed - License changed to Apache 2.0. - NMT self start functionality (OD object 1F80) implemented to strictly folow standard. Default value for object 1F80 have to be updated in OD editor. See README.md. @@ -84,8 +84,8 @@ Change Log Changelog written according to recommendations from https://keepachangelog.com/ -[Unreleased split-driver]: https://github.com/CANopenNode/CANopenNode/tree/split-driver [Unreleased master]: https://github.com/CANopenNode/CANopenNode +[v1.3]: https://github.com/CANopenNode/CANopenNode/tree/v1.3 [v1.2]: https://github.com/CANopenNode/CANopenNode/tree/v1.2 [v1.1]: https://github.com/CANopenNode/CANopenNode/tree/v1.1 [v1.0]: https://github.com/CANopenNode/CANopenNode/tree/v1.0 From 6c24ecfcec85f473727bf9033e274d9fabc2d020 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 29 Apr 2020 13:08:40 +0200 Subject: [PATCH 057/520] Globals alternative to heap now possible from CANopen.c --- CANopen.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 156 insertions(+), 17 deletions(-) diff --git a/CANopen.c b/CANopen.c index c80b7057..bc8dc16e 100644 --- a/CANopen.c +++ b/CANopen.c @@ -27,11 +27,12 @@ #include "CANopen.h" - -#include /* for malloc, free */ +#include /* Global variables ***********************************************************/ +/* #define CO_USE_GLOBALS */ /* If defined, global variables will be used + instead of dynamically allocated. */ extern const CO_OD_entry_t CO_OD[CO_OD_NoOfElements]; /* Object Dictionary */ static CO_t COO; /* Pointers to CANopen objects */ CO_t *CO = NULL; /* Pointer to COO */ @@ -107,7 +108,8 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; CO_NO_LSS_CLIENT) -/******************************************************************************/ +/* Create objects from heap ***************************************************/ +#ifndef CO_USE_GLOBALS CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { int16_t i; uint16_t errCnt = 0; @@ -118,20 +120,6 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { return CO_ERROR_NO; } - /* Verify parameters from CO_OD */ - if (sizeof(OD_TPDOCommunicationParameter_t) != sizeof(CO_TPDOCommPar_t) || - sizeof(OD_TPDOMappingParameter_t) != sizeof(CO_TPDOMapPar_t) || - sizeof(OD_RPDOCommunicationParameter_t) != sizeof(CO_RPDOCommPar_t) || - sizeof(OD_RPDOMappingParameter_t) != sizeof(CO_RPDOMapPar_t)) { - return CO_ERROR_PARAMETERS; - } - -#if CO_NO_SDO_CLIENT != 0 - if (sizeof(OD_SDOClientParameter_t) != sizeof(CO_SDOclientPar_t)) { - return CO_ERROR_PARAMETERS; - } -#endif - /* globals */ CO = &COO; @@ -350,6 +338,143 @@ void CO_delete(void *CANptr) { /* globals */ CO = NULL; } +#endif /* #ifndef CO_USE_GLOBALS */ + + +/* Alternatively create objects as globals ************************************/ +#ifdef CO_USE_GLOBALS + static CO_CANmodule_t COO_CANmodule; + static CO_CANrx_t COO_CANmodule_rxArray0[CO_RXCAN_NO_MSGS]; + static CO_CANtx_t COO_CANmodule_txArray0[CO_TXCAN_NO_MSGS]; + static CO_SDO_t COO_SDO[CO_NO_SDO_SERVER]; + static CO_OD_extension_t COO_SDO_ODExtensions[CO_OD_NoOfElements]; + static CO_EM_t COO_EM; + static CO_EMpr_t COO_EMpr; + static CO_NMT_t COO_NMT; +#if CO_NO_SYNC == 1 + static CO_SYNC_t COO_SYNC; +#endif +#if CO_NO_TIME == 1 + static CO_TIME_t COO_TIME; +#endif + static CO_RPDO_t COO_RPDO[CO_NO_RPDO]; + static CO_TPDO_t COO_TPDO[CO_NO_TPDO]; + static CO_HBconsumer_t COO_HBcons; + static CO_HBconsNode_t COO_HBcons_monitoredNodes[CO_NO_HB_CONS]; +#if CO_NO_SDO_CLIENT != 0 + static CO_SDOclient_t COO_SDOclient[CO_NO_SDO_CLIENT]; +#endif +#if CO_NO_LSS_SERVER == 1 + static CO_LSSslave_t COO_LSSslave; +#endif +#if CO_NO_LSS_CLIENT == 1 + static CO_LSSmaster_t COO_LSSmaster; +#endif +#if CO_NO_TRACE > 0 + #ifndef CO_TRACE_BUFFER_SIZE_FIXED + #define CO_TRACE_BUFFER_SIZE_FIXED 100 + #endif + static CO_trace_t COO_trace[CO_NO_TRACE]; + static uint32_t COO_traceTimeBuffers[CO_NO_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; + static int32_t COO_traceValueBuffers[CO_NO_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; +#endif + +CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { + int16_t i; + + /* If CANopen was initialized before, return. */ + if (CO != NULL) { + return CO_ERROR_NO; + } + + /* globals */ + CO = &COO; + + /* CANmodule */ + CO->CANmodule[0] = &COO_CANmodule; + CO_CANmodule_rxArray0 = &COO_CANmodule_rxArray0[0]; + CO_CANmodule_txArray0 = &COO_CANmodule_txArray0[0]; + + /* SDOserver */ + for (i = 0; i < CO_NO_SDO_SERVER; i++) { + CO->SDO[i] = &COO_SDO[i]; + } + CO_SDO_ODExtensions = &COO_SDO_ODExtensions[0]; + + /* Emergency */ + CO->em = &COO_EM; + CO->emPr = &COO_EMpr; + + /* NMT_Heartbeat */ + CO->NMT = &COO_NMT; + +#if CO_NO_SYNC == 1 + /* SYNC */ + CO->SYNC = &COO_SYNC; +#else + CO->SYNC = NULL; +#endif + +#if CO_NO_TIME == 1 + /* TIME */ + CO->TIME = &COO_TIME; +#else + CO->TIME = NULL; +#endif + + /* RPDO */ + for (i = 0; i < CO_NO_RPDO; i++) { + CO->RPDO[i] = &COO_RPDO[i]; + } + + /* TPDO */ + for (i = 0; i < CO_NO_TPDO; i++) { + CO->TPDO[i] = &COO_TPDO[i]; + } + + /* Heartbeat consumer */ + CO->HBcons = &COO_HBcons; + CO_HBcons_monitoredNodes = &COO_HBcons_monitoredNodes[0]; + +#if CO_NO_SDO_CLIENT != 0 + /* SDOclient */ + for (i = 0; i < CO_NO_SDO_CLIENT; i++) { + CO->SDOclient[i] = &COO_SDOclient[i]; + } +#endif + +#if CO_NO_LSS_SERVER == 1 + /* LSSslave */ + CO->LSSslave = &COO_LSSslave; +#endif + +#if CO_NO_LSS_CLIENT == 1 + /* LSSmaster */ + CO->LSSmaster = &COO_LSSmaster; +#endif + +#if CO_NO_TRACE > 0 + /* Trace */ + for (i = 0; i < CO_NO_TRACE; i++) { + CO->trace[i] = &COO_trace[i]; + CO_traceTimeBuffers[i] = &COO_traceTimeBuffers[i][0]; + CO_traceValueBuffers[i] = &COO_traceValueBuffers[i][0]; + CO_traceBufferSize[i] = CO_TRACE_BUFFER_SIZE_FIXED; + } +#endif + + return CO_ERROR_NO; +} + + +/******************************************************************************/ +void CO_delete(void *CANptr) { + CO_CANsetConfigurationMode(CANptr); + + /* globals */ + CO = NULL; +} +#endif /* #ifdef CO_USE_GLOBALS */ /******************************************************************************/ @@ -414,6 +539,20 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { return CO_ERROR_PARAMETERS; } + /* Verify parameters from CO_OD */ + if (sizeof(OD_TPDOCommunicationParameter_t) != sizeof(CO_TPDOCommPar_t) || + sizeof(OD_TPDOMappingParameter_t) != sizeof(CO_TPDOMapPar_t) || + sizeof(OD_RPDOCommunicationParameter_t) != sizeof(CO_RPDOCommPar_t) || + sizeof(OD_RPDOMappingParameter_t) != sizeof(CO_RPDOMapPar_t)) { + return CO_ERROR_PARAMETERS; + } +#if CO_NO_SDO_CLIENT != 0 + if (sizeof(OD_SDOClientParameter_t) != sizeof(CO_SDOclientPar_t)) { + return CO_ERROR_PARAMETERS; + } +#endif + + /* SDOserver */ for (i = 0; i < CO_NO_SDO_SERVER; i++) { uint32_t COB_IDClientToServer; From 5a2a1e85cfac8e5077927cb70c9ed4df03ad38d0 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 29 Apr 2020 13:12:07 +0200 Subject: [PATCH 058/520] Update configuration macros. SDO state machine preview. --- 301/CO_SDOserver.h | 342 +++++++++++++++++++++++++---------- 301/CO_config.h | 80 +++++--- 301/CO_driver.h | 32 ++-- CANopen.h | 32 +++- Doxyfile | 3 +- doc/index.html | 2 +- example/CO_driver_target.h | 46 ++++- socketCAN/CO_driver_target.h | 43 ++++- 8 files changed, 422 insertions(+), 158 deletions(-) diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index fdad86ad..14db0326 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -55,87 +55,258 @@ extern "C" { * device and provides also some kind of user interface, so configuration of * the network is possible. Code for the SDO client is in file CO_SDOclient.h. * - * SDO communication cycle is initiated by the client. Client can upload (read) data - * from device or can download (write) data to device. If data are less or equal - * of 4 bytes long, communication is finished by one server response (expedited - * transfer). If data are longer, they are split into multiple segments of - * request/response pairs (normal or segmented transfer). For longer data there - * is also a block transfer protocol, which transfers larger block of data in - * secure way with little protocol overhead. If error occurs during SDO transfer - * #CO_SDO_abortCode_t is send by client or server and transfer is terminated. + * SDO communication cycle is initiated by the client. Client can upload (read) + * data from device or can download (write) data to device. If data size is less + * or equal to 4 bytes, communication is finished by one server response + * (expedited transfer). If data size is longer, data are split into multiple + * segments of request/response pairs (normal or segmented transfer). For longer + * data there is also a block transfer protocol, which transfers larger block of + * data in secure way with little protocol overhead. If error occurs during SDO + * transfer #CO_SDO_abortCode_t is send by client or server and transfer is + * terminated. For more details see #CO_SDO_state_t. */ /** - * @defgroup CO_SDO_messageContents SDO message contents + * Internal states of the SDO state machine. * - * Excerpt from CiA DS301, V4.2. - * - * For CAN identifier see #CO_Default_CAN_ID_t - * - * Expedited transfer is used for transmission of up to 4 data bytes. It consists - * of one SDO request and one response. For longer variables is used segmented - * or block transfer. - * - * ####Initiate SDO download (client request) - * - byte 0: SDO command specifier. 8 bits: `0010nnes` (nn: if e=s=1, - * number of data bytes, that do *not* contain data; e=1 for - * expedited transfer; s=1 if data size is indicated). - * - byte 1..2: Object index. - * - byte 3: Object subIndex. - * - byte 4..7: Expedited data or data size if segmented transfer. - * - * ####Initiate SDO download (server response) - * - byte 0: SDO command specifier. 8 bits: `01100000`. - * - byte 1..2: Object index. - * - byte 3: Object subIndex. - * - byte 4..7: reserved. - * - * ####Download SDO segment (client request) - * - byte 0: SDO command specifier. 8 bits: `000tnnnc` (t: toggle bit set - * to 0 in first segment; nnn: number of data bytes, that do - * *not* contain data; c=1 if this is the last segment). - * - byte 1..7: Data segment. - * - * ####Download SDO segment (server response) - * - byte 0: SDO command specifier. 8 bits: `001t0000` (t: toggle bit set - * to 0 in first segment). - * - byte 1..7: Reserved. - * - * ####Initiate SDO upload (client request) - * - byte 0: SDO command specifier. 8 bits: `01000000`. - * - byte 1..2: Object index. - * - byte 3: Object subIndex. - * - byte 4..7: Reserved. - * - * ####Initiate SDO upload (server response) - * - byte 0: SDO command specifier. 8 bits: `0100nnes` (nn: if e=s=1, - * number of data bytes, that do *not* contain data; e=1 for - * expedited transfer; s=1 if data size is indicated). - * - byte 1..2: Object index. - * - byte 3: Object subIndex. - * - byte 4..7: reserved. - * - * ####Upload SDO segment (client request) - * - byte 0: SDO command specifier. 8 bits: `011t0000` (t: toggle bit set - * to 0 in first segment). - * - byte 1..7: Reserved. - * - * ####Upload SDO segment (server response) - * - byte 0: SDO command specifier. 8 bits: `000tnnnc` (t: toggle bit set - * to 0 in first segment; nnn: number of data bytes, that do - * *not* contain data; c=1 if this is the last segment). - * - byte 1..7: Data segment. - * - * ####Abort SDO transfer (client or server) - * - byte 0: SDO command specifier. 8 bits: `10000000`. - * - byte 1..2: Object index. - * - byte 3: Object subIndex. - * - byte 4..7: #CO_SDO_abortCode_t. - * - * ####Block transfer - * See DS301 V4.2. + * Note: CANopen has little endian byte order. + */ +typedef enum { +/** + * - SDO client may start new download to or upload from specified node, + * specified index and specified subindex. It can start normal or block + * communication. + * - SDO server is waiting for client request. */ +CO_SDO_ST_IDLE = 0x00U, +/** + * - Node-ID of the SDO server is the same as node-ID of this node, SDO client + * is the same device as SDO server. Transfer data directly without + * communication on CAN. */ +CO_SDO_ST_LOCAL_TRANSFER = 0x01U, +/** + * - SDO client or server may send SDO abort message in case of error: + * - byte 0: @b 10000000 binary. + * - byte 1..3: Object index and subIndex. + * - byte 4..7: #CO_SDO_abortCode_t. */ +CO_SDO_ST_ABORT = 0x02U, + +/** + * - SDO client initiates SDO download: + * - byte 0: @b 0010nnes binary: (nn: if e=s=1, number of data bytes, that do + * @b not contain data; e=1 for expedited transfer; s=1 if data size is + * indicated.) + * - byte 1..3: Object index and subIndex. + * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for + * segmented transfer is indicated here. + * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ +CO_SDO_ST_DOWNLOAD_INITIATE_REQ = 0x11U, +/** + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 01100000 binary. + * - byte 1..3: Object index and subIndex. + * - byte 4..7: Reserved. + * - In case of expedited transfer communication ends here. */ +CO_SDO_ST_DOWNLOAD_INITIATE_RSP = 0x12U, +/** + * - SDO client sends SDO segment: + * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; + * nnn: number of data bytes, that do @b not contain data; c=1 if this is the + * last segment). + * - byte 1..7: Data segment. + * - SDO server waits for segment. */ +CO_SDO_ST_DOWNLOAD_SEGMENT_REQ = 0x13U, +/** + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 001t0000 binary: (t: toggle bit, set to 0 in first segment). + * - byte 1..7: Reserved. + * - If c was set to 1, then communication ends here. */ +CO_SDO_ST_DOWNLOAD_SEGMENT_RSP = 0x14U, + +/** + * - SDO client initiates SDO upload: + * - byte 0: @b 01000000 binary. + * - byte 1..3: Object index and subIndex. + * - byte 4..7: Reserved. + * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ +CO_SDO_ST_UPLOAD_INITIATE_REQ = 0x21U, +/** + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 0100nnes binary: (nn: if e=s=1, number of data bytes, that do + * @b not contain data; e=1 for expedited transfer; s=1 if data size is + * indicated). + * - byte 1..3: Object index and subIndex. + * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for + * segmented transfer is indicated here. + * - In case of expedited transfer communication ends here. */ +CO_SDO_ST_UPLOAD_INITIATE_RSP = 0x22U, +/** + * - SDO client requests SDO segment: + * - byte 0: @b 011t0000 binary: (t: toggle bit, set to 0 in first segment). + * - byte 1..7: Reserved. + * - SDO server waits for segment. */ +CO_SDO_ST_UPLOAD_SEGMENT_REQ = 0x23U, +/** + * - SDO client waits for response. + * - SDO server responses with data: + * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; + * nnn: number of data bytes, that do @b not contain data; c=1 if this is the + * last segment). + * - byte 1..7: Data segment. + * - If c is set to 1, then communication ends here. */ +CO_SDO_ST_UPLOAD_SEGMENT_RSP = 0x24U, + +/** + * - SDO client initiates SDO block download: + * - byte 0: @b 11000rs0 binary: (r=1 if client supports generating CRC on + * data; s=1 if data size is indicated.) + * - byte 1..3: Object index and subIndex. + * - byte 4..7: If s=1, then size of data for block download is indicated here. + * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ +CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ = 0x31U, +/** + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 10100r00 binary: (r=1 if server supports generating CRC on + * data.) + * - byte 1..3: Object index and subIndex. + * - byte 4: blksize: Number of segments per block that shall be used by the + * client for the following block download with 0 < blksize < 128. + * - byte 5..7: Reserved. */ +CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP = 0x32U, +/** + * - SDO client sends 'blksize' segments of data in sequence: + * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be downloaded, + * enter SDO block download end phase; nnnnnnn is sequence number of segment, + * 1..127. + * - byte 1..7: At most 7 bytes of segment data to be downloaded. + * - SDO server reads sequence of 'blksize' blocks. */ +CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x33U, +/** + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 10100010 binary. + * - byte 1: ackseq: sequence number of last segment that was received + * successfully during the last block download. If ackseq is set to 0 the + * server indicates the client that the segment with the sequence number 1 + * was not received correctly and all segments shall be retransmitted by the + * client. + * - byte 2: Number of segments per block that shall be used by the client for + * the following block download with 0 < blksize < 128. + * - byte 3..7: Reserved. + * - If c was set to 1, then communication enters SDO block download end phase. + */ +CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP = 0x34U, +/** + * - SDO client sends SDO block download end: + * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not + * contain data) + * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. + * - byte 3..7: Reserved. + * - SDO server waits for client request. */ +CO_SDO_ST_DOWNLOAD_BLK_END_REQ = 0x35U, +/** + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 10100001 binary. + * - byte 1..7: Reserved. + * - Block download successfully ends here. + */ +CO_SDO_ST_DOWNLOAD_BLK_END_RSP = 0x36U, + +/** + * - SDO client initiates SDO block upload: + * - byte 0: @b 10100r00 binary: (r=1 if client supports generating CRC on + * data.) + * - byte 1..3: Object index and subIndex. + * - byte 4: blksize: Number of segments per block with 0 < blksize < 128. + * - byte 5: pst - protocol switch threshold. If pst > 0 and size of the data + * in bytes is less or equal pst, then the server may switch to the SDO + * upload protocol #CO_SDO_ST_UPLOAD_INITIATE_RSP. + * - byte 6..7: Reserved. + * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ +CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x41U, +/** + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 11000rs0 binary: (r=1 if server supports generating CRC on + * data; s=1 if data size is indicated. ) + * - byte 1..3: Object index and subIndex. + * - byte 4..7: If s=1, then size of data for block upload is indicated here. + * - If enabled by pst, then server may alternatively response with + * #CO_SDO_ST_UPLOAD_INITIATE_RSP */ +CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP = 0x42U, +/** + * - SDO client sends second initiate for SDO block upload: + * - byte 0: @b 10100011 binary. + * - byte 1..7: Reserved. + * - SDO server waits for client request. */ +CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2 = 0x43U, +/** + * - SDO client reads sequence of 'blksize' blocks. + * - SDO server sends 'blksize' segments of data in sequence: + * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be uploaded, + * enter SDO block upload end phase; nnnnnnn is sequence number of segment, + * 1..127. + * - byte 1..7: At most 7 bytes of segment data to be uploaded. */ +CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x44U, +/** + * This is interim state after server finished sending sequence of segments in + * one sub-block. This state is valid one cycle. In that state data should be + * emptied from internal buffer. In the next cycle client will send response and + * server will send another sequence of segments. */ +CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_DATA_RDY = 0x45U, +/** + * - SDO client responses: + * - byte 0: @b 10100010 binary. + * - byte 1: ackseq: sequence number of last segment that was received + * successfully during the last block upload. If ackseq is set to 0 the + * client indicates the server that the segment with the sequence number 1 + * was not received correctly and all segments shall be retransmitted by the + * server. + * - byte 2: Number of segments per block that shall be used by the server for + * the following block upload with 0 < blksize < 128. + * - byte 3..7: Reserved. + * - SDO server waits for response. + * - If c was set to 1, then communication enters SDO block upload end phase. */ +CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x46U, +/** + * - SDO client waits for server request. + * - SDO server sends SDO block upload end: + * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not + * contain data) + * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. + * - byte 3..7: Reserved. */ +CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x47U, +/** + * - SDO client responses: + * - byte 0: @b 10100001 binary. + * - byte 1..7: Reserved. + * - SDO server waits for response. + * - Block download successfully ends here. Note that this communication ends + * with client response. Client may then start next SDO communication + * immediately. */ +CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x48U, + +/* old state names, will be removed */ +CO_SDO_ST_DOWNLOAD_INITIATE = 0xA1U, +CO_SDO_ST_DOWNLOAD_SEGMENTED = 0xA2U, +CO_SDO_ST_DOWNLOAD_BL_INITIATE = 0xA4U, +CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK = 0xA5U, +CO_SDO_ST_DOWNLOAD_BL_SUB_RESP = 0xA6U, +CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2 = 0xA7U, +CO_SDO_ST_DOWNLOAD_BL_END = 0xA8U, +CO_SDO_ST_UPLOAD_INITIATE = 0xB1U, +CO_SDO_ST_UPLOAD_SEGMENTED = 0xB2U, +CO_SDO_ST_UPLOAD_BL_INITIATE = 0xB4U, +CO_SDO_ST_UPLOAD_BL_INITIATE_2 = 0xB5U, +CO_SDO_ST_UPLOAD_BL_SUBBLOCK = 0xB6U, +CO_SDO_ST_UPLOAD_BL_END = 0xB7U +} CO_SDO_state_t; /** @@ -432,27 +603,6 @@ typedef enum{ }CO_SDO_OD_flags_t; -/** - * Internal states of the SDO server state machine - */ -typedef enum { - CO_SDO_ST_IDLE = 0x00U, - CO_SDO_ST_DOWNLOAD_INITIATE = 0x11U, - CO_SDO_ST_DOWNLOAD_SEGMENTED = 0x12U, - CO_SDO_ST_DOWNLOAD_BL_INITIATE = 0x14U, - CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK = 0x15U, - CO_SDO_ST_DOWNLOAD_BL_SUB_RESP = 0x16U, - CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2 = 0x17U, - CO_SDO_ST_DOWNLOAD_BL_END = 0x18U, - CO_SDO_ST_UPLOAD_INITIATE = 0x21U, - CO_SDO_ST_UPLOAD_SEGMENTED = 0x22U, - CO_SDO_ST_UPLOAD_BL_INITIATE = 0x24U, - CO_SDO_ST_UPLOAD_BL_INITIATE_2 = 0x25U, - CO_SDO_ST_UPLOAD_BL_SUBBLOCK = 0x26U, - CO_SDO_ST_UPLOAD_BL_END = 0x27U -} CO_SDO_state_t; - - /** * Object for one entry with specific index in @ref CO_SDO_objectDictionary. */ diff --git a/301/CO_config.h b/301/CO_config.h index d1f52476..d98bad7a 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -101,7 +101,7 @@ extern "C" { * be used for LEDs. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS) #endif #define CO_CONFIG_NMT_CALLBACK_CHANGE 0x01 #define CO_CONFIG_NMT_MASTER 0x02 @@ -122,7 +122,7 @@ extern "C" { * CO_CONFIG_SDO_SEGMENTED must also be set. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK +#define CO_CONFIG_SDO (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK) #endif /* TODO with new OD */ #define CO_CONFIG_SDO_SEGMENTED 0x01 @@ -130,7 +130,7 @@ extern "C" { /** - * Size of the internal SDO buffer. + * Size of the internal data buffer for the SDO server. * * Size must be at least equal to size of largest variable in * @ref CO_SDO_objectDictionary. If data type is domain, data length is not @@ -139,7 +139,7 @@ extern "C" { * * Value can be in range from 7 to 889 bytes. */ -#ifndef CO_CONFIG_SDO_BUFFER_SIZE +#ifdef CO_DOXYGEN #define CO_CONFIG_SDO_BUFFER_SIZE 32 #endif @@ -156,7 +156,7 @@ extern "C" { * - CO_CONFIG_EM_CONSUMER - Enable emergency consumer. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_EM_CONSUMER +#define CO_CONFIG_EM (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_EM_CONSUMER) #endif #define CO_CONFIG_EM_CONSUMER 0x01 @@ -182,7 +182,7 @@ extern "C" { * NMT state of the specific monitored node. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT +#define CO_CONFIG_HB_CONS (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT) #endif #define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x01 #define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x02 @@ -198,7 +198,7 @@ extern "C" { * - CO_CONFIG_PDO_SYNC_ENABLE - Enable SYNC object inside PDO objects. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE +#define CO_CONFIG_PDO (CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE) #endif #define CO_CONFIG_PDO_SYNC_ENABLE 0x01 @@ -211,7 +211,7 @@ extern "C" { * inside CO_SYNC_process(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SYNC CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_TIMERNEXT) #endif @@ -225,9 +225,34 @@ extern "C" { * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_SDOclientDownloadInitiate(), CO_SDOclientDownload(), * CO_SDOclientUploadInitiate(), CO_SDOclientUpload(). + * - CO_CONFIG_SDO_CLI_SEGMENTED - Enable SDO server segmented transfer. + * - CO_CONFIG_SDO_CLI_BLOCK - Enable SDO server block transfer. If set, then + * CO_CONFIG_SDO_CLI_SEGMENTED must also be set. + * - CO_CONFIG_SDO_CLI_LOCAL - Enable local transfer, if Node-ID of the SDO + * server is the same as node-ID of the SDO client. (SDO client is the same + * device as SDO server.) Transfer data directly without communication on CAN. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_SDO_CLI (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_CLI_SEGMENTED | CO_CONFIG_SDO_CLI_BLOCK | CO_CONFIG_SDO_CLI_LOCAL) +#endif +#define CO_CONFIG_SDO_CLI_SEGMENTED 0x01 +#define CO_CONFIG_SDO_CLI_BLOCK 0x02 +#define CO_CONFIG_SDO_CLI_LOCAL 0x04 + + +/** + * Size of the internal data buffer for the SDO client. + * + * Circular buffer is used for SDO communication. it can be read or written + * between successive SDO calls. So size of the buffer can be lower than size of + * the actual size of data transferred. If only segmented transfer is used, then + * buffer size can be as low as 7 bytes, if data are read/written each cycle. If + * block transfer is used, buffer size should be set to at least 889 bytes, so + * maximum blksize can be used. In that case data should be read/written proper + * time between cycles. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 #endif @@ -240,27 +265,40 @@ extern "C" { * Callback is configured by CO_LSSmaster_initCallbackPre(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_LSS_MST CO_CONFIG_FLAG_CALLBACK_PRE +#define CO_CONFIG_LSS_MST (CO_CONFIG_FLAG_CALLBACK_PRE) #endif /** - * Configuration of Standard CiA 309 usage. + * Configuration of gateway object usage. + * + * Gateway object is covered by standard CiA 309 - CANopen access from other + * networks. It enables usage of the NMT master, SDO client and LSS master as a + * gateway device. * - * CiA 309 standard covers CANopen access from other networks. It enables - * usage of the NMT master, SDO client and LSS master as a gateway device. + * Possible flags, can be ORed: + * - CO_CONFIG_GTW_MULTI_NET - Enable multiple network interfaces in gateway + * device. This functionality is currntly not implemented. + * - CO_CONFIG_GTW_ASCII - Enable gateway device with ASCII mapping (CiA 309-3) + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | CO_CONFIG_GTW_ASCII) +#endif +#define CO_CONFIG_GTW_MULTI_NET 0x01 +#define CO_CONFIG_GTW_ASCII 0x02 + + +/** + * Size of command buffer in ASCII gateway object. * - * Value can be one of the following: - * - 0: Disabled. - * - 1: Interface enabled - * - 2: Modbus/TCP mapping (Not implemented) - * - 3: ASCII mapping - * - 4: Profinet (Not implemented) + * If large amount of data is transferred (block transfer), the this should be + * increased to 1000 or more. Buffer may be refilled between the block transfer. */ -#ifndef CO_CONFIG_309 -#define CO_CONFIG_309 0 +#ifdef CO_DOXYGEN +#define CO_CONFIG_GTWA_COMM_BUF_SIZE 100 #endif + /** @} */ #ifdef __cplusplus diff --git a/301/CO_driver.h b/301/CO_driver.h index 49bf72d5..f66a5b93 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -27,8 +27,8 @@ #ifndef CO_DRIVER_H #define CO_DRIVER_H -#include "CO_driver_target.h" #include "CO_config.h" +#include "CO_driver_target.h" #ifdef __cplusplus extern "C" { @@ -38,11 +38,11 @@ extern "C" { /* Default stack configuration for most common configuration, may be overridden * by CO_driver_target.h. For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT 0 +#define CO_CONFIG_NMT (0) #endif #ifndef CO_CONFIG_SDO -#define CO_CONFIG_SDO CO_CONFIG_SDO_SEGMENTED +#define CO_CONFIG_SDO (CO_CONFIG_SDO_SEGMENTED) #endif #ifndef CO_CONFIG_SDO_BUFFER_SIZE @@ -50,33 +50,43 @@ extern "C" { #endif #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM 0 +#define CO_CONFIG_EM (0) #endif #ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS 0 +#define CO_CONFIG_HB_CONS (0) #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO CO_CONFIG_PDO_SYNC_ENABLE +#define CO_CONFIG_PDO (CO_CONFIG_PDO_SYNC_ENABLE) #endif #ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC 0 +#define CO_CONFIG_SYNC (0) #endif #ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI 0 +#define CO_CONFIG_SDO_CLI (CO_CONFIG_SDO_CLI_SEGMENTED | \ + CO_CONFIG_SDO_CLI_LOCAL) +#endif + +#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 #endif #ifndef CO_CONFIG_LSS_MST -#define CO_CONFIG_LSS_MST 0 +#define CO_CONFIG_LSS_MST (0) #endif -#ifndef CO_CONFIG_309 -#define CO_CONFIG_309 0 +#ifndef CO_CONFIG_GTW +#define CO_CONFIG_GTW (0) #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#ifndef CO_CONFIG_GTWA_COMM_BUF_SIZE +#define CO_CONFIG_GTWA_COMM_BUF_SIZE 100 +#endif +#endif /** * @defgroup CO_driver Driver diff --git a/CANopen.h b/CANopen.h index c141b93d..2a94aa25 100644 --- a/CANopen.h +++ b/CANopen.h @@ -70,7 +70,7 @@ extern "C" { * @defgroup CO_CANopen_301 CANopen_301 * @{ * - * CANopen application layer and communication profile. + * CANopen application layer and communication profile (CiA 301 v4.2.0) * * Definitions of data types, encoding rules, object dictionary objects and * CANopen communication services and protocols. @@ -81,7 +81,7 @@ extern "C" { * @defgroup CO_CANopen_305 CANopen_305 * @{ * - * CANopen layer setting services (LSS) and protocols. + * CANopen layer setting services (LSS) and protocols (CiA 305 DSP v3.0.0) * * Inquire or change three parameters on a CANopen device with LSS slave * capability by a CANopen device with LSS master capability via the CAN @@ -91,6 +91,21 @@ extern "C" { * @} */ +/** + * @defgroup CO_CANopen_309 CANopen_309 + * @{ + * + * CANopen access from other networks (CiA 309) + * + * Standard defines the services and protocols to interface CANopen networks to + * other networks. Standard is organized as follows: + * - Part 1: General principles and services + * - Part 2: Modbus/TCP mapping + * - Part 3: ASCII mapping + * - Part 4: Amendment 7 to Fieldbus Integration into PROFINET IO + * @} + */ + /** * @defgroup CO_CANopen_extra CANopen_extra * @{ @@ -314,18 +329,15 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); * @param co CANopen object. * @param timeDifference_us Time difference from previous function call in * microseconds. - * @param timerNext_us [out] info to OS - maximum delay time after this function + * @param [out] timerNext_us info to OS - maximum delay time after this function * should be called next time in [microseconds]. Value can be used for OS * sleep time. Initial value must be set to maximum interval time. * Output will be equal or lower to initial value. Calculation is based * on various timers which expire in known time. Parameter should be * used in combination with callbacks configured with * CO_***_initCallbackPre() functions. Those callbacks should also - * trigger calling of CO_process() function. - * See also @ref CO_CONFIG_FLAG_CALLBACK_PRE configuration macro. - * - * This is experimental feature and can be used for energy saving in case - * of low traffic on CAN bus. Parameter is ignored if NULL. + * trigger calling of CO_process() function. Parameter is ignored if + * NULL. See also @ref CO_CONFIG_FLAG_CALLBACK_PRE configuration macro. * * @return #CO_NMT_reset_cmd_t from CO_NMT_process(). */ @@ -344,7 +356,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, * @param co CANopen object. * @param timeDifference_us Time difference from previous function call in * microseconds. - * @param timerNext_us [out] info to OS - see CO_process(). + * @param [out] timerNext_us info to OS - see CO_process(). * * @return True, if CANopen SYNC message was just received or transmitted. */ @@ -378,7 +390,7 @@ void CO_process_RPDO(CO_t *co, bool_t syncWas); * transmitted. * @param timeDifference_us Time difference from previous function call in * microseconds. - * @param timerNext_us [out] info to OS - see CO_process(). + * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_process_TPDO(CO_t *co, bool_t syncWas, diff --git a/Doxyfile b/Doxyfile index 993bc354..61d7c832 100644 --- a/Doxyfile +++ b/Doxyfile @@ -785,6 +785,7 @@ INPUT = README.md \ CANopen.h \ 301 \ 305 \ + 309 \ extra \ socketCAN @@ -935,7 +936,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing diff --git a/doc/index.html b/doc/index.html index 13211f4d..5bc11288 120000 --- a/doc/index.html +++ b/doc/index.html @@ -1 +1 @@ -html/md_README.html \ No newline at end of file +html/index.html \ No newline at end of file diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 0ede4fb5..a2510714 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -45,39 +45,67 @@ extern "C" { /* Stack configuration override from CO_driver.h. Compile full stack. * For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_NMT_CALLBACK_CHANGE | \ + CO_CONFIG_NMT_MASTER | \ + CO_CONFIG_NMT_LEDS) #endif #ifndef CO_CONFIG_SDO -#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK +#define CO_CONFIG_SDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_SDO_SEGMENTED | \ + CO_CONFIG_SDO_BLOCK) #endif #ifndef CO_CONFIG_SDO_BUFFER_SIZE -#define CO_CONFIG_SDO_BUFFER_SIZE 889 +#define CO_CONFIG_SDO_BUFFER_SIZE 1800 #endif #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_EM_CONSUMER +#define CO_CONFIG_EM (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_EM_CONSUMER) #endif #ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT +#define CO_CONFIG_HB_CONS (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ + CO_CONFIG_HB_CONS_CALLBACK_MULTI | \ + CO_CONFIG_HB_CONS_QUERY_FUNCT) #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE +#define CO_CONFIG_PDO (CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_PDO_SYNC_ENABLE) #endif #ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_SDO_CLI (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_SDO_CLI_SEGMENTED | \ + CO_CONFIG_SDO_CLI_BLOCK | \ + CO_CONFIG_SDO_CLI_LOCAL) +#endif + +#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 #endif #ifndef CO_CONFIG_LSS_MST -#define CO_CONFIG_LSS_MST CO_CONFIG_FLAG_CALLBACK_PRE +#define CO_CONFIG_LSS_MST (CO_CONFIG_FLAG_CALLBACK_PRE) +#endif + +#ifndef CO_CONFIG_GTW +#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | \ + CO_CONFIG_GTW_ASCII) +#define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 #endif diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 4cefd1f0..b46a7f5b 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -53,39 +53,64 @@ extern "C" { /* Stack configuration override from CO_driver.h. * For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS +#define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_NMT_CALLBACK_CHANGE | \ + CO_CONFIG_NMT_MASTER | \ + CO_CONFIG_NMT_LEDS) #endif #ifndef CO_CONFIG_SDO -#define CO_CONFIG_SDO CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK +#define CO_CONFIG_SDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_SDO_SEGMENTED | \ + CO_CONFIG_SDO_BLOCK) #endif #ifndef CO_CONFIG_SDO_BUFFER_SIZE -#define CO_CONFIG_SDO_BUFFER_SIZE 889 +#define CO_CONFIG_SDO_BUFFER_SIZE 1800 #endif #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_EM_CONSUMER +#define CO_CONFIG_EM (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_EM_CONSUMER) #endif #ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#define CO_CONFIG_HB_CONS (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_HB_CONS_CALLBACK_CHANGE) #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE +#define CO_CONFIG_PDO (CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_PDO_SYNC_ENABLE) #endif #ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT +#define CO_CONFIG_SDO_CLI (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_SDO_CLI_SEGMENTED | \ + CO_CONFIG_SDO_CLI_BLOCK | \ + CO_CONFIG_SDO_CLI_LOCAL) +#endif + +#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 #endif #ifndef CO_CONFIG_LSS_MST -#define CO_CONFIG_LSS_MST CO_CONFIG_FLAG_CALLBACK_PRE +#define CO_CONFIG_LSS_MST (CO_CONFIG_FLAG_CALLBACK_PRE) +#endif + +#ifndef CO_CONFIG_GTW +#define CO_CONFIG_GTW (CO_CONFIG_GTW_ASCII) +#define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 #endif From 4c3011d34addd85359c6ae4b9e3a521caa3d4422 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Mon, 4 May 2020 11:22:32 +0200 Subject: [PATCH 059/520] Replace all memcpy/memset-like functions with standard functions (#175) * Use standard memcpy() instead of CO_memcpy() * Remove CO_memcpy() * Use standard memset() instead of CO_memset() * Remove CO_memset() * Move helper functions from CO_SDOserver.c to header and make them inline * Implement CO_getUint16() with memcpy() * Implement CO_getUint32() with memcpy() * Implement CO_setUint16() with memcpy() * Implement CO_setUint32() with memcpy() * Define memcpy() as CO_memcpySwapX() for little-endian systems * Fix several writes past the buffer due to hardcoded sizes Use more "generic" sizes (via sizeof()) instead of hardcoded number in all calls to memset() to avoid 1-byte errors which result in writes past the buffer, for example: memset(&LSSslave->TXbuff->data[5], 0, 4); in CO_LSSslave_serviceInquire() memset(&LSSmaster->TXbuff->data[6], 0, 3); in CO_LSSmaster_switchStateSelectInitiate() * Use "generic" size in calls to memcpy() where possible * Remove CO_bytes_t This type was used only for CO_{get,set}Uint{16,32}(). --- 301/CO_Emergency.c | 10 ++-- 301/CO_SDOserver.c | 117 -------------------------------------- 301/CO_SDOserver.h | 105 +++++++++++++++++++++------------- 301/CO_TIME.c | 6 +- 305/CO_LSSmaster.c | 22 +++---- 305/CO_LSSslave.c | 25 ++++---- example/eeprom.c | 6 +- socketCAN/CO_OD_storage.c | 4 +- 8 files changed, 106 insertions(+), 189 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 47d7d66b..ec05583b 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -24,6 +24,8 @@ */ +#include + #include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" @@ -331,8 +333,8 @@ void CO_EM_process( #endif /* copy data to CAN emergency message */ - CO_memcpy(emPr->CANtxBuff->data, em->bufReadPtr, 8U); - CO_memcpy((uint8_t*)&preDEF, em->bufReadPtr, 4U); + memcpy(emPr->CANtxBuff->data, em->bufReadPtr, sizeof(emPr->CANtxBuff->data)); + memcpy(&preDEF, em->bufReadPtr, sizeof(preDEF)); em->bufReadPtr += 8; /* Update read buffer pointer and reset inhibit timer */ @@ -427,7 +429,7 @@ void CO_errorReport(CO_EM_t *em, const uint8_t errorBit, const uint16_t errorCod /* copy data to the buffer, increment writePtr and verify buffer full */ CO_LOCK_EMCY(); - CO_memcpy(em->bufWritePtr, &bufCopy[0], 8); + memcpy(em->bufWritePtr, bufCopy, sizeof(bufCopy)); em->bufWritePtr += 8; if(em->bufWritePtr == em->bufEnd) em->bufWritePtr = em->buf; @@ -488,7 +490,7 @@ void CO_errorReset(CO_EM_t *em, const uint8_t errorBit, const uint32_t infoCode) /* copy data to the buffer, increment writePtr and verify buffer full */ CO_LOCK_EMCY(); - CO_memcpy(em->bufWritePtr, &bufCopy[0], 8); + memcpy(em->bufWritePtr, bufCopy, sizeof(bufCopy)); em->bufWritePtr += 8; if(em->bufWritePtr == em->bufEnd) em->bufWritePtr = em->buf; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 1d0a78ee..edebb4df 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -47,123 +47,6 @@ #endif -/* Helper functions. **********************************************************/ -void CO_memcpy(uint8_t dest[], const uint8_t src[], const uint16_t size){ - uint16_t i; - for(i = 0; i < size; i++){ - dest[i] = src[i]; - } -} - -void CO_memset(uint8_t dest[], uint8_t c, const uint16_t size){ - uint16_t i; - for(i = 0; i < size; i++){ - dest[i] = c; - } -} - -uint16_t CO_getUint16(const uint8_t data[]){ - CO_bytes_t b; - b.u8[0] = data[0]; - b.u8[1] = data[1]; - return b.u16[0]; -} - -uint32_t CO_getUint32(const uint8_t data[]){ - CO_bytes_t b; - b.u8[0] = data[0]; - b.u8[1] = data[1]; - b.u8[2] = data[2]; - b.u8[3] = data[3]; - return b.u32[0]; -} - -void CO_setUint16(uint8_t data[], const uint16_t value){ - CO_bytes_t b; - b.u16[0] = value; - data[0] = b.u8[0]; - data[1] = b.u8[1]; -} - -void CO_setUint32(uint8_t data[], const uint32_t value){ - CO_bytes_t b; - b.u32[0] = value; - data[0] = b.u8[0]; - data[1] = b.u8[1]; - data[2] = b.u8[2]; - data[3] = b.u8[3]; -} - -#ifdef CO_LITTLE_ENDIAN -void CO_memcpySwap2(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[0]; - cdest[1] = csrc[1]; -} -void CO_memcpySwap4(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[0]; - cdest[1] = csrc[1]; - cdest[2] = csrc[2]; - cdest[3] = csrc[3]; -} -void CO_memcpySwap8(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[0]; - cdest[1] = csrc[1]; - cdest[2] = csrc[2]; - cdest[3] = csrc[3]; - cdest[4] = csrc[4]; - cdest[5] = csrc[5]; - cdest[6] = csrc[6]; - cdest[7] = csrc[7]; -} -#endif -#ifdef CO_BIG_ENDIAN -void CO_memcpySwap2(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[1]; - cdest[1] = csrc[0]; -} -void CO_memcpySwap4(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[3]; - cdest[1] = csrc[2]; - cdest[2] = csrc[1]; - cdest[3] = csrc[0]; -} -void CO_memcpySwap8(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[7]; - cdest[1] = csrc[6]; - cdest[2] = csrc[5]; - cdest[3] = csrc[4]; - cdest[4] = csrc[3]; - cdest[5] = csrc[2]; - cdest[6] = csrc[1]; - cdest[7] = csrc[0]; -} -#endif - - /* * Read received message from CAN module. * diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 14db0326..14176d60 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -27,6 +27,8 @@ #ifndef CO_SDO_SERVER_H #define CO_SDO_SERVER_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -779,46 +781,17 @@ typedef struct{ }CO_SDO_t; -/** - * Helper union for manipulating data bytes. - */ -typedef union{ - uint8_t u8[8]; /**< 8 bytes */ - uint16_t u16[4]; /**< 4 words */ - uint32_t u32[2]; /**< 2 double words */ -}CO_bytes_t; - - -/** - * Helper function like memcpy. - * - * Function copies n data bytes from source to destination. - * - * @param dest Destination location. - * @param src Source location. - * @param size Number of data bytes to be copied (max 0xFFFF). - */ -void CO_memcpy(uint8_t dest[], const uint8_t src[], const uint16_t size); - -/** - * Helper function like memset. - * - * Function fills destination with char "c". - * - * @param dest Destination location. - * @param c set value. - * @param size Number of data bytes to be copied (max 0xFFFF). - */ -void CO_memset(uint8_t dest[], uint8_t c, const uint16_t size); - - /** * Helper function returns uint16 from byte array. * * @param data Location of source data. * @return Variable of type uint16_t. */ -uint16_t CO_getUint16(const uint8_t data[]); +static inline uint16_t CO_getUint16(const uint8_t data[]){ + uint16_t value; + memcpy(&value, data, sizeof(value)); + return value; +} /** @@ -827,7 +800,11 @@ uint16_t CO_getUint16(const uint8_t data[]); * @param data Location of source data. * @return Variable of type uint32_t. */ -uint32_t CO_getUint32(const uint8_t data[]); +static inline uint32_t CO_getUint32(const uint8_t data[]){ + uint32_t value; + memcpy(&value, data, sizeof(value)); + return value; +} /** @@ -836,7 +813,9 @@ uint32_t CO_getUint32(const uint8_t data[]); * @param data Location of destination data. * @param value Variable of type uint16_t to be written into data. */ -void CO_setUint16(uint8_t data[], const uint16_t value); +static inline void CO_setUint16(uint8_t data[], const uint16_t value){ + memcpy(data, &value, sizeof(value)); +} /** @@ -845,7 +824,9 @@ void CO_setUint16(uint8_t data[], const uint16_t value); * @param data Location of destination data. * @param value Variable of type uint32_t to be written into data. */ -void CO_setUint32(uint8_t data[], const uint32_t value); +static inline void CO_setUint32(uint8_t data[], const uint32_t value){ + memcpy(data, &value, sizeof(value)); +} /** @@ -855,7 +836,19 @@ void CO_setUint32(uint8_t data[], const uint32_t value); * @param dest Destination location. * @param src Source location. */ -void CO_memcpySwap2(void* dest, const void* src); +#ifdef CO_LITTLE_ENDIAN +#define CO_memcpySwap2(dest, src) memcpy(dest, src, 2) +#endif +#ifdef CO_BIG_ENDIAN +static inline void CO_memcpySwap2(void* dest, const void* src){ + char *cdest; + char *csrc; + cdest = (char *) dest; + csrc = (char *) src; + cdest[0] = csrc[1]; + cdest[1] = csrc[0]; +} +#endif /** @@ -865,7 +858,21 @@ void CO_memcpySwap2(void* dest, const void* src); * @param dest Destination location. * @param src Source location. */ -void CO_memcpySwap4(void* dest, const void* src); +#ifdef CO_LITTLE_ENDIAN +#define CO_memcpySwap4(dest, src) memcpy(dest, src, 4) +#endif +#ifdef CO_BIG_ENDIAN +static inline void CO_memcpySwap4(void* dest, const void* src){ + char *cdest; + char *csrc; + cdest = (char *) dest; + csrc = (char *) src; + cdest[0] = csrc[3]; + cdest[1] = csrc[2]; + cdest[2] = csrc[1]; + cdest[3] = csrc[0]; +} +#endif /** @@ -875,7 +882,25 @@ void CO_memcpySwap4(void* dest, const void* src); * @param dest Destination location. * @param src Source location. */ -void CO_memcpySwap8(void* dest, const void* src); +#ifdef CO_LITTLE_ENDIAN +#define CO_memcpySwap8(dest, src) memcpy(dest, src, 8) +#endif +#ifdef CO_BIG_ENDIAN +static inline void CO_memcpySwap8(void* dest, const void* src){ + char *cdest; + char *csrc; + cdest = (char *) dest; + csrc = (char *) src; + cdest[0] = csrc[7]; + cdest[1] = csrc[6]; + cdest[2] = csrc[5]; + cdest[3] = csrc[4]; + cdest[4] = csrc[3]; + cdest[5] = csrc[2]; + cdest[6] = csrc[1]; + cdest[7] = csrc[0]; +} +#endif /** diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 88f76415..838e2b4d 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -23,6 +23,8 @@ * limitations under the License. */ +#include + #include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" @@ -47,7 +49,7 @@ static void CO_TIME_receive(void *object, void *msg){ if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){ // Process Time from msg buffer - CO_memcpy((uint8_t*)&TIME->Time.ullValue, data, DLC); + memcpy(&TIME->Time.ullValue, data, DLC); CO_FLAG_SET(TIME->CANrxNew); } else{ @@ -156,7 +158,7 @@ uint8_t CO_TIME_process( if(TIME->timer >= TIME->periodTime){ TIME->timer = 0; ret = 1; - CO_memcpy(TIME->TXbuff->data, (const uint8_t*)&TIME->Time.ullValue, TIME_MSG_LENGTH); + memcpy(TIME->TXbuff->data, &TIME->Time.ullValue, TIME_MSG_LENGTH); CO_CANsend(TIME->CANdevTx, TIME->TXbuff); } } diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index f48f20e5..0771f487 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -24,6 +24,8 @@ * limitations under the License. */ +#include + #include "301/CO_driver.h" #include "301/CO_SDOserver.h" /* for helper functions */ #include "305/CO_LSSmaster.h" @@ -151,7 +153,7 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); - CO_memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); + memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); #if (CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE LSSmaster->pFunctSignal = NULL; LSSmaster->functSignalObject = NULL; @@ -227,7 +229,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); - CO_memset(&LSSmaster->TXbuff->data[6], 0, 3); + memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -250,7 +252,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION; - CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); + memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -343,7 +345,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_WAITING; - CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); + memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -447,7 +449,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( LSSmaster->TXbuff->data[0] = CO_LSS_CFG_BIT_TIMING; LSSmaster->TXbuff->data[1] = 0; LSSmaster->TXbuff->data[2] = bitTiming; - CO_memset(&LSSmaster->TXbuff->data[3], 0, 5); + memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -492,7 +494,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_NODE_ID; LSSmaster->TXbuff->data[1] = nodeId; - CO_memset(&LSSmaster->TXbuff->data[2], 0, 6); + memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -532,7 +534,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_STORE; - CO_memset(&LSSmaster->TXbuff->data[1], 0, 7); + memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -571,7 +573,7 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); - CO_memset(&LSSmaster->TXbuff->data[3], 0, 5); + memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -590,7 +592,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( { CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = cs; - CO_memset(&LSSmaster->TXbuff->data[1], 0, 7); + memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); return CO_LSSmaster_WAIT_SLAVE; @@ -1051,7 +1053,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( case CO_LSSmaster_FS_STATE_CHECK: ret = CO_LSSmaster_FsCheckWait(LSSmaster, timeDifference_us); if (ret == CO_LSSmaster_SCAN_FINISHED) { - CO_memset((uint8_t*)&fastscan->found, 0, sizeof(fastscan->found)); + memset(&fastscan->found, 0, sizeof(fastscan->found)); /* start scanning procedure by triggering vendor ID scan */ CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_us, diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index bfa5e734..111bb696 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -24,6 +24,8 @@ * limitations under the License. */ +#include + #include "301/CO_driver.h" #include "301/CO_SDOserver.h" /* for helper functions */ #include "305/CO_LSSslave.h" @@ -42,7 +44,7 @@ static void CO_LSSslave_serviceSwitchStateGlobal( switch (mode) { case CO_LSS_STATE_WAITING: LSSslave->lssState = CO_LSS_STATE_WAITING; - CO_memset((uint8_t*)&LSSslave->lssSelect, 0, sizeof(LSSslave->lssSelect)); + memset(&LSSslave->lssSelect, 0, sizeof(LSSslave->lssSelect)); break; case CO_LSS_STATE_CONFIGURATION: LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; @@ -86,7 +88,7 @@ static void CO_LSSslave_serviceSwitchStateSelective( /* send confirmation */ LSSslave->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL; - CO_memset(&LSSslave->TXbuff->data[1], 0, 7); + memset(&LSSslave->TXbuff->data[1], 0, sizeof(LSSslave->TXbuff->data) - 1); CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); } break; @@ -134,7 +136,7 @@ static void CO_LSSslave_serviceConfig( LSSslave->TXbuff->data[0] = CO_LSS_CFG_NODE_ID; LSSslave->TXbuff->data[1] = errorCode; /* we do not use spec-error, always 0 */ - CO_memset(&LSSslave->TXbuff->data[2], 0, 6); + memset(&LSSslave->TXbuff->data[2], 0, sizeof(LSSslave->TXbuff->data) - 2); CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); break; case CO_LSS_CFG_BIT_TIMING: @@ -168,7 +170,7 @@ static void CO_LSSslave_serviceConfig( LSSslave->TXbuff->data[0] = CO_LSS_CFG_BIT_TIMING; LSSslave->TXbuff->data[1] = errorCode; /* we do not use spec-error, always 0 */ - CO_memset(&LSSslave->TXbuff->data[2], 0, 6); + memset(&LSSslave->TXbuff->data[2], 0, sizeof(LSSslave->TXbuff->data) - 2); CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); break; case CO_LSS_CFG_ACTIVATE_BIT_TIMING: @@ -206,7 +208,7 @@ static void CO_LSSslave_serviceConfig( LSSslave->TXbuff->data[0] = CO_LSS_CFG_STORE; LSSslave->TXbuff->data[1] = errorCode; /* we do not use spec-error, always 0 */ - CO_memset(&LSSslave->TXbuff->data[2], 0, 6); + memset(&LSSslave->TXbuff->data[2], 0, sizeof(LSSslave->TXbuff->data) - 2); CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); break; default: @@ -250,7 +252,7 @@ static void CO_LSSslave_serviceInquire( /* send response */ LSSslave->TXbuff->data[0] = service; CO_memcpySwap4(&LSSslave->TXbuff->data[1], &value); - CO_memset(&LSSslave->TXbuff->data[5], 0, 4); + memset(&LSSslave->TXbuff->data[5], 0, sizeof(LSSslave->TXbuff->data) - 5); CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); } @@ -300,8 +302,7 @@ static void CO_LSSslave_serviceIdent( /* Confirm, Reset */ ack = true; LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; - CO_memset((uint8_t*)&LSSslave->lssFastscan, 0, - sizeof(LSSslave->lssFastscan)); + memset(&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); } else if (LSSslave->fastscanPos == lssSub) { uint32_t mask = 0xFFFFFFFF << bitCheck; @@ -319,7 +320,7 @@ static void CO_LSSslave_serviceIdent( } if (ack) { LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; - CO_memset(&LSSslave->TXbuff->data[1], 0, 7); + memset(&LSSslave->TXbuff->data[1], 0, sizeof(LSSslave->TXbuff->data) - 1); CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); } } @@ -392,11 +393,11 @@ CO_ReturnError_t CO_LSSslave_init( return CO_ERROR_ILLEGAL_ARGUMENT; } - CO_memcpy((uint8_t*)&LSSslave->lssAddress, (uint8_t*)&lssAddress, sizeof(LSSslave->lssAddress)); + memcpy(&LSSslave->lssAddress, &lssAddress, sizeof(LSSslave->lssAddress)); LSSslave->lssState = CO_LSS_STATE_WAITING; - CO_memset((uint8_t*)&LSSslave->lssSelect, 0, sizeof(LSSslave->lssSelect)); + memset(&LSSslave->lssSelect, 0, sizeof(LSSslave->lssSelect)); - CO_memset((uint8_t*)&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); + memset(&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; LSSslave->pendingBitRate = pendingBitRate; diff --git a/example/eeprom.c b/example/eeprom.c index ad2b2a96..c8a0824f 100644 --- a/example/eeprom.c +++ b/example/eeprom.c @@ -26,6 +26,8 @@ */ +#include + #include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" @@ -49,7 +51,7 @@ static CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg){ if(!ODF_arg->reading){ /* don't change the old value */ - CO_memcpy(ODF_arg->data, (const uint8_t*)ODF_arg->ODdataStorage, 4U); + memcpy(ODF_arg->data, ODF_arg->ODdataStorage, 4); if(ODF_arg->subIndex == 1U){ if(value == 0x65766173UL){ @@ -86,7 +88,7 @@ static CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg){ if(!ODF_arg->reading){ /* don't change the old value */ - CO_memcpy(ODF_arg->data, (const uint8_t*)ODF_arg->ODdataStorage, 4U); + memcpy(ODF_arg->data, ODF_arg->ODdataStorage, 4); if(ODF_arg->subIndex >= 1U){ if(value == 0x64616F6CUL){ diff --git a/socketCAN/CO_OD_storage.c b/socketCAN/CO_OD_storage.c index dc6fee6c..e5e45586 100644 --- a/socketCAN/CO_OD_storage.c +++ b/socketCAN/CO_OD_storage.c @@ -49,7 +49,7 @@ CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg) { if(!ODF_arg->reading) { /* don't change the old value */ - CO_memcpy(ODF_arg->data, (const uint8_t*)ODF_arg->ODdataStorage, 4U); + memcpy(ODF_arg->data, ODF_arg->ODdataStorage, 4); if(ODF_arg->subIndex == 1) { /* store parameters */ @@ -79,7 +79,7 @@ CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg) { if(!ODF_arg->reading) { /* don't change the old value */ - CO_memcpy(ODF_arg->data, (const uint8_t*)ODF_arg->ODdataStorage, 4U); + memcpy(ODF_arg->data, ODF_arg->ODdataStorage, 4); if(ODF_arg->subIndex >= 1) { /* restore default parameters */ From aa6075b3c87895dc52d29b7970141d7806be1ac6 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Tue, 5 May 2020 13:23:26 +0200 Subject: [PATCH 060/520] Add CO_..._initCallbackPre() for RPDO and SYNC (#178) * Merge two parts of CO_PDO_receive() into single common code * Add CO_RPDO_initCallbackPre() for received RPDO messages This optional mechanism allows to immediatelly wake the thread that processes RPDO, without waiting for its next tick. * Add CO_SYNC_initCallbackPre() for received SYNC messages This optional mechanism allows to immediatelly wake the thread that processes SYNC, without waiting for its next tick. --- 301/CO_PDO.c | 59 ++++++++++++++++++++---------------- 301/CO_PDO.h | 25 +++++++++++++++ 301/CO_SYNC.c | 27 +++++++++++++++++ 301/CO_SYNC.h | 25 +++++++++++++++ 301/CO_config.h | 10 ++++-- example/CO_driver_target.h | 6 ++-- socketCAN/CO_driver_target.h | 6 ++-- 7 files changed, 126 insertions(+), 32 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index eb554ad4..7f989cfc 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -24,6 +24,8 @@ */ +#include + #include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" @@ -54,33 +56,19 @@ static void CO_PDO_receive(void *object, void *msg){ (DLC >= RPDO->dataLength)) { #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if(RPDO->SYNC && RPDO->synchronous && RPDO->SYNC->CANrxToggle) { - /* copy data into second buffer and set 'new message' flag */ - RPDO->CANrxData[1][0] = data[0]; - RPDO->CANrxData[1][1] = data[1]; - RPDO->CANrxData[1][2] = data[2]; - RPDO->CANrxData[1][3] = data[3]; - RPDO->CANrxData[1][4] = data[4]; - RPDO->CANrxData[1][5] = data[5]; - RPDO->CANrxData[1][6] = data[6]; - RPDO->CANrxData[1][7] = data[7]; - - CO_FLAG_SET(RPDO->CANrxNew[1]); - } - else { + const size_t index = RPDO->SYNC && RPDO->synchronous && RPDO->SYNC->CANrxToggle; +#else + const size_t index = 0; #endif - /* copy data into default buffer and set 'new message' flag */ - RPDO->CANrxData[0][0] = data[0]; - RPDO->CANrxData[0][1] = data[1]; - RPDO->CANrxData[0][2] = data[2]; - RPDO->CANrxData[0][3] = data[3]; - RPDO->CANrxData[0][4] = data[4]; - RPDO->CANrxData[0][5] = data[5]; - RPDO->CANrxData[0][6] = data[6]; - RPDO->CANrxData[0][7] = data[7]; - - CO_FLAG_SET(RPDO->CANrxNew[0]); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + + /* copy data into appropriate buffer and set 'new message' flag */ + memcpy(RPDO->CANrxData[index], data, sizeof(RPDO->CANrxData[index])); + CO_FLAG_SET(RPDO->CANrxNew[index]); + +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles RPDO. */ + if(RPDO->pFunctSignalPre != NULL) { + RPDO->pFunctSignalPre(RPDO->functSignalObjectPre); } #endif } @@ -773,6 +761,10 @@ CO_ReturnError_t CO_RPDO_init( RPDO->nodeId = nodeId; RPDO->defaultCOB_ID = defaultCOB_ID; RPDO->restrictionFlags = restrictionFlags; +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE + RPDO->pFunctSignalPre = NULL; + RPDO->functSignalObjectPre = NULL; +#endif /* Configure Object dictionary entry at index 0x1400+ and 0x1600+ */ CO_OD_configure(SDO, idx_RPDOCommPar, CO_ODF_RPDOcom, (void*)RPDO, 0, 0); @@ -793,6 +785,21 @@ CO_ReturnError_t CO_RPDO_init( } +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE +/******************************************************************************/ +void CO_RPDO_initCallbackPre( + CO_RPDO_t *RPDO, + void *object, + void (*pFunctSignalPre)(void *object)) +{ + if(RPDO != NULL){ + RPDO->functSignalObjectPre = object; + RPDO->pFunctSignalPre = pFunctSignalPre; + } +} +#endif + + /******************************************************************************/ CO_ReturnError_t CO_TPDO_init( CO_TPDO_t *TPDO, diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 64b0fe85..ce8783af 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -188,6 +188,12 @@ typedef struct{ #else volatile void *CANrxNew[1]; uint8_t CANrxData[1][8]; +#endif +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN + /** From CO_RPDO_initCallbackPre() or NULL */ + void (*pFunctSignalPre)(void *object); + /** From CO_RPDO_initCallbackPre() or NULL */ + void *functSignalObjectPre; #endif CO_CANmodule_t *CANdevRx; /**< From CO_RPDO_init() */ uint16_t CANdevRxIdx; /**< From CO_RPDO_init() */ @@ -280,6 +286,25 @@ CO_ReturnError_t CO_RPDO_init( uint16_t CANdevRxIdx); +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +/** + * Initialize RPDO callback function. + * + * Function initializes optional callback function, which should immediately + * start processing of CO_RPDO_process() function. + * Callback is called after RPDO message is received from the CAN bus. + * + * @param RPDO This object. + * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. + */ +void CO_RPDO_initCallbackPre( + CO_RPDO_t *RPDO, + void *object, + void (*pFunctSignalPre)(void *object)); +#endif + + /** * Initialize TPDO object. * diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index cb32a2ed..eb66fe0e 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -67,6 +67,13 @@ static void CO_SYNC_receive(void *object, void *msg) { } if(CO_FLAG_READ(SYNC->CANrxNew)) { SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; + +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles SYNC. */ + if(SYNC->pFunctSignalPre != NULL) { + SYNC->pFunctSignalPre(SYNC->functSignalObjectPre); + } +#endif } } } @@ -285,6 +292,11 @@ CO_ReturnError_t CO_SYNC_init( SYNC->CANdevRx = CANdevRx; SYNC->CANdevRxIdx = CANdevRxIdx; +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE + SYNC->pFunctSignalPre = NULL; + SYNC->functSignalObjectPre = NULL; +#endif + /* Configure Object dictionary entry at index 0x1005, 0x1006 and 0x1019 */ CO_OD_configure(SDO, OD_H1005_COBID_SYNC, CO_ODF_1005, (void*)SYNC, 0, 0); CO_OD_configure(SDO, OD_H1006_COMM_CYCL_PERIOD, CO_ODF_1006, (void*)SYNC, 0, 0); @@ -319,6 +331,21 @@ CO_ReturnError_t CO_SYNC_init( } +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE +/******************************************************************************/ +void CO_SYNC_initCallbackPre( + CO_SYNC_t *SYNC, + void *object, + void (*pFunctSignalPre)(void *object)) +{ + if(SYNC != NULL){ + SYNC->functSignalObjectPre = object; + SYNC->pFunctSignalPre = pFunctSignalPre; + } +} +#endif + + /******************************************************************************/ uint8_t CO_SYNC_process( CO_SYNC_t *SYNC, diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index e6a5db53..f92ec5be 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -96,6 +96,12 @@ typedef struct{ uint32_t timer; /** Set to nonzero value, if SYNC with wrong data length is received from CAN */ uint16_t receiveError; +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN + /** From CO_SYNC_initCallbackPre() or NULL */ + void (*pFunctSignalPre)(void *object); + /** From CO_SYNC_initCallbackPre() or NULL */ + void *functSignalObjectPre; +#endif CO_CANmodule_t *CANdevRx; /**< From CO_SYNC_init() */ uint16_t CANdevRxIdx; /**< From CO_SYNC_init() */ CO_CANmodule_t *CANdevTx; /**< From CO_SYNC_init() */ @@ -137,6 +143,25 @@ CO_ReturnError_t CO_SYNC_init( uint16_t CANdevTxIdx); +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +/** + * Initialize SYNC callback function. + * + * Function initializes optional callback function, which should immediately + * start processing of CO_SYNC_process() function. + * Callback is called after SYNC message is received from the CAN bus. + * + * @param SYNC This object. + * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. + */ +void CO_SYNC_initCallbackPre( + CO_SYNC_t *SYNC, + void *object, + void (*pFunctSignalPre)(void *object)); +#endif + + /** * Process SYNC communication. * diff --git a/301/CO_config.h b/301/CO_config.h index d98bad7a..d00acc6f 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -193,12 +193,15 @@ extern "C" { * Configuration of PDO * * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received RPDO CAN message. + * Callback is configured by CO_RPDO_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_TPDO_process(). * - CO_CONFIG_PDO_SYNC_ENABLE - Enable SYNC object inside PDO objects. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PDO (CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE) +#define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE) #endif #define CO_CONFIG_PDO_SYNC_ENABLE 0x01 @@ -207,11 +210,14 @@ extern "C" { * Configuration of SYNC * * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received SYNC CAN message. + * Callback is configured by CO_SYNC_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_SYNC_process(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_TIMERNEXT) +#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT) #endif diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index a2510714..da2ec4cd 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -78,12 +78,14 @@ extern "C" { #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO (CO_CONFIG_FLAG_TIMERNEXT | \ +#define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ CO_CONFIG_PDO_SYNC_ENABLE) #endif #ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_TIMERNEXT) +#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SDO_CLI diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index b46a7f5b..255055df 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -84,12 +84,14 @@ extern "C" { #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO (CO_CONFIG_FLAG_TIMERNEXT | \ +#define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ CO_CONFIG_PDO_SYNC_ENABLE) #endif #ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_TIMERNEXT) +#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SDO_CLI From 466bf0ffb7bed9c819454f7930ad68bce4f8db85 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Mon, 4 May 2020 17:56:11 +0200 Subject: [PATCH 061/520] Fix "comparison of integer expressions of different signedness" warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With -Wextra GCC gives: socketCAN/CO_driver.c: In function ‘setRxFilters’: socketCAN/CO_driver.c:159:19: warning: comparison of integer expressions of different signedness: ‘int’ and ‘uint32_t’ {aka ‘unsigned int’} [-Wsign-compare] 159 | for (i = 0; i < CANmodule->CANinterfaceCount; i ++) { | ^ --- socketCAN/CO_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 818a595e..662f6288 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -131,7 +131,7 @@ static CO_ReturnError_t disableRx(CO_CANmodule_t *CANmodule) static CO_ReturnError_t setRxFilters(CO_CANmodule_t *CANmodule) { int ret; - int i; + size_t i; int count; CO_ReturnError_t retval; From e88ecb894eb73d611e2e6685474d81cf9ffb435d Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Wed, 6 May 2020 16:29:23 +0200 Subject: [PATCH 062/520] Fix "unused parameter" warnings Some functions have a signature required by API, thus they have arguments which will be unused. Fix by casting to void. --- 305/CO_LSSmaster.c | 4 ++++ 305/CO_LSSslave.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 0771f487..2a94b8f5 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -811,6 +811,8 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanInitiate( CO_LSSmaster_scantype_t scan, CO_LSS_fastscan_lss_sub_next lssSub) { + (void)timeDifference_us; /* unused */ + LSSmaster->fsLssSub = lssSub; LSSmaster->fsIdNumber = 0; @@ -900,6 +902,8 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate( uint32_t idNumberCheck, CO_LSS_fastscan_lss_sub_next lssNext) { + (void)timeDifference_us; /* unused */ + switch (scan) { case CO_LSSmaster_FS_SCAN: /* ID obtained by scan */ diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 111bb696..0ad12641 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -38,6 +38,8 @@ static void CO_LSSslave_serviceSwitchStateGlobal( CO_LSS_cs_t service, void *msg) { + (void)service; /* unused */ + uint8_t *data = CO_CANrxMsg_readData(msg); uint8_t mode = data[1]; @@ -224,6 +226,8 @@ static void CO_LSSslave_serviceInquire( CO_LSS_cs_t service, void *msg) { + (void)msg; /* unused */ + uint32_t value; if(LSSslave->lssState != CO_LSS_STATE_CONFIGURATION) { @@ -485,6 +489,8 @@ void CO_LSSslave_process( uint16_t *pendingBitRate, uint8_t *pendingNodeId) { + (void)activeBitRate; /* unused */ + LSSslave->activeNodeID = activeNodeId; *pendingBitRate = LSSslave->pendingBitRate; *pendingNodeId = LSSslave->pendingNodeID; From 495f827d376fd44dc64693081556baf42e24d5fd Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Wed, 6 May 2020 18:00:28 +0200 Subject: [PATCH 063/520] Fix minor typo/edit mistakes in CHANGELOG.md and CO_config.h --- 301/CO_config.h | 4 ++-- doc/CHANGELOG.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_config.h b/301/CO_config.h index d00acc6f..60362af8 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -90,9 +90,9 @@ extern "C" { * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received NMT CAN message. + * Callback is configured by CO_NMT_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_NMT_process(). - * Callback is configured by CO_NMT_initCallbackPre(). * - CO_CONFIG_NMT_CALLBACK_CHANGE - Enable custom callback after NMT * state changes. Callback is configured by * CO_NMT_initCallbackChanged(). @@ -114,9 +114,9 @@ extern "C" { * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received SDO CAN message. + * Callback is configured by CO_SDO_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_SDO_process(). - * Callback is configured by CO_SDO_initCallbackPre(). * - CO_CONFIG_SDO_SEGMENTED - Enable SDO server segmented transfer. * - CO_CONFIG_SDO_BLOCK - Enable SDO server block transfer. If set, then * CO_CONFIG_SDO_SEGMENTED must also be set. diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 0ae2cdd4..f564f777 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -9,7 +9,7 @@ Change Log - All drivers removed from this project, except Neuberger-socketCAN for Linux. ### Changed - Directory structure rearranged. Before was all CANopen object files in `stack` directory, now they are in separate directories according to standard (`301`, `305`, `extra`, `socketCAN` for Linux driver). Include directives for that files now contain directory path. `CO_SDO` renamed to `CO_SDOserver` and `CO_SDOmaster` renamed to `CO_SDOclient`. Change of the project files will be necessary. -- Driver interface clarified. Before was pair of CO_driver.h/.c files for each microcontroller, now there is common CO_driver.h file. Drivers for other microcontrollers will be separate projects. Each driver must have own CO_driver_target.h file and function definitions from C_driver.h file. See documentation in CO_driver.h, example/CO_driver_target.h and example/CO_driver.c. There was no other mayor changes in driver interface. +- Driver interface clarified. Before was pair of CO_driver.h/.c files for each microcontroller, now there is common CO_driver.h file. Drivers for other microcontrollers will be separate projects. Each driver must have own CO_driver_target.h file and function definitions from C_driver.h file. See documentation in CO_driver.h, example/CO_driver_target.h and example/CO_driver.c. There was no other major changes in driver interface. - Time base is now microsecond in all functions. - CANopen.h/.c files simplified and changed. `CO_USE_GLOBALS` and `CO_init()` removed. Interface to those functions changed. - `CO_NMT_sendCommand()` master function renamed and moved from CANopen.c into CO_NMT_Heartbeat.c. From 9b8a296fb7e05c520679ad98bc05ac1f36f80e8b Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Wed, 6 May 2020 18:08:45 +0200 Subject: [PATCH 064/520] Add CO_TIME_initCallbackPre() for received TIME messages This optional mechanism allows to immediatelly wake the thread that processes TIME, without waiting for its next tick. --- 301/CO_TIME.c | 27 ++++++++++++++++++++++++++- 301/CO_TIME.h | 24 ++++++++++++++++++++++++ 301/CO_config.h | 12 ++++++++++++ example/CO_driver_target.h | 4 ++++ socketCAN/CO_driver_target.h | 4 ++++ 5 files changed, 70 insertions(+), 1 deletion(-) diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 838e2b4d..026f1771 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -46,11 +46,17 @@ static void CO_TIME_receive(void *object, void *msg){ TIME = (CO_TIME_t*)object; /* this is the correct pointer type of the first argument */ operState = *TIME->operatingState; - if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){ // Process Time from msg buffer memcpy(&TIME->Time.ullValue, data, DLC); CO_FLAG_SET(TIME->CANrxNew); + +#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles TIME. */ + if(TIME->pFunctSignalPre != NULL) { + TIME->pFunctSignalPre(TIME->functSignalObjectPre); + } +#endif } else{ TIME->receiveError = (uint16_t)DLC; @@ -96,6 +102,11 @@ CO_ReturnError_t CO_TIME_init( TIME->em = em; TIME->operatingState = operatingState; +#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE + TIME->pFunctSignalPre = NULL; + TIME->functSignalObjectPre = NULL; +#endif + /* configure TIME consumer message reception */ TIME->CANdevRx = CANdevRx; @@ -131,6 +142,20 @@ CO_ReturnError_t CO_TIME_init( return ret; } +#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE +/******************************************************************************/ +void CO_TIME_initCallbackPre( + CO_TIME_t *TIME, + void *object, + void (*pFunctSignalPre)(void *object)) +{ + if(TIME != NULL){ + TIME->functSignalObjectPre = object; + TIME->pFunctSignalPre = pFunctSignalPre; + } +} +#endif + /******************************************************************************/ uint8_t CO_TIME_process( CO_TIME_t *TIME, diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 8c6d5421..89a972df 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -99,6 +99,12 @@ typedef struct{ uint32_t timer; /** Set to nonzero value, if TIME with wrong data length is received from CAN */ uint16_t receiveError; +#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN + /** From CO_TIME_initCallbackPre() or NULL */ + void (*pFunctSignalPre)(void *object); + /** From CO_TIME_initCallbackPre() or NULL */ + void *functSignalObjectPre; +#endif CO_CANmodule_t *CANdevRx; /**< From CO_TIME_init() */ uint16_t CANdevRxIdx; /**< From CO_TIME_init() */ CO_CANmodule_t *CANdevTx; /**< From CO_TIME_init() */ @@ -137,6 +143,24 @@ CO_ReturnError_t CO_TIME_init( CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx); +#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +/** + * Initialize TIME callback function. + * + * Function initializes optional callback function, which should immediately + * start processing of CO_TIME_process() function. + * Callback is called after TIME message is received from the CAN bus. + * + * @param TIME This object. + * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. + */ +void CO_TIME_initCallbackPre( + CO_TIME_t *TIME, + void *object, + void (*pFunctSignalPre)(void *object)); +#endif + /** * Process TIME communication. * diff --git a/301/CO_config.h b/301/CO_config.h index 60362af8..70cd6fd7 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -262,6 +262,18 @@ extern "C" { #endif +/** + * Configuration of TIME + * + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received TIME CAN message. + * Callback is configured by CO_TIME_initCallbackPre(). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) +#endif + /** * Configuration of LSS master object * diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index da2ec4cd..ada8042e 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -100,6 +100,10 @@ extern "C" { #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 #endif +#ifndef CO_CONFIG_TIME +#define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) +#endif + #ifndef CO_CONFIG_LSS_MST #define CO_CONFIG_LSS_MST (CO_CONFIG_FLAG_CALLBACK_PRE) #endif diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 255055df..9335d0ef 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -106,6 +106,10 @@ extern "C" { #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 #endif +#ifndef CO_CONFIG_TIME +#define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) +#endif + #ifndef CO_CONFIG_LSS_MST #define CO_CONFIG_LSS_MST (CO_CONFIG_FLAG_CALLBACK_PRE) #endif From b4b0fe069f5462acdf0bd58238505b59b3a3d1b6 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Wed, 6 May 2020 18:22:50 +0200 Subject: [PATCH 065/520] Convert {T,R}PDO_CALLS_EXTENSION to CO_CONFIG_{T,R}PDO_CALLS_EXTENSION User can now enable extension callbacks in RPDO/TPDO handling paths simply by configuration flags instead of modifying sources or by passing the defines directly to the compiler. --- 301/CO_PDO.c | 14 ++++++-------- 301/CO_config.h | 8 +++++++- example/CO_driver_target.h | 4 +++- socketCAN/CO_driver_target.h | 4 +++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 7f989cfc..fb8b9f4f 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -891,14 +891,13 @@ uint8_t CO_TPDOisCOS(CO_TPDO_t *TPDO){ return 0; } -//#define TPDO_CALLS_EXTENSION /******************************************************************************/ int16_t CO_TPDOsend(CO_TPDO_t *TPDO){ int16_t i; uint8_t* pPDOdataByte; uint8_t** ppODdataByte; -#ifdef TPDO_CALLS_EXTENSION +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_CALLS_EXTENSION if(TPDO->SDO->ODExtensions){ /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ const uint32_t* pMap = &TPDO->TPDOMapPar->mappedObject1; @@ -940,7 +939,6 @@ int16_t CO_TPDOsend(CO_TPDO_t *TPDO){ return CO_CANsend(TPDO->CANdevTx, TPDO->CANtxBuff); } -//#define RPDO_CALLS_EXTENSION /******************************************************************************/ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ bool_t process_rpdo = true; @@ -959,9 +957,9 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ } else if(process_rpdo) { -#if defined(RPDO_CALLS_EXTENSION) +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION bool_t update = false; -#endif /* defined(RPDO_CALLS_EXTENSION) */ +#endif uint8_t bufNo = 0; @@ -987,11 +985,11 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ for(; i>0; i--) { **(ppODdataByte++) = *(pPDOdataByte++); } -#if defined(RPDO_CALLS_EXTENSION) +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION update = true; -#endif /* defined(RPDO_CALLS_EXTENSION) */ +#endif } -#ifdef RPDO_CALLS_EXTENSION +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION if(update && RPDO->SDO->ODExtensions){ int16_t i; /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ diff --git a/301/CO_config.h b/301/CO_config.h index 70cd6fd7..0fb5d027 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -199,11 +199,17 @@ extern "C" { * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_TPDO_process(). * - CO_CONFIG_PDO_SYNC_ENABLE - Enable SYNC object inside PDO objects. + * - CO_CONFIG_RPDO_CALLS_EXTENSION - Enable calling configured extension + * callbacks when received RPDO CAN message modifies OD entries. + * - CO_CONFIG_TPDO_CALLS_EXTENSION - Enable calling configured extension + * callbacks before TPDO CAN message is sent. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE) +#define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_RPDO_CALLS_EXTENSION | CO_CONFIG_TPDO_CALLS_EXTENSION) #endif #define CO_CONFIG_PDO_SYNC_ENABLE 0x01 +#define CO_CONFIG_RPDO_CALLS_EXTENSION 0x02 +#define CO_CONFIG_TPDO_CALLS_EXTENSION 0x04 /** diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index ada8042e..4dd55893 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -80,7 +80,9 @@ extern "C" { #ifndef CO_CONFIG_PDO #define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_PDO_SYNC_ENABLE) + CO_CONFIG_PDO_SYNC_ENABLE | \ + CO_CONFIG_RPDO_CALLS_EXTENSION | \ + CO_CONFIG_TPDO_CALLS_EXTENSION) #endif #ifndef CO_CONFIG_SYNC diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 9335d0ef..764b87f5 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -86,7 +86,9 @@ extern "C" { #ifndef CO_CONFIG_PDO #define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_PDO_SYNC_ENABLE) + CO_CONFIG_PDO_SYNC_ENABLE | \ + CO_CONFIG_RPDO_CALLS_EXTENSION | \ + CO_CONFIG_TPDO_CALLS_EXTENSION) #endif #ifndef CO_CONFIG_SYNC From 0048cb52c7d7ce0dc1545a4e543110c544827c2b Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Tue, 12 May 2020 17:24:06 +0200 Subject: [PATCH 066/520] Fix pointer bug in CO_OD_getFlagsPointer() (#181) Function did not check whether the object had any flags assigned. It makes no difference for objects with no subindexes, because then the function will return NULL anyway. But is subIndex argument is not zero, then the function calculates addresses of flags as offsets from NULL. For example, for an object with no flags assigned, when subIndex == 5, the function would return 5 as the address instead of the expected NULL. --- 301/CO_SDOserver.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index edebb4df..ac339685 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -451,13 +451,14 @@ void* CO_OD_getDataPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ /******************************************************************************/ uint8_t* CO_OD_getFlagsPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ - CO_OD_extension_t* ext; - - if((entryNo == 0xFFFFU) || (SDO->ODExtensions == 0)){ - return 0; + if(entryNo == 0xFFFF || SDO->ODExtensions == NULL){ + return NULL; } - ext = &SDO->ODExtensions[entryNo]; + CO_OD_extension_t* ext = &SDO->ODExtensions[entryNo]; + if (ext->flags == NULL){ + return NULL; + } return &ext->flags[subIndex]; } From 61fc785fab65f840a177a03cc0641fa9d226d6c9 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 12 May 2020 17:35:16 +0200 Subject: [PATCH 067/520] CO_SYNC_process: use enums instead of uint8_t (#182) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace hard-coded values with enums and explicit manage all enumeration values in CO_process_SYNC() to avoid warnings like this: CANopen.c:837:5: warning: enumeration value ‘CO_SYNC_NONE’ not handled in switch [-Wswitch] 837 | switch (sync_process) { | ^~~~~~ --- 301/CO_SYNC.c | 10 +++++----- 301/CO_SYNC.h | 11 +++++++---- CANopen.c | 20 +++++++++++++------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index eb66fe0e..fde093a8 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -347,13 +347,13 @@ void CO_SYNC_initCallbackPre( /******************************************************************************/ -uint8_t CO_SYNC_process( +CO_SYNC_status_t CO_SYNC_process( CO_SYNC_t *SYNC, uint32_t timeDifference_us, uint32_t ObjDict_synchronousWindowLength, uint32_t *timerNext_us) { - uint8_t ret = 0; + CO_SYNC_status_t ret = CO_SYNC_NONE; uint32_t timerNew; if(*SYNC->operatingState == CO_NMT_OPERATIONAL || *SYNC->operatingState == CO_NMT_PRE_OPERATIONAL){ @@ -364,7 +364,7 @@ uint8_t CO_SYNC_process( /* was SYNC just received */ if(CO_FLAG_READ(SYNC->CANrxNew)){ SYNC->timer = 0; - ret = 1; + ret = CO_SYNC_RECEIVED; CO_FLAG_CLEAR(SYNC->CANrxNew); } @@ -373,7 +373,7 @@ uint8_t CO_SYNC_process( if(SYNC->timer >= SYNC->periodTime){ if(++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1; SYNC->timer = 0; - ret = 1; + ret = CO_SYNC_RECEIVED; SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; SYNC->CANtxBuff->data[0] = SYNC->counter; CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff); @@ -393,7 +393,7 @@ uint8_t CO_SYNC_process( if(ObjDict_synchronousWindowLength){ if(SYNC->timer > ObjDict_synchronousWindowLength){ if(SYNC->curentSyncTimeIsInsideWindow){ - ret = 2; + ret = CO_SYNC_OUTSIDE_WINDOW; } SYNC->curentSyncTimeIsInsideWindow = false; } diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index f92ec5be..e76de8b4 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -109,6 +109,11 @@ typedef struct{ uint16_t CANdevTxIdx; /**< From CO_SYNC_init() */ }CO_SYNC_t; +typedef enum { + CO_SYNC_NONE = 0, /**< SYNC not received */ + CO_SYNC_RECEIVED = 1, /**< SYNC received */ + CO_SYNC_OUTSIDE_WINDOW = 2, /**< SYNC received outside SYNC window */ +}CO_SYNC_status_t; /** * Initialize SYNC object. @@ -173,11 +178,9 @@ void CO_SYNC_initCallbackPre( * Object dictionary (index 0x1007). * @param [out] timerNext_us info to OS - see CO_process_SYNC_PDO(). * - * @return 0: No special meaning. - * @return 1: New SYNC message recently received or was just transmitted. - * @return 2: SYNC time was just passed out of window. + * @return #CO_SYNC_status_t: CO_SYNC_NONE, CO_SYNC_RECEIVED or CO_SYNC_OUTSIDE_WINDOW. */ -uint8_t CO_SYNC_process( +CO_SYNC_status_t CO_SYNC_process( CO_SYNC_t *SYNC, uint32_t timeDifference_us, uint32_t ObjDict_synchronousWindowLength, diff --git a/CANopen.c b/CANopen.c index bc8dc16e..80d0b7bc 100644 --- a/CANopen.c +++ b/CANopen.c @@ -826,18 +826,24 @@ bool_t CO_process_SYNC(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { - bool_t syncWas = false; - uint8_t sync_process = CO_SYNC_process(co->SYNC, - timeDifference_us, - OD_synchronousWindowLength, - timerNext_us); + bool_t syncWas; + CO_SYNC_status_t sync_process; + + sync_process = CO_SYNC_process(co->SYNC, + timeDifference_us, + OD_synchronousWindowLength, + timerNext_us); switch (sync_process) { - case 1: // immediately after the SYNC message + case CO_SYNC_NONE: + syncWas = false; + break; + case CO_SYNC_RECEIVED: syncWas = true; break; - case 2: // outside SYNC window + case CO_SYNC_OUTSIDE_WINDOW: CO_CANclearPendingSyncPDOs(co->CANmodule[0]); + syncWas = false; break; } From b5bfeec42a61f846ee3390489382a70029525ea6 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 12 May 2020 18:11:43 +0200 Subject: [PATCH 068/520] Added CANopen gateway-ascii command interface according to CiA309-3 as a microcontroller independent module. It includes NMT master, LSS master and SDO client interface. Interface is non-blocking, it is added to mainline. Example for Linux stdio and socket is included. Added CO_fifo.h/c for fifo data buffer, used with rewritten SDO client, etc SDO client is rewritten. Now includes r/w fifo interface to transfer data. doc/gettingStarted.md is updated. --- 301/CO_NMT_Heartbeat.h | 3 + 301/CO_SDOclient.c | 1945 ++++++++++++++++++---------------- 301/CO_SDOclient.h | 366 ++++--- 301/CO_SDOserver.h | 27 +- 301/CO_config.h | 24 +- 301/CO_driver.h | 18 +- 301/CO_fifo.c | 1159 ++++++++++++++++++++ 301/CO_fifo.h | 476 +++++++++ 309/CO_gateway_ascii.c | 1103 +++++++++++++++++++ 309/CO_gateway_ascii.h | 404 +++++++ CANopen.c | 44 +- CANopen.h | 6 + Makefile | 2 + doc/CHANGELOG.md | 5 +- doc/gettingStarted.md | 222 ++-- example/CO_OD.c | 7 + example/CO_OD.h | 15 +- example/CO_driver_target.h | 12 +- example/Makefile | 2 + example/_project.xml | 4 +- socketCAN/CO_Linux_threads.c | 443 ++++++-- socketCAN/CO_Linux_threads.h | 26 +- socketCAN/CO_OD_storage.c | 4 +- socketCAN/CO_driver_target.h | 22 +- socketCAN/CO_error_msgs.h | 26 +- socketCAN/CO_main_basic.c | 156 ++- 26 files changed, 5103 insertions(+), 1418 deletions(-) create mode 100644 301/CO_fifo.c create mode 100644 301/CO_fifo.h create mode 100644 309/CO_gateway_ascii.c create mode 100644 309/CO_gateway_ascii.h diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 2fd306c0..014699f7 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -27,6 +27,9 @@ #ifndef CO_NMT_HEARTBEAT_H #define CO_NMT_HEARTBEAT_H +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index c0be479f..f1bddb24 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -5,7 +5,7 @@ * @ingroup CO_SDOclient * @author Janez Paternoster * @author Matej Severkar - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -25,67 +25,26 @@ */ -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" #include "301/CO_SDOclient.h" +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK #include "301/crc16-ccitt.h" +#endif -/* Client command specifier */ -#define CCS_DOWNLOAD_INITIATE 1 -#define CCS_DOWNLOAD_SEGMENT 0 - -#define CCS_UPLOAD_INITIATE 2 -#define CCS_UPLOAD_SEGMENT 3 - -#define CCS_ABORT 4 - -#define CCS_UPLOAD_BLOCK 5 -#define CCS_DOWNLOAD_BLOCK 6 - -/* Server Command Specifier */ -#define SCS_UPLOAD_INITIATE 2 -#define SCS_UPLOAD_SEGMENT 0 - -#define SCS_DOWNLOAD_INITIATED 3 -#define SCS_DOWNLOAD_SEGMENT 1 - -#define SCS_ABORT 4 - -#define SCS_DOWNLOAD_BLOCK 5 -#define SCS_UPLOAD_BLOCK 6 - - -/* client states */ -#define SDO_STATE_NOTDEFINED 0 -#define SDO_STATE_ABORT 1 - -/* DOWNLOAD EXPEDITED/SEGMENTED */ -#define SDO_STATE_DOWNLOAD_INITIATE 10 -#define SDO_STATE_DOWNLOAD_REQUEST 11 -#define SDO_STATE_DOWNLOAD_RESPONSE 12 - -/* UPLOAD EXPEDITED/SEGMENTED */ -#define SDO_STATE_UPLOAD_INITIATED 20 -#define SDO_STATE_UPLOAD_REQUEST 21 -#define SDO_STATE_UPLOAD_RESPONSE 22 +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) && \ + !((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) +#error If CO_CONFIG_SDO_CLI_BLOCK is enabled, then CO_CONFIG_SDO_CLI_SEGMENTED \ + must be enabled also! +#endif +#if CO_CONFIG_SDO_CLI_BUFFER_SIZE < 7 +#error CO_CONFIG_SDO_CLI_BUFFER_SIZE must be set to 7 or more! +#endif -/* DOWNLOAD BLOCK */ -#define SDO_STATE_BLOCKDOWNLOAD_INITIATE 100 -#define SDO_STATE_BLOCKDOWNLOAD_INPROGRES 101 -#define SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK 102 -#define SDO_STATE_BLOCKDOWNLOAD_CRC 103 -#define SDO_STATE_BLOCKDOWNLOAD_CRC_ACK 104 -/* UPLOAD BLOCK */ -#define SDO_STATE_BLOCKUPLOAD_INITIATE 200 -#define SDO_STATE_BLOCKUPLOAD_INITIATE_ACK 201 -#define SDO_STATE_BLOCKUPLOAD_INPROGRES 202 -#define SDO_STATE_BLOCKUPLOAD_SUB_END 203 -#define SDO_STATE_BLOCKUPLOAD_BLOCK_ACK 204 -#define SDO_STATE_BLOCKUPLOAD_BLOCK_ACK_LAST 205 -#define SDO_STATE_BLOCKUPLOAD_BLOCK_CRC 206 -#define SDO_STATE_BLOCKUPLOAD_BLOCK_END 207 +/* default 'protocol switch threshold' size for block transfer */ +#ifndef CO_CONFIG_SDO_CLI_PST +#define CO_CONFIG_SDO_CLI_PST 21 +#endif /* @@ -95,122 +54,146 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_SDOclient_receive(void *object, void *msg){ +static void CO_SDOclient_receive(void *object, void *msg) { CO_SDOclient_t *SDO_C; uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); - SDO_C = (CO_SDOclient_t*)object; /* this is the correct pointer type of the first argument */ + /* change void pointer to correct object type */ + SDO_C = (CO_SDOclient_t*)object; - /* verify message length and message overflow (previous message was not processed yet) */ - if((DLC == 8U) && (!CO_FLAG_READ(SDO_C->CANrxNew)) && (SDO_C->state != SDO_STATE_NOTDEFINED)){ - if(SDO_C->state != SDO_STATE_BLOCKUPLOAD_INPROGRES) { + /* verify idle state, message length and message overflow (previous message + * was not processed yet) */ + if (SDO_C->state != CO_SDO_ST_IDLE && DLC == 8U + && !CO_FLAG_READ(SDO_C->CANrxNew) + ) { +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + if (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { +#endif /* copy data and set 'new message' flag */ - SDO_C->CANrxData[0] = data[0]; - SDO_C->CANrxData[1] = data[1]; - SDO_C->CANrxData[2] = data[2]; - SDO_C->CANrxData[3] = data[3]; - SDO_C->CANrxData[4] = data[4]; - SDO_C->CANrxData[5] = data[5]; - SDO_C->CANrxData[6] = data[6]; - SDO_C->CANrxData[7] = data[7]; - + memcpy((void *)&SDO_C->CANrxData[0], (const void *)&data[0], 8); CO_FLAG_SET(SDO_C->CANrxNew); +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles + * SDO client processing. */ + if (SDO_C->pFunctSignal != NULL) { + SDO_C->pFunctSignal(SDO_C->functSignalObject); + } +#endif + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK } else { /* block upload, copy data directly */ + CO_SDO_state_t state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; uint8_t seqno; - SDO_C->CANrxData[0] = data[0]; - seqno = SDO_C->CANrxData[0] & 0x7f; + seqno = data[0] & 0x7F; SDO_C->timeoutTimer = 0; - SDO_C->timeoutTimerBLOCK = 0; - - /* check correct sequence number. */ - if(seqno == (SDO_C->block_seqno + 1)) { - /* block_seqno is correct */ - uint8_t i; - - SDO_C->block_seqno++; + SDO_C->block_timeoutTimer = 0; - /* copy data */ - for(i=1; i<8; i++) { - SDO_C->buffer[SDO_C->dataSizeTransfered++] = data[i]; - if(SDO_C->dataSizeTransfered >= SDO_C->bufferSize) { - /* buffer full, break reception */ - SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - CO_FLAG_SET(SDO_C->CANrxNew); - break; - } + /* break sub-block if sequence number is too large */ + if (seqno > SDO_C->block_blksize) { + state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; + } + /* verify if sequence number is correct */ + else if (seqno == (SDO_C->block_seqno + 1)) { + SDO_C->block_seqno = seqno; + + /* is this the last segment? */ + if ((data[0] & 0x80) != 0) { + /* copy data to temporary buffer, because we don't know the + * number of bytes not containing data */ + memcpy((void *)&SDO_C->block_dataUploadLast[0], + (const void *)&data[1], 7); + SDO_C->finished = true; + state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; } - - /* break reception if last segment or block sequence is too large */ - if(((SDO_C->CANrxData[0] & 0x80U) == 0x80U) || (SDO_C->block_seqno >= SDO_C->block_blksize)) { - SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - CO_FLAG_SET(SDO_C->CANrxNew); + else { + /* Copy data. There is always enough space in fifo buffer, + * because block_seqno was calculated before */ + CO_fifo_write(&SDO_C->bufFifo, + (const char *)&data[1], + 7, &SDO_C->block_crc); + SDO_C->sizeTran += 7; + /* all segments in sub-block has been transferred */ + if (seqno == SDO_C->block_blksize) { + state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; + } } } - else if((seqno == SDO_C->block_seqno) || (SDO_C->block_seqno == 0U)){ - /* Ignore message, if it is duplicate or if sequence didn't started yet. */ + else if (seqno == SDO_C->block_seqno || SDO_C->block_seqno == 0U) { + /* Ignore message, if it is duplicate or if sequence didn't + * start yet. */ } else { - /* seqno is totally wrong, break reception. */ - SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END; - CO_FLAG_SET(SDO_C->CANrxNew); + /* seqno is totally wrong, break sub-block. Data after last good + * seqno will be re-transmitted. */ + state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; } - } - + if (state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { + /* SDO_C->state has changed, processing will continue in another + * thread. Make memory barrier here with CO_FLAG_CLEAR() call.*/ + CO_FLAG_CLEAR(SDO_C->CANrxNew); + SDO_C->state = state; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles SDO client. */ - if(CO_FLAG_READ(SDO_C->CANrxNew) && SDO_C->pFunctSignal != NULL) { - SDO_C->pFunctSignal(SDO_C->functSignalObject); - } + /* Optional signal to RTOS, which can resume task, which handles + * SDO client processing. */ + if (SDO_C->pFunctSignal != NULL) { + SDO_C->pFunctSignal(SDO_C->functSignalObject); + } #endif + } + } +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ } } /******************************************************************************/ -CO_ReturnError_t CO_SDOclient_init( - CO_SDOclient_t *SDO_C, - CO_SDO_t *SDO, - CO_SDOclientPar_t *SDOClientPar, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx) +CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, + void *SDO, + CO_SDOclientPar_t *SDOClientPar, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx) { /* verify arguments */ - if(SDO_C==NULL || SDO==NULL || SDOClientPar==NULL || SDOClientPar->maxSubIndex!=3 || - CANdevRx==NULL || CANdevTx==NULL){ + if (SDO_C == NULL || SDOClientPar == NULL || SDOClientPar->maxSubIndex != 3 + || CANdevRx==NULL || CANdevTx==NULL + ) { return CO_ERROR_ILLEGAL_ARGUMENT; } /* Configure object variables */ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - - SDO_C->pst = 21; /* block transfer */ - SDO_C->block_size_max = 127; /* block transfer */ - - SDO_C->SDO = SDO; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL + SDO_C->SDO = (CO_SDO_t *)SDO; +#endif SDO_C->SDOClientPar = SDOClientPar; + SDO_C->CANdevRx = CANdevRx; + SDO_C->CANdevRxIdx = CANdevRxIdx; + SDO_C->CANdevTx = CANdevTx; + SDO_C->CANdevTxIdx = CANdevTxIdx; + + /* prepare circular fifo buffer */ + CO_fifo_init(&SDO_C->bufFifo, SDO_C->buf, + CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1); #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE SDO_C->pFunctSignal = NULL; SDO_C->functSignalObject = NULL; #endif - SDO_C->CANdevRx = CANdevRx; - SDO_C->CANdevRxIdx = CANdevRxIdx; - SDO_C->CANdevTx = CANdevTx; - SDO_C->CANdevTxIdx = CANdevTxIdx; + SDO_C->state = CO_SDO_ST_IDLE; + CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->COB_IDClientToServerPrev = 0; SDO_C->COB_IDServerToClientPrev = 0; - CO_SDOclient_setup(SDO_C, SDO_C->SDOClientPar->COB_IDClientToServer, - SDO_C->SDOClientPar->COB_IDServerToClient, - SDO_C->SDOClientPar->nodeIDOfTheSDOServer); + CO_SDOclient_setup(SDO_C, + SDO_C->SDOClientPar->COB_IDClientToServer, + SDO_C->SDOClientPar->COB_IDServerToClient, + SDO_C->SDOClientPar->nodeIDOfTheSDOServer); return CO_ERROR_NO; } @@ -218,12 +201,11 @@ CO_ReturnError_t CO_SDOclient_init( #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ -void CO_SDOclient_initCallbackPre( - CO_SDOclient_t *SDOclient, - void *object, - void (*pFunctSignal)(void *object)) +void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, + void *object, + void (*pFunctSignal)(void *object)) { - if(SDOclient != NULL){ + if (SDOclient != NULL) { SDOclient->functSignalObject = object; SDOclient->pFunctSignal = pFunctSignal; } @@ -232,39 +214,43 @@ void CO_SDOclient_initCallbackPre( /******************************************************************************/ -CO_SDOclient_return_t CO_SDOclient_setup( - CO_SDOclient_t *SDO_C, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient, - uint8_t nodeIDOfTheSDOServer) +CO_SDOclient_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, + uint32_t COB_IDClientToServer, + uint32_t COB_IDServerToClient, + uint8_t nodeIDOfTheSDOServer) { uint32_t idCtoS, idStoC; uint8_t idNode; /* verify parameters */ - if(SDO_C == NULL || (COB_IDClientToServer&0x7FFFF800L) != 0 || - (COB_IDServerToClient&0x7FFFF800L) != 0 || nodeIDOfTheSDOServer > 127) - { + if (SDO_C == NULL + || (COB_IDClientToServer & 0x7FFFF800L) != 0 + || (COB_IDServerToClient & 0x7FFFF800L) != 0 + || nodeIDOfTheSDOServer > 127 + ) { return CO_SDOcli_wrongArguments; } /* Configure object variables */ - SDO_C->state = SDO_STATE_NOTDEFINED; + SDO_C->state = CO_SDO_ST_IDLE; CO_FLAG_CLEAR(SDO_C->CANrxNew); /* setup Object Dictionary variables */ - if((COB_IDClientToServer & 0x80000000L) != 0 || (COB_IDServerToClient & 0x80000000L) != 0 || nodeIDOfTheSDOServer == 0){ + if ((COB_IDClientToServer & 0x80000000L) != 0 + || (COB_IDServerToClient & 0x80000000L) != 0 + || nodeIDOfTheSDOServer == 0 + ) { /* SDO is NOT used */ idCtoS = 0x80000000L; idStoC = 0x80000000L; idNode = 0; } - else{ - if(COB_IDClientToServer == 0 || COB_IDServerToClient == 0){ + else { + if (COB_IDClientToServer == 0 || COB_IDServerToClient == 0) { idCtoS = 0x600 + nodeIDOfTheSDOServer; idStoC = 0x580 + nodeIDOfTheSDOServer; } - else{ + else { idCtoS = COB_IDClientToServer; idStoC = COB_IDServerToClient; } @@ -276,24 +262,26 @@ CO_SDOclient_return_t CO_SDOclient_setup( SDO_C->SDOClientPar->nodeIDOfTheSDOServer = idNode; /* configure SDO client CAN reception, if differs. */ - if(SDO_C->COB_IDClientToServerPrev != idCtoS || SDO_C->COB_IDServerToClientPrev != idStoC) { + if (SDO_C->COB_IDClientToServerPrev != idCtoS + || SDO_C->COB_IDServerToClientPrev != idStoC + ) { CO_ReturnError_t ret = CO_CANrxBufferInit( - SDO_C->CANdevRx, /* CAN device */ - SDO_C->CANdevRxIdx, /* rx buffer index */ - (uint16_t)idStoC, /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void*)SDO_C, /* object passed to receive function */ - CO_SDOclient_receive); /* this function will process received message */ + SDO_C->CANdevRx, /* CAN device */ + SDO_C->CANdevRxIdx, /* rx buffer index */ + (uint16_t)idStoC, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)SDO_C, /* object passed to receive function */ + CO_SDOclient_receive); /* this function will process rx msg */ /* configure SDO client CAN transmission */ SDO_C->CANtxBuff = CO_CANtxBufferInit( - SDO_C->CANdevTx, /* CAN device */ - SDO_C->CANdevTxIdx, /* index of specific buffer inside CAN module */ - (uint16_t)idCtoS, /* CAN identifier */ - 0, /* rtr */ - 8, /* number of data bytes */ - 0); /* synchronous message flag bit */ + SDO_C->CANdevTx, /* CAN device */ + SDO_C->CANdevTxIdx, /* index of buffer inside CAN module */ + (uint16_t)idCtoS, /* CAN identifier */ + 0, /* rtr */ + 8, /* number of data bytes */ + 0); /* synchronous message flag bit */ SDO_C->COB_IDClientToServerPrev = idCtoS; SDO_C->COB_IDServerToClientPrev = idStoC; @@ -307,324 +295,307 @@ CO_SDOclient_return_t CO_SDOclient_setup( } -/******************************************************************************/ -static void CO_SDOclient_abort(CO_SDOclient_t *SDO_C, uint32_t code){ - SDO_C->CANtxBuff->data[0] = 0x80; - SDO_C->CANtxBuff->data[1] = SDO_C->index & 0xFF; - SDO_C->CANtxBuff->data[2] = (SDO_C->index>>8) & 0xFF; - SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &code); - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); -} - - -/******************************************************************************/ -static void CO_SDOTxBufferClear(CO_SDOclient_t *SDO_C) { - uint16_t i; - - for(i=0; i<8; i++) { - SDO_C->CANtxBuff->data[i] = 0; - } - SDO_C->CANtxBuff->bufferFull = 0; -} - - -/******************************************************************************* - * - * DOWNLOAD - * - * +/****************************************************************************** + * DOWNLOAD * ******************************************************************************/ -CO_SDOclient_return_t CO_SDOclientDownloadInitiate( - CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - uint8_t *dataTx, - uint32_t dataSize, - uint16_t SDOtimeoutTime_ms, - uint8_t blockEnable, - uint32_t *timerNext_us) +CO_SDOclient_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, + uint16_t index, + uint8_t subIndex, + size_t sizeIndicated, + uint16_t SDOtimeoutTime_ms, + bool_t blockEnable) { /* verify parameters */ - if(SDO_C == NULL || dataTx == 0 || dataSize == 0) { + if (SDO_C == NULL) { return CO_SDOcli_wrongArguments; } /* save parameters */ - SDO_C->buffer = dataTx; - SDO_C->bufferSize = dataSize; - SDO_C->SDOtimeoutTimeHalf_us = (uint32_t)SDOtimeoutTime_ms * 500; - SDO_C->SDOtimeoutTime_us = SDO_C->SDOtimeoutTimeHalf_us * 2; - - SDO_C->state = SDO_STATE_DOWNLOAD_INITIATE; - - /* prepare CAN tx message */ - CO_SDOTxBufferClear(SDO_C); - SDO_C->index = index; SDO_C->subIndex = subIndex; - SDO_C->CANtxBuff->data[1] = index & 0xFF; - SDO_C->CANtxBuff->data[2] = index >> 8; - SDO_C->CANtxBuff->data[3] = subIndex; - - /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ - if(SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ - -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT - /* Optional signal to RTOS. We can immediately continue SDO Client */ - if(timerNext_us != NULL) { - *timerNext_us = 0; - } -#endif - - return CO_SDOcli_ok_communicationEnd; - } - - if(dataSize <= 4){ - uint16_t i; - /* expedited transfer */ - SDO_C->CANtxBuff->data[0] = 0x23 | ((4-dataSize) << 2); - - /* copy data */ - for(i=dataSize+3; i>=4; i--) SDO_C->CANtxBuff->data[i] = dataTx[i-4]; + SDO_C->sizeInd = sizeIndicated; + SDO_C->sizeTran = 0; + SDO_C->finished = false; + SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; + SDO_C->timeoutTimer = 0; + CO_fifo_reset(&SDO_C->bufFifo); + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL + /* if node-ID of the SDO server is the same as node-ID of this node, then + * transfer data within this node */ + if (SDO_C->SDO != NULL + && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId + ) { + SDO_C->state = CO_SDO_ST_LOCAL_TRANSFER; } - else if((SDO_C->bufferSize > SDO_C->pst) && blockEnable != 0){ /* BLOCK transfer */ - /* set state of block transfer */ - SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_INITIATE; - - /* init HEAD of packet */ - SDO_C->CANtxBuff->data[0] = CCS_DOWNLOAD_BLOCK<<5; - /* set flag for CRC */ - SDO_C->CANtxBuff->data[0] |= 0x01<<2; - - /* size indicator: */ - SDO_C->CANtxBuff->data[0] |= 0x01<<1; - /* set length of data */ - SDO_C->CANtxBuff->data[4] = (uint8_t) dataSize; - SDO_C->CANtxBuff->data[5] = (uint8_t) (dataSize >> 8); - SDO_C->CANtxBuff->data[6] = (uint8_t) (dataSize >> 16); - SDO_C->CANtxBuff->data[7] = (uint8_t) (dataSize >> 24); - + else +#endif +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + if (blockEnable && (sizeIndicated == 0 || + sizeIndicated > CO_CONFIG_SDO_CLI_PST) + ) { + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ; } - else{ - uint32_t len; - /* segmented transfer */ - SDO_C->CANtxBuff->data[0] = 0x21; - len = dataSize; - CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &len); + else +#endif + { + SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; } - /* empty receive buffer, reset timeout timer and send message */ CO_FLAG_CLEAR(SDO_C->CANrxNew); - SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); return CO_SDOcli_ok_communicationEnd; } -/******************************************************************************/ -CO_SDOclient_return_t CO_SDOclientDownload( - CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - uint32_t *pSDOabortCode, - uint32_t *timerNext_us) +void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, + size_t sizeIndicated) { - CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse; - - /* verify parameters */ - if(SDO_C == NULL) { - return CO_SDOcli_wrongArguments; + if (SDO_C != NULL) { + SDO_C->sizeInd = sizeIndicated; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ + && sizeIndicated > 0 && sizeIndicated <= CO_CONFIG_SDO_CLI_PST + ) { + SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; + } +#endif } +} - /* clear abort code */ - *pSDOabortCode = CO_SDO_AB_NONE; - - /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ - if(SDO_C->SDO && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - /* If SDO server is busy return error */ - if(SDO_C->SDO->state != 0){ - return CO_SDOcli_endedWithClientAbort; - } +/******************************************************************************/ +size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, + const char *buf, + size_t count) +{ + size_t ret = 0; + if (SDO_C != NULL && buf != NULL) { + ret = CO_fifo_write(&SDO_C->bufFifo, buf, count, NULL); + } + return ret; +} - /* init ODF_arg */ - *pSDOabortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index, SDO_C->subIndex); - if((*pSDOabortCode) != CO_SDO_AB_NONE){ - return CO_SDOcli_endedWithServerAbort; - } - /* set buffer */ - SDO_C->SDO->ODF_arg.data = SDO_C->buffer; +/******************************************************************************/ +CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, + uint32_t timeDifference_us, + bool_t abort, + CO_SDO_abortCode_t *SDOabortCode, + size_t *sizeTransferred, + uint32_t *timerNext_us) +{ + CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse; + CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; - /* write data to the Object dictionary */ - *pSDOabortCode = CO_SDO_writeOD(SDO_C->SDO, SDO_C->bufferSize); - if((*pSDOabortCode) != CO_SDO_AB_NONE){ - return CO_SDOcli_endedWithServerAbort; + if (SDO_C == NULL) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + ret = CO_SDOcli_wrongArguments; + } + else if (SDO_C->state == CO_SDO_ST_IDLE) { + ret = CO_SDOcli_ok_communicationEnd; + } + else if (abort) { + abortCode = + (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL + /* Transfer data locally **************************************************/ + else if (SDO_C->state == CO_SDO_ST_LOCAL_TRANSFER) { + if (SDO_C->SDO->state != CO_SDO_ST_IDLE) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + ret = CO_SDOcli_endedWithClientAbort; } + else { + /* Max data size is limited to fifo size (for now). */ + size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo); - return CO_SDOcli_ok_communicationEnd; + if (SDO_C->sizeInd > 0 && SDO_C->sizeInd != count) { + abortCode = CO_SDO_AB_TYPE_MISMATCH; + ret = CO_SDOcli_endedWithClientAbort; + } + else { + /* init ODF_arg */ + abortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index, + SDO_C->subIndex); + if (abortCode == CO_SDO_AB_NONE) { + /* set buffer and write data to the Object dictionary */ + SDO_C->SDO->ODF_arg.data = (uint8_t *)SDO_C->buf; + abortCode = CO_SDO_writeOD(SDO_C->SDO, count); + } + if (abortCode == CO_SDO_AB_NONE) { + SDO_C->sizeTran = count; + ret = CO_SDOcli_ok_communicationEnd; + } + else { + ret = CO_SDOcli_endedWithServerAbort; + } + } + } + SDO_C->state = CO_SDO_ST_IDLE; } - - -/* RX data ****************************************************************************************** */ - if(CO_FLAG_READ(SDO_C->CANrxNew)){ - uint8_t SCS = SDO_C->CANrxData[0]>>5; /* Client command specifier */ - - /* ABORT */ - if (SDO_C->CANrxData[0] == (SCS_ABORT<<5)){ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_memcpySwap4(pSDOabortCode , &SDO_C->CANrxData[4]); - CO_FLAG_CLEAR(SDO_C->CANrxNew); - return CO_SDOcli_endedWithServerAbort; +#endif + /* CAN data received ******************************************************/ + else if (CO_FLAG_READ(SDO_C->CANrxNew)) { + /* is SDO abort */ + if (SDO_C->CANrxData[0] == 0x80) { + uint32_t code; + CO_memcpySwap4(&code , &SDO_C->CANrxData[4]); + abortCode = (CO_SDO_abortCode_t)code; + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_endedWithServerAbort; } + else switch (SDO_C->state) { + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { + if (SDO_C->CANrxData[0] == 0x60) { + /* verify index and subindex */ + uint16_t index; + uint8_t subindex; + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if (index != SDO_C->index || subindex != SDO_C->subIndex) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - switch (SDO_C->state){ - - case SDO_STATE_DOWNLOAD_INITIATE:{ - - if (SCS == SCS_DOWNLOAD_INITIATED){ - if(SDO_C->bufferSize <= 4){ +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED + if (SDO_C->finished) { /* expedited transfer */ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - return CO_SDOcli_ok_communicationEnd; + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_ok_communicationEnd; } - else{ + else { /* segmented transfer - prepare the first segment */ - SDO_C->bufferOffset = 0; - SDO_C->toggle =0; - SDO_C->state = SDO_STATE_DOWNLOAD_REQUEST; + SDO_C->toggle = 0x00; + SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; } +#else + /* expedited transfer */ + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_ok_communicationEnd; +#endif } - else{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } break; } - case SDO_STATE_DOWNLOAD_RESPONSE:{ - - if (SCS == SCS_DOWNLOAD_SEGMENT){ - /* verify toggle bit */ - if((SDO_C->CANrxData[0]&0x10) != (SDO_C->toggle<<4)){ - *pSDOabortCode = CO_SDO_AB_TOGGLE_BIT; - SDO_C->state = SDO_STATE_ABORT; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { + if ((SDO_C->CANrxData[0] & 0xEF) == 0x20) { + /* verify and alternate toggle bit */ + uint8_t toggle = SDO_C->CANrxData[0] & 0x10; + if (toggle != SDO_C->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO_C->state = CO_SDO_ST_ABORT; break; } - /* alternate toggle bit */ - if (SDO_C->toggle ==0x00) - SDO_C->toggle =0x01; - else - SDO_C->toggle =0x00; + SDO_C->toggle = (toggle == 0x00) ? 0x10 : 0x00; /* is end of transfer? */ - if(SDO_C->bufferOffset == SDO_C->bufferSize){ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - return CO_SDOcli_ok_communicationEnd; + if (SDO_C->finished) { + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_ok_communicationEnd; + } + else { + SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; } - SDO_C->state = SDO_STATE_DOWNLOAD_REQUEST; } - else{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } break; } - - case SDO_STATE_BLOCKDOWNLOAD_INITIATE:{ /* waiting on reply on block download initiated */ - if (SCS == SCS_DOWNLOAD_BLOCK){ - uint16_t IndexTmp; - IndexTmp = SDO_C->CANrxData[2]; - IndexTmp = IndexTmp << 8; - IndexTmp |= SDO_C->CANrxData[1]; - - if(IndexTmp != SDO_C->index || SDO_C->CANrxData[3] != SDO_C->subIndex) { - /* wrong index */ - *pSDOabortCode = CO_SDO_AB_PRAM_INCOMPAT; - SDO_C->state = SDO_STATE_ABORT; +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED */ + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { + if ((SDO_C->CANrxData[0] & 0xFB) == 0xA0) { + /* verify index and subindex */ + uint16_t index; + uint8_t subindex; + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if (index != SDO_C->index || subindex != SDO_C->subIndex) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; break; } - /* set blksize */ - SDO_C->block_blksize = SDO_C->CANrxData[4]; + SDO_C->block_crc = 0; + SDO_C->block_blksize = SDO_C->CANrxData[4]; SDO_C->block_seqno = 0; - SDO_C->bufferOffset = 0; - SDO_C->bufferOffsetACK = 0; - SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_INPROGRES; + CO_fifo_altBegin(&SDO_C->bufFifo, 0); + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; } - else{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } break; } - case SDO_STATE_BLOCKDOWNLOAD_INPROGRES: - case SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK:{ /* waiting block ACK */ - if (SCS == SCS_DOWNLOAD_BLOCK){ - /* check server subcommand */ - if((SDO_C->CANrxData[0] & 0x02) == 0){ - /* wrong server sub command */ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; - break; - } - /* check number of segments */ - if(SDO_C->CANrxData[1] != SDO_C->block_blksize){ - /* NOT all segments transferred successfully */ - SDO_C->bufferOffsetACK += SDO_C->CANrxData[1] * 7; - SDO_C->bufferOffset = SDO_C->bufferOffsetACK; + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { + if (SDO_C->CANrxData[0] == 0xA2) { + /* check number of segments */ + if (SDO_C->CANrxData[1] < SDO_C->block_seqno) { + /* NOT all segments transferred successfully. + * Re-transmit data after erroneous segment. */ + CO_fifo_altBegin(&SDO_C->bufFifo, + (size_t)SDO_C->CANrxData[1] * 7); + SDO_C->finished = false; } - else{ - SDO_C->bufferOffsetACK = SDO_C->bufferOffset; + else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) { + /* something strange from server, break transmission */ + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; + break; } - /* set size of next block */ - SDO_C->block_blksize = SDO_C->CANrxData[2]; - SDO_C->block_seqno = 0; - if(SDO_C->bufferOffset >= SDO_C->bufferSize) - SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_CRC; - else - SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_INPROGRES; + /* confirm successfully transmitted data */ + CO_fifo_altFinish(&SDO_C->bufFifo, &SDO_C->block_crc); + + if (SDO_C->finished) { + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_REQ; + } else { + SDO_C->block_blksize = SDO_C->CANrxData[2]; + SDO_C->block_seqno = 0; + CO_fifo_altBegin(&SDO_C->bufFifo, 0); + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; + } } - else{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } break; } - case SDO_STATE_BLOCKDOWNLOAD_CRC_ACK:{ - if (SCS == SCS_DOWNLOAD_BLOCK){ - if((SDO_C->CANrxData[0] & 0x01) == 0){ - /* wrong server sub command */ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; - break; - } + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { + if (SDO_C->CANrxData[0] == 0xA1) { /* SDO block download successfully transferred */ - SDO_C->state = SDO_STATE_NOTDEFINED; - SDO_C->timeoutTimer = 0; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - return CO_SDOcli_ok_communicationEnd; + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_ok_communicationEnd; } - else{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; - break; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } + break; } +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ - default:{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + default: { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; break; } } @@ -633,96 +604,182 @@ CO_SDOclient_return_t CO_SDOclientDownload( CO_FLAG_CLEAR(SDO_C->CANrxNew); } -/* TMO *********************************************************************************************** */ - if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { - SDO_C->timeoutTimer += timeDifference_us; - } - - /* communication TMO */ - if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { - *pSDOabortCode = CO_SDO_AB_TIMEOUT; - CO_SDOclient_abort(SDO_C, *pSDOabortCode); - return CO_SDOcli_endedWithTimeout; - } + /* Timeout timers *********************************************************/ + if (ret == CO_SDOcli_waitingServerResponse) { + if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { + SDO_C->timeoutTimer += timeDifference_us; + } + if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { + abortCode = CO_SDO_AB_TIMEOUT; + SDO_C->state = CO_SDO_ST_ABORT; + } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT - else if (timerNext_us != NULL) { - /* check again after timeout time elapsed */ - uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; - if (*timerNext_us > diff) { - *timerNext_us = diff; + else if (timerNext_us != NULL) { + /* check again after timeout time elapsed */ + uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } } - } #endif - -/* TX data ******************************************************************************************* */ - if(SDO_C->CANtxBuff->bufferFull) { - return CO_SDOcli_transmittBufferFull; + if (SDO_C->CANtxBuff->bufferFull) { + ret = CO_SDOcli_transmittBufferFull; + } } - CO_SDOTxBufferClear(SDO_C); - switch (SDO_C->state){ - uint16_t i, j; - uint16_t tmp16; + /* Transmit CAN data ******************************************************/ + if (ret == CO_SDOcli_waitingServerResponse) { + size_t count; + memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); + + switch (SDO_C->state) { + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { + SDO_C->CANtxBuff->data[0] = 0x20; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + + /* get count of data bytes to transfer */ + count = CO_fifo_getOccupied(&SDO_C->bufFifo); + + /* is expedited transfer, <= 4bytes of data */ + if ((SDO_C->sizeInd == 0 && count <= 4) + || (SDO_C->sizeInd > 0 && SDO_C->sizeInd <= 4) + ) { + SDO_C->CANtxBuff->data[0] |= 0x02; + + /* verify length, indicate data size */ + if (count == 0 || (SDO_C->sizeInd > 0 && + SDO_C->sizeInd != count) + ) { + SDO_C->state = CO_SDO_ST_IDLE; + abortCode = CO_SDO_AB_TYPE_MISMATCH; + ret = CO_SDOcli_endedWithClientAbort; + break; + } + if (SDO_C->sizeInd > 0) { + SDO_C->CANtxBuff->data[0] |= 0x01 | ((4 - count) << 2); + } - /* ABORT */ - case SDO_STATE_ABORT:{ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_SDOclient_abort (SDO_C, *pSDOabortCode); - ret = CO_SDOcli_endedWithClientAbort; + /* copy data */ + CO_fifo_read(&SDO_C->bufFifo, + (char *)&SDO_C->CANtxBuff->data[4], count, NULL); + SDO_C->sizeTran = count; + SDO_C->finished = true; + } + else { +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED + /* segmented transfer, indicate data size */ + if (SDO_C->sizeInd > 0) { + uint32_t size = SDO_C->sizeInd; + SDO_C->CANtxBuff->data[0] |= 0x01; + CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &size); + } +#else + SDO_C->state = CO_SDO_ST_IDLE; + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; + ret = CO_SDOcli_endedWithClientAbort; + break; +#endif + } + + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; break; } - /* SEGMENTED */ - case SDO_STATE_DOWNLOAD_REQUEST:{ - /* calculate length to be sent */ - j = SDO_C->bufferSize - SDO_C->bufferOffset; - if(j > 7) j = 7; - /* fill data bytes */ - for(i=0; iCANtxBuff->data[i+1] = SDO_C->buffer[SDO_C->bufferOffset + i]; - for(; i<7; i++) - SDO_C->CANtxBuff->data[i+1] = 0; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { + /* fill data bytes */ + count = CO_fifo_read(&SDO_C->bufFifo, + (char *)&SDO_C->CANtxBuff->data[1], + 7, NULL); + + /* verify if sizeTran is too large */ + SDO_C->sizeTran += count; + if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + SDO_C->sizeTran -= count; + abortCode = CO_SDO_AB_DATA_LONG; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - SDO_C->bufferOffset += j; /* SDO command specifier */ - SDO_C->CANtxBuff->data[0] = CCS_DOWNLOAD_SEGMENT | ((SDO_C->toggle)<<4) | ((7-j)<<1); - /* is end of transfer? */ - if(SDO_C->bufferOffset == SDO_C->bufferSize){ - SDO_C->CANtxBuff->data[0] |= 1; + SDO_C->CANtxBuff->data[0] = SDO_C->toggle | ((7 - count) << 1); + + /* is end of transfer? Verify also sizeTran */ + if (CO_fifo_getOccupied(&SDO_C->bufFifo) == 0) { + if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + SDO_C->CANtxBuff->data[0] |= 0x01; + SDO_C->finished = true; } - /* Send next SDO message */ + + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = SDO_STATE_DOWNLOAD_RESPONSE; + SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; break; } +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED */ + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { + SDO_C->CANtxBuff->data[0] = 0xC4; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + + /* indicate data size */ + if (SDO_C->sizeInd > 0) { + uint32_t size = SDO_C->sizeInd; + SDO_C->CANtxBuff->data[0] |= 0x02; + CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &size); + } - /* BLOCK */ - case SDO_STATE_BLOCKDOWNLOAD_INPROGRES:{ - SDO_C->block_seqno += 1; - SDO_C->CANtxBuff->data[0] = SDO_C->block_seqno; - - /* set data */ - SDO_C->block_noData = 0; + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; + break; + } - for(i = 1; i < 8; i++){ - if(SDO_C->bufferOffset < SDO_C->bufferSize){ - SDO_C->CANtxBuff->data[i] = *(SDO_C->buffer + SDO_C->bufferOffset); - } - else{ - SDO_C->CANtxBuff->data[i] = 0; - SDO_C->block_noData += 1; - } + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { + SDO_C->CANtxBuff->data[0] = ++SDO_C->block_seqno; - SDO_C->bufferOffset += 1; + /* fill data bytes */ + count = CO_fifo_altRead(&SDO_C->bufFifo, + (char *)&SDO_C->CANtxBuff->data[1], 7); + SDO_C->block_noData = 7 - count; + + /* verify if sizeTran is too large */ + SDO_C->sizeTran += count; + if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + SDO_C->sizeTran -= count; + abortCode = CO_SDO_AB_DATA_LONG; + SDO_C->state = CO_SDO_ST_ABORT; + break; } - if(SDO_C->bufferOffset >= SDO_C->bufferSize){ + /* is end of transfer? Verify also sizeTran */ + if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0) { + if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } SDO_C->CANtxBuff->data[0] |= 0x80; - SDO_C->block_blksize = SDO_C->block_seqno; - SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK; + SDO_C->finished = true; + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; } + /* are all segments in current block transferred? */ else if (SDO_C->block_seqno >= SDO_C->block_blksize) { - SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK; + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT else { @@ -732,417 +789,428 @@ CO_SDOclient_return_t CO_SDOclientDownload( } } #endif - - /* tx data */ + /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - break; } - case SDO_STATE_BLOCKDOWNLOAD_CRC:{ - SDO_C->CANtxBuff->data[0] = (CCS_DOWNLOAD_BLOCK<<5) | (SDO_C->block_noData << 2) | 0x01; + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { + SDO_C->CANtxBuff->data[0] = 0xC1 | (SDO_C->block_noData << 2); + SDO_C->CANtxBuff->data[1] = (uint8_t) SDO_C->block_crc; + SDO_C->CANtxBuff->data[2] = (uint8_t) (SDO_C->block_crc >> 8); - tmp16 = crc16_ccitt((unsigned char *)SDO_C->buffer, (unsigned int)SDO_C->bufferSize, 0); - - SDO_C->CANtxBuff->data[1] = (uint8_t) tmp16; - SDO_C->CANtxBuff->data[2] = (uint8_t) (tmp16>>8); - - /* set state */ - SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_CRC_ACK; - /* tx data */ + /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; break; } +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ - default:{ + default: { break; } + } + } + + if (ret == CO_SDOcli_waitingServerResponse) { + if (SDO_C->state == CO_SDO_ST_ABORT) { + uint32_t code = (uint32_t)abortCode; + /* Send SDO abort message */ + SDO_C->CANtxBuff->data[0] = 0x80; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + + CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &code); + CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_endedWithClientAbort; + } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { + ret = CO_SDOcli_blockDownldInProgress; + } +#endif } - if(SDO_C->state == SDO_STATE_BLOCKDOWNLOAD_INPROGRES) { - ret = CO_SDOcli_blockDownldInProgress; + if (sizeTransferred != NULL) { + *sizeTransferred = SDO_C->sizeTran; + } + if (SDOabortCode != NULL) { + *SDOabortCode = abortCode; } return ret; } -/******************************************************************************* - * - * UPLOAD - * +/****************************************************************************** + * UPLOAD * ******************************************************************************/ -CO_SDOclient_return_t CO_SDOclientUploadInitiate( - CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - uint8_t *dataRx, - uint32_t dataRxSize, - uint16_t SDOtimeoutTime_ms, - uint8_t blockEnable, - uint32_t *timerNext_us) +CO_SDOclient_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, + uint16_t index, + uint8_t subIndex, + uint16_t SDOtimeoutTime_ms, + bool_t blockEnable) { /* verify parameters */ - if(SDO_C == NULL || dataRx == 0 || dataRxSize < 4) { + if (SDO_C == NULL) { return CO_SDOcli_wrongArguments; } /* save parameters */ - SDO_C->buffer = dataRx; - SDO_C->bufferSize = dataRxSize; - SDO_C->SDOtimeoutTimeHalf_us = (uint32_t)SDOtimeoutTime_ms * 500; - SDO_C->SDOtimeoutTime_us = SDO_C->SDOtimeoutTimeHalf_us * 2; - - /* prepare CAN tx message */ - CO_SDOTxBufferClear(SDO_C); - SDO_C->index = index; SDO_C->subIndex = subIndex; + SDO_C->sizeInd = 0; + SDO_C->sizeTran = 0; + SDO_C->finished = false; + CO_fifo_reset(&SDO_C->bufFifo); + SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; + SDO_C->timeoutTimer = 0; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + SDO_C->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 500; +#endif - SDO_C->CANtxBuff->data[1] = index & 0xFF; - SDO_C->CANtxBuff->data[2] = index >> 8; - SDO_C->CANtxBuff->data[3] = subIndex; - - - if(blockEnable == 0){ - SDO_C->state = SDO_STATE_UPLOAD_INITIATED; - SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_INITIATE<<5); +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL + /* if node-ID of the SDO server is the same as node-ID of this node, then + * transfer data within this node */ + if (SDO_C->SDO != NULL + && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId + ) { + SDO_C->state = CO_SDO_ST_LOCAL_TRANSFER; } - else{ - SDO_C->state = SDO_STATE_BLOCKUPLOAD_INITIATE; - - /* header */ - SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5); - - /* set CRC */ - SDO_C->CANtxBuff->data[0] |= 0x04; - - /* set number of segments in block */ - SDO_C->block_blksize = SDO_C->block_size_max; - if ((SDO_C->block_blksize *7) > SDO_C->bufferSize){ - return CO_SDOcli_wrongArguments; - } - - SDO_C->CANtxBuff->data[4] = SDO_C->block_blksize; - SDO_C->CANtxBuff->data[5] = SDO_C->pst; - - - SDO_C->block_seqno = 0; + else +#endif +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + if (blockEnable) { + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ; } - - /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ - if(SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ - -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT - /* Optional signal to RTOS. We can immediately continue SDO Client */ - if(timerNext_us != NULL) { - *timerNext_us = 0; - } + else #endif - - return CO_SDOcli_ok_communicationEnd; + { + SDO_C->state = CO_SDO_ST_UPLOAD_INITIATE_REQ; } - /* empty receive buffer, reset timeout timer and send message */ CO_FLAG_CLEAR(SDO_C->CANrxNew); - SDO_C->timeoutTimer = 0; - SDO_C->timeoutTimerBLOCK =0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); return CO_SDOcli_ok_communicationEnd; } /******************************************************************************/ -CO_SDOclient_return_t CO_SDOclientUpload( - CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - uint32_t *pDataSize, - uint32_t *pSDOabortCode, - uint32_t *timerNext_us) +CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, + uint32_t timeDifference_us, + CO_SDO_abortCode_t *SDOabortCode, + size_t *sizeIndicated, + size_t *sizeTransferred, + uint32_t *timerNext_us) { - uint16_t indexTmp; - uint32_t tmp32; CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse; + CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; - /* verify parameters */ - if(SDO_C == NULL) { - return CO_SDOcli_wrongArguments; + if (SDO_C == NULL) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + ret = CO_SDOcli_wrongArguments; } - - /* clear abort code */ - *pSDOabortCode = CO_SDO_AB_NONE; - - /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */ - if(SDO_C->SDO && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - - /* If SDO server is busy return error */ - if(SDO_C->SDO->state != 0){ - *pSDOabortCode = CO_SDO_AB_DEVICE_INCOMPAT; - return CO_SDOcli_endedWithClientAbort; - } - - /* init ODF_arg */ - *pSDOabortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index, SDO_C->subIndex); - if((*pSDOabortCode) != CO_SDO_AB_NONE){ - return CO_SDOcli_endedWithServerAbort; - } - - /* set buffer and length if domain */ - SDO_C->SDO->ODF_arg.data = SDO_C->buffer; - if(SDO_C->SDO->ODF_arg.ODdataStorage == 0) - SDO_C->SDO->ODF_arg.dataLength = SDO_C->bufferSize; - - /* read data from the Object dictionary */ - *pSDOabortCode = CO_SDO_readOD(SDO_C->SDO, SDO_C->bufferSize); - if((*pSDOabortCode) != CO_SDO_AB_NONE){ - return CO_SDOcli_endedWithServerAbort; + else if (SDO_C->state == CO_SDO_ST_IDLE) { + ret = CO_SDOcli_ok_communicationEnd; + } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL + /* Transfer data locally **************************************************/ + else if (SDO_C->state == CO_SDO_ST_LOCAL_TRANSFER) { + if (SDO_C->SDO->state != 0) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + ret = CO_SDOcli_endedWithClientAbort; } - - /* set data size */ - *pDataSize = SDO_C->SDO->ODF_arg.dataLength; - - /* is SDO buffer too small */ - if(SDO_C->SDO->ODF_arg.lastSegment == 0){ - *pSDOabortCode = CO_SDO_AB_OUT_OF_MEM; /* Out of memory */ - return CO_SDOcli_endedWithServerAbort; + else { + /* Max data size is limited to fifo size (for now). */ + size_t count = CO_fifo_getSpace(&SDO_C->bufFifo); + + /* init ODF_arg */ + abortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index, + SDO_C->subIndex); + if (abortCode == CO_SDO_AB_NONE) { + /* set buffer and read data from the Object dictionary */ + SDO_C->SDO->ODF_arg.data = (uint8_t *)SDO_C->buf; + if (SDO_C->SDO->ODF_arg.ODdataStorage == 0) { + /* set length if domain */ + SDO_C->SDO->ODF_arg.dataLength = count; + } + abortCode = CO_SDO_readOD(SDO_C->SDO, count); + } + if (abortCode == CO_SDO_AB_NONE) { + /* is SDO buffer too small */ + if (SDO_C->SDO->ODF_arg.lastSegment == 0) { + abortCode = CO_SDO_AB_OUT_OF_MEM; /* Out of memory */ + ret = CO_SDOcli_endedWithServerAbort; + } + else { + SDO_C->sizeTran = (size_t)SDO_C->SDO->ODF_arg.dataLength; + /* fifo was written directly, indicate data size manually */ + SDO_C->bufFifo.writePtr = SDO_C->sizeTran; + ret = CO_SDOcli_ok_communicationEnd; + } + } + else { + ret = CO_SDOcli_endedWithServerAbort; + } } - - return CO_SDOcli_ok_communicationEnd; + SDO_C->state = CO_SDO_ST_IDLE; } - - -/* RX data ******************************************************************************** */ - if(CO_FLAG_READ(SDO_C->CANrxNew)){ - uint8_t SCS = SDO_C->CANrxData[0]>>5; /* Client command specifier */ - - /* ABORT */ - if (SDO_C->CANrxData[0] == (SCS_ABORT<<5)){ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - CO_memcpySwap4(pSDOabortCode , &SDO_C->CANrxData[4]); - return CO_SDOcli_endedWithServerAbort; +#endif + /* CAN data received ******************************************************/ + else if (CO_FLAG_READ(SDO_C->CANrxNew)) { + /* is SDO abort */ + if (SDO_C->CANrxData[0] == 0x80) { + uint32_t code; + CO_memcpySwap4(&code , &SDO_C->CANrxData[4]); + abortCode = (CO_SDO_abortCode_t)code; + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_endedWithServerAbort; } - switch (SDO_C->state){ - case SDO_STATE_UPLOAD_INITIATED:{ - - + else switch (SDO_C->state) { + case CO_SDO_ST_UPLOAD_INITIATE_RSP: { + if ((SDO_C->CANrxData[0] & 0xF0) == 0x40) { + /* verify index and subindex */ + uint16_t index; + uint8_t subindex; + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if (index != SDO_C->index || subindex != SDO_C->subIndex) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - if (SCS == SCS_UPLOAD_INITIATE){ - if(SDO_C->CANrxData[0] & 0x02){ - uint8_t size; + if (SDO_C->CANrxData[0] & 0x02) { /* Expedited transfer */ - if(SDO_C->CANrxData[0] & 0x01)/* is size indicated */ - size = 4 - ((SDO_C->CANrxData[0]>>2)&0x03); /* size */ - else - size = 4; - - *pDataSize = size; - - /* copy data */ - while(size--) SDO_C->buffer[size] = SDO_C->CANrxData[4+size]; - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - - return CO_SDOcli_ok_communicationEnd; + size_t count = 4; + /* is size indicated? */ + if (SDO_C->CANrxData[0] & 0x01) { + count -= (SDO_C->CANrxData[0] >> 2) & 0x03; + } + /* copy data, indicate size and finish */ + CO_fifo_write(&SDO_C->bufFifo, + (const char *)&SDO_C->CANrxData[4], + count, NULL); + SDO_C->sizeTran = count; + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_ok_communicationEnd; } - else{ - /* segmented transfer - prepare first segment */ - SDO_C->bufferOffset = 0; - SDO_C->state = SDO_STATE_UPLOAD_REQUEST; - - SDO_C->toggle =0; - /* continue with segmented upload */ + else { +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED + /* segmented transfer, is size indicated? */ + if (SDO_C->CANrxData[0] & 0x01) { + uint32_t size; + CO_memcpySwap4(&size, &SDO_C->CANrxData[4]); + SDO_C->sizeInd = size; + } + SDO_C->toggle = 0x00; + SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; +#else + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; + SDO_C->state = CO_SDO_ST_ABORT; +#endif } } - else{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } break; } - case SDO_STATE_UPLOAD_RESPONSE:{ - if (SCS == SCS_UPLOAD_SEGMENT){ - uint16_t size, i; - /* verify toggle bit */ - if((SDO_C->CANrxData[0] &0x10) != (~SDO_C->toggle &0x10)){ - *pSDOabortCode = CO_SDO_AB_TOGGLE_BIT; - SDO_C->state = SDO_STATE_ABORT; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { + if ((SDO_C->CANrxData[0] & 0xE0) == 0x00) { + size_t count, countWr; + + /* verify and alternate toggle bit */ + uint8_t toggle = SDO_C->CANrxData[0] & 0x10; + if (toggle != SDO_C->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO_C->state = CO_SDO_ST_ABORT; break; } - /* get size */ - size = 7 - ((SDO_C->CANrxData[0]>>1)&0x07); - /* verify length */ - if((SDO_C->bufferOffset + size) > SDO_C->bufferSize){ - *pSDOabortCode = CO_SDO_AB_OUT_OF_MEM; /* Out of memory */ - SDO_C->state = SDO_STATE_ABORT; + SDO_C->toggle = (toggle == 0x00) ? 0x10 : 0x00; + + /* get data size and write data to the buffer */ + count = 7 - ((SDO_C->CANrxData[0] >> 1) & 0x07); + countWr = CO_fifo_write(&SDO_C->bufFifo, + (const char *)&SDO_C->CANrxData[1], + count, NULL); + SDO_C->sizeTran += countWr; + + /* verify, if there was not enough space in fifo buffer */ + if (countWr != count) { + abortCode = CO_SDO_AB_OUT_OF_MEM; + SDO_C->state = CO_SDO_ST_ABORT; break; } - /* copy data to buffer */ - for(i=0; ibuffer[SDO_C->bufferOffset + i] = SDO_C->CANrxData[1 + i]; - SDO_C->bufferOffset += size; - /* If no more segments to be uploaded, finish communication */ - if(SDO_C->CANrxData[0] & 0x01){ - *pDataSize = SDO_C->bufferOffset; - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - return CO_SDOcli_ok_communicationEnd; + + /* verify if size of data uploaded is too large */ + if (SDO_C->sizeInd > 0 + && SDO_C->sizeTran > SDO_C->sizeInd + ) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + + /* If no more segments to be upload, finish */ + if (SDO_C->CANrxData[0] & 0x01) { + /* verify size of data uploaded */ + if (SDO_C->sizeInd > 0 + && SDO_C->sizeTran < SDO_C->sizeInd + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO_C->state = CO_SDO_ST_ABORT; + } else { + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_ok_communicationEnd; + } + } + else { + SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; } - /* set state */ - SDO_C->state = SDO_STATE_UPLOAD_REQUEST; - break; } - else{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } break; } - - case SDO_STATE_BLOCKUPLOAD_INITIATE:{ - if (SCS == SCS_UPLOAD_BLOCK){ /* block upload initiate response */ - - SDO_C->state = SDO_STATE_BLOCKUPLOAD_INITIATE_ACK; - - /* SCR support */ - if((SDO_C->CANrxData[0] & 0x04) != 0) - SDO_C->crcEnabled = 1; /* CRC suported */ - else - SDO_C->crcEnabled = 0; /* CRC not suported */ - - /* chech Index ans subnindex */ - indexTmp = SDO_C->CANrxData[2]; - indexTmp = indexTmp << 8; - indexTmp |= SDO_C->CANrxData[1]; - - if(indexTmp != SDO_C->index || SDO_C->CANrxData[3] != SDO_C->subIndex){ - *pSDOabortCode = CO_SDO_AB_PRAM_INCOMPAT; - SDO_C->state = SDO_STATE_ABORT; +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED */ + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { + if ((SDO_C->CANrxData[0] & 0xF9) == 0xC0) { + uint16_t index; + uint8_t subindex; + + /* get server CRC support info and data size */ + if ((SDO_C->CANrxData[0] & 0x04) != 0) { + SDO_C->block_crcEnabled = true; + } else { + SDO_C->block_crcEnabled = false; + } + if (SDO_C->CANrxData[0] & 0x02) { + uint32_t size; + CO_memcpySwap4(&size, &SDO_C->CANrxData[4]); + SDO_C->sizeInd = size; } - /* set length */ - if(SDO_C->CANrxData[0]&0x02){ - uint32_t len; - CO_memcpySwap4(&len, &SDO_C->CANrxData[4]); - SDO_C->dataSize = len; + /* verify index and subindex */ + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if (index != SDO_C->index || subindex != SDO_C->subIndex) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; } - else{ - SDO_C->dataSize = 0; + else { + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; } - - /* check available buffer size */ - if (SDO_C->dataSize > SDO_C->bufferSize){ - *pSDOabortCode = CO_SDO_AB_OUT_OF_MEM; - SDO_C->state = SDO_STATE_ABORT; + } + /* switch to regular transfer, CO_SDO_ST_UPLOAD_INITIATE_RSP */ + else if ((SDO_C->CANrxData[0] & 0xF0) == 0x40) { + /* verify index and subindex */ + uint16_t index; + uint8_t subindex; + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if (index != SDO_C->index || subindex != SDO_C->subIndex) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + break; } - SDO_C->dataSizeTransfered =0; - } - else if (SCS == SCS_UPLOAD_INITIATE){ /* switch to regular segmented transfer */ - if(SDO_C->CANrxData[0] & 0x02){ - uint8_t size; + if (SDO_C->CANrxData[0] & 0x02) { /* Expedited transfer */ - if(SDO_C->CANrxData[0] & 0x01)/* is size indicated */ - size = 4 - ((SDO_C->CANrxData[0]>>2)&0x03); /* size */ - else - size = 4; - - *pDataSize = size; - - /* copy data */ - while(size--) SDO_C->buffer[size] = SDO_C->CANrxData[4+size]; - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - - return CO_SDOcli_ok_communicationEnd; + size_t count = 4; + /* is size indicated? */ + if (SDO_C->CANrxData[0] & 0x01) { + count -= (SDO_C->CANrxData[0] >> 2) & 0x03; + } + /* copy data, indicate size and finish */ + CO_fifo_write(&SDO_C->bufFifo, + (const char *)&SDO_C->CANrxData[4], + count, NULL); + SDO_C->sizeTran = count; + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_ok_communicationEnd; } - else{ - /* segmented transfer - prepare first segment */ - SDO_C->bufferOffset = 0; - SDO_C->state = SDO_STATE_UPLOAD_REQUEST; - - SDO_C->toggle =0; - /* continue with segmented upload */ + else { + /* segmented transfer, is size indicated? */ + if (SDO_C->CANrxData[0] & 0x01) { + uint32_t size; + CO_memcpySwap4(&size, &SDO_C->CANrxData[4]); + SDO_C->sizeInd = size; + } + SDO_C->toggle = 0x00; + SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; } } - else{ /* unknown SCS */ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } break; } - case SDO_STATE_BLOCKUPLOAD_INPROGRES:{ - /* data are copied directly in receive function */ + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: { + /* data are copied directly in the receive function */ break; } - case SDO_STATE_BLOCKUPLOAD_SUB_END:{ - /* data was copied by receive function, sub-block is finished */ - /* Is last segment? */ - if(SDO_C->CANrxData[0] & 0x80) { - /* Is data size indicated and wrong? */ - if((SDO_C->dataSize != 0) && (SDO_C->dataSize > SDO_C->dataSizeTransfered)) { - *pSDOabortCode = CO_SDO_AB_TYPE_MISMATCH; - SDO_C->state = SDO_STATE_ABORT; - } - else { - SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_ACK_LAST; - } - } - else { - /* Is SDO buffer overflow? */ - if(SDO_C->dataSizeTransfered >= SDO_C->bufferSize) { - *pSDOabortCode = CO_SDO_AB_OUT_OF_MEM; - SDO_C->state = SDO_STATE_ABORT; - } - else { - SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_ACK; - } - } - break; - } - - case SDO_STATE_BLOCKUPLOAD_BLOCK_CRC:{ - if (SCS == SCS_UPLOAD_BLOCK){ - tmp32 = ((SDO_C->CANrxData[0]>>2) & 0x07); - SDO_C->dataSizeTransfered -= tmp32; + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { + if ((SDO_C->CANrxData[0] & 0xE3) == 0xC1) { + /* Get number of data bytes in last segment, that do not + * contain data. Then copy remaining data into fifo */ + uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07); + CO_fifo_write(&SDO_C->bufFifo, + (const char *)&SDO_C->block_dataUploadLast[0], + 7 - noData, + &SDO_C->block_crc); + SDO_C->sizeTran += 7 - noData; - SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_END; - if (SDO_C->crcEnabled){ - uint16_t tmp16; - CO_memcpySwap2(&tmp16, &SDO_C->CANrxData[1]); + /* verify length */ + if (SDO_C->sizeInd > 0 + && SDO_C->sizeTran != SDO_C->sizeInd + ) { + abortCode = (SDO_C->sizeTran > SDO_C->sizeInd) ? + CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - if (tmp16 != crc16_ccitt((unsigned char *)SDO_C->buffer, (unsigned int)SDO_C->dataSizeTransfered, 0)){ - *pSDOabortCode = CO_SDO_AB_CRC; - SDO_C->state = SDO_STATE_ABORT; - } - else{ - SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_END; + /* verify CRC */ + if (SDO_C->block_crcEnabled) { + uint16_t crcServer; + CO_memcpySwap2(&crcServer, &SDO_C->CANrxData[1]); + if (crcServer != SDO_C->block_crc) { + abortCode = CO_SDO_AB_CRC; + SDO_C->state = CO_SDO_ST_ABORT; + break; } } - else{ - SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_END; - } - + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; } - else{ - *pSDOabortCode = CO_SDO_AB_GENERAL; - SDO_C->state = SDO_STATE_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } break; } +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ - default:{ - *pSDOabortCode = CO_SDO_AB_CMD; - SDO_C->state = SDO_STATE_ABORT; + default: { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; break; } } @@ -1151,164 +1219,251 @@ CO_SDOclient_return_t CO_SDOclientUpload( CO_FLAG_CLEAR(SDO_C->CANrxNew); } -/* TMO *************************************************************************************************** */ - if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { - SDO_C->timeoutTimer += timeDifference_us; - if (SDO_C->state == SDO_STATE_BLOCKUPLOAD_INPROGRES) - SDO_C->timeoutTimerBLOCK += timeDifference_us; - } - - /* communication TMO */ - if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { - *pSDOabortCode = CO_SDO_AB_TIMEOUT; - CO_SDOclient_abort(SDO_C, *pSDOabortCode); - return CO_SDOcli_endedWithTimeout; - } + /* Timeout timers *********************************************************/ + if (ret == CO_SDOcli_waitingServerResponse) { + if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { + SDO_C->timeoutTimer += timeDifference_us; + } + if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { + abortCode = CO_SDO_AB_TIMEOUT; + SDO_C->state = CO_SDO_ST_ABORT; + } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT - else if (timerNext_us != NULL) { - /* check again after timeout time elapsed */ - uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; - if (*timerNext_us > diff) { - *timerNext_us = diff; + else if (timerNext_us != NULL) { + /* check again after timeout time elapsed */ + uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } } - } #endif - /* block TMO */ - if (SDO_C->timeoutTimerBLOCK >= SDO_C->SDOtimeoutTimeHalf_us) { - SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_ACK; - } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + /* Timeout for sub-block reception */ + if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { + if (SDO_C->block_timeoutTimer < SDO_C->block_SDOtimeoutTime_us) { + SDO_C->block_timeoutTimer += timeDifference_us; + } + if (SDO_C->block_timeoutTimer >= SDO_C->block_SDOtimeoutTime_us) { + /* SDO_C->state will change, processing will continue in this + * thread. Make memory barrier here with CO_FLAG_CLEAR() call.*/ + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; + CO_FLAG_CLEAR(SDO_C->CANrxNew); + } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT - else if (timerNext_us != NULL) { - /* check again after inhibit time elapsed */ - uint32_t diff = SDO_C->SDOtimeoutTimeHalf_us - SDO_C->timeoutTimerBLOCK; - if (*timerNext_us > diff) { - *timerNext_us = diff; + else if (timerNext_us != NULL) { + /* check again after timeout time elapsed */ + uint32_t diff = SDO_C->block_SDOtimeoutTime_us - + SDO_C->block_timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } +#endif + } +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ + + if (SDO_C->CANtxBuff->bufferFull) { + ret = CO_SDOcli_transmittBufferFull; } } -#endif + /* Transmit CAN data ******************************************************/ -/* TX data ******************************************************************************** */ - if(SDO_C->CANtxBuff->bufferFull) { - return CO_SDOcli_transmittBufferFull; - } + if (ret == CO_SDOcli_waitingServerResponse) { + size_t count; + memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); - CO_SDOTxBufferClear(SDO_C); - switch (SDO_C->state){ - case SDO_STATE_ABORT:{ - SDO_C->state = SDO_STATE_NOTDEFINED; - CO_SDOclient_abort (SDO_C, *pSDOabortCode); - ret = CO_SDOcli_endedWithClientAbort; - break; - } + switch (SDO_C->state) { + case CO_SDO_ST_UPLOAD_INITIATE_REQ: { + SDO_C->CANtxBuff->data[0] = 0x40; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - /* SEGMENTED UPLOAD */ - case SDO_STATE_UPLOAD_REQUEST:{ - SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_SEGMENT<<5) | (SDO_C->toggle & 0x10); + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; + break; + } - SDO_C->state = SDO_STATE_UPLOAD_RESPONSE; - SDO_C->toggle = ~SDO_C->toggle; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { + /* verify, if there is enough space in data buffer */ + if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7) { + ret = CO_SDOcli_uploadDataBufferFull; + break; + } + SDO_C->CANtxBuff->data[0] = 0x60 | SDO_C->toggle; + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; break; } - /* BLOCK */ - case SDO_STATE_BLOCKUPLOAD_INITIATE_ACK:{ - SDO_C->timeoutTimerBLOCK = 0; - SDO_C->block_seqno = 0; - SDO_C->state = SDO_STATE_BLOCKUPLOAD_INPROGRES; +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED */ + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { + SDO_C->CANtxBuff->data[0] = 0xA4; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + + /* calculate number of block segments from free buffer space */ + count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7; + if (count > 127) { + count = 127; + } + else if (count == 0) { + abortCode = CO_SDO_AB_OUT_OF_MEM; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + SDO_C->block_blksize = (uint8_t)count; + SDO_C->CANtxBuff->data[4] = SDO_C->block_blksize; + SDO_C->CANtxBuff->data[5] = CO_CONFIG_SDO_CLI_PST; - /* header */ - SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5) | 0x03; + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; break; } - case SDO_STATE_BLOCKUPLOAD_BLOCK_ACK_LAST:{ - /* header */ - SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5) | 0x02; - SDO_C->CANtxBuff->data[1] = SDO_C->block_seqno; + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { + SDO_C->CANtxBuff->data[0] = 0xA3; + /* reset timeout timers, seqno and send message */ + SDO_C->timeoutTimer = 0; + SDO_C->block_timeoutTimer = 0; SDO_C->block_seqno = 0; - SDO_C->timeoutTimerBLOCK = 0; - - SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_CRC; - - SDO_C->CANtxBuff->data[2] = SDO_C->block_blksize; + SDO_C->block_crc = 0; + /* Block segments will be received in different thread. Make memory + * barrier here with CO_FLAG_CLEAR() call. */ + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + CO_FLAG_CLEAR(SDO_C->CANrxNew); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - break; } - case SDO_STATE_BLOCKUPLOAD_BLOCK_ACK:{ - /* header */ - SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5) | 0x02; + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { + SDO_C->CANtxBuff->data[0] = 0xA2; SDO_C->CANtxBuff->data[1] = SDO_C->block_seqno; - /* set next block size */ - if (SDO_C->dataSize != 0){ - if(SDO_C->dataSizeTransfered >= SDO_C->dataSize){ - SDO_C->block_blksize = 0; - SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_CRC; + /* Is last segment? */ + if (SDO_C->finished) { + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; + } + else { + /* verify if size of data uploaded is too large */ + if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO_C->state = CO_SDO_ST_ABORT; + break; } - else{ - tmp32 = ((SDO_C->dataSize - SDO_C->dataSizeTransfered) / 7); - if(tmp32 >= SDO_C->block_size_max){ - SDO_C->block_blksize = SDO_C->block_size_max; - } - else{ - if((SDO_C->dataSize - SDO_C->dataSizeTransfered) % 7 == 0) - SDO_C->block_blksize = tmp32; - else - SDO_C->block_blksize = tmp32 + 1; + + /* calculate number of block segments from free buffer space */ + count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7; + if (count >= 127) { + count = 127; + } + else if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) > 0) { + /* application must empty data buffer first */ + ret = CO_SDOcli_uploadDataBufferFull; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT + /* Inform OS to call this function again without delay. */ + if (timerNext_us != NULL) { + *timerNext_us = 0; } - SDO_C->block_seqno = 0; - SDO_C->timeoutTimerBLOCK = 0; - SDO_C->state = SDO_STATE_BLOCKUPLOAD_INPROGRES; +#endif + break; } - } - else{ + SDO_C->block_blksize = (uint8_t)count; SDO_C->block_seqno = 0; - SDO_C->timeoutTimerBLOCK = 0; - - SDO_C->state = SDO_STATE_BLOCKUPLOAD_INPROGRES; + /* Block segments will be received in different thread. Make + * memory barrier here with CO_FLAG_CLEAR() call. */ + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + CO_FLAG_CLEAR(SDO_C->CANrxNew); } + SDO_C->CANtxBuff->data[2] = SDO_C->block_blksize; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); break; } - case SDO_STATE_BLOCKUPLOAD_BLOCK_END:{ - SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5) | 0x01; + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: { + SDO_C->CANtxBuff->data[0] = 0xA1; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - - *pDataSize = SDO_C->dataSizeTransfered; - - SDO_C->state = SDO_STATE_NOTDEFINED; - + SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDOcli_ok_communicationEnd; break; } +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ - default: + default: { break; + } + } } - if(SDO_C->state == SDO_STATE_BLOCKUPLOAD_INPROGRES) { - ret = CO_SDOcli_blockUploadInProgress; + if (ret == CO_SDOcli_waitingServerResponse) { + if (SDO_C->state == CO_SDO_ST_ABORT) { + uint32_t code = (uint32_t)abortCode; + /* Send SDO abort message */ + SDO_C->CANtxBuff->data[0] = 0x80; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + + CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &code); + CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDOcli_endedWithClientAbort; + } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { + ret = CO_SDOcli_blockUploadInProgress; + } +#endif + } + + if (sizeIndicated != NULL) { + *sizeIndicated = SDO_C->sizeInd; } + if (sizeTransferred != NULL) { + *sizeTransferred = SDO_C->sizeTran; + } + if (SDOabortCode != NULL) { + *SDOabortCode = abortCode; + } + + return ret; +} + +/******************************************************************************/ +size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, + char *buf, + size_t count) +{ + size_t ret = 0; + if (SDO_C != NULL && buf != NULL) { + ret = CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); + } return ret; } /******************************************************************************/ -void CO_SDOclientClose(CO_SDOclient_t *SDO_C){ - if(SDO_C != NULL) { - SDO_C->state = SDO_STATE_NOTDEFINED; +void CO_SDOclientClose(CO_SDOclient_t *SDO_C) { + if (SDO_C != NULL) { + SDO_C->state = CO_SDO_ST_IDLE; } } diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 79dc5f58..f3f4ad45 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -5,7 +5,7 @@ * @ingroup CO_SDOclient * @author Janez Paternoster * @author Matej Severkar - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -28,6 +28,14 @@ #ifndef CO_SDO_CLIENT_H #define CO_SDO_CLIENT_H +#include "301/CO_driver.h" +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) || defined CO_DOXYGEN +#include "301/CO_SDOserver.h" +#endif +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) || defined CO_DOXYGEN +#include "301/CO_fifo.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -46,16 +54,19 @@ extern "C" { /** * Return values of SDO client functions. */ -typedef enum{ - /** Transmit buffer is full. Waiting */ +typedef enum { + /** Data buffer is full, data must be read before next upload cycle begins*/ + CO_SDOcli_uploadDataBufferFull = 5, + /** CAN transmit buffer is full. Waiting. */ CO_SDOcli_transmittBufferFull = 4, - /** Block download is in progress. Sending train of messages */ + /** Block download is in progress. Sending train of messages. */ CO_SDOcli_blockDownldInProgress = 3, - /** Block upload in progress. Receiving train of messages */ + /** Block upload is in progress. Receiving train of messages. Data must not + * be read in this state. */ CO_SDOcli_blockUploadInProgress = 2, /** Waiting server response */ CO_SDOcli_waitingServerResponse = 1, - /** Success, end of communication */ + /** Success, end of communication. Uploaded data must be read. */ CO_SDOcli_ok_communicationEnd = 0, /** Error in arguments */ CO_SDOcli_wrongArguments = -2, @@ -63,16 +74,14 @@ typedef enum{ CO_SDOcli_endedWithClientAbort = -9, /** Communication ended with server abort */ CO_SDOcli_endedWithServerAbort = -10, - /** Communication ended with timeout */ - CO_SDOcli_endedWithTimeout = -11 -}CO_SDOclient_return_t; +} CO_SDOclient_return_t; /** * SDO Client Parameter. The same as record from Object dictionary * (index 0x1280+). */ -typedef struct{ +typedef struct { /** Equal to 3 */ uint8_t maxSubIndex; /** Communication object identifier for client transmission. @@ -89,88 +98,89 @@ typedef struct{ uint32_t COB_IDServerToClient; /** Node-ID of the SDO server */ uint8_t nodeIDOfTheSDOServer; -}CO_SDOclientPar_t; +} CO_SDOclientPar_t; /** * SDO client object */ -typedef struct{ +typedef struct { +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) || defined CO_DOXYGEN /** From CO_SDOclient_init() */ - CO_SDOclientPar_t *SDOClientPar; + CO_SDO_t *SDO; +#endif /** From CO_SDOclient_init() */ - CO_SDO_t *SDO; - /** Internal state of the SDO client */ - uint8_t state; - /** Pointer to data buffer supplied by user */ - uint8_t *buffer; - /** By download application indicates data size in buffer. - By upload application indicates buffer size */ - uint32_t bufferSize; - /** Offset in buffer of next data segment being read/written */ - uint32_t bufferOffset; - /** Acknowledgement */ - uint32_t bufferOffsetACK; - /** data length to be uploaded in block transfer */ - uint32_t dataSize; - /** Data length transferred in block transfer */ - uint32_t dataSizeTransfered; - /** Maximum timeout time between request and response in microseconds. */ - uint32_t SDOtimeoutTime_us; - /** Half of maximum timeout time between request and response. */ - uint32_t SDOtimeoutTimeHalf_us; - /** Timeout timer for SDO communication */ - uint32_t timeoutTimer; - /** Timeout timer for SDO block transfer */ - uint32_t timeoutTimerBLOCK; - /** Index of current object in Object Dictionary */ - uint16_t index; - /** Subindex of current object in Object Dictionary */ - uint8_t subIndex; + CO_SDOclientPar_t *SDOClientPar; /** From CO_SDOclient_init() */ - CO_CANmodule_t *CANdevRx; + CO_CANmodule_t *CANdevRx; /** From CO_SDOclient_init() */ - uint16_t CANdevRxIdx; - /** Indicates, if new SDO message received from CAN bus. - It is not cleared, until received message is completely processed. */ - volatile void *CANrxNew; + uint16_t CANdevRxIdx; + /** From CO_SDOclient_init() */ + CO_CANmodule_t *CANdevTx; + /** From CO_SDOclient_init() */ + uint16_t CANdevTxIdx; + /** CAN transmit buffer inside CANdevTx for CAN tx message */ + CO_CANtx_t *CANtxBuff; + /** Index of current object in Object Dictionary */ + uint16_t index; + /** Subindex of current object in Object Dictionary */ + uint8_t subIndex; + /* If true, then data transfer is finished */ + bool_t finished; + /** Size of data, which will be transferred. It is optionally indicated by + * client in case of download or by server in case of upload. */ + size_t sizeInd; + /** Size of data which is actually transferred. */ + size_t sizeTran; + /** Internal state of the SDO client */ + volatile CO_SDO_state_t state; + /** Maximum timeout time between request and response in microseconds */ + uint32_t SDOtimeoutTime_us; + /** Timeout timer for SDO communication */ + uint32_t timeoutTimer; + /** CO_fifo_t object for data buffer (not pointer) */ + CO_fifo_t bufFifo; + /** Data buffer of usable size @ref CO_CONFIG_SDO_CLI_BUFFER_SIZE, used + * inside bufFifo. Must be one byte larger for fifo usage. */ + char buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; + /** Indicates, if new SDO message received from CAN bus. It is not cleared, + * until received message is completely processed. */ + volatile void *CANrxNew; /** 8 data bytes of the received message */ - uint8_t CANrxData[8]; + uint8_t CANrxData[8]; + /** Previous value of the COB_IDClientToServer */ + uint32_t COB_IDClientToServerPrev; + /** Previous value of the COB_IDServerToClient */ + uint32_t COB_IDServerToClientPrev; #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_SDOclient_initCallbackPre() or NULL */ - void (*pFunctSignal)(void *object); + void (*pFunctSignal)(void *object); /** From CO_SDOclient_initCallbackPre() or NULL */ - void *functSignalObject; + void *functSignalObject; #endif - /** From CO_SDOclient_init() */ - CO_CANmodule_t *CANdevTx; - /** CAN transmit buffer inside CANdevTx for CAN tx message */ - CO_CANtx_t *CANtxBuff; - /** From CO_SDOclient_init() */ - uint16_t CANdevTxIdx; - /** Toggle bit toggled with each subsequent in segmented transfer */ - uint8_t toggle; - /** Server threshold for switch back to segmented transfer, if data size is - * small. Set in CO_SDOclient_init(). Can be changed by application. - * 0 Disables switching. */ - uint8_t pst; - /** Maximum number of segments in one block. Set in CO_SDOclient_init(). Can - be changed by application to 2 .. 127. */ - uint8_t block_size_max; - /** Last sector number */ - uint8_t block_seqno; - /** Block size in current transfer */ - uint8_t block_blksize; +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) || defined CO_DOXYGEN + /** Toggle bit toggled in each segment in segmented transfer */ + uint8_t toggle; +#endif +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) || defined CO_DOXYGEN + /** Timeout time for SDO sub-block upload, half of #SDOtimeoutTime_us */ + uint32_t block_SDOtimeoutTime_us; + /** Timeout timer for SDO sub-block upload */ + uint32_t block_timeoutTimer; + /** Sequence number of segment in block, 1..127 */ + uint8_t block_seqno; + /** Number of segments per block, 1..127 */ + uint8_t block_blksize; /** Number of bytes in last segment that do not contain data */ - uint8_t block_noData; + uint8_t block_noData; /** Server CRC support in block transfer */ - uint8_t crcEnabled; - /** Previous value of the COB_IDClientToServer */ - uint32_t COB_IDClientToServerPrev; - /** Previous value of the COB_IDServerToClient */ - uint32_t COB_IDServerToClientPrev; - -}CO_SDOclient_t; + bool_t block_crcEnabled; + /** Last 7 bytes of data at block download */ + uint8_t block_dataUploadLast[7]; + /** Calculated CRC checksum */ + uint16_t block_crc; +#endif +} CO_SDOclient_t; /** @@ -190,14 +200,13 @@ typedef struct{ * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_SDOclient_init( - CO_SDOclient_t *SDO_C, - CO_SDO_t *SDO, - CO_SDOclientPar_t *SDOClientPar, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx); +CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, + void *SDO, + CO_SDOclientPar_t *SDOClientPar, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx); #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN @@ -215,10 +224,9 @@ CO_ReturnError_t CO_SDOclient_init( * be NULL. * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_SDOclient_initCallbackPre( - CO_SDOclient_t *SDOclient, - void *object, - void (*pFunctSignal)(void *object)); +void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, + void *object, + void (*pFunctSignal)(void *object)); #endif @@ -243,11 +251,10 @@ void CO_SDOclient_initCallbackPre( * * @return #CO_SDOclient_return_t */ -CO_SDOclient_return_t CO_SDOclient_setup( - CO_SDOclient_t *SDO_C, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient, - uint8_t nodeIDOfTheSDOServer); +CO_SDOclient_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, + uint32_t COB_IDClientToServer, + uint32_t COB_IDServerToClient, + uint8_t nodeIDOfTheSDOServer); /** @@ -260,26 +267,65 @@ CO_SDOclient_return_t CO_SDOclient_setup( * @param SDO_C This object. * @param index Index of object in object dictionary in remote node. * @param subIndex Subindex of object in object dictionary in remote node. - * @param dataTx Pointer to data to be written. Data must be valid until end - * of communication. Note that data are aligned in little-endian - * format, because CANopen itself uses little-endian. Take care, - * when using processors with big-endian. - * @param dataSize Size of data in dataTx. + * @param sizeIndicated Optionally indicate size of data to be downloaded. + * Actual data are written with one or multiple CO_SDOclientDownloadBufWrite() + * calls. + * - If sizeIndicated is different than 0, then total number of data + * written by CO_SDOclientDownloadBufWrite() will be compared against + * sizeIndicated. Also sizeIndicated info will be passed to the server, which + * will compare actual data size downloaded. In case of mismatch, SDO abort + * message will be generated. + * - If sizeIndicated is 0, then actual data size will not be verified. * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. - * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * * @return #CO_SDOclient_return_t */ -CO_SDOclient_return_t CO_SDOclientDownloadInitiate( - CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - uint8_t *dataTx, - uint32_t dataSize, - uint16_t SDOtimeoutTime_ms, - uint8_t blockEnable, - uint32_t *timerNext_us); +CO_SDOclient_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, + uint16_t index, + uint8_t subIndex, + size_t sizeIndicated, + uint16_t SDOtimeoutTime_ms, + bool_t blockEnable); + + +/** + * Initiate SDO download communication - update size. + * + * This is optional function, which updates sizeIndicated, if it was not known + * in the CO_SDOclientDownloadInitiate() function call. This function can be + * used after CO_SDOclientDownloadBufWrite(), but must be used before + * CO_SDOclientDownload(). + * + * @param SDO_C This object. + * @param sizeIndicated Same as in CO_SDOclientDownloadInitiate(). + */ +void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, + size_t sizeIndicated); + + +/** + * Write data into SDO client buffer + * + * This function copies data from buf into internal SDO client fifo buffer. + * Function returns number of bytes successfully copied. If there is not enough + * space in destination, not all bytes will be copied. Additional data can be + * copied in next cycles. If there is enough space in destination and + * sizeIndicated is different than zero, then all data must be written at once. + * + * This function is basically a wrapper for CO_fifo_write() function. As + * alternative, other functions from CO_fifo can be used directly, for example + * CO_fifo_cpyTok2U8() or similar. + * + * @param SDO_C This object. + * @param buf Buffer which will be copied + * @param count Number of bytes in buf + * + * @return number of bytes actually written. + */ +size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, + const char *buf, + size_t count); /** @@ -289,20 +335,31 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate( * download communication initiated with CO_SDOclientDownloadInitiate(). * Function is non-blocking. * + * If function returns #CO_SDOcli_blockDownldInProgress and OS has buffer for + * CAN tx messages, then this function may be called multiple times within own + * loop. This can speed-up SDO block transfer. + * * @param SDO_C This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. - * @param [out] pSDOabortCode Pointer to external variable written by this - * function in case of error in communication. + * @param abort If true, SDO client will send abort message from SDOabortCode + * and transmission will be aborted. + * @param [out] SDOabortCode In case of error in communication, SDO abort code + * contains reason of error. Ignored if NULL. + * @param [out] sizeTransferred Actual size of data transferred. Ignored if NULL * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * - * @return #CO_SDOclient_return_t + * @return #CO_SDOclient_return_t. If less than 0, then error occurred, + * SDOabortCode contains reason and state becomes idle. If 0, communication + * ends successfully and state becomes idle. If greater than 0, then + * communication is in progress. */ -CO_SDOclient_return_t CO_SDOclientDownload( - CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - uint32_t *pSDOabortCode, - uint32_t *timerNext_us); +CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, + uint32_t timeDifference_us, + bool_t abort, + CO_SDO_abortCode_t *SDOabortCode, + size_t *sizeTransferred, + uint32_t *timerNext_us); /** @@ -315,26 +372,16 @@ CO_SDOclient_return_t CO_SDOclientDownload( * @param SDO_C This object. * @param index Index of object in object dictionary in remote node. * @param subIndex Subindex of object in object dictionary in remote node. - * @param dataRx Pointer to data buffer, into which received data will be - * written. Buffer must be valid until end of communication. Note that data are - * aligned in little-endian format, because CANopen itself uses little-endian. - * Take care, when using processors with big-endian. - * @param dataRxSize Size of dataRx. * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. - * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * * @return #CO_SDOclient_return_t */ -CO_SDOclient_return_t CO_SDOclientUploadInitiate( - CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - uint8_t *dataRx, - uint32_t dataRxSize, - uint16_t SDOtimeoutTime_ms, - uint8_t blockEnable, - uint32_t *timerNext_us); +CO_SDOclient_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, + uint16_t index, + uint8_t subIndex, + uint16_t SDOtimeoutTime_ms, + bool_t blockEnable); /** @@ -344,23 +391,58 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate( * upload communication initiated with CO_SDOclientUploadInitiate(). * Function is non-blocking. * + * If this function returns #CO_SDOcli_uploadDataBufferFull, then data must be + * read from fifo buffer to make it empty. This function can then be called + * once again immediately to speed-up block transfer. Note also, that remaining + * data must be read after function returns #CO_SDOcli_ok_communicationEnd. + * Data must not be read, if function returns #CO_SDOcli_blockUploadInProgress. + * * @param SDO_C This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. - * @param [out] pDataSize pointer to external variable, where size of received - * data will be written. - * @param [out] pSDOabortCode Pointer to external variable written by this - * function in case of error in communication. + * @param [out] SDOabortCode In case of error in communication, SDO abort code + * contains reason of error. Ignored if NULL. + * @param [out] sizeIndicated If larger than 0, then SDO server has indicated + * size of data transfer. Ignored if NULL. + * @param [out] sizeTransferred Actual size of data transferred. Ignored if NULL * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * - * @return #CO_SDOclient_return_t + * @return #CO_SDOclient_return_t. If less than 0, then error occurred, + * SDOabortCode contains reason and state becomes idle. If 0, communication + * ends successfully and state becomes idle. If greater than 0, then + * communication is in progress. + */ +CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, + uint32_t timeDifference_us, + CO_SDO_abortCode_t *SDOabortCode, + size_t *sizeIndicated, + size_t *sizeTransferred, + uint32_t *timerNext_us); + + +/** + * Read data from SDO client buffer. + * + * This function copies data from internal fifo buffer of SDO client into buf. + * Function returns number of bytes successfully copied. It can be called in + * multiple cycles, if data length is large. + * + * This function is basically a wrapper for CO_fifo_read() function. As + * alternative, other functions from CO_fifo can be used directly, for example + * CO_fifo_readU82a() or similar. + * + * @warning This function (or similar) must NOT be called when + * CO_SDOclientUpload() returns #CO_SDOcli_blockUploadInProgress! + * + * @param SDO_C This object. + * @param buf Buffer into which data will be copied + * @param count Copy up to count bytes into buffer + * + * @return number of bytes actually read. */ -CO_SDOclient_return_t CO_SDOclientUpload( - CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - uint32_t *pDataSize, - uint32_t *pSDOabortCode, - uint32_t *timerNext_us); +size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, + char *buf, + size_t count); /** diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 14176d60..105b719d 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -82,9 +82,10 @@ typedef enum { * - SDO server is waiting for client request. */ CO_SDO_ST_IDLE = 0x00U, /** - * - Node-ID of the SDO server is the same as node-ID of this node, SDO client - * is the same device as SDO server. Transfer data directly without - * communication on CAN. */ + * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, + * SDO client is the same device as SDO server. Transfer data directly without + * communication on CAN. + * - SDO server does not use this state. */ CO_SDO_ST_LOCAL_TRANSFER = 0x01U, /** * - SDO client or server may send SDO abort message in case of error: @@ -149,7 +150,7 @@ CO_SDO_ST_UPLOAD_INITIATE_RSP = 0x22U, * - SDO client requests SDO segment: * - byte 0: @b 011t0000 binary: (t: toggle bit, set to 0 in first segment). * - byte 1..7: Reserved. - * - SDO server waits for segment. */ + * - SDO server waits for segment request. */ CO_SDO_ST_UPLOAD_SEGMENT_REQ = 0x23U, /** * - SDO client waits for response. @@ -255,12 +256,6 @@ CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2 = 0x43U, * 1..127. * - byte 1..7: At most 7 bytes of segment data to be uploaded. */ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x44U, -/** - * This is interim state after server finished sending sequence of segments in - * one sub-block. This state is valid one cycle. In that state data should be - * emptied from internal buffer. In the next cycle client will send response and - * server will send another sequence of segments. */ -CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_DATA_RDY = 0x45U, /** * - SDO client responses: * - byte 0: @b 10100010 binary. @@ -274,7 +269,7 @@ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_DATA_RDY = 0x45U, * - byte 3..7: Reserved. * - SDO server waits for response. * - If c was set to 1, then communication enters SDO block upload end phase. */ -CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x46U, +CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x45U, /** * - SDO client waits for server request. * - SDO server sends SDO block upload end: @@ -282,7 +277,7 @@ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x46U, * contain data) * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. * - byte 3..7: Reserved. */ -CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x47U, +CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x46U, /** * - SDO client responses: * - byte 0: @b 10100001 binary. @@ -292,7 +287,7 @@ CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x47U, * with client response. Client may then start next SDO communication * immediately. */ -CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x48U, +CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x47U, /* old state names, will be removed */ CO_SDO_ST_DOWNLOAD_INITIATE = 0xA1U, @@ -839,7 +834,7 @@ static inline void CO_setUint32(uint8_t data[], const uint32_t value){ #ifdef CO_LITTLE_ENDIAN #define CO_memcpySwap2(dest, src) memcpy(dest, src, 2) #endif -#ifdef CO_BIG_ENDIAN +#if defined CO_BIG_ENDIAN || defined CO_DOXYGEN static inline void CO_memcpySwap2(void* dest, const void* src){ char *cdest; char *csrc; @@ -861,7 +856,7 @@ static inline void CO_memcpySwap2(void* dest, const void* src){ #ifdef CO_LITTLE_ENDIAN #define CO_memcpySwap4(dest, src) memcpy(dest, src, 4) #endif -#ifdef CO_BIG_ENDIAN +#if defined CO_BIG_ENDIAN || defined CO_DOXYGEN static inline void CO_memcpySwap4(void* dest, const void* src){ char *cdest; char *csrc; @@ -885,7 +880,7 @@ static inline void CO_memcpySwap4(void* dest, const void* src){ #ifdef CO_LITTLE_ENDIAN #define CO_memcpySwap8(dest, src) memcpy(dest, src, 8) #endif -#ifdef CO_BIG_ENDIAN +#if defined CO_BIG_ENDIAN || defined CO_DOXYGEN static inline void CO_memcpySwap8(void* dest, const void* src){ char *cdest; char *csrc; diff --git a/301/CO_config.h b/301/CO_config.h index 0fb5d027..3fbe8602 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -302,24 +302,40 @@ extern "C" { * * Possible flags, can be ORed: * - CO_CONFIG_GTW_MULTI_NET - Enable multiple network interfaces in gateway - * device. This functionality is currntly not implemented. + * device. This functionality is currently not implemented. * - CO_CONFIG_GTW_ASCII - Enable gateway device with ASCII mapping (CiA 309-3) + * - CO_CONFIG_GTW_ASCII_ERROR_DESC - Print error description as additional + * comments in gateway-ascii device for SDO and gateway errors. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | CO_CONFIG_GTW_ASCII) +#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | CO_CONFIG_GTW_ASCII | CO_CONFIG_GTW_ASCII_ERROR_DESC | CO_CONFIG_GTW_ASCII_PRINT_HELP) #endif #define CO_CONFIG_GTW_MULTI_NET 0x01 #define CO_CONFIG_GTW_ASCII 0x02 +#define CO_CONFIG_GTW_ASCII_ERROR_DESC 0x04 +#define CO_CONFIG_GTW_ASCII_PRINT_HELP 0x08 + + +/** + * Number of loops of #CO_SDOclientDownload() in case of block download + * + * If SDO clint has block download in progress and OS has buffer for CAN tx + * messages, then #CO_SDOclientDownload() functionion can be called multiple + * times within own loop (up to 127). This can speed-up SDO block transfer. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GTW_BLOCK_DL_LOOP 1 +#endif /** * Size of command buffer in ASCII gateway object. * - * If large amount of data is transferred (block transfer), the this should be + * If large amount of data is transferred (block transfer), then this should be * increased to 1000 or more. Buffer may be refilled between the block transfer. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_GTWA_COMM_BUF_SIZE 100 +#define CO_CONFIG_GTWA_COMM_BUF_SIZE 200 #endif diff --git a/301/CO_driver.h b/301/CO_driver.h index f66a5b93..87ce3829 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -82,12 +82,6 @@ extern "C" { #define CO_CONFIG_GTW (0) #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -#ifndef CO_CONFIG_GTWA_COMM_BUF_SIZE -#define CO_CONFIG_GTWA_COMM_BUF_SIZE 100 -#endif -#endif - /** * @defgroup CO_driver Driver * @ingroup CO_CANopen_301 @@ -100,7 +94,7 @@ extern "C" { * multiple threads. Reception of CAN messages is pre-processed with very fast * functions. Time critical objects, such as PDO or SYNC are processed in * real-time thread and other objects are processed in normal thread. See - * Flowchart in [README.md](README.md) for more information. + * Flowchart in [README.md](index.html) for more information. * * @anchor CO_obj * #### CANopenNode Object @@ -164,6 +158,12 @@ extern "C" { */ /** CO_LITTLE_ENDIAN or CO_BIG_ENDIAN must be defined */ #define CO_LITTLE_ENDIAN +/** Macro must swap bytes, if CO_BIG_ENDIAN is defined */ +#define CO_SWAP_16(x) x +/** Macro must swap bytes, if CO_BIG_ENDIAN is defined */ +#define CO_SWAP_32(x) x +/** Macro must swap bytes, if CO_BIG_ENDIAN is defined */ +#define CO_SWAP_64(x) x /** NULL, for general usage */ #define NULL (0) /** Logical true, for general use */ @@ -191,7 +191,7 @@ typedef unsigned long long int uint64_t; /** REAL32 in CANopen (0008h), single precision floating point value, 32-bit */ typedef float float32_t; /** REAL64 in CANopen (0011h), double precision floating point value, 64-bit */ -typedef long double float64_t; +typedef double float64_t; /** VISIBLE_STRING in CANopen (0009h), string of signed 8-bit values */ typedef char char_t; /** OCTET_STRING in CANopen (000Ah), string of unsigned 8-bit values */ @@ -377,7 +377,7 @@ typedef struct { * @defgroup CO_critical_sections Critical sections * @{ * CANopenNode is designed to run in different threads, as described in - * [README.md](README.md). Threads are implemented differently in different + * [README.md](index.html). Threads are implemented differently in different * systems. In microcontrollers threads are interrupts with different * priorities, for example. It is necessary to protect sections, where different * threads access to the same resource. In simple systems interrupts or diff --git a/301/CO_fifo.c b/301/CO_fifo.c new file mode 100644 index 00000000..9ad350a7 --- /dev/null +++ b/301/CO_fifo.c @@ -0,0 +1,1159 @@ +/* + * FIFO circular buffer + * + * @file CO_fifo.c + * @ingroup CO_CANopen_309_fifo + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "301/CO_fifo.h" + +#include +#include +#include + +#if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 +#include +#include + +/* Non-graphical character for command delimiter */ +#define DELIM_COMMAND '\n' +/* Graphical character for comment delimiter */ +#define DELIM_COMMENT '#' +#endif /* CO_CONFIG_FIFO_ASCII_COMMANDS == 1 */ + + +/******************************************************************************/ +void CO_fifo_init(CO_fifo_t *fifo, char *buf, size_t bufSize) { + + if (fifo == NULL || buf == NULL || bufSize < 2) { + return; + } + + fifo->readPtr = 0; + fifo->writePtr = 0; + fifo->buf = buf; + fifo->bufSize = bufSize; + + return; +} + + +#if CO_CONFIG_FIFO_CRC16_CCITT == 1 +/* CRC calculation algorithm + * Author of the original crc16 ccitt C code is Lammert Bies. + * + * CRC table is calculated by the following algorithm: + * + * void CO_fifo_crc16_ccitt_table_init(void) { + * uint16_t i, j; + * for (i = 0; i < 256; i++) { + * uint16_t crc = 0; + * uint16_t c = i << 8; + * for(j = 0; j < 8; j++) { + * if((crc ^ c) & 0x8000) crc = (crc << 1) ^ 0x1021; + * else crc = crc << 1; + * c = c << 1; + * } + * CO_fifo_crc16_ccitt_table[i] = crc; + * } + * } */ +static const uint16_t CO_fifo_crc16_ccitt_table[256] = { + 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50A5U, 0x60C6U, 0x70E7U, + 0x8108U, 0x9129U, 0xA14AU, 0xB16BU, 0xC18CU, 0xD1ADU, 0xE1CEU, 0xF1EFU, + 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52B5U, 0x4294U, 0x72F7U, 0x62D6U, + 0x9339U, 0x8318U, 0xB37BU, 0xA35AU, 0xD3BDU, 0xC39CU, 0xF3FFU, 0xE3DEU, + 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64E6U, 0x74C7U, 0x44A4U, 0x5485U, + 0xA56AU, 0xB54BU, 0x8528U, 0x9509U, 0xE5EEU, 0xF5CFU, 0xC5ACU, 0xD58DU, + 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76D7U, 0x66F6U, 0x5695U, 0x46B4U, + 0xB75BU, 0xA77AU, 0x9719U, 0x8738U, 0xF7DFU, 0xE7FEU, 0xD79DU, 0xC7BCU, + 0x48C4U, 0x58E5U, 0x6886U, 0x78A7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, + 0xC9CCU, 0xD9EDU, 0xE98EU, 0xF9AFU, 0x8948U, 0x9969U, 0xA90AU, 0xB92BU, + 0x5AF5U, 0x4AD4U, 0x7AB7U, 0x6A96U, 0x1A71U, 0x0A50U, 0x3A33U, 0x2A12U, + 0xDBFDU, 0xCBDCU, 0xFBBFU, 0xEB9EU, 0x9B79U, 0x8B58U, 0xBB3BU, 0xAB1AU, + 0x6CA6U, 0x7C87U, 0x4CE4U, 0x5CC5U, 0x2C22U, 0x3C03U, 0x0C60U, 0x1C41U, + 0xEDAEU, 0xFD8FU, 0xCDECU, 0xDDCDU, 0xAD2AU, 0xBD0BU, 0x8D68U, 0x9D49U, + 0x7E97U, 0x6EB6U, 0x5ED5U, 0x4EF4U, 0x3E13U, 0x2E32U, 0x1E51U, 0x0E70U, + 0xFF9FU, 0xEFBEU, 0xDFDDU, 0xCFFCU, 0xBF1BU, 0xAF3AU, 0x9F59U, 0x8F78U, + 0x9188U, 0x81A9U, 0xB1CAU, 0xA1EBU, 0xD10CU, 0xC12DU, 0xF14EU, 0xE16FU, + 0x1080U, 0x00A1U, 0x30C2U, 0x20E3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, + 0x83B9U, 0x9398U, 0xA3FBU, 0xB3DAU, 0xC33DU, 0xD31CU, 0xE37FU, 0xF35EU, + 0x02B1U, 0x1290U, 0x22F3U, 0x32D2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, + 0xB5EAU, 0xA5CBU, 0x95A8U, 0x8589U, 0xF56EU, 0xE54FU, 0xD52CU, 0xC50DU, + 0x34E2U, 0x24C3U, 0x14A0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, + 0xA7DBU, 0xB7FAU, 0x8799U, 0x97B8U, 0xE75FU, 0xF77EU, 0xC71DU, 0xD73CU, + 0x26D3U, 0x36F2U, 0x0691U, 0x16B0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, + 0xD94CU, 0xC96DU, 0xF90EU, 0xE92FU, 0x99C8U, 0x89E9U, 0xB98AU, 0xA9ABU, + 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18C0U, 0x08E1U, 0x3882U, 0x28A3U, + 0xCB7DU, 0xDB5CU, 0xEB3FU, 0xFB1EU, 0x8BF9U, 0x9BD8U, 0xABBBU, 0xBB9AU, + 0x4A75U, 0x5A54U, 0x6A37U, 0x7A16U, 0x0AF1U, 0x1AD0U, 0x2AB3U, 0x3A92U, + 0xFD2EU, 0xED0FU, 0xDD6CU, 0xCD4DU, 0xBDAAU, 0xAD8BU, 0x9DE8U, 0x8DC9U, + 0x7C26U, 0x6C07U, 0x5C64U, 0x4C45U, 0x3CA2U, 0x2C83U, 0x1CE0U, 0x0CC1U, + 0xEF1FU, 0xFF3EU, 0xCF5DU, 0xDF7CU, 0xAF9BU, 0xBFBAU, 0x8FD9U, 0x9FF8U, + 0x6E17U, 0x7E36U, 0x4E55U, 0x5E74U, 0x2E93U, 0x3EB2U, 0x0ED1U, 0x1EF0U +}; + +/* + * Update crc16_ccitt variable with one data byte + * + * This function updates crc variable for one data byte using crc16 ccitt + * algorithm. Function is used inside CO_fifo_write() and CO_fifo_altRead(). + * User can also provide own function for crc calculation. + * + * @param [in,out] crc Externally defined variable for CRC checksum + * @param chr One byte of data + */ +static inline void CO_fifo_crc16_ccitt(uint16_t *crc, const char chr) { + uint8_t tmp = (uint8_t)(*crc >> 8) ^ (uint8_t)chr; + *crc = (*crc << 8) ^ CO_fifo_crc16_ccitt_table[tmp]; +} +#endif /* CO_CONFIG_FIFO_CRC16_CCITT == 1 */ + + +/* Circular FIFO buffer example for fifo->bufSize = 7 (usable size = 6): ****** + * * + * 0 * * * * * + * 1 rp==wp readPtr writePtr * * + * 2 * * * * * + * 3 * * * writePtr * + * 4 * writePtr readPtr readPtr * + * 5 * * * * * + * 6 * * * * * + * * + * empty 3 bytes 4 bytes buffer * + * buffer in buff in buff full * + ******************************************************************************/ +size_t CO_fifo_write(CO_fifo_t *fifo, + const char *buf, + size_t count, + uint16_t *crc) +{ + size_t i; + char *bufDest; + + if (fifo == NULL || buf == NULL) { + return 0; + } + + bufDest = &fifo->buf[fifo->writePtr]; + for (i = count; i > 0; i--) { + size_t writePtrNext = fifo->writePtr + 1; + + /* is circular buffer full */ + if (writePtrNext == fifo->readPtr || + (writePtrNext == fifo->bufSize && fifo->readPtr == 0)) { + break; + } + + *bufDest = *buf; + +#if CO_CONFIG_FIFO_CRC16_CCITT > 0 + if (crc != NULL) { + CO_fifo_crc16_ccitt(crc, *buf); + } +#endif + + /* increment variables */ + if (writePtrNext == fifo->bufSize) { + fifo->writePtr = 0; + bufDest = &fifo->buf[0]; + } + else { + fifo->writePtr++; + bufDest++; + } + buf++; + } + + return count - i; +} + + +/******************************************************************************/ +size_t CO_fifo_read(CO_fifo_t *fifo, char *buf, size_t count, bool_t *eof) { + size_t i; + const char *bufSrc; + + if (eof != NULL) { + *eof = false; + } + if (fifo == NULL || buf == NULL || fifo->readPtr == fifo->writePtr) { + return 0; + } + + bufSrc = &fifo->buf[fifo->readPtr]; + for (i = count; i > 0; ) { + const char c = *bufSrc; + + /* is circular buffer empty */ + if (fifo->readPtr == fifo->writePtr) { + break; + } + + *(buf++) = c; + + /* increment variables */ + if (++fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + bufSrc = &fifo->buf[0]; + } + else { + bufSrc++; + } + i--; + +#if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 + /* is delimiter? */ + if (eof != NULL && c == DELIM_COMMAND) { + *eof = true; + break; + } +#endif + } + + return count - i; +} + + +#if CO_CONFIG_FIFO_ALT_READ == 1 +/******************************************************************************/ +size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset) { + size_t i; + + if (fifo == NULL) { + return 0; + } + + fifo->altReadPtr = fifo->readPtr; + for (i = offset; i > 0; i--) { + /* is circular buffer empty */ + if (fifo->altReadPtr == fifo->writePtr) { + break; + } + + /* increment variable */ + if (++fifo->altReadPtr == fifo->bufSize) { + fifo->altReadPtr = 0; + } + } + + return offset - i; +} + +void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { + + if (fifo == NULL) { + return; + } + + if (crc == NULL) { + fifo->readPtr = fifo->altReadPtr; + } + else { + const char *bufSrc = &fifo->buf[fifo->readPtr]; + while (fifo->readPtr != fifo->altReadPtr) { +#if CO_CONFIG_FIFO_CRC16_CCITT > 0 + CO_fifo_crc16_ccitt(crc, *bufSrc); +#endif + /* increment variable */ + if (++fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + bufSrc = &fifo->buf[0]; + } + else { + bufSrc++; + } + } + } +} + +size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count) +{ + size_t i; + const char *bufSrc; + + bufSrc = &fifo->buf[fifo->altReadPtr]; + for (i = count; i > 0; i--) { + const char c = *bufSrc; + + /* is there no more data */ + if (fifo->altReadPtr == fifo->writePtr) { + break; + } + + *(buf++) = c; + + /* increment variables */ + if (++fifo->altReadPtr == fifo->bufSize) { + fifo->altReadPtr = 0; + bufSrc = &fifo->buf[0]; + } + else { + bufSrc++; + } + } + + return count - i; +} +#endif /* CO_CONFIG_FIFO_ALT_READ == 1 */ + + +#if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 +/******************************************************************************/ +bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { + bool_t newCommand = false; + size_t count; + char *commandEnd; + + if (fifo == NULL || fifo->readPtr == fifo->writePtr) { + return 0; + } + + /* search delimiter until writePtr or until end of buffer */ + if (fifo->readPtr < fifo->writePtr) { + count = fifo->writePtr - fifo->readPtr; + } else { + count = fifo->bufSize - fifo->readPtr; + } + commandEnd = (char *)memchr((const void *)&fifo->buf[fifo->readPtr], + DELIM_COMMAND, + count); + if (commandEnd != NULL) { + newCommand = true; + } + else if (fifo->readPtr > fifo->writePtr) { + /* not found, search in the beginning of the circular buffer */ + commandEnd = (char *)memchr((const void *)&fifo->buf[0], + DELIM_COMMAND, + fifo->writePtr); + if (commandEnd != NULL || fifo->readPtr == (fifo->writePtr + 1)) { + /* command delimiter found or buffer full */ + newCommand = true; + } + } + else if (fifo->readPtr == 0 && fifo->writePtr == (fifo->bufSize - 1)) { + /* buffer full */ + newCommand = true; + } + + /* Clear buffer if set so */ + if (clear) { + if (commandEnd != NULL) { + fifo->readPtr = (int)(commandEnd - fifo->buf) + 1; + if (fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + } + } + else { + fifo->readPtr = fifo->writePtr; + } + } + + return newCommand; +} + + +/******************************************************************************/ +bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo) { + bool_t delimCommandFound = false; + + if (fifo != NULL) { + while (fifo->readPtr != fifo->writePtr) { + char c = fifo->buf[fifo->readPtr]; + + if (c == DELIM_COMMENT) { + /* comment found, clear all until next DELIM_COMMAND */ + while (fifo->readPtr != fifo->writePtr) { + if (++fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + } + if (c == DELIM_COMMAND) { + delimCommandFound = true; + break; + } + } + break; + } + else if (isgraph(c) != 0) { + break; + } + if (++fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + } + if (c == DELIM_COMMAND) { + delimCommandFound = true; + break; + } + } + } + return delimCommandFound; +} + + +/******************************************************************************/ +size_t CO_fifo_readToken(CO_fifo_t *fifo, + char *buf, + size_t count, + char *closed, + bool_t *err) +{ + bool_t delimCommandFound = false; + bool_t delimCommentFound = false; + size_t tokenSize = 0; + + if (fifo != NULL && buf != NULL && count > 1 && (err == NULL || *err == 0) + && fifo->readPtr != fifo->writePtr + ) { + bool_t finished = false; + char step = 0; + size_t ptr = fifo->readPtr; /* current pointer (integer, 0 based) */ + char *c = &fifo->buf[ptr]; /* current char */ + do { + switch (step) { + case 0: /* skip leading empty characters, stop on delimiter */ + if (isgraph(*c) != 0) { + if (*c == DELIM_COMMENT) { + delimCommentFound = true; + } else { + buf[tokenSize++] = *c; + step++; + } + } + else if (*c == DELIM_COMMAND) { + delimCommandFound = true; + } + break; + case 1: /* search for end of the token */ + if (isgraph(*c) != 0) { + if (*c == DELIM_COMMENT) { + delimCommentFound = true; + } else if (tokenSize < count) { + buf[tokenSize++] = *c; + } + } + else { + if (*c == DELIM_COMMAND) { + delimCommandFound = true; + } + step++; + } + break; + case 2: /* skip trailing empty characters */ + if (isgraph(*c) != 0) { + if (*c == DELIM_COMMENT) { + delimCommentFound = true; + } else { + fifo->readPtr = ptr; + finished = true; + } + } + else if (*c == DELIM_COMMAND) { + delimCommandFound = true; + } + break; + } + if (delimCommentFound == true) { + /* Comment delimiter found, clear all till end of the line. */ + fifo->readPtr = ptr; + delimCommandFound = CO_fifo_CommSearch(fifo, true); + finished = true; + } + else if (delimCommandFound) { + /* command delimiter found, set readPtr behind it. */ + if (++ptr == fifo->bufSize) ptr = 0; + fifo->readPtr = ptr; + finished = true; + } + else if (!finished) { + /* find next character in the circular buffer */ + if (++ptr == fifo->bufSize) { + ptr = 0; + c = &fifo->buf[ptr]; + } + else { + c++; + } + /* end, if buffer is now empty */ + if (ptr == fifo->writePtr) { + if (step == 2) { + fifo->readPtr = ptr; + } + else { + tokenSize = 0; + } + finished = true; + } + } + } while (!finished); + } + + /* set 'err' return value */ + if (err != NULL && *err == false) { + if (tokenSize == count || (closed != NULL && + ((*closed == 1 && (!delimCommandFound || tokenSize == 0)) || + (*closed == 0 && (delimCommandFound || tokenSize == 0))) + )) { + *err = true; + } + } + /* set 'closed' return value */ + if (closed != NULL) { + *closed = delimCommandFound ? 1 : 0; + } + + /* token was larger then size of the buffer, all was cleaned, return '' */ + if (tokenSize == count) { + tokenSize = 0; + } + /* write string terminator character */ + if (buf != NULL && count > tokenSize) { + buf[tokenSize] = '\0'; + } + + return tokenSize; +} + + +/******************************************************************************/ +size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + uint8_t n; + + if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "0x%02"PRIX8, n); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + uint16_t n; + + if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + uint32_t n; + + if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + uint64_t n; + + if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + int8_t n; + + if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "%"PRId8, n); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + int16_t n; + + if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "%"PRId16, CO_SWAP_16(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + int32_t n; + + if (fifo != NULL && count >= 13 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "%"PRId32, CO_SWAP_32(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + int64_t n; + + if (fifo != NULL && count >= 23 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "%"PRId64, CO_SWAP_64(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + float32_t n; + + if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "%g", CO_SWAP_32(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + float64_t n; + + if (fifo != NULL && count >= 30 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "%g", CO_SWAP_64(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + size_t len = 0; + + if (fifo != NULL && count > 3) { + /* Very first write is without leading space */ + if (!fifo->started) { + char c; + if(CO_fifo_getc(fifo, &c)) { + len = sprintf(&buf[0], "%02"PRIX8, (uint8_t)c); + fifo->started = true; + } + } + + while ((len + 3) < count) { + char c; + if(!CO_fifo_getc(fifo, &c)) { + break; + } + len += sprintf(&buf[len], " %02"PRIX8, (uint8_t)c); + } + } + + return len; +} + +size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + size_t len = 0; + + if (fifo != NULL && count > 3) { + /* Start with '"' */ + if (!fifo->started) { + buf[len++] = '"'; + fifo->started = true; + } + + while ((len + 2) < count) { + char c; + if(!CO_fifo_getc(fifo, &c)) { + if (end) { + buf[len++] = '"'; + } + break; + } + if (c == '"') { + buf[len++] = '"'; + } + buf[len++] = c; + } + } + + return len; +} + + +/******************************************************************************/ +size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[15]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + uint32_t u32 = strtoul(buf, &sRet, 0); + if (sRet != strchr(buf, '\0') || u32 > UINT8_MAX) st |= 20; + else { + uint8_t num = (uint8_t) u32; + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[15]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + uint32_t u32 = strtoul(buf, &sRet, 0); + if (sRet != strchr(buf, '\0') || u32 > UINT16_MAX) st |= 20; + else { + uint16_t num = CO_SWAP_16((uint16_t) u32); + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[15]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + uint32_t u32 = strtoul(buf, &sRet, 0); + if (sRet != strchr(buf, '\0')) st |= 20; + else { + uint32_t num = CO_SWAP_32(u32); + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[25]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + uint64_t u64 = strtoull(buf, &sRet, 0); + if (sRet != strchr(buf, '\0')) st |= 20; + else { + uint64_t num = CO_SWAP_64(u64); + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[15]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + int32_t i32 = strtol(buf, &sRet, 0); + if (sRet != strchr(buf, '\0') || i32 < INT8_MIN || i32 > INT8_MAX) { + st |= 20; + } else { + int8_t num = (int8_t) i32; + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[15]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + int32_t i32 = strtol(buf, &sRet, 0); + if (sRet != strchr(buf, '\0') || i32 < INT16_MIN || i32 > INT16_MAX) { + st |= 20; + } else { + int16_t num = CO_SWAP_16((int16_t) i32); + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[15]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + int32_t i32 = strtol(buf, &sRet, 0); + if (sRet != strchr(buf, '\0')) st |= 20; + else { + int32_t num = CO_SWAP_32(i32); + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[25]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + int64_t i64 = strtoll(buf, &sRet, 0); + if (sRet != strchr(buf, '\0')) st |= 20; + else { + int64_t num = CO_SWAP_64(i64); + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[30]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + float32_t f32 = strtof(buf, &sRet); + if (sRet != strchr(buf, '\0')) st |= 20; + else { + float32_t num = CO_SWAP_32(f32); + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + char buf[40]; + char st = -1; + bool_t err = 0; + size_t nWr = 0; + + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); + if (nRd == 0 || err) st |= 0x10; + else { + char *sRet; + float64_t f64 = strtof(buf, &sRet); + if (sRet != strchr(buf, '\0')) st |= 20; + else { + float64_t num = CO_SWAP_64(f64); + nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + if (nWr != sizeof(num)) st |= 0x40; + } + } + if (status != NULL) *status = (uint8_t) st; + return nWr; +} + +size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + size_t destSpace, destSpaceStart; + bool_t finished = false; + uint8_t st = 0; + + if (dest == NULL || src == NULL) { + return 0; + } + + /* get free space of the dest fifo */ + destSpaceStart = destSpace = CO_fifo_getSpace(dest); + + /* repeat until destination space available and no error and not finished + * and source characters available */ + while (destSpace > 0 && (st & 0xF0) == 0 && !finished) { + char c; + if (!CO_fifo_getc(src, &c)) { + break; + } + + if (dest->started == false) { + /* search for first of two hex digits in token */ + if (isxdigit(c) != 0) { + /* first hex digit is known */ + dest->aux = c; + dest->started = true; + } + else if (c == DELIM_COMMAND) { + /* newline found, finish */ + st |= 0x01; + finished = true; + } + else if (c == DELIM_COMMENT) { + /* comment found, clear line and finish */ + while (CO_fifo_getc(src, &c)) { + if (c == DELIM_COMMAND) { + st |= 0x01; + break; + } + } + finished = true; + } + else if (isgraph(c) != 0) { + /* printable character, not hex digit, error */ + st |= 0x10; + } + /* else just skip empty space */ + } + else { + /* one hex digit is known, what is next */ + if (isxdigit(c) != 0) { + /* two hex digits are known */ + char s[3]; + int32_t num; + s[0] = (char) dest->aux; s[1] = c, s[2] = 0; + num = strtol(s, NULL, 16); + /* copy the character */ + CO_fifo_putc(dest, (char) num); + destSpace--; + } + else if (isgraph(c) != 0 && c != DELIM_COMMENT) { + /* printable character, not hex digit, error */ + st |= 0x10; + } + else { + /* this is space or comment, single hex digit is known */ + char s[2]; + int32_t num; + s[0] = (char) dest->aux; s[1] = 0; + num = strtol(s, NULL, 16); + /* copy the character */ + CO_fifo_putc(dest, (char) num); + destSpace--; + if (c == DELIM_COMMAND) { + /* newline found, finish */ + st |= 0x01; + finished = true; + } + else if (c == DELIM_COMMENT) { + /* comment found, clear line and finish */ + while (CO_fifo_getc(src, &c)) { + if (c == DELIM_COMMAND) { + st |= 0x01; + break; + } + } + finished = true; + } + } + dest->started = false; + } + } + + if (!finished) { + st |= 0x02; + } + + if (status != NULL) *status = st; + + return destSpaceStart - destSpace; +} + +size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { + size_t destSpace, destSpaceStart; + bool_t finished = false; + uint8_t st = 0; + + if (dest == NULL || src == NULL) { + return 0; + } + + /* get free space of the dest fifo */ + destSpaceStart = destSpace = CO_fifo_getSpace(dest); + + /* is this the first write into dest? */ + if (!dest->started) { + /* aux variable is used as state here */ + dest->aux = 0; + dest->started = true; + } + + /* repeat until destination space available and no error and not finished + * and source characters available */ + while (destSpace > 0 && (st & 0xF0) == 0 && !finished) { + char c; + if (!CO_fifo_getc(src, &c)) { + break; + } + + switch (dest->aux) { + case 0: /* beginning of the string, first write into dest */ + if (isgraph(c) == 0 || c == DELIM_COMMENT) { + if (CO_fifo_trimSpaces(src)) { + /* newline found without string, this is an error */ + st |= 0x10; + } + } + else if (c == '"') { + /* Indicated beginning of the string, skip this character. */ + dest->aux = 1; + } + else { + /* this must be a single word string without '"' */ + /* copy the character */ + CO_fifo_putc(dest, c); + destSpace--; + dest->aux = 2; + } + break; + + case 1: /* inside string, quoted string */ + case 2: /* inside string, single word, no quotes */ + if (c == '"') { + /* double qoute found, this may be end of the string or escaped + * double quote (with two double quotes) */ + dest->aux += 2; + } + else if (isgraph(c) == 0 && dest->aux == 2) { + /* end of single word string */ + if (c == DELIM_COMMAND) { + st |= 0x01; + } + else if (CO_fifo_trimSpaces(src)) { + st |= 0x01; + } + finished = true; + } + else if (c == DELIM_COMMAND) { + /* no closing quote, error */ + st |= 0x10; + } + else { + /* copy the character */ + CO_fifo_putc(dest, c); + destSpace--; + } + break; + + case 3: /* previous was double quote, parsing quoted string */ + case 4: /* previous was double quote, parsing no quoted word */ + if (c == '"') { + /* escaped double quote, copy the character and continue */ + CO_fifo_putc(dest, c); + destSpace--; + dest->aux -= 2; + } + else { + /* previous character was closing double quote */ + if (dest->aux == 4) { + /* no opening double quote, syntax error */ + st |= 0x10; + } + else { + if (isgraph(c) == 0) { + /* string finished */ + if (c == DELIM_COMMAND) { + st |= 0x01; + } + else if (CO_fifo_trimSpaces(src)) { + st |= 0x01; + } + finished = true; + } + else { + /* space must follow closing double quote, error */ + st |= 0x10; + } + } + } + break; + + default: /* error */ + st |= 0x80; + break; + } + } + + if (!finished) { + st |= 0x02; + } + + if (status != NULL) *status = st; + + return destSpaceStart - destSpace; +} + +#endif /* CO_CONFIG_FIFO_ASCII_COMMANDS == 1 */ diff --git a/301/CO_fifo.h b/301/CO_fifo.h new file mode 100644 index 00000000..9f062bee --- /dev/null +++ b/301/CO_fifo.h @@ -0,0 +1,476 @@ +/** + * FIFO circular buffer + * + * @file CO_fifo.h + * @ingroup CO_CANopen_301_fifo + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CO_FIFO_H +#define CO_FIFO_H + + +#include "301/CO_driver.h" + + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#ifndef CO_CONFIG_FIFO_ALT_READ +#define CO_CONFIG_FIFO_ALT_READ 1 +#endif +#ifndef CO_CONFIG_FIFO_CRC16_CCITT +#define CO_CONFIG_FIFO_CRC16_CCITT 1 +#endif +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#ifndef CO_CONFIG_FIFO_ASCII_COMMANDS +#define CO_CONFIG_FIFO_ASCII_COMMANDS 1 +#endif +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_CANopen_301_fifo FIFO circular buffer + * @ingroup CO_CANopen_301 + * @{ + * + * FIFO is organized as circular buffer with predefined capacity. It must be + * initialized by CO_fifo_init(). Functions are not not thread safe. + * + * It can be used as general purpose FIFO circular buffer for any data. Data can + * be written by CO_fifo_write() and read by CO_fifo_read() functions. + * + * Buffer has additional functions for usage with CiA309-3 standard. It acts as + * circular buffer for storing ascii commands and fetching tokens from them. + */ + +/** + * Fifo object + */ +typedef struct { + /** Buffer of size bufSize. Initialized by CO_fifo_init() */ + char *buf; + /** Initialized by CO_fifo_init() */ + size_t bufSize; + /** Location in the buffer, which will be next written. */ + size_t writePtr; + /** Location in the buffer, which will be next read. */ + size_t readPtr; +#if CO_CONFIG_FIFO_ALT_READ > 0 || defined CO_DOXYGEN + /** Location in the buffer, which will be next read. */ + size_t altReadPtr; +#endif +#if CO_CONFIG_FIFO_ASCII_COMMANDS > 0 || defined CO_DOXYGEN + /** helper variable, set to false in CO_fifo_reset(), used in some + * functions. */ + bool_t started; + /** auxiliary variable, used in some functions. */ + uint32_t aux; +#endif +} CO_fifo_t; + + + +/** + * Initialize fifo object + * + * @param fifo This object will be initialized + * @param buf Pointer to externally defined buffer + * @param bufSize Size of the above buffer. Usable size of the buffer will be + * one byte less than bufSize, it is used for operation of the circular buffer. + */ +void CO_fifo_init(CO_fifo_t *fifo, char *buf, size_t bufSize); + + +/** + * Reset fifo object, make it empty + * + * @param fifo This object + */ +static inline void CO_fifo_reset(CO_fifo_t *fifo) { + if (fifo != NULL) { + fifo->readPtr = 0; + fifo->writePtr = 0; +#if CO_CONFIG_FIFO_ASCII_COMMANDS > 0 + fifo->started = false; +#endif + } + + return; +} + + +/** + * Get free buffer space in CO_fifo_t object + * + * @param fifo This object + * + * @return number of available bytes + */ +static inline size_t CO_fifo_getSpace(CO_fifo_t *fifo) { + int sizeLeft = (int)fifo->readPtr - fifo->writePtr - 1; + if (sizeLeft < 0) { + sizeLeft += fifo->bufSize; + } + + return (size_t) sizeLeft; +} + + +/** + * Get size of data inside CO_fifo_t buffer object + * + * @param fifo This object + * + * @return number of occupied bytes + */ +static inline size_t CO_fifo_getOccupied(CO_fifo_t *fifo) { + int sizeOccupied = (int)fifo->writePtr - fifo->readPtr; + if (sizeOccupied < 0) { + sizeOccupied += fifo->bufSize; + } + + return (size_t) sizeOccupied; +} + + +/** + * Put one character into CO_fifo_t buffer object + * + * @param fifo This object + * @param c Character to put + * + * @return true, if write was successful (enough space in fifo buffer) + */ +static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const char c) { + if (fifo != NULL) { + size_t writePtrNext = fifo->writePtr + 1; + if (writePtrNext != fifo->readPtr && + !(writePtrNext == fifo->bufSize && fifo->readPtr == 0)) + { + fifo->buf[fifo->writePtr] = c; + fifo->writePtr = (writePtrNext == fifo->bufSize) ? 0 : writePtrNext; + return true; + } + } + return false; +} + + +/** + * Get one character from CO_fifo_t buffer object + * + * @param fifo This object + * @param buf Buffer of length one byte, where character will be copied + * + * @return true, if read was successful (non-empty fifo buffer) + */ +static inline bool_t CO_fifo_getc(CO_fifo_t *fifo, char *buf) { + if (fifo != NULL && buf != NULL && fifo->readPtr != fifo->writePtr) { + *buf = fifo->buf[fifo->readPtr]; + if (++fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + } + return true; + } + return false; +} + + +/** + * Write data into CO_fifo_t object. + * + * This function copies data from buf into internal buffer of CO_fifo_t + * object. Function returns number of bytes successfully copied. + * If there is not enough space in destination, not all bytes will be copied. + * + * @param fifo This object + * @param buf Buffer which will be copied + * @param count Number of bytes in buf + * @param [in,out] crc Externally defined variable for CRC checksum, ignored if + * NULL + * + * @return number of bytes actually written. + */ +size_t CO_fifo_write(CO_fifo_t *fifo, + const char *buf, + size_t count, + uint16_t *crc); + + +/** + * Read data from CO_fifo_t object. + * + * This function copies data from internal buffer of CO_fifo_t object into + * buf. Function returns number of bytes successfully copied. Function also + * writes true into eof argument, if command delimiter character is reached. + * + * @param fifo This object + * @param buf Buffer into which data will be copied + * @param count Copy up to count bytes into buffer + * @param [out] eof If different than NULL, then search for delimiter character. + * If found, then read up to (including) that character and set *eof to true. + * Otherwise set *eof to false. + * + * @return number of bytes actually read. + */ +size_t CO_fifo_read(CO_fifo_t *fifo, char *buf, size_t count, bool_t *eof); + + +#if CO_CONFIG_FIFO_ALT_READ > 0 || defined CO_DOXYGEN +/** + * Initializes alternate read with #CO_fifo_altRead + * + * @param fifo This object + * @param offset Offset in bytes from original read pointer + * + * @return same as offset or lower, if there is not enough data. + */ +size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset); + + +/** + * Ends alternate read with #CO_fifo_altRead and calculate crc checksum + * + * @param fifo This object + * @param [in,out] crc Externally defined variable for CRC checksum, ignored if + * NULL + */ +void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc); + + +/** + * Get alternate size of remaining data, see #CO_fifo_altRead + * + * @param fifo This object + * + * @return number of occupied bytes. + */ +static inline size_t CO_fifo_altGetOccupied(CO_fifo_t *fifo) { + int sizeOccupied = (int)fifo->writePtr - fifo->altReadPtr; + if (sizeOccupied < 0) { + sizeOccupied += fifo->bufSize; + } + + return (size_t) sizeOccupied; +} + + +/** + * Alternate read data from CO_fifo_t object. + * + * This function is similar as CO_fifo_read(), but uses alternate read pointer + * inside circular buffer. It reads data from the buffer and data remains in it. + * This function uses alternate read pointer and keeps original read pointer + * unchanged. Before using this function, alternate read pointer must be + * initialized with CO_fifo_altBegin(). CO_fifo_altFinish() sets original read + * pointer to alternate read pointer and so empties the buffer. + * + * @param fifo This object + * @param buf Buffer into which data will be copied + * @param count Copy up to count bytes into buffer + * + * @return number of bytes actually read. + */ +size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count); +#endif /* CO_CONFIG_FIFO_ALT_READ > 0 */ + + +#if CO_CONFIG_FIFO_ASCII_COMMANDS > 0 || defined CO_DOXYGEN +/** + * Search command inside FIFO + * + * If there are some data inside the FIFO, then search for command delimiter. + * + * If command is long, then in the buffer may not be enough space for it. + * In that case buffer is full and no delimiter is present. Function then + * returns true and command should be processed for the starting tokens. + * Buffer can later be refilled multiple times, until command is closed by + * command delimiter. + * + * If this function returns different than 0, then buffer is usually read + * by multiple CO_fifo_readToken() calls. If reads was successful, then + * delimiter is reached and fifo->readPtr is set after the command. If any + * CO_fifo_readToken() returns nonzero *err, then there is an error and command + * should be cleared. All this procedure must be implemented inside single + * function call. + * + * @param fifo This object. + * @param clear If true, then command will be cleared from the + * buffer. If there is no delimiter, buffer will be cleared entirely. + * + * @return true if command with delimiter found or buffer full. + */ +bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear); + + +/** + * Trim spaces inside FIFO + * + * Function removes all non graphical characters and comments from fifo + * buffer. It stops on first graphical character or on command delimiter (later + * is also removed). + * + * @param fifo This object. + * + * @return true if command delimiter was found. + */ +bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo); + + +/** + * Get token from FIFO buffer + * + * Function search FIFO buffer for token. Token is string of only graphical + * characters. Graphical character is any printable character except space with + * acsii code within limits: 0x20 < code < 0x7F (see isgraph() function). + * + * If token is found, then copy it to the buf, if count is large enough. On + * success also set readPtr to point to the next graphical character. + * + * Each token must have at least one empty space after it (space, command + * delimiter, '\0', etc.). Delimiter must not be graphical character. + * + * If comment delimiter (delimComment, see #CO_fifo_init) character is found, + * then all string till command delimiter (delimCommand, see #CO_fifo_init) will + * be erased from the buffer. + * + * See also #CO_fifo_CommSearch(). + * + * @param fifo This object. + * @param buf Buffer into which data will be copied. Will be terminated by '\0'. + * @param count Copy up to count bytes into buffer + * @param [in,out] closed This is input/output variable. Not used if NULL. + * - As output variable it is set to 1, if command delimiter (delimCommand, + * see #CO_fifo_init) is found after the token and set to 0 otherwise. + * - As input variable it is used for verifying error condition: + * - *closed = 0: Set *err to true if token is empty or command delimiter + * is found. + * - *closed = 1: Set *err to true if token is empty or command delimiter + * is NOT found. + * - *closed = any other value: No checking of token size or command delimiter. + * @param [out] err If not NULL, it is set to true if token is larger than buf + * or in matching combination in 'closed' argument. If it is already true, then + * function returns immediately. + * + * @return Number of bytes read. + */ +size_t CO_fifo_readToken(CO_fifo_t *fifo, + char *buf, + size_t count, + char *closed, + bool_t *err); + + +/** + * Read uint8_t variable from fifo and output as ascii string. + * + * @param fifo This object. + * @param buf Buffer into which ascii string will be copied. + * @param count Available count of bytes inside the buf. + * @param end If true, then fifo contains last bytes, which has to be read. + * + * @return Number of ascii bytes written into buf. + */ +size_t CO_fifo_readU82a (CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read uint16_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read uint32_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read uint64_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read int8_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readI82a (CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read int16_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read int32_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read int64_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read float32_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read float64_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read data from fifo and output as space separated two digit ascii string, + * see also CO_fifo_readU82a */ +size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read data from fifo and output as visible string. A visible string is + * enclosed with double quotes. If a double quote is used within the string, + * the quotes are escaped by a second quotes, e.g. “Hello “”World””, CANopen + * is great”. See also CO_fifo_readU82a */ +size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); + + +/** + * Read ascii string from src fifo and copy as uint8_t variable to dest fifo. + * + * @param dest destination fifo buffer object. + * @param src source fifo buffer object. + * @param [out] status bitfield with the following bits: + * - bit0: if 1, command delimiter is reached in src + * - bit1: if 1, copy was partial, more data are available. If 0 and no error + * bit is set, then all data was successfully copied. + * - bit4: if 1, error: no valid token found + * - bit5: if 1, error: value is not valid or out of limits + * - bit6: if 1, error: destination buffer to small + * - bit7: if 1, error: internal + * + * @return Number of bytes written into dest. + */ +size_t CO_fifo_cpyTok2U8 (CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to uint16_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to uint32_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to uint64_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to int8_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2I8 (CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to int16_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to int32_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to int64_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to float32_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy ascii string to float64_t variable, see CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy bytes written as two hex digits into to data. Bytes may be space + * separated. See CO_fifo_cpyTok2U8 for parameters. */ +size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +/** Copy visible string to data. A visible string must be enclosed with double + * quotes, if it contains space. If a double quote is used within the string, + * the quotes are escaped by a second quotes. See CO_fifo_cpyTok2U8 */ +size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); + +#endif /* CO_CONFIG_FIFO_ASCII_COMMANDS > 0 */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +/** @} */ +#endif /* CO_FIFO_H */ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c new file mode 100644 index 00000000..2fb06f2e --- /dev/null +++ b/309/CO_gateway_ascii.c @@ -0,0 +1,1103 @@ +/* + * Access from other networks - ASCII mapping (CiA 309-3 DS v2.1.0) + * + * @file CO_gateway_ascii.c + * @ingroup CO_CANopen_309_3 + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "309/CO_gateway_ascii.h" + + +/******************************************************************************/ +CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, + CO_SDOclient_t* SDO_C, + uint16_t SDOtimeoutTimeDefault, + bool_t SDOblockTransferEnableDefault, + CO_NMT_t *NMT) +{ + /* verify arguments */ + if (gtwa == NULL + || SDO_C == NULL || SDOtimeoutTimeDefault == 0 + || NMT == NULL + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* initialize variables */ + gtwa->readCallback = NULL; + gtwa->readCallbackObject = NULL; + gtwa->SDO_C = SDO_C; + gtwa->SDOtimeoutTime = SDOtimeoutTimeDefault; + gtwa->SDOblockTransferEnable = SDOblockTransferEnableDefault; + gtwa->NMT = NMT; + gtwa->net_default = -1; + gtwa->node_default = -1; + gtwa->state = CO_GTWA_ST_IDLE; + gtwa->timeDifference_us_cumulative = 0; + gtwa->respBufOffset = 0; + gtwa->respBufCount = 0; + gtwa->respHold = false; + + CO_fifo_init(>wa->commFifo, + >wa->commBuf[0], + CO_CONFIG_GTWA_COMM_BUF_SIZE + 1); + + return CO_ERROR_NO; +} + + +/******************************************************************************/ +void CO_GTWA_initRead(CO_GTWA_t* gtwa, + size_t (*readCallback)(void *object, + const char *buf, + size_t count), + void *readCallbackObject) +{ + if (gtwa != NULL) { + gtwa->readCallback = readCallback; + gtwa->readCallbackObject = readCallbackObject; + } +} + + +/******************************************************************************* + * HELPER FUNCTIONS + ******************************************************************************/ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP +/* help string */ +static const char *CO_GTWA_helpString = +"Command strings start with '\"[\"\"]\"' followed by:\n" \ +"[[] ] r[ead] [] # SDO upload.\n" \ +"[[] ] w[rite] # SDO download.\n" \ +"\n" \ +"[[] ] start # NMT Start node.\n" \ +"[[] ] stop # NMT Stop node.\n" \ +"[[] ] preop[erational] # NMT Set node to pre-operational.\n" \ +"[[] ] reset node # NMT Reset node.\n" \ +"[[] ] reset comm[unication] # NMT Reset communication.\n" \ +"\n" \ +"[] set network # Set default net.\n" \ +"[] set node # Set default node.\n" \ +"[] set sdo_timeout # Configure SDO time-out.\n" \ +"[] set sdo_block # Enable/disable SDO block transfer.\n" \ +"\n" \ +"help # Print this help.\n" \ +"\n" \ +"Datatypes:\n" \ +"b # Boolean.\n" \ +"u8, u16, u32, u64 # Unsigned integers.\n" \ +"i8, i16, i32, i64 # Signed integers.\n" \ +"r32, r64 # Real numbers.\n" \ +"t, td # Time of day, time difference.\n" \ +"vs # Visible string (between double quotes if multi-word).\n" \ +"os, us, d # Octet string, unicode string, domain (mime-base64\n" \ +" # (RFC2045) based, one line).\n" \ +"hex # Hexagonal data, optionally space separated, non-standard.\n" \ +"\n" \ +"Response:\n" \ +"\"[\"\"]\" OK | |\n" \ +" ERROR: | ERROR: \n" \ +"\n" \ +"Every command must be terminated with ('\\r\\n'). characters. Same is\n" \ +"response. String is not null terminated, is optional in command.\n" \ +"\n" \ +"Comments started with '#' are ignored. They may be on the beginning of the\n" \ +"line or after the command string.\n" \ +"\n" \ +"'sdo_timeout' is in milliseconds, 500 by default. Block transfer is disabled\n" \ +"by default.\n" \ +"\n" \ +"If '' or '' is not specified within commands, then value defined by\n" \ +"'set network' or 'set node' command is used.\r\n"; +#endif + + +/* Get uint32 number from token, verify limits and set *err if necessary */ +static inline uint32_t getU32(char *token, uint32_t min, + uint32_t max, bool_t *err) +{ + char *sRet; + uint32_t num = strtoul(token, &sRet, 0); + + if (sRet != strchr(token, '\0') || num < min || num > max) { + *err = true; + } + + return num; +} + +/* Verify net and node, return true on error */ +static bool_t checkNetNode(CO_GTWA_t *gtwa, + int32_t net, int16_t node, uint8_t NodeMin, + CO_GTWA_respErrorCode_t *errCode) +{ + bool_t e = false; + CO_GTWA_respErrorCode_t eCode; + + if (node == -1) { + eCode = CO_GTWA_respErrorNoDefaultNodeSet; + e = true; + } + else if (node < NodeMin || node > 127) { + eCode = CO_GTWA_respErrorUnsupportedNode; + e = true; + } +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET + else if (net == -1) { + eCode = CO_GTWA_respErrorNoDefaultNetSet; + e = true; + } + /* not implemented */ + else if (net < CO_CONFIG_GTW_NET_MIN || net > CO_CONFIG_GTW_NET_MAX) { + eCode = CO_GTWA_respErrorUnsupportedNet; + e = true; + } +#endif + else { + gtwa->net = (uint16_t)net; + gtwa->node = (uint8_t)node; + } + if (e) { + *errCode = eCode; + } + return e; +} + +/* Verify net, return true on error */ +static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, + CO_GTWA_respErrorCode_t *errCode) +{ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET + bool_t e = false; + CO_GTWA_respErrorCode_t eCode; + + if (net == -1) { + eCode = CO_GTWA_respErrorNoDefaultNetSet; + e = true; + } + /* not implemented */ + else if (net < CO_CONFIG_GTW_NET_MIN || net > CO_CONFIG_GTW_NET_MAX) { + eCode = CO_GTWA_respErrorUnsupportedNet; + e = true; + } + else { + gtwa->net = (uint16_t)net; + } + if (e) { + *errCode = eCode; + } + return e; +#else + #define CO_CONFIG_GTW_NET_MIN 0 + #define CO_CONFIG_GTW_NET_MAX 0xFFFF + gtwa->net = (uint16_t)net; + return false; +#endif +} + +/* data types for SDO read or write */ +static const CO_GTWA_dataType_t dataTypes[] = { + {"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */ + {"b", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* BOOLEAN */ + {"u8", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ + {"u16", 2, CO_fifo_readU162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ + {"u32", 4, CO_fifo_readU322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ + {"u64", 8, CO_fifo_readU642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ + {"i8", 1, CO_fifo_readI82a, CO_fifo_cpyTok2I8}, /* INTEGER8 */ + {"i16", 2, CO_fifo_readI162a, CO_fifo_cpyTok2I16}, /* INTEGER16 */ + {"i32", 4, CO_fifo_readI322a, CO_fifo_cpyTok2I32}, /* INTEGER32 */ + {"i64", 8, CO_fifo_readI642a, CO_fifo_cpyTok2I64}, /* INTEGER64 */ + {"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */ + {"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */ +// {"t", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* TIME_OF_DAY */ +// {"td", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* TIME_DIFFERENCE */ + {"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}//, +// {"os", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* ochar_t (OCTET_STRING) (mime-base64 (RFC2045) should be used here) */ +// {"us", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* (UNICODE_STRING) (mime-base64 (RFC2045) should be used here) */ +// {"d", 0, CO_GWA_dtpHex, CO_DWA_dtsHex} /* domain_t (DOMAIN) (mime-base64 (RFC2045) should be used here) */ +}; + + +/* get data type from token */ +static const CO_GTWA_dataType_t *CO_GTWA_getDataType(char *token, bool_t *err) { + if (token != NULL && *err == false) { + int i; + int len = sizeof(dataTypes) / sizeof(CO_GTWA_dataType_t); + + for (i = 0; i < len; i++) { + const CO_GTWA_dataType_t *dt = &dataTypes[i]; + if (strcmp(token, dt->syntax) == 0) { + return dt; + } + } + } + + *err = true; + return NULL; +} + + +/* transfer response buffer and verify if all bytes was read */ +static void respBufTransfer(CO_GTWA_t *gtwa) { + if (gtwa->readCallback == NULL) { + /* no callback registered, just purge the response */ + gtwa->respBufOffset = 0; + gtwa->respBufCount = 0; + gtwa->respHold = false; + } + else { + /* transfer response to the application */ + size_t countRead = + gtwa->readCallback(gtwa->readCallbackObject, + (const char *)>wa->respBuf[gtwa->respBufOffset], + gtwa->respBufCount); + + if (countRead < gtwa->respBufCount) { + gtwa->respBufOffset += countRead; + gtwa->respBufCount -= countRead; + gtwa->respHold = true; + } + else { + gtwa->respBufOffset = 0; + gtwa->respBufCount = 0; + gtwa->respHold = false; + } + } +} + + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC +#ifndef CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS +#define CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS +typedef struct { + const uint32_t code; + const char* desc; +} errorDescs_t; + +static const errorDescs_t errorDescs[] = { + {100, "Request not supported."}, + {101, "Syntax error."}, + {102, "Request not processed due to internal state."}, + {103, "Time-out (where applicable)."}, + {104, "No default net set."}, + {105, "No default node set."}, + {106, "Unsupported net."}, + {107, "Unsupported node."}, + {200, "Lost guarding message."}, + {201, "Lost connection."}, + {202, "Heartbeat started."}, + {203, "Heartbeat lost."}, + {204, "Wrong NMT state."}, + {205, "Boot-up."}, + {300, "Error passive."}, + {301, "Bus off."}, + {303, "CAN buffer overflow."}, + {304, "CAN init."}, + {305, "CAN active (at init or start-up)."}, + {400, "PDO already used."}, + {401, "PDO length exceeded."}, + {501, "LSS implementation- / manufacturer-specific error."}, + {502, "LSS node-ID not supported."}, + {503, "LSS bit-rate not supported."}, + {504, "LSS parameter storing failed."}, + {505, "LSS command failed because of media error."}, + {600, "Running out of memory."} +}; +static const errorDescs_t errorDescsSDO[] = { + {0x00000000, "No abort."}, + {0x05030000, "Toggle bit not altered."}, + {0x05040000, "SDO protocol timed out."}, + {0x05040001, "Command specifier not valid or unknown."}, + {0x05040002, "Invalid block size in block mode."}, + {0x05040003, "Invalid sequence number in block mode."}, + {0x05040004, "CRC error (block mode only)."}, + {0x05040005, "Out of memory."}, + {0x06010000, "Unsupported access to an object."}, + {0x06010001, "Attempt to read a write only object."}, + {0x06010002, "Attempt to write a read only object."}, + {0x06020000, "Object does not exist."}, + {0x06040041, "Object cannot be mapped to the PDO."}, + {0x06040042, "Number and length of object to be mapped exceeds PDO length."}, + {0x06040043, "General parameter incompatibility reasons."}, + {0x06040047, "General internal incompatibility in device."}, + {0x06060000, "Access failed due to hardware error."}, + {0x06070010, "Data type does not match, length of service parameter does not match."}, + {0x06070012, "Data type does not match, length of service parameter too high."}, + {0x06070013, "Data type does not match, length of service parameter too short."}, + {0x06090011, "Sub index does not exist."}, + {0x06090030, "Invalid value for parameter (download only)."}, + {0x06090031, "Value range of parameter written too high."}, + {0x06090032, "Value range of parameter written too low."}, + {0x06090036, "Maximum value is less than minimum value."}, + {0x060A0023, "Resource not available: SDO connection."}, + {0x08000000, "General error."}, + {0x08000020, "Data cannot be transferred or stored to application."}, + {0x08000021, "Data cannot be transferred or stored to application because of local control."}, + {0x08000022, "Data cannot be transferred or stored to application because of present device state."}, + {0x08000023, "Object dictionary not present or dynamic generation fails."}, + {0x08000024, "No data available."} +}; +#endif /* CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS */ + +static void responseWithError(CO_GTWA_t *gtwa, + CO_GTWA_respErrorCode_t respErrorCode) +{ + int i; + int len = sizeof(errorDescs) / sizeof(errorDescs_t); + const char *desc = "-"; + + for (i = 0; i < len; i++) { + const errorDescs_t *ed = &errorDescs[i]; + if(ed->code == respErrorCode) { + desc = ed->desc; + } + } + + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR: %d #%s\r\n", + gtwa->sequence, respErrorCode, desc); + respBufTransfer(gtwa); +} + +static void responseWithErrorSDO(CO_GTWA_t *gtwa, + CO_SDO_abortCode_t abortCode) +{ + int i; + int len = sizeof(errorDescs) / sizeof(errorDescs_t); + const char *desc = "-"; + + for (i = 0; i < len; i++) { + const errorDescs_t *ed = &errorDescsSDO[i]; + if(ed->code == abortCode) { + desc = ed->desc; + } + } + + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR: 0x%08X #%s\r\n", + gtwa->sequence, abortCode, desc); + respBufTransfer(gtwa); +} + +#else /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */ +static inline void responseWithError(CO_GTWA_t *gtwa, + CO_GTWA_respErrorCode_t respErrorCode) +{ + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR: %d\r\n", + gtwa->sequence, respErrorCode); + respBufTransfer(gtwa); +} + +static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, + CO_SDO_abortCode_t abortCode) +{ + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR: 0x%08X\r\n", + gtwa->sequence, abortCode); + respBufTransfer(gtwa); +} +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */ + + +static inline void responseWithOK(CO_GTWA_t *gtwa) { + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] OK\r\n", gtwa->sequence); + respBufTransfer(gtwa); +} + + +/******************************************************************************* + * PROCESS FUNCTION + ******************************************************************************/ +void CO_GTWA_process(CO_GTWA_t *gtwa, + bool_t enable, + uint32_t timeDifference_us, + uint32_t *timerNext_us) +{ + bool_t err = false; /* syntax or other error, true or false, I/O variable */ + char closed; /* indication of command delimiter, I/O variable */ + CO_GTWA_respErrorCode_t respErrorCode = CO_GTWA_respErrorNone; + + if (gtwa == NULL) { + return; + } + + if (!enable) { + gtwa->state = CO_GTWA_ST_IDLE; + CO_fifo_reset(>wa->commFifo); + return; + } + + /* If there is some more output data for application, read them first. + * Hold on this state, if necessary. */ + if (gtwa->respHold) { + timeDifference_us += gtwa->timeDifference_us_cumulative; + + respBufTransfer(gtwa); + if (gtwa->respHold) { + gtwa->timeDifference_us_cumulative = timeDifference_us; + return; + } + else { + gtwa->timeDifference_us_cumulative = 0; + } + } + + /*************************************************************************** + * COMMAND PARSER + ***************************************************************************/ + /* if idle, search for new command, skip comments or empty lines */ + while (gtwa->state == CO_GTWA_ST_IDLE + && CO_fifo_CommSearch(>wa->commFifo, false) + ) { + char token[20]; /* must be the size of tokenSize */ + const size_t tokenSize = 20; + size_t n; + uint32_t ui[3]; + int i; + int32_t net = gtwa->net_default; + int16_t node = gtwa->node_default; + + + /* parse mandatory token '"[""]"' */ + closed = -1; + n = CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + /* Break if error in token or token was found, but closed with + * command delimiter. */ + if (err || (n > 0 && closed != 0)) { + err = true; + break; + } + /* If empty line or just comment, continue with next command */ + else if (n == 0 && closed != 0) { + continue; + } + if (token[0] != '[' || token[strlen(token)-1] != ']') { + err = true; + break; + } + token[strlen(token)-1] = '\0'; + gtwa->sequence = getU32(token+1, 0, 0xFFFFFFFF, &err); + if (err) break; + + + /* parse optional tokens '[[] ]', both numerical. Then + * follows mandatory token , which is not numerical. */ + for (i = 0; i < 3; i++) { + closed = -1; + n = CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + if (err || n == 0) { + /* empty token, break on error */ + err = true; + break; + } else if (isdigit(token[0]) == 0) { + /* found */ + break; + } else if (closed != 0) { + /* numerical value must not be closed */ + err = true; + break; + } + + ui[i] = getU32(token, 0, 0xFFFFFFFF, &err); + if (err) break; + } + if (err) break; + + switch(i) { + case 0: /* only (pointed by token) */ + break; + case 1: /* and tokens */ + if (ui[0] > 127) { + err = true; + respErrorCode = CO_GTWA_respErrorUnsupportedNode; + } + else { + node = (int16_t) ui[0]; + } + break; + case 2: /* , and tokens */ + if (ui[0] > 0xFFFF) { + err = true; + respErrorCode = CO_GTWA_respErrorUnsupportedNet; + } + else if (ui[1] > 127) { + err = true; + respErrorCode = CO_GTWA_respErrorUnsupportedNode; + } + else { + net = (int32_t) ui[0]; + node = (int16_t) ui[1]; + } + break; + case 3: /* token contains digit */ + err = true; + break; + } + if (err) break; + + + /* Upload SDO command - 'r[ead] ' */ + if (strcmp(token, "r") == 0 || strcmp(token, "read") == 0) { + uint16_t idx; + uint8_t subidx; + CO_SDOclient_return_t SDO_ret; + bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* index */ + closed = 0; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + idx = (uint16_t)getU32(token, 0, 0xFFFF, &err); + if (err) break; + + /* subindex */ + closed = -1; + n = CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + subidx = (uint8_t)getU32(token, 0, 0xFF, &err); + if (err || n == 0) { + err = true; + break; + } + + /* optional data type */ + if (closed == 0) { + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + gtwa->SDOdataType = CO_GTWA_getDataType(token, &err); + if (err) break; + } + else { + gtwa->SDOdataType = &dataTypes[0]; /* use generic data type */ + } + + /* setup client */ + SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, 0, 0, gtwa->node); + if (SDO_ret != CO_SDOcli_ok_communicationEnd) { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + + /* initiate upload */ + SDO_ret = CO_SDOclientUploadInitiate(gtwa->SDO_C, idx, subidx, + gtwa->SDOtimeoutTime, + gtwa->SDOblockTransferEnable); + if (SDO_ret != CO_SDOcli_ok_communicationEnd) { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + + /* indicate that gateway response didn't start yet */ + gtwa->SDOdataCopyStatus = false; + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_READ; + } + + /* Download SDO comm. - w[rite] */ + else if (strcmp(token, "w") == 0 || strcmp(token, "write") == 0) { + uint16_t idx; + uint8_t subidx; + uint8_t status; + CO_SDOclient_return_t SDO_ret; + size_t size; + bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* index */ + closed = 0; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + idx = (uint16_t)getU32(token, 0, 0xFFFF, &err); + if (err) break; + + /* subindex */ + closed = 0; + n = CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + subidx = (uint8_t)getU32(token, 0, 0xFF, &err); + if (err) break; + + /* data type */ + closed = 0; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + gtwa->SDOdataType = CO_GTWA_getDataType(token, &err); + if (err) break; + + /* setup client */ + SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, 0, 0, gtwa->node); + if (SDO_ret != CO_SDOcli_ok_communicationEnd) { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + + /* initiate download */ + SDO_ret = + CO_SDOclientDownloadInitiate(gtwa->SDO_C, idx, subidx, + gtwa->SDOdataType->length, + gtwa->SDOtimeoutTime, + gtwa->SDOblockTransferEnable); + if (SDO_ret != CO_SDOcli_ok_communicationEnd) { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + + /* copy data from comm to the SDO buffer, according to data type */ + size = gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, + >wa->commFifo, + &status); + /* set to true, if command delimiter was found */ + closed = (status & 0x01) == 1; + /* set to true, if data are copied only partially */ + gtwa->SDOdataCopyStatus = (status & 0x02) != 0; + + /* is syntax error in command or size is zero or not the last token + * in command */ + if ((status & 0xF0) != 0 || size == 0 + || (gtwa->SDOdataCopyStatus == false && closed != 1) + ) { + err = true; + break; + } + + /* if data size was not known before and is known now, update SDO */ + if (gtwa->SDOdataType->length == 0 && !gtwa->SDOdataCopyStatus) { + CO_SDOclientDownloadInitiateSize(gtwa->SDO_C, size); + } + + /* continue with state machine */ + gtwa->stateTimeoutTmr = 0; + gtwa->state = CO_GTWA_ST_WRITE; + } + + /* NMT start node */ + else if (strcmp(token, "start") == 0) { + CO_ReturnError_t ret; + bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); + CO_NMT_command_t command2 = CO_NMT_ENTER_OPERATIONAL; + + if (closed != 1 || NodeErr) { + err = true; + break; + } + ret = CO_NMT_sendCommand(gtwa->NMT, command2, gtwa->node); + + if (ret == CO_ERROR_NO) { + responseWithOK(gtwa); + } + else { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + } + + /* NMT stop node */ + else if (strcmp(token, "stop") == 0) { + CO_ReturnError_t ret; + bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); + CO_NMT_command_t command2 = CO_NMT_ENTER_STOPPED; + + if (closed != 1 || NodeErr) { + err = true; + break; + } + ret = CO_NMT_sendCommand(gtwa->NMT, command2, gtwa->node); + + if (ret == CO_ERROR_NO) { + responseWithOK(gtwa); + } + else { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + } + + /* NMT Set node to pre-operational */ + else if (strcmp(token, "preop") == 0 || + strcmp(token, "preoperational") == 0 + ) { + CO_ReturnError_t ret; + bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); + CO_NMT_command_t command2 = CO_NMT_ENTER_PRE_OPERATIONAL; + + if (closed != 1 || NodeErr) { + err = true; + break; + } + ret = CO_NMT_sendCommand(gtwa->NMT, command2, gtwa->node); + + if (ret == CO_ERROR_NO) { + responseWithOK(gtwa); + } + else { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + } + + /* NMT reset (node or communication) */ + else if (strcmp(token, "reset") == 0) { + CO_ReturnError_t ret; + bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); + CO_NMT_command_t command2; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* command 2 */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + if (err) break; + + if (strcmp(token, "node") == 0) { + command2 = CO_NMT_RESET_NODE; + } else if (strcmp(token, "comm") == 0 || + strcmp(token, "communication") == 0 + ) { + command2 = CO_NMT_RESET_COMMUNICATION; + } else { + err = true; + break; + } + + ret = CO_NMT_sendCommand(gtwa->NMT, command2, gtwa->node); + + if (ret == CO_ERROR_NO) { + responseWithOK(gtwa); + } + else { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + } + + /* set command - multiple sub commands */ + else if (strcmp(token, "set") == 0) { + if (closed != 0) { + err = true; + break; + } + + /* command 2 */ + closed = -1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + if (err) break; + + if (strcmp(token, "network") == 0) { + uint16_t value; + + if (closed != 0) { + err = true; + break; + } + + /* value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + value = (uint16_t)getU32(token, CO_CONFIG_GTW_NET_MIN, + CO_CONFIG_GTW_NET_MAX, &err); + if (err) break; + + gtwa->net_default = value; + responseWithOK(gtwa); + } + else if (strcmp(token, "node") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint8_t value; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + value = (uint8_t)getU32(token, 1, 127, &err); + if (err) break; + + gtwa->node_default = value; + responseWithOK(gtwa); + } + else if (strcmp(token, "sdo_timeout") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint16_t value; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + value = (uint16_t)getU32(token, 1, 0xFFFF, &err); + if (err) break; + + gtwa->SDOtimeoutTime = value; + responseWithOK(gtwa); + } + else if (strcmp(token, "sdo_block") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint16_t value; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + value = (uint16_t)getU32(token, 0, 1, &err); + if (err) break; + + gtwa->SDOblockTransferEnable = value==1 ? true : false; + responseWithOK(gtwa); + } + else { + respErrorCode = CO_GTWA_respErrorReqNotSupported; + err = true; + break; + } + } + + /* TODO LSS */ + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP + /* Print help */ + else if (strcmp(token, "help") == 0) { + gtwa->helpStringOffset = 0; + gtwa->state = CO_GTWA_ST_HELP; + } +#endif + + /* Unrecognized command */ + else { + respErrorCode = CO_GTWA_respErrorReqNotSupported; + err = true; + break; + } + } /* while CO_GTWA_ST_IDLE && CO_fifo_CommSearch */ + + + + /*************************************************************************** + * STATE MACHINE + ***************************************************************************/ + /* If error, generate error response */ + if (err) { + if (respErrorCode == CO_GTWA_respErrorNone) { + respErrorCode = CO_GTWA_respErrorSyntax; + } + responseWithError(gtwa, respErrorCode); + + /* delete command, if it was only partially read */ + if(closed == 0) { + CO_fifo_CommSearch(>wa->commFifo, true); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + + /* SDO upload state */ + else if (gtwa->state == CO_GTWA_ST_READ) { + CO_SDO_abortCode_t abortCode; + size_t sizeTransferred; + CO_SDOclient_return_t ret; + + ret = CO_SDOclientUpload(gtwa->SDO_C, + timeDifference_us, + &abortCode, + NULL, + &sizeTransferred, + timerNext_us); + + if (ret < 0) { + responseWithErrorSDO(gtwa, abortCode); + gtwa->state = CO_GTWA_ST_IDLE; + } + /* Response data must be read, partially or whole */ + else if (ret == CO_SDOcli_uploadDataBufferFull + || ret == CO_SDOcli_ok_communicationEnd + ) { + size_t fifoRemain; + + /* write response head first */ + if (!gtwa->SDOdataCopyStatus) { + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ", + gtwa->sequence); + gtwa->SDOdataCopyStatus = true; + } + + /* Empty SDO fifo buffer in multiple cycles. Repeat until + * application runs out of space (respHold) or fifo empty. */ + do { + /* read SDO fifo (partially) and print specific data type as + * ascii into intermediate respBuf */ + gtwa->respBufCount += gtwa->SDOdataType->dataTypePrint( + >wa->SDO_C->bufFifo, + >wa->respBuf[gtwa->respBufCount], + CO_GTWA_RESP_BUF_SIZE - 2 - gtwa->respBufCount, + ret == CO_SDOcli_ok_communicationEnd); + fifoRemain = CO_fifo_getOccupied(>wa->SDO_C->bufFifo); + + /* end of communication, print newline and enter idle state */ + if (ret == CO_SDOcli_ok_communicationEnd && fifoRemain == 0) { + gtwa->respBufCount += + sprintf(>wa->respBuf[gtwa->respBufCount], "\r\n"); + gtwa->state = CO_GTWA_ST_IDLE; + } + + /* transfer response to the application */ + respBufTransfer(gtwa); + } while (gtwa->respHold == false && fifoRemain > 0); + } + } + + /* SDO download state */ + else if (gtwa->state == CO_GTWA_ST_WRITE) { + CO_SDO_abortCode_t abortCode; + size_t sizeTransferred; + bool_t abort = false; + bool_t hold = false; + CO_SDOclient_return_t ret; + int loop = 0; + + /* copy data to the SDO buffer if more data available */ + if (gtwa->SDOdataCopyStatus) { + uint8_t status; + gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, + >wa->commFifo, + &status); + /* set to true, if command delimiter was found */ + closed = (status & 0x01) == 1; + /* set to true, if data are copied only partially */ + gtwa->SDOdataCopyStatus = (status & 0x02) != 0; + + /* is syntax error in command or not the last token in command */ + if ((status & 0xF0) != 0 + || (gtwa->SDOdataCopyStatus == false && closed != 1) + ) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + abort = true; /* abort SDO communication */ + } + } + /* If not all data were transferred, make sure, there is enough data in + * SDO buffer, to continue communication. Otherwise wait and check for + * timeout */ + if (gtwa->SDOdataCopyStatus + && CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < + (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7) + ) { + if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + abort = true; + } + else { + gtwa->stateTimeoutTmr += timeDifference_us; + hold = true; + } + } + if (!hold) { + /* if OS has CANtx queue, speedup block transfer */ + do { + ret = CO_SDOclientDownload(gtwa->SDO_C, + timeDifference_us, + abort, + &abortCode, + &sizeTransferred, + timerNext_us); + if (++loop >= CO_CONFIG_GTW_BLOCK_DL_LOOP) { + break; + } + } while (ret == CO_SDOcli_blockDownldInProgress); + + /* send response in case of error or finish */ + if (ret < 0) { + responseWithErrorSDO(gtwa, abortCode); + gtwa->state = CO_GTWA_ST_IDLE; + } + else if (ret == CO_SDOcli_ok_communicationEnd) { + responseWithOK(gtwa); + gtwa->state = CO_GTWA_ST_IDLE; + } + } + } + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP + /* Print help string (in multiple segments if necessary) */ + else if (gtwa->state == CO_GTWA_ST_HELP) { + size_t lenBuf = CO_GTWA_RESP_BUF_SIZE; + size_t lenHelp = strlen(CO_GTWA_helpString); + + do { + size_t lenHelpRemain = lenHelp - gtwa->helpStringOffset; + size_t lenCopied = lenBuf < lenHelpRemain ? lenBuf : lenHelpRemain; + + memcpy(gtwa->respBuf, + &CO_GTWA_helpString[gtwa->helpStringOffset], + lenCopied); + + gtwa->respBufCount = lenCopied; + gtwa->helpStringOffset += lenCopied; + respBufTransfer(gtwa); + + if (gtwa->helpStringOffset == lenHelp) { + gtwa->state = CO_GTWA_ST_IDLE; + break; + } + } while (gtwa->respHold == false); + } +#endif + + /* illegal state */ + else if (gtwa->state != CO_GTWA_ST_IDLE) { + respErrorCode = CO_GTWA_respErrorInternalState; + responseWithError(gtwa, respErrorCode); + gtwa->state = CO_GTWA_ST_IDLE; + } + +} diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h new file mode 100644 index 00000000..6649048e --- /dev/null +++ b/309/CO_gateway_ascii.h @@ -0,0 +1,404 @@ +/** + * CANopen access from other networks - ASCII mapping (CiA 309-3 DS v2.1.0) + * + * @file CO_gateway_ascii.h + * @ingroup CO_CANopen_309_3 + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CO_GATEWAY_ASCII_H +#define CO_GATEWAY_ASCII_H + +#include "301/CO_driver.h" +#include "301/CO_fifo.h" +#include "301/CO_SDOserver.h" +#include "301/CO_SDOclient.h" +#include "301/CO_NMT_Heartbeat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_CANopen_309_3 ASCII mapping + * @ingroup CO_CANopen_309 + * @{ + * + * CANopen access from other networks - ASCII mapping (CiA 309-3 DS v2.1.0) + * + * This module enables ascii command interface (CAN gateway), which can be used + * for master interaction with CANopen network. Some sort of string input/output + * stream can be used, for example serial port + terminal on microcontroller or + * stdio in OS or sockets, etc. + * + * For example, one wants to read 'Heartbeat producer time' parameter (0x1017,0) + * on remote node (with id=4). Parameter is 16-bit integer. He can can enter + * command string: `[1] 4 read 0x1017 0 i16`. CANopenNode will use SDO client, + * send request to remote node via CAN, wait for response via CAN and prints + * `[1] OK` to output stream on success. + * + * This module is usually initialized and processed in CANopen.c file. + * Application should register own callback function for reading the output + * stream. Application writes new commands with CO_GTWA_write(). + */ + +/** + * @defgroup CO_CANopen_309_3_Syntax Command syntax + * @{ + * + * @code{.unparsed} +Command strings start with '"[""]"' followed by: +[[] ] r[ead] [] # SDO upload. +[[] ] w[rite] # SDO download. + +[[] ] start # NMT Start node. +[[] ] stop # NMT Stop node. +[[] ] preop[erational] # NMT Set node to pre-operational. +[[] ] reset node # NMT Reset node. +[[] ] reset comm[unication] # NMT Reset communication. + +[] set network # Set default net. +[] set node # Set default node. +[] set sdo_timeout # Configure SDO time-out. +[] set sdo_block # Enable/disable SDO block transfer. + +help # Print this help. + +Datatypes: +b # Boolean. +u8, u16, u32, u64 # Unsigned integers. +i8, i16, i32, i64 # Signed integers. +r32, r64 # Real numbers. +t, td # Time of day, time difference. +vs # Visible string (between double quotes if multi-word). +os, us, d # Octet string, unicode string, domain (mime-base64 + # (RFC2045) based, one line). +hex # Hexagonal data, optionally space separated, non-standard. + +Response: +"[""]" OK | | + ERROR: | ERROR: + +Every command must be terminated with ('\\r\\n'). characters. Same is +response. String is not null terminated, is optional in command. + +Comments started with '#' are ignored. They may be on the beginning of the +line or after the command string. + +'sdo_timeout' is in milliseconds, 500 by default. Block transfer is disabled +by default. + +If '' or '' is not specified within commands, then value defined by +'set network' or 'set node' command is used. + * @endcode + * + * This help text is the same as variable contents in CO_GTWA_helpString. + * @} + */ + + +/** Size of response string buffer. This is intermediate buffer. If there is + * larger amount of data to transfer, then multiple transfers will occur. */ +#ifndef CO_GTWA_RESP_BUF_SIZE +#define CO_GTWA_RESP_BUF_SIZE 200 +#endif + + +/** Timeout time in microseconds for some internal states. */ +#ifndef CO_GTWA_STATE_TIMEOUT_TIME_US +#define CO_GTWA_STATE_TIMEOUT_TIME_US 1000000 +#endif + + +/** + * Response error codes as specified by CiA 309-3. Values less or equal to 0 + * are used for control for some functions and are not part of the standard. + */ +typedef enum { + /** 0 - No error or idle */ + CO_GTWA_respErrorNone = 0, + /** 100 - Request not supported */ + CO_GTWA_respErrorReqNotSupported = 100, + /** 101 - Syntax error */ + CO_GTWA_respErrorSyntax = 101, + /** 102 - Request not processed due to internal state */ + CO_GTWA_respErrorInternalState = 102, + /** 103 - Time-out (where applicable) */ + CO_GTWA_respErrorTimeOut = 103, + /** 104 - No default net set */ + CO_GTWA_respErrorNoDefaultNetSet = 104, + /** 105 - No default node set */ + CO_GTWA_respErrorNoDefaultNodeSet = 105, + /** 106 - Unsupported net */ + CO_GTWA_respErrorUnsupportedNet = 106, + /** 107 - Unsupported node */ + CO_GTWA_respErrorUnsupportedNode = 107, + /** 200 - Lost guarding message */ + CO_GTWA_respErrorLostGuardingMessage = 200, + /** 201 - Lost connection */ + CO_GTWA_respErrorLostConnection = 201, + /** 202 - Heartbeat started */ + CO_GTWA_respErrorHeartbeatStarted = 202, + /** 203 - Heartbeat lost */ + CO_GTWA_respErrorHeartbeatLost = 203, + /** 204 - Wrong NMT state */ + CO_GTWA_respErrorWrongNMTstate = 204, + /** 205 - Boot-up */ + CO_GTWA_respErrorBootUp = 205, + /** 300 - Error passive */ + CO_GTWA_respErrorErrorPassive = 300, + /** 301 - Bus off */ + CO_GTWA_respErrorBusOff = 301, + /** 303 - CAN buffer overflow */ + CO_GTWA_respErrorCANbufferOverflow = 303, + /** 304 - CAN init */ + CO_GTWA_respErrorCANinit = 304, + /** 305 - CAN active (at init or start-up) */ + CO_GTWA_respErrorCANactive = 305, + /** 400 - PDO already used */ + CO_GTWA_respErrorPDOalreadyUsed = 400, + /** 401 - PDO length exceeded */ + CO_GTWA_respErrorPDOlengthExceeded = 401, + /** 501 - LSS implementation- / manufacturer-specific error */ + CO_GTWA_respErrorLSSmanufacturer = 501, + /** 502 - LSS node-ID not supported */ + CO_GTWA_respErrorLSSnodeIdNotSupported = 502, + /** 503 - LSS bit-rate not supported */ + CO_GTWA_respErrorLSSbitRateNotSupported = 503, + /** 504 - LSS parameter storing failed */ + CO_GTWA_respErrorLSSparameterStoringFailed = 504, + /** 505 - LSS command failed because of media error */ + CO_GTWA_respErrorLSSmediaError = 505, + /** 600 - Running out of memory */ + CO_GTWA_respErrorRunningOutOfMemory = 600 +} CO_GTWA_respErrorCode_t; + + +/** + * Internal states of the Gateway-ascii state machine. + */ +typedef enum { + /** Gateway is idle, no command is processing. This state is starting point + * for new commands, which are parsed here. */ + CO_GTWA_ST_IDLE = 0x00U, + /** SDO 'read' (upload) */ + CO_GTWA_ST_READ = 0x10U, + /** SDO 'write' (download) */ + CO_GTWA_ST_WRITE = 0x11U, + /** print 'help' text */ + CO_GTWA_ST_HELP = 0x90U +} CO_GTWA_state_t; + + +/* + * CANopen Gateway-ascii data types structure + */ +typedef struct { + /** Data type syntax, as defined in CiA309-3 */ + char* syntax; + /** Data type length in bytes, 0 if size is not known */ + size_t length; + /** Function, which reads data of specific data type from fifo buffer and + * writes them as corresponding ascii string. It is a pointer to + * #CO_fifo_readU82a function or similar and is used with SDO upload. For + * description of parameters see #CO_fifo_readU82a */ + size_t (*dataTypePrint)(CO_fifo_t *fifo, + char *buf, + size_t count, + bool_t end); + /** Function, which reads ascii-data of specific data type from fifo buffer + * and copies them to another fifo buffer as binary data. It is a pointer to + * #CO_fifo_cpyTok2U8 function or similar and is used with SDO download. For + * description of parameters see #CO_fifo_cpyTok2U8 */ + size_t (*dataTypeScan)(CO_fifo_t *dest, + CO_fifo_t *src, + uint8_t *status); +} CO_GTWA_dataType_t; + + +/** + * CANopen Gateway-ascii object + */ +typedef struct { + /** Pointer to external function for reading response from Gateway-ascii + * object. Pointer is initialized in CO_GTWA_initRead(). + * + * @param object Void pointer to custom object + * @param buf Buffer from which data can be read + * @param count Count of bytes available inside buffer + * + * @return Count of bytes actually transferred. + */ + size_t (*readCallback)(void *object, const char *buf, size_t count); + /** Pointer to object, which will be used inside readCallback, from + * CO_GTWA_init() */ + void *readCallbackObject; + /** Sequence number of the command */ + uint32_t sequence; + /** Default CANopen Net number is undefined (-1) at startup */ + int32_t net_default; + /** Default CANopen Node ID number is undefined (-1) at startup */ + int16_t node_default; + /** Current CANopen Net number */ + uint16_t net; + /** Current CANopen Node ID */ + uint8_t node; + /** CO_fifo_t object for command (not pointer) */ + CO_fifo_t commFifo; + /** Command buffer of usable size @ref CO_CONFIG_GTWA_COMM_BUF_SIZE */ + char commBuf[CO_CONFIG_GTWA_COMM_BUF_SIZE + 1]; + /** Response buffer of usable size @ref CO_GTWA_RESP_BUF_SIZE */ + char respBuf[CO_GTWA_RESP_BUF_SIZE]; + /** Actual size of data in respBuf */ + size_t respBufCount; + /** If only part of data has been successfully written into external + * application (with readCallback()), then Gateway-ascii object will stay + * in current state. This situation is indicated with respHold variable and + * respBufOffset indicates offset to untransferred data inside respBuf. */ + size_t respBufOffset; + /** See respBufOffset above */ + bool_t respHold; + /** Sum of time difference from CO_GTWA_process() in case of respHold */ + uint32_t timeDifference_us_cumulative; + /** Current state of the gateway object */ + CO_GTWA_state_t state; + /** Timeout timer for the current state */ + uint32_t stateTimeoutTmr; + /** SDO client object from CO_GTWA_init() */ + CO_SDOclient_t *SDO_C; + /** Timeout time for SDO transfer in milliseconds, if no response */ + uint16_t SDOtimeoutTime; + /** SDO block transfer enabled? */ + bool_t SDOblockTransferEnable; + /** Indicate status of data copy from / to SDO buffer */ + bool_t SDOdataCopyStatus; + /** Data type of variable in current SDO communication */ + const CO_GTWA_dataType_t *SDOdataType; + /** NMT object from CO_GTWA_init() */ + CO_NMT_t *NMT; +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) || defined CO_DOXYGEN + /** Offset, when printing help text */ + size_t helpStringOffset; +#endif +} CO_GTWA_t; + + +/** + * Initialize Gateway-ascii object + * + * @param gtwa This object will be initialized + * @param SDO_C SDO client object + * @param SDOtimeoutTimeDefault in milliseconds, 500 typically + * @param SDOblockTransferEnableDefault true or false + * @param NMT NMT object + * + * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT + */ +CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, + CO_SDOclient_t* SDO_C, + uint16_t SDOtimeoutTimeDefault, + bool_t SDOblockTransferEnableDefault, + CO_NMT_t *NMT); + + +/** + * Initialize read callback in Gateway-ascii object + * + * Callback will used for transfer data to output stream of the application. It + * will be called from CO_GTWA_process() zero or multiple times, depending on + * the data available. If readCallback is uninitialized or NULL, then output + * data will be purged. + * + * @param gtwa This object will be initialized + * @param readCallback Pointer to external function for reading response from + * Gateway-ascii object. See #CO_GTWA_t for parameters. + * @param readCallbackObject Pointer to object, which will be used inside + * readCallback + */ +void CO_GTWA_initRead(CO_GTWA_t* gtwa, + size_t (*readCallback)(void *object, + const char *buf, + size_t count), + void *readCallbackObject); + + +/** + * Get free write buffer space + * + * @param gtwa This object + * + * @return number of available bytes + */ +static inline size_t CO_GTWA_write_getSpace(CO_GTWA_t* gtwa) { + return CO_fifo_getSpace(>wa->commFifo); +} + + +/** + * Write command into CO_GTWA_t object. + * + * This function copies ascii command from buf into internal fifo buffer. + * Command must be closed with '\n' character. Function returns number of bytes + * successfully copied. If there is not enough space in destination, not all + * bytes will be copied and data can be refilled later (in case of large SDO + * download). + * + * @param gtwa This object + * @param buf Buffer which will be copied + * @param count Number of bytes in buf + * + * @return number of bytes actually written. + */ +static inline size_t CO_GTWA_write(CO_GTWA_t* gtwa, + const char *buf, + size_t count) +{ + return CO_fifo_write(>wa->commFifo, buf, count, NULL); +} + + +/** + * Process Gateway-ascii object + * + * This is non-blocking function and must be called cyclically + * + * @param gtwa This object will be initialized. + * @param enable If true, gateway operates normally. If false, gateway is + * completely disabled and no command interaction is possible. Can be connected + * to hardware switch, for example. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. + * @param [out] timerNext_us info to OS - see CO_process(). + * + * @return CO_ReturnError_t: CO_ERROR_NO on success or CO_ERROR_ILLEGAL_ARGUMENT + */ +void CO_GTWA_process(CO_GTWA_t *gtwa, + bool_t enable, + uint32_t timeDifference_us, + uint32_t *timerNext_us); + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +/** @} */ +#endif /* CO_GATEWAY_ASCII_H */ diff --git a/CANopen.c b/CANopen.c index 80d0b7bc..08569cb3 100644 --- a/CANopen.c +++ b/CANopen.c @@ -42,6 +42,9 @@ static CO_CANtx_t *CO_CANmodule_txArray0; static CO_OD_extension_t *CO_SDO_ODExtensions; static CO_HBconsNode_t *CO_HBcons_monitoredNodes; +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) && !defined CO_GTWA_ENABLE +#define CO_GTWA_ENABLE true +#endif #if CO_NO_TRACE > 0 static uint32_t *CO_traceTimeBuffers[CO_NO_TRACE]; static int32_t *CO_traceValueBuffers[CO_NO_TRACE]; @@ -224,6 +227,13 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { CO_memoryUsed += sizeof(CO_LSSmaster_t); #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + /* Gateway-ascii */ + CO->gtwa = (CO_GTWA_t *)calloc(1, sizeof(CO_GTWA_t)); + if (CO->gtwa == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_GTWA_t); +#endif + #if CO_NO_TRACE > 0 /* Trace */ for (i = 0; i < CO_NO_TRACE; i++) { @@ -276,6 +286,11 @@ void CO_delete(void *CANptr) { } #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + /* Gateway-ascii */ + free(CO->gtwa); +#endif + #if CO_NO_LSS_CLIENT == 1 /* LSSmaster */ free(CO->LSSmaster); @@ -370,6 +385,9 @@ void CO_delete(void *CANptr) { #if CO_NO_LSS_CLIENT == 1 static CO_LSSmaster_t COO_LSSmaster; #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + static CO_GTWA_t COO_gtwa; +#endif #if CO_NO_TRACE > 0 #ifndef CO_TRACE_BUFFER_SIZE_FIXED #define CO_TRACE_BUFFER_SIZE_FIXED 100 @@ -453,6 +471,11 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { CO->LSSmaster = &COO_LSSmaster; #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + /* Gateway-ascii */ + CO->gtwa = &COO_gtwa; +#endif + #if CO_NO_TRACE > 0 /* Trace */ for (i = 0; i < CO_NO_TRACE; i++) { @@ -710,12 +733,11 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { if (err) return err; - #if CO_NO_SDO_CLIENT != 0 /* SDOclient */ for (i = 0; i < CO_NO_SDO_CLIENT; i++) { err = CO_SDOclient_init(CO->SDOclient[i], - CO->SDO[0], + (void *)CO->SDO[0], (CO_SDOclientPar_t *)&OD_SDOClientParameter[i], CO->CANmodule[0], CO_RXCAN_SDO_CLI + i, @@ -738,7 +760,17 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { CO_CAN_ID_LSS_SRV); if (err) return err; +#endif + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + /* Gateway-ascii */ + err = CO_GTWA_init(CO->gtwa, + CO->SDOclient[0], + 500, + false, + CO->NMT); + if (err) return err; #endif #if CO_NO_TRACE > 0 @@ -816,6 +848,14 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, timeDifference_us, timerNext_us); +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + /* Gateway-ascii */ + CO_GTWA_process(CO->gtwa, + CO_GTWA_ENABLE, + timeDifference_us, + timerNext_us); +#endif + return reset; } diff --git a/CANopen.h b/CANopen.h index 2a94aa25..2264347d 100644 --- a/CANopen.h +++ b/CANopen.h @@ -136,6 +136,9 @@ extern "C" { #if CO_NO_LSS_CLIENT != 0 #include "305/CO_LSSmaster.h" #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + #include "309/CO_gateway_ascii.h" +#endif #if CO_NO_TRACE != 0 #include "extra/CO_trace.h" #endif @@ -241,6 +244,9 @@ typedef struct { #if CO_NO_LSS_CLIENT == 1 CO_LSSmaster_t *LSSmaster; /**< LSS master object */ #endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN + CO_GTWA_t *gtwa; /**< Gateway-ascii object (CiA309-3) */ +#endif #if CO_NO_TRACE > 0 CO_trace_t *trace[CO_NO_TRACE]; /**< Trace object for recording variables */ #endif diff --git a/Makefile b/Makefile index 30d85989..41899cb1 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,10 @@ SOURCES = \ $(CANOPEN_SRC)/301/CO_TIME.c \ $(CANOPEN_SRC)/301/CO_SDOclient.c \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ + $(CANOPEN_SRC)/301/CO_fifo.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ $(CANOPEN_SRC)/305/CO_LSSmaster.c \ + $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ $(OD_SRC)/CO_OD.c \ diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index f564f777..77287d5d 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -20,6 +20,7 @@ Change Log - Added `void *object` argument to CO_*_initCallback() functions. API clarified. - Add emergency receive callback also for own emergency messages. - Heartbeat is send immediately after NMT state changes. +- SDO client is rewritten. Now includes read/write fifo interface to transfer data. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN - driver API updated @@ -33,13 +34,15 @@ Change Log - Documentation added to `doc` directory: CHANGELOG.md, deviceSupport.md, gettingStarted.md, LSSusage.md and traceUsage.md. - All CANopen objects calculates next timer info for OS. Useful for energy saving. - Added file CO_config.h for stack configuration. Can be overridden by target specific or by custom definitions. +- CO_fifo.h/c for fifo data buffer, used with rewritten SDO client, etc. +- CANopen gateway-ascii command interface according to CiA309-3 as a microcontroller independent module. It includes NMT master, LSS master and SDO client interface. Interface is non-blocking, it is added to mainline. Example for Linux stdio and socket is included. [v1.3] - 2020-04-27 ------------------- - [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...v1.3) ### Changed - License changed to Apache 2.0. -- NMT self start functionality (OD object 1F80) implemented to strictly folow standard. Default value for object 1F80 have to be updated in OD editor. See README.md. +- NMT self start functionality (OD object 1F80) implemented to strictly follow standard. Default value for object 1F80 have to be updated in OD editor. See README.md. ### Fixed - Various fixes. - neuberger-socketCAN fixed. diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index 16dcf381..608899d2 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -15,194 +15,156 @@ CANopen network usually has one device with master functionalities for network c CANopenNode on Linux -------------------- -CANopenNode should run on any Linux machine. Examples below was tested on Debian based machines, including **Ubuntu** and **Raspberry PI**. It is possible to run tests described below without real CAN interface, because Linux kernel already contains virtual CAN interface. +CANopenNode should run on any Linux machine. Examples below was tested on Debian based machines, including Ubuntu and Raspberry PI. It is possible to run tests described below without real CAN interface, because Linux kernel already contains virtual CAN interface. +All necessary Linux specific files are included in socketCAN directory of CANopenNode and Makefile is included in base directory. ----- +### Preparation +We will use Linux command line interface (Terminal) for all examples below. Open the terminal and cd to your working directory. +First install supporting packages: [can-utils](https://github.com/linux-can/can-utils), which is very useful tool for working with CAN interface and [git](https://git-scm.com/), which is recommended for working with repositories. +Then clone [CANopenNode](https://github.com/CANopenNode/CANopenNode) from Github and build the executable program. -TODO update all below. (This is currently part of https://github.com/CANopenNode/CANopenSocket, but will become part of CANopenNode.) + sudo apt-get install git + sudo apt-get install can-utils + git clone https://github.com/CANopenNode/CANopenNode.git + cd CANopenNode + make -CANopenSocket consists of two applications: **canopend**, which runs in background, and **canopencomm**, command interface for SDO and NMT master. +Now prepare CAN virtual device and run _candump_, which will show all CAN traffic. Use a second terminal: + sudo modprobe vcan + sudo ip link add dev vcan0 type vcan + sudo ip link set up vcan0 + candump vcan0 -### canopend -**canopend** is an implementation of CANopen device with master functionality. It runs within three threads. Realtime thread processes CANopen SYNC and PDO objects. Mainline thread processes other non time critical objects. Both are nonblocking. Command interface thread is blocking. It accepts commands from socket connection from external application and executes master SDO and NMT tasks. +### First CANopen device +Go to the first terminal, where we have recently build executable, named _canopend_. +First print help, then run the program with some options. -### canopencomm -**canopencomm** is the other end of the Command interface. It accepts text commands form arguments or from standard input or from file. It sends commands to *canopend* via socket, line after line. Received result is printed to standard output. It is implementation of the CiA 309 standard. + ./canopend --help + ./canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto +You are now running a fully functional CANopen device on virtual CAN network. It is running in background until you terminate the process (with CTRL+C for example) or it receives a reset message from CAN network. By default process also shows some info messages on terminal, for example changes of NMT state or emergency messages, own and remote. -Getting started ---------------- -We will run two instances of *CANopend*. First will be basic node with ID=4, -second, with nodeID = 3, will have master functionality. +On the second terminal you can see some CAN traffic. After _canopend_ startup, first messages are: + vcan0 704 [1] 00 # Bootup message. + vcan0 084 [8] 00 50 01 2F F3 FF FF FF # Emergency message. + vcan0 704 [1] 7F # Heartbeat messages each second + vcan0 704 [1] 7F -### Get the project +Bootup and Heartbeat messages of node 4 have CAN-ID equal to 0x704. CAN-ID is 11-bit standard CAN identifier. 0x7F in heartbeat message means, that node is in NMT pre-operational state. -Clone the project from git repository and get submodules: +Also, both, first and second terminal shows, that there is an Emergency message after the bootup. Also Heartbeat messages shows NMT pre-operational state. - $ git clone https://github.com/CANopenNode/CANopenSocket.git - $ cd CANopenSocket - $ git submodule init - $ git submodule update +The easiest way to find the reason of the emergency message is to check the byte 4 (errorBit). It has value of 0x2F. Go to CANopenNode source code and open the file "301/CO_Emergency.h", section "Error status bits". 0x2F means "CO_EM_NON_VOLATILE_MEMORY", which is generic, critical error with access to non volatile device memory. -(If you want to work on submodule CANopenNode, you can `cd CANopenNode`, -and apply git commands directly on it. Initially is in head detached state, -so you have to `git checkout master` first. Then you can control submodule -separately, for example `git remote add {yourName} {url-of-your-git-repository}`, -and `git pull {yourName} {yourbranch}`) +This byte is CANopenNode specific. You can observe also first two bytes, which shows standard error code (0x5000 - Device Hardware) or third byte, which shows error register. If error register is different than zero, then node may be prohibited to enter operational and PDOs can not be exchanged with it. +You can follow the reason of the problem inside the source code. However, there are missing non-default storage files. Go to the first terminal, terminate the application with CTRL+C, add files and run _canopend_ again. -### First terminal: CAN dump + echo "-" > od4_storage + echo "-" > od4_storage_auto + ./canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto -Prepare CAN virtual (or real) device: +Second terminal now shows operational state (0x05) and one pre-defined PDO message with CAN-ID 0x184 and two bytes of data. To learn more about PDOs, how to configure communication and mapping parameters and how to use them see other sources of CANopen documentation. For example, you can read the article of PDO re-mapping procedure in [CAN newsletter magazine, June 2016](http://can-newsletter.org/engineering/engineering-miscellaneous/160601_can-newsletter-magazine-june-2016). - $ sudo modprobe vcan - $ sudo ip link add dev vcan0 type vcan - $ sudo ip link set up vcan0 + vcan0 704 [1] 00 + vcan0 184 [2] 00 00 # PDO message + vcan0 704 [1] 05 -Run candump from [can-utils](https://github.com/linux-can/can-utils): - $ sudo apt-get install can-utils - $ candump vcan0 +### Second CANopen device +Open the third terminal and cd to the same directory as is in the first terminal. First generate default storage files. Then start second instance of _canopend_ with NodeID = 3. Use default od_storage files and enable command interface on standard IO (terminal). -It will show all CAN traffic on vcan0. + echo "-" > od_storage + echo "-" > od_storage_auto + ./canopend vcan0 -i3 -c "stdio" +Now you should see in second terminal (_candump_) two CANopen devices sending heartbeats in one second interval each. One with node-ID = 4 and one with node-ID = 3. Both should be operational. -### Second terminal: canopend -Start second terminal, compile and start *canopend*. +### CANopen command interface +Second instance of _canopend_ was started with command interface enabled. This is CANopen gateway interface with ascii mapping, as specified in standard CiA309-3. This enables usage of CANopen master functionalities via basic terminal. Go to third terminal, type "help" and press enter to see its functionalities. - $ cd CANopenSocket/canopend - $ make - $ app/canopend --help - $ app/canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto + help -You should now see CAN messages on CAN dump terminal. Wait few seconds and -press CTRL-C. +#### SDO client +For example read Heartbeat producer parameter on CANopen device with ID=4. Parameter is located at index 0x1017, subindex 0, it is 16-bit integer. (It is basically unsigned 16 bit integer (u16), but i16 give us more readable output in our case.) - vcan0 704 [1] 00 # Bootup message. - vcan0 084 [8] 00 50 01 2F F3 FF FF FF # Emergency message. - vcan0 704 [1] 7F # Heartbeat messages - vcan0 704 [1] 7F # one per second. + [1] 4 read 0x1017 0 i16 -Heartbeat messages shows pre-operational state (0x7F). If you follow byte 4 of the -Emergency message into [CANopenNode/stack/CO_Emergency.h], -CO_EM_errorStatusBits, you will see under 0x2F "CO_EM_NON_VOLATILE_MEMORY", -which is generic, critical error with access to non volatile device memory. -This byte is CANopenNode specific. You can observe also first two bytes, -which shows standard error code (0x5000 - Device Hardware) or third byte, -which shows error register. If error register is different than zero, then -node is not able to enter operational and PDOs can not be exchanged with it. +You should see the response, which says that Heartbeats are transmitted in 1000 ms intervals: -You can follow the reason of the problem inside the source code. However, -there are missing non-default storage files. Add them and run it again. + [1] 1000 - $ echo - > od4_storage - $ echo - > od4_storage_auto - $ app/canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto +In CAN dump you can see some SDO communication. SDO communication can be quite complicated, if observing on _candump_, especially if larger data is split between multiple segments. However, there is no need to know the details, everything should work correctly in the background. Details about SDO communication can be found in CiA301 standard and partly also in 301/CO_SDOserver.h file, description of CO_SDO_state_t enumerator. - vcan0 704 [1] 00 - vcan0 184 [2] 00 00 # PDO message - vcan0 704 [1] 05 + [2] 4 write 0x1017 0 u16 5000 + [2] OK #response -Now there is operational state (0x05) and there shows one PDO on CAN -address 0x184. To learn more about PDOs, how to configure communication -and mapping parameters and how to use them see other sources of CANopen -documentation (For example article of PDO re-mapping procedure in [CAN -newsletter magazine, June 2016](http://can-newsletter.org/engineering/engineering-miscellaneous/160601_can-newsletter-magazine-june-2016) ). +In _candump_ you will notice, that heartbeats from node 4 are coming in 5 second interval now. You can do the same also for node 3, but you won't see anything on _candump_, because data are written into itself directly. In "stdio" you can omit sequence number, to make typing easier. -Start also second instance of *canopend* (master on nodeID=3) in the same -window (*canopend terminal*). Use default od_storage files and default -socket for command interface. + 3 w 0x1017 0 u16 2500 + [0] OK - $ # press CTRL-Z - $ bg - $ app/canopend vcan0 -i 3 -c "" +Now store Object dictionary on node-ID 4, so it will preserve variables on next start of the program. + 4 w 0x1010 1 u32 0x65766173 + [0] OK -### Third terminal: canopencomm +More details about Object dictionary variables can be found in CiA301 standard or in example/IO.html file. -Start third terminal, compile and start canopencomm. - $ cd CANopenSocket/canopencomm - $ make - $ ./canopencomm --help - -#### SDO master - -Play with it and also observe CAN dump terminal. First Heartbeat at -index 0x1017, subindex 0, 16-bit integer, on nodeID 4. +#### NMT master +If node is operational (started), it can exchange all objects, including PDO, SDO, etc. In NMT pre-operational, PDOs are disabled, SDOs works. In stopped only NMT messages are accepted. Try following commands and observe _candump_. - $ ./canopencomm [1] 4 read 0x1017 0 i16 - $ ./canopencomm [1] 4 write 0x1017 0 i16 5000 + set node 4 + [0] OK -In CAN dump you can see some SDO communication. You will notice, that -Heartbeats from node 4 are coming in 5 second interval now. You can do -the same also for node 3. Now store Object dictionary, so it will preserve -variables on next start of the program. + preop + [0] OK - $ ./canopencomm 4 w 0x1010 1 u32 0x65766173 + start + [0] OK -You can read more about Object dictionary variables for this -CANopenNode in [canopend/CANopenSocket.html]. + stop + [0] OK + r 0x1017 0 i16 + [0] ERROR: 0x05040000 #SDO protocol timed out. -#### NMT master -If node is operational (started), it can exchange all objects, including -PDO, SDO, etc. In pre-operational, PDOs are disabled, SDOs works. In stopped -only NMT messages are accepted. + reset communication + [0] OK - $ ./canopencomm 4 preop - $ ./canopencomm 4 start - $ ./canopencomm 4 stop - $ ./canopencomm 4 r 0x1017 0 i16 # time out - $ ./canopencomm 4 reset communication - $ ./canopencomm 4 reset node - $ ./canopencomm 3 reset node + reset node + [0] OK -In *canopend terminal* you see, that both devices finished. Further commands -are not possible. If you set so, last command can also reset computer. + 3 reset communication + [0] OK -#### Combining NMT commands into a single file + 3 reset node + [0] OK -Create a `commands.txt` file, and for its content enter your commands. -Example: - [1] 3 start - [2] 4 start +#### Other communication channels +We used simple stdio for command interface. In Linux also sockets can be used, either local or tcp. See `./canopend --help` for options. Simple Linux tool for establishing socket connection is _netcat_ or _nc_. For example `nc -U /tmp/CO_command_socket` for local socket or `nc 60000` for tcp socket. There are also some tools from [CANopenSocket](https://github.com/CANopenNode/CANopenSocket) project. -Make canopencomm use that file: - - $ ./canopencomm -f commands.txt - [1] OK - [2] OK +Please be careful when exposing your CANopen network to the outside world, it is your responsibility, if something dangerous happen. ### Next steps -Now you can learn more skills on CANopen from some other sources: -books, data sheet of some CANopen device, standard CiA 301(it's free), etc. -Then you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware). - - -Accessing real CANopen devices is the same as described above for virtual CAN interface. -Some tested USB to CAN interfaces, which are natively integrated into Linux are: +Now you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware). +Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native integrated into Linux kernel are: - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with: `sudo slcand -f -o -c -s8 /dev/ttyACM0 can0; sudo ip link set up can0` - - [EMS CPC-USB](http://www.ems-wuensche.com/product/datasheet/html/can-usb-adapter-converter-interface-cpcusb.html) - Start with: `sudo ip link set up can0 type can bitrate 250000` - - [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Needs newer Linux kernel, supports CAN flexible data rate. + - [EMS CPC-USB](https://www.ems-wuensche.com/?post_type=product&p=746) or [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Start with: `sudo ip link set up can0 type can bitrate 250000` - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can) (Kconfig files). - - Beaglebone or Paspberry PI or similar has CAN capes available. On RPI worked - also the above USB interfaces, but it was necessary to compile the kernel. + - Beaglebone or Paspberry PI or similar has CAN capes available. On RPI worked also the above USB interfaces, but it was necessary to compile the kernel. -With [CANopenNode](https://github.com/CANopenNode/CANopenNode) you can also design your -own device. There are many very useful and high quality specifications for different -[device profiles](http://www.can-cia.org/standardization/specifications/), -some of them are public and free to download. +With [CANopenNode](https://github.com/CANopenNode/CANopenNode) you can also design your own device. There are many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download. -Here we played with virtual CAN interface and result shows as pixels on -screen. If you connect real CAN interface to your computer, things may +Here we played with virtual CAN interface and result shows as pixels on screen. If you connect real CAN interface to your computer, things may become dangerous. Keep control and safety on your machines! diff --git a/example/CO_OD.c b/example/CO_OD.c index 290a9fbe..9b22f840 100644 --- a/example/CO_OD.c +++ b/example/CO_OD.c @@ -48,6 +48,7 @@ struct sCO_OD_RAM CO_OD_RAM = { /*1003*/ {0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, /*1010*/ {0x3L}, /*1011*/ {0x1L}, +/*1280*/{{0x3, 0x0L, 0x0L, 0x0}}, /*2100*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*2103*/ 0x0, /*2104*/ 0x0, @@ -135,6 +136,11 @@ struct sCO_OD_EEPROM CO_OD_EEPROM = { {(void*)&CO_OD_ROM.SDOServerParameter[0].maxSubIndex, 0x05, 1}, {(void*)&CO_OD_ROM.SDOServerParameter[0].COB_IDClientToServer, 0x85, 4}, {(void*)&CO_OD_ROM.SDOServerParameter[0].COB_IDServerToClient, 0x85, 4}}; +/*0x1280*/ const CO_OD_entryRecord_t OD_record1280[4] = { + {(void*)&CO_OD_RAM.SDOClientParameter[0].maxSubIndex, 0x06, 1}, + {(void*)&CO_OD_RAM.SDOClientParameter[0].COB_IDClientToServer, 0xBE, 4}, + {(void*)&CO_OD_RAM.SDOClientParameter[0].COB_IDServerToClient, 0xBE, 4}, + {(void*)&CO_OD_RAM.SDOClientParameter[0].nodeIDOfTheSDOServer, 0x0E, 1}}; /*0x1400*/ const CO_OD_entryRecord_t OD_record1400[3] = { {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].maxSubIndex, 0x05, 1}, {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].COB_IDUsedByRPDO, 0x8D, 4}, @@ -302,6 +308,7 @@ const CO_OD_entry_t CO_OD[CO_OD_NoOfElements] = { {0x1019, 0x00, 0x0D, 1, (void*)&CO_OD_ROM.synchronousCounterOverflowValue}, {0x1029, 0x06, 0x0D, 1, (void*)&CO_OD_ROM.errorBehavior[0]}, {0x1200, 0x02, 0x00, 0, (void*)&OD_record1200}, +{0x1280, 0x03, 0x00, 0, (void*)&OD_record1280}, {0x1400, 0x02, 0x00, 0, (void*)&OD_record1400}, {0x1401, 0x02, 0x00, 0, (void*)&OD_record1401}, {0x1402, 0x02, 0x00, 0, (void*)&OD_record1402}, diff --git a/example/CO_OD.h b/example/CO_OD.h index 756970cf..c2dad14d 100644 --- a/example/CO_OD.h +++ b/example/CO_OD.h @@ -93,7 +93,7 @@ #define CO_NO_TIME 1 //Associated objects: 1012-1013 #define CO_NO_EMERGENCY 1 //Associated objects: 1014, 1015 #define CO_NO_SDO_SERVER 1 //Associated objects: 1200 - #define CO_NO_SDO_CLIENT 0 + #define CO_NO_SDO_CLIENT 1 //Associated objects: 1280 #define CO_NO_RPDO 4 //Associated objects: 1400, 1401, 1402, 1403, 1600, 1601, 1602, 1603 #define CO_NO_TPDO 4 //Associated objects: 1800, 1801, 1802, 1803, 1A00, 1A01, 1A02, 1A03 #define CO_NO_NMT_MASTER 0 @@ -104,7 +104,7 @@ /******************************************************************************* OBJECT DICTIONARY *******************************************************************************/ - #define CO_OD_NoOfElements 56 + #define CO_OD_NoOfElements 57 /******************************************************************************* @@ -124,6 +124,13 @@ UNSIGNED32 COB_IDServerToClient; } OD_SDOServerParameter_t; +/*1280[1] */ typedef struct{ + UNSIGNED8 maxSubIndex; + UNSIGNED32 COB_IDClientToServer; + UNSIGNED32 COB_IDServerToClient; + UNSIGNED8 nodeIDOfTheSDOServer; + } OD_SDOClientParameter_t; + /*1400[4] */ typedef struct{ UNSIGNED8 maxSubIndex; UNSIGNED32 COB_IDUsedByRPDO; @@ -195,6 +202,7 @@ struct sCO_OD_RAM{ /*1003 */ UNSIGNED32 preDefinedErrorField[8]; /*1010 */ UNSIGNED32 storeParameters[1]; /*1011 */ UNSIGNED32 restoreDefaultParameters[1]; +/*1280[1] */ OD_SDOClientParameter_t SDOClientParameter[1]; /*2100 */ OCTET_STRING errorStatusBits[10]; /*2103 */ UNSIGNED16 SYNCCounter; /*2104 */ UNSIGNED16 SYNCTime; @@ -346,6 +354,9 @@ extern struct sCO_OD_ROM CO_OD_ROM; /*1200[1], Data Type: OD_SDOServerParameter_t, Array[1] */ #define OD_SDOServerParameter CO_OD_ROM.SDOServerParameter +/*1280[1], Data Type: OD_SDOClientParameter_t, Array[1] */ + #define OD_SDOClientParameter CO_OD_RAM.SDOClientParameter + /*1400[4], Data Type: OD_RPDOCommunicationParameter_t, Array[4] */ #define OD_RPDOCommunicationParameter CO_OD_ROM.RPDOCommunicationParameter diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 4dd55893..410e210f 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -112,19 +112,25 @@ extern "C" { #ifndef CO_CONFIG_GTW #define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | \ - CO_CONFIG_GTW_ASCII) + CO_CONFIG_GTW_ASCII | \ + CO_CONFIG_GTW_ASCII_ERROR_DESC | \ + CO_CONFIG_GTW_ASCII_PRINT_HELP) +#define CO_CONFIG_GTW_BLOCK_DL_LOOP 1 #define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 #endif -/* Basic definitions */ +/* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ #define CO_LITTLE_ENDIAN +#define CO_SWAP_16(x) x +#define CO_SWAP_32(x) x +#define CO_SWAP_64(x) x /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ typedef unsigned char bool_t; typedef float float32_t; -typedef long double float64_t; +typedef double float64_t; typedef char char_t; typedef unsigned char oChar_t; typedef unsigned char domain_t; diff --git a/example/Makefile b/example/Makefile index c89dd380..dc3a9a11 100644 --- a/example/Makefile +++ b/example/Makefile @@ -29,8 +29,10 @@ SOURCES = \ $(CANOPEN_SRC)/301/CO_TIME.c \ $(CANOPEN_SRC)/301/CO_SDOclient.c \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ + $(CANOPEN_SRC)/301/CO_fifo.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ $(CANOPEN_SRC)/305/CO_LSSmaster.c \ + $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ $(OD_SRC)/CO_OD.c \ diff --git a/example/_project.xml b/example/_project.xml index 160fd9d3..26a47637 100644 --- a/example/_project.xml +++ b/example/_project.xml @@ -28,7 +28,7 @@ SDO server is implemented on all CANopen devices. Permissible value for SDO sever is 0 or 1. - + A Service Data Object (SDO) reads from entries or writes to entries of the Object Dictionary. SDO client is usually a master device in a CANopen network. @@ -253,7 +253,7 @@ bit 0-7: Node ID (optional) - + 0x1280 - 0x12FF SDO client parameter max sub-index diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index cee5b056..d6a5df94 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -25,6 +25,12 @@ * limitations under the License. */ +/* following macro is necessary for accept4() function call (sockets) */ +#define _GNU_SOURCE + +#include "CANopen.h" +#include "CO_Linux_threads.h" + #include #include #include @@ -32,12 +38,22 @@ #include #include #include +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#include +#include +#include +#include +#include +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ -#include "CANopen.h" + +#ifndef LISTEN_BACKLOG +#define LISTEN_BACKLOG 50 +#endif /* Helper function - get monotonic clock time in microseconds */ -static uint64_t CO_LinuxThreads_clock_gettime_us(void) +static inline uint64_t CO_LinuxThreads_clock_gettime_us(void) { struct timespec ts; @@ -46,67 +62,51 @@ static uint64_t CO_LinuxThreads_clock_gettime_us(void) } -/* Mainline thread - basic (threadMain) ***************************************/ -static struct -{ - uint64_t start; /* time value CO_process() was called last time in us */ -} threadMain; - -void threadMain_init(void (*callback)(void*), void *object) -{ - threadMain.start = CO_LinuxThreads_clock_gettime_us(); - - CO_NMT_initCallbackPre(CO->NMT, object, callback); - CO_SDO_initCallbackPre(CO->SDO[0], object, callback); - CO_EM_initCallbackPre(CO->em, object, callback); - CO_HBconsumer_initCallbackPre(CO->HBcons, object, callback); -} - -void threadMain_close(void) -{ - CO_NMT_initCallbackPre(CO->NMT, NULL, NULL); - CO_SDO_initCallbackPre(CO->SDO[0], NULL, NULL); - CO_EM_initCallbackPre(CO->em, NULL, NULL); - CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, NULL); -} +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +/* write response string from gateway-ascii object */ +static size_t gtwa_write_response(void *object, const char *buf, size_t count) { + int* fd = (int *)object; + size_t nWritten = 0; -void threadMain_process(CO_NMT_reset_cmd_t *reset) -{ - uint32_t finished; - uint32_t diff; - uint64_t now; - - now = CO_LinuxThreads_clock_gettime_us(); - diff = (uint32_t)(now - threadMain.start); - threadMain.start = now; - - /* we use timerNext_us in CO_process() as indication if processing is - * finished. We ignore any calculated values for maximum delay times. */ - do { - finished = 1; - *reset = CO_process(CO, diff, &finished); - diff = 0; - } while ((*reset == CO_RESET_NOT) && (finished == 0)); + if (fd != NULL && *fd >= 0) { + ssize_t n = write(*fd, (const void *)buf, count); + if (n > 0) { + nWritten = (size_t)n; + } + else { + log_printf(LOG_DEBUG, DBG_ERRNO, "write(gtwa_response)"); + } + } + return nWritten; } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ /* Mainline thread - Blocking (threadMainWait) ********************************/ -static struct -{ +static struct { uint64_t start; /* time value CO_process() was called last time in us */ int epoll_fd; /* epoll file descriptor */ int event_fd; /* notification event file descriptor */ int timer_fd; /* interval timer file descriptor */ uint32_t interval_us; /* interval for threadMainWait_process */ struct itimerspec tm; /* structure for timer configuration */ -} threadMainWait; +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + int32_t commandInterface; /* command interface type or tcp port */ + uint32_t socketTimeout_us; + uint32_t socketTimeoutTmr_us; + char *localSocketPath;/* path in case of local socket */ + int gtwa_fdSocket; /* gateway socket file descriptor */ + int gtwa_fd; /* gateway io stream file descriptor */ + bool_t freshCommand; +#endif +} tmw; static void threadMainWait_callback(void *object) { /* send event to wake threadMainWait_process() */ uint64_t u = 1; ssize_t s; - s = write(threadMainWait.event_fd, &u, sizeof(uint64_t)); + s = write(tmw.event_fd, &u, sizeof(uint64_t)); if (s != sizeof(uint64_t)) { log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); } @@ -119,60 +119,175 @@ void threadMainWait_init(void) CO_SDO_initCallbackPre(CO->SDO[0], NULL, threadMainWait_callback); CO_EM_initCallbackPre(CO->em, NULL, threadMainWait_callback); CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, threadMainWait_callback); +#if CO_NO_SDO_CLIENT != 0 + CO_SDOclient_initCallbackPre(CO->SDOclient[0], NULL, + threadMainWait_callback); +#endif + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + CO_GTWA_initRead(CO->gtwa, gtwa_write_response, (void *)&tmw.gtwa_fd); + tmw.freshCommand = true; +#endif /* Initial value for time calculation */ - threadMainWait.start = CO_LinuxThreads_clock_gettime_us(); + tmw.start = CO_LinuxThreads_clock_gettime_us(); } -void threadMainWait_initOnce(uint32_t interval_us) +void threadMainWait_initOnce(uint32_t interval_us, + int32_t commandInterface, + uint32_t socketTimeout_ms, + char *localSocketPath) { - int32_t ret; + int ret; struct epoll_event ev; /* Configure epoll for mainline */ - threadMainWait.epoll_fd = epoll_create(1); - if (threadMainWait.epoll_fd < 0) { + tmw.epoll_fd = epoll_create(1); + if (tmw.epoll_fd < 0) { log_printf(LOG_CRIT, DBG_ERRNO, "epoll_create()"); exit(EXIT_FAILURE); } /* Configure eventfd for notifications and add it to epoll */ - threadMainWait.event_fd = eventfd(0, EFD_NONBLOCK); - if (threadMainWait.event_fd < 0) { + tmw.event_fd = eventfd(0, EFD_NONBLOCK); + if (tmw.event_fd < 0) { log_printf(LOG_CRIT, DBG_ERRNO, "eventfd()"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; - ev.data.fd = threadMainWait.event_fd; - ret = epoll_ctl(threadMainWait.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0){ + ev.data.fd = tmw.event_fd; + ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0) { log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(event_fd)"); exit(EXIT_FAILURE); } /* Configure timer for interval_us and add it to epoll */ - threadMainWait.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); - if (threadMainWait.timer_fd < 0) { + tmw.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (tmw.timer_fd < 0) { log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_create()"); exit(EXIT_FAILURE); } - threadMainWait.interval_us = interval_us; - threadMainWait.tm.it_interval.tv_sec = interval_us / 1000000; - threadMainWait.tm.it_interval.tv_nsec = (interval_us % 1000000) * 1000; - threadMainWait.tm.it_value.tv_sec = 0; - threadMainWait.tm.it_value.tv_nsec = 1; - ret = timerfd_settime(threadMainWait.timer_fd, 0, &threadMainWait.tm, NULL); - if (ret < 0){ + tmw.interval_us = interval_us; + tmw.tm.it_interval.tv_sec = interval_us / 1000000; + tmw.tm.it_interval.tv_nsec = (interval_us % 1000000) * 1000; + tmw.tm.it_value.tv_sec = 0; + tmw.tm.it_value.tv_nsec = 1; + ret = timerfd_settime(tmw.timer_fd, 0, &tmw.tm, NULL); + if (ret < 0) { log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_settime"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; - ev.data.fd = threadMainWait.timer_fd; - ret = epoll_ctl(threadMainWait.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0){ + ev.data.fd = tmw.timer_fd; + ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0) { log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(timer_fd)"); exit(EXIT_FAILURE); } + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + /* Configure gateway-ascii command interface (CiA309-3) */ + tmw.commandInterface = commandInterface; + tmw.socketTimeout_us = (socketTimeout_ms < (UINT_MAX / 1000 - 1000000)) ? + socketTimeout_ms * 1000 : (UINT_MAX - 1000000); + tmw.gtwa_fdSocket = -1; + tmw.gtwa_fd = -1; + + if (commandInterface == CO_COMMAND_IF_STDIO) { + tmw.gtwa_fd = STDIN_FILENO; + log_printf(LOG_INFO, DBG_COMMAND_STDIO_INFO); + } + else if (commandInterface == CO_COMMAND_IF_LOCAL_SOCKET) { + struct sockaddr_un addr; + tmw.localSocketPath = localSocketPath; + + /* Create, bind and listen local socket */ + tmw.gtwa_fdSocket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); + if(tmw.gtwa_fdSocket < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "socket(local)"); + exit(EXIT_FAILURE); + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, localSocketPath, sizeof(addr.sun_path) - 1); + ret = bind(tmw.gtwa_fdSocket, (struct sockaddr *) &addr, + sizeof(struct sockaddr_un)); + if(ret < 0) { + log_printf(LOG_CRIT, DBG_COMMAND_LOCAL_BIND, localSocketPath); + exit(EXIT_FAILURE); + } + + ret = listen(tmw.gtwa_fdSocket, LISTEN_BACKLOG); + if(ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "listen(local)"); + exit(EXIT_FAILURE); + } + + log_printf(LOG_INFO, DBG_COMMAND_LOCAL_INFO, localSocketPath); + } + else if (commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN && + commandInterface <= CO_COMMAND_IF_TCP_SOCKET_MAX + ) { + struct sockaddr_in addr; + const int yes = 1; + + /* Create, bind and listen socket */ + tmw.gtwa_fdSocket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if(tmw.gtwa_fdSocket < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "socket(tcp)"); + exit(EXIT_FAILURE); + } + + setsockopt(tmw.gtwa_fdSocket, SOL_SOCKET, SO_REUSEADDR, + &yes, sizeof(int)); + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(commandInterface); + addr.sin_addr.s_addr = INADDR_ANY; + + ret = bind(tmw.gtwa_fdSocket, (struct sockaddr *) &addr, + sizeof(struct sockaddr_in)); + if(ret < 0) { + log_printf(LOG_CRIT, DBG_COMMAND_TCP_BIND, commandInterface); + exit(EXIT_FAILURE); + } + + ret = listen(tmw.gtwa_fdSocket, LISTEN_BACKLOG); + if(ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "listen(tcp)"); + exit(EXIT_FAILURE); + } + + log_printf(LOG_INFO, DBG_COMMAND_TCP_INFO, commandInterface); + } + else { + tmw.commandInterface = CO_COMMAND_IF_DISABLED; + } + + if (tmw.gtwa_fd >= 0) { + ev.events = EPOLLIN; + ev.data.fd = tmw.gtwa_fd; + ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fd)"); + exit(EXIT_FAILURE); + } + } + if (tmw.gtwa_fdSocket >= 0) { + /* prepare epool for listening for new socket connection. After + * connection will be accepted, fd for io operation will be defined. */ + ev.events = EPOLLIN | EPOLLONESHOT; + ev.data.fd = tmw.gtwa_fdSocket; + ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fdSocket)"); + exit(EXIT_FAILURE); + } + } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ } void threadMainWait_close(void) @@ -182,65 +297,201 @@ void threadMainWait_close(void) CO_EM_initCallbackPre(CO->em, NULL, NULL); CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, NULL); - close(threadMainWait.epoll_fd); - close(threadMainWait.event_fd); - close(threadMainWait.timer_fd); - threadMainWait.epoll_fd = -1; - threadMainWait.event_fd = -1; - threadMainWait.timer_fd = -1; + close(tmw.epoll_fd); + tmw.epoll_fd = -1; + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + if (tmw.commandInterface == CO_COMMAND_IF_LOCAL_SOCKET) { + if (tmw.gtwa_fd > 0) { + close(tmw.gtwa_fd); + } + close(tmw.gtwa_fdSocket); + /* Remove local socket file from filesystem. */ + if(remove(tmw.localSocketPath) < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "remove(local)"); + } + } + else if (tmw.commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN) { + if (tmw.gtwa_fd > 0) { + close(tmw.gtwa_fd); + } + close(tmw.gtwa_fdSocket); + } + tmw.gtwa_fd = -1; + tmw.gtwa_fdSocket = -1; +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ + + close(tmw.event_fd); + tmw.event_fd = -1; + + close(tmw.timer_fd); + tmw.timer_fd = -1; } +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +static inline void socetAcceptEnableForEpoll(void) { + struct epoll_event ev; + int ret; + + ev.events = EPOLLIN | EPOLLONESHOT; + ev.data.fd = tmw.gtwa_fdSocket; + ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_MOD, ev.data.fd, &ev); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fdSocket)"); + } +} +#endif + uint32_t threadMainWait_process(CO_NMT_reset_cmd_t *reset) { - int ready, ret; + int ready; struct epoll_event ev; uint64_t ull; ssize_t s; uint32_t diff, timerNext_us; /* wait for event or timer expiration and read data from file descriptors */ - ready = epoll_wait(threadMainWait.epoll_fd, &ev, 1, -1); + ready = epoll_wait(tmw.epoll_fd, &ev, 1, -1); if (ready != 1 && errno != EINTR) { log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_wait"); } - else if (ev.data.fd == threadMainWait.event_fd) { - s = read(threadMainWait.event_fd, &ull, sizeof(uint64_t)); + else if (ev.data.fd == tmw.event_fd) { + s = read(tmw.event_fd, &ull, sizeof(uint64_t)); if (s != sizeof(uint64_t)) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(event_fd)"); + log_printf(LOG_DEBUG, DBG_ERRNO, "read(event_fd)"); } } - else if (ev.data.fd == threadMainWait.timer_fd) { - s = read(threadMainWait.timer_fd, &ull, sizeof(uint64_t)); + else if (ev.data.fd == tmw.timer_fd) { + s = read(tmw.timer_fd, &ull, sizeof(uint64_t)); if (s != sizeof(uint64_t) && errno != EAGAIN) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(timer_fd)"); + log_printf(LOG_DEBUG, DBG_ERRNO, "read(timer_fd)"); } } +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + else if (ev.data.fd == tmw.gtwa_fdSocket) { + bool_t fail = false; + + tmw.gtwa_fd = accept4(tmw.gtwa_fdSocket, NULL, NULL, SOCK_NONBLOCK); + if (tmw.gtwa_fd < 0) { + fail = true; + if (errno != EAGAIN && errno != EWOULDBLOCK) { + log_printf(LOG_CRIT, DBG_ERRNO, "accept(gtwa_fdSocket)"); + } + } + else { + int ret; + /* add fd to epoll */ + struct epoll_event ev2; + ev2.events = EPOLLIN; + ev2.data.fd = tmw.gtwa_fd; + ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev2.data.fd, &ev2); + if (ret < 0) { + fail = true; + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(add, gtwa_fd)"); + } + tmw.socketTimeoutTmr_us = 0; + } + + if (fail) { + socetAcceptEnableForEpoll(); + } + } + else if (ev.data.fd == tmw.gtwa_fd) { + char buf[CO_CONFIG_GTWA_COMM_BUF_SIZE]; + size_t space = CO_GTWA_write_getSpace(CO->gtwa); + + s = read(tmw.gtwa_fd, buf, space); + if (s < 0 && errno != EAGAIN) { + log_printf(LOG_DEBUG, DBG_ERRNO, "read(gtwa_fd)"); + } + else if (s >= 0) { + if (tmw.commandInterface == CO_COMMAND_IF_STDIO) { + /* simplify command interface on stdio, make hard to type + * sequence optional, prepend "[0] " to string, if missing */ + const char sequence[] = "[0] "; + bool_t closed = (buf[s-1] == '\n'); /* is command closed? */ + + if (buf[0] != '[' && (space - s) >= strlen(sequence) + && s > 1 && closed && tmw.freshCommand + ) { + CO_GTWA_write(CO->gtwa, sequence, strlen(sequence)); + } + tmw.freshCommand = closed; + CO_GTWA_write(CO->gtwa, buf, s); + } + else { /* socket, local or tcp */ + if (s == 0) { + int ret; + /* EOF received, close connection and enable socket accept*/ + ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_DEL, + tmw.gtwa_fd, NULL); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, + "epoll_ctl(del, gtwa_fd)"); + } + if (close(tmw.gtwa_fd) < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd)"); + } + tmw.gtwa_fd = -1; + socetAcceptEnableForEpoll(); + } + else { + CO_GTWA_write(CO->gtwa, buf, s); + } + } + } + tmw.socketTimeoutTmr_us = 0; + } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ /* calculate time difference since last call */ ull = CO_LinuxThreads_clock_gettime_us(); - diff = (uint32_t)(ull - threadMainWait.start); - threadMainWait.start = ull; + diff = (uint32_t)(ull - tmw.start); + tmw.start = ull; + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + /* if socket connection is established, verify timeout */ + if (tmw.socketTimeout_us > 0 && tmw.gtwa_fdSocket > 0 && tmw.gtwa_fd > 0) { + if (tmw.socketTimeoutTmr_us > tmw.socketTimeout_us) { + int ret; + /* timout expired, close current connection and accept next */ + ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_DEL, tmw.gtwa_fd, NULL); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(del, gtwa_fd), tmo"); + } + if (close(tmw.gtwa_fd) < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd), tmo"); + } + tmw.gtwa_fd = -1; + socetAcceptEnableForEpoll(); + } + else { + tmw.socketTimeoutTmr_us += diff; + } + } +#endif /* stack will lower this, if necessary */ - timerNext_us = threadMainWait.interval_us; + timerNext_us = tmw.interval_us; /* process CANopen objects */ *reset = CO_process(CO, diff, &timerNext_us); /* lower next timer interval if necessary */ - if (timerNext_us < threadMainWait.interval_us) { + if (timerNext_us < tmw.interval_us) { + int ret; /* add one microsecond extra delay and make sure it is not zero */ timerNext_us += 1; - if (threadMainWait.interval_us < 1000000) { - threadMainWait.tm.it_value.tv_nsec = timerNext_us * 1000; - } else { - threadMainWait.tm.it_value.tv_sec = timerNext_us / 1000000; - threadMainWait.tm.it_value.tv_nsec = (timerNext_us % 1000000) * 1000; + if (tmw.interval_us < 1000000) { + tmw.tm.it_value.tv_nsec = timerNext_us * 1000; + } + else { + tmw.tm.it_value.tv_sec = timerNext_us / 1000000; + tmw.tm.it_value.tv_nsec = (timerNext_us % 1000000) * 1000; } - ret = timerfd_settime(threadMainWait.timer_fd, 0, - &threadMainWait.tm, NULL); - if (ret < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "timerfd_settime"); + ret = timerfd_settime(tmw.timer_fd, 0, &tmw.tm, NULL); + if (ret < 0) { + log_printf(LOG_DEBUG, DBG_ERRNO, "timerfd_settime"); } } @@ -285,7 +536,7 @@ uint32_t CANrx_threadTmr_process(void) if (result < 0) { result = read(threadRT.interval_fd, &missed, sizeof(missed)); if (result > 0) { - /* at least one timer interval occured */ + /* at least one timer interval occurred */ CO_LOCK_OD(); if(CO->CANmodule[0]->CANnormal) { diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index 0bd535f9..e5a3e057 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -34,6 +34,20 @@ extern "C" { #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +/** + * Command interface type for gateway-ascii + */ +typedef enum { + CO_COMMAND_IF_DISABLED = -100, + CO_COMMAND_IF_STDIO = -2, + CO_COMMAND_IF_LOCAL_SOCKET = -1, + CO_COMMAND_IF_TCP_SOCKET_MIN = 0, + CO_COMMAND_IF_TCP_SOCKET_MAX = 0xFFFF +} CO_commandInterface_t; +#endif + + /** * @defgroup CO_socketCAN socketCAN * @{ @@ -104,9 +118,15 @@ void threadMainWait_init(void); * * Function must be called only once, before node starts operating. * - * @param interval_us interval of the threadMainWait_process() + * @param interval_us Interval of the threadMainWait_process() + * @param commandInterface Command interface type from CO_commandInterface_t + * @param socketTimeout_ms Timeout for established socket connection in [ms] + * @param localSocketPath File path, if commandInterface is local socket */ -void threadMainWait_initOnce(uint32_t interval_us); +void threadMainWait_initOnce(uint32_t interval_us, + int32_t commandInterface, + uint32_t socketTimeout_ms, + char *localSocketPath); /** @@ -169,7 +189,7 @@ void CANrx_threadTmr_close(void); * * @return Number of interval timer passes since last call. */ -void CANrx_threadTmr_process(void); +uint32_t CANrx_threadTmr_process(void); /** @} */ diff --git a/socketCAN/CO_OD_storage.c b/socketCAN/CO_OD_storage.c index e5e45586..1a39ee8f 100644 --- a/socketCAN/CO_OD_storage.c +++ b/socketCAN/CO_OD_storage.c @@ -128,10 +128,10 @@ int CO_OD_storage_saveSecure( FILE *fp = fopen(filename, "w"); if(fp != NULL) { - CO_LOCK_OD(); + //CO_LOCK_OD(); fwrite((const void *)odAddress, 1, odSize, fp); CRC = crc16_ccitt((unsigned char*)odAddress, odSize, 0); - CO_UNLOCK_OD(); + //CO_UNLOCK_OD(); fwrite((const void *)&CRC, 1, 2, fp); fclose(fp); diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 764b87f5..a6cf3f4d 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -26,13 +26,13 @@ */ +#ifndef CO_DRIVER_TARGET +#define CO_DRIVER_TARGET + /* This file contains device and application specific definitions. * It is included from CO_driver.h, which contains documentation * for common definitions below. */ -#ifndef CO_DRIVER_TARGET -#define CO_DRIVER_TARGET - #include #include #include @@ -41,7 +41,7 @@ #include #include -#if __has_include("CO_driver_custom.h") +#ifdef CO_DRIVER_CUSTOM #include "CO_driver_custom.h" #endif #include "CO_error.h" @@ -117,7 +117,10 @@ extern "C" { #endif #ifndef CO_CONFIG_GTW -#define CO_CONFIG_GTW (CO_CONFIG_GTW_ASCII) +#define CO_CONFIG_GTW (CO_CONFIG_GTW_ASCII | \ + CO_CONFIG_GTW_ASCII_ERROR_DESC | \ + CO_CONFIG_GTW_ASCII_PRINT_HELP) +#define CO_CONFIG_GTW_BLOCK_DL_LOOP 3 #define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 #endif @@ -194,8 +197,15 @@ extern "C" { #ifdef __BYTE_ORDER #if __BYTE_ORDER == __LITTLE_ENDIAN #define CO_LITTLE_ENDIAN + #define CO_SWAP_16(x) x + #define CO_SWAP_32(x) x + #define CO_SWAP_64(x) x #else #define CO_BIG_ENDIAN + #include + #define CO_SWAP_16(x) bswap_16(x) + #define CO_SWAP_32(x) bswap_32(x) + #define CO_SWAP_64(x) bswap_64(x) #endif #endif /* #define CO_USE_LEDS */ @@ -204,7 +214,7 @@ extern "C" { /* int8_t to uint64_t are defined in stdint.h */ typedef unsigned char bool_t; typedef float float32_t; -typedef long double float64_t; +typedef double float64_t; typedef char char_t; typedef unsigned char oChar_t; typedef unsigned char domain_t; diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index 2008dc40..310fde40 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -46,13 +46,13 @@ extern "C" { /* * Message definitions for Linux CANopen socket driver (notice and errors) */ -#define CAN_NOT_FOUND "CAN Interface \"%s\" not found" -#define CAN_INIT_FAILED "CAN Interface \"%s\" Init failed" -#define CAN_NAMETOINDEX "Interface \"%s\" -> Index %d" +#define CAN_NOT_FOUND "(%s) CAN Interface \"%s\" not found", __func__ +#define CAN_INIT_FAILED "(%s) CAN Interface \"%s\" Init failed", __func__ +#define CAN_BINDING_FAILED "(%s) Binding CAN Interface \"%s\" failed", __func__ +#define CAN_ERROR_FILTER_FAILED "(%s) Setting CAN Interface \"%s\" error filter failed", __func__ +#define CAN_FILTER_FAILED "(%s) Setting CAN Interface \"%s\" message filter failed", __func__ +#define CAN_NAMETOINDEX "CAN Interface \"%s\" -> Index %d" #define CAN_SOCKET_BUF_SIZE "CAN Interface \"%s\" Buffer set to %d messages (%d Bytes)" -#define CAN_BINDING_FAILED "Binding CAN Interface \"%s\" failed" -#define CAN_ERROR_FILTER_FAILED "Setting CAN Interface \"%s\" error filter failed" -#define CAN_FILTER_FAILED "Setting CAN Interface \"%s\" message filter failed" #define CAN_RX_SOCKET_QUEUE_OVERFLOW "CAN Interface \"%s\" has lost %d messages" #define CAN_BUSOFF "CAN Interface \"%s\" changed to \"Bus Off\". Switching to Listen Only mode..." #define CAN_NOACK "CAN Interface \"%s\" no \"ACK\" received. Switching to Listen Only mode..." @@ -81,15 +81,21 @@ extern "C" { #define DBG_EMERGENCY_RX "CANopen Emergency message from node 0x%02X: errorCode=0x%04X, errorRegister=0x%02X, errorBit=0x%02X, infoCode=0x%08X" #define DBG_NMT_CHANGE "CANopen NMT state changed to: \"%s\" (%d)" #define DBG_HB_CONS_NMT_CHANGE "CANopen Remote node ID = 0x%02X: NMT state changed to: \"%s\" (%d)" -#define DBG_NOT_TCP_PORT "(%s) -t argument \'%s\' is not a valid tcp port", __func__ +#define DBG_ARGUMENT_UNKNOWN "(%s) Unknown %s argument: \"%s\"", __func__ +#define DBG_NOT_TCP_PORT "(%s) -c argument \"%s\" is not a valid tcp port", __func__ #define DBG_WRONG_NODE_ID "(%s) Wrong node ID \"%d\"", __func__ #define DBG_WRONG_PRIORITY "(%s) Wrong RT priority \"%d\"", __func__ #define DBG_NO_CAN_DEVICE "(%s) Can't find CAN device \"%s\"", __func__ #define DBG_OBJECT_DICTIONARY "(%s) Error in Object Dictionary \"%s\"", __func__ #define DBG_CAN_OPEN "(%s) CANopen error in %s, err=%d", __func__ -#define DBG_CAN_OPEN_INFO "(%s) CANopen device, Node ID = 0x%02X, %s", __func__ -#define DBG_COMMAND_LOCAL_INFO "(%s) Command interface on socket \"%s\" started", __func__ -#define DBG_COMMAND_TCP_INFO "(%s) Command interface on tcp port \"%hu\" started", __func__ +#define DBG_CAN_OPEN_INFO "CANopen device, Node ID = 0x%02X, %s" + +/* CO_Linux_threads */ +#define DBG_COMMAND_LOCAL_BIND "(%s) Can't bind local socket to path \"%s\"", __func__ +#define DBG_COMMAND_TCP_BIND "(%s) Can't bind tcp socket to port \"%d\"", __func__ +#define DBG_COMMAND_STDIO_INFO "CANopen command interface on \"standard IO\" started" +#define DBG_COMMAND_LOCAL_INFO "CANopen command interface on local socket \"%s\" started" +#define DBG_COMMAND_TCP_INFO "CANopen command interface on tcp port \"%d\" started" #ifdef __cplusplus diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 94c92825..310776b5 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -54,8 +54,8 @@ /* Use DS309-3 standard - ASCII command interface to CANopen: NMT master, * LSS master and SDO client */ -#if CO_CONFIG_309 > 0 -#include "CO_command.h" +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#include "309/CO_gateway_ascii.h" #endif /* Interval of mainline and real-time thread in microseconds */ @@ -67,12 +67,6 @@ #endif -#if CO_CONFIG_309 > 0 -/* Mutex is locked, when CAN is not valid (configuration state). May be used - * from command interface. RT threads may use CO->CANmodule[0]->CANnormal instead. */ -pthread_mutex_t CO_CAN_VALID_mtx = PTHREAD_MUTEX_INITIALIZER; -#endif - /* Other variables and objects */ static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ static int CO_ownNodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ @@ -80,9 +74,6 @@ static CO_OD_storage_t odStor; /* Object Dictionary storage obj static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ static char *odStorFile_rom = "od_storage"; /* Name of the file */ static char *odStorFile_eeprom = "od_storage_auto"; /* Name of the file */ -#if CO_CONFIG_309 > 0 -static in_port_t CO_command_socket_tcp_port = 60000; /* default port when used in tcp gateway mode */ -#endif #if CO_NO_TRACE > 0 static CO_time_t CO_time; /* Object for current time */ #endif @@ -152,19 +143,19 @@ printf( " -s Set Filename for OD storage ('od_storage' is default).\n" " -a Set Filename for automatic storage variables from\n" " Object dictionary. ('od_storage_auto' is default).\n"); -#if CO_CONFIG_309 > 0 -printf( -" -c Enable command interface for master functionality. \n" -" If socket path is specified as empty string \"\",\n" -" default '%s' will be used.\n" -" Note that location of socket path may affect security.\n" -" See 'canopencomm/canopencomm --help' for more info.\n" -, CO_command_socketPath); +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII printf( -" -t Enable command interface for master functionality over\n" -" tcp, listen to .\n" -" Note that using this mode may affect security.\n" -); +" -c Enable command interface for master functionality.\n" +" One of three types of interfaces can be specified as:\n" +" 1. \"stdio\" - Standard IO of a program (terminal).\n" +" 2. \"local-\" - Local socket interface on file\n" +" path, for example \"local-/tmp/CO_command_socket\".\n" +" 3. \"tcp-\" - Tcp socket interface on specified \n" +" port, for example \"tcp-60000\".\n" +" Note that this option may affect security of the CAN.\n" +" -T If -c is specified as local or tcp socket, then this\n" +" parameter specifies socket timeout time in milliseconds.\n" +" Default is 0 - no timeout on established connection.\n"); #endif printf( "\n" @@ -188,9 +179,15 @@ int main (int argc, char *argv[]) { char* CANdevice = NULL; /* CAN device, configurable by arguments. */ bool_t nodeIdFromArgs = false; /* True, if program arguments are used for CANopen Node Id */ bool_t rebootEnable = false; /* Configurable by arguments */ -#if CO_CONFIG_309 > 0 - typedef enum CMD_MODE {CMD_NONE, CMD_LOCAL, CMD_REMOTE} cmdMode_t; - cmdMode_t commandEnable = CMD_NONE; /* Configurable by arguments */ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + /* values from CO_commandInterface_t */ + int32_t commandInterface = CO_COMMAND_IF_DISABLED; + /* local socket path if commandInterface == CO_COMMAND_IF_LOCAL_SOCKET */ + char *localSocketPath = NULL; + uint32_t socketTimeout_ms = 0; +#else + #define commandInterface 0 + #define localSocketPath NULL #endif /* configure system log */ @@ -202,37 +199,51 @@ int main (int argc, char *argv[]) { printUsage(argv[0]); exit(EXIT_SUCCESS); } - while((opt = getopt(argc, argv, "i:p:rc:t:s:a:")) != -1) { + while((opt = getopt(argc, argv, "i:p:rc:T:s:a:")) != -1) { + const char comm_stdio[] = "stdio"; + const char comm_local[] = "local-"; + const char comm_tcp[] = "tcp-"; switch (opt) { case 'i': CO_ownNodeId = strtol(optarg, NULL, 0); nodeIdFromArgs = true; break; - case 'p': rtPriority = strtol(optarg, NULL, 0); break; - case 'r': rebootEnable = true; break; -#if CO_CONFIG_309 > 0 + case 'p': rtPriority = strtol(optarg, NULL, 0); + break; + case 'r': rebootEnable = true; + break; +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII case 'c': - /* In case of empty string keep default name, just enable interface. */ - if(strlen(optarg) != 0) { - CO_command_socketPath = optarg; + if (strcmp(optarg, comm_stdio) == 0) { + commandInterface = CO_COMMAND_IF_STDIO; } - commandEnable = CMD_LOCAL; - break; - case 't': - /* In case of empty string keep default port, just enable interface. */ - if(strlen(optarg) != 0) { - //CO_command_socket_tcp_port = optarg; - int scanResult = sscanf(optarg, "%hu", &CO_command_socket_tcp_port); - if(scanResult != 1){ //expect one argument to be extracted - log_printf(LOG_CRIT, DBG_NOT_TCP_PORT, optarg); - exit(EXIT_FAILURE); - } + else if (strncmp(optarg, comm_local, strlen(comm_local)) == 0) { + commandInterface = CO_COMMAND_IF_LOCAL_SOCKET; + localSocketPath = &optarg[6]; + } + else if (strncmp(optarg, comm_tcp, strlen(comm_tcp)) == 0) { + const char *portStr = &optarg[4]; + uint16_t port; + int nMatch = sscanf(portStr, "%hu", &port); + if(nMatch != 1) { + log_printf(LOG_CRIT, DBG_NOT_TCP_PORT, portStr); + exit(EXIT_FAILURE); + } + commandInterface = port; + } + else { + log_printf(LOG_CRIT, DBG_ARGUMENT_UNKNOWN, "-c", optarg); + exit(EXIT_FAILURE); } - commandEnable = CMD_REMOTE; + break; + case 'T': + socketTimeout_ms = strtoul(optarg, NULL, 0); break; #endif - case 's': odStorFile_rom = optarg; break; - case 'a': odStorFile_eeprom = optarg; break; + case 's': odStorFile_rom = optarg; + break; + case 'a': odStorFile_eeprom = optarg; + break; default: printUsage(argv[0]); exit(EXIT_FAILURE); @@ -311,11 +322,6 @@ int main (int argc, char *argv[]) { log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "communication reset"); -#if CO_CONFIG_309 > 0 - /* Wait other threads (command interface). */ - pthread_mutex_lock(&CO_CAN_VALID_mtx); -#endif - /* Wait rt_thread. */ if(!firstRun) { CO_LOCK_OD(); @@ -376,8 +382,8 @@ int main (int argc, char *argv[]) { /* Init threadMainWait structure and file descriptors */ - threadMainWait_initOnce(MAIN_THREAD_INTERVAL_US); - + threadMainWait_initOnce(MAIN_THREAD_INTERVAL_US, commandInterface, + socketTimeout_ms, localSocketPath); /* Init threadRT structure and file descriptors */ CANrx_threadTmr_init(TMR_THREAD_INTERVAL_US); @@ -397,26 +403,6 @@ int main (int argc, char *argv[]) { } } -#if CO_CONFIG_309 > 0 - /* Initialize socket command interface */ - switch(commandEnable) { - case CMD_LOCAL: - if(CO_command_init() != 0) { - CO_errExit("Socket command interface initialization failed"); - } - log_printf(LOG_INFO, DBG_COMMAND_LOCAL_INFO, CO_command_socketPath); - break; - case CMD_REMOTE: - if(CO_command_init_tcp(CO_command_socket_tcp_port) != 0) { - CO_errExit("Socket command interface initialization failed"); - } - log_printf(LOG_INFO, DBG_COMMAND_TCP_INFO, CO_command_socket_tcp_port); - break; - default: - break; - } -#endif - #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ app_programStart(); @@ -433,11 +419,6 @@ int main (int argc, char *argv[]) { /* start CAN */ CO_CANsetNormalMode(CO->CANmodule[0]); -#if CO_CONFIG_309 > 0 - pthread_mutex_unlock(&CO_CAN_VALID_mtx); -#endif - - reset = CO_RESET_NOT; log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "running ..."); @@ -458,22 +439,6 @@ int main (int argc, char *argv[]) { /* program exit ***************************************************************/ /* join threads */ -#if CO_CONFIG_309 > 0 - switch (commandEnable) - { - case CMD_LOCAL: - if (CO_command_clear() != 0) { - CO_errExit("Socket command interface removal failed"); - } - break; - case CMD_REMOTE: - //nothing to do yet - break; - default: - break; - } -#endif - CO_endProgram = 1; if (pthread_join(rt_thread_id, NULL) != 0) { log_printf(LOG_CRIT, DBG_ERRNO, "pthread_join()"); @@ -517,6 +482,7 @@ static void* rt_thread(void* arg) { /* Endless loop */ while(CO_endProgram == 0) { + /* function may skip some milliseconds. Number of missed is returned */ CANrx_threadTmr_process(); #if CO_NO_TRACE > 0 From 3c6a19765055ff6192d485565ec873fdebbc60b9 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 12 May 2020 18:35:23 +0200 Subject: [PATCH 069/520] Update readme --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e7d56c66..3df7cd16 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,9 @@ Characteristics - [Time-stamp](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) protocol producer/consumer. - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) master and - slave, LSS fastscan + slave, LSS fastscan. + - [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/), + CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. ### Other - [Suitable for 16-bit microcontrollers and above](#device-support) @@ -139,11 +141,14 @@ File structure - **CO_SDOserver.h/.c** - CANopen Service Data Object - server protocol. - **CO_SYNC.h/.c** - CANopen Synchronisation protocol (producer and consumer). - **CO_TIME.h/.c** - CANopen Time-stamp protocol. + - **CO_fifo.h/.c** - Fifo buffer for SDO and gateway data transfer. - **crc16-ccitt.h/.c** - Calculation of CRC 16 CCITT polynomial. - **305/** - CANopen layer setting services (LSS) and protocols. - **CO_LSS.h** - CANopen Layer Setting Services protocol (common). - **CO_LSSmaster.h/.c** - CANopen Layer Setting Service - master protocol. - **CO_LSSslave.h/.c** - CANopen Layer Setting Service - slave protocol. + - **309/** - CANopen access from other networks. + - **CO_gateway_ascii.h/.c** - Ascii mapping: NMT master, LSS master, SDO client. - **extra/** - **CO_trace.h/.c** - CANopen trace object for recording variables over time. - **example/** - Directory with basic example, should compile on any system. From d272934647a8a91e720ecba12e097e13d8e17f9f Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 14 May 2020 16:23:02 +0200 Subject: [PATCH 070/520] Fix new -Wextra warnings (#185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix new "unused argument" warnings * Fix "variable may be used uninitialized" in CO_process_SYNC() With enabled optimization compiler reports: CANopen.c: In function ‘CO_process_SYNC’: CANopen.c:890:12: warning: ‘syncWas’ may be used uninitialized in this function [-Wmaybe-uninitialized] 890 | return syncWas; | ^~~~~~~ --- 301/CO_fifo.c | 2 ++ 309/CO_gateway_ascii.c | 1 + CANopen.c | 9 +++------ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 9ad350a7..4ca010f2 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -654,6 +654,8 @@ size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + (void)end; /* unused */ + size_t len = 0; if (fifo != NULL && count > 3) { diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 2fb06f2e..f32c436e 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -211,6 +211,7 @@ static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, } return e; #else + (void)errCode; /* unused */ #define CO_CONFIG_GTW_NET_MIN 0 #define CO_CONFIG_GTW_NET_MAX 0xFFFF gtwa->net = (uint16_t)net; diff --git a/CANopen.c b/CANopen.c index 08569cb3..022c1bee 100644 --- a/CANopen.c +++ b/CANopen.c @@ -866,24 +866,21 @@ bool_t CO_process_SYNC(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { - bool_t syncWas; - CO_SYNC_status_t sync_process; - - sync_process = CO_SYNC_process(co->SYNC, + const CO_SYNC_status_t sync_process = CO_SYNC_process(co->SYNC, timeDifference_us, OD_synchronousWindowLength, timerNext_us); + bool_t syncWas = false; + switch (sync_process) { case CO_SYNC_NONE: - syncWas = false; break; case CO_SYNC_RECEIVED: syncWas = true; break; case CO_SYNC_OUTSIDE_WINDOW: CO_CANclearPendingSyncPDOs(co->CANmodule[0]); - syncWas = false; break; } From 288f8c603fba02c5b4a52a050c6810bf79abafd4 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 14 May 2020 16:24:04 +0200 Subject: [PATCH 071/520] Fix fifo include (#184) * Include CO_fifo.h in CO_SDOclient.h in all cases Struct CO_SDOclient_t has CO_fifo_t member no matter what configuration is set, so the header is always required. Without this change the build fails when CO_CONFIG_SDO_CLI_SEGMENTED is not enabled. * Fix minor copy-paste errors in CO_config.h comments --- 301/CO_SDOclient.h | 2 -- 301/CO_config.h | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index f3f4ad45..2f786bc8 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -32,9 +32,7 @@ #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) || defined CO_DOXYGEN #include "301/CO_SDOserver.h" #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) || defined CO_DOXYGEN #include "301/CO_fifo.h" -#endif #ifdef __cplusplus extern "C" { diff --git a/301/CO_config.h b/301/CO_config.h index 3fbe8602..beb8f281 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -237,8 +237,8 @@ extern "C" { * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_SDOclientDownloadInitiate(), CO_SDOclientDownload(), * CO_SDOclientUploadInitiate(), CO_SDOclientUpload(). - * - CO_CONFIG_SDO_CLI_SEGMENTED - Enable SDO server segmented transfer. - * - CO_CONFIG_SDO_CLI_BLOCK - Enable SDO server block transfer. If set, then + * - CO_CONFIG_SDO_CLI_SEGMENTED - Enable SDO client segmented transfer. + * - CO_CONFIG_SDO_CLI_BLOCK - Enable SDO client block transfer. If set, then * CO_CONFIG_SDO_CLI_SEGMENTED must also be set. * - CO_CONFIG_SDO_CLI_LOCAL - Enable local transfer, if Node-ID of the SDO * server is the same as node-ID of the SDO client. (SDO client is the same From c1a30b8a03e446bdcd796fb6b8cfcbae5429a9a6 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 15 May 2020 15:52:22 +0200 Subject: [PATCH 072/520] Some style corrections - add CO_fifo_st enumerator for use in CO_fifo_cpyTok2xx functions. - 309/CO_gateway_ascii: add x8 to x64 nonstandard data types - example compiles now - Fix "unused argument" warnings in socketCAN --- 301/CO_SDOclient.c | 12 +- 301/CO_fifo.c | 261 +++++++++++++++++++++-------------- 301/CO_fifo.h | 60 +++++--- 309/CO_gateway_ascii.c | 31 +++-- 309/CO_gateway_ascii.h | 5 +- doc/gettingStarted.md | 7 +- example/CO_driver_target.h | 3 +- socketCAN/CO_Linux_threads.c | 5 +- socketCAN/CO_Linux_threads.h | 3 + socketCAN/CO_driver.c | 4 + socketCAN/CO_main_basic.c | 4 +- 11 files changed, 243 insertions(+), 152 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index f1bddb24..6f0fad16 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -26,9 +26,6 @@ #include "301/CO_SDOclient.h" -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK -#include "301/crc16-ccitt.h" -#endif #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) && \ @@ -1225,7 +1222,14 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->timeoutTimer += timeDifference_us; } if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { - abortCode = CO_SDO_AB_TIMEOUT; + if (SDO_C->state == CO_SDO_ST_UPLOAD_SEGMENT_REQ || + SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP + ) { + /* application didn't empty buffer */ + abortCode = CO_SDO_AB_GENERAL; + } else { + abortCode = CO_SDO_AB_TIMEOUT; + } SDO_C->state = CO_SDO_ST_ABORT; } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 4ca010f2..c0b17d3e 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -285,8 +285,7 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { } } -size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count) -{ +size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count) { size_t i; const char *bufSrc; @@ -538,7 +537,7 @@ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); - return sprintf(buf, "0x%02"PRIX8, n); + return sprintf(buf, "%"PRIu8, n); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -550,7 +549,7 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); - return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); + return sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -562,7 +561,7 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); - return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); + return sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -572,6 +571,54 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n; + if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + uint8_t n; + + if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "0x%02"PRIX8, n); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + uint16_t n; + + if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + uint32_t n; + + if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); + } + else { + return CO_fifo_readHex2a(fifo, buf, count, end); + } +} + +size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + uint64_t n; + if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); return sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); @@ -710,232 +757,232 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { /******************************************************************************/ -size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if (sRet != strchr(buf, '\0') || u32 > UINT8_MAX) st |= 20; + if (sRet != strchr(buf, '\0') || u32 > UINT8_MAX) st |= CO_fifo_st_errVal; else { uint8_t num = (uint8_t) u32; nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) *status = st; return nWr; } -size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if (sRet != strchr(buf, '\0') || u32 > UINT16_MAX) st |= 20; + if (sRet != strchr(buf, '\0') || u32 > UINT16_MAX) st |= CO_fifo_st_errVal; else { uint16_t num = CO_SWAP_16((uint16_t) u32); nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) *status = st; return nWr; } -size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) st |= 20; + if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { uint32_t num = CO_SWAP_32(u32); nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) *status = st; return nWr; } -size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[25]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; uint64_t u64 = strtoull(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) st |= 20; + if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { uint64_t num = CO_SWAP_64(u64); nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } if (status != NULL) *status = (uint8_t) st; return nWr; } -size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); if (sRet != strchr(buf, '\0') || i32 < INT8_MIN || i32 > INT8_MAX) { - st |= 20; + st |= CO_fifo_st_errVal; } else { int8_t num = (int8_t) i32; nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) *status = st; return nWr; } -size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); if (sRet != strchr(buf, '\0') || i32 < INT16_MIN || i32 > INT16_MAX) { - st |= 20; + st |= CO_fifo_st_errVal; } else { int16_t num = CO_SWAP_16((int16_t) i32); nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) *status = st; return nWr; } -size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) st |= 20; + if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { int32_t num = CO_SWAP_32(i32); nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) *status = st; return nWr; } -size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[25]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; int64_t i64 = strtoll(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) st |= 20; + if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { int64_t num = CO_SWAP_64(i64); nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } if (status != NULL) *status = (uint8_t) st; return nWr; } -size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[30]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; float32_t f32 = strtof(buf, &sRet); - if (sRet != strchr(buf, '\0')) st |= 20; + if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { float32_t num = CO_SWAP_32(f32); nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) *status = st; return nWr; } -size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[40]; - char st = -1; + char closed = -1; bool_t err = 0; size_t nWr = 0; - - size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &st, &err); - if (nRd == 0 || err) st |= 0x10; + size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); + CO_fifo_st st = (uint8_t)closed; + if (nRd == 0 || err) st |= CO_fifo_st_errTok; else { char *sRet; float64_t f64 = strtof(buf, &sRet); - if (sRet != strchr(buf, '\0')) st |= 20; + if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { float64_t num = CO_SWAP_64(f64); nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= 0x40; + if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) *status = st; return nWr; } -size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t destSpace, destSpaceStart; bool_t finished = false; - uint8_t st = 0; + CO_fifo_st st = 0; if (dest == NULL || src == NULL) { return 0; @@ -946,7 +993,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { /* repeat until destination space available and no error and not finished * and source characters available */ - while (destSpace > 0 && (st & 0xF0) == 0 && !finished) { + while (destSpace > 0 && (st & CO_fifo_st_errMask) == 0 && !finished) { char c; if (!CO_fifo_getc(src, &c)) { break; @@ -961,14 +1008,14 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } else if (c == DELIM_COMMAND) { /* newline found, finish */ - st |= 0x01; + st |= CO_fifo_st_closed; finished = true; } else if (c == DELIM_COMMENT) { /* comment found, clear line and finish */ while (CO_fifo_getc(src, &c)) { if (c == DELIM_COMMAND) { - st |= 0x01; + st |= CO_fifo_st_closed; break; } } @@ -976,7 +1023,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } else if (isgraph(c) != 0) { /* printable character, not hex digit, error */ - st |= 0x10; + st |= CO_fifo_st_errTok; } /* else just skip empty space */ } @@ -994,7 +1041,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } else if (isgraph(c) != 0 && c != DELIM_COMMENT) { /* printable character, not hex digit, error */ - st |= 0x10; + st |= CO_fifo_st_errTok; } else { /* this is space or comment, single hex digit is known */ @@ -1007,14 +1054,14 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { destSpace--; if (c == DELIM_COMMAND) { /* newline found, finish */ - st |= 0x01; + st |= CO_fifo_st_closed; finished = true; } else if (c == DELIM_COMMENT) { /* comment found, clear line and finish */ while (CO_fifo_getc(src, &c)) { if (c == DELIM_COMMAND) { - st |= 0x01; + st |= CO_fifo_st_closed; break; } } @@ -1026,7 +1073,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } if (!finished) { - st |= 0x02; + st |= CO_fifo_st_partial; } if (status != NULL) *status = st; @@ -1034,10 +1081,10 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return destSpaceStart - destSpace; } -size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t destSpace, destSpaceStart; bool_t finished = false; - uint8_t st = 0; + CO_fifo_st st = 0; if (dest == NULL || src == NULL) { return 0; @@ -1055,7 +1102,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { /* repeat until destination space available and no error and not finished * and source characters available */ - while (destSpace > 0 && (st & 0xF0) == 0 && !finished) { + while (destSpace > 0 && (st & CO_fifo_st_errMask) == 0 && !finished) { char c; if (!CO_fifo_getc(src, &c)) { break; @@ -1066,7 +1113,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { if (isgraph(c) == 0 || c == DELIM_COMMENT) { if (CO_fifo_trimSpaces(src)) { /* newline found without string, this is an error */ - st |= 0x10; + st |= CO_fifo_st_errTok; } } else if (c == '"') { @@ -1092,16 +1139,16 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else if (isgraph(c) == 0 && dest->aux == 2) { /* end of single word string */ if (c == DELIM_COMMAND) { - st |= 0x01; + st |= CO_fifo_st_closed; } else if (CO_fifo_trimSpaces(src)) { - st |= 0x01; + st |= CO_fifo_st_closed; } finished = true; } else if (c == DELIM_COMMAND) { /* no closing quote, error */ - st |= 0x10; + st |= CO_fifo_st_errTok; } else { /* copy the character */ @@ -1122,35 +1169,35 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { /* previous character was closing double quote */ if (dest->aux == 4) { /* no opening double quote, syntax error */ - st |= 0x10; + st |= CO_fifo_st_errTok; } else { if (isgraph(c) == 0) { /* string finished */ if (c == DELIM_COMMAND) { - st |= 0x01; + st |= CO_fifo_st_closed; } else if (CO_fifo_trimSpaces(src)) { - st |= 0x01; + st |= CO_fifo_st_closed; } finished = true; } else { /* space must follow closing double quote, error */ - st |= 0x10; + st |= CO_fifo_st_errTok; } } } break; - default: /* error */ - st |= 0x80; + default: /* internal error */ + st |= CO_fifo_st_errInt; break; } } if (!finished) { - st |= 0x02; + st |= CO_fifo_st_partial; } if (status != NULL) *status = st; diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 9f062bee..0a75a52a 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -401,6 +401,14 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); /** Read uint64_t variable from fifo as ascii string, see CO_fifo_readU82a */ size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read uint8_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readX82a (CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read uint16_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read uint32_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read uint64_t variable from fifo as ascii string, see CO_fifo_readU82a */ +size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); /** Read int8_t variable from fifo as ascii string, see CO_fifo_readU82a */ size_t CO_fifo_readI82a (CO_fifo_t *fifo, char *buf, size_t count, bool_t end); /** Read int16_t variable from fifo as ascii string, see CO_fifo_readU82a */ @@ -423,48 +431,60 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar */ +typedef enum { + /** Bit is set, if command delimiter is reached in src */ + CO_fifo_st_closed = 0x01U, + /** Bit is set, if copy was partial and more data are available. If unset + * and no error, then all data was successfully copied. */ + CO_fifo_st_partial = 0x02U, + /** Bit is set, if no valid token found */ + CO_fifo_st_errTok = 0x10U, + /** Bit is set, if value is not valid or out of limits */ + CO_fifo_st_errVal = 0x20U, + /** Bit is set, if destination buffer is to small */ + CO_fifo_st_errBuf = 0x40U, + /** Bit is set, if internal error */ + CO_fifo_st_errInt = 0x80U, + /** Bitmask for error bits */ + CO_fifo_st_errMask = 0xF0U +} CO_fifo_st; + /** * Read ascii string from src fifo and copy as uint8_t variable to dest fifo. * * @param dest destination fifo buffer object. * @param src source fifo buffer object. - * @param [out] status bitfield with the following bits: - * - bit0: if 1, command delimiter is reached in src - * - bit1: if 1, copy was partial, more data are available. If 0 and no error - * bit is set, then all data was successfully copied. - * - bit4: if 1, error: no valid token found - * - bit5: if 1, error: value is not valid or out of limits - * - bit6: if 1, error: destination buffer to small - * - bit7: if 1, error: internal + * @param [out] status bitfield of the CO_fifo_st type. * * @return Number of bytes written into dest. */ -size_t CO_fifo_cpyTok2U8 (CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2U8 (CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to uint16_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to uint32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to uint64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to int8_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I8 (CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2I8 (CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to int16_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to int32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to int64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to float32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy ascii string to float64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy bytes written as two hex digits into to data. Bytes may be space * separated. See CO_fifo_cpyTok2U8 for parameters. */ -size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy visible string to data. A visible string must be enclosed with double * quotes, if it contains space. If a double quote is used within the string, * the quotes are escaped by a second quotes. See CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); #endif /* CO_CONFIG_FIFO_ASCII_COMMANDS > 0 */ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index f32c436e..0c094bb5 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -108,8 +108,9 @@ static const char *CO_GTWA_helpString = "\n" \ "Datatypes:\n" \ "b # Boolean.\n" \ -"u8, u16, u32, u64 # Unsigned integers.\n" \ "i8, i16, i32, i64 # Signed integers.\n" \ +"u8, u16, u32, u64 # Unsigned integers.\n" \ +"x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard.\n" \ "r32, r64 # Real numbers.\n" \ "t, td # Time of day, time difference.\n" \ "vs # Visible string (between double quotes if multi-word).\n" \ @@ -223,14 +224,18 @@ static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, static const CO_GTWA_dataType_t dataTypes[] = { {"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */ {"b", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* BOOLEAN */ - {"u8", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ - {"u16", 2, CO_fifo_readU162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ - {"u32", 4, CO_fifo_readU322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ - {"u64", 8, CO_fifo_readU642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ {"i8", 1, CO_fifo_readI82a, CO_fifo_cpyTok2I8}, /* INTEGER8 */ {"i16", 2, CO_fifo_readI162a, CO_fifo_cpyTok2I16}, /* INTEGER16 */ {"i32", 4, CO_fifo_readI322a, CO_fifo_cpyTok2I32}, /* INTEGER32 */ {"i64", 8, CO_fifo_readI642a, CO_fifo_cpyTok2I64}, /* INTEGER64 */ + {"u8", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ + {"u16", 2, CO_fifo_readU162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ + {"u32", 4, CO_fifo_readU322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ + {"u64", 8, CO_fifo_readU642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ + {"x8", 1, CO_fifo_readX82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ + {"x16", 2, CO_fifo_readX162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ + {"x32", 4, CO_fifo_readX322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ + {"x64", 8, CO_fifo_readX642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ {"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */ {"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */ // {"t", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* TIME_OF_DAY */ @@ -626,7 +631,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(token, "w") == 0 || strcmp(token, "write") == 0) { uint16_t idx; uint8_t subidx; - uint8_t status; + CO_fifo_st status; CO_SDOclient_return_t SDO_ret; size_t size; bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); @@ -681,13 +686,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, >wa->commFifo, &status); /* set to true, if command delimiter was found */ - closed = (status & 0x01) == 1; + closed = ((status & CO_fifo_st_closed) == 0) ? 0 : 1; /* set to true, if data are copied only partially */ - gtwa->SDOdataCopyStatus = (status & 0x02) != 0; + gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0; /* is syntax error in command or size is zero or not the last token * in command */ - if ((status & 0xF0) != 0 || size == 0 + if ((status & CO_fifo_st_errMask) != 0 || size == 0 || (gtwa->SDOdataCopyStatus == false && closed != 1) ) { err = true; @@ -1009,17 +1014,17 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* copy data to the SDO buffer if more data available */ if (gtwa->SDOdataCopyStatus) { - uint8_t status; + CO_fifo_st status; gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, >wa->commFifo, &status); /* set to true, if command delimiter was found */ - closed = (status & 0x01) == 1; + closed = ((status & CO_fifo_st_closed) == 0) ? 0 : 1; /* set to true, if data are copied only partially */ - gtwa->SDOdataCopyStatus = (status & 0x02) != 0; + gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0; /* is syntax error in command or not the last token in command */ - if ((status & 0xF0) != 0 + if ((status & CO_fifo_st_errMask) != 0 || (gtwa->SDOdataCopyStatus == false && closed != 1) ) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 6649048e..6ef5bdb1 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -84,8 +84,9 @@ help # Print this help. Datatypes: b # Boolean. -u8, u16, u32, u64 # Unsigned integers. i8, i16, i32, i64 # Signed integers. +u8, u16, u32, u64 # Unsigned integers. +x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard. r32, r64 # Real numbers. t, td # Time of day, time difference. vs # Visible string (between double quotes if multi-word). @@ -230,7 +231,7 @@ typedef struct { * description of parameters see #CO_fifo_cpyTok2U8 */ size_t (*dataTypeScan)(CO_fifo_t *dest, CO_fifo_t *src, - uint8_t *status); + CO_fifo_st *status); } CO_GTWA_dataType_t; diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index 608899d2..7f4bd79b 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -18,6 +18,9 @@ CANopenNode on Linux CANopenNode should run on any Linux machine. Examples below was tested on Debian based machines, including Ubuntu and Raspberry PI. It is possible to run tests described below without real CAN interface, because Linux kernel already contains virtual CAN interface. All necessary Linux specific files are included in socketCAN directory of CANopenNode and Makefile is included in base directory. +Windows or Mac users, who don't have Linux installed, can use [VirtualBox](https://www.virtualbox.org/) and install [Ubuntu](https://ubuntu.com/download/desktop) or similar. + + ### Preparation We will use Linux command line interface (Terminal) for all examples below. Open the terminal and cd to your working directory. First install supporting packages: [can-utils](https://github.com/linux-can/can-utils), which is very useful tool for working with CAN interface and [git](https://git-scm.com/), which is recommended for working with repositories. @@ -90,9 +93,9 @@ Second instance of _canopend_ was started with command interface enabled. This i help #### SDO client -For example read Heartbeat producer parameter on CANopen device with ID=4. Parameter is located at index 0x1017, subindex 0, it is 16-bit integer. (It is basically unsigned 16 bit integer (u16), but i16 give us more readable output in our case.) +For example read Heartbeat producer parameter on CANopen device with ID=4. Parameter is located at index 0x1017, subindex 0, it is 16-bit unsigned integer. - [1] 4 read 0x1017 0 i16 + [1] 4 read 0x1017 0 u16 You should see the response, which says that Heartbeats are transmitted in 1000 ms intervals: diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 410e210f..e700ace7 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -111,8 +111,7 @@ extern "C" { #endif #ifndef CO_CONFIG_GTW -#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | \ - CO_CONFIG_GTW_ASCII | \ +#define CO_CONFIG_GTW (CO_CONFIG_GTW_ASCII | \ CO_CONFIG_GTW_ASCII_ERROR_DESC | \ CO_CONFIG_GTW_ASCII_PRINT_HELP) #define CO_CONFIG_GTW_BLOCK_DL_LOOP 1 diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index d6a5df94..23458bcb 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -40,6 +40,7 @@ #include #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII #include +#include #include #include #include @@ -103,6 +104,7 @@ static struct { static void threadMainWait_callback(void *object) { + (void)object; /* send event to wake threadMainWait_process() */ uint64_t u = 1; ssize_t s; @@ -412,7 +414,8 @@ uint32_t threadMainWait_process(CO_NMT_reset_cmd_t *reset) bool_t closed = (buf[s-1] == '\n'); /* is command closed? */ if (buf[0] != '[' && (space - s) >= strlen(sequence) - && s > 1 && closed && tmw.freshCommand + && isgraph(buf[0]) && buf[0] != '#' + && closed && tmw.freshCommand ) { CO_GTWA_write(CO->gtwa, sequence, strlen(sequence)); } diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index e5a3e057..78b01294 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -66,6 +66,9 @@ typedef enum { * * The "threads" specified here do not fork threads themselves, but require * that two threads are provided by the calling application. + * + * Main references for Linux functions used here are Linux man pages and the + * book: The Linux Programming Interface by Michael Kerrisk. */ diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 662f6288..72fbd281 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -174,6 +174,7 @@ static CO_ReturnError_t setRxFilters(CO_CANmodule_t *CANmodule) /******************************************************************************/ void CO_CANsetConfigurationMode(void *CANptr) { + (void)CANptr; /* Can't do anything because no reference to CANmodule_t is provided */ } @@ -208,6 +209,7 @@ CO_ReturnError_t CO_CANmodule_init( int32_t ret; uint16_t i; struct epoll_event ev; + (void)CANbitRate; /* verify arguments */ if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ @@ -749,6 +751,7 @@ CO_ReturnError_t CO_CANCheckSend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) /******************************************************************************/ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) { + (void)CANmodule; /* Messages are either written to the socket queue or dropped */ } @@ -756,6 +759,7 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) /******************************************************************************/ void CO_CANverifyErrors(CO_CANmodule_t *CANmodule) { + (void)CANmodule; /* socketCAN doesn't support microcontroller-like error counters. If an * error has occured, a special can message is created by the driver and * received by the application like a regular message. diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 310776b5..7802000c 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -85,6 +85,7 @@ static void* rt_thread(void* arg); /* Signal handler */ volatile sig_atomic_t CO_endProgram = 0; static void sigHandler(int sig) { + (void)sig; CO_endProgram = 1; } @@ -124,6 +125,7 @@ static void HeartbeatNmtChangedCallback(uint8_t nodeId, CO_NMT_internalState_t state, void *object) { + (void)object; log_printf(LOG_NOTICE, DBG_HB_CONS_NMT_CHANGE, nodeId, NmtState2Str(state), state); } @@ -478,7 +480,7 @@ int main (int argc, char *argv[]) { * Realtime thread for CAN receive and threadTmr ******************************************************************************/ static void* rt_thread(void* arg) { - + (void)arg; /* Endless loop */ while(CO_endProgram == 0) { From 6c16680d021454fb0f668d17b166fffc1118b1e3 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Wed, 27 May 2020 13:42:50 +0200 Subject: [PATCH 073/520] Use memcpy() and memset() where possible (#188) * LLSMaster: replace explicit array element copy with memcpy() Replace explicit array element copy with memcpy() Signed-off-by: Paolo Teti * SDO server: copy and zeroize arrays using memcpy() and memset() * Replace array elements copy with memcpy(). * Clear response buffer using memset() Signed-off-by: Paolo Teti --- 301/CO_SDOserver.c | 13 ++----------- 305/CO_LSSmaster.c | 9 +-------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index ac339685..11683328 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -71,15 +71,7 @@ static void CO_SDO_receive(void *object, void *msg){ if((DLC == 8U) && (!CO_FLAG_READ(SDO->CANrxNew))){ if(SDO->state != CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) { /* copy data and set 'new message' flag */ - SDO->CANrxData[0] = data[0]; - SDO->CANrxData[1] = data[1]; - SDO->CANrxData[2] = data[2]; - SDO->CANrxData[3] = data[3]; - SDO->CANrxData[4] = data[4]; - SDO->CANrxData[5] = data[5]; - SDO->CANrxData[6] = data[6]; - SDO->CANrxData[7] = data[7]; - + memcpy(SDO->CANrxData, data, DLC); CO_FLAG_SET(SDO->CANrxNew); } else { @@ -704,8 +696,7 @@ int8_t CO_SDO_process( } /* clear response buffer */ - SDO->CANtxBuff->data[0] = SDO->CANtxBuff->data[1] = SDO->CANtxBuff->data[2] = SDO->CANtxBuff->data[3] = 0; - SDO->CANtxBuff->data[4] = SDO->CANtxBuff->data[5] = SDO->CANtxBuff->data[6] = SDO->CANtxBuff->data[7] = 0; + memset(SDO->CANtxBuff->data, 0, sizeof(SDO->CANtxBuff->data)); /* Is abort from client? */ if((CO_FLAG_READ(SDO->CANrxNew)) && (SDO->CANrxData[0] == CCS_ABORT)){ diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 2a94b8f5..e026b0f9 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -87,14 +87,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING){ /* copy data and set 'new message' flag */ - LSSmaster->CANrxData[0] = data[0]; - LSSmaster->CANrxData[1] = data[1]; - LSSmaster->CANrxData[2] = data[2]; - LSSmaster->CANrxData[3] = data[3]; - LSSmaster->CANrxData[4] = data[4]; - LSSmaster->CANrxData[5] = data[5]; - LSSmaster->CANrxData[6] = data[6]; - LSSmaster->CANrxData[7] = data[7]; + memcpy(LSSmaster->CANrxData, data, sizeof(LSSmaster->CANrxData)); CO_FLAG_SET(LSSmaster->CANrxNew); From 6db813a9982394fe65ef0846e52d04e0540bac88 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Wed, 27 May 2020 13:48:16 +0200 Subject: [PATCH 074/520] TIME: fix round up conversion from usec to msec (#189) Use standard idiom for integer rounding up. Signed-off-by: Paolo Teti --- 301/CO_TIME.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 026f1771..42ce457c 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -31,6 +31,8 @@ #include "301/CO_NMT_Heartbeat.h" #include "301/CO_TIME.h" +#define DIV_ROUND_UP(_n, _d) (((_n) + (_d) - 1) / (_d)) + /* * Read received message from CAN module. * @@ -166,7 +168,7 @@ uint8_t CO_TIME_process( if(*TIME->operatingState == CO_NMT_OPERATIONAL || *TIME->operatingState == CO_NMT_PRE_OPERATIONAL){ /* update TIME timer, no overflow */ - uint32_t timeDifference_ms = (timeDifference_us+500) / 1000; //this should be optimized + uint32_t timeDifference_ms = DIV_ROUND_UP(timeDifference_us, 1000); timerNew = TIME->timer + timeDifference_ms; if(timerNew > TIME->timer) TIME->timer = timerNew; From ecce574965aa534509b086c68f8b695eb0147c3f Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 28 May 2020 09:38:30 +0200 Subject: [PATCH 075/520] =?UTF-8?q?fix=20according=20to=20standard:=20-=20?= =?UTF-8?q?There=20is=20no=20white=20space=20between=20the=20=E2=80=9CERRO?= =?UTF-8?q?R:=E2=80=9D=20string=20and=20the=20=20value.=20-=20?= =?UTF-8?q?non-case-sensitive=20ASCII=20strings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 309/CO_gateway_ascii.c | 31 ++++++++++++++++++++++++++----- 309/CO_gateway_ascii.h | 4 ++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 0c094bb5..ad894f5a 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -120,7 +120,7 @@ static const char *CO_GTWA_helpString = "\n" \ "Response:\n" \ "\"[\"\"]\" OK | |\n" \ -" ERROR: | ERROR: \n" \ +" ERROR: | ERROR:\n" \ "\n" \ "Every command must be terminated with ('\\r\\n'). characters. Same is\n" \ "response. String is not null terminated, is optional in command.\n" \ @@ -382,7 +382,7 @@ static void responseWithError(CO_GTWA_t *gtwa, } } - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR: %d #%s\r\n", + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR:%d #%s\r\n", gtwa->sequence, respErrorCode, desc); respBufTransfer(gtwa); } @@ -401,7 +401,7 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, } } - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR: 0x%08X #%s\r\n", + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR:0x%08X #%s\r\n", gtwa->sequence, abortCode, desc); respBufTransfer(gtwa); } @@ -410,7 +410,7 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, static inline void responseWithError(CO_GTWA_t *gtwa, CO_GTWA_respErrorCode_t respErrorCode) { - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR: %d\r\n", + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR:%d\r\n", gtwa->sequence, respErrorCode); respBufTransfer(gtwa); } @@ -418,7 +418,7 @@ static inline void responseWithError(CO_GTWA_t *gtwa, static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, CO_SDO_abortCode_t abortCode) { - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR: 0x%08X\r\n", + gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR:0x%08X\r\n", gtwa->sequence, abortCode); respBufTransfer(gtwa); } @@ -431,6 +431,21 @@ static inline void responseWithOK(CO_GTWA_t *gtwa) { } +static inline void convertToLower(char *token, size_t maxCount) { + size_t i; + char *c = &token[0]; + + for (i = 0; i < maxCount; i++) { + if (*c == 0) { + break; + } else { + *c = tolower(*c); + } + c++; + } +} + + /******************************************************************************* * PROCESS FUNCTION ******************************************************************************/ @@ -562,6 +577,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } if (err) break; + /* command is case insensitive */ + convertToLower(token, sizeof(token)); /* Upload SDO command - 'r[ead] ' */ if (strcmp(token, "r") == 0 || strcmp(token, "read") == 0) { @@ -596,6 +613,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1; CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + convertToLower(token, sizeof(token)); gtwa->SDOdataType = CO_GTWA_getDataType(token, &err); if (err) break; } @@ -658,6 +676,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 0; CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + convertToLower(token, sizeof(token)); gtwa->SDOdataType = CO_GTWA_getDataType(token, &err); if (err) break; @@ -793,6 +812,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); if (err) break; + convertToLower(token, sizeof(token)); if (strcmp(token, "node") == 0) { command2 = CO_NMT_RESET_NODE; } else if (strcmp(token, "comm") == 0 || @@ -828,6 +848,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); if (err) break; + convertToLower(token, sizeof(token)); if (strcmp(token, "network") == 0) { uint16_t value; diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 6ef5bdb1..7fea0252 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -42,7 +42,7 @@ extern "C" { * @ingroup CO_CANopen_309 * @{ * - * CANopen access from other networks - ASCII mapping (CiA 309-3 DS v2.1.0) + * CANopen access from other networks - ASCII mapping (CiA 309-3 DSP v3.0.0) * * This module enables ascii command interface (CAN gateway), which can be used * for master interaction with CANopen network. Some sort of string input/output @@ -96,7 +96,7 @@ hex # Hexagonal data, optionally space separated, non-standard. Response: "[""]" OK | | - ERROR: | ERROR: + ERROR: | ERROR: Every command must be terminated with ('\\r\\n'). characters. Same is response. String is not null terminated, is optional in command. From f41069561a44e5543479376d4c076ac7d9faf0fe Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 28 May 2020 16:40:21 +0200 Subject: [PATCH 076/520] Make SDO client and NMT master optional in gateway_ascii --- 301/CO_config.h | 20 ++- 301/CO_fifo.c | 4 +- 301/CO_fifo.h | 31 +++-- 309/CO_gateway_ascii.c | 227 +++++++++++++++++++---------------- 309/CO_gateway_ascii.h | 18 ++- CANopen.c | 4 +- example/CO_driver_target.h | 4 + socketCAN/CO_driver_target.h | 4 + 8 files changed, 187 insertions(+), 125 deletions(-) diff --git a/301/CO_config.h b/301/CO_config.h index beb8f281..db54ebda 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -70,7 +70,7 @@ extern "C" { * * This flag is common to multiple configuration macros. */ -#define CO_CONFIG_FLAG_CALLBACK_PRE 0x0100 +#define CO_CONFIG_FLAG_CALLBACK_PRE 0x1000 /** @@ -81,7 +81,7 @@ extern "C" { * * This flag is common to multiple configuration macros. */ -#define CO_CONFIG_FLAG_TIMERNEXT 0x0200 +#define CO_CONFIG_FLAG_TIMERNEXT 0x2000 /** @@ -304,16 +304,26 @@ extern "C" { * - CO_CONFIG_GTW_MULTI_NET - Enable multiple network interfaces in gateway * device. This functionality is currently not implemented. * - CO_CONFIG_GTW_ASCII - Enable gateway device with ASCII mapping (CiA 309-3) + * - CO_CONFIG_GTW_ASCII_SDO - Enable SDO client + * - CO_CONFIG_GTW_ASCII_NMT - Enable NMT master + * - CO_CONFIG_GTW_ASCII_LSS - Enable LSS master + * - CO_CONFIG_GTW_ASCII_LOG - Enable non-standard message log read * - CO_CONFIG_GTW_ASCII_ERROR_DESC - Print error description as additional * comments in gateway-ascii device for SDO and gateway errors. + * - CO_CONFIG_GTW_ASCII_PRINT_HELP - use non-standard command "help" to print + * help usage. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | CO_CONFIG_GTW_ASCII | CO_CONFIG_GTW_ASCII_ERROR_DESC | CO_CONFIG_GTW_ASCII_PRINT_HELP) +#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | CO_CONFIG_GTW_ASCII | CO_CONFIG_GTW_ASCII_SDO | CO_CONFIG_GTW_ASCII_NMT | CO_CONFIG_GTW_ASCII_LSS | CO_CONFIG_GTW_ASCII_LOG | CO_CONFIG_GTW_ASCII_ERROR_DESC | CO_CONFIG_GTW_ASCII_PRINT_HELP) #endif #define CO_CONFIG_GTW_MULTI_NET 0x01 #define CO_CONFIG_GTW_ASCII 0x02 -#define CO_CONFIG_GTW_ASCII_ERROR_DESC 0x04 -#define CO_CONFIG_GTW_ASCII_PRINT_HELP 0x08 +#define CO_CONFIG_GTW_ASCII_SDO 0x04 +#define CO_CONFIG_GTW_ASCII_NMT 0x08 +#define CO_CONFIG_GTW_ASCII_LSS 0x10 +#define CO_CONFIG_GTW_ASCII_LOG 0x20 +#define CO_CONFIG_GTW_ASCII_ERROR_DESC 0x40 +#define CO_CONFIG_GTW_ASCII_PRINT_HELP 0x80 /** diff --git a/301/CO_fifo.c b/301/CO_fifo.c index c0b17d3e..33c04805 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -529,8 +529,10 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, return tokenSize; } +#endif /* #if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 */ +#if CO_CONFIG_FIFO_ASCII_DATATYPES == 1 /******************************************************************************/ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n; @@ -1205,4 +1207,4 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return destSpaceStart - destSpace; } -#endif /* CO_CONFIG_FIFO_ASCII_COMMANDS == 1 */ +#endif /* CO_CONFIG_FIFO_ASCII_DATATYPES == 1 */ diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 0a75a52a..e7115626 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -32,18 +32,23 @@ #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK -#ifndef CO_CONFIG_FIFO_ALT_READ -#define CO_CONFIG_FIFO_ALT_READ 1 -#endif -#ifndef CO_CONFIG_FIFO_CRC16_CCITT -#define CO_CONFIG_FIFO_CRC16_CCITT 1 -#endif + #ifndef CO_CONFIG_FIFO_ALT_READ + #define CO_CONFIG_FIFO_ALT_READ 1 + #endif + #ifndef CO_CONFIG_FIFO_CRC16_CCITT + #define CO_CONFIG_FIFO_CRC16_CCITT 1 + #endif #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -#ifndef CO_CONFIG_FIFO_ASCII_COMMANDS -#define CO_CONFIG_FIFO_ASCII_COMMANDS 1 -#endif + #ifndef CO_CONFIG_FIFO_ASCII_COMMANDS + #define CO_CONFIG_FIFO_ASCII_COMMANDS 1 + #endif + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO + #ifndef CO_CONFIG_FIFO_ASCII_DATATYPES + #define CO_CONFIG_FIFO_ASCII_DATATYPES 1 + #endif + #endif #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ @@ -82,7 +87,7 @@ typedef struct { /** Location in the buffer, which will be next read. */ size_t altReadPtr; #endif -#if CO_CONFIG_FIFO_ASCII_COMMANDS > 0 || defined CO_DOXYGEN +#if CO_CONFIG_FIFO_ASCII_DATATYPES > 0 || defined CO_DOXYGEN /** helper variable, set to false in CO_fifo_reset(), used in some * functions. */ bool_t started; @@ -113,7 +118,7 @@ static inline void CO_fifo_reset(CO_fifo_t *fifo) { if (fifo != NULL) { fifo->readPtr = 0; fifo->writePtr = 0; -#if CO_CONFIG_FIFO_ASCII_COMMANDS > 0 +#if CO_CONFIG_FIFO_ASCII_DATATYPES > 0 fifo->started = false; #endif } @@ -382,8 +387,10 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, size_t count, char *closed, bool_t *err); +#endif /* CO_CONFIG_FIFO_ASCII_COMMANDS > 0 */ +#if CO_CONFIG_FIFO_ASCII_DATATYPES > 0 || defined CO_DOXYGEN /** * Read uint8_t variable from fifo and output as ascii string. * @@ -486,7 +493,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); * the quotes are escaped by a second quotes. See CO_fifo_cpyTok2U8 */ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); -#endif /* CO_CONFIG_FIFO_ASCII_COMMANDS > 0 */ +#endif /* CO_CONFIG_FIFO_ASCII_DATATYPES > 0 */ #ifdef __cplusplus } diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index ad894f5a..ccf63746 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -33,15 +33,19 @@ /******************************************************************************/ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, - CO_SDOclient_t* SDO_C, + void* SDO_C, uint16_t SDOtimeoutTimeDefault, bool_t SDOblockTransferEnableDefault, - CO_NMT_t *NMT) + void *NMT) { /* verify arguments */ if (gtwa == NULL +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO || SDO_C == NULL || SDOtimeoutTimeDefault == 0 +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT || NMT == NULL +#endif ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -49,10 +53,14 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, /* initialize variables */ gtwa->readCallback = NULL; gtwa->readCallbackObject = NULL; - gtwa->SDO_C = SDO_C; +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO + gtwa->SDO_C = (CO_SDOclient_t *)SDO_C; gtwa->SDOtimeoutTime = SDOtimeoutTimeDefault; gtwa->SDOblockTransferEnable = SDOblockTransferEnableDefault; - gtwa->NMT = NMT; +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT + gtwa->NMT = (CO_NMT_t *)NMT; +#endif gtwa->net_default = -1; gtwa->node_default = -1; gtwa->state = CO_GTWA_ST_IDLE; @@ -220,6 +228,8 @@ static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, #endif } + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO /* data types for SDO read or write */ static const CO_GTWA_dataType_t dataTypes[] = { {"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */ @@ -264,6 +274,7 @@ static const CO_GTWA_dataType_t *CO_GTWA_getDataType(char *token, bool_t *err) { *err = true; return NULL; } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ /* transfer response buffer and verify if all bytes was read */ @@ -332,6 +343,7 @@ static const errorDescs_t errorDescs[] = { {505, "LSS command failed because of media error."}, {600, "Running out of memory."} }; +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO static const errorDescs_t errorDescsSDO[] = { {0x00000000, "No abort."}, {0x05030000, "Toggle bit not altered."}, @@ -366,6 +378,7 @@ static const errorDescs_t errorDescsSDO[] = { {0x08000023, "Object dictionary not present or dynamic generation fails."}, {0x08000024, "No data available."} }; +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #endif /* CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS */ static void responseWithError(CO_GTWA_t *gtwa, @@ -387,6 +400,7 @@ static void responseWithError(CO_GTWA_t *gtwa, respBufTransfer(gtwa); } +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO static void responseWithErrorSDO(CO_GTWA_t *gtwa, CO_SDO_abortCode_t abortCode) { @@ -405,6 +419,7 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, gtwa->sequence, abortCode, desc); respBufTransfer(gtwa); } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #else /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */ static inline void responseWithError(CO_GTWA_t *gtwa, @@ -415,6 +430,7 @@ static inline void responseWithError(CO_GTWA_t *gtwa, respBufTransfer(gtwa); } +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, CO_SDO_abortCode_t abortCode) { @@ -422,6 +438,7 @@ static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, gtwa->sequence, abortCode); respBufTransfer(gtwa); } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */ @@ -580,8 +597,107 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* command is case insensitive */ convertToLower(token, sizeof(token)); + /* set command - multiple sub commands */ + if (strcmp(token, "set") == 0) { + if (closed != 0) { + err = true; + break; + } + + /* command 2 */ + closed = -1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + if (err) break; + + convertToLower(token, sizeof(token)); + if (strcmp(token, "network") == 0) { + uint16_t value; + + if (closed != 0) { + err = true; + break; + } + + /* value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + value = (uint16_t)getU32(token, CO_CONFIG_GTW_NET_MIN, + CO_CONFIG_GTW_NET_MAX, &err); + if (err) break; + + gtwa->net_default = value; + responseWithOK(gtwa); + } + else if (strcmp(token, "node") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint8_t value; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + value = (uint8_t)getU32(token, 1, 127, &err); + if (err) break; + + gtwa->node_default = value; + responseWithOK(gtwa); + } +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO + else if (strcmp(token, "sdo_timeout") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint16_t value; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + value = (uint16_t)getU32(token, 1, 0xFFFF, &err); + if (err) break; + + gtwa->SDOtimeoutTime = value; + responseWithOK(gtwa); + } + else if (strcmp(token, "sdo_block") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint16_t value; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, token, tokenSize, + &closed, &err); + value = (uint16_t)getU32(token, 0, 1, &err); + if (err) break; + + gtwa->SDOblockTransferEnable = value==1 ? true : false; + responseWithOK(gtwa); + } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ + else { + respErrorCode = CO_GTWA_respErrorReqNotSupported; + err = true; + break; + } + } + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO /* Upload SDO command - 'r[ead] ' */ - if (strcmp(token, "r") == 0 || strcmp(token, "read") == 0) { + else if (strcmp(token, "r") == 0 || strcmp(token, "read") == 0) { uint16_t idx; uint8_t subidx; CO_SDOclient_return_t SDO_ret; @@ -727,7 +843,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->stateTimeoutTmr = 0; gtwa->state = CO_GTWA_ST_WRITE; } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT /* NMT start node */ else if (strcmp(token, "start") == 0) { CO_ReturnError_t ret; @@ -835,102 +953,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } } - - /* set command - multiple sub commands */ - else if (strcmp(token, "set") == 0) { - if (closed != 0) { - err = true; - break; - } - - /* command 2 */ - closed = -1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); - if (err) break; - - convertToLower(token, sizeof(token)); - if (strcmp(token, "network") == 0) { - uint16_t value; - - if (closed != 0) { - err = true; - break; - } - - /* value */ - closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, - &closed, &err); - value = (uint16_t)getU32(token, CO_CONFIG_GTW_NET_MIN, - CO_CONFIG_GTW_NET_MAX, &err); - if (err) break; - - gtwa->net_default = value; - responseWithOK(gtwa); - } - else if (strcmp(token, "node") == 0) { - bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - uint8_t value; - - if (closed != 0 || NodeErr) { - err = true; - break; - } - - /* value */ - closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, - &closed, &err); - value = (uint8_t)getU32(token, 1, 127, &err); - if (err) break; - - gtwa->node_default = value; - responseWithOK(gtwa); - } - else if (strcmp(token, "sdo_timeout") == 0) { - bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - uint16_t value; - - if (closed != 0 || NodeErr) { - err = true; - break; - } - - /* value */ - closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, - &closed, &err); - value = (uint16_t)getU32(token, 1, 0xFFFF, &err); - if (err) break; - - gtwa->SDOtimeoutTime = value; - responseWithOK(gtwa); - } - else if (strcmp(token, "sdo_block") == 0) { - bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - uint16_t value; - - if (closed != 0 || NodeErr) { - err = true; - break; - } - - /* value */ - closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, - &closed, &err); - value = (uint16_t)getU32(token, 0, 1, &err); - if (err) break; - - gtwa->SDOblockTransferEnable = value==1 ? true : false; - responseWithOK(gtwa); - } - else { - respErrorCode = CO_GTWA_respErrorReqNotSupported; - err = true; - break; - } - } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT */ /* TODO LSS */ @@ -969,6 +992,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_IDLE; } +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO /* SDO upload state */ else if (gtwa->state == CO_GTWA_ST_READ) { CO_SDO_abortCode_t abortCode; @@ -1093,6 +1117,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP /* Print help string (in multiple segments if necessary) */ diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 7fea0252..60e6b690 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -29,9 +29,13 @@ #include "301/CO_driver.h" #include "301/CO_fifo.h" +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO #include "301/CO_SDOserver.h" #include "301/CO_SDOclient.h" +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT #include "301/CO_NMT_Heartbeat.h" +#endif #ifdef __cplusplus extern "C" { @@ -209,6 +213,7 @@ typedef enum { } CO_GTWA_state_t; +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN /* * CANopen Gateway-ascii data types structure */ @@ -233,6 +238,7 @@ typedef struct { CO_fifo_t *src, CO_fifo_st *status); } CO_GTWA_dataType_t; +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ /** @@ -283,6 +289,7 @@ typedef struct { CO_GTWA_state_t state; /** Timeout timer for the current state */ uint32_t stateTimeoutTmr; +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN /** SDO client object from CO_GTWA_init() */ CO_SDOclient_t *SDO_C; /** Timeout time for SDO transfer in milliseconds, if no response */ @@ -293,8 +300,11 @@ typedef struct { bool_t SDOdataCopyStatus; /** Data type of variable in current SDO communication */ const CO_GTWA_dataType_t *SDOdataType; +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN /** NMT object from CO_GTWA_init() */ CO_NMT_t *NMT; +#endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) || defined CO_DOXYGEN /** Offset, when printing help text */ size_t helpStringOffset; @@ -314,17 +324,17 @@ typedef struct { * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT */ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, - CO_SDOclient_t* SDO_C, + void* SDO_C, uint16_t SDOtimeoutTimeDefault, bool_t SDOblockTransferEnableDefault, - CO_NMT_t *NMT); + void *NMT); /** * Initialize read callback in Gateway-ascii object * - * Callback will used for transfer data to output stream of the application. It - * will be called from CO_GTWA_process() zero or multiple times, depending on + * Callback will be used for transfer data to output stream of the application. + * It will be called from CO_GTWA_process() zero or multiple times, depending on * the data available. If readCallback is uninitialized or NULL, then output * data will be purged. * diff --git a/CANopen.c b/CANopen.c index 022c1bee..2ce689cc 100644 --- a/CANopen.c +++ b/CANopen.c @@ -765,10 +765,10 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII /* Gateway-ascii */ err = CO_GTWA_init(CO->gtwa, - CO->SDOclient[0], + (void *)CO->SDOclient[0], 500, false, - CO->NMT); + (void *)CO->NMT); if (err) return err; #endif diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index e700ace7..ab40c3c3 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -112,6 +112,10 @@ extern "C" { #ifndef CO_CONFIG_GTW #define CO_CONFIG_GTW (CO_CONFIG_GTW_ASCII | \ + CO_CONFIG_GTW_ASCII_SDO | \ + CO_CONFIG_GTW_ASCII_NMT | \ + CO_CONFIG_GTW_ASCII_LSS | \ + CO_CONFIG_GTW_ASCII_LOG | \ CO_CONFIG_GTW_ASCII_ERROR_DESC | \ CO_CONFIG_GTW_ASCII_PRINT_HELP) #define CO_CONFIG_GTW_BLOCK_DL_LOOP 1 diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index a6cf3f4d..34f45848 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -118,6 +118,10 @@ extern "C" { #ifndef CO_CONFIG_GTW #define CO_CONFIG_GTW (CO_CONFIG_GTW_ASCII | \ + CO_CONFIG_GTW_ASCII_SDO | \ + CO_CONFIG_GTW_ASCII_NMT | \ + CO_CONFIG_GTW_ASCII_LSS | \ + CO_CONFIG_GTW_ASCII_LOG | \ CO_CONFIG_GTW_ASCII_ERROR_DESC | \ CO_CONFIG_GTW_ASCII_PRINT_HELP) #define CO_CONFIG_GTW_BLOCK_DL_LOOP 3 From cb9b2cce425a6112f7f597e57664b5557de63381 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 29 May 2020 07:36:23 +0200 Subject: [PATCH 077/520] Add printout of message log from CANopen gateway-ascii (non-standard). --- 301/CO_SYNC.h | 7 ++++-- 301/CO_config.h | 8 ++++++ 301/CO_fifo.c | 2 +- 301/CO_fifo.h | 22 ++++++++++++++++- 309/CO_gateway_ascii.c | 48 +++++++++++++++++++++++++++++++++++- 309/CO_gateway_ascii.h | 26 +++++++++++++++++++ example/CO_driver_target.h | 1 + socketCAN/CO_Linux_threads.c | 6 +++-- socketCAN/CO_driver.c | 1 + socketCAN/CO_driver_target.h | 1 + socketCAN/CO_error.c | 1 + socketCAN/CO_error.h | 9 ++++--- socketCAN/CO_error_msgs.h | 11 --------- socketCAN/CO_main_basic.c | 31 +++++++++++++++++++++++ 14 files changed, 152 insertions(+), 22 deletions(-) diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index e76de8b4..9cad1ea6 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -109,11 +109,14 @@ typedef struct{ uint16_t CANdevTxIdx; /**< From CO_SYNC_init() */ }CO_SYNC_t; + +/** Return value for #CO_SYNC_process */ typedef enum { CO_SYNC_NONE = 0, /**< SYNC not received */ CO_SYNC_RECEIVED = 1, /**< SYNC received */ - CO_SYNC_OUTSIDE_WINDOW = 2, /**< SYNC received outside SYNC window */ -}CO_SYNC_status_t; + CO_SYNC_OUTSIDE_WINDOW = 2 /**< SYNC received outside SYNC window */ +} CO_SYNC_status_t; + /** * Initialize SYNC object. diff --git a/301/CO_config.h b/301/CO_config.h index db54ebda..706c8eac 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -349,6 +349,14 @@ extern "C" { #endif +/** + * Size of message log buffer in ASCII gateway object. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GTWA_LOG_BUF_SIZE 2000 +#endif + + /** @} */ #ifdef __cplusplus diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 33c04805..c4d7721b 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -149,7 +149,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, size_t i; char *bufDest; - if (fifo == NULL || buf == NULL) { + if (fifo == NULL || fifo->buf == NULL || buf == NULL) { return 0; } diff --git a/301/CO_fifo.h b/301/CO_fifo.h index e7115626..05c816cc 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -170,7 +170,7 @@ static inline size_t CO_fifo_getOccupied(CO_fifo_t *fifo) { * @return true, if write was successful (enough space in fifo buffer) */ static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const char c) { - if (fifo != NULL) { + if (fifo != NULL && fifo->buf != NULL) { size_t writePtrNext = fifo->writePtr + 1; if (writePtrNext != fifo->readPtr && !(writePtrNext == fifo->bufSize && fifo->readPtr == 0)) @@ -184,6 +184,26 @@ static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const char c) { } +/** + * Put one character into CO_fifo_t buffer object + * + * Overwrite old characters, if run out of space + * + * @param fifo This object + * @param c Character to put + */ +static inline void CO_fifo_putc_ov(CO_fifo_t *fifo, const char c) { + if (fifo != NULL && fifo->buf != NULL) { + fifo->buf[fifo->writePtr] = c; + + if (++fifo->writePtr == fifo->bufSize) fifo->writePtr = 0; + if (fifo->readPtr == fifo->writePtr) { + if (++fifo->readPtr == fifo->bufSize) fifo->readPtr = 0; + } + } +} + + /** * Get one character from CO_fifo_t buffer object * diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index ccf63746..2fc6d037 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -73,6 +73,12 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, >wa->commBuf[0], CO_CONFIG_GTWA_COMM_BUF_SIZE + 1); +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG + CO_fifo_init(>wa->logFifo, + >wa->logBuf[0], + CO_CONFIG_GTWA_LOG_BUF_SIZE + 1); +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) */ + return CO_ERROR_NO; } @@ -91,6 +97,20 @@ void CO_GTWA_initRead(CO_GTWA_t* gtwa, } +/******************************************************************************/ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG +void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { + if (gtwa != NULL && message != NULL) { + const char *c; + + for (c = &message[0]; *c != 0; c++) { + CO_fifo_putc_ov(>wa->logFifo, *c); + } + } +} +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ + + /******************************************************************************* * HELPER FUNCTIONS ******************************************************************************/ @@ -113,6 +133,7 @@ static const char *CO_GTWA_helpString = "[] set sdo_block # Enable/disable SDO block transfer.\n" \ "\n" \ "help # Print this help.\n" \ +"log # Print message log.\n" \ "\n" \ "Datatypes:\n" \ "b # Boolean.\n" \ @@ -955,7 +976,16 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT */ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS /* TODO LSS */ +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG + /* Print message log */ + else if (strcmp(token, "log") == 0) { + gtwa->state = CO_GTWA_ST_LOG; + } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP /* Print help */ @@ -963,7 +993,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->helpStringOffset = 0; gtwa->state = CO_GTWA_ST_HELP; } -#endif +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP */ /* Unrecognized command */ else { @@ -1119,6 +1149,22 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG + /* print message log */ + else if (gtwa->state == CO_GTWA_ST_LOG) { + do { + gtwa->respBufCount = CO_fifo_read(>wa->logFifo, gtwa->respBuf, + CO_GTWA_RESP_BUF_SIZE, NULL); + respBufTransfer(gtwa); + + if (CO_fifo_getOccupied(>wa->logFifo) == 0) { + gtwa->state = CO_GTWA_ST_IDLE; + break; + } + } while (gtwa->respHold == false); + } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP /* Print help string (in multiple segments if necessary) */ else if (gtwa->state == CO_GTWA_ST_HELP) { diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 60e6b690..efa18aca 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -85,6 +85,7 @@ Command strings start with '"[""]"' followed by: [] set sdo_block # Enable/disable SDO block transfer. help # Print this help. +log # Print message log. Datatypes: b # Boolean. @@ -208,6 +209,8 @@ typedef enum { CO_GTWA_ST_READ = 0x10U, /** SDO 'write' (download) */ CO_GTWA_ST_WRITE = 0x11U, + /** print message log */ + CO_GTWA_ST_LOG = 0x80U, /** print 'help' text */ CO_GTWA_ST_HELP = 0x90U } CO_GTWA_state_t; @@ -305,6 +308,12 @@ typedef struct { /** NMT object from CO_GTWA_init() */ CO_NMT_t *NMT; #endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) || defined CO_DOXYGEN + /** Message log buffer of usable size @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */ + char logBuf[CO_CONFIG_GTWA_LOG_BUF_SIZE + 1]; + /** CO_fifo_t object for message log (not pointer) */ + CO_fifo_t logFifo; +#endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) || defined CO_DOXYGEN /** Offset, when printing help text */ size_t helpStringOffset; @@ -386,6 +395,23 @@ static inline size_t CO_GTWA_write(CO_GTWA_t* gtwa, } +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) || defined CO_DOXYGEN +/** + * Print message log string into fifo buffer + * + * This function enables recording of system log messages including CANopen + * events. Function can be called by application for recording any message. + * Message is copied to internal fifo buffer. In case fifo is full, old messages + * will be owerwritten. Message log fifo can be read with non-standard command + * "log". After log is read, it is emptied. + * + * @param gtwa This object + * @param message Null terminated string + */ +void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message); +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ + + /** * Process Gateway-ascii object * diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index ab40c3c3..105e610c 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -120,6 +120,7 @@ extern "C" { CO_CONFIG_GTW_ASCII_PRINT_HELP) #define CO_CONFIG_GTW_BLOCK_DL_LOOP 1 #define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 +#define CO_CONFIG_GTWA_LOG_BUF_SIZE 2000 #endif diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index 23458bcb..b31f4f8d 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -67,11 +68,12 @@ static inline uint64_t CO_LinuxThreads_clock_gettime_us(void) /* write response string from gateway-ascii object */ static size_t gtwa_write_response(void *object, const char *buf, size_t count) { int* fd = (int *)object; - size_t nWritten = 0; + /* nWritten = count -> in case of error (non-existing fd) data are purged */ + size_t nWritten = count; if (fd != NULL && *fd >= 0) { ssize_t n = write(*fd, (const void *)buf, count); - if (n > 0) { + if (n >= 0) { nWritten = (size_t)n; } else { diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 72fbd281..166d63ad 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 34f45848..f8f8c950 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -126,6 +126,7 @@ extern "C" { CO_CONFIG_GTW_ASCII_PRINT_HELP) #define CO_CONFIG_GTW_BLOCK_DL_LOOP 3 #define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 +#define CO_CONFIG_GTWA_LOG_BUF_SIZE 10000 #endif diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index 640aa17b..ee5eedda 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 1f5fab6e..12517982 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -55,8 +55,11 @@ extern "C" { /** * Message logging function. * - * Default usage is to print messages into system log with syslog() call. By - * default system stores messages in /var/log/syslog file. + * Function must be defined by application. It should record log message to some + * place, for example syslog() call in Linux or logging functionality in + * CANopen gateway @ref CO_CANopen_309_3. + * + * By default system stores messages in /var/log/syslog file. * Log can optionally be configured before, for example to filter out less * critical errors than LOG_NOTICE, specify program name, print also process PID * and print also to standard error, set 'user' type of program, use: @@ -69,9 +72,7 @@ extern "C" { * LOG_NOTICE, LOG_INFO, LOG_DEBUG * @param format format string as in printf */ -#ifdef CO_DOXYGEN void log_printf(int priority, const char *format, ...); -#endif /** diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index 310fde40..202138c0 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -32,17 +32,6 @@ extern "C" { #endif -/* - * Message logging function. - */ -#ifndef log_printf -#include - -#define log_printf(macropar_prio, macropar_message, ...) \ - syslog(macropar_prio, macropar_message, ##__VA_ARGS__) -#endif - - /* * Message definitions for Linux CANopen socket driver (notice and errors) */ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 7802000c..dae915aa 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -89,6 +92,34 @@ static void sigHandler(int sig) { CO_endProgram = 1; } +/* Message logging function */ +void log_printf(int priority, const char *format, ...) { + va_list ap; + + va_start(ap, format); + vsyslog(priority, format, ap); + va_end(ap); + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG + if (CO != NULL) { + char buf[200]; + time_t timer; + struct tm* tm_info; + size_t len; + + timer = time(NULL); + tm_info = localtime(&timer); + len = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S: ", tm_info); + + va_start(ap, format); + vsnprintf(buf + len, sizeof(buf) - len - 2, format, ap); + va_end(ap); + strcat(buf, "\r\n"); + CO_GTWA_log_print(CO->gtwa, buf); + } +#endif +} + /* callback for emergency messages */ static void EmergencyRxCallback(const uint16_t ident, const uint16_t errorCode, From ae220f91153236b3212bb7d2f5dfdd4254925c44 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 29 May 2020 09:56:05 +0200 Subject: [PATCH 078/520] Configuration for LSS updated. --- 301/CO_config.h | 9 ++++-- 301/CO_driver.h | 4 +-- 305/CO_LSSmaster.c | 6 ++-- 305/CO_LSSmaster.h | 4 +-- 309/CO_gateway_ascii.c | 9 +++++- 309/CO_gateway_ascii.h | 11 ++++++- CANopen.c | 39 ++++++++++++----------- CANopen.h | 62 +++++++++++++++++++++++------------- example/CO_OD.h | 3 -- example/CO_driver_target.h | 5 +-- socketCAN/CO_driver_target.h | 5 +-- 11 files changed, 98 insertions(+), 59 deletions(-) diff --git a/301/CO_config.h b/301/CO_config.h index 706c8eac..0f34926c 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -280,17 +280,22 @@ extern "C" { #define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) #endif + /** - * Configuration of LSS master object + * Configuration of LSS objects * * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received SDO CAN message. * Callback is configured by CO_LSSmaster_initCallbackPre(). + * - CO_CONFIG_LSS_SLAVE - Enable LSS slave + * - CO_CONFIG_LSS_MASTER - Enable LSS master */ #ifdef CO_DOXYGEN -#define CO_CONFIG_LSS_MST (CO_CONFIG_FLAG_CALLBACK_PRE) +#define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER) #endif +#define CO_CONFIG_LSS_SLAVE 0x01 +#define CO_CONFIG_LSS_MASTER 0x02 /** diff --git a/301/CO_driver.h b/301/CO_driver.h index 87ce3829..1ac3b275 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -74,8 +74,8 @@ extern "C" { #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 #endif -#ifndef CO_CONFIG_LSS_MST -#define CO_CONFIG_LSS_MST (0) +#ifndef CO_CONFIG_LSS +#define CO_CONFIG_LSS (0) #endif #ifndef CO_CONFIG_GTW diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index e026b0f9..8416f93a 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -91,7 +91,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) CO_FLAG_SET(LSSmaster->CANrxNew); -#if (CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE +#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles further processing. */ if(LSSmaster->pFunctSignal != NULL) { LSSmaster->pFunctSignal(LSSmaster->functSignalObject); @@ -147,7 +147,7 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); -#if (CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE +#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE LSSmaster->pFunctSignal = NULL; LSSmaster->functSignalObject = NULL; #endif @@ -191,7 +191,7 @@ void CO_LSSmaster_changeTimeout( } -#if (CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE +#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ void CO_LSSmaster_initCallbackPre( CO_LSSmaster_t *LSSmaster, diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 8ccc764a..fb257c14 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -118,7 +118,7 @@ typedef struct{ volatile void *CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */ uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ -#if ((CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN void (*pFunctSignal)(void *object); /**< From CO_LSSmaster_initCallbackPre() or NULL */ void *functSignalObject;/**< Pointer to object */ #endif @@ -184,7 +184,7 @@ void CO_LSSmaster_changeTimeout( uint16_t timeout_ms); -#if ((CO_CONFIG_LSS_MST) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** * Initialize LSSmasterRx callback function. * diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 2fc6d037..188957c9 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -36,7 +36,8 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, void* SDO_C, uint16_t SDOtimeoutTimeDefault, bool_t SDOblockTransferEnableDefault, - void *NMT) + void *NMT, + void *LSS) { /* verify arguments */ if (gtwa == NULL @@ -45,6 +46,9 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT || NMT == NULL +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS + || LSS == NULL #endif ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -60,6 +64,9 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT gtwa->NMT = (CO_NMT_t *)NMT; +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS + gtwa->LSS = (CO_LSSmaster_t *)LSS; #endif gtwa->net_default = -1; gtwa->node_default = -1; diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index efa18aca..d0abd063 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -36,6 +36,9 @@ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT #include "301/CO_NMT_Heartbeat.h" #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS +#include "305/CO_LSSmaster.h" +#endif #ifdef __cplusplus extern "C" { @@ -308,6 +311,10 @@ typedef struct { /** NMT object from CO_GTWA_init() */ CO_NMT_t *NMT; #endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN + /** LSS object from CO_GTWA_init() */ + CO_LSSmaster_t *LSS; +#endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) || defined CO_DOXYGEN /** Message log buffer of usable size @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */ char logBuf[CO_CONFIG_GTWA_LOG_BUF_SIZE + 1]; @@ -329,6 +336,7 @@ typedef struct { * @param SDOtimeoutTimeDefault in milliseconds, 500 typically * @param SDOblockTransferEnableDefault true or false * @param NMT NMT object + * @param LSS LSS master object * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT */ @@ -336,7 +344,8 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, void* SDO_C, uint16_t SDOtimeoutTimeDefault, bool_t SDOblockTransferEnableDefault, - void *NMT); + void *NMT, + void *LSS); /** diff --git a/CANopen.c b/CANopen.c index 2ce689cc..965d0f26 100644 --- a/CANopen.c +++ b/CANopen.c @@ -62,9 +62,9 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; || (CO_NO_TPDO < 1 || CO_NO_TPDO > 0x200) \ || ODL_consumerHeartbeatTime_arrayLength == 0 \ || ODL_errorStatusBits_stringLength < 10 \ - || CO_NO_LSS_SERVER > 1 \ - || CO_NO_LSS_CLIENT > 1 \ - || (CO_NO_LSS_SERVER > 0 && CO_NO_LSS_CLIENT > 0) + || CO_NO_LSS_SLAVE > 1 \ + || CO_NO_LSS_MASTER > 1 \ + || (CO_NO_LSS_SLAVE > 0 && CO_NO_LSS_MASTER > 0) #error Features from CO_OD.h file are not corectly configured for this project! #endif @@ -86,8 +86,8 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; CO_NO_SDO_SERVER + \ CO_NO_SDO_CLIENT + \ CO_NO_HB_CONS + \ - CO_NO_LSS_SERVER + \ - CO_NO_LSS_CLIENT) + CO_NO_LSS_SLAVE + \ + CO_NO_LSS_MASTER) /* Indexes of CO_CANtx_t objects in CO_CANmodule_t and total number of them. **/ #define CO_TXCAN_NMT 0 @@ -107,8 +107,8 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; CO_NO_SDO_SERVER + \ CO_NO_SDO_CLIENT + \ CO_NO_HB_PROD + \ - CO_NO_LSS_SERVER + \ - CO_NO_LSS_CLIENT) + CO_NO_LSS_SLAVE + \ + CO_NO_LSS_MASTER) /* Create objects from heap ***************************************************/ @@ -213,14 +213,14 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { CO_memoryUsed += sizeof(CO_SDOclient_t) * CO_NO_SDO_CLIENT; #endif -#if CO_NO_LSS_SERVER == 1 +#if CO_NO_LSS_SLAVE == 1 /* LSSslave */ CO->LSSslave = (CO_LSSslave_t *)calloc(1, sizeof(CO_LSSslave_t)); if (CO->LSSslave == NULL) errCnt++; CO_memoryUsed += sizeof(CO_LSSslave_t); #endif -#if CO_NO_LSS_CLIENT == 1 +#if CO_NO_LSS_MASTER == 1 /* LSSmaster */ CO->LSSmaster = (CO_LSSmaster_t *)calloc(1, sizeof(CO_LSSmaster_t)); if (CO->LSSmaster == NULL) errCnt++; @@ -291,12 +291,12 @@ void CO_delete(void *CANptr) { free(CO->gtwa); #endif -#if CO_NO_LSS_CLIENT == 1 +#if CO_NO_LSS_MASTER == 1 /* LSSmaster */ free(CO->LSSmaster); #endif -#if CO_NO_LSS_SERVER == 1 +#if CO_NO_LSS_SLAVE == 1 /* LSSslave */ free(CO->LSSslave); #endif @@ -379,10 +379,10 @@ void CO_delete(void *CANptr) { #if CO_NO_SDO_CLIENT != 0 static CO_SDOclient_t COO_SDOclient[CO_NO_SDO_CLIENT]; #endif -#if CO_NO_LSS_SERVER == 1 +#if CO_NO_LSS_SLAVE == 1 static CO_LSSslave_t COO_LSSslave; #endif -#if CO_NO_LSS_CLIENT == 1 +#if CO_NO_LSS_MASTER == 1 static CO_LSSmaster_t COO_LSSmaster; #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII @@ -461,12 +461,12 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { } #endif -#if CO_NO_LSS_SERVER == 1 +#if CO_NO_LSS_SLAVE == 1 /* LSSslave */ CO->LSSslave = &COO_LSSslave; #endif -#if CO_NO_LSS_CLIENT == 1 +#if CO_NO_LSS_MASTER == 1 /* LSSmaster */ CO->LSSmaster = &COO_LSSmaster; #endif @@ -523,7 +523,7 @@ CO_ReturnError_t CO_CANinit(void *CANptr, /******************************************************************************/ -#if CO_NO_LSS_SERVER == 1 +#if CO_NO_LSS_SLAVE == 1 CO_ReturnError_t CO_LSSinit(uint8_t nodeId, uint16_t bitRate) { @@ -549,7 +549,7 @@ CO_ReturnError_t CO_LSSinit(uint8_t nodeId, return err; } -#endif /* CO_NO_LSS_SERVER == 1 */ +#endif /* CO_NO_LSS_SLAVE == 1 */ /******************************************************************************/ @@ -748,7 +748,7 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { } #endif -#if CO_NO_LSS_CLIENT == 1 +#if CO_NO_LSS_MASTER == 1 /* LSSmaster */ err = CO_LSSmaster_init(CO->LSSmaster, CO_LSSmaster_DEFAULT_TIMEOUT, @@ -768,7 +768,8 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { (void *)CO->SDOclient[0], 500, false, - (void *)CO->NMT); + (void *)CO->NMT, + (void *)CO->LSSmaster); if (err) return err; #endif diff --git a/CANopen.h b/CANopen.h index 2264347d..484efef9 100644 --- a/CANopen.h +++ b/CANopen.h @@ -127,21 +127,6 @@ extern "C" { #include "301/CO_TIME.h" #include "301/CO_PDO.h" #include "301/CO_HBconsumer.h" -#if CO_NO_SDO_CLIENT != 0 - #include "301/CO_SDOclient.h" -#endif -#if CO_NO_LSS_SERVER != 0 - #include "305/CO_LSSslave.h" -#endif -#if CO_NO_LSS_CLIENT != 0 - #include "305/CO_LSSmaster.h" -#endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - #include "309/CO_gateway_ascii.h" -#endif -#if CO_NO_TRACE != 0 - #include "extra/CO_trace.h" -#endif #include "CO_OD.h" @@ -158,7 +143,7 @@ extern "C" { /** Number of NMT objects, fixed to 1 slave(CANrx) */ #define CO_NO_NMT (1) /** Number of NMT master objects, 0 or 1 master(CANtx). It depends on - * @ref CO_CONFIG_EM setting. */ + * @ref CO_CONFIG_NMT setting. */ #define CO_NO_NMT_MST (0...1) /** Number of SYNC objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ #define CO_NO_SYNC (0...1) @@ -181,9 +166,11 @@ extern "C" { #define CO_NO_HB_PROD (1) /** Number of HB consumer objects, from 0 to 127 consumers(CANrx) */ #define CO_NO_HB_CONS (0...127) -/** Number of LSS slave objects, 0 or 1 (CANrx + CANtx) */ +/** Number of LSS slave objects, 0 or 1 (CANrx + CANtx). It depends on + * @ref CO_CONFIG_LSS setting. */ #define CO_NO_LSS_SLAVE (0...1) -/** Number of LSS master objects, 0 or 1 (CANrx + CANtx) */ +/** Number of LSS master objects, 0 or 1 (CANrx + CANtx). It depends on + * @ref CO_CONFIG_LSS setting. */ #define CO_NO_LSS_MASTER (0...1) /** Number of Trace objects, 0 to many */ #define CO_NO_TRACE (0...) @@ -218,9 +205,40 @@ extern "C" { #else #define CO_NO_HB_CONS 0 #endif + +/* LSS slave count depends on stack configuration */ +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#define CO_NO_LSS_SLAVE 1 +#else +#define CO_NO_LSS_SLAVE 0 +#endif + +/* LSS master count depends on stack configuration */ +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#define CO_NO_LSS_MASTER 1 +#else +#define CO_NO_LSS_MASTER 0 +#endif #endif /* CO_DOXYGEN */ +#if CO_NO_SDO_CLIENT != 0 + #include "301/CO_SDOclient.h" +#endif +#if CO_NO_LSS_SLAVE != 0 + #include "305/CO_LSSslave.h" +#endif +#if CO_NO_LSS_MASTER != 0 + #include "305/CO_LSSmaster.h" +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + #include "309/CO_gateway_ascii.h" +#endif +#if CO_NO_TRACE != 0 + #include "extra/CO_trace.h" +#endif + + /** * CANopen object with pointers to all CANopenNode objects. */ @@ -238,10 +256,10 @@ typedef struct { #if CO_NO_SDO_CLIENT != 0 CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */ #endif -#if CO_NO_LSS_SERVER == 1 +#if CO_NO_LSS_SLAVE == 1 CO_LSSslave_t *LSSslave; /**< LSS slave object */ #endif -#if CO_NO_LSS_CLIENT == 1 +#if CO_NO_LSS_MASTER == 1 CO_LSSmaster_t *LSSmaster; /**< LSS master object */ #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN @@ -299,7 +317,7 @@ CO_ReturnError_t CO_CANinit(void *CANptr, uint16_t bitRate); -#if CO_NO_LSS_SERVER == 1 +#if CO_NO_LSS_SLAVE == 1 /** * Initialize CANopen LSS slave * @@ -312,7 +330,7 @@ CO_ReturnError_t CO_CANinit(void *CANptr, */ CO_ReturnError_t CO_LSSinit(uint8_t nodeId, uint16_t bitRate); -#endif /* CO_NO_LSS_SERVER == 1 */ +#endif /* CO_NO_LSS_SLAVE == 1 */ /** diff --git a/example/CO_OD.h b/example/CO_OD.h index c2dad14d..8f4a5a29 100644 --- a/example/CO_OD.h +++ b/example/CO_OD.h @@ -96,10 +96,7 @@ #define CO_NO_SDO_CLIENT 1 //Associated objects: 1280 #define CO_NO_RPDO 4 //Associated objects: 1400, 1401, 1402, 1403, 1600, 1601, 1602, 1603 #define CO_NO_TPDO 4 //Associated objects: 1800, 1801, 1802, 1803, 1A00, 1A01, 1A02, 1A03 - #define CO_NO_NMT_MASTER 0 #define CO_NO_TRACE 0 - #define CO_NO_LSS_SERVER 0 - #define CO_NO_LSS_CLIENT 0 /******************************************************************************* OBJECT DICTIONARY diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 105e610c..01663447 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -106,8 +106,9 @@ extern "C" { #define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) #endif -#ifndef CO_CONFIG_LSS_MST -#define CO_CONFIG_LSS_MST (CO_CONFIG_FLAG_CALLBACK_PRE) +#ifndef CO_CONFIG_LSS +#define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_LSS_MASTER) #endif #ifndef CO_CONFIG_GTW diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index f8f8c950..72f1b9a0 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -112,8 +112,9 @@ extern "C" { #define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) #endif -#ifndef CO_CONFIG_LSS_MST -#define CO_CONFIG_LSS_MST (CO_CONFIG_FLAG_CALLBACK_PRE) +#ifndef CO_CONFIG_LSS +#define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_LSS_MASTER) #endif #ifndef CO_CONFIG_GTW From 92a803f169d233fd6f69eab6d47236ea729c26e3 Mon Sep 17 00:00:00 2001 From: Janez Date: Sun, 31 May 2020 13:08:35 +0200 Subject: [PATCH 079/520] Add LSS master into gateway-ascii (CiA309). - Rename local variable 'token' into 'tok' in CO_GTWA_process(). - CO_LSSmaster: replace CO_LSSmaster_InquireNodeId() with more generic CO_LSSmaster_Inquire(). CiA309-3 command 'lss_inquire_addr' now works also according to standard. - CANopen.h: fix doxygen. - gettingStarted.md: Change example "master" device from node-Id=3 to 1... --- 305/CO_LSSmaster.c | 23 +- 305/CO_LSSmaster.h | 15 +- 309/CO_gateway_ascii.c | 779 +++++++++++++++++++++++++++++++++++++---- 309/CO_gateway_ascii.h | 47 ++- CANopen.h | 46 +-- doc/gettingStarted.md | 26 +- 6 files changed, 806 insertions(+), 130 deletions(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 8416f93a..41dbf344 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -54,7 +54,7 @@ typedef enum { CO_LSSmaster_COMMAND_INQUIRE_PRODUCT, CO_LSSmaster_COMMAND_INQUIRE_REV, CO_LSSmaster_COMMAND_INQUIRE_SERIAL, - CO_LSSmaster_COMMAND_INQUIRE_NODE_ID, + CO_LSSmaster_COMMAND_INQUIRE, CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN, } CO_LSSmaster_command_t; @@ -107,7 +107,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) * or after the timeout expired. Only if no message has been received we have * to check for timeouts */ -static CO_LSSmaster_return_t CO_LSSmaster_check_timeout( +static inline CO_LSSmaster_return_t CO_LSSmaster_check_timeout( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us) { @@ -709,14 +709,15 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( /******************************************************************************/ -CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId( +CO_LSSmaster_return_t CO_LSSmaster_Inquire( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, - uint8_t *nodeId) + CO_LSS_cs_t lssInquireCs, + uint32_t *value) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if (LSSmaster==NULL || nodeId==NULL){ + if (LSSmaster==NULL || value==NULL){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } @@ -725,19 +726,15 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId( LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL) && LSSmaster->command == CO_LSSmaster_COMMAND_WAITING) { - LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_NODE_ID; + LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE; LSSmaster->timeoutTimer = 0; - ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_NODE_ID); + ret = CO_LSSmaster_inquireInitiate(LSSmaster, lssInquireCs); } /* Check for reply */ - else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_NODE_ID) { - uint32_t tmp = 0; - + else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE) { ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, - CO_LSS_INQUIRE_NODE_ID, &tmp); - - *nodeId = tmp & 0xff; + lssInquireCs, value); } if (ret != CO_LSSmaster_WAIT_SLAVE) { diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index fb257c14..5047e9e6 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -131,7 +131,9 @@ typedef struct{ * Default timeout for LSS slave in ms. This is the same as for SDO. For more * info about LSS timeout see #CO_LSSmaster_changeTimeout() */ +#ifndef CO_LSSmaster_DEFAULT_TIMEOUT #define CO_LSSmaster_DEFAULT_TIMEOUT 1000U /* ms */ +#endif /** @@ -364,9 +366,10 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( /** - * Request LSS inquire node ID + * Request LSS inquire node ID or part of LSS address * - * The node ID value is read from the node. + * The node-ID, identity vendor-ID, product-code, revision-number or + * serial-number value is read from the node. * * This function needs one specific node to be selected. * @@ -376,14 +379,16 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( * @param LSSmaster This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. Zero when request is started. - * @param [out] nodeId read result when function returns successfully + * @param lssInquireCs One of CO_LSS_INQUIRE_xx commands from #CO_LSS_cs_t. + * @param [out] value read result when function returns successfully * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ -CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId( +CO_LSSmaster_return_t CO_LSSmaster_Inquire( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, - uint8_t *nodeId); + CO_LSS_cs_t lssInquireCs, + uint32_t *value); /** diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 188957c9..2e161ce6 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -1,9 +1,10 @@ /* - * Access from other networks - ASCII mapping (CiA 309-3 DS v2.1.0) + * CANopen access from other networks - ASCII mapping (CiA 309-3 DS v3.0.0) * * @file CO_gateway_ascii.c * @ingroup CO_CANopen_309_3 * @author Janez Paternoster + * @author Martin Wagner * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. @@ -26,6 +27,7 @@ #include #include #include +#include #include #include "309/CO_gateway_ascii.h" @@ -37,7 +39,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, uint16_t SDOtimeoutTimeDefault, bool_t SDOblockTransferEnableDefault, void *NMT, - void *LSS) + void *LSSmaster) { /* verify arguments */ if (gtwa == NULL @@ -48,7 +50,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, || NMT == NULL #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS - || LSS == NULL + || LSSmaster == NULL #endif ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -66,7 +68,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, gtwa->NMT = (CO_NMT_t *)NMT; #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS - gtwa->LSS = (CO_LSSmaster_t *)LSS; + gtwa->LSSmaster = (CO_LSSmaster_t *)LSSmaster; #endif gtwa->net_default = -1; gtwa->node_default = -1; @@ -423,8 +425,9 @@ static void responseWithError(CO_GTWA_t *gtwa, } } - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR:%d #%s\r\n", - gtwa->sequence, respErrorCode, desc); + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] ERROR:%d #%s\r\n", + gtwa->sequence, respErrorCode, desc); respBufTransfer(gtwa); } @@ -443,8 +446,9 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, } } - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR:0x%08X #%s\r\n", - gtwa->sequence, abortCode, desc); + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] ERROR:0x%08X #%s\r\n", + gtwa->sequence, abortCode, desc); respBufTransfer(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ @@ -453,8 +457,9 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, static inline void responseWithError(CO_GTWA_t *gtwa, CO_GTWA_respErrorCode_t respErrorCode) { - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR:%d\r\n", - gtwa->sequence, respErrorCode); + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] ERROR:%d\r\n", + gtwa->sequence, respErrorCode); respBufTransfer(gtwa); } @@ -462,8 +467,9 @@ static inline void responseWithError(CO_GTWA_t *gtwa, static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, CO_SDO_abortCode_t abortCode) { - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ERROR:0x%08X\r\n", - gtwa->sequence, abortCode); + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] ERROR:0x%08X\r\n", + gtwa->sequence, abortCode); respBufTransfer(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ @@ -471,11 +477,36 @@ static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, static inline void responseWithOK(CO_GTWA_t *gtwa) { - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] OK\r\n", gtwa->sequence); + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] OK\r\n", + gtwa->sequence); respBufTransfer(gtwa); } +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS +static void responseLSS(CO_GTWA_t *gtwa, CO_LSSmaster_return_t lss_ret) { + if (lss_ret == CO_LSSmaster_OK) { + responseWithOK(gtwa); + } + else { + CO_GTWA_respErrorCode_t respErrorCode; + + if (lss_ret==CO_LSSmaster_TIMEOUT || lss_ret==CO_LSSmaster_SCAN_NOACK) { + respErrorCode = CO_GTWA_respErrorTimeOut; + } + else if (lss_ret == CO_LSSmaster_OK_MANUFACTURER) { + respErrorCode = CO_GTWA_respErrorLSSmanufacturer; + } + else { + respErrorCode = CO_GTWA_respErrorInternalState; + } + responseWithError(gtwa, respErrorCode); + } +} +#endif + + static inline void convertToLower(char *token, size_t maxCount) { size_t i; char *c = &token[0]; @@ -535,8 +566,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, while (gtwa->state == CO_GTWA_ST_IDLE && CO_fifo_CommSearch(>wa->commFifo, false) ) { - char token[20]; /* must be the size of tokenSize */ - const size_t tokenSize = 20; + char tok[20]; size_t n; uint32_t ui[3]; int i; @@ -546,7 +576,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* parse mandatory token '"[""]"' */ closed = -1; - n = CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); /* Break if error in token or token was found, but closed with * command delimiter. */ if (err || (n > 0 && closed != 0)) { @@ -557,12 +587,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (n == 0 && closed != 0) { continue; } - if (token[0] != '[' || token[strlen(token)-1] != ']') { + if (tok[0] != '[' || tok[strlen(tok)-1] != ']') { err = true; break; } - token[strlen(token)-1] = '\0'; - gtwa->sequence = getU32(token+1, 0, 0xFFFFFFFF, &err); + tok[strlen(tok)-1] = '\0'; + gtwa->sequence = getU32(tok + 1, 0, 0xFFFFFFFF, &err); if (err) break; @@ -570,13 +600,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * follows mandatory token , which is not numerical. */ for (i = 0; i < 3; i++) { closed = -1; - n = CO_fifo_readToken(>wa->commFifo, token, tokenSize, + n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err || n == 0) { /* empty token, break on error */ err = true; break; - } else if (isdigit(token[0]) == 0) { + } else if (isdigit(tok[0]) == 0) { /* found */ break; } else if (closed != 0) { @@ -585,7 +615,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - ui[i] = getU32(token, 0, 0xFFFFFFFF, &err); + ui[i] = getU32(tok, 0, 0xFFFFFFFF, &err); if (err) break; } if (err) break; @@ -623,10 +653,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (err) break; /* command is case insensitive */ - convertToLower(token, sizeof(token)); + convertToLower(tok, sizeof(tok)); /* set command - multiple sub commands */ - if (strcmp(token, "set") == 0) { + if (strcmp(tok, "set") == 0) { if (closed != 0) { err = true; break; @@ -634,11 +664,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* command 2 */ closed = -1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err) break; - convertToLower(token, sizeof(token)); - if (strcmp(token, "network") == 0) { + convertToLower(tok, sizeof(tok)); + /* 'set network ' */ + if (strcmp(tok, "network") == 0) { uint16_t value; if (closed != 0) { @@ -648,16 +679,17 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - value = (uint16_t)getU32(token, CO_CONFIG_GTW_NET_MIN, + value = (uint16_t)getU32(tok, CO_CONFIG_GTW_NET_MIN, CO_CONFIG_GTW_NET_MAX, &err); if (err) break; gtwa->net_default = value; responseWithOK(gtwa); } - else if (strcmp(token, "node") == 0) { + /* 'set node ' */ + else if (strcmp(tok, "node") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t value; @@ -668,16 +700,17 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - value = (uint8_t)getU32(token, 1, 127, &err); + value = (uint8_t)getU32(tok, 1, 127, &err); if (err) break; gtwa->node_default = value; responseWithOK(gtwa); } #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO - else if (strcmp(token, "sdo_timeout") == 0) { + /* 'set sdo_timeout ' */ + else if (strcmp(tok, "sdo_timeout") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t value; @@ -688,15 +721,16 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - value = (uint16_t)getU32(token, 1, 0xFFFF, &err); + value = (uint16_t)getU32(tok, 1, 0xFFFF, &err); if (err) break; gtwa->SDOtimeoutTime = value; responseWithOK(gtwa); } - else if (strcmp(token, "sdo_block") == 0) { + /* 'set sdo_timeout <0|1>' */ + else if (strcmp(tok, "sdo_block") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t value; @@ -707,9 +741,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - value = (uint16_t)getU32(token, 0, 1, &err); + value = (uint16_t)getU32(tok, 0, 1, &err); if (err) break; gtwa->SDOblockTransferEnable = value==1 ? true : false; @@ -725,7 +759,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO /* Upload SDO command - 'r[ead] ' */ - else if (strcmp(token, "r") == 0 || strcmp(token, "read") == 0) { + else if (strcmp(tok, "r") == 0 || strcmp(tok, "read") == 0) { uint16_t idx; uint8_t subidx; CO_SDOclient_return_t SDO_ret; @@ -738,15 +772,15 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* index */ closed = 0; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); - idx = (uint16_t)getU32(token, 0, 0xFFFF, &err); + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) break; /* subindex */ closed = -1; - n = CO_fifo_readToken(>wa->commFifo, token, tokenSize, + n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - subidx = (uint8_t)getU32(token, 0, 0xFF, &err); + subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); if (err || n == 0) { err = true; break; @@ -755,10 +789,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* optional data type */ if (closed == 0) { closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - convertToLower(token, sizeof(token)); - gtwa->SDOdataType = CO_GTWA_getDataType(token, &err); + convertToLower(tok, sizeof(tok)); + gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err); if (err) break; } else { @@ -790,7 +824,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* Download SDO comm. - w[rite] */ - else if (strcmp(token, "w") == 0 || strcmp(token, "write") == 0) { + else if (strcmp(tok, "w") == 0 || strcmp(tok, "write") == 0) { uint16_t idx; uint8_t subidx; CO_fifo_st status; @@ -805,23 +839,23 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* index */ closed = 0; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); - idx = (uint16_t)getU32(token, 0, 0xFFFF, &err); + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) break; /* subindex */ closed = 0; - n = CO_fifo_readToken(>wa->commFifo, token, tokenSize, + n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - subidx = (uint8_t)getU32(token, 0, 0xFF, &err); + subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); if (err) break; /* data type */ closed = 0; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - convertToLower(token, sizeof(token)); - gtwa->SDOdataType = CO_GTWA_getDataType(token, &err); + convertToLower(tok, sizeof(tok)); + gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err); if (err) break; /* setup client */ @@ -874,8 +908,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT - /* NMT start node */ - else if (strcmp(token, "start") == 0) { + /* NMT start node - 'start' */ + else if (strcmp(tok, "start") == 0) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_OPERATIONAL; @@ -896,8 +930,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } - /* NMT stop node */ - else if (strcmp(token, "stop") == 0) { + /* NMT stop node - 'stop' */ + else if (strcmp(tok, "stop") == 0) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_STOPPED; @@ -918,9 +952,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } - /* NMT Set node to pre-operational */ - else if (strcmp(token, "preop") == 0 || - strcmp(token, "preoperational") == 0 + /* NMT Set node to pre-operational - 'preop[erational]' */ + else if (strcmp(tok, "preop") == 0 || + strcmp(tok, "preoperational") == 0 ) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); @@ -942,8 +976,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } - /* NMT reset (node or communication) */ - else if (strcmp(token, "reset") == 0) { + /* NMT reset (node or communication) - 'reset '*/ + else if (strcmp(tok, "reset") == 0) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2; @@ -955,14 +989,14 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* command 2 */ closed = 1; - CO_fifo_readToken(>wa->commFifo, token, tokenSize, &closed, &err); + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err) break; - convertToLower(token, sizeof(token)); - if (strcmp(token, "node") == 0) { + convertToLower(tok, sizeof(tok)); + if (strcmp(tok, "node") == 0) { command2 = CO_NMT_RESET_NODE; - } else if (strcmp(token, "comm") == 0 || - strcmp(token, "communication") == 0 + } else if (strcmp(tok, "comm") == 0 || + strcmp(tok, "communication") == 0 ) { command2 = CO_NMT_RESET_COMMUNICATION; } else { @@ -984,19 +1018,348 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS - /* TODO LSS */ + /* Switch state global command - 'lss_switch_glob <0|1>' */ + else if (strcmp(tok, "lss_switch_glob") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint8_t select; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* get value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + select = (uint8_t)getU32(tok, 0, 1, &err); + if (err) break; + + if (select == 0) { + /* send non-confirmed message */ + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_switchStateDeselect(gtwa->LSSmaster); + if (ret == CO_LSSmaster_OK) { + responseWithOK(gtwa); + } + else { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + } + else { + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_LSS_SWITCH_GLOB; + } + } + /* Switch state selective command - + * 'lss_switch_sel ' */ + else if (strcmp(tok, "lss_switch_sel") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + CO_LSS_address_t *addr = >wa->lssAddress; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* get values */ + closed = 0; + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + addr->identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + addr->identity.productCode = getU32(tok, 0, 0xFFFFFFFF, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + addr->identity.revisionNumber = getU32(tok, 0, 0xFFFFFFFF, &err); + if (err) break; + + closed = 1; + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + addr->identity.serialNumber = getU32(tok, 0, 0xFFFFFFFF, &err); + if (err) break; + + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_LSS_SWITCH_SEL; + } + /* LSS configure node-ID command - 'lss_set_node ' */ + else if (strcmp(tok, "lss_set_node") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* get value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + gtwa->lssNID = (uint8_t)getU32(tok, 0, 0xFF, &err); + if (gtwa->lssNID > 0x7F && gtwa->lssNID < 0xFF) err = true; + if (err) break; + + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_LSS_SET_NODE; + } + /* LSS configure bit-rate command - + * 'lss_conf_bitrate ' + * table_index: 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s, + * 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto */ + else if (strcmp(tok, "lss_conf_bitrate") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint8_t tableIndex; + int maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / + sizeof(CO_LSS_bitTimingTableLookup[0])) - 1; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* First parameter is table selector. We only support the CiA + * bit timing table from CiA301 ("0") */ + closed = 0; + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)getU32(tok, 0, 0, &err); + + /* get value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + tableIndex = (uint8_t)getU32(tok, 0, maxIndex, &err); + if (tableIndex == 5) err = true; + if (err) break; + gtwa->lssBitrate = CO_LSS_bitTimingTableLookup[tableIndex]; + + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_LSS_CONF_BITRATE; + } + /* LSS activate new bit-rate command - + * 'lss_activate_bitrate ' */ + else if (strcmp(tok, "lss_activate_bitrate") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint16_t switchDelay; + CO_LSSmaster_return_t ret; + + if (closed != 0 || NodeErr) { + err = true; + break; + } + + /* get value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + switchDelay = (uint16_t)getU32(tok, 0, 0xFFFF, &err); + if (err) break; + + /* send non-confirmed message */ + ret = CO_LSSmaster_ActivateBit(gtwa->LSSmaster, switchDelay); + if (ret == CO_LSSmaster_OK) { + responseWithOK(gtwa); + } + else { + respErrorCode = CO_GTWA_respErrorInternalState; + err = true; + break; + } + } + /* LSS store configuration command - 'lss_store' */ + else if (strcmp(tok, "lss_store") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + + if (closed != 1 || NodeErr) { + err = true; + break; + } + + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_LSS_STORE; + } + /* Inquire LSS address command - 'lss_inquire_addr []' */ + else if (strcmp(tok, "lss_inquire_addr") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + + if (NodeErr) { + err = true; + break; + } + + if (closed == 0) { + uint8_t lsssub; + /* get value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + lsssub = (uint8_t)getU32(tok, 0, 3, &err); + if (err) break; + switch (lsssub) { + case 0: gtwa->lssInquireCs = CO_LSS_INQUIRE_VENDOR; break; + case 1: gtwa->lssInquireCs = CO_LSS_INQUIRE_PRODUCT; break; + case 2: gtwa->lssInquireCs = CO_LSS_INQUIRE_REV; break; + default: gtwa->lssInquireCs = CO_LSS_INQUIRE_SERIAL; break; + } + + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_LSS_INQUIRE; + } + else { + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL; + } + } + /* LSS inquire node-ID command - 'lss_get_node'*/ + else if (strcmp(tok, "lss_get_node") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + + if (closed != 1 || NodeErr) { + err = true; + break; + } + + /* continue with state machine */ + gtwa->lssInquireCs = CO_LSS_INQUIRE_NODE_ID; + gtwa->state = CO_GTWA_ST_LSS_INQUIRE; + } + /* LSS identify fastscan. This is a manufacturer specific command as + * the one in DSP309 is quite useless - '_lss_fastscan []'*/ + else if (strcmp(tok, "_lss_fastscan") == 0) { + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint16_t timeout_ms = 0; + + if (NodeErr) { + err = true; + break; + } + + if (closed == 0) { + /* get value */ + closed = 1; + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); + if (err) break; + } + + /* If timeout not specified, use 100ms. Should work in most cases */ + if (timeout_ms == 0) { + timeout_ms = 100; + } + CO_LSSmaster_changeTimeout(gtwa->LSSmaster, timeout_ms); + + /* prepare lssFastscan, all zero */ + memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); + + /* continue with state machine */ + gtwa->state = CO_GTWA_ST__LSS_FASTSCAN; + } + /* LSS complete node-ID configuration command - 'lss_allnodes + * [ [ + * + * ]]' */ + else if (strcmp(tok, "lss_allnodes") == 0) { + /* Request node enumeration by LSS identify fastscan. + * This initiates node enumeration by the means of LSS fastscan + * mechanism. When this function is finished: + * - All nodes that match the given criteria are assigned a node ID + * beginning with nodeId. If 127 is reached, the process + * is stopped, no matter if there are nodes remaining or not. + * - No IDs are assigned because: + * - the given criteria do not match any node, + * - all nodes are already configured. + * This function needs that no node is selected when starting the + * scan process. */ + bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); + uint16_t timeout_ms = 0; + + if (NodeErr) { + err = true; + break; + } + + if (closed == 0) { + /* get optional token timeout (non standard) */ + closed = -1; + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); + if (err) break; + + } + /* If timeout not specified, use 100ms. Should work in most cases */ + gtwa->lssTimeout_ms = timeout_ms == 0 ? 100 : timeout_ms; + CO_LSSmaster_changeTimeout(gtwa->LSSmaster, gtwa->lssTimeout_ms); + gtwa->lssNodeCount = 0; + gtwa->lssSubState = 0; + + if (closed == 1) { + /* No other arguments, as by CiA specification for this command. + * Do full scan. */ + /* use start node ID 2. Should work in most cases */ + gtwa->lssNID = 2; + /* store node ID in node's NVM */ + gtwa->lssStore = true; + /* prepare lssFastscan, all zero */ + memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); + } + else { + CO_LSSmaster_fastscan_t *fs = >wa->lssFastscan; + /* read other arguments */ + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + gtwa->lssNID = getU32(tok, 1, 127, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + gtwa->lssStore = (bool_t)getU32(tok, 0, 1, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + fs->scan[CO_LSS_FASTSCAN_VENDOR_ID] = getU32(tok, 0, 2, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + fs->match.identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + fs->scan[CO_LSS_FASTSCAN_PRODUCT] = getU32(tok, 0, 2, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + fs->match.identity.productCode = getU32(tok,0,0xFFFFFFFF, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + fs->scan[CO_LSS_FASTSCAN_REV] = getU32(tok, 0, 2, &err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + fs->match.identity.revisionNumber=getU32(tok,0,0xFFFFFFFF,&err); + if (err) break; + + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + fs->scan[CO_LSS_FASTSCAN_SERIAL] = getU32(tok, 0, 2, &err); + if (err) break; + + closed = 1; + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + fs->match.identity.serialNumber = getU32(tok,0,0xFFFFFFFF,&err); + if (err) break; + } + + /* continue with state machine */ + gtwa->state = CO_GTWA_ST_LSS_ALLNODES; + } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG /* Print message log */ - else if (strcmp(token, "log") == 0) { + else if (strcmp(tok, "log") == 0) { gtwa->state = CO_GTWA_ST_LOG; } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP /* Print help */ - else if (strcmp(token, "help") == 0) { + else if (strcmp(tok, "help") == 0) { gtwa->helpStringOffset = 0; gtwa->state = CO_GTWA_ST_HELP; } @@ -1055,8 +1418,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* write response head first */ if (!gtwa->SDOdataCopyStatus) { - gtwa->respBufCount = sprintf(gtwa->respBuf, "[%d] ", - gtwa->sequence); + gtwa->respBufCount = snprintf(gtwa->respBuf, + CO_GTWA_RESP_BUF_SIZE - 2, + "[%"PRId32"] ", + gtwa->sequence); gtwa->SDOdataCopyStatus = true; } @@ -1156,6 +1521,274 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS + else if (gtwa->state == CO_GTWA_ST_LSS_SWITCH_GLOB) { + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster, + timeDifference_us, + NULL); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + responseLSS(gtwa, ret); + gtwa->state = CO_GTWA_ST_IDLE; + } + } + else if (gtwa->state == CO_GTWA_ST_LSS_SWITCH_SEL) { + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster, + timeDifference_us, + >wa->lssAddress); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + responseLSS(gtwa, ret); + gtwa->state = CO_GTWA_ST_IDLE; + } + } + else if (gtwa->state == CO_GTWA_ST_LSS_SET_NODE) { + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster, + timeDifference_us, + gtwa->lssNID); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { + respErrorCode = CO_GTWA_respErrorLSSnodeIdNotSupported; + responseWithError(gtwa, respErrorCode); + } + else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + else if (gtwa->state == CO_GTWA_ST_LSS_CONF_BITRATE) { + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_configureBitTiming(gtwa->LSSmaster, + timeDifference_us, + gtwa->lssBitrate); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { + respErrorCode = CO_GTWA_respErrorLSSbitRateNotSupported; + responseWithError(gtwa, respErrorCode); + } + else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + else if (gtwa->state == CO_GTWA_ST_LSS_STORE) { + CO_LSSmaster_return_t ret; + + ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, timeDifference_us); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { + respErrorCode = CO_GTWA_respErrorLSSparameterStoringFailed; + responseWithError(gtwa, respErrorCode); + } + else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + else if (gtwa->state == CO_GTWA_ST_LSS_INQUIRE) { + CO_LSSmaster_return_t ret; + uint32_t value; + + ret = CO_LSSmaster_Inquire(gtwa->LSSmaster, timeDifference_us, + gtwa->lssInquireCs, &value); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK) { + if (gtwa->lssInquireCs == CO_LSS_INQUIRE_NODE_ID) { + gtwa->respBufCount = + snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] 0x%02"PRIX32"\r\n", + gtwa->sequence, value & 0xFF); + } else { + gtwa->respBufCount = + snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] 0x%08"PRIX32"\r\n", + gtwa->sequence, value); + } + respBufTransfer(gtwa); + } + else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + else if (gtwa->state == CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL) { + CO_LSSmaster_return_t ret; + CO_LSS_address_t lssAddress; + + ret = CO_LSSmaster_InquireLssAddress(gtwa->LSSmaster, timeDifference_us, + &lssAddress); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK) { + gtwa->respBufCount = + snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ + " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", + gtwa->sequence, + lssAddress.identity.vendorID, + lssAddress.identity.productCode, + lssAddress.identity.revisionNumber, + lssAddress.identity.serialNumber); + respBufTransfer(gtwa); + } + else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + else if (gtwa->state == CO_GTWA_ST__LSS_FASTSCAN) { + CO_LSSmaster_return_t ret; + + ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, timeDifference_us, + >wa->lssFastscan); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK || ret == CO_LSSmaster_SCAN_FINISHED) { + gtwa->respBufCount = + snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ + " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", + gtwa->sequence, + gtwa->lssFastscan.found.identity.vendorID, + gtwa->lssFastscan.found.identity.productCode, + gtwa->lssFastscan.found.identity.revisionNumber, + gtwa->lssFastscan.found.identity.serialNumber); + respBufTransfer(gtwa); + } + else { + responseLSS(gtwa, ret); + } + CO_LSSmaster_changeTimeout(gtwa->LSSmaster, + CO_LSSmaster_DEFAULT_TIMEOUT); + gtwa->state = CO_GTWA_ST_IDLE; + } + } + else if (gtwa->state == CO_GTWA_ST_LSS_ALLNODES) { + CO_LSSmaster_return_t ret; + if (gtwa->lssSubState == 0) { /* _lss_fastscan */ + ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, + timeDifference_us, + >wa->lssFastscan); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + CO_LSSmaster_changeTimeout(gtwa->LSSmaster, + CO_LSSmaster_DEFAULT_TIMEOUT); + + if (ret == CO_LSSmaster_OK || ret == CO_LSSmaster_SCAN_NOACK) { + /* no (more) nodes found, send report sum and finish */ + gtwa->respBufCount = + snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "# Found %d nodes, search finished.\r\n" \ + "[%"PRId32"] OK\r\n", + gtwa->lssNodeCount, + gtwa->sequence); + respBufTransfer(gtwa); + gtwa->state = CO_GTWA_ST_IDLE; + } + else if (ret == CO_LSSmaster_SCAN_FINISHED) { + /* next sub-step */ + gtwa->lssSubState++; + } + else { + /* error occurred */ + responseLSS(gtwa, ret); + gtwa->state = CO_GTWA_ST_IDLE; + } + } + } + if (gtwa->lssSubState == 1) { /* lss_set_node */ + ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster, + timeDifference_us, + gtwa->lssNID); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK) { + /* next sub-step */ + gtwa->lssSubState += gtwa->lssStore ? 1 : 2; + } + else { + /* error occurred */ + if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { + respErrorCode = CO_GTWA_respErrorLSSnodeIdNotSupported; + responseWithError(gtwa, respErrorCode); + } + else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + } + if (gtwa->lssSubState == 2) { /* lss_store */ + ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, + timeDifference_us); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK) { + /* next sub-step */ + gtwa->lssSubState++; + } + else { + /* error occurred */ + if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { + respErrorCode = + CO_GTWA_respErrorLSSparameterStoringFailed; + responseWithError(gtwa, respErrorCode); + } + else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + } + if (gtwa->lssSubState >= 3) { /* lss_switch_glob 0 */ + /* send non-confirmed message */ + ret = CO_LSSmaster_switchStateDeselect(gtwa->LSSmaster); + if (ret != CO_LSSmaster_OK) { + /* error occurred */ + responseLSS(gtwa, ret); + gtwa->state = CO_GTWA_ST_IDLE; + } + else { + /* cycle finished successfully, send report */ + const char msg2Fmt[] = "# Not all nodes scanned!\r\n" \ + "[%"PRId32"] OK\r\n"; + char msg2[sizeof(msg2Fmt)+10] = {0}; + + /* increment variables, check end-of-nodeId */ + gtwa->lssNodeCount++; + if (gtwa->lssNID < 127) { + /* repeat cycle with next node-id */ + gtwa->lssNID++; + CO_LSSmaster_changeTimeout(gtwa->LSSmaster, + gtwa->lssTimeout_ms); + gtwa->lssSubState = 0; + } + else { + /* If we can't assign more node IDs, quit scanning */ + sprintf(msg2, msg2Fmt, gtwa->sequence); + gtwa->state = CO_GTWA_ST_IDLE; + } + + /* send report */ + gtwa->respBufCount = + snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "# Node-ID %d assigned to: 0x%08"PRIX32" 0x%08" \ + PRIX32" 0x%08"PRIX32" 0x%08"PRIX32"\r\n%s", + gtwa->lssNID, + gtwa->lssFastscan.found.identity.vendorID, + gtwa->lssFastscan.found.identity.productCode, + gtwa->lssFastscan.found.identity.revisionNumber, + gtwa->lssFastscan.found.identity.serialNumber, + msg2); + respBufTransfer(gtwa); + } + } + } /* else if (gtwa->state == CO_GTWA_ST_LSS_ALLNODES) */ +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG /* print message log */ else if (gtwa->state == CO_GTWA_ST_LOG) { diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index d0abd063..77912aa3 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -1,9 +1,10 @@ /** - * CANopen access from other networks - ASCII mapping (CiA 309-3 DS v2.1.0) + * CANopen access from other networks - ASCII mapping (CiA 309-3 DS v3.0.0) * * @file CO_gateway_ascii.h * @ingroup CO_CANopen_309_3 * @author Janez Paternoster + * @author Martin Wagner * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. @@ -212,6 +213,24 @@ typedef enum { CO_GTWA_ST_READ = 0x10U, /** SDO 'write' (download) */ CO_GTWA_ST_WRITE = 0x11U, + /** LSS 'lss_switch_glob' */ + CO_GTWA_ST_LSS_SWITCH_GLOB = 0x20U, + /** LSS 'lss_switch_sel' */ + CO_GTWA_ST_LSS_SWITCH_SEL = 0x21U, + /** LSS 'lss_set_node' */ + CO_GTWA_ST_LSS_SET_NODE = 0x22U, + /** LSS 'lss_conf_bitrate' */ + CO_GTWA_ST_LSS_CONF_BITRATE = 0x23U, + /** LSS 'lss_store' */ + CO_GTWA_ST_LSS_STORE = 0x24U, + /** LSS 'lss_inquire_addr' or 'lss_get_node' */ + CO_GTWA_ST_LSS_INQUIRE = 0x25U, + /** LSS 'lss_inquire_addr', all parameters */ + CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL = 0x26U, + /** LSS '_lss_fastscan' */ + CO_GTWA_ST__LSS_FASTSCAN = 0x30U, + /** LSS 'lss_allnodes' */ + CO_GTWA_ST_LSS_ALLNODES = 0x31U, /** print message log */ CO_GTWA_ST_LOG = 0x80U, /** print 'help' text */ @@ -312,8 +331,26 @@ typedef struct { CO_NMT_t *NMT; #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN - /** LSS object from CO_GTWA_init() */ - CO_LSSmaster_t *LSS; + /** LSSmaster object from CO_GTWA_init() */ + CO_LSSmaster_t *LSSmaster; + /** 128 bit number, uniquely identifying each node */ + CO_LSS_address_t lssAddress; + /** LSS Node-ID parameter */ + uint8_t lssNID; + /** LSS bitrate parameter */ + uint16_t lssBitrate; + /** LSS inquire parameter */ + CO_LSS_cs_t lssInquireCs; + /** LSS fastscan parameter */ + CO_LSSmaster_fastscan_t lssFastscan; + /** LSS allnodes sub state parameter */ + uint8_t lssSubState; + /** LSS allnodes node count parameter */ + uint8_t lssNodeCount; + /** LSS allnodes store parameter */ + bool_t lssStore; + /** LSS allnodes timeout parameter */ + uint16_t lssTimeout_ms; #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) || defined CO_DOXYGEN /** Message log buffer of usable size @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */ @@ -336,7 +373,7 @@ typedef struct { * @param SDOtimeoutTimeDefault in milliseconds, 500 typically * @param SDOblockTransferEnableDefault true or false * @param NMT NMT object - * @param LSS LSS master object + * @param LSSmaster LSS master object * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT */ @@ -345,7 +382,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, uint16_t SDOtimeoutTimeDefault, bool_t SDOblockTransferEnableDefault, void *NMT, - void *LSS); + void *LSSmaster); /** diff --git a/CANopen.h b/CANopen.h index 484efef9..5a3d6c88 100644 --- a/CANopen.h +++ b/CANopen.h @@ -144,36 +144,36 @@ extern "C" { #define CO_NO_NMT (1) /** Number of NMT master objects, 0 or 1 master(CANtx). It depends on * @ref CO_CONFIG_NMT setting. */ -#define CO_NO_NMT_MST (0...1) +#define CO_NO_NMT_MST (0 - 1) /** Number of SYNC objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ -#define CO_NO_SYNC (0...1) +#define CO_NO_SYNC (0 - 1) /** Number of Emergency producer objects, fixed to 1 producer(CANtx) */ #define CO_NO_EMERGENCY (1) /** Number of Emergency consumer objects, 0 or 1 consumer(CANrx). It depends on * @ref CO_CONFIG_EM setting. */ -#define CO_NO_EM_CONS (0...1) +#define CO_NO_EM_CONS (0 - 1) /** Number of Time-stamp objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ -#define CO_NO_TIME (0...1) +#define CO_NO_TIME (0 - 1) /** Number of RPDO objects, 1 to 512 consumers (CANrx) */ -#define CO_NO_RPDO (1...512) +#define CO_NO_RPDO (1 - 512) /** Number of TPDO objects, 1 to 512 producers (CANtx) */ -#define CO_NO_TPDO (1...512) +#define CO_NO_TPDO (1 - 512) /** Number of SDO server objects, from 1 to 128 (CANrx + CANtx) */ -#define CO_NO_SDO_SERVER (1...128) +#define CO_NO_SDO_SERVER (1 - 128) /** Number of SDO client objects, from 0 to 128 (CANrx + CANtx) */ -#define CO_NO_SDO_CLIENT (0...128) +#define CO_NO_SDO_CLIENT (0 - 128) /** Number of HB producer objects, fixed to 1 producer(CANtx) */ #define CO_NO_HB_PROD (1) /** Number of HB consumer objects, from 0 to 127 consumers(CANrx) */ -#define CO_NO_HB_CONS (0...127) +#define CO_NO_HB_CONS (0 - 127) /** Number of LSS slave objects, 0 or 1 (CANrx + CANtx). It depends on * @ref CO_CONFIG_LSS setting. */ -#define CO_NO_LSS_SLAVE (0...1) +#define CO_NO_LSS_SLAVE (0 - 1) /** Number of LSS master objects, 0 or 1 (CANrx + CANtx). It depends on * @ref CO_CONFIG_LSS setting. */ -#define CO_NO_LSS_MASTER (0...1) +#define CO_NO_LSS_MASTER (0 - 1) /** Number of Trace objects, 0 to many */ -#define CO_NO_TRACE (0...) +#define CO_NO_TRACE (0 - ) /** @} */ #else /* CO_DOXYGEN */ @@ -222,19 +222,19 @@ extern "C" { #endif /* CO_DOXYGEN */ -#if CO_NO_SDO_CLIENT != 0 +#if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN #include "301/CO_SDOclient.h" #endif -#if CO_NO_LSS_SLAVE != 0 +#if CO_NO_LSS_SLAVE != 0 || defined CO_DOXYGEN #include "305/CO_LSSslave.h" #endif -#if CO_NO_LSS_MASTER != 0 +#if CO_NO_LSS_MASTER != 0 || defined CO_DOXYGEN #include "305/CO_LSSmaster.h" #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN #include "309/CO_gateway_ascii.h" #endif -#if CO_NO_TRACE != 0 +#if CO_NO_TRACE != 0 || defined CO_DOXYGEN #include "extra/CO_trace.h" #endif @@ -253,19 +253,19 @@ typedef struct { CO_RPDO_t *RPDO[CO_NO_RPDO]; /**< RPDO objects */ CO_TPDO_t *TPDO[CO_NO_TPDO]; /**< TPDO objects */ CO_HBconsumer_t *HBcons; /**< Heartbeat consumer object*/ -#if CO_NO_SDO_CLIENT != 0 +#if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */ #endif -#if CO_NO_LSS_SLAVE == 1 +#if CO_NO_LSS_SLAVE == 1 || defined CO_DOXYGEN CO_LSSslave_t *LSSslave; /**< LSS slave object */ #endif -#if CO_NO_LSS_MASTER == 1 +#if CO_NO_LSS_MASTER == 1 || defined CO_DOXYGEN CO_LSSmaster_t *LSSmaster; /**< LSS master object */ #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN CO_GTWA_t *gtwa; /**< Gateway-ascii object (CiA309-3) */ #endif -#if CO_NO_TRACE > 0 +#if CO_NO_TRACE > 0 || defined CO_DOXYGEN CO_trace_t *trace[CO_NO_TRACE]; /**< Trace object for recording variables */ #endif } CO_t; @@ -317,7 +317,7 @@ CO_ReturnError_t CO_CANinit(void *CANptr, uint16_t bitRate); -#if CO_NO_LSS_SLAVE == 1 +#if CO_NO_LSS_SLAVE == 1 || defined CO_DOXYGEN /** * Initialize CANopen LSS slave * @@ -370,7 +370,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, uint32_t *timerNext_us); -#if CO_NO_SYNC == 1 +#if CO_NO_SYNC == 1 || defined CO_DOXYGEN /** * Process CANopen SYNC objects. * diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index 7f4bd79b..4295bfc5 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -78,13 +78,13 @@ Second terminal now shows operational state (0x05) and one pre-defined PDO messa ### Second CANopen device -Open the third terminal and cd to the same directory as is in the first terminal. First generate default storage files. Then start second instance of _canopend_ with NodeID = 3. Use default od_storage files and enable command interface on standard IO (terminal). +Open the third terminal and cd to the same directory as is in the first terminal. First generate default storage files. Then start second instance of _canopend_ with NodeID = 1. Use default od_storage files and enable command interface on standard IO (terminal). echo "-" > od_storage echo "-" > od_storage_auto - ./canopend vcan0 -i3 -c "stdio" + ./canopend vcan0 -i1 -c "stdio" -Now you should see in second terminal (_candump_) two CANopen devices sending heartbeats in one second interval each. One with node-ID = 4 and one with node-ID = 3. Both should be operational. +Now you should see in second terminal (_candump_) two CANopen devices sending heartbeats in one second interval each. One with node-ID = 4 and one with node-ID = 1. Both should be operational. ### CANopen command interface @@ -106,9 +106,9 @@ In CAN dump you can see some SDO communication. SDO communication can be quite c [2] 4 write 0x1017 0 u16 5000 [2] OK #response -In _candump_ you will notice, that heartbeats from node 4 are coming in 5 second interval now. You can do the same also for node 3, but you won't see anything on _candump_, because data are written into itself directly. In "stdio" you can omit sequence number, to make typing easier. +In _candump_ you will notice, that heartbeats from node 4 are coming in 5 second interval now. You can do the same also for node 1, but you won't see anything on _candump_, because data are written into itself directly. In "stdio" you can omit sequence number, to make typing easier. - 3 w 0x1017 0 u16 2500 + 1 w 0x1017 0 u16 2500 [0] OK Now store Object dictionary on node-ID 4, so it will preserve variables on next start of the program. @@ -143,10 +143,10 @@ If node is operational (started), it can exchange all objects, including PDO, SD reset node [0] OK - 3 reset communication + 1 reset communication [0] OK - 3 reset node + 1 reset node [0] OK @@ -159,15 +159,19 @@ Please be careful when exposing your CANopen network to the outside world, it is ### Next steps Now you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware). -Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native integrated into Linux kernel are: +You can also build your own CANopen device with your favourite microcontroller, see *deviceSupport.md*. There is also a bare-metal demo for [PIC microcontrollers](https://github.com/CANopenNode/CANopenPIC), most complete example is for PIC32. + +Assigning Node-ID or CAN bitrate to unconfigured nodes, which support LSS configuration, is described in *LSSusage.md*. + +Some further CANopenNode related Linux tools are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket). + +Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native in Linux kernel are: - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with: `sudo slcand -f -o -c -s8 /dev/ttyACM0 can0; sudo ip link set up can0` - [EMS CPC-USB](https://www.ems-wuensche.com/?post_type=product&p=746) or [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Start with: `sudo ip link set up can0 type can bitrate 250000` - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can) (Kconfig files). - - Beaglebone or Paspberry PI or similar has CAN capes available. On RPI worked also the above USB interfaces, but it was necessary to compile the kernel. - + - Raspberry PI or similar has CAN capes available. With [CANopenNode](https://github.com/CANopenNode/CANopenNode) you can also design your own device. There are many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download. - Here we played with virtual CAN interface and result shows as pixels on screen. If you connect real CAN interface to your computer, things may become dangerous. Keep control and safety on your machines! From 229b5c5fd3762b2dfdb392c0bc17c38a1f4e698a Mon Sep 17 00:00:00 2001 From: Janez Date: Sun, 31 May 2020 22:08:36 +0200 Subject: [PATCH 080/520] Change optional arguments in CO_RPDO_init(), CO_TPDO_init(), CO_GTWA_init() --- 301/CO_PDO.c | 19 ++++++++----------- 301/CO_PDO.h | 16 ++++++++++++++-- 309/CO_gateway_ascii.c | 20 ++++++++++++++------ 309/CO_gateway_ascii.h | 13 ++++++++++--- CANopen.c | 28 +++++++++++++++++----------- CANopen.h | 6 +++++- 6 files changed, 68 insertions(+), 34 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index fb8b9f4f..b76a1d24 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -26,13 +26,6 @@ #include -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" -#include "301/CO_Emergency.h" -#include "301/CO_NMT_Heartbeat.h" -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE -#include "301/CO_SYNC.h" -#endif #include "301/CO_PDO.h" /* @@ -731,7 +724,9 @@ CO_ReturnError_t CO_RPDO_init( CO_RPDO_t *RPDO, CO_EM_t *em, CO_SDO_t *SDO, - void *SYNC, +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + CO_SYNC_t *SYNC, +#endif CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, @@ -753,7 +748,7 @@ CO_ReturnError_t CO_RPDO_init( RPDO->em = em; RPDO->SDO = SDO; #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - RPDO->SYNC = (CO_SYNC_t *)SYNC; + RPDO->SYNC = SYNC; #endif RPDO->RPDOCommPar = RPDOCommPar; RPDO->RPDOMapPar = RPDOMapPar; @@ -805,7 +800,9 @@ CO_ReturnError_t CO_TPDO_init( CO_TPDO_t *TPDO, CO_EM_t *em, CO_SDO_t *SDO, - void *SYNC, +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + CO_SYNC_t *SYNC, +#endif CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, @@ -827,7 +824,7 @@ CO_ReturnError_t CO_TPDO_init( TPDO->em = em; TPDO->SDO = SDO; #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - TPDO->SYNC = (CO_SYNC_t *)SYNC; + TPDO->SYNC = SYNC; #endif TPDO->TPDOCommPar = TPDOCommPar; TPDO->TPDOMapPar = TPDOMapPar; diff --git a/301/CO_PDO.h b/301/CO_PDO.h index ce8783af..b1fd2498 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -23,6 +23,14 @@ * limitations under the License. */ +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#include "301/CO_SYNC.h" +#endif + #ifndef CO_PDO_H #define CO_PDO_H @@ -273,7 +281,9 @@ CO_ReturnError_t CO_RPDO_init( CO_RPDO_t *RPDO, CO_EM_t *em, CO_SDO_t *SDO, - void *SYNC, +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN + CO_SYNC_t *SYNC, +#endif CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, @@ -339,7 +349,9 @@ CO_ReturnError_t CO_TPDO_init( CO_TPDO_t *TPDO, CO_EM_t *em, CO_SDO_t *SDO, - void *SYNC, +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN + CO_SYNC_t *SYNC, +#endif CO_NMT_internalState_t *operatingState, uint8_t nodeId, uint16_t defaultCOB_ID, diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 2e161ce6..71373c2e 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -35,12 +35,20 @@ /******************************************************************************/ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, - void* SDO_C, +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN + CO_SDOclient_t* SDO_C, uint16_t SDOtimeoutTimeDefault, bool_t SDOblockTransferEnableDefault, - void *NMT, - void *LSSmaster) +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN + CO_NMT_t *NMT, +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN + CO_LSSmaster_t *LSSmaster, +#endif + uint8_t dummy) { + (void)dummy; /* verify arguments */ if (gtwa == NULL #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO @@ -60,15 +68,15 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, gtwa->readCallback = NULL; gtwa->readCallbackObject = NULL; #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO - gtwa->SDO_C = (CO_SDOclient_t *)SDO_C; + gtwa->SDO_C = SDO_C; gtwa->SDOtimeoutTime = SDOtimeoutTimeDefault; gtwa->SDOblockTransferEnable = SDOblockTransferEnableDefault; #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT - gtwa->NMT = (CO_NMT_t *)NMT; + gtwa->NMT = NMT; #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS - gtwa->LSSmaster = (CO_LSSmaster_t *)LSSmaster; + gtwa->LSSmaster = LSSmaster; #endif gtwa->net_default = -1; gtwa->node_default = -1; diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 77912aa3..a9935841 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -378,11 +378,18 @@ typedef struct { * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT */ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, - void* SDO_C, +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN + CO_SDOclient_t* SDO_C, uint16_t SDOtimeoutTimeDefault, bool_t SDOblockTransferEnableDefault, - void *NMT, - void *LSSmaster); +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN + CO_NMT_t *NMT, +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN + CO_LSSmaster_t *LSSmaster, +#endif + uint8_t dummy); /** diff --git a/CANopen.c b/CANopen.c index 965d0f26..c875e14a 100644 --- a/CANopen.c +++ b/CANopen.c @@ -167,8 +167,6 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { CO->SYNC = (CO_SYNC_t *)calloc(1, sizeof(CO_SYNC_t)); if (CO->SYNC == NULL) errCnt++; CO_memoryUsed += sizeof(CO_SYNC_t); -#else - CO->SYNC = NULL; #endif #if CO_NO_TIME == 1 @@ -429,8 +427,6 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { #if CO_NO_SYNC == 1 /* SYNC */ CO->SYNC = &COO_SYNC; -#else - CO->SYNC = NULL; #endif #if CO_NO_TIME == 1 @@ -686,7 +682,9 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { err = CO_RPDO_init(CO->RPDO[i], CO->em, CO->SDO[0], - (void *)CO->SYNC, +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + CO->SYNC, +#endif &CO->NMT->operatingState, nodeId, ((i < 4) ? (CO_CAN_ID_RPDO_1 + i * 0x100) : 0), @@ -706,7 +704,9 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { err = CO_TPDO_init(CO->TPDO[i], CO->em, CO->SDO[0], - (void *)CO->SYNC, +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + CO->SYNC, +#endif &CO->NMT->operatingState, nodeId, ((i < 4) ? (CO_CAN_ID_TPDO_1 + i * 0x100) : 0), @@ -765,14 +765,20 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII /* Gateway-ascii */ err = CO_GTWA_init(CO->gtwa, - (void *)CO->SDOclient[0], +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO + CO->SDOclient[0], 500, false, - (void *)CO->NMT, - (void *)CO->LSSmaster); - - if (err) return err; #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT + CO->NMT, +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS + CO->LSSmaster, +#endif + 0); + if (err) return err; +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ #if CO_NO_TRACE > 0 /* Trace */ diff --git a/CANopen.h b/CANopen.h index 5a3d6c88..abcfea5a 100644 --- a/CANopen.h +++ b/CANopen.h @@ -123,7 +123,6 @@ extern "C" { #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" #include "301/CO_NMT_Heartbeat.h" - #include "301/CO_SYNC.h" #include "301/CO_TIME.h" #include "301/CO_PDO.h" #include "301/CO_HBconsumer.h" @@ -222,6 +221,9 @@ extern "C" { #endif /* CO_DOXYGEN */ +#if CO_NO_SYNC == 1 || defined CO_DOXYGEN + #include "301/CO_SYNC.h" +#endif #if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN #include "301/CO_SDOclient.h" #endif @@ -248,7 +250,9 @@ typedef struct { CO_EM_t *em; /**< Emergency report object */ CO_EMpr_t *emPr; /**< Emergency process object */ CO_NMT_t *NMT; /**< NMT object */ +#if CO_NO_SYNC == 1 || defined CO_DOXYGEN CO_SYNC_t *SYNC; /**< SYNC object */ +#endif CO_TIME_t *TIME; /**< TIME object */ CO_RPDO_t *RPDO[CO_NO_RPDO]; /**< RPDO objects */ CO_TPDO_t *TPDO[CO_NO_TPDO]; /**< TPDO objects */ From bd3326fed9eba4c229407fc02ef7cef3896ce364 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 5 Jun 2020 18:02:26 +0200 Subject: [PATCH 081/520] Make own file for CANopen status LED diodesLED indicator indication (CiA303-3) moved from NMT into own files. Now fully comply to standard. --- 301/CO_NMT_Heartbeat.c | 126 ++--------------------------- 301/CO_NMT_Heartbeat.h | 46 ++--------- 301/CO_config.h | 33 ++++++-- 301/CO_driver.h | 6 +- 303/CO_LEDs.c | 151 +++++++++++++++++++++++++++++++++++ 303/CO_LEDs.h | 151 +++++++++++++++++++++++++++++++++++ CANopen.c | 61 ++++++++++++++ CANopen.h | 16 ++++ Doxyfile | 1 + Makefile | 1 + doc/CHANGELOG.md | 1 + example/CO_driver_target.h | 13 ++- example/Makefile | 1 + example/main_blank.c | 4 + socketCAN/CO_driver_target.h | 13 ++- 15 files changed, 448 insertions(+), 176 deletions(-) create mode 100644 303/CO_LEDs.c create mode 100644 303/CO_LEDs.h diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 8ce755c5..8eb94357 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -23,12 +23,9 @@ * limitations under the License. */ - -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" -#include "301/CO_Emergency.h" #include "301/CO_NMT_Heartbeat.h" + /* * Read received message from CAN module. * @@ -105,6 +102,8 @@ CO_ReturnError_t CO_NMT_init( uint16_t HB_txIdx, uint16_t CANidTxHB) { + CO_ReturnError_t ret = CO_ERROR_NO; + /* verify arguments */ if (NMT == NULL || emPr == NULL || NMT_CANdevRx == NULL || HB_CANdevTx == NULL #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER @@ -114,36 +113,15 @@ CO_ReturnError_t CO_NMT_init( return CO_ERROR_ILLEGAL_ARGUMENT; } - CO_ReturnError_t ret = CO_ERROR_NO; - - /* blinking bytes and LEDS */ -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_LEDS - NMT->LEDtimer = 0; - NMT->LEDflickering = 0; - NMT->LEDblinking = 0; - NMT->LEDsingleFlash = 0; - NMT->LEDdoubleFlash = 0; - NMT->LEDtripleFlash = 0; - NMT->LEDquadrupleFlash = 0; - NMT->LEDgreenRun = -1; - NMT->LEDredError = 1; -#endif /* CO_CONFIG_NMT_LEDS */ + /* clear the object */ + memset(NMT, 0, sizeof(CO_NMT_t)); /* Configure object variables */ NMT->operatingState = CO_NMT_INITIALIZING; NMT->operatingStatePrev = CO_NMT_INITIALIZING; NMT->nodeId = nodeId; NMT->firstHBTime = (int32_t)firstHBTime_ms * 1000; - NMT->resetCommand = 0; - NMT->HBproducerTimer = 0; NMT->emPr = emPr; -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE - NMT->pFunctSignalPre = NULL; - NMT->functSignalObjectPre = NULL; -#endif -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE - NMT->pFunctNMT = NULL; -#endif /* configure NMT CAN reception */ ret = CO_CANrxBufferInit( @@ -229,7 +207,6 @@ CO_NMT_reset_cmd_t CO_NMT_process( uint32_t *timerNext_us) { uint8_t CANpassive; - CO_NMT_internalState_t currentOperatingState = NMT->operatingState; uint32_t HBtime = (uint32_t)HBtime_ms * 1000; @@ -242,8 +219,7 @@ CO_NMT_reset_cmd_t CO_NMT_process( if ((NMT->operatingState == CO_NMT_INITIALIZING) || (HBtime != 0 && (NMT->HBproducerTimer >= HBtime || NMT->operatingState != NMT->operatingStatePrev) - )) - { + )) { /* Start from the beginning. If OS is slow, time sliding may occur. However, * heartbeat is not for synchronization, it is for health report. */ NMT->HBproducerTimer = 0; @@ -269,85 +245,6 @@ CO_NMT_reset_cmd_t CO_NMT_process( if(CO_isError(NMT->emPr->em, CO_EM_CAN_TX_BUS_PASSIVE) || CO_isError(NMT->emPr->em, CO_EM_CAN_RX_BUS_PASSIVE)) CANpassive = 1; - -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_LEDS - NMT->LEDtimer += timeDifference_us; - if (NMT->LEDtimer >= 50000) { - NMT->LEDtimer -= 50000; - -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT - if (timerNext_us != NULL) { - uint32_t diff = 50000 - NMT->LEDtimer; - if (*timerNext_us > diff) { - *timerNext_us = diff; - } - } -#endif - - if (++NMT->LEDflickering >= 1) NMT->LEDflickering = -1; - - if (++NMT->LEDblinking >= 4) NMT->LEDblinking = -4; - - if (++NMT->LEDsingleFlash >= 4) NMT->LEDsingleFlash = -20; - - switch (++NMT->LEDdoubleFlash) { - case 4: NMT->LEDdoubleFlash = -104; break; - case -100: NMT->LEDdoubleFlash = 100; break; - case 104: NMT->LEDdoubleFlash = -20; break; - default: break; - } - - switch (++NMT->LEDtripleFlash) { - case 4: NMT->LEDtripleFlash = -104; break; - case -100: NMT->LEDtripleFlash = 100; break; - case 104: NMT->LEDtripleFlash = -114; break; - case -110: NMT->LEDtripleFlash = 110; break; - case 114: NMT->LEDtripleFlash = -20; break; - default: break; - } - - switch (++NMT->LEDquadrupleFlash) { - case 4: NMT->LEDquadrupleFlash = -104; break; - case -100: NMT->LEDquadrupleFlash = 100; break; - case 104: NMT->LEDquadrupleFlash = -114; break; - case -110: NMT->LEDquadrupleFlash = 110; break; - case 114: NMT->LEDquadrupleFlash = -124; break; - case -120: NMT->LEDquadrupleFlash = 120; break; - case 124: NMT->LEDquadrupleFlash = -20; break; - default: break; - } - } - - /* CANopen green RUN LED (DR 303-3) */ - switch(NMT->operatingState){ - case CO_NMT_STOPPED: NMT->LEDgreenRun = NMT->LEDsingleFlash; break; - case CO_NMT_PRE_OPERATIONAL: NMT->LEDgreenRun = NMT->LEDblinking; break; - case CO_NMT_OPERATIONAL: NMT->LEDgreenRun = 1; break; - default: break; - } - - - /* CANopen red ERROR LED (DR 303-3) */ - if(CO_isError(NMT->emPr->em, CO_EM_CAN_TX_BUS_OFF)) - NMT->LEDredError = 1; - - else if(CO_isError(NMT->emPr->em, CO_EM_SYNC_TIME_OUT)) - NMT->LEDredError = NMT->LEDtripleFlash; - - else if(CO_isError(NMT->emPr->em, CO_EM_HEARTBEAT_CONSUMER) || CO_isError(NMT->emPr->em, CO_EM_HB_CONSUMER_REMOTE_RESET)) - NMT->LEDredError = NMT->LEDdoubleFlash; - - else if(CANpassive || CO_isError(NMT->emPr->em, CO_EM_CAN_BUS_WARNING)) - NMT->LEDredError = NMT->LEDsingleFlash; - - else if(errorRegister) - NMT->LEDredError = (NMT->LEDblinking>=0)?-1:1; - - else - NMT->LEDredError = -1; -#endif /* CO_CONFIG_NMT_LEDS */ - - /* in case of error enter pre-operational state */ if(errorBehavior && (NMT->operatingState == CO_NMT_OPERATIONAL)){ if(CANpassive && (errorBehavior[2] == 0 || errorBehavior[2] == 2)) errorRegister |= 0x10; @@ -430,17 +327,6 @@ CO_NMT_reset_cmd_t CO_NMT_process( } -/******************************************************************************/ -CO_NMT_internalState_t CO_NMT_getInternalState( - CO_NMT_t *NMT) -{ - if(NMT != NULL){ - return NMT->operatingState; - } - return CO_NMT_INITIALIZING; -} - - #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER /******************************************************************************/ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 014699f7..5e235d5b 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -27,6 +27,7 @@ #ifndef CO_NMT_HEARTBEAT_H #define CO_NMT_HEARTBEAT_H +#include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" @@ -64,34 +65,9 @@ extern "C" { * 0 | #CO_NMT_internalState_t * * @see #CO_Default_CAN_ID_t - * - * ###Status LED diodes - * Macros for @ref CO_NMT_statusLEDdiodes are also implemented in this object. */ -/** - * @defgroup CO_NMT_statusLEDdiodes Status LED diodes - * @{ - * - * Macros for status LED diodes. - * - * Helper macros for implementing status LED diodes are used by stack and can - * also be used by the application. If macro returns 1 LED should be ON, - * otherwise OFF. Function CO_NMT_blinkingProcess50ms() must be called cyclically - * to update the variables. - */ - #define LED_FLICKERING(NMT) (((NMT)->LEDflickering>=0) ? 1 : 0) /**< 10HZ (100MS INTERVAL) */ - #define LED_BLINKING(NMT) (((NMT)->LEDblinking>=0) ? 1 : 0) /**< 2.5HZ (400MS INTERVAL) */ - #define LED_SINGLE_FLASH(NMT) (((NMT)->LEDsingleFlash>=0) ? 1 : 0) /**< 200MS ON, 1000MS OFF */ - #define LED_DOUBLE_FLASH(NMT) (((NMT)->LEDdoubleFlash>=0) ? 1 : 0) /**< 200MS ON, 200MS OFF, 200MS ON, 1000MS OFF */ - #define LED_TRIPLE_FLASH(NMT) (((NMT)->LEDtripleFlash>=0) ? 1 : 0) /**< 200MS ON, 200MS OFF, 200MS ON, 200MS OFF, 200MS ON, 1000MS OFF */ - #define LED_QUADRUPLE_FLASH(NMT)(((NMT)->LEDquadrupleFlash>=0) ? 1 : 0) /**< 200MS ON, 200MS OFF, 200MS ON, 200MS OFF, 200MS ON, 200MS OFF, 200MS ON, 1000MS OFF */ - #define LED_GREEN_RUN(NMT) (((NMT)->LEDgreenRun>=0) ? 1 : 0) /**< CANOPEN RUN LED ACCORDING TO CIA DR 303-3 */ - #define LED_RED_ERROR(NMT) (((NMT)->LEDredError>=0) ? 1 : 0) /**< CANopen error LED according to CiA DR 303-3 */ -/** @} */ - - /** * Internal network state of the CANopen node */ @@ -129,22 +105,9 @@ typedef enum{ /** - * NMT consumer and Heartbeat producer object. It includes also variables for - * @ref CO_NMT_statusLEDdiodes. Object is initialized by CO_NMT_init(). + * NMT consumer and Heartbeat producer object, initialized by CO_NMT_init() */ typedef struct{ -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_LEDS) || defined CO_DOXYGEN - uint32_t LEDtimer; /**< 50ms led timer */ - int8_t LEDflickering; /**< See @ref CO_NMT_statusLEDdiodes */ - int8_t LEDblinking; /**< See @ref CO_NMT_statusLEDdiodes */ - int8_t LEDsingleFlash; /**< See @ref CO_NMT_statusLEDdiodes */ - int8_t LEDdoubleFlash; /**< See @ref CO_NMT_statusLEDdiodes */ - int8_t LEDtripleFlash; /**< See @ref CO_NMT_statusLEDdiodes */ - int8_t LEDquadrupleFlash; /**< See @ref CO_NMT_statusLEDdiodes */ - int8_t LEDgreenRun; /**< See @ref CO_NMT_statusLEDdiodes */ - int8_t LEDredError; /**< See @ref CO_NMT_statusLEDdiodes */ -#endif /* CO_CONFIG_NMT_LEDS */ - CO_NMT_internalState_t operatingState; /**< Current NMT operating state. */ CO_NMT_internalState_t operatingStatePrev; /**< Previous NMT operating state. */ uint8_t resetCommand; /**< If different than zero, device will reset */ @@ -283,8 +246,9 @@ CO_NMT_reset_cmd_t CO_NMT_process( * * @return #CO_NMT_internalState_t */ -CO_NMT_internalState_t CO_NMT_getInternalState( - CO_NMT_t *NMT); +static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { + return (NMT == NULL) ? CO_NMT_INITIALIZING : NMT->operatingState; +} #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN diff --git a/301/CO_config.h b/301/CO_config.h index 0f34926c..d4bb7a32 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -97,15 +97,12 @@ extern "C" { * state changes. Callback is configured by * CO_NMT_initCallbackChanged(). * - CO_CONFIG_NMT_MASTER - Enable simple NMT master - * - CO_CONFIG_NMT_LEDS - Calculate CANopen blinking variables, which can - * be used for LEDs. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER | CO_CONFIG_NMT_LEDS) +#define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER0) #endif #define CO_CONFIG_NMT_CALLBACK_CHANGE 0x01 #define CO_CONFIG_NMT_MASTER 0x02 -#define CO_CONFIG_NMT_LEDS 0x04 /** @@ -281,21 +278,38 @@ extern "C" { #endif +/** + * Configuration of LEDs object + * + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_NMT_process(). + * - CO_CONFIG_LEDS_ENABLE - Enable calculation of the CANopen LED indicators. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_LEDS (CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_LEDS_ENABLE) +#endif +#define CO_CONFIG_LEDS_ENABLE 0x01 + + /** * Configuration of LSS objects * * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received SDO CAN message. + * received CAN message. * Callback is configured by CO_LSSmaster_initCallbackPre(). * - CO_CONFIG_LSS_SLAVE - Enable LSS slave + * - CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND - Send LSS fastscan respond + * directly from CO_LSSslave_receive() function. * - CO_CONFIG_LSS_MASTER - Enable LSS master */ #ifdef CO_DOXYGEN -#define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER) +#define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | CO_CONFIG_LSS_MASTER ) #endif #define CO_CONFIG_LSS_SLAVE 0x01 -#define CO_CONFIG_LSS_MASTER 0x02 +#define CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND 0x02 +#define CO_CONFIG_LSS_MASTER 0x10 /** @@ -317,9 +331,11 @@ extern "C" { * comments in gateway-ascii device for SDO and gateway errors. * - CO_CONFIG_GTW_ASCII_PRINT_HELP - use non-standard command "help" to print * help usage. + * - CO_CONFIG_GTW_ASCII_PRINT_LEDS - Display "red" and "green" CANopen status + * LED diodes on terminal. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | CO_CONFIG_GTW_ASCII | CO_CONFIG_GTW_ASCII_SDO | CO_CONFIG_GTW_ASCII_NMT | CO_CONFIG_GTW_ASCII_LSS | CO_CONFIG_GTW_ASCII_LOG | CO_CONFIG_GTW_ASCII_ERROR_DESC | CO_CONFIG_GTW_ASCII_PRINT_HELP) +#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | CO_CONFIG_GTW_ASCII | CO_CONFIG_GTW_ASCII_SDO | CO_CONFIG_GTW_ASCII_NMT | CO_CONFIG_GTW_ASCII_LSS | CO_CONFIG_GTW_ASCII_LOG | CO_CONFIG_GTW_ASCII_ERROR_DESC | CO_CONFIG_GTW_ASCII_PRINT_HELP | CO_CONFIG_GTW_ASCII_PRINT_LEDS) #endif #define CO_CONFIG_GTW_MULTI_NET 0x01 #define CO_CONFIG_GTW_ASCII 0x02 @@ -329,6 +345,7 @@ extern "C" { #define CO_CONFIG_GTW_ASCII_LOG 0x20 #define CO_CONFIG_GTW_ASCII_ERROR_DESC 0x40 #define CO_CONFIG_GTW_ASCII_PRINT_HELP 0x80 +#define CO_CONFIG_GTW_ASCII_PRINT_LEDS 0x100 /** diff --git a/301/CO_driver.h b/301/CO_driver.h index 1ac3b275..7a2a83a2 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -75,7 +75,11 @@ extern "C" { #endif #ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (0) +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE) +#endif + +#ifndef CO_CONFIG_LEDS +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE) #endif #ifndef CO_CONFIG_GTW diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c new file mode 100644 index 00000000..077cdf00 --- /dev/null +++ b/303/CO_LEDs.c @@ -0,0 +1,151 @@ +/* + * CANopen Indicator specification (CiA 303-3 v1.4.0) + * + * @file CO_LEDs.h + * @ingroup CO_LEDs + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "303/CO_LEDs.h" + + +/******************************************************************************/ +CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { + CO_ReturnError_t ret = CO_ERROR_NO; + + /* verify arguments */ + if (LEDs == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* clear the object */ + memset(LEDs, 0, sizeof(CO_LEDs_t)); + + return ret; +} + + +/******************************************************************************/ +void CO_LEDs_process(CO_LEDs_t *LEDs, + uint32_t timeDifference_us, + bool_t ErrCANbusOff, + bool_t ErrNodeId, + bool_t ErrRpdo, + bool_t ErrSync, + bool_t ErrHbCons, + bool_t ErrCANbusWarn, + bool_t ErrOther, + CO_NMT_internalState_t NMTstate, + bool_t LSSconfig, + bool_t firmwareDownload, + uint32_t *timerNext_us) +{ + uint8_t rd = 0; + uint8_t gr = 0; + bool_t tick = false; + + LEDs->LEDtmr50ms += timeDifference_us; + while (LEDs->LEDtmr50ms >= 50000) { + bool_t rdFlickerNext = (LEDs->LEDred & CO_LED_flicker) == 0; + + tick = true; + LEDs->LEDtmr50ms -= 50000; + + if (++LEDs->LEDtmr200ms > 3) { + /* calculate 2,5Hz blinking and flashing */ + LEDs->LEDtmr200ms = 0; + rd = gr = 0; + + if ((LEDs->LEDred & CO_LED_blink) == 0) rd |= CO_LED_blink; + else gr |= CO_LED_blink; + + switch (++LEDs->LEDtmrflash_1) { + case 1: rd |= CO_LED_flash_1; break; + case 2: gr |= CO_LED_flash_1; break; + case 6: LEDs->LEDtmrflash_1 = 0; break; + default: break; + } + switch (++LEDs->LEDtmrflash_2) { + case 1: case 3: rd |= CO_LED_flash_2; break; + case 2: case 4: gr |= CO_LED_flash_2; break; + case 8: LEDs->LEDtmrflash_2 = 0; break; + default: break; + } + switch (++LEDs->LEDtmrflash_3) { + case 1: case 3: case 5: rd |= CO_LED_flash_3; break; + case 2: case 4: case 6: gr |= CO_LED_flash_3; break; + case 10: LEDs->LEDtmrflash_3 = 0; break; + default: break; + } + switch (++LEDs->LEDtmrflash_4) { + case 1: case 3: case 5: case 7: rd |= CO_LED_flash_4; break; + case 2: case 4: case 6: case 8: gr |= CO_LED_flash_4; break; + case 12: LEDs->LEDtmrflash_4 = 0; break; + default: break; + } + } + else { + /* clear flicker bit, keep others */ + rd = LEDs->LEDred & (0xFF ^ CO_LED_flicker); + gr = LEDs->LEDgreen & (0xFF ^ CO_LED_flicker); + } + + /* calculate 10Hz flickering */ + if (rdFlickerNext) rd |= CO_LED_flicker; + else gr |= CO_LED_flicker; + + } /* while (LEDs->LEDtmr50ms >= 50000) */ + + if (tick) { + uint8_t rd_co, gr_co; + + /* CANopen red ERROR LED */ + if (ErrCANbusOff) rd_co = 1; + else if (ErrNodeId) rd_co = rd & CO_LED_flicker; + else if (ErrRpdo) rd_co = rd & CO_LED_flash_4; + else if (ErrSync) rd_co = rd & CO_LED_flash_3; + else if (ErrHbCons) rd_co = rd & CO_LED_flash_2; + else if (ErrCANbusWarn) rd_co = rd & CO_LED_flash_1; + else if (ErrOther) rd_co = rd & CO_LED_blink; + else rd_co = 0; + + /* CANopen green RUN LED */ + if (LSSconfig) gr_co = gr & CO_LED_flicker; + else if (firmwareDownload) gr_co = gr & CO_LED_flash_3; + else if (NMTstate == CO_NMT_STOPPED) gr_co = gr & CO_LED_flash_1; + else if (NMTstate == CO_NMT_PRE_OPERATIONAL)gr_co = gr & CO_LED_blink; + else if (NMTstate == CO_NMT_OPERATIONAL) gr_co = 1; + else gr_co = 0; + + if (rd_co != 0) rd |= CO_LED_CANopen; + if (gr_co != 0) gr |= CO_LED_CANopen; + LEDs->LEDred = rd; + LEDs->LEDgreen = gr; + } /* if (tick) */ + +#if (CO_CONFIG_LEDS) & CO_CONFIG_FLAG_TIMERNEXT + if (timerNext_us != NULL) { + uint32_t diff = 50000 - LEDs->LEDtmr50ms; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } +#endif +} diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h new file mode 100644 index 00000000..b3a6affe --- /dev/null +++ b/303/CO_LEDs.h @@ -0,0 +1,151 @@ +/** + * CANopen Indicator specification (CiA 303-3 v1.4.0) + * + * @file CO_LEDs.h + * @ingroup CO_LEDs + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CO_LEDS_H +#define CO_LEDS_H + +#include "301/CO_driver.h" +#include "301/CO_NMT_Heartbeat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_LEDs LED indicator specification + * @ingroup CO_CANopen_303 + * @{ + * + * CIA 303-3 standard specifies indicator LED diodes, which reflects state of + * the CANopen device. Green and red leds or bi-color led can be used. + * + * CANopen green led - run led: + * - flickering: LSS configuration state is active + * - blinking: device is in NMT pre-operational state + * - single flash: device is in NMT stopped state + * - triple flash: a software download is running in the device + * - on: device is in NMT operational state + * + * CANopen red led - error led: + * - off: no error + * - flickering: LSS node id is not configured, CANopen is not initialized + * - blinking: invalid configuration, general error + * - single flash: CAN warning limit reached + * - double flash: heartbeat consumer - error in remote monitored node + * - triple flash: sync message reception timeout + * - quadruple flash: PDO has not been received before the event timer elapsed + * - on: CAN bus off + * + * To apply on/off state to led diode, use #CO_LED_RED and #CO_LED_GREEN macros. + * For CANopen leds use CO_LED_BITFIELD_t CO_LED_CANopen. Other bitfields are + * available for implementing custom leds. + */ + +/** Bitfield for combining with red or green led */ +typedef enum { + CO_LED_flicker = 0x01, /**< LED flickering 10Hz */ + CO_LED_blink = 0x02, /**< LED blinking 2,5Hz */ + CO_LED_flash_1 = 0x04, /**< LED single flash */ + CO_LED_flash_2 = 0x08, /**< LED double flash */ + CO_LED_flash_3 = 0x10, /**< LED triple flash */ + CO_LED_flash_4 = 0x20, /**< LED quadruple flash */ + CO_LED_CANopen = 0x80 /**< LED CANopen according to CiA 303-3 */ +} CO_LED_BITFIELD_t; + +/** Get on/off state for green led for specified bitfield */ +#define CO_LED_RED(LEDs, BITFIELD) (((LEDs)->LEDred & BITFIELD) ? 1 : 0) +/** Get on/off state for green led for specified bitfield */ +#define CO_LED_GREEN(LEDs, BITFIELD) (((LEDs)->LEDgreen & BITFIELD) ? 1 : 0) + + +/** + * LEDs object, initialized by CO_LEDs_init() + */ +typedef struct{ + uint32_t LEDtmr50ms; /**< 50ms led timer */ + uint8_t LEDtmr200ms; /**< 200ms led timer */ + uint8_t LEDtmrflash_1; /**< single flash led timer */ + uint8_t LEDtmrflash_2; /**< double flash led timer */ + uint8_t LEDtmrflash_3; /**< triple flash led timer */ + uint8_t LEDtmrflash_4; /**< quadruple flash led timer */ + uint8_t LEDred; /**< red led #CO_LED_BITFIELD_t */ + uint8_t LEDgreen; /**< green led #CO_LED_BITFIELD_t */ +} CO_LEDs_t; + + +/** + * Initialize LEDs object. + * + * Function must be called in the communication reset section. + * + * @param LEDs This object will be initialized. + * + * @return #CO_ReturnError_t CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + */ +CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs); + + +/** + * Process indicator states + * + * Function must be called cyclically. + * + * @param LEDs This object. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. + * @param ErrCANbusOff CAN bus off indication (highest priority). + * @param ErrNodeId LSS unconfigured Node Id indication. + * @param ErrRpdo RPDO evnet timer timeout indication. + * @param ErrSync Sync receive timeout indication. + * @param ErrHbCons Heartbeat consumer error (remote node) indication. + * @param ErrCANbusWarn CAN error warning limit reached indication. + * @param ErrOther Other error indication (lowest priority). + * @param NMTstate NMT operating state. + * @param LSSconfig Node is in LSS configuration state indication. + * @param firmwareDownload Firmware download is in progress indication. + * @param [out] timerNext_us info to OS - see CO_process(). + */ +void CO_LEDs_process(CO_LEDs_t *LEDs, + uint32_t timeDifference_us, + bool_t ErrCANbusOff, + bool_t ErrNodeId, + bool_t ErrRpdo, + bool_t ErrSync, + bool_t ErrHbCons, + bool_t ErrCANbusWarn, + bool_t ErrOther, + CO_NMT_internalState_t NMTstate, + bool_t LSSconfig, + bool_t firmwareDownload, + uint32_t *timerNext_us); + +/** @} */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif diff --git a/CANopen.c b/CANopen.c index c875e14a..1be0e39e 100644 --- a/CANopen.c +++ b/CANopen.c @@ -50,6 +50,9 @@ static uint32_t *CO_traceTimeBuffers[CO_NO_TRACE]; static int32_t *CO_traceValueBuffers[CO_NO_TRACE]; static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #endif +#ifndef CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS +#define CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS 0 +#endif /* Verify number of CANopenNode objects from CO_OD.h **************************/ @@ -211,6 +214,13 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { CO_memoryUsed += sizeof(CO_SDOclient_t) * CO_NO_SDO_CLIENT; #endif +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + /* LEDs */ + CO->LEDs = (CO_LEDs_t *)calloc(1, sizeof(CO_LEDs_t)); + if (CO->LEDs == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_LEDs_t); +#endif + #if CO_NO_LSS_SLAVE == 1 /* LSSslave */ CO->LSSslave = (CO_LSSslave_t *)calloc(1, sizeof(CO_LSSslave_t)); @@ -377,6 +387,9 @@ void CO_delete(void *CANptr) { #if CO_NO_SDO_CLIENT != 0 static CO_SDOclient_t COO_SDOclient[CO_NO_SDO_CLIENT]; #endif +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + static CO_LEDs_t COO_LEDs; +#endif #if CO_NO_LSS_SLAVE == 1 static CO_LSSslave_t COO_LSSslave; #endif @@ -457,6 +470,11 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { } #endif +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + /* LEDs */ + CO->LEDs = &COO_LEDs; +#endif + #if CO_NO_LSS_SLAVE == 1 /* LSSslave */ CO->LSSslave = &COO_LSSslave; @@ -571,6 +589,18 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { } #endif +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + /* LEDs */ + err = CO_LEDs_init(CO->LEDs); + + if (err) return err; +#endif + +#if CO_NO_LSS_SLAVE == 1 + if (CO->nodeIdUnconfiguredLSS) { + return CO_ERROR_NO; + } +#endif /* SDOserver */ for (i = 0; i < CO_NO_SDO_SERVER; i++) { @@ -775,6 +805,9 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS CO->LSSmaster, +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS + CO->LEDs, #endif 0); if (err) return err; @@ -815,6 +848,34 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, bool_t NMTisPreOrOperational = false; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + CO_LEDs_process(co->LEDs, + timeDifference_us, + CO_isError(co->em, CO_EM_CAN_TX_BUS_OFF), + #if CO_NO_LSS_SLAVE == 1 + co->nodeIdUnconfiguredLSS, + #else + 0, + #endif + 0, /* RPDO event timer timeout */ + CO_isError(co->em, CO_EM_SYNC_TIME_OUT), + CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) + || CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET), + CO_isError(co->em, CO_EM_CAN_BUS_WARNING) + || CO_isError(co->em, CO_EM_CAN_TX_BUS_PASSIVE) + || CO_isError(co->em, CO_EM_CAN_RX_BUS_PASSIVE), + OD_errorRegister != 0, + co->NMT->operatingState, + #if CO_NO_LSS_SLAVE == 1 + CO_LSSslave_getState(co->LSSslave) + == CO_LSS_STATE_CONFIGURATION, + #else + 0, + #endif + CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS, + timerNext_us); +#endif /* (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE */ + if (co->NMT->operatingState == CO_NMT_PRE_OPERATIONAL || co->NMT->operatingState == CO_NMT_OPERATIONAL) NMTisPreOrOperational = true; diff --git a/CANopen.h b/CANopen.h index abcfea5a..4261e180 100644 --- a/CANopen.h +++ b/CANopen.h @@ -77,6 +77,16 @@ extern "C" { * @} */ +/** + * @defgroup CO_CANopen_303 CANopen_303 + * @{ + * + * CANopen recommendation for indicator specification (CiA 303-3 v1.4.0) + * + * Description of communication related indicators - green and red LED diodes. + * @} + */ + /** * @defgroup CO_CANopen_305 CANopen_305 * @{ @@ -230,6 +240,9 @@ extern "C" { #if CO_NO_LSS_SLAVE != 0 || defined CO_DOXYGEN #include "305/CO_LSSslave.h" #endif +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN + #include "303/CO_LEDs.h" +#endif #if CO_NO_LSS_MASTER != 0 || defined CO_DOXYGEN #include "305/CO_LSSmaster.h" #endif @@ -260,6 +273,9 @@ typedef struct { #if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */ #endif +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN + CO_LEDs_t *LEDs; /**< LEDs object */ +#endif #if CO_NO_LSS_SLAVE == 1 || defined CO_DOXYGEN CO_LSSslave_t *LSSslave; /**< LSS slave object */ #endif diff --git a/Doxyfile b/Doxyfile index 61d7c832..77fd7495 100644 --- a/Doxyfile +++ b/Doxyfile @@ -784,6 +784,7 @@ INPUT = README.md \ doc \ CANopen.h \ 301 \ + 303 \ 305 \ 309 \ extra \ diff --git a/Makefile b/Makefile index 41899cb1..43856864 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ SOURCES = \ $(CANOPEN_SRC)/301/CO_SDOclient.c \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ $(CANOPEN_SRC)/301/CO_fifo.c \ + $(CANOPEN_SRC)/303/CO_LEDs.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ $(CANOPEN_SRC)/305/CO_LSSmaster.c \ $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 77287d5d..f294f8e0 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -21,6 +21,7 @@ Change Log - Add emergency receive callback also for own emergency messages. - Heartbeat is send immediately after NMT state changes. - SDO client is rewritten. Now includes read/write fifo interface to transfer data. +- LED indicator indication (CiA303-3) moved from NMT into own files. Now fully comply to standard. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN - driver API updated diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 01663447..e6366a77 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -48,8 +48,7 @@ extern "C" { #define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ CO_CONFIG_NMT_CALLBACK_CHANGE | \ - CO_CONFIG_NMT_MASTER | \ - CO_CONFIG_NMT_LEDS) + CO_CONFIG_NMT_MASTER) #endif #ifndef CO_CONFIG_SDO @@ -106,8 +105,15 @@ extern "C" { #define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) #endif +#ifndef CO_CONFIG_LEDS +#define CO_CONFIG_LEDS (CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_LEDS_ENABLE) +#endif + #ifndef CO_CONFIG_LSS #define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_LSS_SLAVE | \ + CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ CO_CONFIG_LSS_MASTER) #endif @@ -118,7 +124,8 @@ extern "C" { CO_CONFIG_GTW_ASCII_LSS | \ CO_CONFIG_GTW_ASCII_LOG | \ CO_CONFIG_GTW_ASCII_ERROR_DESC | \ - CO_CONFIG_GTW_ASCII_PRINT_HELP) + CO_CONFIG_GTW_ASCII_PRINT_HELP | \ + CO_CONFIG_GTW_ASCII_PRINT_LEDS) #define CO_CONFIG_GTW_BLOCK_DL_LOOP 1 #define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 #define CO_CONFIG_GTWA_LOG_BUF_SIZE 2000 diff --git a/example/Makefile b/example/Makefile index dc3a9a11..ca8aba45 100644 --- a/example/Makefile +++ b/example/Makefile @@ -30,6 +30,7 @@ SOURCES = \ $(CANOPEN_SRC)/301/CO_SDOclient.c \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ $(CANOPEN_SRC)/301/CO_fifo.c \ + $(CANOPEN_SRC)/303/CO_LEDs.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ $(CANOPEN_SRC)/305/CO_LSSmaster.c \ $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ diff --git a/example/main_blank.c b/example/main_blank.c index d37718dd..24a85fb8 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -39,6 +39,8 @@ /* Global variables and objects */ volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */ + uint8_t LED_red, LED_green; + /* main ***********************************************************************/ @@ -116,6 +118,8 @@ int main (void){ /* CANopen process */ reset = CO_process(CO, (uint32_t)timer1msDiff*1000, NULL); + LED_red = CO_LED_RED(CO->LEDs, CO_LED_CANopen); + LED_green = CO_LED_GREEN(CO->LEDs, CO_LED_CANopen); /* Nonblocking application code may go here. */ diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 72f1b9a0..38a41387 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -56,8 +56,7 @@ extern "C" { #define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ CO_CONFIG_NMT_CALLBACK_CHANGE | \ - CO_CONFIG_NMT_MASTER | \ - CO_CONFIG_NMT_LEDS) + CO_CONFIG_NMT_MASTER) #endif #ifndef CO_CONFIG_SDO @@ -112,8 +111,15 @@ extern "C" { #define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) #endif +#ifndef CO_CONFIG_LEDS +#define CO_CONFIG_LEDS (CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_LEDS_ENABLE) +#endif + #ifndef CO_CONFIG_LSS #define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_LSS_SLAVE | \ + CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ CO_CONFIG_LSS_MASTER) #endif @@ -124,7 +130,8 @@ extern "C" { CO_CONFIG_GTW_ASCII_LSS | \ CO_CONFIG_GTW_ASCII_LOG | \ CO_CONFIG_GTW_ASCII_ERROR_DESC | \ - CO_CONFIG_GTW_ASCII_PRINT_HELP) + CO_CONFIG_GTW_ASCII_PRINT_HELP | \ + CO_CONFIG_GTW_ASCII_PRINT_LEDS) #define CO_CONFIG_GTW_BLOCK_DL_LOOP 3 #define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 #define CO_CONFIG_GTWA_LOG_BUF_SIZE 10000 From ae1b66e6ea58e1748e4b3e071239e1d24043bee7 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 5 Jun 2020 22:23:45 +0200 Subject: [PATCH 082/520] Gateway - command interface: update help strings, add status LED indication --- 309/CO_gateway_ascii.c | 165 +++++++++++++++++++++++++++++++++-------- 309/CO_gateway_ascii.h | 76 ++++++++++++++----- doc/gettingStarted.md | 1 + 3 files changed, 191 insertions(+), 51 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 71373c2e..856fc48e 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -45,6 +45,9 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN CO_LSSmaster_t *LSSmaster, +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) || defined CO_DOXYGEN + CO_LEDs_t *LEDs, #endif uint8_t dummy) { @@ -59,14 +62,18 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS || LSSmaster == NULL +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS + || LEDs == NULL #endif ) { return CO_ERROR_ILLEGAL_ARGUMENT; } + /* clear the object */ + memset(gtwa, 0, sizeof(CO_GTWA_t)); + /* initialize variables */ - gtwa->readCallback = NULL; - gtwa->readCallbackObject = NULL; #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO gtwa->SDO_C = SDO_C; gtwa->SDOtimeoutTime = SDOtimeoutTimeDefault; @@ -77,13 +84,13 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS gtwa->LSSmaster = LSSmaster; +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS + gtwa->LEDs = LEDs; #endif gtwa->net_default = -1; gtwa->node_default = -1; gtwa->state = CO_GTWA_ST_IDLE; - gtwa->timeDifference_us_cumulative = 0; - gtwa->respBufOffset = 0; - gtwa->respBufCount = 0; gtwa->respHold = false; CO_fifo_init(>wa->commFifo, @@ -132,9 +139,9 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { * HELPER FUNCTIONS ******************************************************************************/ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP -/* help string */ -static const char *CO_GTWA_helpString = -"Command strings start with '\"[\"\"]\"' followed by:\n" \ +/* help strings */ +static const char CO_GTWA_helpString[] = +"\nCommand strings start with '\"[\"\"]\"' followed by:\n" \ "[[] ] r[ead] [] # SDO upload.\n" \ "[[] ] w[rite] # SDO download.\n" \ "\n" \ @@ -149,10 +156,25 @@ static const char *CO_GTWA_helpString = "[] set sdo_timeout # Configure SDO time-out.\n" \ "[] set sdo_block # Enable/disable SDO block transfer.\n" \ "\n" \ -"help # Print this help.\n" \ +"help [datatype|lss] # Print this or datatype or lss help.\n" \ +"led # Print status LED diodes.\n" \ "log # Print message log.\n" \ "\n" \ -"Datatypes:\n" \ +"Response:\n" \ +"\"[\"\"]\" OK | |\n" \ +" ERROR: | ERROR:\n" \ +"\n" \ +"* Every command must be terminated with ('\\r\\n'). characters. Same\n" \ +" is response. String is not null terminated, is optional in command.\n" \ +"* Comments started with '#' are ignored. They may be on the beginning of the\n" \ +" line or after the command string.\n" \ +"* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is\n" \ +" disabled by default.\n" \ +"* If '' or '' is not specified within commands, then value defined\n" \ +" by 'set network' or 'set node' command is used.\r\n"; + +static const char CO_GTWA_helpStringDatatypes[] = +"\nDatatypes:\n" \ "b # Boolean.\n" \ "i8, i16, i32, i64 # Signed integers.\n" \ "u8, u16, u32, u64 # Unsigned integers.\n" \ @@ -160,27 +182,45 @@ static const char *CO_GTWA_helpString = "r32, r64 # Real numbers.\n" \ "t, td # Time of day, time difference.\n" \ "vs # Visible string (between double quotes if multi-word).\n" \ -"os, us, d # Octet string, unicode string, domain (mime-base64\n" \ -" # (RFC2045) based, one line).\n" \ -"hex # Hexagonal data, optionally space separated, non-standard.\n" \ -"\n" \ -"Response:\n" \ -"\"[\"\"]\" OK | |\n" \ -" ERROR: | ERROR:\n" \ -"\n" \ -"Every command must be terminated with ('\\r\\n'). characters. Same is\n" \ -"response. String is not null terminated, is optional in command.\n" \ +"os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line).\n" \ +"d # domain (mime-base64 (RFC2045) based, one line).\n" \ +"hex # Hexagonal data, optionally space separated, non-standard.\r\n"; + +static const char CO_GTWA_helpStringLss[] = +"\nLSS commands:\n" \ +"lss_switch_glob <0|1> # Switch state global command.\n" \ +"lss_switch_sel \\\n" \ +" #Switch state selective.\n" \ +"lss_set_node # Configure node-ID.\n" \ +"lss_conf_bitrate \\\n" \ +" # Configure bit-rate.\n" \ +"lss_activate_bitrate # Activate new bit-rate.\n" \ +"lss_store # LSS store configuration.\n" \ +"lss_inquire_addr [] # Inquire LSS address.\n" \ +"lss_get_node # Inquire node-ID.\n" \ +"_lss_fastscan [] # Identify fastscan, non-standard.\n" \ +"lss_allnodes [ [ \\\n" \ +" \\\n" \ +" ]]\n" \ +" # Node-ID configuration of all nodes.\n" \ "\n" \ -"Comments started with '#' are ignored. They may be on the beginning of the\n" \ -"line or after the command string.\n" \ +": 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\n" \ +" 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\n" \ "\n" \ -"'sdo_timeout' is in milliseconds, 500 by default. Block transfer is disabled\n" \ -"by default.\n" \ -"\n" \ -"If '' or '' is not specified within commands, then value defined by\n" \ -"'set network' or 'set node' command is used.\r\n"; +"All LSS commands start with '\"[\"\"]\" []'.\r\n"; #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS +#define CO_GTWA_LED_PRINTOUTS_SIZE 5 +static const char *CO_GTWA_LED_PRINTOUTS[CO_GTWA_LED_PRINTOUTS_SIZE] = { + " CANopen status LEDs: R G \r", + " CANopen status LEDs: R G* \r", + " CANopen status LEDs: R* G \r", + " CANopen status LEDs: R* G* \r", + " \r" +}; +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */ + /* Get uint32 number from token, verify limits and set *err if necessary */ static inline uint32_t getU32(char *token, uint32_t min, @@ -1260,7 +1300,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* continue with state machine */ gtwa->state = CO_GTWA_ST__LSS_FASTSCAN; } - /* LSS complete node-ID configuration command - 'lss_allnodes + /* LSS complete node-ID configuration command - 'lss_allnodes * [ [ * * ]]' */ @@ -1361,6 +1401,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG /* Print message log */ else if (strcmp(tok, "log") == 0) { + if (closed == 0) { + err = true; + break; + } gtwa->state = CO_GTWA_ST_LOG; } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ @@ -1368,11 +1412,45 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP /* Print help */ else if (strcmp(tok, "help") == 0) { + if (closed == 1) { + gtwa->helpString = CO_GTWA_helpString; + } + else { + /* get second token */ + closed = 1; + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + if (err) break; + + convertToLower(tok, sizeof(tok)); + if (strcmp(tok, "datatype") == 0) { + gtwa->helpString = CO_GTWA_helpStringDatatypes; + } + else if (strcmp(tok, "lss") == 0) { + gtwa->helpString = CO_GTWA_helpStringLss; + } + else { + err = true; + break; + } + } + /* continue with state machine */ gtwa->helpStringOffset = 0; gtwa->state = CO_GTWA_ST_HELP; } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP */ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS + /* Print status led diodes */ + else if (strcmp(tok, "led") == 0) { + if (closed == 0) { + err = true; + break; + } + gtwa->ledStringPreviousIndex = 0xFF; + gtwa->state = CO_GTWA_ST_LED; + } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */ + /* Unrecognized command */ else { respErrorCode = CO_GTWA_respErrorReqNotSupported; @@ -1817,15 +1895,15 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* Print help string (in multiple segments if necessary) */ else if (gtwa->state == CO_GTWA_ST_HELP) { size_t lenBuf = CO_GTWA_RESP_BUF_SIZE; - size_t lenHelp = strlen(CO_GTWA_helpString); + size_t lenHelp = strlen(gtwa->helpString); do { size_t lenHelpRemain = lenHelp - gtwa->helpStringOffset; size_t lenCopied = lenBuf < lenHelpRemain ? lenBuf : lenHelpRemain; memcpy(gtwa->respBuf, - &CO_GTWA_helpString[gtwa->helpStringOffset], - lenCopied); + >wa->helpString[gtwa->helpStringOffset], + lenCopied); gtwa->respBufCount = lenCopied; gtwa->helpStringOffset += lenCopied; @@ -1839,6 +1917,31 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS + /* print CANopen status LED diodes */ + else if (gtwa->state == CO_GTWA_ST_LED) { + uint8_t i; + + if (CO_fifo_CommSearch(>wa->commFifo, false)) { + gtwa->state = CO_GTWA_ST_IDLE; + i = 4; + } + else { + i = CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2 + + CO_LED_GREEN(gtwa->LEDs, CO_LED_CANopen); + } + if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1)) + i = CO_GTWA_LED_PRINTOUTS_SIZE - 1; + + if (i != gtwa->ledStringPreviousIndex) { + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "%s", CO_GTWA_LED_PRINTOUTS[i]); + respBufTransfer(gtwa); + gtwa->ledStringPreviousIndex = i; + } + } +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */ + /* illegal state */ else if (gtwa->state != CO_GTWA_ST_IDLE) { respErrorCode = CO_GTWA_respErrorInternalState; diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index a9935841..1c11f8d0 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -40,6 +40,9 @@ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS #include "305/CO_LSSmaster.h" #endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS +#include "303/CO_LEDs.h" +#endif #ifdef __cplusplus extern "C" { @@ -88,9 +91,23 @@ Command strings start with '"[""]"' followed by: [] set sdo_timeout # Configure SDO time-out. [] set sdo_block # Enable/disable SDO block transfer. -help # Print this help. +help [datatype|lss] # Print this or datatype or lss help. +led # Print status LED diodes. log # Print message log. +Response: +"[""]" OK | | + ERROR: | ERROR: + +* Every command must be terminated with ('\\r\\n'). characters. Same + is response. String is not null terminated, is optional in command. +* Comments started with '#' are ignored. They may be on the beginning of the + line or after the command string. +* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is + disabled by default. +* If '' or '' is not specified within commands, then value defined + by 'set network' or 'set node' command is used. + Datatypes: b # Boolean. i8, i16, i32, i64 # Signed integers. @@ -99,25 +116,31 @@ x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard. r32, r64 # Real numbers. t, td # Time of day, time difference. vs # Visible string (between double quotes if multi-word). -os, us, d # Octet string, unicode string, domain (mime-base64 - # (RFC2045) based, one line). +os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line). +d # domain (mime-base64 (RFC2045) based, one line). hex # Hexagonal data, optionally space separated, non-standard. -Response: -"[""]" OK | | - ERROR: | ERROR: - -Every command must be terminated with ('\\r\\n'). characters. Same is -response. String is not null terminated, is optional in command. - -Comments started with '#' are ignored. They may be on the beginning of the -line or after the command string. - -'sdo_timeout' is in milliseconds, 500 by default. Block transfer is disabled -by default. - -If '' or '' is not specified within commands, then value defined by -'set network' or 'set node' command is used. +LSS commands: +lss_switch_glob <0|1> # Switch state global command. +lss_switch_sel \\ + #Switch state selective. +lss_set_node # Configure node-ID. +lss_conf_bitrate \\ + # Configure bit-rate. +lss_activate_bitrate # Activate new bit-rate. +lss_store # LSS store configuration. +lss_inquire_addr [] # Inquire LSS address. +lss_get_node # Inquire node-ID. +_lss_fastscan [] # Identify fastscan, non-standard. +lss_allnodes [ [ \\ + \\ + ]] + # Node-ID configuration of all nodes. + +: 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s, + 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto + +All LSS commands start with '"[""]" []'. * @endcode * * This help text is the same as variable contents in CO_GTWA_helpString. @@ -231,10 +254,12 @@ typedef enum { CO_GTWA_ST__LSS_FASTSCAN = 0x30U, /** LSS 'lss_allnodes' */ CO_GTWA_ST_LSS_ALLNODES = 0x31U, - /** print message log */ + /** print message 'log' */ CO_GTWA_ST_LOG = 0x80U, /** print 'help' text */ - CO_GTWA_ST_HELP = 0x90U + CO_GTWA_ST_HELP = 0x81U, + /** print 'status' of the node */ + CO_GTWA_ST_LED = 0x82U } CO_GTWA_state_t; @@ -360,8 +385,14 @@ typedef struct { #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) || defined CO_DOXYGEN /** Offset, when printing help text */ + const char *helpString; size_t helpStringOffset; #endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) || defined CO_DOXYGEN + /** CO_LEDs_t object for CANopen status LEDs imitation from CO_GTWA_init()*/ + CO_LEDs_t *LEDs; + uint8_t ledStringPreviousIndex; +#endif } CO_GTWA_t; @@ -374,6 +405,8 @@ typedef struct { * @param SDOblockTransferEnableDefault true or false * @param NMT NMT object * @param LSSmaster LSS master object + * @param LEDs LEDs object + * @param dummy dummy argument, set to 0 * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT */ @@ -388,6 +421,9 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN CO_LSSmaster_t *LSSmaster, +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) || defined CO_DOXYGEN + CO_LEDs_t *LEDs, #endif uint8_t dummy); diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index 4295bfc5..3056235a 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -91,6 +91,7 @@ Now you should see in second terminal (_candump_) two CANopen devices sending he Second instance of _canopend_ was started with command interface enabled. This is CANopen gateway interface with ascii mapping, as specified in standard CiA309-3. This enables usage of CANopen master functionalities via basic terminal. Go to third terminal, type "help" and press enter to see its functionalities. help + help datatype #### SDO client For example read Heartbeat producer parameter on CANopen device with ID=4. Parameter is located at index 0x1017, subindex 0, it is 16-bit unsigned integer. From dd1677b5bc3d0feda9a3b76da00f5ae8851be406 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 9 Jun 2020 14:55:07 +0200 Subject: [PATCH 083/520] Integrate LSS slave into CANopenNode more directly. - CO_LSSslave: move expensive code from CAN receive (interrupt) to mainline CO_LSSslave_process() function. - LSS slave now runs in parallel to other CANopen objects. - LSS slave and master can run both on same device. - LSS slave, LSS master and gateway-ascii(CiA309) LSS functions tested. - LSSusage.md updated. --- 301/CO_driver.h | 5 +- 305/CO_LSS.h | 10 - 305/CO_LSSmaster.h | 2 +- 305/CO_LSSslave.c | 716 ++++++++++++++++------------------- 305/CO_LSSslave.h | 311 +++++---------- 309/CO_gateway_ascii.c | 43 ++- 309/CO_gateway_ascii.h | 12 +- CANopen.c | 75 +++- CANopen.h | 19 +- doc/CHANGELOG.md | 1 + doc/LSSusage.md | 97 +++-- doc/gettingStarted.md | 2 +- example/main_blank.c | 28 +- socketCAN/CO_Linux_threads.c | 39 +- socketCAN/CO_Linux_threads.h | 44 +-- socketCAN/CO_main_basic.c | 112 ++++-- 16 files changed, 713 insertions(+), 803 deletions(-) diff --git a/301/CO_driver.h b/301/CO_driver.h index 7a2a83a2..21ce302e 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -501,7 +501,10 @@ typedef enum { CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current state */ CO_ERROR_SYSCALL = -17, /**< Syscall failed */ - CO_ERROR_INVALID_STATE = -18 /**< Driver not ready */ + CO_ERROR_INVALID_STATE = -18, /**< Driver not ready */ + CO_ERROR_NODE_ID_UNCONFIGURED_LSS = -19 /**< Node-id is in LSS unconfigured + state. If objects are handled properly, + this may not be an error. */ } CO_ReturnError_t; diff --git a/305/CO_LSS.h b/305/CO_LSS.h index b5fbab8c..c3992b46 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -94,16 +94,6 @@ typedef enum { CO_LSS_INQUIRE_NODE_ID = 0x5EU, /**< Inquire node-ID protocol */ } CO_LSS_cs_t; -/** - * Macro to get service type group from command specifier - * @{*/ -#define CO_LSS_CS_SERVICE_IS_SWITCH_GLOBAL(cs) (cs == CO_LSS_SWITCH_STATE_GLOBAL) -#define CO_LSS_CS_SERVICE_IS_SWITCH_STATE_SELECTIVE(cs) (cs >= CO_LSS_SWITCH_STATE_SEL_VENDOR && cs <= CO_LSS_SWITCH_STATE_SEL) -#define CO_LSS_CS_SERVICE_IS_CONFIG(cs) (cs >= CO_LSS_CFG_NODE_ID && cs <= CO_LSS_CFG_STORE) -#define CO_LSS_CS_SERVICE_IS_INQUIRE(cs) (cs >= CO_LSS_INQUIRE_VENDOR && cs <= CO_LSS_INQUIRE_NODE_ID) -#define CO_LSS_CS_SERVICE_IS_IDENT(cs) (cs==CO_LSS_IDENT_SLAVE || cs==CO_LSS_IDENT_FASTSCAN) -/**@}*/ - /** * Error codes for Configure node ID protocol */ diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 5047e9e6..bf5ad402 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -105,7 +105,7 @@ typedef enum { * LSS master object. */ typedef struct{ - uint16_t timeout_us; /**< LSS response timeout in us */ + uint32_t timeout_us; /**< LSS response timeout in us */ uint8_t state; /**< Node is currently selected */ uint8_t command; /**< Active command */ diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 0ad12641..7acb3704 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -4,6 +4,7 @@ * @file CO_LSSslave.c * @ingroup CO_LSS * @author Martin Wagner + * @author Janez Paternoster * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * * @@ -30,341 +31,156 @@ #include "301/CO_SDOserver.h" /* for helper functions */ #include "305/CO_LSSslave.h" -/* - * Helper function - Handle service "switch state global" - */ -static void CO_LSSslave_serviceSwitchStateGlobal( - CO_LSSslave_t *LSSslave, - CO_LSS_cs_t service, - void *msg) -{ - (void)service; /* unused */ - - uint8_t *data = CO_CANrxMsg_readData(msg); - uint8_t mode = data[1]; - - switch (mode) { - case CO_LSS_STATE_WAITING: - LSSslave->lssState = CO_LSS_STATE_WAITING; - memset(&LSSslave->lssSelect, 0, sizeof(LSSslave->lssSelect)); - break; - case CO_LSS_STATE_CONFIGURATION: - LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; - break; - default: - break; - } -} - -/* - * Helper function - Handle service "switch state selective" - */ -static void CO_LSSslave_serviceSwitchStateSelective( - CO_LSSslave_t *LSSslave, - CO_LSS_cs_t service, - void *msg) -{ - uint32_t value; - uint8_t *data = CO_CANrxMsg_readData(msg); - CO_memcpySwap4(&value, &data[1]); - - if(LSSslave->lssState != CO_LSS_STATE_WAITING) { - return; - } - - switch (service) { - case CO_LSS_SWITCH_STATE_SEL_VENDOR: - LSSslave->lssSelect.identity.vendorID = value; - break; - case CO_LSS_SWITCH_STATE_SEL_PRODUCT: - LSSslave->lssSelect.identity.productCode = value; - break; - case CO_LSS_SWITCH_STATE_SEL_REV: - LSSslave->lssSelect.identity.revisionNumber = value; - break; - case CO_LSS_SWITCH_STATE_SEL_SERIAL: - LSSslave->lssSelect.identity.serialNumber = value; - - if (CO_LSS_ADDRESS_EQUAL(LSSslave->lssAddress, LSSslave->lssSelect)) { - LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; - - /* send confirmation */ - LSSslave->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL; - memset(&LSSslave->TXbuff->data[1], 0, sizeof(LSSslave->TXbuff->data) - 1); - CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); - } - break; - default: - break; - } -} /* - * Helper function - Handle service "configure" + * Read received message from CAN module. * - * values inside message have different meaning, depending on the selected - * configuration type + * Function will be called (by CAN receive interrupt) every time, when CAN + * message with correct identifier will be received. For more information and + * description of parameters see file CO_driver.h. */ -static void CO_LSSslave_serviceConfig( - CO_LSSslave_t *LSSslave, - CO_LSS_cs_t service, - void *msg) +static void CO_LSSslave_receive(void *object, void *msg) { - uint8_t nid; - uint8_t tableSelector; - uint8_t tableIndex; - uint8_t errorCode; - uint8_t *data; - - if(LSSslave->lssState != CO_LSS_STATE_CONFIGURATION) { - return; - } - - data = CO_CANrxMsg_readData(msg); + CO_LSSslave_t *LSSslave = (CO_LSSslave_t*)object; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); - switch (service) { - case CO_LSS_CFG_NODE_ID: - nid = data[1]; - errorCode = CO_LSS_CFG_NODE_ID_OK; + if(DLC == 8U && !CO_FLAG_READ(LSSslave->sendResponse)) { + bool_t request_LSSslave_process = false; + uint8_t *data = CO_CANrxMsg_readData(msg); + CO_LSS_cs_t cs = (CO_LSS_cs_t) data[0]; - if (CO_LSS_NODE_ID_VALID(nid)) { - LSSslave->pendingNodeID = nid; + if (cs == CO_LSS_SWITCH_STATE_GLOBAL) { + uint8_t mode = data[1]; + + switch (mode) { + case CO_LSS_STATE_WAITING: + if (LSSslave->lssState == CO_LSS_STATE_CONFIGURATION && + LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT && + *LSSslave->pendingNodeID != CO_LSS_NODE_ID_ASSIGNMENT) + { + /* Slave process function will request NMT Reset comm.*/ + LSSslave->service = cs; + request_LSSslave_process = true; + } + LSSslave->lssState = CO_LSS_STATE_WAITING; + memset(&LSSslave->lssSelect, 0, + sizeof(LSSslave->lssSelect)); + break; + case CO_LSS_STATE_CONFIGURATION: + LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; + break; + default: + break; } - else { - errorCode = CO_LSS_CFG_NODE_ID_OUT_OF_RANGE; - } - - /* send confirmation */ - LSSslave->TXbuff->data[0] = CO_LSS_CFG_NODE_ID; - LSSslave->TXbuff->data[1] = errorCode; - /* we do not use spec-error, always 0 */ - memset(&LSSslave->TXbuff->data[2], 0, sizeof(LSSslave->TXbuff->data) - 2); - CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); - break; - case CO_LSS_CFG_BIT_TIMING: - if (LSSslave->pFunctLSScheckBitRate == NULL) { - /* setting bit timing is not supported. Drop request */ + } + else if(LSSslave->lssState == CO_LSS_STATE_WAITING) { + switch (cs) { + case CO_LSS_SWITCH_STATE_SEL_VENDOR: { + CO_memcpySwap4(&LSSslave->lssSelect.identity.vendorID, + &data[1]); break; } - - tableSelector = data[1]; - tableIndex = data[2]; - errorCode = CO_LSS_CFG_BIT_TIMING_OK; - - if (tableSelector==0 && CO_LSS_BIT_TIMING_VALID(tableIndex)) { - uint16_t bit = CO_LSS_bitTimingTableLookup[tableIndex]; - bool_t bit_rate_supported = LSSslave->pFunctLSScheckBitRate( - LSSslave->functLSScheckBitRateObject, bit); - - if (bit_rate_supported) { - LSSslave->pendingBitRate = bit; - } - else { - errorCode = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; - } - } - else { - /* we currently only support CiA301 bit timing table */ - errorCode = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; - } - - /* send confirmation */ - LSSslave->TXbuff->data[0] = CO_LSS_CFG_BIT_TIMING; - LSSslave->TXbuff->data[1] = errorCode; - /* we do not use spec-error, always 0 */ - memset(&LSSslave->TXbuff->data[2], 0, sizeof(LSSslave->TXbuff->data) - 2); - CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); - break; - case CO_LSS_CFG_ACTIVATE_BIT_TIMING: - if (LSSslave->pFunctLSScheckBitRate == NULL) { - /* setting bit timing is not supported. Drop request */ + case CO_LSS_SWITCH_STATE_SEL_PRODUCT: { + CO_memcpySwap4(&LSSslave->lssSelect.identity.productCode, + &data[1]); break; } - - /* notify application */ - if (LSSslave->pFunctLSSactivateBitRate != NULL) { - uint16_t delay; - CO_memcpySwap2(&delay, &data[1]); - LSSslave->pFunctLSSactivateBitRate( - LSSslave->functLSSactivateBitRateObject, delay); + case CO_LSS_SWITCH_STATE_SEL_REV: { + CO_memcpySwap4(&LSSslave->lssSelect.identity.revisionNumber, + &data[1]); + break; } - break; - case CO_LSS_CFG_STORE: - errorCode = CO_LSS_CFG_STORE_OK; - - if (LSSslave->pFunctLSScfgStore == NULL) { - /* storing is not supported. Reply error */ - errorCode = CO_LSS_CFG_STORE_NOT_SUPPORTED; + case CO_LSS_SWITCH_STATE_SEL_SERIAL: { + CO_memcpySwap4(&LSSslave->lssSelect.identity.serialNumber, + &data[1]); + + if (CO_LSS_ADDRESS_EQUAL(LSSslave->lssAddress, + LSSslave->lssSelect) + ) { + LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; + LSSslave->service = cs; + request_LSSslave_process = true; + } + break; } - else { - bool_t result; - /* Store "pending" to "persistent" */ - result = LSSslave->pFunctLSScfgStore(LSSslave->functLSScfgStore, - LSSslave->pendingNodeID, LSSslave->pendingBitRate); - if (!result) { - errorCode = CO_LSS_CFG_STORE_FAILED; + case CO_LSS_IDENT_FASTSCAN: { + /* fastscan is only active on unconfigured nodes */ + if (*LSSslave->pendingNodeID == CO_LSS_NODE_ID_ASSIGNMENT && + LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT) + { + uint8_t bitCheck = data[5]; + uint8_t lssSub = data[6]; + uint8_t lssNext = data[7]; + uint32_t idNumber; + bool_t ack; + + if (!CO_LSS_FASTSCAN_BITCHECK_VALID(bitCheck) || + !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssSub) || + !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssNext)) { + /* Invalid request */ + break; + } + + CO_memcpySwap4(&idNumber, &data[1]); + ack = false; + + if (bitCheck == CO_LSS_FASTSCAN_CONFIRM) { + /* Confirm, Reset */ + ack = true; + LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; + memset(&LSSslave->lssFastscan, 0, + sizeof(LSSslave->lssFastscan)); + } + else if (LSSslave->fastscanPos == lssSub) { + uint32_t mask = 0xFFFFFFFF << bitCheck; + + if ((LSSslave->lssAddress.addr[lssSub] & mask) + == (idNumber & mask)) + { + /* all requested bits match */ + ack = true; + LSSslave->fastscanPos = lssNext; + + if (bitCheck == 0 && lssNext < lssSub) { + /* complete match, enter configuration state */ + LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; + } + } + } + if (ack) { +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND + LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; + memset(&LSSslave->TXbuff->data[1], 0, + sizeof(LSSslave->TXbuff->data) - 1); + CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); +#else + LSSslave->service = cs; + request_LSSslave_process = true; +#endif + } } + break; + } + default: { + break; } - - /* send confirmation */ - LSSslave->TXbuff->data[0] = CO_LSS_CFG_STORE; - LSSslave->TXbuff->data[1] = errorCode; - /* we do not use spec-error, always 0 */ - memset(&LSSslave->TXbuff->data[2], 0, sizeof(LSSslave->TXbuff->data) - 2); - CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); - break; - default: - break; - } -} - -/* - * Helper function - Handle service "inquire" - */ -static void CO_LSSslave_serviceInquire( - CO_LSSslave_t *LSSslave, - CO_LSS_cs_t service, - void *msg) -{ - (void)msg; /* unused */ - - uint32_t value; - - if(LSSslave->lssState != CO_LSS_STATE_CONFIGURATION) { - return; - } - - switch (service) { - case CO_LSS_INQUIRE_VENDOR: - value = LSSslave->lssAddress.identity.vendorID; - break; - case CO_LSS_INQUIRE_PRODUCT: - value = LSSslave->lssAddress.identity.productCode; - break; - case CO_LSS_INQUIRE_REV: - value = LSSslave->lssAddress.identity.revisionNumber; - break; - case CO_LSS_INQUIRE_SERIAL: - value = LSSslave->lssAddress.identity.serialNumber; - break; - case CO_LSS_INQUIRE_NODE_ID: - value = (uint32_t)LSSslave->activeNodeID; - break; - default: - return; - } - /* send response */ - LSSslave->TXbuff->data[0] = service; - CO_memcpySwap4(&LSSslave->TXbuff->data[1], &value); - memset(&LSSslave->TXbuff->data[5], 0, sizeof(LSSslave->TXbuff->data) - 5); - CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); -} - -/* - * Helper function - Handle service "identify" - */ -static void CO_LSSslave_serviceIdent( - CO_LSSslave_t *LSSslave, - CO_LSS_cs_t service, - void *msg) -{ - uint32_t idNumber; - uint8_t bitCheck; - uint8_t lssSub; - uint8_t lssNext; - bool_t ack; - uint8_t *data = CO_CANrxMsg_readData(msg); - - if (LSSslave->lssState != CO_LSS_STATE_WAITING) { - /* fastscan is only allowed in waiting state */ - return; - } - if (service != CO_LSS_IDENT_FASTSCAN) { - /* we only support "fastscan" identification */ - return; - } - if (LSSslave->pendingNodeID!=CO_LSS_NODE_ID_ASSIGNMENT || - LSSslave->activeNodeID!=CO_LSS_NODE_ID_ASSIGNMENT) { - /* fastscan is only active on unconfigured nodes */ - return; - } - - CO_memcpySwap4(&idNumber, &data[1]); - bitCheck = data[5]; - lssSub = data[6]; - lssNext = data[7]; - - if (!CO_LSS_FASTSCAN_BITCHECK_VALID(bitCheck) || - !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssSub) || - !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssNext)) { - /* Invalid request */ - return; - } - - ack = false; - if (bitCheck == CO_LSS_FASTSCAN_CONFIRM) { - /* Confirm, Reset */ - ack = true; - LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; - memset(&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); - } - else if (LSSslave->fastscanPos == lssSub) { - uint32_t mask = 0xFFFFFFFF << bitCheck; - - if ((LSSslave->lssAddress.addr[lssSub] & mask) == (idNumber & mask)) { - /* all requested bits match */ - ack = true; - LSSslave->fastscanPos = lssNext; - - if (bitCheck==0 && lssNextlssState = CO_LSS_STATE_CONFIGURATION; } } - } - if (ack) { - LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; - memset(&LSSslave->TXbuff->data[1], 0, sizeof(LSSslave->TXbuff->data) - 1); - CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); - } -} - - -/* - * Read received message from CAN module. - * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. - */ -static void CO_LSSslave_receive(void *object, void *msg) -{ - CO_LSSslave_t *LSSslave; - uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); - - LSSslave = (CO_LSSslave_t*)object; /* this is the correct pointer type of the first argument */ - - if(DLC == 8){ - CO_LSS_cs_t cs = (CO_LSS_cs_t) data[0]; - - if (CO_LSS_CS_SERVICE_IS_SWITCH_GLOBAL(cs)) { - CO_LSSslave_serviceSwitchStateGlobal(LSSslave, cs, msg); - } - else if (CO_LSS_CS_SERVICE_IS_SWITCH_STATE_SELECTIVE(cs)) { - CO_LSSslave_serviceSwitchStateSelective(LSSslave, cs, msg); - } - else if (CO_LSS_CS_SERVICE_IS_CONFIG(cs)) { - CO_LSSslave_serviceConfig(LSSslave, cs, msg); - } - else if (CO_LSS_CS_SERVICE_IS_INQUIRE(cs)) { - CO_LSSslave_serviceInquire(LSSslave, cs, msg); - } - else if (CO_LSS_CS_SERVICE_IS_IDENT(cs)) { - CO_LSSslave_serviceIdent(LSSslave, cs, msg); + else { /* LSSslave->lssState == CO_LSS_STATE_CONFIGURATION */ + memcpy(&LSSslave->CANdata, &data[0], sizeof(LSSslave->CANdata)); + LSSslave->service = cs; + request_LSSslave_process = true; } - else { - /* No Ack -> Unsupported commands are dropped */ + + if (request_LSSslave_process) { + CO_FLAG_SET(LSSslave->sendResponse); +#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, + * which handles further processing. */ + if (LSSslave->pFunctSignalPre != NULL) { + LSSslave->pFunctSignalPre(LSSslave->functSignalObjectPre); + } +#endif } } } @@ -374,8 +190,8 @@ static void CO_LSSslave_receive(void *object, void *msg) CO_ReturnError_t CO_LSSslave_init( CO_LSSslave_t *LSSslave, CO_LSS_address_t lssAddress, - uint16_t pendingBitRate, - uint8_t pendingNodeID, + uint16_t *pendingBitRate, + uint8_t *pendingNodeID, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, uint32_t CANidLssMaster, @@ -386,33 +202,27 @@ CO_ReturnError_t CO_LSSslave_init( CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if (LSSslave==NULL || CANdevRx==NULL || CANdevTx==NULL || - !CO_LSS_NODE_ID_VALID(pendingNodeID)) { + if (LSSslave==NULL || pendingBitRate == NULL || pendingNodeID == NULL || + CANdevRx==NULL || CANdevTx==NULL || + !CO_LSS_NODE_ID_VALID(*pendingNodeID) + ) { return CO_ERROR_ILLEGAL_ARGUMENT; } - /* check LSS address for plausibility. As a bare minimum, the vendor - * ID and serial number must be set */ - if (lssAddress.identity.vendorID==0 || lssAddress.identity.serialNumber==0) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } + /* Application must make sure that lssAddress is filled with data. */ + /* clear the object */ + memset(LSSslave, 0, sizeof(CO_LSSslave_t)); + + /* Configure object variables */ memcpy(&LSSslave->lssAddress, &lssAddress, sizeof(LSSslave->lssAddress)); LSSslave->lssState = CO_LSS_STATE_WAITING; - memset(&LSSslave->lssSelect, 0, sizeof(LSSslave->lssSelect)); - - memset(&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; LSSslave->pendingBitRate = pendingBitRate; LSSslave->pendingNodeID = pendingNodeID; - LSSslave->activeNodeID = CO_LSS_NODE_ID_ASSIGNMENT; - LSSslave->pFunctLSScheckBitRate = NULL; - LSSslave->functLSScheckBitRateObject = NULL; - LSSslave->pFunctLSSactivateBitRate = NULL; - LSSslave->functLSSactivateBitRateObject = NULL; - LSSslave->pFunctLSScfgStore = NULL; - LSSslave->functLSScfgStore = NULL; + LSSslave->activeNodeID = *pendingNodeID; + CO_FLAG_CLEAR(LSSslave->sendResponse); /* configure LSS CAN Master message reception */ ret = CO_CANrxBufferInit( @@ -442,6 +252,21 @@ CO_ReturnError_t CO_LSSslave_init( } +#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE +/******************************************************************************/ +void CO_LSSslave_initCallbackPre( + CO_LSSslave_t *LSSslave, + void *object, + void (*pFunctSignalPre)(void *object)) +{ + if(LSSslave != NULL){ + LSSslave->functSignalObjectPre = object; + LSSslave->pFunctSignalPre = pFunctSignalPre; + } +} +#endif + + /******************************************************************************/ void CO_LSSslave_initCheckBitRateCallback( CO_LSSslave_t *LSSslave, @@ -475,72 +300,183 @@ void CO_LSSslave_initCfgStoreCallback( bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate)) { if(LSSslave != NULL){ - LSSslave->functLSScfgStore = object; + LSSslave->functLSScfgStoreObject = object; LSSslave->pFunctLSScfgStore = pFunctLSScfgStore; } } /******************************************************************************/ -void CO_LSSslave_process( - CO_LSSslave_t *LSSslave, - uint16_t activeBitRate, - uint8_t activeNodeId, - uint16_t *pendingBitRate, - uint8_t *pendingNodeId) -{ - (void)activeBitRate; /* unused */ +bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { + bool_t resetCommunication = false; + + if (CO_FLAG_READ(LSSslave->sendResponse)) { + uint8_t nid; + uint8_t errorCode; + uint8_t errorCodeManuf; + uint8_t tableSelector; + uint8_t tableIndex; + bool_t CANsend = false; + + memset(&LSSslave->TXbuff->data[0], 0, sizeof(LSSslave->TXbuff->data)); + + switch (LSSslave->service) { + case CO_LSS_SWITCH_STATE_GLOBAL: { + /* Node-Id was unconfigured before, now it is configured, + * enter the NMT Reset communication autonomously. */ + resetCommunication = true; + break; + } + case CO_LSS_SWITCH_STATE_SEL_SERIAL: { + LSSslave->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL; + CANsend = true; + break; + } + case CO_LSS_CFG_NODE_ID: { + nid = LSSslave->CANdata[1]; + errorCode = CO_LSS_CFG_NODE_ID_OK; - LSSslave->activeNodeID = activeNodeId; - *pendingBitRate = LSSslave->pendingBitRate; - *pendingNodeId = LSSslave->pendingNodeID; -} + if (CO_LSS_NODE_ID_VALID(nid)) { + *LSSslave->pendingNodeID = nid; + } + else { + errorCode = CO_LSS_CFG_NODE_ID_OUT_OF_RANGE; + } + /* send confirmation */ + LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[1] = errorCode; + /* we do not use spec-error, always 0 */ + CANsend = true; + break; + } + case CO_LSS_CFG_BIT_TIMING: { + if (LSSslave->pFunctLSScheckBitRate == NULL) { + /* setting bit timing is not supported. Drop request */ + break; + } -/******************************************************************************/ -CO_LSS_state_t CO_LSSslave_getState( - CO_LSSslave_t *LSSslave) -{ - if(LSSslave != NULL){ - return LSSslave->lssState; - } - return CO_LSS_STATE_WAITING; -} + tableSelector = LSSslave->CANdata[1]; + tableIndex = LSSslave->CANdata[2]; + errorCode = CO_LSS_CFG_BIT_TIMING_OK; + errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OK; + if (tableSelector == 0 && CO_LSS_BIT_TIMING_VALID(tableIndex)) { + uint16_t bit = CO_LSS_bitTimingTableLookup[tableIndex]; + bool_t bit_rate_supported = LSSslave->pFunctLSScheckBitRate( + LSSslave->functLSScheckBitRateObject, bit); -/******************************************************************************/ -bool_t CO_LSSslave_LEDprocess( - CO_LSSslave_t *LSSslave, - uint32_t timeDifference_us, - bool_t *LEDon) -{ - static uint32_t ms50 = 0; - static int8_t flash1, flash2; - - if (LSSslave == NULL || LEDon == NULL) - return false; - ms50 += timeDifference_us; - if(ms50 >= 50000) { - ms50 -= 50000; - /* 4 cycles on, 50 cycles off */ - if(++flash1 >= 4) flash1 = -50; - - /* 4 cycles on, 4 cycles off, 4 cycles on, 50 cycles off */ - switch(++flash2){ - case 4: flash2 = -104; break; - case -100: flash2 = 100; break; - case 104: flash2 = -50; break; + if (bit_rate_supported) { + *LSSslave->pendingBitRate = bit; + } + else { + errorCode = CO_LSS_CFG_BIT_TIMING_MANUFACTURER; + errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; + } + } + else { + /* we currently only support CiA301 bit timing table */ + errorCode = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; + } + + /* send confirmation */ + LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[1] = errorCode; + LSSslave->TXbuff->data[2] = errorCodeManuf; + CANsend = true; + break; } + case CO_LSS_CFG_ACTIVATE_BIT_TIMING: { + if (LSSslave->pFunctLSScheckBitRate == NULL) { + /* setting bit timing is not supported. Drop request */ + break; + } + + /* notify application */ + if (LSSslave->pFunctLSSactivateBitRate != NULL) { + uint16_t delay; + CO_memcpySwap2(&delay, &LSSslave->CANdata[1]); + LSSslave->pFunctLSSactivateBitRate( + LSSslave->functLSSactivateBitRateObject, delay); + } + break; + } + case CO_LSS_CFG_STORE: { + errorCode = CO_LSS_CFG_STORE_OK; + + if (LSSslave->pFunctLSScfgStore == NULL) { + /* storing is not supported. Reply error */ + errorCode = CO_LSS_CFG_STORE_NOT_SUPPORTED; + } + else { + bool_t result; + /* Store "pending" to "persistent" */ + result = + LSSslave->pFunctLSScfgStore(LSSslave->functLSScfgStoreObject, + *LSSslave->pendingNodeID, + *LSSslave->pendingBitRate); + if (!result) { + errorCode = CO_LSS_CFG_STORE_FAILED; + } + } + + /* send confirmation */ + LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[1] = errorCode; + /* we do not use spec-error, always 0 */ + CANsend = true; + break; + } + case CO_LSS_INQUIRE_VENDOR: { + LSSslave->TXbuff->data[0] = LSSslave->service; + CO_memcpySwap4(&LSSslave->TXbuff->data[1], + &LSSslave->lssAddress.identity.vendorID); + CANsend = true; + break; + } + case CO_LSS_INQUIRE_PRODUCT: { + LSSslave->TXbuff->data[0] = LSSslave->service; + CO_memcpySwap4(&LSSslave->TXbuff->data[1], + &LSSslave->lssAddress.identity.productCode); + CANsend = true; + break; + } + case CO_LSS_INQUIRE_REV: { + LSSslave->TXbuff->data[0] = LSSslave->service; + CO_memcpySwap4(&LSSslave->TXbuff->data[1], + &LSSslave->lssAddress.identity.revisionNumber); + CANsend = true; + break; + } + case CO_LSS_INQUIRE_SERIAL: { + LSSslave->TXbuff->data[0] = LSSslave->service; + CO_memcpySwap4(&LSSslave->TXbuff->data[1], + &LSSslave->lssAddress.identity.serialNumber); + CANsend = true; + break; + } + case CO_LSS_INQUIRE_NODE_ID: { + LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[1] = LSSslave->activeNodeID; + CANsend = true; + break; + } + case CO_LSS_IDENT_FASTSCAN: { + LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; + CANsend = true; + break; + } + default: { + break; + } + } + + if(CANsend) { + CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); + } + + CO_FLAG_CLEAR(LSSslave->sendResponse); } - if (LSSslave->lssState == CO_LSS_STATE_CONFIGURATION) - { - *LEDon = (flash2 >= 0); - return true; - } - else if (LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT) - { - *LEDon = (flash1 >= 0); - return true; - } - return false; + + return resetCommunication; } diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index 26252982..07c33b71 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -4,6 +4,7 @@ * @file CO_LSSslave.h * @ingroup CO_LSS * @author Martin Wagner + * @author Janez Paternoster * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * * @@ -53,178 +54,33 @@ extern "C" { * * After CAN module start, the LSS slave and NMT slave are started and then * coexist alongside each other. To achieve this behaviour, the CANopen node - * startup process has to be conrolled more detailled. Therefore, the function - * CO_init() is split up into the functions CO_new(), CO_CANinit(), CO_LSSinit() - * and CO_CANopenInit(). - * Moreover, the LSS slave needs to pause the NMT slave initialization in case - * no valid node ID is available at start up. - * - * ###Example - * - * It is strongly recommended that the user already has a fully working application - * running with the standard (non LSS) version of CANopenNode. This is required - * to understand what this example does and where you need to change it for your - * requirements. - * - * The following code is only a suggestion on how to use the LSS slave. It is - * not a working example! To simplify the code, no error handling is - * included. For stable code, proper error handling has to be added to the user - * code. + * startup process has to be controlled more detailed. Therefore, CO_LSSinit() + * must be invoked between CO_CANinit() and CO_CANopenInit() in the + * communication reset section. * - * This example is not intended for bare metal targets. If you intend to do CAN - * message receiving inside interrupt, be aware that the callback functions - * will be called inside the interrupt handler context! - * - * \code{.c} - - const uint16_t FIRST_BIT = 125; - queue changeBitRate; - uint8_t activeNid; - uint16_t activeBit; - - bool_t checkBitRateCallback(void *object, uint16_t bitRate) - { - if (validBit(bitRate)) { - return true; - } - return false; - } - - void activateBitRateCallback(void *object, uint16_t delay) - { - int time = getCurrentTime(); - queueSend(&changeBitRate, time, delay); - } - - bool_t cfgStoreCallback(void *object, uint8_t id, uint16_t bitRate) - { - savePersistent(id, bitRate); - return true; - } - - void start_canopen(uint8_t nid) - { - uint8_t persistentNid; - uint8_t pendingNid; - uint16_t persistentBit; - uint16_t pendingBit; - - loadPersistent(&persistentNid, &persistentBit); - - if ( ! validBit(persistentBit)) { - printf("no bit rate found, defaulting to %d", FIRST_BIT); - pendingBit = FIRST_BIT; - } - else { - printf("loaded bit rate from nvm: %d", persistentBit); - pendingBit = persistentBit; - } - - if (nid == 0) { - if ( ! validNid(persistentNid)) { - pendingNid = CO_LSS_NODE_ID_ASSIGNMENT; - printf("no node id found, needs to be set by LSS. NMT will" - "not be started until valid node id is set"); - } - else { - printf("loaded node id from nvm: %d", persistentNid); - pendingNid = persistentNid; - } - } - else { - printf("node id provided by application: %d", nid); - pendingNid = nid; - } - - CO_new(); - CO_CANinit(0, pendingBit); - CO_LSSinit(pendingNid, pendingBit); - CO_CANsetNormalMode(CO->CANmodule[0]); - activeBit = pendingBit; - - CO_LSSslave_initCheckBitRateCallback(CO->LSSslave, NULL, checkBitRateCallback); - CO_LSSslave_initActivateBitRateCallback(CO->LSSslave, NULL, activateBitRateCallback); - CO_LSSslave_initCfgStoreCallback(CO->LSSslave, NULL, cfgStoreCallback); - - while (1) { - CO_LSSslave_process(CO->LSSslave, activeBit, activeNid, - &pendingBit, &pendingNid); - if (pendingNid!=CO_LSS_NODE_ID_ASSIGNMENT && - CO_LSSslave_getState(CO->LSSslave)==CO_LSS_STATE_WAITING) { - printf("node ID has been found: %d", pendingNid); - break; - } - - if ( ! queueEmpty(&changeBitRate)) { - printf("bit rate change requested: %d", pendingBit); - int time; - uint16_t delay; - queueReceive(&changeBitRate, time, delay); - delayUntil(time + delay); - CO_CANsetBitrate(CO->CANmodule[0], pendingBit); - delay(delay); - } - - printf("waiting for node id"); - CO_CANrxWait(CO->CANmodule[0]); - } - - CO_CANopenInit(pendingNid); - activeNid = pendingNid; - - printf("from this on, initialization doesn't differ to non-LSS version" - "You can now intialize your CO_CANrxWait() thread or interrupt"); - } - - void main(void) - { - uint8_t pendingNid; - uint16_t pendingBit; - - printf("like example in dir \"example\""); - - CO_NMT_reset_cmd_t reset = CO_RESET_NOT; - uint16_t timer1msPrevious; - - start_canopen(0); - - reset = CO_RESET_NOT; - timer1msPrevious = CO_timer1ms; - while(reset == CO_RESET_NOT){ - printf("loop for normal program execution"); - uint16_t timer1msCopy, timer1msDiff; - - timer1msCopy = CO_timer1ms; - timer1msDiff = timer1msCopy - timer1msPrevious; - timer1msPrevious = timer1msCopy; - - reset = CO_process(CO, timer1msDiff, NULL); - - CO_LSSslave_process(CO->LSSslave, activeBit, activeNid, - &pendingBit, &pendingNid); - if (reset == CO_RESET_COMM) { - printf("restarting CANopen using pending node ID %d", pendingNid); - CO_delete(0); - start_canopen(pendingNid); - reset = CO_RESET_NOT; - } - if ( ! queueEmpty(&changeBitRate)) { - printf("bit rate change requested: %d", pendingBit); - int time; - uint16_t delay; - queueReceive(&changeBitRate, time, delay); - printf("Disabling CANopen for givent time"); - pauseReceiveThread(); - delayUntil(time + delay); - CO_CANsetBitrate(CO->CANmodule[0], pendingBit); - delay(delay); - resumeReceiveThread(); - printf("Re-enabling CANopen after bit rate switch"); - } - } - } - - * \endcode + * Moreover, the LSS slave needs to pause the NMT slave initialization in case + * no valid node ID is available at start up. In that case CO_CANopenInit() + * skips initialization of other CANopen modules and CO_process() skips + * processing of other modules than LSS slave automatically. + * + * Variables for CAN-bitrate and CANopen node-id must be initialized by + * application from non-volatile memory or dip switches. Pointers to them are + * passed to CO_LSSinit() function. Those variables represents pending values. + * If node-id is valid in the moment it enters CO_LSSinit(), it also becomes + * active node-id and the stack initialises normally. Otherwise, node-id must be + * configured by lss and after successful configuration stack passes reset + * communication autonomously. + * + * Device with all threads can be normally initialized and running despite that + * node-id is not valid. Application must take care, because CANopen is not + * initialized. In that case CO_CANopenInit() returns error condition + * CO_ERROR_NODE_ID_UNCONFIGURED_LSS which must be handled properly. Status can + * also be checked with CO->nodeIdUnconfigured variable. + * + * Some callback functions may be initialized by application with + * CO_LSSslave_initCheckBitRateCallback(), + * CO_LSSslave_initActivateBitRateCallback() and + * CO_LSSslave_initCfgStoreCallback(). */ /** @@ -238,16 +94,24 @@ typedef struct{ CO_LSS_address_t lssFastscan; /**< Received LSS Address by fastscan */ uint8_t fastscanPos; /**< Current state of fastscan */ - uint16_t pendingBitRate; /**< Bit rate value that is temporarily configured in volatile memory */ - uint8_t pendingNodeID; /**< Node ID that is temporarily configured in volatile memory */ + uint16_t *pendingBitRate; /**< Bit rate value that is temporarily configured */ + uint8_t *pendingNodeID; /**< Node ID that is temporarily configured */ uint8_t activeNodeID; /**< Node ID used at the CAN interface */ + volatile void *sendResponse; /**< Variable indicates, if LSS response has to be sent by mainline processing function */ + CO_LSS_cs_t service; /**< Service, which will have to be processed by mainline processing function */ + uint8_t CANdata[8]; /**< Received CAN data, which will be processed by mainline processing function */ + +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN + void (*pFunctSignalPre)(void *object); /**< From CO_LSSslave_initCallbackPre() or NULL */ + void *functSignalObjectPre;/**< Pointer to object */ +#endif bool_t (*pFunctLSScheckBitRate)(void *object, uint16_t bitRate); /**< From CO_LSSslave_initCheckBitRateCallback() or NULL */ void *functLSScheckBitRateObject; /** Pointer to object */ void (*pFunctLSSactivateBitRate)(void *object, uint16_t delay); /**< From CO_LSSslave_initActivateBitRateCallback() or NULL. Delay is in ms */ void *functLSSactivateBitRateObject; /** Pointer to object */ bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate); /**< From CO_LSSslave_initCfgStoreCallback() or NULL */ - void *functLSScfgStore; /** Pointer to object */ + void *functLSScfgStoreObject; /** Pointer to object */ CO_CANmodule_t *CANdevTx; /**< From #CO_LSSslave_init() */ CO_CANtx_t *TXbuff; /**< CAN transmit buffer */ @@ -258,20 +122,32 @@ typedef struct{ * * Function must be called in the communication reset section. * - * Depending on the startup type, pending bit rate and node ID have to be - * supplied differently. After #CO_NMT_RESET_NODE or at power up they should - * be restored from persitent bit rate and node id. After #CO_NMT_RESET_COMMUNICATION - * they have to be supplied from the application and are generally the values - * that have been last returned by #CO_LSSslave_process() before resetting. + * pendingBitRate and pendingNodeID must be pointers to external variables. Both + * variables must be initialized on program startup (after #CO_NMT_RESET_NODE) + * from non-volatile memory, dip switches or similar. They must not change + * during #CO_NMT_RESET_COMMUNICATION. Both variables can be changed by + * CO_LSSslave_process(), depending on commands from the LSS master. + * + * If pendingNodeID is valid (1 <= pendingNodeID <= 0x7F), then this becomes + * valid active nodeId just after exit of this function. In that case all other + * CANopen objects may be initialized and processed in run time. + * + * If pendingNodeID is not valid (pendingNodeID == 0xFF), then only LSS slave is + * initialized and processed in run time. In that state pendingNodeID can be + * configured and after successful configuration reset communication with all + * CANopen object is activated automatically. * * @remark The LSS address needs to be unique on the network. For this, the 128 - * bit wide identity object (1018h) is used. Therefore, this object has to be fully - * initalized before passing it to this function. + * bit wide identity object (1018h) is used. Therefore, this object has to be + * fully initialized before passing it to this function (vendorID, product + * code, revisionNo, serialNo are set to 0 by default). Otherwise, if + * non-configured devices are present on CANopen network, LSS configuration may + * behave unpredictable. * * @param LSSslave This object will be initialized. * @param lssAddress LSS address - * @param pendingBitRate Bit rate of the CAN interface. - * @param pendingNodeID Node ID or 0xFF - invalid. + * @param [in,out] pendingBitRate Pending bit rate of the CAN interface + * @param [in,out] pendingNodeID Pending node ID or 0xFF - invalid * @param CANdevRx CAN device for LSS slave reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANidLssMaster COB ID for reception. @@ -283,8 +159,8 @@ typedef struct{ CO_ReturnError_t CO_LSSslave_init( CO_LSSslave_t *LSSslave, CO_LSS_address_t lssAddress, - uint16_t pendingBitRate, - uint8_t pendingNodeID, + uint16_t *pendingBitRate, + uint8_t *pendingNodeID, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, uint32_t CANidLssMaster, @@ -295,21 +171,17 @@ CO_ReturnError_t CO_LSSslave_init( /** * Process LSS communication * - * - sets currently active node ID and bit rate so master can read it - * - hands over pending node ID and bit rate to user application + * Object is partially pre-processed after LSS message received. Further + * processing is inside this function. + * + * In case that Node-Id is unconfigured, then this function may request CANopen + * communication reset. This happens, when valid node-id is configured by LSS + * master. * * @param LSSslave This object. - * @param activeBitRate Currently active bit rate - * @param activeNodeId Currently active node ID - * @param [out] pendingBitRate Requested bit rate - * @param [out] pendingNodeId Requested node id + * @return True, if #CO_NMT_RESET_COMMUNICATION is requested */ -void CO_LSSslave_process( - CO_LSSslave_t *LSSslave, - uint16_t activeBitRate, - uint8_t activeNodeId, - uint16_t *pendingBitRate, - uint8_t *pendingNodeId); +bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave); /** * Get current LSS state @@ -317,30 +189,30 @@ void CO_LSSslave_process( * @param LSSslave This object. * @return #CO_LSS_state_t */ -CO_LSS_state_t CO_LSSslave_getState( - CO_LSSslave_t *LSSslave); +static inline CO_LSS_state_t CO_LSSslave_getState(CO_LSSslave_t *LSSslave) { + return (LSSslave == NULL) ? CO_LSS_STATE_WAITING : LSSslave->lssState; +} + +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** - * Process LSS LED + * Initialize LSSslaveRx callback function. * - * Returns the status of the LSS LED (if LSS is involved) - * with the following meaning: - * - * UNCONFIGURED (activeNodeId is unconfigured) --> single flash - * SELECTED --> double flash - * - * If none of above conditions apply, returns false. + * Function initializes optional callback function, which should immediately + * start further LSS processing. Callback is called after LSS message is + * received from the CAN bus. It should signal the RTOS to resume corresponding + * task. * * @param LSSslave This object. - * @param timeDifference_us The amount of time elapsed since the last call - * @param [out] LEDon LED state - * - * @return true if LSS is involved (unconfigured node or selected node) + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL + * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -bool_t CO_LSSslave_LEDprocess( +void CO_LSSslave_initCallbackPre( CO_LSSslave_t *LSSslave, - uint32_t timeDifference_us, - bool_t *LEDon); + void *object, + void (*pFunctSignalPre)(void *object)); +#endif + /** * Initialize verify bit rate callback @@ -351,9 +223,6 @@ bool_t CO_LSSslave_LEDprocess( * When no callback is set the LSS slave will no-ack the request, indicating to * the master that bit rate change is not supported. * - * @remark Depending on the CAN driver implementation, this function is called - * inside an ISR - * * @param LSSslave This object. * @param object Pointer to object, which will be passed to pFunctLSScheckBitRate(). Can be NULL * @param pFunctLSScheckBitRate Pointer to the callback function. Not called if NULL. @@ -371,10 +240,7 @@ void CO_LSSslave_initCheckBitRateCallback( * allow setting a timer or do calculations based on the exact time the request * arrived. * According to DSP 305 6.4.4, the delay has to be applied once before and once after - * switching bit rates. During this time, a device musn't send any messages. - * - * @remark Depending on the CAN driver implementation, this function is called - * inside an ISR + * switching bit rates. During this time, a device mustn't send any messages. * * @param LSSslave This object. * @param object Pointer to object, which will be passed to pFunctLSSactivateBitRate(). Can be NULL @@ -395,9 +261,6 @@ void CO_LSSslave_initActivateBitRateCallback( * callback is set the LSS slave will no-ack the request, indicating to the master * that storing is not supported. * - * @remark Depending on the CAN driver implementation, this function is called - * inside an ISR - * * @param LSSslave This object. * @param object Pointer to object, which will be passed to pFunctLSScfgStore(). Can be NULL * @param pFunctLSScfgStore Pointer to the callback function. Not called if NULL. diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 856fc48e..341c64e3 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -200,14 +200,14 @@ static const char CO_GTWA_helpStringLss[] = "lss_get_node # Inquire node-ID.\n" \ "_lss_fastscan [] # Identify fastscan, non-standard.\n" \ "lss_allnodes [ [ \\\n" \ -" \\\n" \ -" ]]\n" \ +" [ \\\n" \ +" ]]]\n" \ " # Node-ID configuration of all nodes.\n" \ "\n" \ -": 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\n" \ -" 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\n" \ -"\n" \ -"All LSS commands start with '\"[\"\"]\" []'.\r\n"; +"* All LSS commands start with '\"[\"\"]\" []'.\n" \ +"* : 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\n" \ +" 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\n" \ +"* : 0=fastscan, 1=ignore, 2=match value in next parameter\r\n"; #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS @@ -396,7 +396,7 @@ static const errorDescs_t errorDescs[] = { {100, "Request not supported."}, {101, "Syntax error."}, {102, "Request not processed due to internal state."}, - {103, "Time-out (where applicable)."}, + {103, "Time-out."}, {104, "No default net set."}, {105, "No default node set."}, {106, "Unsupported net."}, @@ -1348,17 +1348,26 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* prepare lssFastscan, all zero */ memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); } - else { - CO_LSSmaster_fastscan_t *fs = >wa->lssFastscan; - /* read other arguments */ + if (closed == 0) { + /* more arguments follow */ CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); gtwa->lssNID = getU32(tok, 1, 127, &err); if (err) break; + closed = -1; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); gtwa->lssStore = (bool_t)getU32(tok, 0, 1, &err); if (err) break; + if (closed == 1) { + /* No other arguments, prepare lssFastscan, all zero */ + memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); + } + } + if (closed == 0) { + /* more arguments follow */ + CO_LSSmaster_fastscan_t *fs = >wa->lssFastscan; + CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_VENDOR_ID] = getU32(tok, 0, 2, &err); if (err) break; @@ -1704,10 +1713,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } else if (gtwa->state == CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL) { CO_LSSmaster_return_t ret; - CO_LSS_address_t lssAddress; ret = CO_LSSmaster_InquireLssAddress(gtwa->LSSmaster, timeDifference_us, - &lssAddress); + >wa->lssAddress); if (ret != CO_LSSmaster_WAIT_SLAVE) { if (ret == CO_LSSmaster_OK) { gtwa->respBufCount = @@ -1715,10 +1723,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", gtwa->sequence, - lssAddress.identity.vendorID, - lssAddress.identity.productCode, - lssAddress.identity.revisionNumber, - lssAddress.identity.serialNumber); + gtwa->lssAddress.identity.vendorID, + gtwa->lssAddress.identity.productCode, + gtwa->lssAddress.identity.revisionNumber, + gtwa->lssAddress.identity.serialNumber); respBufTransfer(gtwa); } else { @@ -1839,6 +1847,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } else { /* cycle finished successfully, send report */ + uint8_t lssNidAssigned = gtwa->lssNID; const char msg2Fmt[] = "# Not all nodes scanned!\r\n" \ "[%"PRId32"] OK\r\n"; char msg2[sizeof(msg2Fmt)+10] = {0}; @@ -1863,7 +1872,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "# Node-ID %d assigned to: 0x%08"PRIX32" 0x%08" \ PRIX32" 0x%08"PRIX32" 0x%08"PRIX32"\r\n%s", - gtwa->lssNID, + lssNidAssigned, gtwa->lssFastscan.found.identity.vendorID, gtwa->lssFastscan.found.identity.productCode, gtwa->lssFastscan.found.identity.revisionNumber, diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 1c11f8d0..617cd6ba 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -133,14 +133,14 @@ lss_inquire_addr [] # Inquire LSS address. lss_get_node # Inquire node-ID. _lss_fastscan [] # Identify fastscan, non-standard. lss_allnodes [ [ \\ - \\ - ]] + [ \\ + ]]] # Node-ID configuration of all nodes. -: 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s, - 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto - -All LSS commands start with '"[""]" []'. +* All LSS commands start with '\"[\"\"]\" []'. +* : 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s, + 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto +* : 0=fastscan, 1=ignore, 2=match value in next parameter * @endcode * * This help text is the same as variable contents in CO_GTWA_helpString. diff --git a/CANopen.c b/CANopen.c index 1be0e39e..a52be726 100644 --- a/CANopen.c +++ b/CANopen.c @@ -66,8 +66,7 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; || ODL_consumerHeartbeatTime_arrayLength == 0 \ || ODL_errorStatusBits_stringLength < 10 \ || CO_NO_LSS_SLAVE > 1 \ - || CO_NO_LSS_MASTER > 1 \ - || (CO_NO_LSS_SLAVE > 0 && CO_NO_LSS_MASTER > 0) + || CO_NO_LSS_MASTER > 1 #error Features from CO_OD.h file are not corectly configured for this project! #endif @@ -80,7 +79,8 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #define CO_RXCAN_SDO_SRV (CO_RXCAN_RPDO + CO_NO_RPDO) #define CO_RXCAN_SDO_CLI (CO_RXCAN_SDO_SRV + CO_NO_SDO_SERVER) #define CO_RXCAN_CONS_HB (CO_RXCAN_SDO_CLI + CO_NO_SDO_CLIENT) -#define CO_RXCAN_LSS (CO_RXCAN_CONS_HB + CO_NO_HB_CONS) +#define CO_RXCAN_LSS_SLV (CO_RXCAN_CONS_HB + CO_NO_HB_CONS) +#define CO_RXCAN_LSS_MST (CO_RXCAN_LSS_SLV + CO_NO_LSS_SLAVE) #define CO_RXCAN_NO_MSGS (CO_NO_NMT + \ CO_NO_SYNC + \ CO_NO_EM_CONS + \ @@ -101,7 +101,8 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #define CO_TXCAN_SDO_SRV (CO_TXCAN_TPDO + CO_NO_TPDO) #define CO_TXCAN_SDO_CLI (CO_TXCAN_SDO_SRV + CO_NO_SDO_SERVER) #define CO_TXCAN_HB (CO_TXCAN_SDO_CLI + CO_NO_SDO_CLIENT) -#define CO_TXCAN_LSS (CO_TXCAN_HB + CO_NO_HB_PROD) +#define CO_TXCAN_LSS_SLV (CO_TXCAN_HB + CO_NO_HB_PROD) +#define CO_TXCAN_LSS_MST (CO_TXCAN_LSS_SLV + CO_NO_LSS_SLAVE) #define CO_TXCAN_NO_MSGS (CO_NO_NMT_MST + \ CO_NO_SYNC + \ CO_NO_EMERGENCY + \ @@ -538,8 +539,8 @@ CO_ReturnError_t CO_CANinit(void *CANptr, /******************************************************************************/ #if CO_NO_LSS_SLAVE == 1 -CO_ReturnError_t CO_LSSinit(uint8_t nodeId, - uint16_t bitRate) +CO_ReturnError_t CO_LSSinit(uint8_t *nodeId, + uint16_t *bitRate) { CO_LSS_address_t lssAddress; CO_ReturnError_t err; @@ -555,10 +556,10 @@ CO_ReturnError_t CO_LSSinit(uint8_t nodeId, bitRate, nodeId, CO->CANmodule[0], - CO_RXCAN_LSS, + CO_RXCAN_LSS_SLV, CO_CAN_ID_LSS_SRV, CO->CANmodule[0], - CO_TXCAN_LSS, + CO_TXCAN_LSS_SLV, CO_CAN_ID_LSS_CLI); return err; @@ -572,6 +573,13 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { CO_ReturnError_t err; /* Verify CANopen Node-ID */ + CO->nodeIdUnconfigured = false; +#if CO_NO_LSS_SLAVE == 1 + if (nodeId == CO_LSS_NODE_ID_ASSIGNMENT) { + CO->nodeIdUnconfigured = true; + } + else +#endif if (nodeId < 1 || nodeId > 127) { return CO_ERROR_PARAMETERS; } @@ -597,8 +605,8 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { #endif #if CO_NO_LSS_SLAVE == 1 - if (CO->nodeIdUnconfiguredLSS) { - return CO_ERROR_NO; + if (CO->nodeIdUnconfigured) { + return CO_ERROR_NODE_ID_UNCONFIGURED_LSS; } #endif @@ -783,10 +791,10 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { err = CO_LSSmaster_init(CO->LSSmaster, CO_LSSmaster_DEFAULT_TIMEOUT, CO->CANmodule[0], - CO_RXCAN_LSS, + CO_RXCAN_LSS_MST, CO_CAN_ID_LSS_CLI, CO->CANmodule[0], - CO_TXCAN_LSS, + CO_TXCAN_LSS_MST, CO_CAN_ID_LSS_SRV); if (err) return err; @@ -848,15 +856,15 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, bool_t NMTisPreOrOperational = false; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; +#if CO_NO_LSS_SLAVE == 1 + bool_t resetLSS = CO_LSSslave_process(co->LSSslave); +#endif + #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE CO_LEDs_process(co->LEDs, timeDifference_us, CO_isError(co->em, CO_EM_CAN_TX_BUS_OFF), - #if CO_NO_LSS_SLAVE == 1 - co->nodeIdUnconfiguredLSS, - #else - 0, - #endif + co->nodeIdUnconfigured, 0, /* RPDO event timer timeout */ CO_isError(co->em, CO_EM_SYNC_TIME_OUT), CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) @@ -876,6 +884,15 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, timerNext_us); #endif /* (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE */ +#if CO_NO_LSS_SLAVE == 1 + if (resetLSS) { + reset = CO_RESET_COMM; + } + if (co->nodeIdUnconfigured) { + return reset; + } +#endif + if (co->NMT->operatingState == CO_NMT_PRE_OPERATIONAL || co->NMT->operatingState == CO_NMT_OPERATIONAL) NMTisPreOrOperational = true; @@ -918,7 +935,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII /* Gateway-ascii */ - CO_GTWA_process(CO->gtwa, + CO_GTWA_process(co->gtwa, CO_GTWA_ENABLE, timeDifference_us, timerNext_us); @@ -934,13 +951,19 @@ bool_t CO_process_SYNC(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { + bool_t syncWas = false; + +#if CO_NO_LSS_SLAVE == 1 + if (co->nodeIdUnconfigured) { + return syncWas; + } +#endif + const CO_SYNC_status_t sync_process = CO_SYNC_process(co->SYNC, timeDifference_us, OD_synchronousWindowLength, timerNext_us); - bool_t syncWas = false; - switch (sync_process) { case CO_SYNC_NONE: break; @@ -963,6 +986,12 @@ void CO_process_RPDO(CO_t *co, { int16_t i; +#if CO_NO_LSS_SLAVE == 1 + if (co->nodeIdUnconfigured) { + return; + } +#endif + for (i = 0; i < CO_NO_RPDO; i++) { CO_RPDO_process(co->RPDO[i], syncWas); } @@ -977,6 +1006,12 @@ void CO_process_TPDO(CO_t *co, { int16_t i; +#if CO_NO_LSS_SLAVE == 1 + if (co->nodeIdUnconfigured) { + return; + } +#endif + /* Verify PDO Change Of State and process PDOs */ for (i = 0; i < CO_NO_TPDO; i++) { if (!co->TPDO[i]->sendRequest) diff --git a/CANopen.h b/CANopen.h index 4261e180..fb0f7880 100644 --- a/CANopen.h +++ b/CANopen.h @@ -258,6 +258,7 @@ extern "C" { * CANopen object with pointers to all CANopenNode objects. */ typedef struct { + bool_t nodeIdUnconfigured; /**< True in unconfigured LSS slave */ CO_CANmodule_t *CANmodule[1]; /**< CAN module objects */ CO_SDO_t *SDO[CO_NO_SDO_SERVER]; /**< SDO object */ CO_EM_t *em; /**< Emergency report object */ @@ -341,15 +342,16 @@ CO_ReturnError_t CO_CANinit(void *CANptr, /** * Initialize CANopen LSS slave * - * Function must be called in the communication reset section. + * Function must be called before CO_CANopenInit. * - * @param nodeId Node ID of the CANopen device (1 ... 127) or - * CO_LSS_NODE_ID_ASSIGNMENT - * @param bitRate CAN bit rate. + * See #CO_LSSslave_init() for description of parameters. + * + * @param [in,out] pendingNodeID Pending node ID or 0xFF(unconfigured) + * @param [in,out] pendingBitRate Pending bit rate of the CAN interface * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT */ -CO_ReturnError_t CO_LSSinit(uint8_t nodeId, - uint16_t bitRate); +CO_ReturnError_t CO_LSSinit(uint8_t *pendingNodeID, + uint16_t *pendingBitRate); #endif /* CO_NO_LSS_SLAVE == 1 */ @@ -358,7 +360,10 @@ CO_ReturnError_t CO_LSSinit(uint8_t nodeId, * * Function must be called in the communication reset section. * - * @param nodeId Node ID of the CANopen device (1 ... 127). + * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). In the + * CANopen initialization it is the same as pendingBitRate from CO_LSSinit(). + * If it is unconfigured, then some CANopen objects will not be initialized nor + * processed. * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT */ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index f294f8e0..b860ad99 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -22,6 +22,7 @@ Change Log - Heartbeat is send immediately after NMT state changes. - SDO client is rewritten. Now includes read/write fifo interface to transfer data. - LED indicator indication (CiA303-3) moved from NMT into own files. Now fully comply to standard. +- LSS slave is integrated into CANopenNode more directly. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN - driver API updated diff --git a/doc/LSSusage.md b/doc/LSSusage.md index b7046b6f..f632a960 100644 --- a/doc/LSSusage.md +++ b/doc/LSSusage.md @@ -2,74 +2,107 @@ LSS usage ========= LSS (Layer settings service) is an extension to CANopen described in CiA DSP 305. The -interface is described in CiA DS 309 2.1.0 (ASCII mapping). +interface is described in CiA DS 309 3.0.0 (ASCII mapping). LSS allows the user to change node ID and bitrate, as well as setting the node ID on an unconfigured node. -LSS uses the the OD Identity register as an unique value to select a node. Therefore +LSS uses the the OD Identity register (0x1018) as an unique value to select a node. Therefore the LSS address always consists of four 32 bit values. This also means that LSS relies -on this register to actually be unique. - -To use LSS, a compatible node is needed. Note that canopend only includes LSS master -functionality. - -The following example show some typical use cases for LSS: - +on this register to actually be unique. (_vendorID_, _productCode_, _revisionNumber_ and +_serialNumber_ must be configured and unique on each device.) + +### Preparation for testing on Linux virtual CAN +LSS can be tested on Linux virtual CAN, similar as in gettingStarted.md. + +1. Open terminal, setup _vcan0_ and _cd_ to CANopenNode directory. +2. Make some unique CANopen devices: + - Edit CO_OD.c, change initialization for identity, for example change line to `/*1018*/ {0x4, 0x1L, 0x2L, 0x3L, 0x4L},` + - `make` + - `mv canopend canopend4` + - Edit CO_OD.c, for example: `/*1018*/ {0x4, 0x1L, 0x2L, 0x3L, 0x5L},` + - `make` + - `mv canopend canopend5` + - Repeat this step and create three further "unique" CANopen devices. +3. Clear default OD storage file. We will use default (empty) storage for all instances: + - `echo "-" > od_storage` +4. Run "master" with command interface and node-id = 1. Note that this device + has enabled both: LSS master and LSS slave. But LSS master does not 'see' own LSS slave. + - `make` + - `./canopend vcan0 -i1 -c "stdio"` +5. Run one CANopen device with node-id=22 in own terminal: + - `./canopend4 vcan0 -i22` +6. Run other unique CANopen devices with unconfigured node-id, each in own terminal: + - `./canopend5 vcan0 -i0xFF` + - `./canopend6 vcan0 -i0xFF` + - `./canopend7 vcan0 -i0xFF` + - `./canopend8 vcan0 -i0xFF` +7. Note that `lss_store` does not work in this example. For it to work, OD storage must be used properly. + +### Typical usage of LSS - Changing the node ID for a known slave, store the new node ID to eeprom, apply new node ID. The node currently has the node ID 22. - $ ./canopencomm lss_switch_sel 0x00000428 0x00000431 0x00000002 0x5C17EEBC - $ ./canopencomm lss_set_node 4 - $ ./canopencomm lss_store - $ ./canopencomm lss_switch_glob 0 - $ ./canopencomm 22 reset communication + help lss + + lss_switch_sel 0x00000001 0x00000002 0x00000003 0x00000004 + lss_set_node 10 + lss_store + lss_switch_glob 0 + 22 reset communication - Note that the node ID change is not done until reset communication/node + Note that the node ID change is not done until reset communication/node. - Changing the node ID for a known slave, store the new node ID to eeprom, apply new node ID. The node currently has an invalid node ID. - $ ./canopencomm lss_switch_sel 0x00000428 0x00000431 0x00000002 0x5C17EEBC - $ ./canopencomm lss_set_node 4 - $ ./canopencomm lss_store - $ ./canopencomm lss_switch_glob 0 + lss_switch_sel 0x00000001 0x00000002 0x00000003 0x00000005 + lss_set_node 11 + lss_store + lss_switch_glob 0 - Note that the node ID is automatically applied. + Note that the node ID is automatically applied. This can be seen on `candump`. +### LSS fastscan - Search for a node via LSS fastscan, store the new node ID to eeprom, apply new node ID - $ ./canopencomm [1] _lss_fastscan + _lss_fastscan - [1] 0x00000428 0x00000432 0x00000002 0x6C81413C + [0] 0x00000001 0x00000002 0x00000003 0x00000006 - $ ./canopencomm lss_set_node 4 - $ ./canopencomm lss_store - $ ./canopencomm lss_switch_glob 0 + lss_set_node 12 + lss_store + lss_switch_glob 0 To increase scanning speed, you can use - $ ./canopencomm [1] _lss_fastscan 25 + _lss_fastscan 25 where 25 is the scan step delay in ms. Be aware that the scan will become unreliable when the delay is set to low. + We won't configure this node now, reset LSS. Now we have 1+3 nodes operational in our example. + + lss_switch_glob 0 + +### Auto enumerate all nodes - Auto enumerate all nodes via LSS fastscan. Enumeration automatically begins at node ID 2 and node ID is automatically stored to eeprom. Like with _lss_fastscan, an optional parameter can be used to change default delay time. - $ ./canopencomm lss_allnodes + lss_allnodes - [1] OK, found 3 nodes starting at node ID 2. + # Node-ID 2 assigned to: 0x00000001 0x00000002 0x00000003 0x00000007 + # Node-ID 3 assigned to: 0x00000001 0x00000002 0x00000003 0x00000008 + # Found 2 nodes, search finished. + [0] OK - To get further control over the fastscan process, the lss_allnodes command supports - an extended parameter set. If you want to use this set, all parameters are mandatory. + an extended parameter set. Auto enumerate all nodes via LSS fastscan. Set delay time to 25ms, set enumeration start to node ID 7, do not store LSS address in eeprom, enumerate only devices with vendor ID "0x428", ignore product code and software revision, scan for serial number - $ ./canopencomm lss_allnodes 25 7 0 2 0x428 1 0 1 0 0 0 - - [1] OK, found 2 nodes starting at node ID 7. + lss_allnodes 25 7 0 2 0x428 1 0 1 0 0 0 The parameters are as following: - 25 scan step delay time in ms diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index 3056235a..4739e603 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -162,7 +162,7 @@ Now you can enter the big world of [CANopen devices](http://can-newsletter.org/h You can also build your own CANopen device with your favourite microcontroller, see *deviceSupport.md*. There is also a bare-metal demo for [PIC microcontrollers](https://github.com/CANopenNode/CANopenPIC), most complete example is for PIC32. -Assigning Node-ID or CAN bitrate to unconfigured nodes, which support LSS configuration, is described in *LSSusage.md*. +Assigning Node-ID or CAN bitrate, which support LSS configuration, is described in *LSSusage.md*. Some further CANopenNode related Linux tools are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket). diff --git a/example/main_blank.c b/example/main_blank.c index 24a85fb8..3dd2778a 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -38,6 +38,7 @@ /* Global variables and objects */ + volatile static bool_t CANopenConfiguredOK = false; /* Indication if CANopen modules are configured */ volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */ uint8_t LED_red, LED_green; @@ -48,6 +49,10 @@ int main (void){ CO_ReturnError_t err; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; uint32_t heapMemoryUsed; + void *CANmoduleAddress = NULL; /* CAN module address */ + uint8_t pendingNodeId = 10; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ + uint8_t activeNodeId = 10; /* Copied from CO_pendingNodeId in the communication reset section */ + uint16_t pendingBitRate = 125; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ /* Configure microcontroller. */ @@ -75,21 +80,30 @@ int main (void){ /* CANopen communication reset - initialize CANopen objects *******************/ uint16_t timer1msPrevious; - log_printf("CANopenNode - Reset communication\n"); + log_printf("CANopenNode - Reset communication...\n"); /* disable CAN and CAN interrupts */ + CANopenConfiguredOK = false; /* initialize CANopen */ - err = CO_CANinit(NULL /* CAN module address */, 125 /* bit rate */); + err = CO_CANinit(CANmoduleAddress, pendingBitRate); if (err != CO_ERROR_NO) { log_printf("Error: CAN initialization failed: %d\n", err); return 0; } - err = CO_CANopenInit(10 /* NodeID */); + err = CO_LSSinit(&pendingNodeId, &pendingBitRate); if(err != CO_ERROR_NO) { + log_printf("Error: LSS slave initialization failed: %d\n", err); + return 0; + } + activeNodeId = pendingNodeId; + err = CO_CANopenInit(activeNodeId); + if(err == CO_ERROR_NO) { + CANopenConfiguredOK = true; + } + else if(err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { log_printf("Error: CANopen initialization failed: %d\n", err); return 0; - /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */ } /* Configure Timer interrupt function for execution every 1 millisecond */ @@ -98,6 +112,12 @@ int main (void){ /* Configure CAN transmit and receive interrupt */ + /* Configure CANopen callbacks, etc */ + if(CANopenConfiguredOK) { + + } + + /* start CAN */ CO_CANsetNormalMode(CO->CANmodule[0]); diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c index b31f4f8d..78185aee 100644 --- a/socketCAN/CO_Linux_threads.c +++ b/socketCAN/CO_Linux_threads.c @@ -116,8 +116,19 @@ static void threadMainWait_callback(void *object) } } -void threadMainWait_init(void) +void threadMainWait_init(bool_t CANopenConfiguredOK) { + /* Configure LSS slave callback function */ +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + CO_LSSslave_initCallbackPre(CO->LSSslave, NULL, threadMainWait_callback); +#endif + + /* Initial value for time calculation */ + tmw.start = CO_LinuxThreads_clock_gettime_us(); + + if (!CANopenConfiguredOK) + return; + /* Configure callback functions */ CO_NMT_initCallbackPre(CO->NMT, NULL, threadMainWait_callback); CO_SDO_initCallbackPre(CO->SDO[0], NULL, threadMainWait_callback); @@ -127,14 +138,19 @@ void threadMainWait_init(void) CO_SDOclient_initCallbackPre(CO->SDOclient[0], NULL, threadMainWait_callback); #endif +#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE + CO_TIME_initCallbackPre(CO->TIME, NULL, threadMainWait_callback); +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + CO_LSSmaster_initCallbackPre(CO->LSSmaster, NULL, threadMainWait_callback); +#endif +#endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_GTWA_initRead(CO->gtwa, gtwa_write_response, (void *)&tmw.gtwa_fd); tmw.freshCommand = true; #endif - - /* Initial value for time calculation */ - tmw.start = CO_LinuxThreads_clock_gettime_us(); } void threadMainWait_initOnce(uint32_t interval_us, @@ -296,11 +312,6 @@ void threadMainWait_initOnce(uint32_t interval_us, void threadMainWait_close(void) { - CO_NMT_initCallbackPre(CO->NMT, NULL, NULL); - CO_SDO_initCallbackPre(CO->SDO[0], NULL, NULL); - CO_EM_initCallbackPre(CO->em, NULL, NULL); - CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, NULL); - close(tmw.epoll_fd); tmw.epoll_fd = -1; @@ -402,10 +413,16 @@ uint32_t threadMainWait_process(CO_NMT_reset_cmd_t *reset) } else if (ev.data.fd == tmw.gtwa_fd) { char buf[CO_CONFIG_GTWA_COMM_BUF_SIZE]; - size_t space = CO_GTWA_write_getSpace(CO->gtwa); + size_t space = CO->nodeIdUnconfigured ? + CO_CONFIG_GTWA_COMM_BUF_SIZE : + CO_GTWA_write_getSpace(CO->gtwa); s = read(tmw.gtwa_fd, buf, space); - if (s < 0 && errno != EAGAIN) { + + if (CO->nodeIdUnconfigured) { + /* purge data */ + } + else if (s < 0 && errno != EAGAIN) { log_printf(LOG_DEBUG, DBG_ERRNO, "read(gtwa_fd)"); } else if (s >= 0) { diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index 78b01294..33ba786d 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -61,8 +61,7 @@ typedef enum { * CANopenNode runs in two threads: * - timer based real-time thread for CAN receive, SYNC and PDO, see * CANrx_threadTmr_process() - * - mainline thread for other processing, see threadMain_process() or - * threadMainWait_process() + * - mainline thread for other processing, see threadMainWait_process() * * The "threads" specified here do not fork threads themselves, but require * that two threads are provided by the calling application. @@ -72,48 +71,17 @@ typedef enum { */ -/** - * Initialize mainline thread - basic. - * - * @param callback this function is called to indicate #threadMain_process() has - * work to do - * @param object this pointer is given to _callback()_ - */ -void threadMain_init(void (*callback)(void*), void *object); - - -/** - * Cleanup mainline thread - basic. - */ -void threadMain_close(void); - - -/** - * Process mainline thread - basic. - * - * threadMain is non-realtime thread for CANopenNode processing. It is - * initialized by threadMain_init(). There is no configuration for CANopen - * objects. There is also no configuration for epool or interval timer or - * eventfd. These must be specified externally. For more complete function see - * threadMainWait_process(), they are included. - * - * threadMain_process() calls CO_process() function for processing mainline - * CANopen objects. It is non-blocking and should be called cyclically in 50 ms - * intervals (typically). Function must also be called immediately after - * callback provided in threadMain_init() is called. - * - * @param reset return value from CO_process() function. - */ -void threadMain_process(CO_NMT_reset_cmd_t *reset); - - /** * Initialize mainline thread - blocking. * * Function must be called always in communication reset section, after * CO_CANopenInit(). + * + * @param CANopenConfiguredOK True, if node has successfully passed NMT + * initialization - it has a valid CANopen node-id, all CANopen objects + * are configured and CANopen runs normally. */ -void threadMainWait_init(void); +void threadMainWait_init(bool_t CANopenConfiguredOK); /** diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index dae915aa..b2c76293 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -71,8 +71,12 @@ /* Other variables and objects */ +volatile static bool_t CANopenConfiguredOK = false; /* Indication if CANopen modules are configured */ static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ -static int CO_ownNodeId = -1; /* Use value from Object Dictionary or set to 1..127 by arguments */ +static uint8_t CO_pendingNodeId = 0xFF;/* Use value from Object Dictionary or by arguments (set to 1..127 + * or unconfigured=0xFF). Can be changed by LSS slave. */ +static uint8_t CO_activeNodeId = 0xFF;/* Copied from CO_pendingNodeId in the communication reset section */ +static uint16_t CO_pendingBitRate = 0; /* CAN bitrate, not used here */ static CO_OD_storage_t odStor; /* Object Dictionary storage object for CO_OD_ROM */ static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ static char *odStorFile_rom = "od_storage"; /* Name of the file */ @@ -127,7 +131,7 @@ static void EmergencyRxCallback(const uint16_t ident, const uint8_t errorBit, const uint32_t infoCode) { - int16_t nodeIdRx = ident ? (ident&0x7F) : CO_ownNodeId; + int16_t nodeIdRx = ident ? (ident&0x7F) : CO_activeNodeId; log_printf(LOG_NOTICE, DBG_EMERGENCY_RX, nodeIdRx, errorCode, errorRegister, errorBit, infoCode); @@ -161,6 +165,14 @@ static void HeartbeatNmtChangedCallback(uint8_t nodeId, nodeId, NmtState2Str(state), state); } +/* callback for storing node id and bitrate */ +static bool_t LSScfgStoreCallback(void *object, uint8_t id, uint16_t bitRate) { + (void)object; + OD_CANNodeID = id; + OD_CANBitRate = bitRate; + return true; +} + /* Print usage */ static void printUsage(char *progName) { printf( @@ -168,8 +180,8 @@ printf( printf( "\n" "Options:\n" -" -i CANopen Node-id (1..127). If not specified, value from\n" -" Object dictionary (0x2101) is used.\n" +" -i CANopen Node-id (1..127) or 0xFF(unconfigured). If not\n" +" specified, value from Object dictionary (0x2101) is used.\n" " -p Real-time priority of RT thread (1 .. 99). If not set or\n" " set to -1, then normal scheduler is used for RT thread.\n" " -r Enable reboot on CANopen NMT reset_node command. \n" @@ -238,7 +250,7 @@ int main (int argc, char *argv[]) { const char comm_tcp[] = "tcp-"; switch (opt) { case 'i': - CO_ownNodeId = strtol(optarg, NULL, 0); + CO_pendingNodeId = (uint8_t)strtol(optarg, NULL, 0); nodeIdFromArgs = true; break; case 'p': rtPriority = strtol(optarg, NULL, 0); @@ -288,8 +300,17 @@ int main (int argc, char *argv[]) { CANdevice0Index = if_nametoindex(CANdevice); } - if(nodeIdFromArgs && (CO_ownNodeId < 1 || CO_ownNodeId > 127)) { - log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_ownNodeId); + if(!nodeIdFromArgs) { + /* use value from Object dictionary, if not set by program arguments */ + CO_pendingNodeId = OD_CANNodeID; + } + + if((CO_pendingNodeId < 1 || CO_pendingNodeId > 127) +#if CO_NO_LSS_SLAVE == 1 + && CO_pendingNodeId != CO_LSS_NODE_ID_ASSIGNMENT +#endif + ) { + log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_pendingNodeId); printUsage(argv[0]); exit(EXIT_FAILURE); } @@ -307,7 +328,7 @@ int main (int argc, char *argv[]) { } - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "starting"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_pendingNodeId, "starting"); /* Allocate memory for CANopen objects */ @@ -352,9 +373,6 @@ int main (int argc, char *argv[]) { while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { /* CANopen communication reset - initialize CANopen objects *******************/ - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "communication reset"); - - /* Wait rt_thread. */ if(!firstRun) { CO_LOCK_OD(); @@ -364,50 +382,62 @@ int main (int argc, char *argv[]) { /* Enter CAN configuration. */ + CANopenConfiguredOK = false; CO_CANsetConfigurationMode((void *)CANdevice0Index); /* initialize CANopen */ - if(!nodeIdFromArgs) { - /* use value from Object dictionary, if not set by program arguments */ - CO_ownNodeId = OD_CANNodeID; - } - err = CO_CANinit((void *)CANdevice0Index, 0 /* bit rate not used */); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANinit()", err); exit(EXIT_FAILURE); } - err = CO_CANopenInit(CO_ownNodeId); + err = CO_LSSinit(&CO_pendingNodeId, &CO_pendingBitRate); if(err != CO_ERROR_NO) { - log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); + log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_LSSinit()", err); exit(EXIT_FAILURE); } - /* initialize part of threadMain and callbacks */ - threadMainWait_init(); - CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); - CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); - CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, - HeartbeatNmtChangedCallback); - - - /* initialize OD objects 1010 and 1011 and verify errors. */ - CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U); - CO_OD_configure(CO->SDO[0], OD_H1011_REST_PARAM_FUNC, CO_ODF_1011, (void*)&odStor, 0, 0U); - if(odStorStatus_rom != CO_ERROR_NO) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_rom); + CO_activeNodeId = CO_pendingNodeId; + + err = CO_CANopenInit(CO_activeNodeId); + if(err == CO_ERROR_NO) { + CANopenConfiguredOK = true; } - if(odStorStatus_eeprom != CO_ERROR_NO) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_eeprom + 1000); + else if(err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); + exit(EXIT_FAILURE); } + /* initialize part of threadMain and callbacks */ + threadMainWait_init(CANopenConfiguredOK); + CO_LSSslave_initCfgStoreCallback(CO->LSSslave, NULL, + LSScfgStoreCallback); + if(CANopenConfiguredOK) { + CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); + CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); + CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, + HeartbeatNmtChangedCallback); + /* initialize OD objects 1010 and 1011 and verify errors. */ + CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U); + CO_OD_configure(CO->SDO[0], OD_H1011_REST_PARAM_FUNC, CO_ODF_1011, (void*)&odStor, 0, 0U); + if(odStorStatus_rom != CO_ERROR_NO) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_rom); + } + if(odStorStatus_eeprom != CO_ERROR_NO) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_eeprom + 1000); + } #if CO_NO_TRACE > 0 - /* Initialize time */ - CO_time_init(&CO_time, CO->SDO[0], &OD_time.epochTimeBaseMs, &OD_time.epochTimeOffsetMs, 0x2130); + /* Initialize time */ + CO_time_init(&CO_time, CO->SDO[0], &OD_time.epochTimeBaseMs, &OD_time.epochTimeOffsetMs, 0x2130); #endif + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "communication reset"); + } + else { + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "node-id not initialized"); + } /* First time only initialization. */ if(firstRun) { @@ -438,14 +468,14 @@ int main (int argc, char *argv[]) { #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_programStart(); + app_programStart(CANopenConfiguredOK); #endif } /* if(firstRun) */ #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_communicationReset(); + app_communicationReset(CANopenConfiguredOK); #endif @@ -454,7 +484,7 @@ int main (int argc, char *argv[]) { reset = CO_RESET_NOT; - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "running ..."); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "running ..."); while(reset == CO_RESET_NOT && CO_endProgram == 0) { @@ -462,7 +492,7 @@ int main (int argc, char *argv[]) { uint32_t timer1usDiff = threadMainWait_process(&reset); #ifdef CO_USE_APPLICATION - app_programAsync(timer1usDiff); + app_programAsync(CANopenConfiguredOK, timer1usDiff); #endif CO_OD_storage_autoSave(&odStorAuto, timer1usDiff, 60000000); @@ -492,7 +522,7 @@ int main (int argc, char *argv[]) { threadMainWait_close(); CO_delete((void *)CANdevice0Index); - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_ownNodeId, "finished"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "finished"); /* Flush all buffers (and reboot) */ if(rebootEnable && reset == CO_RESET_APP) { @@ -528,7 +558,7 @@ static void* rt_thread(void* arg) { #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_program1ms(); + app_program1ms(CANopenConfiguredOK); #endif } From 655123340608ad5bd3c081151fb5a08bd2ee7a58 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 9 Jun 2020 17:11:09 +0200 Subject: [PATCH 084/520] GCC 10: Fix dereference of NULL warning (#191) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 10 static analyzer (-fanalyzer) warn about possible dereference of NULL ‘ext’ on 'ext->pODFunc'. This patch adds a guard on 'ext' to fix the issue. --- 301/CO_SDOserver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 11683328..6e974e71 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -511,7 +511,7 @@ uint32_t CO_SDO_readOD(CO_SDO_t *SDO, uint16_t SDOBufferSize){ uint8_t *SDObuffer = SDO->ODF_arg.data; uint8_t *ODdata = (uint8_t*)SDO->ODF_arg.ODdataStorage; uint16_t length = SDO->ODF_arg.dataLength; - CO_OD_extension_t *ext = 0; + CO_OD_extension_t *ext = NULL; /* is object readable? */ if((SDO->ODF_arg.attribute & CO_ODA_READABLE) == 0) @@ -530,7 +530,7 @@ uint32_t CO_SDO_readOD(CO_SDO_t *SDO, uint16_t SDOBufferSize){ } /* if domain, Object dictionary function MUST exist */ else{ - if(ext->pODFunc == NULL){ + if(ext && ext->pODFunc == NULL){ CO_UNLOCK_OD(); return CO_SDO_AB_DEVICE_INCOMPAT; /* general internal incompatibility in the device */ } @@ -538,7 +538,7 @@ uint32_t CO_SDO_readOD(CO_SDO_t *SDO, uint16_t SDOBufferSize){ /* call Object dictionary function if registered */ SDO->ODF_arg.reading = true; - if(ext->pODFunc != NULL){ + if(ext && ext->pODFunc != NULL){ uint32_t abortCode = ext->pODFunc(&SDO->ODF_arg); if(abortCode != 0U){ CO_UNLOCK_OD(); From 35854fd6a0599b1c09bbd238458f20be0e7d095e Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 10 Jun 2020 09:13:49 +0200 Subject: [PATCH 085/520] CO_trace: fix warning "cast increases required alignment of target type" Same as #193 in v1.3-master --- README.md | 3 ++- extra/CO_trace.c | 12 ++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3df7cd16..4508e277 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,8 @@ Documentation with [Getting started](doc/gettingStarted.md), directory. Code is documented in header files. Running [doxygen](http://www.doxygen.nl/) in project base directory will produce complete html documentation. -Just open CANopenNode/doc/html/index.html in the browser. +Just open CANopenNode/doc/html/index.html in the browser. Alternatively browse +documentation [online](https://canopennode.github.io/CANopenSocket/). Report issues on https://github.com/CANopenNode/CANopenNode/issues diff --git a/extra/CO_trace.c b/extra/CO_trace.c index 5bfcb27c..80ce5531 100644 --- a/extra/CO_trace.c +++ b/extra/CO_trace.c @@ -180,8 +180,7 @@ static CO_SDO_abortCode_t CO_ODF_traceConfig(CO_ODF_arg_t *ODF_arg) { switch(ODF_arg->subIndex) { case 1: /* size */ if(ODF_arg->reading) { - uint32_t *value = (uint32_t*) ODF_arg->data; - *value = trace->bufferSize; + CO_setUint32(ODF_arg->data, trace->bufferSize); } break; @@ -249,22 +248,19 @@ static CO_SDO_abortCode_t CO_ODF_trace(CO_ODF_arg_t *ODF_arg) { switch(ODF_arg->subIndex) { case 1: /* size */ if(ODF_arg->reading) { - uint32_t *value = (uint32_t*) ODF_arg->data; uint32_t size = trace->bufferSize; uint32_t wp = trace->writePtr; uint32_t rp = trace->readPtr; if(wp >= rp) { - *value = wp - rp; + CO_setUint32(ODF_arg->data, wp - rp); } else { - *value = size - rp + wp; + CO_setUint32(ODF_arg->data, size - rp + wp); } } else { - uint32_t *value = (uint32_t*) ODF_arg->data; - - if(*value == 0) { + if(CO_getUint32(ODF_arg->data) == 0) { /* clear buffer, handle race conditions */ while(trace->readPtr != 0 || trace->writePtr != 0) { trace->readPtr = 0; From e1c7e2dbfa96719c809c145f0b59b8f63b9cd56a Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 11 Jun 2020 10:33:03 +0200 Subject: [PATCH 086/520] Add fifo queue for SDO received messages to fix possible drops Same as pr #174 in v1.3-master --- 301/CO_SDOserver.c | 220 +++++++++++++++++++++++++++------------------ 301/CO_SDOserver.h | 28 +++++- README.md | 3 + 3 files changed, 161 insertions(+), 90 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 6e974e71..be09ed35 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -46,6 +46,19 @@ #error CO_CONFIG_SDO_BLOCK is enabled, CO_CONFIG_SDO_SEGMENTED must be enabled also. #endif +static void CO_SDO_receive_done(CO_SDO_t *SDO){ +#if CO_SDO_RX_DATA_SIZE > 1 + uint8_t rcv = SDO->CANrxRcv; + uint8_t newRcv = rcv; + + if (++newRcv >= CO_SDO_RX_DATA_SIZE) + newRcv = 0; + SDO->CANrxRcv = newRcv; + CO_FLAG_SET(SDO->CANrxNew[rcv]); +#else + CO_FLAG_SET(SDO->CANrxNew[0]); +#endif +} /* * Read received message from CAN module. @@ -57,29 +70,27 @@ static void CO_SDO_receive(void *object, void *msg); static void CO_SDO_receive(void *object, void *msg){ CO_SDO_t *SDO; + uint8_t rcv, *CANrxData; uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); SDO = (CO_SDO_t*)object; /* this is the correct pointer type of the first argument */ + rcv = SDO->CANrxRcv; + CANrxData = SDO->CANrxData[rcv]; - /* WARNING: When doing a SDO block upload and immediately after that - * starting another SDO request, this request is dropped. Especially if - * processing function has slow response. - * See: https://github.com/CANopenNode/CANopenNode/issues/39 */ - - /* verify message length and message overflow (previous message was not processed yet) */ - if((DLC == 8U) && (!CO_FLAG_READ(SDO->CANrxNew))){ + /* verify message length and message queue overflow (if previous messages were not processed yet) */ + if((DLC == 8U) && (!CO_FLAG_READ(SDO->CANrxNew[rcv]))){ if(SDO->state != CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) { /* copy data and set 'new message' flag */ - memcpy(SDO->CANrxData, data, DLC); - CO_FLAG_SET(SDO->CANrxNew); + memcpy(CANrxData, data, DLC); + CO_SDO_receive_done(SDO); } else { /* block download, copy data directly */ uint8_t seqno; - SDO->CANrxData[0] = data[0]; - seqno = SDO->CANrxData[0] & 0x7fU; + CANrxData[0] = data[0]; + seqno = CANrxData[0] & 0x7fU; SDO->timeoutTimer = 0; /* clear timeout in sub-block transfer indication if set before */ if (SDO->timeoutSubblockDownolad) { @@ -99,30 +110,30 @@ static void CO_SDO_receive(void *object, void *msg){ if(SDO->bufferOffset >= CO_CONFIG_SDO_BUFFER_SIZE) { /* buffer full, break reception */ SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - CO_FLAG_SET(SDO->CANrxNew); + CO_SDO_receive_done(SDO); break; } } /* break reception if last segment, block ends or block sequence is too large */ - if(((SDO->CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) { + if(((CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) { SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - CO_FLAG_SET(SDO->CANrxNew); + CO_SDO_receive_done(SDO); } } - else if((seqno == SDO->sequence) || (SDO->sequence == 0U)){ + else if((seqno == SDO->sequence) || (SDO->sequence == 0U)) { /* Ignore message, if it is duplicate or if sequence didn't started yet. */ } else { /* seqno is wrong, send response without resetting sequence */ SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2; - CO_FLAG_SET(SDO->CANrxNew); + CO_SDO_receive_done(SDO); } } #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles SDO server. */ - if(CO_FLAG_READ(SDO->CANrxNew) && SDO->pFunctSignalPre != NULL) { + if(CO_FLAG_READ(SDO->CANrxNew[rcv]) && SDO->pFunctSignalPre != NULL) { SDO->pFunctSignalPre(SDO->functSignalObjectPre); } #endif @@ -206,7 +217,14 @@ CO_ReturnError_t CO_SDO_init( SDO->nodeId = nodeId; SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; SDO->state = CO_SDO_ST_IDLE; - CO_FLAG_CLEAR(SDO->CANrxNew); + + uint8_t i; + for(i=0U; iCANrxNew[i]); + } + SDO->CANrxRcv = 0; + SDO->CANrxProc = 0; + #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE SDO->pFunctSignalPre = NULL; SDO->functSignalObjectPre = NULL; @@ -649,6 +667,27 @@ uint32_t CO_SDO_writeOD(CO_SDO_t *SDO, uint16_t length){ return 0; } +/******************************************************************************/ +static void CO_SDO_process_done(CO_SDO_t *SDO, uint32_t *timerNext_us) { +#if CO_SDO_RX_DATA_SIZE > 1 + uint8_t proc = SDO->CANrxProc; + uint8_t newProc = proc; + + if (++newProc >= CO_SDO_RX_DATA_SIZE) + newProc = 0; + + SDO->CANrxProc = newProc; + CO_FLAG_CLEAR(SDO->CANrxNew[proc]); + +#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT + if ((timerNext_us != NULL) && (CO_FLAG_READ(SDO->CANrxNew[newProc]))) + timerNext_us = 0; /* Set timerNext_us to 0 to inform OS to call CO_SDO_process function again without delay. */ +#endif +#else + (void)(timerNext_us); + CO_FLAG_CLEAR(SDO->CANrxNew[0]); +#endif +} /******************************************************************************/ static void CO_SDO_abort(CO_SDO_t *SDO, uint32_t code){ @@ -658,7 +697,9 @@ static void CO_SDO_abort(CO_SDO_t *SDO, uint32_t code){ SDO->CANtxBuff->data[3] = SDO->ODF_arg.subIndex; CO_memcpySwap4(&SDO->CANtxBuff->data[4], &code); SDO->state = CO_SDO_ST_IDLE; - CO_FLAG_CLEAR(SDO->CANrxNew); + /* skip all received messages in queue */ + while (CO_FLAG_READ(SDO->CANrxNew[SDO->CANrxProc])) + CO_SDO_process_done(SDO, NULL); CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); } @@ -672,23 +713,28 @@ int8_t CO_SDO_process( { CO_SDO_state_t state = CO_SDO_ST_IDLE; bool_t sendResponse = false; + uint8_t proc, *CANrxData; + bool_t isNew; + + proc = SDO->CANrxProc; + isNew = CO_FLAG_READ(SDO->CANrxNew[proc]); /* return if idle */ - if((SDO->state == CO_SDO_ST_IDLE) && (!CO_FLAG_READ(SDO->CANrxNew))){ + if((SDO->state == CO_SDO_ST_IDLE) && (!isNew)){ return 0; } /* SDO is allowed to work only in operational or pre-operational NMT state */ if(!NMTisPreOrOperational){ SDO->state = CO_SDO_ST_IDLE; - CO_FLAG_CLEAR(SDO->CANrxNew); + CO_SDO_process_done(SDO, timerNext_us); return 0; } - /* Is something new to process? */ - if((!SDO->CANtxBuff->bufferFull) && ((CO_FLAG_READ(SDO->CANrxNew)) || (SDO->state == CO_SDO_ST_UPLOAD_BL_SUBBLOCK))){ - uint8_t CCS = SDO->CANrxData[0] >> 5; /* Client command specifier */ + CANrxData = SDO->CANrxData[proc]; + /* Is something new to process? */ + if((!SDO->CANtxBuff->bufferFull) && (isNew || (SDO->state == CO_SDO_ST_UPLOAD_BL_SUBBLOCK))){ /* reset timeout */ if(SDO->state != CO_SDO_ST_UPLOAD_BL_SUBBLOCK) { SDO->timeoutTimer = 0; @@ -699,9 +745,9 @@ int8_t CO_SDO_process( memset(SDO->CANtxBuff->data, 0, sizeof(SDO->CANtxBuff->data)); /* Is abort from client? */ - if((CO_FLAG_READ(SDO->CANrxNew)) && (SDO->CANrxData[0] == CCS_ABORT)){ + if(isNew && (CANrxData[0] == CCS_ABORT)){ SDO->state = CO_SDO_ST_IDLE; - CO_FLAG_CLEAR(SDO->CANrxNew); + CO_SDO_process_done(SDO, timerNext_us); return -1; } @@ -712,6 +758,7 @@ int8_t CO_SDO_process( else{ uint32_t abortCode; uint16_t index; + uint8_t CCS = CANrxData[0] >> 5; /* Client command specifier */ /* Is client command specifier valid */ if((CCS != CCS_DOWNLOAD_INITIATE) && (CCS != CCS_UPLOAD_INITIATE) && @@ -721,9 +768,9 @@ int8_t CO_SDO_process( } /* init ODF_arg */ - index = SDO->CANrxData[2]; - index = index << 8 | SDO->CANrxData[1]; - abortCode = CO_SDO_initTransfer(SDO, index, SDO->CANrxData[3]); + index = CANrxData[2]; + index = index << 8 | CANrxData[1]; + abortCode = CO_SDO_initTransfer(SDO, index, CANrxData[3]); if(abortCode != 0U){ CO_SDO_abort(SDO, abortCode); return -1; @@ -754,7 +801,7 @@ int8_t CO_SDO_process( } /* if data size is large enough set state machine to block upload, otherwise set to normal transfer */ - if((CCS == CCS_UPLOAD_BLOCK) && (SDO->ODF_arg.dataLength > SDO->CANrxData[5])){ + if((CCS == CCS_UPLOAD_BLOCK) && (SDO->ODF_arg.dataLength > CANrxData[5])){ state = CO_SDO_ST_UPLOAD_BL_INITIATE; } else{ @@ -796,7 +843,7 @@ int8_t CO_SDO_process( return 0; } - /* state machine (buffer is freed (CO_FLAG_CLEAR()) at the end) */ + /* state machine (buffer is freed with process_done() at the end) */ switch(state){ uint32_t abortCode; uint16_t len, i; @@ -805,25 +852,25 @@ int8_t CO_SDO_process( case CO_SDO_ST_DOWNLOAD_INITIATE:{ /* default response */ SDO->CANtxBuff->data[0] = 0x60; - SDO->CANtxBuff->data[1] = SDO->CANrxData[1]; - SDO->CANtxBuff->data[2] = SDO->CANrxData[2]; - SDO->CANtxBuff->data[3] = SDO->CANrxData[3]; + SDO->CANtxBuff->data[1] = CANrxData[1]; + SDO->CANtxBuff->data[2] = CANrxData[2]; + SDO->CANtxBuff->data[3] = CANrxData[3]; /* Expedited transfer */ - if((SDO->CANrxData[0] & 0x02U) != 0U){ + if((CANrxData[0] & 0x02U) != 0U){ /* is size indicated? Get message length */ - if((SDO->CANrxData[0] & 0x01U) != 0U){ - len = 4U - ((SDO->CANrxData[0] >> 2U) & 0x03U); + if((CANrxData[0] & 0x01U) != 0U){ + len = 4U - ((CANrxData[0] >> 2U) & 0x03U); } else{ len = SDO->ODF_arg.dataLength; } /* copy data to SDO buffer */ - SDO->ODF_arg.data[0] = SDO->CANrxData[4]; - SDO->ODF_arg.data[1] = SDO->CANrxData[5]; - SDO->ODF_arg.data[2] = SDO->CANrxData[6]; - SDO->ODF_arg.data[3] = SDO->CANrxData[7]; + SDO->ODF_arg.data[0] = CANrxData[4]; + SDO->ODF_arg.data[1] = CANrxData[5]; + SDO->ODF_arg.data[2] = CANrxData[6]; + SDO->ODF_arg.data[3] = CANrxData[7]; /* write data to the Object dictionary */ abortCode = CO_SDO_writeOD(SDO, len); @@ -844,9 +891,9 @@ int8_t CO_SDO_process( /* Segmented transfer */ else{ /* verify length if size is indicated */ - if((SDO->CANrxData[0]&0x01) != 0){ + if((CANrxData[0]&0x01) != 0){ uint32_t lenRx; - CO_memcpySwap4(&lenRx, &SDO->CANrxData[4]); + CO_memcpySwap4(&lenRx, &CANrxData[4]); SDO->ODF_arg.dataLengthTotal = lenRx; /* verify length except for domain data type */ @@ -865,20 +912,20 @@ int8_t CO_SDO_process( case CO_SDO_ST_DOWNLOAD_SEGMENTED:{ /* verify client command specifier */ - if((SDO->CANrxData[0]&0xE0) != 0x00U){ + if((CANrxData[0]&0xE0) != 0x00U){ CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ return -1; } /* verify toggle bit */ - i = (SDO->CANrxData[0]&0x10U) ? 1U : 0U; + i = (CANrxData[0]&0x10U) ? 1U : 0U; if(i != SDO->sequence){ CO_SDO_abort(SDO, CO_SDO_AB_TOGGLE_BIT);/* toggle bit not alternated */ return -1; } /* get size of data in message */ - len = 7U - ((SDO->CANrxData[0] >> 1U) & 0x07U); + len = 7U - ((CANrxData[0] >> 1U) & 0x07U); /* verify length. Domain data type enables length larger than SDO buffer size */ if((SDO->bufferOffset + len) > SDO->ODF_arg.dataLength){ @@ -902,10 +949,10 @@ int8_t CO_SDO_process( /* copy data to buffer */ for(i=0U; iODF_arg.data[SDO->bufferOffset++] = SDO->CANrxData[i+1]; + SDO->ODF_arg.data[SDO->bufferOffset++] = CANrxData[i+1]; /* If no more segments to be downloaded, write data to the Object dictionary */ - if((SDO->CANrxData[0] & 0x01U) != 0U){ + if((CANrxData[0] & 0x01U) != 0U){ SDO->ODF_arg.lastSegment = true; abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset); if(abortCode != 0U){ @@ -930,29 +977,29 @@ int8_t CO_SDO_process( case CO_SDO_ST_DOWNLOAD_BL_INITIATE:{ /* verify client command specifier and subcommand */ - if((SDO->CANrxData[0]&0xE1U) != 0xC0U){ + if((CANrxData[0]&0xE1U) != 0xC0U){ CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ return -1; } /* prepare response */ SDO->CANtxBuff->data[0] = 0xA4; - SDO->CANtxBuff->data[1] = SDO->CANrxData[1]; - SDO->CANtxBuff->data[2] = SDO->CANrxData[2]; - SDO->CANtxBuff->data[3] = SDO->CANrxData[3]; + SDO->CANtxBuff->data[1] = CANrxData[1]; + SDO->CANtxBuff->data[2] = CANrxData[2]; + SDO->CANtxBuff->data[3] = CANrxData[3]; /* blksize */ SDO->blksize = (CO_CONFIG_SDO_BUFFER_SIZE > (7*127)) ? 127 : (CO_CONFIG_SDO_BUFFER_SIZE / 7); SDO->CANtxBuff->data[4] = SDO->blksize; /* is CRC enabled */ - SDO->crcEnabled = (SDO->CANrxData[0] & 0x04) ? true : false; + SDO->crcEnabled = (CANrxData[0] & 0x04) ? true : false; SDO->crc = 0; /* verify length if size is indicated */ - if((SDO->CANrxData[0]&0x02) != 0U){ + if((CANrxData[0]&0x02) != 0U){ uint32_t lenRx; - CO_memcpySwap4(&lenRx, &SDO->CANrxData[4]); + CO_memcpySwap4(&lenRx, &CANrxData[4]); SDO->ODF_arg.dataLengthTotal = lenRx; /* verify length except for domain data type */ @@ -981,7 +1028,7 @@ int8_t CO_SDO_process( case CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2:{ /* check if last segment received */ lastSegmentInSubblock = (!SDO->timeoutSubblockDownolad && - ((SDO->CANrxData[0] & 0x80U) == 0x80U)) ? true : false; + ((CANrxData[0] & 0x80U) == 0x80U)) ? true : false; /* prepare response */ SDO->CANtxBuff->data[0] = 0xA2; @@ -1036,13 +1083,13 @@ int8_t CO_SDO_process( case CO_SDO_ST_DOWNLOAD_BL_END:{ /* verify client command specifier and subcommand */ - if((SDO->CANrxData[0]&0xE1U) != 0xC1U){ + if((CANrxData[0]&0xE1U) != 0xC1U){ CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ return -1; } /* number of bytes in the last segment of the last block that do not contain data. */ - len = (SDO->CANrxData[0]>>2U) & 0x07U; + len = (CANrxData[0]>>2U) & 0x07U; SDO->bufferOffset -= len; /* calculate and verify CRC, if enabled */ @@ -1050,7 +1097,7 @@ int8_t CO_SDO_process( uint16_t crc; SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->bufferOffset, SDO->crc); - CO_memcpySwap2(&crc, &SDO->CANrxData[1]); + CO_memcpySwap2(&crc, &CANrxData[1]); if(SDO->crc != crc){ CO_SDO_abort(SDO, CO_SDO_AB_CRC); /* CRC error (block mode only). */ @@ -1079,9 +1126,9 @@ int8_t CO_SDO_process( case CO_SDO_ST_UPLOAD_INITIATE:{ /* default response */ - SDO->CANtxBuff->data[1] = SDO->CANrxData[1]; - SDO->CANtxBuff->data[2] = SDO->CANrxData[2]; - SDO->CANtxBuff->data[3] = SDO->CANrxData[3]; + SDO->CANtxBuff->data[1] = CANrxData[1]; + SDO->CANtxBuff->data[2] = CANrxData[2]; + SDO->CANtxBuff->data[3] = CANrxData[3]; /* Expedited transfer */ if(SDO->ODF_arg.dataLength <= 4U){ @@ -1123,13 +1170,13 @@ int8_t CO_SDO_process( case CO_SDO_ST_UPLOAD_SEGMENTED:{ /* verify client command specifier */ - if((SDO->CANrxData[0]&0xE0U) != 0x60U){ + if((CANrxData[0]&0xE0U) != 0x60U){ CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ return -1; } /* verify toggle bit */ - i = ((SDO->CANrxData[0]&0x10U) != 0) ? 1U : 0U; + i = ((CANrxData[0]&0x10U) != 0) ? 1U : 0U; if(i != SDO->sequence){ CO_SDO_abort(SDO, CO_SDO_AB_TOGGLE_BIT);/* toggle bit not alternated */ return -1; @@ -1194,12 +1241,12 @@ int8_t CO_SDO_process( case CO_SDO_ST_UPLOAD_BL_INITIATE:{ /* default response */ - SDO->CANtxBuff->data[1] = SDO->CANrxData[1]; - SDO->CANtxBuff->data[2] = SDO->CANrxData[2]; - SDO->CANtxBuff->data[3] = SDO->CANrxData[3]; + SDO->CANtxBuff->data[1] = CANrxData[1]; + SDO->CANtxBuff->data[2] = CANrxData[2]; + SDO->CANtxBuff->data[3] = CANrxData[3]; /* calculate CRC, if enabled */ - if((SDO->CANrxData[0] & 0x04U) != 0U){ + if((CANrxData[0] & 0x04U) != 0U){ SDO->crcEnabled = true; SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->ODF_arg.dataLength, 0); } @@ -1209,10 +1256,10 @@ int8_t CO_SDO_process( } /* Number of segments per block */ - SDO->blksize = SDO->CANrxData[4]; + SDO->blksize = CANrxData[4]; /* verify client subcommand */ - if((SDO->CANrxData[0]&0x03U) != 0x00U){ + if((CANrxData[0]&0x03U) != 0x00U){ CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ return -1; } @@ -1242,7 +1289,7 @@ int8_t CO_SDO_process( case CO_SDO_ST_UPLOAD_BL_INITIATE_2:{ /* verify client command specifier and subcommand */ - if((SDO->CANrxData[0]&0xE3U) != 0xA3U){ + if((CANrxData[0]&0xE3U) != 0xA3U){ CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ return -1; } @@ -1250,7 +1297,8 @@ int8_t CO_SDO_process( SDO->bufferOffset = 0U; SDO->sequence = 0U; SDO->endOfTransfer = false; - CO_FLAG_CLEAR(SDO->CANrxNew); + CO_SDO_process_done(SDO, timerNext_us); + isNew = false; SDO->state = CO_SDO_ST_UPLOAD_BL_SUBBLOCK; /* continue in next case */ } @@ -1258,17 +1306,17 @@ int8_t CO_SDO_process( case CO_SDO_ST_UPLOAD_BL_SUBBLOCK:{ /* is block confirmation received */ - if(CO_FLAG_READ(SDO->CANrxNew)){ + if(isNew){ uint8_t ackseq; uint16_t j; /* verify client command specifier and subcommand */ - if((SDO->CANrxData[0]&0xE3U) != 0xA2U){ + if((CANrxData[0]&0xE3U) != 0xA2U){ CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ return -1; } - ackseq = SDO->CANrxData[1]; /* sequence number of the last segment, that was received correctly. */ + ackseq = CANrxData[1]; /* sequence number of the last segment, that was received correctly. */ /* verify if response is too early */ if(ackseq > SDO->sequence){ @@ -1300,7 +1348,7 @@ int8_t CO_SDO_process( SDO->ODF_arg.dataLength -= ackseq * 7U; /* new block size */ - SDO->blksize = SDO->CANrxData[2]; + SDO->blksize = CANrxData[2]; /* If data type is domain, re-fill the data buffer if necessary and indicated so. */ if((SDO->ODF_arg.ODdataStorage == 0) && (SDO->ODF_arg.dataLength < (SDO->blksize*7U)) && (!SDO->ODF_arg.lastSegment)){ @@ -1335,14 +1383,11 @@ int8_t CO_SDO_process( SDO->bufferOffset = 0U; SDO->sequence = 0U; SDO->endOfTransfer = false; - - /* clear flag here */ - CO_FLAG_CLEAR(SDO->CANrxNew); } /* return, if all segments was already transfered or on end of transfer */ if((SDO->sequence == SDO->blksize) || (SDO->endOfTransfer)){ - return 1;/* don't call CO_FLAG_CLEAR, so return directly */ + break; } /* reset timeout */ @@ -1371,7 +1416,7 @@ int8_t CO_SDO_process( } /* send response */ - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + sendResponse = true; #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT /* Inform OS to call this function again without delay. */ @@ -1380,13 +1425,12 @@ int8_t CO_SDO_process( } #endif - /* don't call CO_FLAG_CLEAR, so return directly */ - return 1; + break; } case CO_SDO_ST_UPLOAD_BL_END:{ /* verify client command specifier */ - if((SDO->CANrxData[0]&0xE1U) != 0xA1U){ + if((CANrxData[0]&0xE1U) != 0xA1U){ CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ return -1; } @@ -1412,8 +1456,12 @@ int8_t CO_SDO_process( } } - /* free buffer and send message */ - CO_FLAG_CLEAR(SDO->CANrxNew); + /* free receive buffer if it is not empty */ + if (isNew) { + CO_SDO_process_done(SDO, timerNext_us); + } + + /* send message */ if(sendResponse) { CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); } diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 105b719d..2b479db6 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -491,6 +491,20 @@ typedef enum{ */ +/** + * Size of fifo queue for SDO received messages. + * + * If block transfers are used size of fifo queue should be more that 1 message + * to avoid possible drops in consecutive SDO block upload transfers. + * To increase performance, value can be set to 1 if block transfers are not used + * + * Min value is 1. + */ + #ifndef CO_SDO_RX_DATA_SIZE + #define CO_SDO_RX_DATA_SIZE 2 + #endif + + /** * Object Dictionary attributes. Bit masks for attribute in CO_OD_entry_t. */ @@ -719,8 +733,8 @@ typedef struct{ * SDO server object. */ typedef struct{ - /** 8 data bytes of the received message. */ - uint8_t CANrxData[8]; + /** FIFO queue of the received message 8 data bytes each */ + uint8_t CANrxData[CO_SDO_RX_DATA_SIZE][8]; /** SDO data buffer of size #CO_CONFIG_SDO_BUFFER_SIZE. */ uint8_t databuffer[CO_CONFIG_SDO_BUFFER_SIZE]; /** Internal flag indicates, that this object has own OD */ @@ -761,8 +775,14 @@ typedef struct{ bool_t timeoutSubblockDownolad; /** Indication end of block transfer */ bool_t endOfTransfer; - /** Variable indicates, if new SDO message received from CAN bus */ - volatile void *CANrxNew; + /** Variables indicates, if new SDO message received from CAN bus */ + volatile void *CANrxNew[CO_SDO_RX_DATA_SIZE]; + /** Index of CANrxData for new received SDO message */ + uint8_t CANrxRcv; + /** Index of CANrxData SDO message to processed */ + uint8_t CANrxProc; + /** Number of new SDO messages in CANrxData to process */ + uint8_t CANrxSize; #if ((CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_SDO_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void *object); diff --git a/README.md b/README.md index 4508e277..9357b053 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,8 @@ File structure - **CO_TIME.h/.c** - CANopen Time-stamp protocol. - **CO_fifo.h/.c** - Fifo buffer for SDO and gateway data transfer. - **crc16-ccitt.h/.c** - Calculation of CRC 16 CCITT polynomial. + - **303/** - CANopen Recommendation + - **CO_LEDs.h/.c** - CANopen LED Indicators - **305/** - CANopen layer setting services (LSS) and protocols. - **CO_LSS.h** - CANopen Layer Setting Services protocol (common). - **CO_LSSmaster.h/.c** - CANopen Layer Setting Service - master protocol. @@ -183,6 +185,7 @@ File structure - **.clang-format** - Definition file for the coding style. - **Doxyfile** - Configuration file for the documentation generator *doxygen*. - **Makefile** - Makefile for Linux socketCAN. + - **canopend** - Executable for Linux, build with `make`. - **LICENSE** - License. - **README.md** - This file. From ca452c47ccca873fb533e49da49fd698bd70c0df Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 13 Jun 2020 14:06:35 +0200 Subject: [PATCH 087/520] CO_driver interface: remove Emergency object dependency for reporting CAN errors, use CANerrorStatus own variable instead. Emergency object updated. --- 301/CO_Emergency.c | 67 +++++++++++++++++++++++++++-- 301/CO_Emergency.h | 1 + 301/CO_driver.h | 36 +++++++++++++--- 303/CO_LEDs.c | 23 +++++----- 303/CO_LEDs.h | 16 ++++--- CANopen.c | 27 ++++++------ doc/CHANGELOG.md | 1 + example/CO_driver_blank.c | 81 +++++++++++++++++------------------- example/CO_driver_target.h | 2 +- socketCAN/CO_driver.c | 39 ++++++++--------- socketCAN/CO_driver_target.h | 14 +------ socketCAN/CO_error.c | 22 +++++++++- socketCAN/CO_error.h | 1 + 13 files changed, 211 insertions(+), 119 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index ec05583b..260b9408 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -184,6 +184,7 @@ CO_ReturnError_t CO_EM_init( emPr->preDefErrSize = preDefErrSize; emPr->preDefErrNoOfErrors = 0U; emPr->inhibitEmTimer = 0U; + emPr->CANerrorStatusOld = 0U; /* clear error status bits */ for(i=0U; iCANdev = CANdevTx; - emPr->CANdev->em = (void*)em; /* update pointer inside CAN device. */ emPr->CANtxBuff = CO_CANtxBufferInit( CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ @@ -271,9 +271,70 @@ void CO_EM_process( uint8_t errorMask; uint8_t i; uint32_t emInhTime_us = (uint32_t)emInhTime_100us * 100; + uint16_t CANerrSt = emPr->CANdev->CANerrorStatus; + + /* verify errors from driver */ + if (CANerrSt != emPr->CANerrorStatusOld) { + uint16_t CANerrStChanged = CANerrSt ^ emPr->CANerrorStatusOld; + emPr->CANerrorStatusOld = CANerrSt; + + if (CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) { + if (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) + CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, 0); + else + CO_errorReset(em, CO_EM_CAN_BUS_WARNING, 0); + } + + if (CANerrStChanged & CO_CAN_ERRTX_PASSIVE) { + if (CANerrSt & CO_CAN_ERRTX_PASSIVE) + CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, + CO_EMC_CAN_PASSIVE, 0); + else + CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, 0); + } + + if (CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) { + if (CANerrSt & CO_CAN_ERRTX_BUS_OFF) + CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, + CO_EMC_BUS_OFF_RECOVERED, 0); + else + CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, 0); + } + + if (CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) { + if (CANerrSt & CO_CAN_ERRTX_OVERFLOW) + CO_errorReport(em, CO_EM_CAN_TX_OVERFLOW, + CO_EMC_CAN_OVERRUN, 0); + else + CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, 0); + } + + if (CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) { + if (CANerrSt & CO_CAN_ERRTX_PDO_LATE) + CO_errorReport(em, CO_EM_TPDO_OUTSIDE_WINDOW, + CO_EMC_COMMUNICATION, 0); + else + CO_errorReset(em, CO_EM_TPDO_OUTSIDE_WINDOW, 0); + } + + if (CANerrStChanged & CO_CAN_ERRRX_PASSIVE) { + if (CANerrSt & CO_CAN_ERRRX_PASSIVE) + CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, + CO_EMC_CAN_PASSIVE, 0); + else + CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, 0); + } + + if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) { + if (CANerrSt & CO_CAN_ERRRX_OVERFLOW) + CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, + CO_EMC_CAN_OVERRUN, 0); + else + CO_errorReset(em, CO_EM_CAN_RXB_OVERFLOW, 0); + } + } - /* verify errors from driver and other */ - CO_CANverifyErrors(emPr->CANdev); + /* verify other errors */ if(em->wrongErrorReport != 0U){ CO_errorReport(em, CO_EM_WRONG_ERROR_REPORT, CO_EMC_SOFTWARE_INTERNAL, (uint32_t)em->wrongErrorReport); em->wrongErrorReport = 0U; diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index ab8a02a6..3e5ff3bc 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -346,6 +346,7 @@ typedef struct{ uint8_t preDefErrNoOfErrors;/**< Number of active errors in preDefErr */ uint32_t inhibitEmTimer; /**< Internal timer for emergency message */ CO_EM_t *em; /**< CO_EM_t sub object is included here */ + uint16_t CANerrorStatusOld;/**< Old CAN error status bitfield */ CO_CANmodule_t *CANdev; /**< From CO_EM_init() */ CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer */ }CO_EMpr_t; diff --git a/301/CO_driver.h b/301/CO_driver.h index 21ce302e..667fd8d2 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -359,6 +359,8 @@ typedef struct { uint16_t rxSize; /**< From CO_CANmodule_init() */ CO_CANtx_t *txArray; /**< From CO_CANmodule_init() */ uint16_t txSize; /**< From CO_CANmodule_init() */ + uint16_t CANerrorStatus; /**< CAN error status bitfield, + see @ref CO_CAN_ERR_status_t */ volatile bool_t CANnormal; /**< CAN module is in normal mode */ volatile bool_t useCANrxFilters; /**< Value different than zero indicates, that CAN module hardware filters are used for CAN reception. If @@ -373,7 +375,6 @@ typedef struct { volatile uint16_t CANtxCount; /**< Number of messages in transmit buffer, which are waiting to be copied to the CAN module */ uint32_t errOld; /**< Previous state of CAN errors */ - void *em; /**< Emergency object */ } CO_CANmodule_t; @@ -472,6 +473,30 @@ typedef enum { } CO_Default_CAN_ID_t; +/** + * CAN error status bitmasks. + * + * CAN warning level is reached, if CAN transmit or receive error counter is + * more or equal to 96. CAN passive level is reached, if counters are more or + * equal to 128. Transmitter goes in error state 'bus off' if transmit error + * counter is more or equal to 256. + */ +typedef enum { + CO_CAN_ERRTX_WARNING = 0x0001, /**< 0x0001, CAN transmitter warning */ + CO_CAN_ERRTX_PASSIVE = 0x0002, /**< 0x0002, CAN transmitter passive */ + CO_CAN_ERRTX_BUS_OFF = 0x0004, /**< 0x0004, CAN transmitter bus off */ + CO_CAN_ERRTX_OVERFLOW = 0x0008, /**< 0x0008, CAN transmitter overflow */ + + CO_CAN_ERRTX_PDO_LATE = 0x0080, /**< 0x0080, TPDO is outside sync window */ + + CO_CAN_ERRRX_WARNING = 0x0100, /**< 0x0100, CAN receiver warning */ + CO_CAN_ERRRX_PASSIVE = 0x0200, /**< 0x0200, CAN receiver passive */ + CO_CAN_ERRRX_OVERFLOW = 0x0800, /**< 0x0800, CAN receiver overflow */ + + CO_CAN_ERR_WARN_PASSIVE = 0x0303/**< 0x0303, combination */ +} CO_CAN_ERR_status_t; + + /** * Return values of some CANopen functions. If function was executed * successfully it returns 0 otherwise it returns <0. @@ -640,7 +665,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); * CANopen allows synchronous PDO communication only inside time between SYNC * message and SYNC Window. If time is outside this window, new synchronous PDOs * must not be sent and all pending sync TPDOs, which may be on CAN TX buffers, - * must be cleared. + * may optionally be cleared. * * This function checks (and aborts transmission if necessary) CAN TX buffers * when it is called. Function should be called by the stack in the moment, @@ -652,13 +677,14 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); /** - * Verify all errors of CAN module. + * Process can module - verify CAN errors * - * Function is called directly from CO_EM_process() function. + * Function must be called cyclically. It should calculate CANerrorStatus + * bitfield for CAN errors defined in @ref CO_CAN_ERR_status_t. * * @param CANmodule This object. */ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule); +void CO_CANmodule_process(CO_CANmodule_t *CANmodule); /** @} */ /* @defgroup CO_driver Driver */ diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 077cdf00..76307947 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -45,15 +45,14 @@ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { /******************************************************************************/ void CO_LEDs_process(CO_LEDs_t *LEDs, uint32_t timeDifference_us, + CO_NMT_internalState_t NMTstate, + bool_t LSSconfig, bool_t ErrCANbusOff, - bool_t ErrNodeId, + bool_t ErrCANbusWarn, bool_t ErrRpdo, bool_t ErrSync, bool_t ErrHbCons, - bool_t ErrCANbusWarn, bool_t ErrOther, - CO_NMT_internalState_t NMTstate, - bool_t LSSconfig, bool_t firmwareDownload, uint32_t *timerNext_us) { @@ -117,14 +116,14 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, uint8_t rd_co, gr_co; /* CANopen red ERROR LED */ - if (ErrCANbusOff) rd_co = 1; - else if (ErrNodeId) rd_co = rd & CO_LED_flicker; - else if (ErrRpdo) rd_co = rd & CO_LED_flash_4; - else if (ErrSync) rd_co = rd & CO_LED_flash_3; - else if (ErrHbCons) rd_co = rd & CO_LED_flash_2; - else if (ErrCANbusWarn) rd_co = rd & CO_LED_flash_1; - else if (ErrOther) rd_co = rd & CO_LED_blink; - else rd_co = 0; + if (ErrCANbusOff) rd_co = 1; + else if (NMTstate == CO_NMT_INITIALIZING) rd_co = rd & CO_LED_flicker; + else if (ErrRpdo) rd_co = rd & CO_LED_flash_4; + else if (ErrSync) rd_co = rd & CO_LED_flash_3; + else if (ErrHbCons) rd_co = rd & CO_LED_flash_2; + else if (ErrCANbusWarn) rd_co = rd & CO_LED_flash_1; + else if (ErrOther) rd_co = rd & CO_LED_blink; + else rd_co = 0; /* CANopen green RUN LED */ if (LSSconfig) gr_co = gr & CO_LED_flicker; diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index b3a6affe..e1a6dae3 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -116,29 +116,27 @@ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs); * @param LEDs This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. + * @param NMTstate NMT operating state. + * @param LSSconfig Node is in LSS configuration state indication. * @param ErrCANbusOff CAN bus off indication (highest priority). - * @param ErrNodeId LSS unconfigured Node Id indication. - * @param ErrRpdo RPDO evnet timer timeout indication. + * @param ErrCANbusWarn CAN error warning limit reached indication. + * @param ErrRpdo RPDO event timer timeout indication. * @param ErrSync Sync receive timeout indication. * @param ErrHbCons Heartbeat consumer error (remote node) indication. - * @param ErrCANbusWarn CAN error warning limit reached indication. * @param ErrOther Other error indication (lowest priority). - * @param NMTstate NMT operating state. - * @param LSSconfig Node is in LSS configuration state indication. * @param firmwareDownload Firmware download is in progress indication. * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_LEDs_process(CO_LEDs_t *LEDs, uint32_t timeDifference_us, + CO_NMT_internalState_t NMTstate, + bool_t LSSconfig, bool_t ErrCANbusOff, - bool_t ErrNodeId, + bool_t ErrCANbusWarn, bool_t ErrRpdo, bool_t ErrSync, bool_t ErrHbCons, - bool_t ErrCANbusWarn, bool_t ErrOther, - CO_NMT_internalState_t NMTstate, - bool_t LSSconfig, bool_t firmwareDownload, uint32_t *timerNext_us); diff --git a/CANopen.c b/CANopen.c index a52be726..9b1f67c9 100644 --- a/CANopen.c +++ b/CANopen.c @@ -856,30 +856,31 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, bool_t NMTisPreOrOperational = false; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; + CO_CANmodule_process(CO->CANmodule[0]); + #if CO_NO_LSS_SLAVE == 1 bool_t resetLSS = CO_LSSslave_process(co->LSSslave); #endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + bool_t unc = co->nodeIdUnconfigured; + uint16_t CANerrorStatus = CO->CANmodule[0]->CANerrorStatus; CO_LEDs_process(co->LEDs, timeDifference_us, - CO_isError(co->em, CO_EM_CAN_TX_BUS_OFF), - co->nodeIdUnconfigured, - 0, /* RPDO event timer timeout */ - CO_isError(co->em, CO_EM_SYNC_TIME_OUT), - CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) - || CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET), - CO_isError(co->em, CO_EM_CAN_BUS_WARNING) - || CO_isError(co->em, CO_EM_CAN_TX_BUS_PASSIVE) - || CO_isError(co->em, CO_EM_CAN_RX_BUS_PASSIVE), - OD_errorRegister != 0, - co->NMT->operatingState, + unc ? CO_NMT_INITIALIZING : co->NMT->operatingState, #if CO_NO_LSS_SLAVE == 1 CO_LSSslave_getState(co->LSSslave) - == CO_LSS_STATE_CONFIGURATION, + == CO_LSS_STATE_CONFIGURATION, #else - 0, + false, #endif + (CANerrorStatus & CO_CAN_ERRTX_BUS_OFF) != 0, + (CANerrorStatus & CO_CAN_ERR_WARN_PASSIVE) != 0, + 0, /* RPDO event timer timeout */ + unc ? false : CO_isError(co->em, CO_EM_SYNC_TIME_OUT), + unc ? false : (CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) + || CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET)), + OD_errorRegister != 0, CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS, timerNext_us); #endif /* (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE */ diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index b860ad99..a7c81f7d 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -23,6 +23,7 @@ Change Log - SDO client is rewritten. Now includes read/write fifo interface to transfer data. - LED indicator indication (CiA303-3) moved from NMT into own files. Now fully comply to standard. - LSS slave is integrated into CANopenNode more directly. +- CO_driver interface: remove Emergency object dependency for reporting CAN errors, use CANerrorStatus own variable instead. Emergency object updated. ### Changed SocketCAN - ./stack/socketCAN removed from the project, ./stack/Neuberger-socketCAN moved to ./socketCAN - driver API updated diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index 47737652..66380be6 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -27,7 +27,6 @@ #include "301/CO_driver.h" -#include "301/CO_Emergency.h" /******************************************************************************/ @@ -67,13 +66,13 @@ CO_ReturnError_t CO_CANmodule_init( CANmodule->rxSize = rxSize; CANmodule->txArray = txArray; CANmodule->txSize = txSize; + CANmodule->CANerrorStatus = 0; CANmodule->CANnormal = false; CANmodule->useCANrxFilters = (rxSize <= 32U) ? true : false;/* microcontroller dependent */ CANmodule->bufferInhibitFlag = false; CANmodule->firstCANtxMessage = true; CANmodule->CANtxCount = 0U; CANmodule->errOld = 0U; - CANmodule->em = NULL; for(i=0U; ibufferFull){ if(!CANmodule->firstCANtxMessage){ /* don't set error, if bootup message is still on buffers */ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, buffer->ident); + CANmodule->CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; } err = CO_ERROR_TX_OVERFLOW; } @@ -249,66 +248,62 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ if(tpdoDeleted != 0U){ - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted); + CANmodule->CANerrorStatus |= CO_CAN_ERRTX_PDO_LATE; } } /******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){ - uint16_t rxErrors, txErrors, overflow; - CO_EM_t* em = (CO_EM_t*)CANmodule->em; - uint32_t err; +/* Get error counters from the module. If necessary, function may use + * different way to determine errors. */ +static uint16_t rxErrors=0, txErrors=0, overflow=0; - /* get error counters from module. Id possible, function may use different way to - * determine errors. */ - rxErrors = CANmodule->txSize; - txErrors = CANmodule->txSize; - overflow = CANmodule->txSize; +void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { + uint32_t err; err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; - if(CANmodule->errOld != err){ + if (CANmodule->errOld != err) { + uint16_t status = CANmodule->CANerrorStatus; + CANmodule->errOld = err; - if(txErrors >= 256U){ /* bus off */ - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err); + if (txErrors >= 256U) { + /* bus off */ + status |= CO_CAN_ERRTX_BUS_OFF; } - else{ /* not bus off */ - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err); - - if((rxErrors >= 96U) || (txErrors >= 96U)){ /* bus warning */ - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err); + else { + /* recalculate CANerrorStatus, first clear some flags */ + status &= 0xFFFF ^ (CO_CAN_ERRTX_BUS_OFF | + CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE | + CO_CAN_ERRTX_WARNING | CO_CAN_ERRTX_PASSIVE); + + /* rx bus warning or passive */ + if (rxErrors >= 128) { + status |= CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE; + } else if (rxErrors >= 96) { + status |= CO_CAN_ERRRX_WARNING; } - if(rxErrors >= 128U){ /* RX bus passive */ - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - else{ - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err); + /* tx bus warning or passive */ + if (txErrors >= 128) { + status |= CO_CAN_ERRTX_WARNING | CO_CAN_ERRTX_PASSIVE; + } else if (rxErrors >= 96) { + status |= CO_CAN_ERRTX_WARNING; } - if(txErrors >= 128U){ /* TX bus passive */ - if(!CANmodule->firstCANtxMessage){ - CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err); - } - } - else{ - bool_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE); - if(isError){ - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err); - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err); - } - } - - if((rxErrors < 96U) && (txErrors < 96U)){ /* no error */ - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err); + /* if not tx passive clear also overflow */ + if ((status & CO_CAN_ERRTX_PASSIVE) == 0) { + status &= 0xFFFF ^ CO_CAN_ERRTX_OVERFLOW; } } - if(overflow != 0U){ /* CAN RX bus overflow */ - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err); + if (overflow != 0) { + /* CAN RX bus overflow */ + status |= CO_CAN_ERRRX_OVERFLOW; } + + CANmodule->CANerrorStatus = status; } } diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index e6366a77..45c85673 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -177,13 +177,13 @@ typedef struct { uint16_t rxSize; CO_CANtx_t *txArray; uint16_t txSize; + uint16_t CANerrorStatus; volatile bool_t CANnormal; volatile bool_t useCANrxFilters; volatile bool_t bufferInhibitFlag; volatile bool_t firstCANtxMessage; volatile uint16_t CANtxCount; uint32_t errOld; - void *em; } CO_CANmodule_t; diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 166d63ad..409348e2 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -41,10 +41,6 @@ #include "301/CO_driver.h" #include "CO_error.h" -#if CO_DRIVER_USE_EMERGENCY > 0 -#include "301/CO_Emergency.h" -#endif - pthread_mutex_t CO_EMCY_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -249,8 +245,8 @@ CO_ReturnError_t CO_CANmodule_init( CANmodule->rxSize = rxSize; CANmodule->txArray = txArray; CANmodule->txSize = txSize; + CANmodule->CANerrorStatus = 0; CANmodule->CANnormal = false; - CANmodule->em = NULL; //this is set inside CO_Emergency.c init function! CANmodule->fdTimerRead = -1; #if CO_DRIVER_MULTI_INTERFACE > 0 for (i = 0; i < CO_CAN_MSG_SFF_MAX_COB_ID; i++) { @@ -663,6 +659,9 @@ static CO_ReturnError_t CO_CANCheckSendInterface( else if (errno == ENOBUFS) { /* socketCAN doesn't support blocking write. You can wait here for * a few hundred us and then try again */ +#if CO_DRIVER_ERROR_REPORTING > 0 + interface->errorhandler.CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; +#endif return CO_ERROR_TX_BUSY; } else if (n != CAN_MTU) { @@ -671,8 +670,8 @@ static CO_ReturnError_t CO_CANCheckSendInterface( } while (errno != 0); if(n != CAN_MTU){ -#if CO_DRIVER_USE_EMERGENCY > 0 - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); +#if CO_DRIVER_ERROR_REPORTING > 0 + interface->errorhandler.CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; #endif log_printf(LOG_ERR, DBG_CAN_TX_FAILED, buffer->ident, interface->ifName); log_printf(LOG_DEBUG, DBG_ERRNO, "send()"); @@ -710,9 +709,6 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) err = CO_CANCheckSend(CANmodule, buffer); if (err == CO_ERROR_TX_BUSY) { /* send doesn't have "busy" */ -#if CO_DRIVER_USE_EMERGENCY > 0 - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); -#endif log_printf(LOG_ERR, DBG_CAN_TX_FAILED, buffer->ident, "CANx"); log_printf(LOG_DEBUG, DBG_ERRNO, "send()"); err = CO_ERROR_TX_OVERFLOW; @@ -758,13 +754,20 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) /******************************************************************************/ -void CO_CANverifyErrors(CO_CANmodule_t *CANmodule) +void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { - (void)CANmodule; /* socketCAN doesn't support microcontroller-like error counters. If an * error has occured, a special can message is created by the driver and * received by the application like a regular message. - * Therefore, error counter evaluation is included in rx function.*/ + * Therefore, error counter evaluation is included in rx function. + * Here we just copy evaluated CANerrorStatus from the first CAN interface. */ + +#if CO_DRIVER_ERROR_REPORTING > 0 + if (CANmodule->CANinterfaceCount > 0) { + CANmodule->CANerrorStatus = + CANmodule->CANinterfaces[0].errorhandler.CANerrorStatus; + } +#endif } @@ -797,9 +800,8 @@ static CO_ReturnError_t CO_CANread( n = recvmsg(interface->fd, &msghdr, 0); if (n != CAN_MTU) { -#if CO_DRIVER_USE_EMERGENCY > 0 - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_RXB_OVERFLOW, - CO_EMC_CAN_OVERRUN, n); +#if CO_DRIVER_ERROR_REPORTING > 0 + interface->errorhandler.CANerrorStatus |= CO_CAN_ERRRX_OVERFLOW; #endif log_printf(LOG_DEBUG, DBG_CAN_RX_FAILED, interface->ifName); log_printf(LOG_DEBUG, DBG_ERRNO, "recvmsg()"); @@ -817,9 +819,8 @@ static CO_ReturnError_t CO_CANread( else if (cmsg->cmsg_type == SO_RXQ_OVFL) { dropped = *(uint32_t*)CMSG_DATA(cmsg); if (dropped > CANmodule->rxDropCount) { -#if CO_DRIVER_USE_EMERGENCY > 0 - CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_RXB_OVERFLOW, - CO_EMC_COMMUNICATION, 0); +#if CO_DRIVER_ERROR_REPORTING > 0 + interface->errorhandler.CANerrorStatus |= CO_CAN_ERRRX_OVERFLOW; #endif log_printf(LOG_ERR, CAN_RX_SOCKET_QUEUE_OVERFLOW, interface->ifName, dropped); diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 38a41387..79eb6a82 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -191,18 +191,6 @@ extern "C" { #define CO_DRIVER_ERROR_REPORTING 1 #endif -/** - * Use CANopen Emergency object on CAN RX or TX overflow. - * - * If CO_DRIVER_USE_EMERGENCY is set to 1, then CANopen Emergency message will - * be sent, if CAN rx or tx bufers are overflowed. - * - * Macro is set to 1 (enabled) by default. It can be overridden. - */ -#ifndef CO_DRIVER_USE_EMERGENCY -#define CO_DRIVER_USE_EMERGENCY 1 -#endif - /* skip this section for Doxygen, because it is documented in CO_driver.h */ #ifndef CO_DOXYGEN @@ -304,8 +292,8 @@ typedef struct { uint32_t rxDropCount; /* messages dropped on rx socket queue */ CO_CANtx_t *txArray; uint16_t txSize; + uint16_t CANerrorStatus; volatile bool_t CANnormal; - void *em; int fdEvent; /* notification event file descriptor */ int fdEpoll; /* epoll FD for event, CANrx sockets in all interfaces and fdTimerRead */ diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index ee5eedda..1e6e11c8 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -32,6 +32,7 @@ #include #include "CO_error.h" +#include "301/CO_driver.h" /** @@ -98,6 +99,7 @@ static CO_CANinterfaceState_t CO_CANerrorBusoff( * Restarting the interface is the only way to clear kernel and hardware * tx queues */ result = CO_CANerrorSetListenOnly(CANerrorhandler, true); + CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_BUS_OFF; } return result; } @@ -117,25 +119,42 @@ static CO_CANinterfaceState_t CO_CANerrorCrtl( * to do in here * - we can't really do anything about buffer overflows here. Confirmed * CANopen protocols will detect the error, non-confirmed protocols - * need to be error tolerant */ + * need to be error tolerant. + * - There is no information, when CAN controller leaves warning level, + * so we can't clear it. So we also don't set it. */ if ((msg->can_id & CAN_ERR_CRTL) != 0) { + /* clear bus off here */ + CANerrorhandler->CANerrorStatus &= 0xFFFF ^ CO_CAN_ERRTX_BUS_OFF; + if ((msg->data[1] & CAN_ERR_CRTL_RX_PASSIVE) != 0) { log_printf(LOG_NOTICE, CAN_RX_PASSIVE, CANerrorhandler->ifName); + CANerrorhandler->CANerrorStatus |= CO_CAN_ERRRX_PASSIVE; + /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRRX_WARNING; */ } else if ((msg->data[1] & CAN_ERR_CRTL_TX_PASSIVE) != 0) { log_printf(LOG_NOTICE, CAN_TX_PASSIVE, CANerrorhandler->ifName); + CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_PASSIVE; + /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_WARNING; */ } else if ((msg->data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) { log_printf(LOG_NOTICE, CAN_RX_BUF_OVERFLOW, CANerrorhandler->ifName); + CANerrorhandler->CANerrorStatus |= CO_CAN_ERRRX_OVERFLOW; } else if ((msg->data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) { log_printf(LOG_NOTICE, CAN_TX_BUF_OVERFLOW, CANerrorhandler->ifName); + CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; } else if ((msg->data[1] & CAN_ERR_CRTL_RX_WARNING) != 0) { log_printf(LOG_INFO, CAN_RX_LEVEL_WARNING, CANerrorhandler->ifName); + /* clear passive flag, set warning */ + CANerrorhandler->CANerrorStatus &= 0x7FFF ^ CO_CAN_ERRRX_PASSIVE; + /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRRX_WARNING; */ } else if ((msg->data[1] & CAN_ERR_CRTL_TX_WARNING) != 0) { log_printf(LOG_INFO, CAN_TX_LEVEL_WARNING, CANerrorhandler->ifName); + /* clear passive flag, set warning */ + CANerrorhandler->CANerrorStatus &= 0x7FFF ^ CO_CAN_ERRTX_PASSIVE; + /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_WARNING; */ } else if ((msg->data[1] & CAN_ERR_CRTL_ACTIVE) != 0) { log_printf(LOG_NOTICE, CAN_TX_LEVEL_ACTIVE, CANerrorhandler->ifName); @@ -195,6 +214,7 @@ void CO_CANerror_init( CANerrorhandler->listenOnly = false; CANerrorhandler->timestamp.tv_sec = 0; CANerrorhandler->timestamp.tv_nsec = 0; + CANerrorhandler->CANerrorStatus = 0; } diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h index 12517982..5c99772d 100644 --- a/socketCAN/CO_error.h +++ b/socketCAN/CO_error.h @@ -116,6 +116,7 @@ typedef struct { uint32_t noackCounter; /**< counts no ACK on CAN transmission */ volatile unsigned char listenOnly; /**< set to listen only mode */ struct timespec timestamp; /**< listen only mode started at this time */ + uint16_t CANerrorStatus; /**< CAN error status bitfield, see @ref CO_CAN_ERR_status_t */ } CO_CANinterfaceErrorhandler_t; From aed6a472d4c63e4b14df55ab89ff514a77f9a72f Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 13 Jun 2020 16:52:04 +0200 Subject: [PATCH 088/520] LSS led flickering fix. --- 301/CO_SDOclient.c | 2 ++ 303/CO_LEDs.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 6f0fad16..135c7476 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -1275,7 +1275,9 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* Transmit CAN data ******************************************************/ if (ret == CO_SDOcli_waitingServerResponse) { +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK size_t count; +#endif memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); switch (SDO_C->state) { diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 76307947..94944e0c 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -101,9 +101,9 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, } } else { - /* clear flicker bit, keep others */ - rd = LEDs->LEDred & (0xFF ^ CO_LED_flicker); - gr = LEDs->LEDgreen & (0xFF ^ CO_LED_flicker); + /* clear flicker and CANopen bits, keep others */ + rd = LEDs->LEDred & (0xFF ^ (CO_LED_flicker | CO_LED_CANopen)); + gr = LEDs->LEDgreen & (0xFF ^ (CO_LED_flicker | CO_LED_CANopen)); } /* calculate 10Hz flickering */ From 0f7b3e2d1714f939827849cb18fb005aeb89e584 Mon Sep 17 00:00:00 2001 From: gotocoffee Date: Mon, 22 Jun 2020 10:14:14 +0200 Subject: [PATCH 089/520] CANopen Safety (SRDO according to DIN EN 50325-5:2016) (#196) * CANopen Safety (SRDO according to DIN EN 50325-5:2016) * GFC code and docs * clang-format on GFC Co-authored-by: rg1 --- 301/CO_SDOserver.h | 5 + 301/CO_config.h | 43 +++ 301/CO_driver.h | 2 + 304/CO_GFC.c | 122 ++++++ 304/CO_GFC.h | 128 +++++++ 304/CO_SRDO.c | 752 +++++++++++++++++++++++++++++++++++++ 304/CO_SRDO.h | 293 +++++++++++++++ CANopen.c | 142 ++++++- CANopen.h | 45 +++ Makefile | 2 + example/CO_OD.h | 16 +- example/CO_driver_target.h | 17 + example/Makefile | 2 + 13 files changed, 1565 insertions(+), 4 deletions(-) create mode 100644 304/CO_GFC.c create mode 100644 304/CO_GFC.h create mode 100644 304/CO_SRDO.c create mode 100644 304/CO_SRDO.h diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 2b479db6..f5faa59e 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -565,6 +565,11 @@ typedef enum{ OD_H1029_ERR_BEHAVIOR = 0x1029U,/**< Error behaviour */ OD_H1200_SDO_SERVER_PARAM = 0x1200U,/**< SDO server parameters */ OD_H1280_SDO_CLIENT_PARAM = 0x1280U,/**< SDO client parameters */ + OD_H1300_GFC_PARAM = 0x1300U,/**< GFC parameter */ + OD_H1301_SRDO_1_PARAM = 0x1301U,/**< SRDO communication parameters */ + OD_H1381_SRDO_1_MAPPING = 0x1381U,/**< SRDO mapping parameters */ + OD_H13FE_SRDO_VALID = 0x13FEU,/**< SRDO valid flag */ + OD_H13FF_SRDO_CHECKSUM = 0x13FFU,/**< SRDO checksum */ OD_H1400_RXPDO_1_PARAM = 0x1400U,/**< RXPDO communication parameter */ OD_H1401_RXPDO_2_PARAM = 0x1401U,/**< RXPDO communication parameter */ OD_H1402_RXPDO_3_PARAM = 0x1402U,/**< RXPDO communication parameter */ diff --git a/301/CO_config.h b/301/CO_config.h index d4bb7a32..23970d3c 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -185,6 +185,49 @@ extern "C" { #define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x02 #define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x04 +/** + * Configuration of GFC + * + * Possible flags, can be ORed: + * - CO_CONFIG_GFC_CONSUMER - Enable the GFC consumer + * - CO_CONFIG_GFC_PRODUCER - Enable the GFC producer + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GFC (CO_CONFIG_GFC_CONSUMER | CO_CONFIG_GFC_PRODUCER) +#endif +#define CO_CONFIG_GFC_CONSUMER 0x01 +#define CO_CONFIG_GFC_PRODUCER 0x02 + +/** + * Configuration of SRDO + * + * Possible flags, can be ORed: + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received RSRDO CAN message. + * Callback is configured by CO_SRDO_initCallbackPre(). + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_SRDO_process() (Tx SRDO only). + * - CO_CONFIG_RSRDO_CALLS_EXTENSION - Enable calling configured extension + * callbacks when received RSRDO CAN message modifies OD entries. + * - CO_CONFIG_TRSRDO_CALLS_EXTENSION - Enable calling configured extension + * callbacks before TSRDO CAN message is sent. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SRDO (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SRDO_CHECK_TX | CO_CONFIG_RSRDO_CALLS_EXTENSION | CO_CONFIG_TSRDO_CALLS_EXTENSION) +#endif +#define CO_CONFIG_SRDO_CHECK_TX 0x01 +#define CO_CONFIG_RSRDO_CALLS_EXTENSION 0x02 +#define CO_CONFIG_TSRDO_CALLS_EXTENSION 0x04 + +/** + * SRDO Tx time delay + * + * minimum time between the first and second SRDO (Tx) message + * in us + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 +#endif /** * Configuration of PDO diff --git a/301/CO_driver.h b/301/CO_driver.h index 667fd8d2..8b09b08e 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -454,9 +454,11 @@ typedef struct { */ typedef enum { CO_CAN_ID_NMT_SERVICE = 0x000, /**< 0x000, Network management */ + CO_CAN_ID_GFC = 0x001, /**< 0x001, Global fail-safe command */ CO_CAN_ID_SYNC = 0x080, /**< 0x080, Synchronous message */ CO_CAN_ID_EMERGENCY = 0x080, /**< 0x080, Emergency messages (+nodeID) */ CO_CAN_ID_TIME = 0x100, /**< 0x100, Time message */ + CO_CAN_ID_SRDO_1 = 0x0FF, /**< 0x0FF, Default SRDO1 (+2*nodeID) */ CO_CAN_ID_TPDO_1 = 0x180, /**< 0x180, Default TPDO1 (+nodeID) */ CO_CAN_ID_RPDO_1 = 0x200, /**< 0x200, Default RPDO1 (+nodeID) */ CO_CAN_ID_TPDO_2 = 0x280, /**< 0x280, Default TPDO2 (+nodeID) */ diff --git a/304/CO_GFC.c b/304/CO_GFC.c new file mode 100644 index 00000000..0efc27c8 --- /dev/null +++ b/304/CO_GFC.c @@ -0,0 +1,122 @@ +/** + * CANopen Global fail-safe command protocol. + * + * @file CO_GFC.c + * @ingroup CO_GFC + * @author Robert Grüning + * @copyright 2020 - 2020 Robert Grüning + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "304/CO_GFC.h" + +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER + +static void CO_GFC_receive(void *object, void *msg) +{ + CO_GFC_t *GFC; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + + GFC = (CO_GFC_t *) + object; /* this is the correct pointer type of the first argument */ + + if ((*GFC->valid == 0x01) && (DLC == 0)) { + +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER + /* Optional signal to RTOS, which can resume task, which handles SRDO. + */ + if (GFC->pFunctSignalSafe != NULL) { + GFC->pFunctSignalSafe(GFC->functSignalObjectSafe); + } +#endif + } +} + +void CO_GFC_initCallbackEnterSafeState(CO_GFC_t *GFC, + void *object, + void (*pFunctSignalSafe)(void *object)) +{ + if (GFC != NULL) { + GFC->functSignalObjectSafe = object; + GFC->pFunctSignalSafe = pFunctSignalSafe; + } +} +#endif + +CO_ReturnError_t CO_GFC_init(CO_GFC_t *GFC, + uint8_t *valid, + CO_CANmodule_t *GFC_CANdevRx, + uint16_t GFC_rxIdx, + uint16_t CANidRxGFC, + CO_CANmodule_t *GFC_CANdevTx, + uint16_t GFC_txIdx, + uint16_t CANidTxGFC) +{ + CO_ReturnError_t r; + if (GFC == NULL || valid == NULL || GFC_CANdevRx == NULL || + GFC_CANdevTx == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + GFC->valid = valid; +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER + GFC->CANdevTx = GFC_CANdevTx; +#endif +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER + GFC->functSignalObjectSafe = NULL; + GFC->pFunctSignalSafe = NULL; +#endif + +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER + GFC->CANtxBuff = CO_CANtxBufferInit( + GFC->CANdevTx, /* CAN device */ + GFC_txIdx, /* index of specific buffer inside CAN module */ + CANidTxGFC, /* CAN identifier */ + 0, /* rtr */ + 0, /* number of data bytes */ + 0); /* synchronous message flag bit */ + + if (GFC->CANtxBuff == 0) { + return CO_ERROR_TX_UNCONFIGURED; + } +#endif +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER + r = CO_CANrxBufferInit( + GFC_CANdevRx, /* CAN device */ + GFC_rxIdx, /* rx buffer index */ + CANidRxGFC, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void *)GFC, /* object passed to receive function */ + CO_GFC_receive); /* this function will process received message */ + if (r != CO_ERROR_NO) { + return r; + } +#endif + + return CO_ERROR_NO; +} + +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER + +CO_ReturnError_t CO_GFCsend(CO_GFC_t *GFC) +{ + if (*GFC->valid == 0x01) + return CO_CANsend(GFC->CANdevTx, GFC->CANtxBuff); + return CO_ERROR_NO; +} +#endif diff --git a/304/CO_GFC.h b/304/CO_GFC.h new file mode 100644 index 00000000..e06cdb48 --- /dev/null +++ b/304/CO_GFC.h @@ -0,0 +1,128 @@ +/** + * CANopen Global fail-safe command protocol. + * + * @file CO_GFC.h + * @ingroup CO_GFC + * @author Robert Grüning + * @copyright 2020 - 2020 Robert Grüning + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "301/CO_driver.h" + +#ifndef CO_GFC_H +#define CO_GFC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_GFC GFC + * @ingroup CO_CANopen_304 + * @{ + * + * Global fail-safe command protocol. + * + * Very simple consumer/producer protocol. + * A net can have multiple GFC producer and multiple GFC consumer. + * On a safety-relevant the producer can send a GFC message (ID 0, DLC 0). + * The consumer can use this message to start the transition to a safe state. + * The GFC is optional for the security protocol and is not monitored (timed). + */ + + +/** + * GFC object. + */ +typedef struct { + uint8_t *valid; /**< From CO_GFC_init() */ +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_PRODUCER) || defined CO_DOXYGEN + CO_CANmodule_t *CANdevTx; /**< From CO_GFC_init() */ + CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ +#endif +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) || defined CO_DOXYGEN + /** From CO_GFC_initCallbackEnterSafeState() or NULL */ + void (*pFunctSignalSafe)(void *object); + /** From CO_GFC_initCallbackEnterSafeState() or NULL */ + void *functSignalObjectSafe; +#endif +} CO_GFC_t; + +/** + * Initialize GFC object. + * + * Function must be called in the communication reset section. + * + * @param GFC This object will be initialized. + * @param valid pointer to the valid flag in OD (0x1300) + * @param GFC_CANdevRx CAN device used for SRDO reception. + * @param GFC_rxIdx Index of receive buffer in the above CAN device. + * @param CANidRxGFC GFC CAN ID for reception + * @param GFC_CANdevTx AN device used for SRDO transmission. + * @param GFC_txIdx Index of transmit buffer in the above CAN device. + * @param CANidTxGFC GFC CAN ID for transmission + * + * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + */ +CO_ReturnError_t CO_GFC_init(CO_GFC_t *GFC, + uint8_t *valid, + CO_CANmodule_t *GFC_CANdevRx, + uint16_t GFC_rxIdx, + uint16_t CANidRxGFC, + CO_CANmodule_t *GFC_CANdevTx, + uint16_t GFC_txIdx, + uint16_t CANidTxGFC); + +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) || defined CO_DOXYGEN +/** + * Initialize GFC callback function. + * + * Function initializes optional callback function, that is called when GFC is + * received. Callback is called from receive function (interrupt). + * + * @param GFC This object. + * @param object Pointer to object, which will be passed to pFunctSignalSafe(). + * Can be NULL + * @param pFunctSignalSafe Pointer to the callback function. Not called if NULL. + */ +void CO_GFC_initCallbackEnterSafeState(CO_GFC_t *GFC, + void *object, + void (*pFunctSignalSafe)(void *object)); +#endif + +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_PRODUCER) || defined CO_DOXYGEN +/** + * Send GFC message. + * + * It should be called by application, for example after a safety-relevant + * change. + * + * @param GFC GFC object. + * + * @return Same as CO_CANsend(). + */ +CO_ReturnError_t CO_GFCsend(CO_GFC_t *GFC); +#endif + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +/** @} */ +#endif diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c new file mode 100644 index 00000000..b6b20be9 --- /dev/null +++ b/304/CO_SRDO.c @@ -0,0 +1,752 @@ +/** + * CANopen Safety Related Data Object protocol. + * + * @file CO_SRDO.c + * @ingroup CO_SRDO + * @author Robert Grüning + * @copyright 2020 - 2020 Robert Grüning + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "304/CO_SRDO.h" + +#include "301/crc16-ccitt.h" + +#define CO_SRDO_INVALID (0U) +#define CO_SRDO_TX (1U) +#define CO_SRDO_RX (2U) + +#define CO_SRDO_VALID_MAGIC (0xA5) + + +static void CO_SRDO_receive_normal(void *object, void *msg){ + CO_SRDO_t *SRDO; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); + + SRDO = (CO_SRDO_t*)object; /* this is the correct pointer type of the first argument */ + + if( (SRDO->valid == CO_SRDO_RX) && + (DLC >= SRDO->dataLength) && !CO_FLAG_READ(SRDO->CANrxNew[1])) + { + /* copy data into appropriate buffer and set 'new message' flag */ + memcpy(SRDO->CANrxData[0], data, sizeof(SRDO->CANrxData[0])); + CO_FLAG_SET(SRDO->CANrxNew[0]); + +#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles SRDO. */ + if(SRDO->pFunctSignalPre != NULL) { + SRDO->pFunctSignalPre(SRDO->functSignalObjectPre); + } +#endif + } +} + +static void CO_SRDO_receive_inverted(void *object, void *msg){ + CO_SRDO_t *SRDO; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); + + SRDO = (CO_SRDO_t*)object; /* this is the correct pointer type of the first argument */ + + if( (SRDO->valid == CO_SRDO_RX) && + (DLC >= SRDO->dataLength) && CO_FLAG_READ(SRDO->CANrxNew[0])) + { + /* copy data into appropriate buffer and set 'new message' flag */ + memcpy(SRDO->CANrxData[1], data, sizeof(SRDO->CANrxData[1])); + CO_FLAG_SET(SRDO->CANrxNew[1]); + +#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles SRDO. */ + if(SRDO->pFunctSignalPre != NULL) { + SRDO->pFunctSignalPre(SRDO->functSignalObjectPre); + } +#endif + } +} + +static void CO_SRDOconfigCom(CO_SRDO_t* SRDO, uint32_t COB_IDnormal, uint32_t COB_IDinverted){ + uint16_t IDs[2][2] = {0}; + uint16_t* ID; + uint16_t successCount = 0; + + int16_t i; + + uint32_t COB_ID[2]; + COB_ID[0] = COB_IDnormal; + COB_ID[1] = COB_IDinverted; + + SRDO->valid = CO_SRDO_INVALID; + + /* is SRDO used? */ + if(*SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC && (SRDO->SRDOCommPar->informationDirection == CO_SRDO_TX || SRDO->SRDOCommPar->informationDirection == CO_SRDO_RX) && + SRDO->dataLength){ + ID = &IDs[SRDO->SRDOCommPar->informationDirection - 1][0]; + /* is used default COB-ID? */ + for(i = 0; i < 2; i++){ + if(!(COB_ID[i] & 0xBFFFF800L)){ + ID[i] = (uint16_t)COB_ID[i] & 0x7FF; + + if(ID[i] == SRDO->defaultCOB_ID[i] && SRDO->nodeId <= 64){ + ID[i] += 2*SRDO->nodeId; + + } + if(0x101 <= ID[i] && ID[i] <= 0x180 && ((ID[i] ^ i) & 1)){ + successCount++; + } + } + } + } + /* all ids are ok*/ + if(successCount == 2){ + SRDO->valid = SRDO->SRDOCommPar->informationDirection; + + if (SRDO->valid == CO_SRDO_TX){ + SRDO->timer = 500 * SRDO->nodeId; /* 0.5ms * node-ID delay*/ + } + else if (SRDO->valid == CO_SRDO_RX){ + SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U; + } + } + else{ + memset(IDs, 0, sizeof(IDs)); + CO_FLAG_CLEAR(SRDO->CANrxNew[0]); + CO_FLAG_CLEAR(SRDO->CANrxNew[1]); + SRDO->valid = CO_SRDO_INVALID; + } + + + for(i = 0; i < 2; i++){ + CO_ReturnError_t r; + SRDO->CANtxBuff[i] = CO_CANtxBufferInit( + SRDO->CANdevTx, /* CAN device */ + SRDO->CANdevTxIdx[i], /* index of specific buffer inside CAN module */ + IDs[0][i], /* CAN identifier */ + 0, /* rtr */ + SRDO->dataLength, /* number of data bytes */ + 0); /* synchronous message flag bit */ + + if(SRDO->CANtxBuff[i] == 0){ + SRDO->valid = CO_SRDO_INVALID; + } + + r = CO_CANrxBufferInit( + SRDO->CANdevRx, /* CAN device */ + SRDO->CANdevRxIdx[i], /* rx buffer index */ + IDs[1][i], /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)SRDO, /* object passed to receive function */ + i ? CO_SRDO_receive_inverted : CO_SRDO_receive_normal); /* this function will process received message */ + if(r != CO_ERROR_NO){ + SRDO->valid = CO_SRDO_INVALID; + CO_FLAG_CLEAR(SRDO->CANrxNew[i]); + } + } +} + +static uint32_t CO_SRDOfindMap( + CO_SDO_t *SDO, + uint32_t map, + uint8_t R_T, + uint8_t **ppData, + uint8_t *pLength, + uint8_t *pSendIfCOSFlags, + uint8_t *pIsMultibyteVar) +{ + uint16_t entryNo; + uint16_t index; + uint8_t subIndex; + uint8_t dataLen; + uint8_t objectLen; + uint8_t attr; + + index = (uint16_t)(map>>16); + subIndex = (uint8_t)(map>>8); + dataLen = (uint8_t) map; /* data length in bits */ + + /* data length must be byte aligned */ + if(dataLen&0x07) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ + + dataLen >>= 3; /* new data length is in bytes */ + *pLength += dataLen; + + /* total PDO length can not be more than 8 bytes */ + if(*pLength > 8) return CO_SDO_AB_MAP_LEN; /* The number and length of the objects to be mapped would exceed PDO length. */ + + /* is there a reference to dummy entries */ + if(index <=7 && subIndex == 0){ + static uint32_t dummyTX = 0; + static uint32_t dummyRX; + uint8_t dummySize = 4; + + if(index<2) dummySize = 0; + else if(index==2 || index==5) dummySize = 1; + else if(index==3 || index==6) dummySize = 2; + + /* is size of variable big enough for map */ + if(dummySize < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ + + /* Data and ODE pointer */ + if(R_T == 0) *ppData = (uint8_t*) &dummyRX; + else *ppData = (uint8_t*) &dummyTX; + + return 0; + } + + /* find object in Object Dictionary */ + entryNo = CO_OD_find(SDO, index); + + /* Does object exist in OD? */ + if(entryNo == 0xFFFF || subIndex > SDO->OD[entryNo].maxSubIndex) + return CO_SDO_AB_NOT_EXIST; /* Object does not exist in the object dictionary. */ + + attr = CO_OD_getAttribute(SDO, entryNo, subIndex); + /* Is object Mappable for RPDO? */ + if(R_T==0 && !((attr&CO_ODA_RPDO_MAPABLE) && (attr&CO_ODA_WRITEABLE))) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ + /* Is object Mappable for TPDO? */ + if(R_T!=0 && !((attr&CO_ODA_TPDO_MAPABLE) && (attr&CO_ODA_READABLE))) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ + + /* is size of variable big enough for map */ + objectLen = CO_OD_getLength(SDO, entryNo, subIndex); + if(objectLen < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ + + /* mark multibyte variable */ + *pIsMultibyteVar = (attr&CO_ODA_MB_VALUE) ? 1 : 0; + + /* pointer to data */ + *ppData = (uint8_t*) CO_OD_getDataPointer(SDO, entryNo, subIndex); +#ifdef CO_BIG_ENDIAN + /* skip unused MSB bytes */ + if(*pIsMultibyteVar){ + *ppData += objectLen - dataLen; + } +#endif + + /* setup change of state flags */ + if(attr&CO_ODA_TPDO_DETECT_COS){ + int16_t i; + for(i=*pLength-dataLen; i<*pLength; i++){ + *pSendIfCOSFlags |= 1<SRDOMapPar->mappedObjects[0]; + + + for(i=noOfMappedObjects; i>0; i--){ + int16_t j; + uint8_t* pData; + uint8_t dummy = 0; + uint8_t* length = &lengths[i%2]; + uint8_t** mapPointer = SRDO->mapPointer[i%2]; + uint8_t prevLength = *length; + uint8_t MBvar; + uint32_t map = *(pMap++); + + /* function do much checking of errors in map */ + ret = CO_SRDOfindMap( + SRDO->SDO, + map, + SRDO->SRDOCommPar->informationDirection == CO_SRDO_TX, + &pData, + length, + &dummy, + &MBvar); + if(ret){ + *length = 0; + CO_errorReport(SRDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, map); + break; + } + + /* write SRDO data pointers */ +#ifdef CO_BIG_ENDIAN + if(MBvar){ + for(j=*length-1; j>=prevLength; j--) + mapPointer[j] = pData++; + } + else{ + for(j=prevLength; j<*length; j++) + mapPointer[j] = pData++; + } +#else + for(j=prevLength; j<*length; j++){ + mapPointer[j] = pData++; + } +#endif + + } + if(lengths[0] == lengths[1]) + SRDO->dataLength = lengths[0]; + else{ + SRDO->dataLength = 0; + CO_errorReport(SRDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, 0); + ret = CO_SDO_AB_MAP_LEN; + } + + return ret; +} + +static uint16_t CO_SRDOcalcCrc(const CO_SRDOCommPar_t *com, const CO_SRDOMapPar_t *map){ + uint16_t i; + uint16_t result = 0x0000; + uint8_t buffer[4]; + + result = crc16_ccitt(&com->informationDirection, 1, result); + CO_memcpySwap2(&buffer[0], &com->safetyCycleTime); + result = crc16_ccitt(&buffer[0], 2, result); + result = crc16_ccitt(&com->safetyRelatedValidationTime, 1, result); + CO_memcpySwap4(&buffer[0], &com->COB_ID1_normal); + result = crc16_ccitt(&buffer[0], 4, result); + CO_memcpySwap4(&buffer[0], &com->COB_ID2_inverted); + result = crc16_ccitt(&buffer[0], 4, result); + + result = crc16_ccitt(&map->numberOfMappedObjects, 1, result); + for(i = 0; i < map->numberOfMappedObjects;){ + uint8_t subindex = i + 1; + result = crc16_ccitt(&subindex, 1, result); + CO_memcpySwap4(&buffer[0], &map->mappedObjects[i]); + result = crc16_ccitt(&buffer[0], 4, result); + i = subindex; + } + return result; +} + +static CO_SDO_abortCode_t CO_ODF_SRDOcom(CO_ODF_arg_t *ODF_arg){ + CO_SRDO_t *SRDO; + + SRDO = (CO_SRDO_t*) ODF_arg->object; + + /* Reading Object Dictionary variable */ + if(ODF_arg->reading){ + if(ODF_arg->subIndex == 5 || ODF_arg->subIndex == 6){ + uint32_t value = CO_getUint32(ODF_arg->data); + uint16_t index = ODF_arg->subIndex - 5; + + /* if default COB ID is used, write default value here */ + if(((value)&0x7FF) == SRDO->defaultCOB_ID[index] && SRDO->defaultCOB_ID[index]) + value += SRDO->nodeId; + + /* If PDO is not valid, set bit 31 */ + if(!SRDO->valid) value |= 0x80000000L; + + CO_setUint32(ODF_arg->data, value); + } + return CO_SDO_AB_NONE; + } + + /* Writing Object Dictionary variable */ + if(*SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL) + return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + + if(ODF_arg->subIndex == 1){ + uint8_t value = ODF_arg->data[0]; + if (value > 2) + return CO_SDO_AB_INVALID_VALUE; + } + else if(ODF_arg->subIndex == 2){ + uint16_t value = CO_getUint16(ODF_arg->data); + if (value == 0) + return CO_SDO_AB_INVALID_VALUE; + } + else if(ODF_arg->subIndex == 3){ + uint8_t value = ODF_arg->data[0]; + if (value == 0) + return CO_SDO_AB_INVALID_VALUE; + } + else if(ODF_arg->subIndex == 4){ /* Transmission_type */ + uint8_t *value = (uint8_t*) ODF_arg->data; + if(*value != 254) + return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + } + else if(ODF_arg->subIndex == 5 || ODF_arg->subIndex == 6){ /* COB_ID */ + uint32_t value = CO_getUint32(ODF_arg->data); + uint16_t index = ODF_arg->subIndex - 5; + + /* bits 11...29 must be zero */ + if(value & 0x3FFFF800L) + return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + + /* if default COB-ID is being written, write defaultCOB_ID without nodeId */ + if(((value)&0x7FF) == (SRDO->defaultCOB_ID[index] + SRDO->nodeId)){ + value &= 0xC0000000L; + value += SRDO->defaultCOB_ID[index]; + CO_setUint32(ODF_arg->data, value); + } + } + + *SRDO->SRDOGuard->configurationValid = CO_SRDO_INVALID; + + return CO_SDO_AB_NONE; +} + +static CO_SDO_abortCode_t CO_ODF_SRDOmap(CO_ODF_arg_t *ODF_arg){ + CO_SRDO_t *SRDO; + + SRDO = (CO_SRDO_t*) ODF_arg->object; + + /* Reading Object Dictionary variable */ + if(ODF_arg->reading){ + uint8_t *value = (uint8_t*) ODF_arg->data; + + if(ODF_arg->subIndex == 0){ + /* If there is error in mapping, dataLength is 0, so numberOfMappedObjects is 0. */ + if(!SRDO->dataLength) *value = 0; + } + return CO_SDO_AB_NONE; + } + + /* Writing Object Dictionary variable */ + + if(*SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL) + return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + if(SRDO->SRDOCommPar->informationDirection) /* SRDO must be deleted */ + return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */ + + /* numberOfMappedObjects */ + if(ODF_arg->subIndex == 0){ + uint8_t *value = (uint8_t*) ODF_arg->data; + + if(*value > 16 || *value & 1) /*only odd numbers are allowed*/ + return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds PDO length. */ + } + else{ + if (SRDO->SRDOMapPar->numberOfMappedObjects != 0) + return CO_SDO_AB_UNSUPPORTED_ACCESS; + } + *SRDO->SRDOGuard->configurationValid = CO_SRDO_INVALID; + return CO_SDO_AB_NONE; +} + +static CO_SDO_abortCode_t CO_ODF_SRDOcrc(CO_ODF_arg_t *ODF_arg){ + CO_SRDOGuard_t *SRDOGuard; + + SRDOGuard = (CO_SRDOGuard_t*) ODF_arg->object; + + if (!ODF_arg->reading){ + if(*SRDOGuard->operatingState == CO_NMT_OPERATIONAL) + return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + *SRDOGuard->configurationValid = CO_SRDO_INVALID; + } + return CO_SDO_AB_NONE; +} + +static CO_SDO_abortCode_t CO_ODF_SRDOvalid(CO_ODF_arg_t *ODF_arg){ + CO_SRDOGuard_t *SRDOGuard; + + SRDOGuard = (CO_SRDOGuard_t*) ODF_arg->object; + + if(!ODF_arg->reading){ + if(*SRDOGuard->operatingState == CO_NMT_OPERATIONAL) + return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + SRDOGuard->checkCRC = ODF_arg->data[0] == CO_SRDO_VALID_MAGIC; + } + return CO_SDO_AB_NONE; +} + +CO_ReturnError_t CO_SRDOGuard_init( + CO_SRDOGuard_t *SRDOGuard, + CO_SDO_t *SDO, + CO_NMT_internalState_t *operatingState, + uint8_t *configurationValid, + uint16_t idx_SRDOvalid, + uint16_t idx_SRDOcrc) +{ + /* verify arguments */ + if(SRDOGuard==NULL || SDO==NULL || operatingState==NULL || configurationValid==NULL){ + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + SRDOGuard->operatingState = operatingState; + SRDOGuard->operatingStatePrev = CO_NMT_INITIALIZING; + SRDOGuard->configurationValid = configurationValid; + SRDOGuard->checkCRC = *configurationValid == CO_SRDO_VALID_MAGIC; + + + /* Configure Object dictionary entry at index 0x13FE and 0x13FF */ + CO_OD_configure(SDO, idx_SRDOvalid, CO_ODF_SRDOvalid, (void*)SRDOGuard, 0, 0); + CO_OD_configure(SDO, idx_SRDOcrc, CO_ODF_SRDOcrc, (void*)SRDOGuard, 0, 0); + + return CO_ERROR_NO; +} + +uint8_t CO_SRDOGuard_process( + CO_SRDOGuard_t *SRDOGuard) +{ + uint8_t result = 0; + CO_NMT_internalState_t operatingState = *SRDOGuard->operatingState; + if(operatingState != SRDOGuard->operatingStatePrev && operatingState == CO_NMT_OPERATIONAL){ + SRDOGuard->operatingStatePrev = operatingState; + result |= 1 << 0; + } + + if(SRDOGuard->checkCRC){ + result |= 1 << 1; + SRDOGuard->checkCRC = 0; + } + return result; +} + +#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE +/******************************************************************************/ +void CO_SRDO_initCallbackPre( + CO_SRDO_t *SRDO, + void *object, + void (*pFunctSignalPre)(void *object)) +{ + if(SRDO != NULL){ + SRDO->functSignalObjectPre = object; + SRDO->pFunctSignalPre = pFunctSignalPre; + } +} +#endif + +/******************************************************************************/ +void CO_SRDO_initCallbackEnterSafeState( + CO_SRDO_t *SRDO, + void *object, + void (*pFunctSignalSafe)(void *object)) +{ + if(SRDO != NULL){ + SRDO->functSignalObjectSafe = object; + SRDO->pFunctSignalSafe = pFunctSignalSafe; + } +} + +CO_ReturnError_t CO_SRDO_init( + CO_SRDO_t *SRDO, + CO_SRDOGuard_t *SRDOGuard, + CO_EM_t *em, + CO_SDO_t *SDO, + uint8_t nodeId, + uint16_t defaultCOB_ID, + const CO_SRDOCommPar_t *SRDOCommPar, + const CO_SRDOMapPar_t *SRDOMapPar, + const uint16_t *checksum, + uint16_t idx_SRDOCommPar, + uint16_t idx_SRDOMapPar, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdxNormal, + uint16_t CANdevRxIdxInverted, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdxNormal, + uint16_t CANdevTxIdxInverted) +{ + /* verify arguments */ + if(SRDO==NULL || SRDOGuard==NULL || em==NULL || SDO==NULL || checksum==NULL || + SRDOCommPar==NULL || SRDOMapPar==NULL || CANdevRx==NULL || CANdevTx==NULL){ + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + SRDO->SRDOGuard = SRDOGuard; + SRDO->em = em; + SRDO->SDO = SDO; + SRDO->SRDOCommPar = SRDOCommPar; + SRDO->SRDOMapPar = SRDOMapPar; + SRDO->checksum = checksum; + SRDO->CANdevRx = CANdevRx; + SRDO->CANdevRxIdx[0] = CANdevRxIdxNormal; + SRDO->CANdevRxIdx[1] = CANdevRxIdxInverted; + SRDO->CANdevTx = CANdevTx; + SRDO->CANdevTxIdx[0] = CANdevTxIdxNormal; + SRDO->CANdevTxIdx[1] = CANdevTxIdxInverted; + SRDO->nodeId = nodeId; + SRDO->defaultCOB_ID[0] = defaultCOB_ID; + SRDO->defaultCOB_ID[1] = defaultCOB_ID + 1; + SRDO->valid = CO_SRDO_INVALID; + SRDO->toogle = 0; + SRDO->timer = 0; + SRDO->pFunctSignalSafe = NULL; + SRDO->functSignalObjectSafe = NULL; +#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE + SRDO->pFunctSignalPre = NULL; + SRDO->functSignalObjectPre = NULL; +#endif + + /* Configure Object dictionary entry at index 0x1301+ and 0x1341+ */ + CO_OD_configure(SDO, idx_SRDOCommPar, CO_ODF_SRDOcom, (void*)SRDO, 0, 0); + CO_OD_configure(SDO, idx_SRDOMapPar, CO_ODF_SRDOmap, (void*)SRDO, 0, 0); + + return CO_ERROR_NO; +} + +void CO_SRDO_process( + CO_SRDO_t *SRDO, + uint8_t commands, + uint32_t timeDifference_us, + uint32_t *timerNext_us) +{ + if(commands & (1<<1)){ + uint16_t crcValue = CO_SRDOcalcCrc(SRDO->SRDOCommPar, SRDO->SRDOMapPar); + if (*SRDO->checksum != crcValue) + *SRDO->SRDOGuard->configurationValid = 0; + } + + if((commands & (1<<0)) && *SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC){ + if(CO_SRDOconfigMap(SRDO, SRDO->SRDOMapPar->numberOfMappedObjects) == 0){ + CO_SRDOconfigCom(SRDO, SRDO->SRDOCommPar->COB_ID1_normal, SRDO->SRDOCommPar->COB_ID2_inverted); + } + else{ + SRDO->valid = CO_SRDO_INVALID; + } + } + + if(SRDO->valid && *SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL){ + SRDO->timer = (SRDO->timer > timeDifference_us) ? (SRDO->timer - timeDifference_us) : 0; + if(SRDO->valid == CO_SRDO_TX){ + if(SRDO->timer == 0){ + if(SRDO->toogle){ + CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[1]); + SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U - CO_CONFIG_SRDO_MINIMUM_DELAY; + } + else{ + + int16_t i; + uint8_t* pPDOdataByte_normal; + uint8_t* pPDOdataByte_inverted; + + uint8_t** ppODdataByte_normal; + uint8_t** ppODdataByte_inverted; + + bool_t data_ok = true; + + pPDOdataByte_normal = &SRDO->CANtxBuff[0]->data[0]; + ppODdataByte_normal = &SRDO->mapPointer[0][0]; + + pPDOdataByte_inverted = &SRDO->CANtxBuff[1]->data[0]; + ppODdataByte_inverted = &SRDO->mapPointer[1][0]; + +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX + /* check data before sending (optional) */ + for(i = 0; idataLength; i++){ + uint8_t invert = ~pPDOdataByte_inverted[i]; + if (pPDOdataByte_normal[i] != invert) + { + data_ok = false; + break; + } + } +#else + (void)timerNext_us; +#endif + if(data_ok){ + /* Copy data from Object dictionary. */ + for(i = 0; idataLength; i++){ + pPDOdataByte_normal[i] = *(ppODdataByte_normal[i]); + pPDOdataByte_inverted[i] = *(ppODdataByte_inverted[i]); + } + + CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[0]); + + SRDO->timer = CO_CONFIG_SRDO_MINIMUM_DELAY; + } + else{ + SRDO->toogle = 1; + /* save state */ + if(SRDO->pFunctSignalSafe != NULL){ + SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe); + } + } + } + SRDO->toogle = !SRDO->toogle; + } +#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT + if(timerNext_us != NULL){ + if(*timerNext_us > SRDO->timer){ + *timerNext_us = SRDO->timer; /* Schedule for next message timer */ + } + } +#endif + } + else if(SRDO->valid == CO_SRDO_RX){ + if(CO_FLAG_READ(SRDO->CANrxNew[SRDO->toogle])){ + + if(SRDO->toogle){ + int16_t i; + uint8_t* pPDOdataByte_normal; + uint8_t* pPDOdataByte_inverted; + + uint8_t** ppODdataByte_normal; + uint8_t** ppODdataByte_inverted; + bool_t data_ok = true; + + pPDOdataByte_normal = &SRDO->CANrxData[0][0]; + pPDOdataByte_inverted = &SRDO->CANrxData[1][0]; + for(i = 0; idataLength; i++){ + uint8_t invert = ~pPDOdataByte_inverted[i]; + if(pPDOdataByte_normal[i] != invert){ + data_ok = false; + break; + } + } + if(data_ok){ + ppODdataByte_normal = &SRDO->mapPointer[0][0]; + ppODdataByte_inverted = &SRDO->mapPointer[1][0]; + + /* Copy data to Object dictionary. If between the copy operation CANrxNew + * is set to true by receive thread, then copy the latest data again. */ + + for(i = 0; idataLength; i++){ + *(ppODdataByte_normal[i]) = pPDOdataByte_normal[i]; + *(ppODdataByte_inverted[i]) = pPDOdataByte_inverted[i]; + } + CO_FLAG_CLEAR(SRDO->CANrxNew[0]); + CO_FLAG_CLEAR(SRDO->CANrxNew[1]); + } + else{ + CO_FLAG_CLEAR(SRDO->CANrxNew[0]); + CO_FLAG_CLEAR(SRDO->CANrxNew[1]); + /* save state */ + if(SRDO->pFunctSignalSafe != NULL){ + SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe); + } + } + + SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U; + } + else{ + SRDO->timer = SRDO->SRDOCommPar->safetyRelatedValidationTime * 1000U; + } + SRDO->toogle = !SRDO->toogle; + } + + if(SRDO->timer == 0){ + SRDO->toogle = 0; + SRDO->timer = SRDO->SRDOCommPar->safetyRelatedValidationTime * 1000U; + CO_FLAG_CLEAR(SRDO->CANrxNew[0]); + CO_FLAG_CLEAR(SRDO->CANrxNew[1]); + /* save state */ + if(SRDO->pFunctSignalSafe != NULL){ + SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe); + } + } + } + } + else{ + SRDO->valid = CO_SRDO_INVALID; + CO_FLAG_CLEAR(SRDO->CANrxNew[0]); + CO_FLAG_CLEAR(SRDO->CANrxNew[1]); + } +} diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h new file mode 100644 index 00000000..446c9480 --- /dev/null +++ b/304/CO_SRDO.h @@ -0,0 +1,293 @@ +/** + * CANopen Safety Related Data Object protocol. + * + * @file CO_SRDO.h + * @ingroup CO_SRDO + * @author Robert Grüning + * @copyright 2020 - 2020 Robert Grüning + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" + +#ifndef CO_SRDO_H +#define CO_SRDO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_SRDO SRDO + * @ingroup CO_CANopen_304 + * @{ + * + * CANopen Safety Related Data Object protocol. + * + * The functionality is very similar to that of the PDOs. + * The main differences is every message is send and received twice. + * The second message must be bitwise inverted. The delay between the two messages and between each message pair is monitored. + * The distinction between sending and receiving SRDO is made at runtime (for PDO it is compile time). + * If the security protocol is used, at least one SRDO is mandatory. + */ + + +/** + * SRDO communication parameter. The same as record from Object dictionary (index 0x1301-0x1340). + */ +typedef struct{ + uint8_t maxSubIndex; /**< Equal to 6 */ + /** Direction of the SRDO. Values: + - 0: SRDO is invalid (deleted) + - 1: SRDO is transmiting data + - 2: SRDO is receive data */ + uint8_t informationDirection; + /** Refresh-time / SCT + - in tx mode (Refresh-time): transmission interval + - in rx mode (SCT): receive timeout between two SRDO */ + uint16_t safetyCycleTime; + /** SRVT + - in tx mode: unsed + - in rx mode: receive timeout between first and second SRDO message */ + uint8_t safetyRelatedValidationTime; + /** Transmission type. Values: + - 254: Manufacturer specific.*/ + uint8_t transmissionType; + /** Communication object identifier for message received. Meaning of the specific bits: + - Bit 0-10: COB-ID for PDO, to change it bit 31 must be set. + - Bit 11-29: set to 0 for 11 bit COB-ID. + - Bit 30: If true, rtr are NOT allowed for PDO. + - Bit 31: If true, node does NOT use the PDO. */ + uint32_t COB_ID1_normal; + /** Communication object identifier for message received. Meaning of the specific bits: + - Bit 0-10: COB-ID for PDO, to change it bit 31 must be set. + - Bit 11-29: set to 0 for 11 bit COB-ID. + - Bit 30: If true, rtr are NOT allowed for PDO. + - Bit 31: If true, node does NOT use the PDO. */ + uint32_t COB_ID2_inverted; +}CO_SRDOCommPar_t; + + +typedef struct{ + /** Actual number of mapped objects from 0 to 16. Only even numbers are allowed. To change mapped object, + this value must be 0. */ + uint8_t numberOfMappedObjects; + /** Location and size of the mapped object. + Even index is the normal object. Odd index is the inverted object. Bit meanings `0xIIIISSLL`: + - Bit 0-7: Data Length in bits. + - Bit 8-15: Subindex from object distionary. + - Bit 16-31: Index from object distionary. */ + uint32_t mappedObjects[16]; +}CO_SRDOMapPar_t; + +/** + * Gurad Object for SRDO + * monitors: + * - access to CRC objects + * - access configuration valid flag + * - change in operation state + */ +typedef struct{ + CO_NMT_internalState_t *operatingState; /**< pointer to current operation state */ + CO_NMT_internalState_t operatingStatePrev; /**< last operation state */ + uint8_t *configurationValid; /**< pointer to the configuration valid flag in OD */ + uint8_t checkCRC; /**< specifies whether a CRC check should be performed */ +}CO_SRDOGuard_t; + +/** + * SRDO object. + */ +typedef struct{ + CO_EM_t *em; /**< From CO_SRDO_init() */ + CO_SDO_t *SDO; /**< From CO_SRDO_init() */ + CO_SRDOGuard_t *SRDOGuard; /**< From CO_SRDO_init() */ + /** Pointers to 2*8 data objects, where SRDO will be copied */ + uint8_t *mapPointer[2][8]; + /** Data length of the received PDO message. Calculated from mapping */ + uint8_t dataLength; + uint8_t nodeId; /**< From CO_SRDO_init() */ + uint16_t defaultCOB_ID[2]; /**< From CO_SRDO_init() */ + /** 0 - invalid, 1 - tx, 2 - rx */ + uint8_t valid; + const CO_SRDOCommPar_t *SRDOCommPar; /**< From CO_SRDO_init() */ + const CO_SRDOMapPar_t *SRDOMapPar; /**< From CO_SRDO_init() */ + const uint16_t *checksum; /**< From CO_SRDO_init() */ + CO_CANmodule_t *CANdevRx; /**< From CO_SRDO_init() */ + CO_CANmodule_t *CANdevTx; /**< From CO_SRDO_init() */ + CO_CANtx_t *CANtxBuff[2]; /**< CAN transmit buffer inside CANdevTx */ + uint16_t CANdevRxIdx[2]; /**< From CO_SRDO_init() */ + uint16_t CANdevTxIdx[2]; /**< From CO_SRDO_init() */ + uint8_t toogle; /**< defines the current state */ + uint32_t timer; /**< transmit timer and receive timeout */ + /** Variable indicates, if new SRDO message received from CAN bus. */ + volatile void *CANrxNew[2]; + /** 2*8 data bytes of the received message. */ + uint8_t CANrxData[2][8]; + /** From CO_SRDO_initCallbackEnterSafeState() or NULL */ + void (*pFunctSignalSafe)(void *object); + /** From CO_SRDO_initCallbackEnterSafeState() or NULL */ + void *functSignalObjectSafe; +#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN + /** From CO_SRDO_initCallbackPre() or NULL */ + void (*pFunctSignalPre)(void *object); + /** From CO_SRDO_initCallbackPre() or NULL */ + void *functSignalObjectPre; +#endif +}CO_SRDO_t; + +/** + * Initialize SRDOGuard object. + * + * Function must be called in the communication reset section. + * + * @param SRDOGuard This object will be initialized. + * @param SDO SDO object. + * @param operatingState Pointer to variable indicating CANopen device NMT internal state. + * @param configurationValid Pointer to variable with the SR valid flag + * @param idx_SRDOvalid Index in Object Dictionary + * @param idx_SRDOcrc Index in Object Dictionary + * + * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + */ +CO_ReturnError_t CO_SRDOGuard_init( + CO_SRDOGuard_t *SRDOGuard, + CO_SDO_t *SDO, + CO_NMT_internalState_t *operatingState, + uint8_t *configurationValid, + uint16_t idx_SRDOvalid, + uint16_t idx_SRDOcrc); + +/** + * Process operation and valid state changes. + * + * @param SRDOGuard This object. + * @return uint8_t command for CO_SRDO_process(). + * - bit 0 entered operational + * - bit 1 validate checksum + */ +uint8_t CO_SRDOGuard_process( + CO_SRDOGuard_t *SRDOGuard); + +/** + * Initialize SRDO object. + * + * Function must be called in the communication reset section. + * + * @param SRDO This object will be initialized. + * @param SRDOGuard SRDOGuard object. + * @param em Emergency object. + * @param SDO SDO object. + * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. + * @param defaultCOB_ID Default COB ID for this SRDO (without NodeId). + * @param SRDOCommPar Pointer to _SRDO communication parameter_ record from Object + * dictionary (index 0x1301+). + * @param SRDOMapPar Pointer to _SRDO mapping parameter_ record from Object + * dictionary (index 0x1381+). + * @param checksum + * @param idx_SRDOCommPar Index in Object Dictionary + * @param idx_SRDOMapPar Index in Object Dictionary + * @param CANdevRx CAN device used for SRDO reception. + * @param CANdevRxIdxNormal Index of receive buffer in the above CAN device. + * @param CANdevRxIdxInverted Index of receive buffer in the above CAN device. + * @param CANdevTx CAN device used for SRDO transmission. + * @param CANdevTxIdxNormal Index of transmit buffer in the above CAN device. + * @param CANdevTxIdxInverted Index of transmit buffer in the above CAN device. + * + * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + */ +CO_ReturnError_t CO_SRDO_init( + CO_SRDO_t *SRDO, + CO_SRDOGuard_t *SRDOGuard, + CO_EM_t *em, + CO_SDO_t *SDO, + uint8_t nodeId, + uint16_t defaultCOB_ID, + const CO_SRDOCommPar_t *SRDOCommPar, + const CO_SRDOMapPar_t *SRDOMapPar, + const uint16_t *checksum, + uint16_t idx_SRDOCommPar, + uint16_t idx_SRDOMapPar, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdxNormal, + uint16_t CANdevRxIdxInverted, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdxNormal, + uint16_t CANdevTxIdxInverted); + +#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +/** + * Initialize SRDO callback function. + * + * Function initializes optional callback function, which should immediately + * start processing of CO_SRDO_process() function. + * Callback is called after SRDO message is received from the CAN bus. + * + * @param SRDO This object. + * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. + */ +void CO_SRDO_initCallbackPre( + CO_SRDO_t *RPDO, + void *object, + void (*pFunctSignalPre)(void *object)); +#endif + +/** + * Initialize SRDO callback function. + * + * Function initializes optional callback function, that is called when SRDO enters a safe state. + * This happens when a timeout is reached or the data is inconsistent. The safe state itself is not further defined. + * One measure, for example, would be to go back to the pre-operational state + * Callback is called from CO_SRDO_process(). + * + * @param SRDO This object. + * @param object Pointer to object, which will be passed to pFunctSignalSafe(). Can be NULL + * @param pFunctSignalSafe Pointer to the callback function. Not called if NULL. + */ +void CO_SRDO_initCallbackEnterSafeState( + CO_SRDO_t *SRDO, + void *object, + void (*pFunctSignalSafe)(void *object)); + +/** + * Process transmitting/receiving SRDO messages. + * + * This function verifies the checksum on demand. + * This function also configures the SRDO on operation state change to operational + * + * @param SRDO This object. + * @param commands result from CO_SRDOGuard_process(). + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param [out] timerNext_us info to OS. + */ +void CO_SRDO_process( + CO_SRDO_t *SRDO, + uint8_t commands, + uint32_t timeDifference_us, + uint32_t *timerNext_us); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +/** @} */ +#endif + diff --git a/CANopen.c b/CANopen.c index 9b1f67c9..7ed99017 100644 --- a/CANopen.c +++ b/CANopen.c @@ -61,6 +61,8 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; || (CO_NO_SDO_SERVER < 1 || CO_NO_SDO_SERVER > 128) \ || CO_NO_TIME > 1 \ || CO_NO_SDO_CLIENT > 128 \ + || CO_NO_GFC > 1 \ + || CO_NO_SRDO > 64 \ || (CO_NO_RPDO < 1 || CO_NO_RPDO > 0x200) \ || (CO_NO_TPDO < 1 || CO_NO_TPDO > 0x200) \ || ODL_consumerHeartbeatTime_arrayLength == 0 \ @@ -75,7 +77,9 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #define CO_RXCAN_SYNC (CO_RXCAN_NMT + CO_NO_NMT) #define CO_RXCAN_EMERG (CO_RXCAN_SYNC + CO_NO_SYNC) #define CO_RXCAN_TIME (CO_RXCAN_EMERG + CO_NO_EM_CONS) -#define CO_RXCAN_RPDO (CO_RXCAN_TIME + CO_NO_TIME) +#define CO_RXCAN_GFC (CO_RXCAN_TIME + CO_NO_TIME) +#define CO_RXCAN_SRDO (CO_RXCAN_GFC + CO_NO_GFC) +#define CO_RXCAN_RPDO (CO_RXCAN_SRDO + CO_NO_SRDO*2) #define CO_RXCAN_SDO_SRV (CO_RXCAN_RPDO + CO_NO_RPDO) #define CO_RXCAN_SDO_CLI (CO_RXCAN_SDO_SRV + CO_NO_SDO_SERVER) #define CO_RXCAN_CONS_HB (CO_RXCAN_SDO_CLI + CO_NO_SDO_CLIENT) @@ -85,6 +89,8 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; CO_NO_SYNC + \ CO_NO_EM_CONS + \ CO_NO_TIME + \ + CO_NO_GFC + \ + CO_NO_SRDO*2 + \ CO_NO_RPDO + \ CO_NO_SDO_SERVER + \ CO_NO_SDO_CLIENT + \ @@ -97,7 +103,9 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; #define CO_TXCAN_SYNC (CO_TXCAN_NMT + CO_NO_NMT_MST) #define CO_TXCAN_EMERG (CO_TXCAN_SYNC + CO_NO_SYNC) #define CO_TXCAN_TIME (CO_TXCAN_EMERG + CO_NO_EMERGENCY) -#define CO_TXCAN_TPDO (CO_TXCAN_TIME + CO_NO_TIME) +#define CO_TXCAN_GFC (CO_TXCAN_TIME + CO_NO_TIME) +#define CO_TXCAN_SRDO (CO_TXCAN_GFC + CO_NO_GFC) +#define CO_TXCAN_TPDO (CO_TXCAN_SRDO + CO_NO_SRDO*2) #define CO_TXCAN_SDO_SRV (CO_TXCAN_TPDO + CO_NO_TPDO) #define CO_TXCAN_SDO_CLI (CO_TXCAN_SDO_SRV + CO_NO_SDO_SERVER) #define CO_TXCAN_HB (CO_TXCAN_SDO_CLI + CO_NO_SDO_CLIENT) @@ -107,6 +115,8 @@ static uint32_t CO_traceBufferSize[CO_NO_TRACE]; CO_NO_SYNC + \ CO_NO_EMERGENCY + \ CO_NO_TIME + \ + CO_NO_GFC + \ + CO_NO_SRDO*2 + \ CO_NO_TPDO + \ CO_NO_SDO_SERVER + \ CO_NO_SDO_CLIENT + \ @@ -182,6 +192,22 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { CO->TIME = NULL; #endif +#if CO_NO_GFC == 1 + CO->GFC = (CO_GFC_t *)calloc(1, sizeof(CO_GFC_t)); + if (CO->GFC == NULL) errCnt++; + CO_memoryUsed += sizeof(CO_GFC_t); +#endif + +#if CO_NO_SRDO != 0 + /* SRDO */ + CO->SRDOGuard = (CO_SRDOGuard_t *)calloc(1, sizeof(CO_SRDOGuard_t)); + if (CO->SRDOGuard == NULL) errCnt++; + for (i = 0; i < CO_NO_SRDO; i++) { + CO->SRDO[i] = (CO_SRDO_t *)calloc(1, sizeof(CO_SRDO_t)); + if (CO->SRDO[i] == NULL) errCnt++; + } + CO_memoryUsed += sizeof(CO_SRDO_t) * CO_NO_SRDO + sizeof(CO_SRDOGuard_t); +#endif /* RPDO */ for (i = 0; i < CO_NO_RPDO; i++) { CO->RPDO[i] = (CO_RPDO_t *)calloc(1, sizeof(CO_RPDO_t)); @@ -321,6 +347,19 @@ void CO_delete(void *CANptr) { free(CO_HBcons_monitoredNodes); free(CO->HBcons); +#if CO_NO_GFC == 1 + /* GFC */ + free(CO->GFC); +#endif + +#if CO_NO_SRDO != 0 + /* SRDO */ + for (i = 0; i < CO_NO_SRDO; i++) { + free(CO->SRDO[i]); + } + free(CO->SRDOGuard); +#endif + /* TPDO */ for (i = 0; i < CO_NO_TPDO; i++) { free(CO->TPDO[i]); @@ -380,6 +419,13 @@ void CO_delete(void *CANptr) { #endif #if CO_NO_TIME == 1 static CO_TIME_t COO_TIME; +#endif +#if CO_NO_GFC == 1 + static CO_GFC_t COO_GFC; +#endif +#if CO_NO_SRDO != 0 + static CO_SRDOGuard_t COO_SRDOGuard; + static CO_SRDO_t COO_SRDO[CO_NO_SRDO]; #endif static CO_RPDO_t COO_RPDO[CO_NO_RPDO]; static CO_TPDO_t COO_TPDO[CO_NO_TPDO]; @@ -450,6 +496,19 @@ CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { CO->TIME = NULL; #endif +#if CO_NO_GFC == 1 + /* GFC */ + CO->GFC = &COO_GFC; +#endif + +#if CO_NO_SRDO != 0 + /* SRDO */ + CO->SRDOGuard = &COO_SRDOGuard; + for (i = 0; i < CO_NO_SRDO; i++) { + CO->SRDO[i] = &COO_SRDO[i]; + } +#endif + /* RPDO */ for (i = 0; i < CO_NO_RPDO; i++) { CO->RPDO[i] = &COO_RPDO[i]; @@ -583,8 +642,13 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { if (nodeId < 1 || nodeId > 127) { return CO_ERROR_PARAMETERS; } - /* Verify parameters from CO_OD */ +#if CO_NO_SRDO != 0 + if (sizeof(OD_SRDOCommunicationParameter_t) != sizeof(CO_SRDOCommPar_t) || + sizeof(OD_SRDOMappingParameter_t) != sizeof(CO_SRDOMapPar_t)) { + return CO_ERROR_PARAMETERS; + } +#endif if (sizeof(OD_TPDOCommunicationParameter_t) != sizeof(CO_TPDOCommPar_t) || sizeof(OD_TPDOMappingParameter_t) != sizeof(CO_TPDOMapPar_t) || sizeof(OD_RPDOCommunicationParameter_t) != sizeof(CO_RPDOCommPar_t) || @@ -712,6 +776,54 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { if (err) return err; #endif +#if CO_NO_GFC == 1 + /* GFC */ + CO_GFC_init(CO->GFC, + &OD_globalFailSafeCommandParameter, + CO->CANmodule[0], + CO_RXCAN_GFC, + CO_CAN_ID_GFC, + CO->CANmodule[0], + CO_TXCAN_GFC, + CO_CAN_ID_GFC); +#endif + +#if CO_NO_SRDO != 0 + /* SRDO */ + err = CO_SRDOGuard_init(CO->SRDOGuard, + CO->SDO[0], + &CO->NMT->operatingState, + &OD_configurationValid, + OD_H13FE_SRDO_VALID, + OD_H13FF_SRDO_CHECKSUM); + if (err) return err; + + for (i = 0; i < CO_NO_SRDO; i++) { + CO_CANmodule_t *CANdev = CO->CANmodule[0]; + uint16_t CANdevRxIdx = CO_RXCAN_SRDO + 2*i; + uint16_t CANdevTxIdx = CO_TXCAN_SRDO + 2*i; + + err = CO_SRDO_init(CO->SRDO[i], + CO->SRDOGuard, + CO->em, + CO->SDO[0], + nodeId, + ((i == 0) ? CO_CAN_ID_SRDO_1 : 0), + (CO_SRDOCommPar_t*)&OD_SRDOCommunicationParameter[i], + (CO_SRDOMapPar_t *)&OD_SRDOMappingParameter[i], + &OD_safetyConfigurationChecksum[i], + OD_H1301_SRDO_1_PARAM + i, + OD_H1381_SRDO_1_MAPPING + i, + CANdev, + CANdevRxIdx, + CANdevRxIdx + 1, + CANdev, + CANdevTxIdx, + CANdevTxIdx + 1); + if (err) return err; + } +#endif + /* RPDO */ for (i = 0; i < CO_NO_RPDO; i++) { CO_CANmodule_t *CANdevRx = CO->CANmodule[0]; @@ -1020,3 +1132,27 @@ void CO_process_TPDO(CO_t *co, CO_TPDO_process(co->TPDO[i], syncWas, timeDifference_us, timerNext_us); } } + +/******************************************************************************/ +#if CO_NO_SRDO != 0 +void CO_process_SRDO(CO_t *co, + uint32_t timeDifference_us, + uint32_t *timerNext_us) +{ + int16_t i; + uint8_t firstOperational; + +#if CO_NO_LSS_SLAVE == 1 + if (co->nodeIdUnconfigured) { + return; + } +#endif + + firstOperational = CO_SRDOGuard_process(co->SRDOGuard); + + /* Verify PDO Change Of State and process PDOs */ + for (i = 0; i < CO_NO_SRDO; i++) { + CO_SRDO_process(co->SRDO[i], firstOperational, timeDifference_us, timerNext_us); + } +} +#endif diff --git a/CANopen.h b/CANopen.h index fb0f7880..5a0f9967 100644 --- a/CANopen.h +++ b/CANopen.h @@ -87,6 +87,18 @@ extern "C" { * @} */ +/** + * @defgroup CO_CANopen_304 CANopen_304 + * @{ + * + * CANopen Safety (EN 50325­-5:2010 (formerly CiA 304)) + * + * Standard defines the usage of Safety Related Data Objects (SRDO) and the GFC. + * This is an additional protocol (to SDO, PDO) to exchange data. + * The meaning of "security" here refers not to security (crypto) but to data consistency. + * @} + */ + /** * @defgroup CO_CANopen_305 CANopen_305 * @{ @@ -163,6 +175,10 @@ extern "C" { #define CO_NO_EM_CONS (0 - 1) /** Number of Time-stamp objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ #define CO_NO_TIME (0 - 1) +/** Number of GFC objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ +#define CO_NO_GFC (0 - 1) +/** Number of SRDO objects, 0 to 64 (consumer(CANrx) + producer(CANtx)) */ +#define CO_NO_RPDO (0 - 64) /** Number of RPDO objects, 1 to 512 consumers (CANrx) */ #define CO_NO_RPDO (1 - 512) /** Number of TPDO objects, 1 to 512 producers (CANtx) */ @@ -237,6 +253,12 @@ extern "C" { #if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN #include "301/CO_SDOclient.h" #endif +#if CO_NO_GFC != 0 || defined CO_DOXYGEN + #include "304/CO_GFC.h" +#endif +#if CO_NO_SRDO != 0 || defined CO_DOXYGEN + #include "304/CO_SRDO.h" +#endif #if CO_NO_LSS_SLAVE != 0 || defined CO_DOXYGEN #include "305/CO_LSSslave.h" #endif @@ -277,6 +299,13 @@ typedef struct { #if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN CO_LEDs_t *LEDs; /**< LEDs object */ #endif +#if CO_NO_GFC != 0 || defined CO_DOXYGEN + CO_GFC_t *GFC; /**< GFC objects */ +#endif +#if CO_NO_SRDO != 0 || defined CO_DOXYGEN + CO_SRDOGuard_t *SRDOGuard; /**< SRDO objects */ + CO_SRDO_t *SRDO[CO_NO_SRDO]; /**< SRDO objects */ +#endif #if CO_NO_LSS_SLAVE == 1 || defined CO_DOXYGEN CO_LSSslave_t *LSSslave; /**< LSS slave object */ #endif @@ -446,6 +475,22 @@ void CO_process_TPDO(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us); +#if CO_NO_SRDO != 0 || defined CO_DOXYGEN +/** + * Process CANopen SRDO objects. + * + * Function must be called cyclically from real time thread with constant. + * interval (1ms typically). It processes receive SRDO CANopen objects. + * + * @param co CANopen object. + * @param timeDifference_us Time difference from previous function call in + * microseconds. + * @param [out] timerNext_us info to OS - see CO_process(). + */ +void CO_process_SRDO(CO_t *co, + uint32_t timeDifference_us, + uint32_t *timerNext_us); +#endif /* CO_NO_SRDO != 0 */ /** @} */ diff --git a/Makefile b/Makefile index 43856864..d7892215 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,8 @@ SOURCES = \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ $(CANOPEN_SRC)/301/CO_fifo.c \ $(CANOPEN_SRC)/303/CO_LEDs.c \ + $(CANOPEN_SRC)/304/CO_GFC.c \ + $(CANOPEN_SRC)/304/CO_SRDO.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ $(CANOPEN_SRC)/305/CO_LSSmaster.c \ $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ diff --git a/example/CO_OD.h b/example/CO_OD.h index 8f4a5a29..4e2f31e2 100644 --- a/example/CO_OD.h +++ b/example/CO_OD.h @@ -94,6 +94,8 @@ #define CO_NO_EMERGENCY 1 //Associated objects: 1014, 1015 #define CO_NO_SDO_SERVER 1 //Associated objects: 1200 #define CO_NO_SDO_CLIENT 1 //Associated objects: 1280 + #define CO_NO_GFC 0 //Associated objects: 1300 + #define CO_NO_SRDO 0 //Associated objects: 1301-13FF #define CO_NO_RPDO 4 //Associated objects: 1400, 1401, 1402, 1403, 1600, 1601, 1602, 1603 #define CO_NO_TPDO 4 //Associated objects: 1800, 1801, 1802, 1803, 1A00, 1A01, 1A02, 1A03 #define CO_NO_TRACE 0 @@ -127,7 +129,19 @@ UNSIGNED32 COB_IDServerToClient; UNSIGNED8 nodeIDOfTheSDOServer; } OD_SDOClientParameter_t; - +/*1301 */ typedef struct { + UNSIGNED8 maxSubIndex; + UNSIGNED8 informationDirection; + UNSIGNED16 safetyCycleTime; + UNSIGNED8 safetyRelatedValidationTime; + UNSIGNED8 transmissionType; + UNSIGNED32 COB_ID1_normal; + UNSIGNED32 COB_ID2_inverted; + } OD_SRDOCommunicationParameter_t; +/*1381 */ typedef struct { + UNSIGNED8 numberOfMappedObjects; + UNSIGNED32 mappedObject[16]; + } OD_SRDOMappingParameter_t; /*1400[4] */ typedef struct{ UNSIGNED8 maxSubIndex; UNSIGNED32 COB_IDUsedByRPDO; diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 45c85673..bcc7c89a 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -76,6 +76,23 @@ extern "C" { CO_CONFIG_HB_CONS_QUERY_FUNCT) #endif +#ifndef CO_CONFIG_GFC +#define CO_CONFIG_GFC (CO_CONFIG_GFC_CONSUMER | \ + CO_CONFIG_GFC_PRODUCER) +#endif + +#ifndef CO_CONFIG_SRDO +#define CO_CONFIG_SRDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_SRDO_CHECK_TX | \ + CO_CONFIG_RSRDO_CALLS_EXTENSION | \ + CO_CONFIG_TSRDO_CALLS_EXTENSION) +#endif + +#ifndef CO_CONFIG_SRDO_MINIMUM_DELAY +#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 +#endif + #ifndef CO_CONFIG_PDO #define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ diff --git a/example/Makefile b/example/Makefile index ca8aba45..b4264b7a 100644 --- a/example/Makefile +++ b/example/Makefile @@ -31,6 +31,8 @@ SOURCES = \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ $(CANOPEN_SRC)/301/CO_fifo.c \ $(CANOPEN_SRC)/303/CO_LEDs.c \ + $(CANOPEN_SRC)/304/CO_GFC.c \ + $(CANOPEN_SRC)/304/CO_SRDO.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ $(CANOPEN_SRC)/305/CO_LSSmaster.c \ $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ From 7c13199a1afb039aab99925b0b87c6b9181e4ea1 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Fri, 26 Jun 2020 11:56:46 +0200 Subject: [PATCH 090/520] Fix all possible warnings about unused timerNext_us argument --- 301/CO_Emergency.c | 1 + 301/CO_HBconsumer.c | 2 ++ 301/CO_NMT_Heartbeat.c | 2 ++ 301/CO_PDO.c | 2 ++ 301/CO_SDOclient.c | 4 ++++ 301/CO_SDOserver.c | 3 ++- 301/CO_SYNC.c | 2 ++ 303/CO_LEDs.c | 2 ++ 304/CO_SRDO.c | 4 ++-- 309/CO_gateway_ascii.c | 2 ++ 10 files changed, 21 insertions(+), 3 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 260b9408..7c1b44ce 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -265,6 +265,7 @@ void CO_EM_process( uint16_t emInhTime_100us, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ CO_EM_t *em = emPr->em; uint8_t errorRegister; diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 67d9cff2..a9d90345 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -317,6 +317,8 @@ void CO_HBconsumer_process( uint32_t timeDifference_us, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + uint8_t i; bool_t allMonitoredActiveCurrent = true; uint8_t allMonitoredOperationalCurrent = CO_NMT_OPERATIONAL; diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 8eb94357..c7513edb 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -206,6 +206,8 @@ CO_NMT_reset_cmd_t CO_NMT_process( const uint8_t errorBehavior[], uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + uint8_t CANpassive; CO_NMT_internalState_t currentOperatingState = NMT->operatingState; uint32_t HBtime = (uint32_t)HBtime_ms * 1000; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index b76a1d24..171e4b83 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -1026,6 +1026,8 @@ void CO_TPDO_process( uint32_t timeDifference_us, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + /* update timers */ TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) : 0; TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) ? (TPDO->eventTimer - timeDifference_us) : 0; diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 135c7476..50a0558d 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -382,6 +382,8 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, size_t *sizeTransferred, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; @@ -904,6 +906,8 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, size_t *sizeTransferred, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index be09ed35..8c899574 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -669,6 +669,8 @@ uint32_t CO_SDO_writeOD(CO_SDO_t *SDO, uint16_t length){ /******************************************************************************/ static void CO_SDO_process_done(CO_SDO_t *SDO, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + #if CO_SDO_RX_DATA_SIZE > 1 uint8_t proc = SDO->CANrxProc; uint8_t newProc = proc; @@ -684,7 +686,6 @@ static void CO_SDO_process_done(CO_SDO_t *SDO, uint32_t *timerNext_us) { timerNext_us = 0; /* Set timerNext_us to 0 to inform OS to call CO_SDO_process function again without delay. */ #endif #else - (void)(timerNext_us); CO_FLAG_CLEAR(SDO->CANrxNew[0]); #endif } diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index fde093a8..a08dde2d 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -353,6 +353,8 @@ CO_SYNC_status_t CO_SYNC_process( uint32_t ObjDict_synchronousWindowLength, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + CO_SYNC_status_t ret = CO_SYNC_NONE; uint32_t timerNew; diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 94944e0c..edf6aa26 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -56,6 +56,8 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, bool_t firmwareDownload, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + uint8_t rd = 0; uint8_t gr = 0; bool_t tick = false; diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index b6b20be9..82e35d72 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -598,6 +598,8 @@ void CO_SRDO_process( uint32_t timeDifference_us, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + if(commands & (1<<1)){ uint16_t crcValue = CO_SRDOcalcCrc(SRDO->SRDOCommPar, SRDO->SRDOMapPar); if (*SRDO->checksum != crcValue) @@ -648,8 +650,6 @@ void CO_SRDO_process( break; } } -#else - (void)timerNext_us; #endif if(data_ok){ /* Copy data from Object dictionary. */ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 341c64e3..3c15f0a5 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -578,6 +578,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, uint32_t timeDifference_us, uint32_t *timerNext_us) { + (void)timerNext_us; /* may be unused */ + bool_t err = false; /* syntax or other error, true or false, I/O variable */ char closed; /* indication of command delimiter, I/O variable */ CO_GTWA_respErrorCode_t respErrorCode = CO_GTWA_respErrorNone; From 6da668fc7ee67de7727c11a91bc58808e38f363f Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Fri, 26 Jun 2020 11:56:58 +0200 Subject: [PATCH 091/520] Fix whitespace issues in CO_SRDO.c and CO_SRDO.h --- 304/CO_SRDO.c | 10 +++++----- 304/CO_SRDO.h | 29 ++++++++++++++--------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 82e35d72..68414c25 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -489,7 +489,7 @@ CO_ReturnError_t CO_SRDOGuard_init( CO_OD_configure(SDO, idx_SRDOvalid, CO_ODF_SRDOvalid, (void*)SRDOGuard, 0, 0); CO_OD_configure(SDO, idx_SRDOcrc, CO_ODF_SRDOcrc, (void*)SRDOGuard, 0, 0); - return CO_ERROR_NO; + return CO_ERROR_NO; } uint8_t CO_SRDOGuard_process( @@ -591,10 +591,10 @@ CO_ReturnError_t CO_SRDO_init( return CO_ERROR_NO; } - + void CO_SRDO_process( CO_SRDO_t *SRDO, - uint8_t commands, + uint8_t commands, uint32_t timeDifference_us, uint32_t *timerNext_us) { @@ -655,7 +655,7 @@ void CO_SRDO_process( /* Copy data from Object dictionary. */ for(i = 0; idataLength; i++){ pPDOdataByte_normal[i] = *(ppODdataByte_normal[i]); - pPDOdataByte_inverted[i] = *(ppODdataByte_inverted[i]); + pPDOdataByte_inverted[i] = *(ppODdataByte_inverted[i]); } CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[0]); @@ -691,7 +691,7 @@ void CO_SRDO_process( uint8_t** ppODdataByte_normal; uint8_t** ppODdataByte_inverted; bool_t data_ok = true; - + pPDOdataByte_normal = &SRDO->CANrxData[0][0]; pPDOdataByte_inverted = &SRDO->CANrxData[1][0]; for(i = 0; idataLength; i++){ diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 446c9480..40ac3102 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -41,7 +41,7 @@ extern "C" { * @{ * * CANopen Safety Related Data Object protocol. - * + * * The functionality is very similar to that of the PDOs. * The main differences is every message is send and received twice. * The second message must be bitwise inverted. The delay between the two messages and between each message pair is monitored. @@ -155,16 +155,16 @@ typedef struct{ /** * Initialize SRDOGuard object. - * + * * Function must be called in the communication reset section. - * + * * @param SRDOGuard This object will be initialized. * @param SDO SDO object. * @param operatingState Pointer to variable indicating CANopen device NMT internal state. * @param configurationValid Pointer to variable with the SR valid flag * @param idx_SRDOvalid Index in Object Dictionary * @param idx_SRDOcrc Index in Object Dictionary - * + * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_SRDOGuard_init( @@ -177,7 +177,7 @@ CO_ReturnError_t CO_SRDOGuard_init( /** * Process operation and valid state changes. - * + * * @param SRDOGuard This object. * @return uint8_t command for CO_SRDO_process(). * - bit 0 entered operational @@ -188,9 +188,9 @@ uint8_t CO_SRDOGuard_process( /** * Initialize SRDO object. - * + * * Function must be called in the communication reset section. - * + * * @param SRDO This object will be initialized. * @param SRDOGuard SRDOGuard object. * @param em Emergency object. @@ -201,7 +201,7 @@ uint8_t CO_SRDOGuard_process( * dictionary (index 0x1301+). * @param SRDOMapPar Pointer to _SRDO mapping parameter_ record from Object * dictionary (index 0x1381+). - * @param checksum + * @param checksum * @param idx_SRDOCommPar Index in Object Dictionary * @param idx_SRDOMapPar Index in Object Dictionary * @param CANdevRx CAN device used for SRDO reception. @@ -210,7 +210,7 @@ uint8_t CO_SRDOGuard_process( * @param CANdevTx CAN device used for SRDO transmission. * @param CANdevTxIdxNormal Index of transmit buffer in the above CAN device. * @param CANdevTxIdxInverted Index of transmit buffer in the above CAN device. - * + * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_SRDO_init( @@ -251,13 +251,13 @@ void CO_SRDO_initCallbackPre( #endif /** - * Initialize SRDO callback function. - * + * Initialize SRDO callback function. + * * Function initializes optional callback function, that is called when SRDO enters a safe state. * This happens when a timeout is reached or the data is inconsistent. The safe state itself is not further defined. * One measure, for example, would be to go back to the pre-operational state * Callback is called from CO_SRDO_process(). - * + * * @param SRDO This object. * @param object Pointer to object, which will be passed to pFunctSignalSafe(). Can be NULL * @param pFunctSignalSafe Pointer to the callback function. Not called if NULL. @@ -269,10 +269,10 @@ void CO_SRDO_initCallbackEnterSafeState( /** * Process transmitting/receiving SRDO messages. - * + * * This function verifies the checksum on demand. * This function also configures the SRDO on operation state change to operational - * + * * @param SRDO This object. * @param commands result from CO_SRDOGuard_process(). * @param timeDifference_us Time difference from previous function call in [microseconds]. @@ -290,4 +290,3 @@ void CO_SRDO_process( /** @} */ #endif - From 19bf4a7fd536742246a1df286972feb3a3417eaa Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Fri, 26 Jun 2020 12:03:18 +0200 Subject: [PATCH 092/520] Fix warnings about unused arguments and variables in CO_GFC.c --- 304/CO_GFC.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/304/CO_GFC.c b/304/CO_GFC.c index 0efc27c8..0c532d08 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -67,7 +67,6 @@ CO_ReturnError_t CO_GFC_init(CO_GFC_t *GFC, uint16_t GFC_txIdx, uint16_t CANidTxGFC) { - CO_ReturnError_t r; if (GFC == NULL || valid == NULL || GFC_CANdevRx == NULL || GFC_CANdevTx == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -90,12 +89,15 @@ CO_ReturnError_t CO_GFC_init(CO_GFC_t *GFC, 0, /* number of data bytes */ 0); /* synchronous message flag bit */ - if (GFC->CANtxBuff == 0) { + if (GFC->CANtxBuff == NULL) { return CO_ERROR_TX_UNCONFIGURED; } +#else + (void)GFC_txIdx; /* unused */ + (void)CANidTxGFC; /* unused */ #endif #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER - r = CO_CANrxBufferInit( + const CO_ReturnError_t r = CO_CANrxBufferInit( GFC_CANdevRx, /* CAN device */ GFC_rxIdx, /* rx buffer index */ CANidRxGFC, /* CAN identifier */ @@ -106,6 +108,9 @@ CO_ReturnError_t CO_GFC_init(CO_GFC_t *GFC, if (r != CO_ERROR_NO) { return r; } +#else + (void)GFC_rxIdx; /* unused */ + (void)CANidRxGFC; /* unused */ #endif return CO_ERROR_NO; From 3fbaec1d5e0a7f2853d14de85605737d38dac4bb Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Fri, 26 Jun 2020 12:09:37 +0200 Subject: [PATCH 093/520] Add configs for GFC & SRDO for socketCAN, otherwise the test build fails Default "make" for CANopenNode would fail with an error, because for socketCAN CO_CONFIG_SRDO_MINIMUM_DELAY was not defined. --- socketCAN/CO_driver_target.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 79eb6a82..c1b66fd5 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -82,6 +82,23 @@ extern "C" { CO_CONFIG_HB_CONS_CALLBACK_CHANGE) #endif +#ifndef CO_CONFIG_GFC +#define CO_CONFIG_GFC (CO_CONFIG_GFC_CONSUMER | \ + CO_CONFIG_GFC_PRODUCER) +#endif + +#ifndef CO_CONFIG_SRDO +#define CO_CONFIG_SRDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_SRDO_CHECK_TX | \ + CO_CONFIG_RSRDO_CALLS_EXTENSION | \ + CO_CONFIG_TSRDO_CALLS_EXTENSION) +#endif + +#ifndef CO_CONFIG_SRDO_MINIMUM_DELAY +#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 +#endif + #ifndef CO_CONFIG_PDO #define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ From 3cf4f62109715755f0106905dd8b805b6f1287ea Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Fri, 26 Jun 2020 12:35:46 +0200 Subject: [PATCH 094/520] Completely disable CO_gateway_ascii module if not enabled by config When CO_CONFIG_GTW_ASCII is not enabled in configuration, this module produces multiple important warnings, like 2 warnings about implicit function declaration. Instead of making the source more complex and fixing each warning individually, in this case it is much easier to just completely disable compilation of the whole thing. --- 309/CO_gateway_ascii.c | 3 +++ 309/CO_gateway_ascii.h | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 3c15f0a5..4ec5ab7b 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -32,6 +32,7 @@ #include "309/CO_gateway_ascii.h" +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII /******************************************************************************/ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, @@ -1961,3 +1962,5 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } + +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 617cd6ba..f9e74022 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -29,6 +29,9 @@ #define CO_GATEWAY_ASCII_H #include "301/CO_driver.h" + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + #include "301/CO_fifo.h" #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO #include "301/CO_SDOserver.h" @@ -526,5 +529,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /*__cplusplus*/ +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ + /** @} */ #endif /* CO_GATEWAY_ASCII_H */ From 3a50bc88c76301ad43a03e1389682408dfd9007d Mon Sep 17 00:00:00 2001 From: gotocoffee Date: Tue, 30 Jun 2020 19:17:55 +0200 Subject: [PATCH 095/520] SRDO tx & rx extension (#201) * CANopen Safety (SRDO according to DIN EN 50325-5:2016) * GFC code and docs * clang-format on GFC * SRDO tx and rx extension added CANopen Safety to README.md allow manual SRDO transmit some minor bug fixes Co-authored-by: rg1 --- 304/CO_SRDO.c | 176 +++++++++++++++++++++++++++++++++++++------------- 304/CO_SRDO.h | 31 +++++---- Doxyfile | 1 + README.md | 5 ++ 4 files changed, 157 insertions(+), 56 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index b6b20be9..b7cbfc43 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -104,9 +104,8 @@ static void CO_SRDOconfigCom(CO_SRDO_t* SRDO, uint32_t COB_IDnormal, uint32_t CO if(ID[i] == SRDO->defaultCOB_ID[i] && SRDO->nodeId <= 64){ ID[i] += 2*SRDO->nodeId; - } - if(0x101 <= ID[i] && ID[i] <= 0x180 && ((ID[i] ^ i) & 1)){ + if(0x101 <= ID[i] && ID[i] <= 0x180 && ((ID[i] & 1) != i )){ successCount++; } } @@ -309,18 +308,34 @@ static uint32_t CO_SRDOconfigMap(CO_SRDO_t* SRDO, uint8_t noOfMappedObjects){ return ret; } -static uint16_t CO_SRDOcalcCrc(const CO_SRDOCommPar_t *com, const CO_SRDOMapPar_t *map){ +static uint16_t CO_SRDOcalcCrc(const CO_SRDO_t *SRDO){ uint16_t i; uint16_t result = 0x0000; uint8_t buffer[4]; + uint32_t cob; + + const CO_SRDOCommPar_t *com = SRDO->SRDOCommPar; + const CO_SRDOMapPar_t *map = SRDO->SRDOMapPar; result = crc16_ccitt(&com->informationDirection, 1, result); CO_memcpySwap2(&buffer[0], &com->safetyCycleTime); result = crc16_ccitt(&buffer[0], 2, result); result = crc16_ccitt(&com->safetyRelatedValidationTime, 1, result); - CO_memcpySwap4(&buffer[0], &com->COB_ID1_normal); + + /* adjust COB-ID if the default is used + Caution: if the node id changes and you are using the default COB-ID you have to recalculate the checksum + This behaviour is controversial and could be changed or made optional. + */ + cob = com->COB_ID1_normal; + if(((cob)&0x7FF) == SRDO->defaultCOB_ID[0] && SRDO->nodeId <= 64) + cob += SRDO->nodeId; + CO_memcpySwap4(&buffer[0], &cob); result = crc16_ccitt(&buffer[0], 4, result); - CO_memcpySwap4(&buffer[0], &com->COB_ID2_inverted); + + cob = com->COB_ID2_inverted; + if(((cob)&0x7FF) == SRDO->defaultCOB_ID[1] && SRDO->nodeId <= 64) + cob += SRDO->nodeId; + CO_memcpySwap4(&buffer[0], &cob); result = crc16_ccitt(&buffer[0], 4, result); result = crc16_ccitt(&map->numberOfMappedObjects, 1, result); @@ -346,11 +361,11 @@ static CO_SDO_abortCode_t CO_ODF_SRDOcom(CO_ODF_arg_t *ODF_arg){ uint16_t index = ODF_arg->subIndex - 5; /* if default COB ID is used, write default value here */ - if(((value)&0x7FF) == SRDO->defaultCOB_ID[index] && SRDO->defaultCOB_ID[index]) + if(((value)&0x7FF) == SRDO->defaultCOB_ID[index] && SRDO->nodeId <= 64) value += SRDO->nodeId; - /* If PDO is not valid, set bit 31 */ - if(!SRDO->valid) value |= 0x80000000L; + /* If SRDO is not valid, set bit 31. but I do not think this applies to SRDO ?! */ + /* if(!SRDO->valid) value |= 0x80000000L; */ CO_setUint32(ODF_arg->data, value); } @@ -385,14 +400,13 @@ static CO_SDO_abortCode_t CO_ODF_SRDOcom(CO_ODF_arg_t *ODF_arg){ uint32_t value = CO_getUint32(ODF_arg->data); uint16_t index = ODF_arg->subIndex - 5; - /* bits 11...29 must be zero */ - if(value & 0x3FFFF800L) + /* check value range, the spec does not specify if COB-ID flags are allowed */ + if(value < 0x101 || value > 0x180 || (value & 1) == index) return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ /* if default COB-ID is being written, write defaultCOB_ID without nodeId */ - if(((value)&0x7FF) == (SRDO->defaultCOB_ID[index] + SRDO->nodeId)){ - value &= 0xC0000000L; - value += SRDO->defaultCOB_ID[index]; + if(SRDO->nodeId <= 64 && value == (SRDO->defaultCOB_ID[index] + SRDO->nodeId)){ + value = SRDO->defaultCOB_ID[index]; CO_setUint32(ODF_arg->data, value); } } @@ -406,17 +420,8 @@ static CO_SDO_abortCode_t CO_ODF_SRDOmap(CO_ODF_arg_t *ODF_arg){ CO_SRDO_t *SRDO; SRDO = (CO_SRDO_t*) ODF_arg->object; - - /* Reading Object Dictionary variable */ - if(ODF_arg->reading){ - uint8_t *value = (uint8_t*) ODF_arg->data; - - if(ODF_arg->subIndex == 0){ - /* If there is error in mapping, dataLength is 0, so numberOfMappedObjects is 0. */ - if(!SRDO->dataLength) *value = 0; - } + if(ODF_arg->reading) return CO_SDO_AB_NONE; - } /* Writing Object Dictionary variable */ @@ -430,7 +435,7 @@ static CO_SDO_abortCode_t CO_ODF_SRDOmap(CO_ODF_arg_t *ODF_arg){ uint8_t *value = (uint8_t*) ODF_arg->data; if(*value > 16 || *value & 1) /*only odd numbers are allowed*/ - return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds PDO length. */ + return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds SRDO length. */ } else{ if (SRDO->SRDOMapPar->numberOfMappedObjects != 0) @@ -497,9 +502,10 @@ uint8_t CO_SRDOGuard_process( { uint8_t result = 0; CO_NMT_internalState_t operatingState = *SRDOGuard->operatingState; - if(operatingState != SRDOGuard->operatingStatePrev && operatingState == CO_NMT_OPERATIONAL){ + if(operatingState != SRDOGuard->operatingStatePrev){ SRDOGuard->operatingStatePrev = operatingState; - result |= 1 << 0; + if (operatingState == CO_NMT_OPERATIONAL) + result |= 1 << 0; } if(SRDOGuard->checkCRC){ @@ -585,12 +591,28 @@ CO_ReturnError_t CO_SRDO_init( SRDO->functSignalObjectPre = NULL; #endif - /* Configure Object dictionary entry at index 0x1301+ and 0x1341+ */ + /* Configure Object dictionary entry at index 0x1301+ and 0x1381+ */ CO_OD_configure(SDO, idx_SRDOCommPar, CO_ODF_SRDOcom, (void*)SRDO, 0, 0); CO_OD_configure(SDO, idx_SRDOMapPar, CO_ODF_SRDOmap, (void*)SRDO, 0, 0); return CO_ERROR_NO; } + +CO_ReturnError_t CO_SRDO_requestSend( + CO_SRDO_t *SRDO) +{ + if (*SRDO->SRDOGuard->operatingState != CO_NMT_OPERATIONAL) + return CO_ERROR_WRONG_NMT_STATE; + + if (SRDO->valid != CO_SRDO_TX) + return CO_ERROR_TX_UNCONFIGURED; + + if(SRDO->toogle != 0) + return CO_ERROR_TX_BUSY; + + SRDO->timer = 0; + return CO_ERROR_NO; +} void CO_SRDO_process( CO_SRDO_t *SRDO, @@ -599,7 +621,7 @@ void CO_SRDO_process( uint32_t *timerNext_us) { if(commands & (1<<1)){ - uint16_t crcValue = CO_SRDOcalcCrc(SRDO->SRDOCommPar, SRDO->SRDOMapPar); + uint16_t crcValue = CO_SRDOcalcCrc(SRDO); if (*SRDO->checksum != crcValue) *SRDO->SRDOGuard->configurationValid = 0; } @@ -624,25 +646,56 @@ void CO_SRDO_process( else{ int16_t i; - uint8_t* pPDOdataByte_normal; - uint8_t* pPDOdataByte_inverted; + uint8_t* pSRDOdataByte_normal; + uint8_t* pSRDOdataByte_inverted; uint8_t** ppODdataByte_normal; uint8_t** ppODdataByte_inverted; bool_t data_ok = true; - - pPDOdataByte_normal = &SRDO->CANtxBuff[0]->data[0]; +#if (CO_CONFIG_SRDO) & CO_CONFIG_TSRDO_CALLS_EXTENSION + if(SRDO->SDO->ODExtensions){ + /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ + const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0]; + CO_SDO_t *pSDO = SRDO->SDO; + + for(i=SRDO->SRDOMapPar->numberOfMappedObjects; i>0; i--){ + uint32_t map = *(pMap++); + uint16_t index = (uint16_t)(map>>16); + uint8_t subIndex = (uint8_t)(map>>8); + uint16_t entryNo = CO_OD_find(pSDO, index); + if ( entryNo != 0xFFFF ) + { + CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo]; + if( ext->pODFunc != NULL) + { + CO_ODF_arg_t ODF_arg; + memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t)); + ODF_arg.reading = true; + ODF_arg.index = index; + ODF_arg.subIndex = subIndex; + ODF_arg.object = ext->object; + ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex); + ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex); + ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); /* https://github.com/CANopenNode/CANopenNode/issues/100 */ + ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex); + ext->pODFunc(&ODF_arg); + } + } + } + } +#endif + pSRDOdataByte_normal = &SRDO->CANtxBuff[0]->data[0]; ppODdataByte_normal = &SRDO->mapPointer[0][0]; - pPDOdataByte_inverted = &SRDO->CANtxBuff[1]->data[0]; + pSRDOdataByte_inverted = &SRDO->CANtxBuff[1]->data[0]; ppODdataByte_inverted = &SRDO->mapPointer[1][0]; #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX /* check data before sending (optional) */ for(i = 0; idataLength; i++){ - uint8_t invert = ~pPDOdataByte_inverted[i]; - if (pPDOdataByte_normal[i] != invert) + uint8_t invert = ~*(ppODdataByte_inverted[i]); + if (*(ppODdataByte_normal[i]) != invert) { data_ok = false; break; @@ -654,8 +707,8 @@ void CO_SRDO_process( if(data_ok){ /* Copy data from Object dictionary. */ for(i = 0; idataLength; i++){ - pPDOdataByte_normal[i] = *(ppODdataByte_normal[i]); - pPDOdataByte_inverted[i] = *(ppODdataByte_inverted[i]); + pSRDOdataByte_normal[i] = *(ppODdataByte_normal[i]); + pSRDOdataByte_inverted[i] = *(ppODdataByte_inverted[i]); } CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[0]); @@ -685,18 +738,18 @@ void CO_SRDO_process( if(SRDO->toogle){ int16_t i; - uint8_t* pPDOdataByte_normal; - uint8_t* pPDOdataByte_inverted; + uint8_t* pSRDOdataByte_normal; + uint8_t* pSRDOdataByte_inverted; uint8_t** ppODdataByte_normal; uint8_t** ppODdataByte_inverted; bool_t data_ok = true; - pPDOdataByte_normal = &SRDO->CANrxData[0][0]; - pPDOdataByte_inverted = &SRDO->CANrxData[1][0]; + pSRDOdataByte_normal = &SRDO->CANrxData[0][0]; + pSRDOdataByte_inverted = &SRDO->CANrxData[1][0]; for(i = 0; idataLength; i++){ - uint8_t invert = ~pPDOdataByte_inverted[i]; - if(pPDOdataByte_normal[i] != invert){ + uint8_t invert = ~pSRDOdataByte_inverted[i]; + if(pSRDOdataByte_normal[i] != invert){ data_ok = false; break; } @@ -709,11 +762,44 @@ void CO_SRDO_process( * is set to true by receive thread, then copy the latest data again. */ for(i = 0; idataLength; i++){ - *(ppODdataByte_normal[i]) = pPDOdataByte_normal[i]; - *(ppODdataByte_inverted[i]) = pPDOdataByte_inverted[i]; + *(ppODdataByte_normal[i]) = pSRDOdataByte_normal[i]; + *(ppODdataByte_inverted[i]) = pSRDOdataByte_inverted[i]; } CO_FLAG_CLEAR(SRDO->CANrxNew[0]); CO_FLAG_CLEAR(SRDO->CANrxNew[1]); +#if (CO_CONFIG_SRDO) & CO_CONFIG_RSRDO_CALLS_EXTENSION + if(SRDO->SDO->ODExtensions){ + int16_t i; + /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ + const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0]; + CO_SDO_t *pSDO = SRDO->SDO; + + for(i=SRDO->SRDOMapPar->numberOfMappedObjects; i>0; i--){ + uint32_t map = *(pMap++); + uint16_t index = (uint16_t)(map>>16); + uint8_t subIndex = (uint8_t)(map>>8); + uint16_t entryNo = CO_OD_find(pSDO, index); + if ( entryNo != 0xFFFF ) + { + CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo]; + if( ext->pODFunc != NULL) + { + CO_ODF_arg_t ODF_arg; + memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t)); + ODF_arg.reading = false; + ODF_arg.index = index; + ODF_arg.subIndex = subIndex; + ODF_arg.object = ext->object; + ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex); + ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex); + ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); /* https://github.com/CANopenNode/CANopenNode/issues/100 */ + ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex); + ext->pODFunc(&ODF_arg); + } + } + } + } +#endif } else{ CO_FLAG_CLEAR(SRDO->CANrxNew[0]); diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 446c9480..9b9292f2 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -72,16 +72,12 @@ typedef struct{ - 254: Manufacturer specific.*/ uint8_t transmissionType; /** Communication object identifier for message received. Meaning of the specific bits: - - Bit 0-10: COB-ID for PDO, to change it bit 31 must be set. - - Bit 11-29: set to 0 for 11 bit COB-ID. - - Bit 30: If true, rtr are NOT allowed for PDO. - - Bit 31: If true, node does NOT use the PDO. */ + - Bit 0-10: COB-ID for SRDO + - Bit 11-31: set to 0 for 11 bit COB-ID. */ uint32_t COB_ID1_normal; /** Communication object identifier for message received. Meaning of the specific bits: - - Bit 0-10: COB-ID for PDO, to change it bit 31 must be set. - - Bit 11-29: set to 0 for 11 bit COB-ID. - - Bit 30: If true, rtr are NOT allowed for PDO. - - Bit 31: If true, node does NOT use the PDO. */ + - Bit 0-10: COB-ID for SRDO + - Bit 11-31: set to 0 for 11 bit COB-ID. */ uint32_t COB_ID2_inverted; }CO_SRDOCommPar_t; @@ -121,7 +117,7 @@ typedef struct{ CO_SRDOGuard_t *SRDOGuard; /**< From CO_SRDO_init() */ /** Pointers to 2*8 data objects, where SRDO will be copied */ uint8_t *mapPointer[2][8]; - /** Data length of the received PDO message. Calculated from mapping */ + /** Data length of the received SRDO message. Calculated from mapping */ uint8_t dataLength; uint8_t nodeId; /**< From CO_SRDO_init() */ uint16_t defaultCOB_ID[2]; /**< From CO_SRDO_init() */ @@ -245,7 +241,7 @@ CO_ReturnError_t CO_SRDO_init( * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ void CO_SRDO_initCallbackPre( - CO_SRDO_t *RPDO, + CO_SRDO_t *SRDO, void *object, void (*pFunctSignalPre)(void *object)); #endif @@ -258,7 +254,7 @@ void CO_SRDO_initCallbackPre( * One measure, for example, would be to go back to the pre-operational state * Callback is called from CO_SRDO_process(). * - * @param SRDO This object. + * @param SRDO This object. * @param object Pointer to object, which will be passed to pFunctSignalSafe(). Can be NULL * @param pFunctSignalSafe Pointer to the callback function. Not called if NULL. */ @@ -267,6 +263,19 @@ void CO_SRDO_initCallbackEnterSafeState( void *object, void (*pFunctSignalSafe)(void *object)); + +/** + * Send SRDO on event + * + * Sends SRDO before the next refresh timer tiggers. The message itself is send in CO_SRDO_process(). + * After the transmission the timer is reset to the full refresh time. + * + * @param SRDO This object. + * @return CO_ReturnError_t CO_ERROR_NO if request is granted + */ +CO_ReturnError_t CO_SRDO_requestSend( + CO_SRDO_t *SRDO); + /** * Process transmitting/receiving SRDO messages. * diff --git a/Doxyfile b/Doxyfile index 77fd7495..40cf1ac1 100644 --- a/Doxyfile +++ b/Doxyfile @@ -785,6 +785,7 @@ INPUT = README.md \ CANopen.h \ 301 \ 303 \ + 304 \ 305 \ 309 \ extra \ diff --git a/README.md b/README.md index 9357b053..64b35482 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ Characteristics slave, LSS fastscan. - [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. + - CANopen Safety, + EN 50325-5 "PDO like" communication in safety-relevant networks ### Other - [Suitable for 16-bit microcontrollers and above](#device-support) @@ -146,6 +148,9 @@ File structure - **crc16-ccitt.h/.c** - Calculation of CRC 16 CCITT polynomial. - **303/** - CANopen Recommendation - **CO_LEDs.h/.c** - CANopen LED Indicators + - **304/** - CANopen Safety. + - **CO_SRDO.h/.c** - CANopen Safety-relevant Data Object protocol. + - **CO_GFC.h/.c** - CANopen Global Failsafe Command (producer and consumer). - **305/** - CANopen layer setting services (LSS) and protocols. - **CO_LSS.h** - CANopen Layer Setting Services protocol (common). - **CO_LSSmaster.h/.c** - CANopen Layer Setting Service - master protocol. From 035da160b5130944f40548fe93612c4b3ca6e248 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 1 Jul 2020 09:44:18 +0200 Subject: [PATCH 096/520] SDO: fix to always check if buffer is empty before freeing it #204 Before this patch SDO queue process pointer could overrun receive pointer on receiving NMT stop command during active SDO communication. This fix is applied to 'master' and 'v1.3-master' branches. --- 301/CO_SDOserver.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 8c899574..0667c44e 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -675,6 +675,11 @@ static void CO_SDO_process_done(CO_SDO_t *SDO, uint32_t *timerNext_us) { uint8_t proc = SDO->CANrxProc; uint8_t newProc = proc; + /* check if buffer needs to be free */ + if (!CO_FLAG_READ(SDO->CANrxNew[proc])) { + return; + } + if (++newProc >= CO_SDO_RX_DATA_SIZE) newProc = 0; @@ -698,7 +703,7 @@ static void CO_SDO_abort(CO_SDO_t *SDO, uint32_t code){ SDO->CANtxBuff->data[3] = SDO->ODF_arg.subIndex; CO_memcpySwap4(&SDO->CANtxBuff->data[4], &code); SDO->state = CO_SDO_ST_IDLE; - /* skip all received messages in queue */ + /* skip all received messages in queue if any */ while (CO_FLAG_READ(SDO->CANrxNew[SDO->CANrxProc])) CO_SDO_process_done(SDO, NULL); CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); @@ -728,6 +733,7 @@ int8_t CO_SDO_process( /* SDO is allowed to work only in operational or pre-operational NMT state */ if(!NMTisPreOrOperational){ SDO->state = CO_SDO_ST_IDLE; + /* free receive buffer if it is not empty */ CO_SDO_process_done(SDO, timerNext_us); return 0; } @@ -1458,9 +1464,7 @@ int8_t CO_SDO_process( } /* free receive buffer if it is not empty */ - if (isNew) { - CO_SDO_process_done(SDO, timerNext_us); - } + CO_SDO_process_done(SDO, timerNext_us); /* send message */ if(sendResponse) { From 997a311a38ee58326a20a7935710bb27ed21cbec Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 8 Jul 2020 13:48:49 +0200 Subject: [PATCH 097/520] Fixed: delay between gateway commands #208 --- 309/CO_gateway_ascii.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 4ec5ab7b..c708c1be 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -1490,6 +1490,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_IDLE; } + else if (gtwa->state == CO_GTWA_ST_IDLE) { + return; + } + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO /* SDO upload state */ else if (gtwa->state == CO_GTWA_ST_READ) { @@ -1955,12 +1959,19 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */ /* illegal state */ - else if (gtwa->state != CO_GTWA_ST_IDLE) { + else { respErrorCode = CO_GTWA_respErrorInternalState; responseWithError(gtwa, respErrorCode); gtwa->state = CO_GTWA_ST_IDLE; } + /* execute next CANopen processing immediately, if idle and more commands + * available */ + if (timerNext_us != NULL && gtwa->state == CO_GTWA_ST_IDLE + && CO_fifo_CommSearch(>wa->commFifo, false) + ) { + *timerNext_us = 0; + } } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ From e79ed1709e1dbb96f3c72c01467c903f9a960278 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 13 Jul 2020 14:07:26 +0200 Subject: [PATCH 098/520] Update documentation --- 301/CO_SDOserver.h | 2 +- Doxyfile | 238 +++++++++++++++++++++++++++++-------------- doc/deviceSupport.md | 1 + 3 files changed, 162 insertions(+), 79 deletions(-) diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index f5faa59e..031f9a6d 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -325,7 +325,7 @@ typedef enum{ CO_SDO_AB_UNSUPPORTED_ACCESS = 0x06010000UL, /**< 0x06010000, Unsupported access to an object */ CO_SDO_AB_WRITEONLY = 0x06010001UL, /**< 0x06010001, Attempt to read a write only object */ CO_SDO_AB_READONLY = 0x06010002UL, /**< 0x06010002, Attempt to write a read only object */ - CO_SDO_AB_NOT_EXIST = 0x06020000UL, /**< 0x06020000, Object does not exist */ + CO_SDO_AB_NOT_EXIST = 0x06020000UL, /**< 0x06020000, Object does not exist in the object dictionary */ CO_SDO_AB_NO_MAP = 0x06040041UL, /**< 0x06040041, Object cannot be mapped to the PDO */ CO_SDO_AB_MAP_LEN = 0x06040042UL, /**< 0x06040042, Number and length of object to be mapped exceeds PDO length */ CO_SDO_AB_PRAM_INCOMPAT = 0x06040043UL, /**< 0x06040043, General parameter incompatibility reasons */ diff --git a/Doxyfile b/Doxyfile index 40cf1ac1..fa8eb200 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.13 +# Doxyfile 1.8.17 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,11 +17,11 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -179,6 +187,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -226,7 +244,12 @@ TAB_SIZE = 4 # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) ALIASES = @@ -264,17 +287,26 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # @@ -285,7 +317,7 @@ EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -297,7 +329,7 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 0. +# Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 @@ -327,7 +359,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -433,6 +465,12 @@ EXTRACT_ALL = NO EXTRACT_PRIVATE = NO +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -443,7 +481,7 @@ EXTRACT_PACKAGE = NO # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, @@ -487,8 +525,8 @@ HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -511,7 +549,7 @@ INTERNAL_DOCS = NO # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# (including Cygwin) ands Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES @@ -560,7 +598,7 @@ INLINE_INFO = YES # name. If set to NO, the members will appear in declaration order. # The default value is: YES. -SORT_MEMBER_DOCS = YES +SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member @@ -698,7 +736,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. @@ -743,7 +781,8 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = NO @@ -794,7 +833,7 @@ INPUT = README.md \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of # possible encodings. # The default value is: UTF-8. @@ -811,8 +850,10 @@ INPUT_ENCODING = UTF-8 # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, -# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = @@ -967,7 +1008,7 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO @@ -999,12 +1040,12 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -1032,7 +1073,7 @@ VERBATIM_HEADERS = YES # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse-libclang=ON option for CMake. +# generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO @@ -1045,6 +1086,16 @@ CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files +# were built. This is equivalent to specifying the "-p" option to a clang tool, +# such as clang-check. These options will then be passed to the parser. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1163,7 +1214,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1199,6 +1250,17 @@ HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. @@ -1222,13 +1284,13 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1267,7 +1329,7 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1343,7 +1405,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1351,7 +1413,7 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1360,7 +1422,7 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1368,7 +1430,7 @@ QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1376,7 +1438,7 @@ QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1417,7 +1479,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -DISABLE_INDEX = NO +DISABLE_INDEX = YES # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag @@ -1469,7 +1531,7 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # @@ -1480,8 +1542,14 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1508,8 +1576,8 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest @@ -1551,7 +1619,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1570,7 +1638,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1583,7 +1651,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1635,21 +1703,35 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. @@ -1770,7 +1852,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1784,6 +1866,14 @@ LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1823,9 +1913,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1834,8 +1924,8 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = @@ -1921,6 +2011,13 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- @@ -1953,9 +2050,9 @@ DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sf.net) file that captures the -# structure of the code including all documentation. Note that this feature is -# still experimental and incomplete at the moment. +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -2128,12 +2225,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2147,15 +2238,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = NO -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index ad3ec5da..94e18eff 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -96,6 +96,7 @@ S32DS (NXP S32 Design studio for Arm or Powerpc) Other ----- +* [FreeRTOS](https://github.com/martinwag/CANopenNode/tree/neuberger-freertos/stack/neuberger-FreeRTOS) by Neuberger, 2020-06-23, based on v1.3-master, see also [issue 198](https://github.com/CANopenNode/CANopenNode/issues/198). * [STM32CubeMX HAL](https://github.com/w1ne/CANOpenNode-CubeMX-HAL), 2019-05-03, demo project for Atollic studio, tested on Nucleo STM32L452xx board. * K64F_FreeRTOS, Kinetis SDK, 2018-02-13, [zip file](https://github.com/CANopenNode/CANopenNode/pull/28#issuecomment-365392867) * LPC1768 (MBED) (released in 2016) - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), [known example from 2016](https://github.com/exmachina-dev/CANopenMbed) From d98fb635f5e4591ff8ee945d760aa075ee2d5a18 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 13 Jul 2020 14:08:16 +0200 Subject: [PATCH 099/520] Added CO_ODinterface --- 301/CO_ODinterface.c | 668 +++++++++++++++++++++++++++++++++ 301/CO_ODinterface.h | 874 +++++++++++++++++++++++++++++++++++++++++++ Makefile | 1 + README.md | 9 +- example/Makefile | 1 + 5 files changed, 1550 insertions(+), 3 deletions(-) create mode 100644 301/CO_ODinterface.c create mode 100644 301/CO_ODinterface.h diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c new file mode 100644 index 00000000..734193f2 --- /dev/null +++ b/301/CO_ODinterface.c @@ -0,0 +1,668 @@ +/* + * CANopen Object Dictionary interface + * + * @file CO_ODinterface.c + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#define OD_DEFINITION +#include "301/CO_ODinterface.h" + + +/* Read value from variable from Object Dictionary, see OD_subEntry_t *********/ +static OD_size_t OD_readDirect(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) +{ + (void) subIndex; + + if (stream == NULL || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + OD_size_t n = stream->dataLength; + const char *odData = (const char *)stream->dataObject; + + if (odData == NULL) { + *returnCode = ODR_SUB_NOT_EXIST; + return 0; + } + + *returnCode = ODR_OK; + + if (stream->dataOffset > 0 || n > count) { + /* data will be (are) read in several segments */ + n -= stream->dataOffset; + odData += stream->dataOffset; + + if (n > count) { + /* not enough space in destionation buffer */ + n = count; + stream->dataOffset += n; + *returnCode = ODR_PARTIAL; + } + else { + stream->dataOffset = 0; /* copy finished, reset offset */ + } + } + + memcpy(buf, odData, n); + return n; +} + +/* Write value to variable from Object Dictionary, see OD_subEntry_t **********/ +static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + (void) subIndex; + + if (stream == NULL || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + OD_size_t n = stream->dataLength; + char *odData = (char *)stream->dataObject; + + if (odData == NULL) { + *returnCode = ODR_SUB_NOT_EXIST; + return 0; + } + + *returnCode = ODR_OK; + + if (stream->dataOffset > 0 || n > count) { + /* data will be (are) written in several segments */ + n -= stream->dataOffset; + odData += stream->dataOffset; + + if (n > count) { + /* OD variable is larger than current ammount of data */ + n = count; + stream->dataOffset += n; + *returnCode = ODR_PARTIAL; + } + else { + stream->dataOffset = 0; /* copy finished, reset offset */ + } + } + + memcpy(odData, buf, n); + return n; +} + +/******************************************************************************/ +const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { + unsigned int cur; + unsigned int min = 0; + unsigned int max = od->size - 1; + + if (od == NULL || od->size == 0) { + return NULL; + } + + /* Fast search in ordered Object Dictionary. If indexes are mixed, + * this won't work. If Object Dictionary has up to 2^N entries, then N is + * max number of loop passes. */ + while (min < max) { + /* get entry between min and max */ + cur = (min + max) >> 1; + const OD_entry_t* entry = &od->list[cur]; + + if (index == entry->index) { + return entry; + } + else if (index < entry->index) { + max = cur; + if(max > 0) max--; + } + else { + min = cur + 1; + } + } + + if (min == max) { + const OD_entry_t* entry = &od->list[min]; + if (index == entry->index) { + return entry; + } + } + + return NULL; /* entry does not exist in OD */ +} + +/******************************************************************************/ +ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, + OD_subEntry_t *subEntry, OD_stream_t *stream) +{ + if (entry == NULL) return ODR_IDX_NOT_EXIST; + else if (subIndex > entry->maxSubIndex) return ODR_SUB_NOT_EXIST; + else if (subEntry == NULL || stream == NULL) return ODR_DEV_INCOMPAT; + + const void *odObject = entry->odObject; + bool_t io_configured = false; + uint8_t odBasicType = entry->odObjectType & ODT_TYPE_MASK; + + if (odObject == NULL) return ODR_DEV_INCOMPAT; + + /* common properties */ + subEntry->index = entry->index; + subEntry->subIndex = subIndex; + subEntry->maxSubIndex = entry->maxSubIndex; + subEntry->storageGroup = entry->storageGroup; + stream->dataOffset = 0; + + /* Object type is extended */ + if ((entry->odObjectType & ODT_EXTENSION_MASK) != 0) { + const OD_obj_extended_t *odoe = (const OD_obj_extended_t *)odObject; + + if (odoe->extIO != NULL && odoe->extIO->object != NULL) { + subEntry->read = odoe->extIO->read; + subEntry->write = odoe->extIO->write; + stream->dataObject = odoe->extIO->object; + io_configured = true; + } + subEntry->flagsPDO = odoe->flagsPDO; + odObject = odoe->odObjectOriginal; + if (odObject == NULL) return ODR_DEV_INCOMPAT; + } + else { + subEntry->flagsPDO = NULL; + } + + if (!io_configured) { + subEntry->read = OD_readDirect; + subEntry->write = OD_writeDirect; + } + + if (odBasicType == ODT_VAR) { + const OD_obj_var_t *odo = (const OD_obj_var_t *)odObject; + + subEntry->lowLimit = 0; + subEntry->highLimit = -1; + subEntry->attribute = odo->attribute; + if (!io_configured) stream->dataObject = odo->data; + stream->dataLength = odo->dataLength; + } + else if (odBasicType == ODT_VARL) { + const OD_obj_varLimits_t *odo = (const OD_obj_varLimits_t *)odObject; + + subEntry->lowLimit = odo->limit.low; + subEntry->highLimit = odo->limit.high; + subEntry->attribute = odo->attribute; + if (!io_configured) stream->dataObject = odo->data; + stream->dataLength = odo->dataLength; + } + else if (odBasicType == ODT_ARR) { + const OD_obj_array_t *odo = (const OD_obj_array_t *)odObject; + + subEntry->lowLimit = 0; + subEntry->highLimit = -1; + if (subIndex == 0) { + subEntry->attribute = odo->attribute0; + if (!io_configured) stream->dataObject = odo->data0; + stream->dataLength = 1; + } + else { + char *data = (char *)odo->data; + + subEntry->attribute = odo->attribute; + if (!io_configured) { + int i = subIndex - 1; + if (data == NULL) return ODR_DEV_INCOMPAT; + stream->dataObject = data + odo->dataElementSizeof * i; + } + stream->dataLength = odo->dataElementLength; + } + } + else if (odBasicType == ODT_ARRL) { + const OD_obj_arrayLimAttr_t *odo = + (const OD_obj_arrayLimAttr_t *)odObject; + + if (subIndex == 0) { + subEntry->lowLimit = 0; + subEntry->highLimit = -1; + subEntry->attribute = odo->attribute0; + if (!io_configured) stream->dataObject = odo->data0; + stream->dataLength = 1; + } + else { + char *data = (char *)odo->data; + int i = subIndex - 1; + + if (odo->limits == NULL || odo->attributes == NULL) + return ODR_DEV_INCOMPAT; + subEntry->lowLimit = odo->limits[i].low; + subEntry->highLimit = odo->limits[i].high; + subEntry->attribute = odo->attributes[i]; + if (!io_configured) { + if (data == NULL) return ODR_DEV_INCOMPAT; + stream->dataObject = data + odo->dataElementSizeof * i; + } + stream->dataLength = odo->dataElementLength; + } + } + else if (odBasicType == ODT_REC) { + const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)odObject; + const OD_obj_var_t *odo = &odo_rec[subIndex]; + + subEntry->lowLimit = 0; + subEntry->highLimit = -1; + subEntry->attribute = odo->attribute; + if (!io_configured) stream->dataObject = odo->data; + stream->dataLength = odo->dataLength; + } + else if (odBasicType == ODT_RECL) { + const OD_obj_varLimits_t *odo_rec = (const OD_obj_varLimits_t*)odObject; + const OD_obj_varLimits_t *odo = &odo_rec[subIndex]; + + subEntry->lowLimit = odo->limit.low; + subEntry->highLimit = odo->limit.high; + subEntry->attribute = odo->attribute; + if (!io_configured) stream->dataObject = odo->data; + stream->dataLength = odo->dataLength; + } + else { + return ODR_DEV_INCOMPAT; + } + + return ODR_OK; +} + +/******************************************************************************/ +uint32_t OD_getSDOabortCode(ODR_t returnCode) { + static const uint32_t abortCodes[ODR_COUNT] = { + 0x00000000UL, /* No abort */ + 0x05040005UL, /* Out of memory */ + 0x06010000UL, /* Unsupported access to an object */ + 0x06010001UL, /* Attempt to read a write only object */ + 0x06010002UL, /* Attempt to write a read only object */ + 0x06020000UL, /* Object does not exist in the object dictionary */ + 0x06040041UL, /* Object cannot be mapped to the PDO */ + 0x06040042UL, /* Num and len of object to be mapped exceeds PDO len */ + 0x06040043UL, /* General parameter incompatibility reasons */ + 0x06040047UL, /* General internal incompatibility in device */ + 0x06060000UL, /* Access failed due to hardware error */ + 0x06070010UL, /* Data type does not match, length does not match */ + 0x06070012UL, /* Data type does not match, length too high */ + 0x06070013UL, /* Data type does not match, length too short */ + 0x06090011UL, /* Sub index does not exist */ + 0x06090030UL, /* Invalid value for parameter (download only). */ + 0x06090031UL, /* Value range of parameter written too high */ + 0x06090032UL, /* Value range of parameter written too low */ + 0x06090036UL, /* Maximum value is less than minimum value. */ + 0x060A0023UL, /* Resource not available: SDO connection */ + 0x08000000UL, /* General error */ + 0x08000020UL, /* Data cannot be transferred or stored to application */ + 0x08000021UL, /* Data cannot be transf. because of local control */ + 0x08000022UL, /* Data cannot be tran. because of present device state */ + 0x08000023UL, /* Object dict. not present or dynamic generation fails */ + 0x08000024UL /* No data available */ + }; + + return (returnCode < 0 || returnCode >= ODR_COUNT) ? + abortCodes[ODR_DEV_INCOMPAT] : abortCodes[returnCode]; +} + +/******************************************************************************/ +bool_t OD_extensionIO_init(const OD_entry_t *entry, + void *object, + OD_size_t (*read)(OD_stream_t *stream, + uint8_t subIndex, + void *buf, + OD_size_t count, + ODR_t *returnCode), + OD_size_t (*write)(OD_stream_t *stream, + uint8_t subIndex, + const void *buf, + OD_size_t count, + ODR_t *returnCode)) +{ + if (entry == NULL || (entry->odObjectType & ODT_EXTENSION_MASK) == 0) { + return false; + } + + const OD_obj_extended_t *odo = (const OD_obj_extended_t *) entry->odObject; + + odo->extIO->object = object; + odo->extIO->read = read; + odo->extIO->write = write; + + return true; +} + +/******************************************************************************/ +void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup) { + if (od == NULL) return; + + int i; + + for (i = 0; i < od->size; i++) { + const OD_entry_t *entry = &od->list[i]; + const OD_obj_extended_t *odoe; + uint8_t subIndex; + uint8_t odBasicType; + const void *orig; + + /* skip non-matched storage group and non-extended OD objects */ + if (entry->storageGroup != storageGroup + || (entry->odObjectType & ODT_EXTENSION_MASK) != 0) + continue; + + /* skip if extIO read or original object is not specified */ + odoe = (const OD_obj_extended_t *)entry->odObject; + orig = odoe->odObjectOriginal; + if (odoe->extIO == NULL || orig == NULL + || odoe->extIO->object == NULL || odoe->extIO->read == NULL) + continue; + + /* update each sub-index separately */ + odBasicType = entry->odObjectType & ODT_TYPE_MASK; + for (subIndex = 0; subIndex < entry->maxSubIndex; subIndex++) { + OD_attr_t attr; + void *dataObject = NULL; + OD_size_t dataLength, dataReadTotal; + + if (odBasicType == ODT_VAR) { + const OD_obj_var_t *odo = (const OD_obj_var_t *)orig; + + attr = odo->attribute; + dataObject = odo->data; + dataLength = odo->dataLength; + } + else if (odBasicType == ODT_VARL) { + const OD_obj_varLimits_t *odo = (const OD_obj_varLimits_t*)orig; + + attr = odo->attribute; + dataObject = odo->data; + dataLength = odo->dataLength; + } + else if (odBasicType == ODT_ARR) { + const OD_obj_array_t *odo = (const OD_obj_array_t *)orig; + + if (subIndex == 0) { + attr = odo->attribute0; + dataObject = odo->data0; + dataLength = 1; + } + else { + char *data = (char *)odo->data; + if (data != NULL) { + int i = subIndex - 1; + attr = odo->attribute; + dataObject = data + odo->dataElementSizeof * i; + dataLength = odo->dataElementLength; + } + } + } + else if (odBasicType == ODT_ARRL) { + const OD_obj_arrayLimAttr_t *odo = + (const OD_obj_arrayLimAttr_t *)orig; + + if (subIndex == 0) { + attr = odo->attribute0; + dataObject = odo->data0; + dataLength = 1; + } + else { + char *data = (char *)odo->data; + if (data != NULL && odo->attributes != NULL) { + int i = subIndex - 1; + attr = odo->attributes[i]; + dataObject = data + odo->dataElementSizeof * i; + dataLength = odo->dataElementLength; + } + } + } + else if (odBasicType == ODT_REC) { + const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)orig; + const OD_obj_var_t *odo = &odo_rec[subIndex]; + + attr = odo->attribute; + dataObject = odo->data; + dataLength = odo->dataLength; + } + else if (odBasicType == ODT_RECL) { + const OD_obj_varLimits_t *odo_rec + = (const OD_obj_varLimits_t*)orig; + const OD_obj_varLimits_t *odo = &odo_rec[subIndex]; + + attr = odo->attribute; + dataObject = odo->data; + dataLength = odo->dataLength; + } + + if (dataObject == NULL || (attr&ODA_NOINIT) != 0 || dataLength == 0) + continue; + + /* copy data to group structure, several times if data is large */ + dataReadTotal = 0; + do { + char buf[32]; + ODR_t returnCode; + char *dest = (char *)dataObject + dataReadTotal; + OD_size_t dataRead = odoe->extIO->read(odoe->extIO->object, + subIndex, + buf, sizeof(buf), + &returnCode); + dataReadTotal += dataRead; + if (dataRead == 0 || dataReadTotal > dataLength) break; + memcpy(dest, buf, dataRead); + } while (dataReadTotal == dataLength); + } /* for (subIndex) */ + } /* for (entry) */ +} + + +/******************************************************************************/ +ODR_t OD_get_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t *val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t *val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t *val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_i64(const OD_entry_t *entry, uint16_t subIndex, int64_t *val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t *val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t *val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t *val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_u64(const OD_entry_t *entry, uint16_t subIndex, uint64_t *val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_r32(const OD_entry_t *entry, uint16_t subIndex, float32_t *val){ + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +ODR_t OD_get_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t *val){ + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + return ret; +} + +/******************************************************************************/ +ODR_t OD_set_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_i64(const OD_entry_t *entry, uint16_t subIndex, int64_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + int32_t lowLimit = subEntry.lowLimit; + int32_t highLimit = subEntry.highLimit; + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK && lowLimit <= highLimit) { + if (val > 0x7FFF || val > highLimit) ret = ODR_VALUE_HIGH; + else if (val < lowLimit) ret = ODR_VALUE_LOW; + } + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_u64(const OD_entry_t *entry, uint16_t subIndex, uint64_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_r32(const OD_entry_t *entry, uint16_t subIndex, float32_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} + +ODR_t OD_set_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + + if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + return ret; +} diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h new file mode 100644 index 00000000..d0d71282 --- /dev/null +++ b/301/CO_ODinterface.h @@ -0,0 +1,874 @@ +/** + * CANopen Object Dictionary interface + * + * @file CO_ODinterface.h + * @ingroup CO_ODinterface + * @author Janez Paternoster + * @copyright 2020 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef CO_OD_INTERFACE_H +#define CO_OD_INTERFACE_H + +#include "301/CO_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_ODinterface Object Dictionary interface + * @ingroup CO_CANopen_301 + * @{ + * See @ref CO_ODinterface_operation + */ +/** + * @defgroup CO_ODinterface_operation Operation + * @{ + * The CANopen Object Dictionary is essentially a grouping of objects accessible + * via the network in an ordered pre-defined fashion. + * + * Each object within the object dictionary is addressed using a 16-bit index + * and a 8-bit sub-index. + * + * ### Terms + * The term **OD object** means object from Object Dictionary located at + * specific 16-bit index. There are different types of OD objects in CANopen: + * variables, arrays and records (structures). Each OD object contains pointer + * to actual data, data length(s) and attribute(s). See @ref OD_objectTypes_t. + * + * The term **OD variable** is basic variable of specified type. For example: + * int8_t, uint32_t, float64_t, ... or just sequence of binary data with known + * or unknown data length. Each OD variable resides in Object dictionary at + * specified 16-bit index and 8-bit sub-index. + * + * The term **OD entry** means structure element, which contains some basic + * properties of the OD object, indication of type of OD object and pointer to + * all necessary data for the OD object. An array of OD entries together with + * information about total number of OD entries represents Object Dictionary as + * defined inside CANopenNode. See @ref OD_entry_t and @ref OD_t. + * + * ### Access + * Application and the stack have access to OD objects via universal @ref OD_t + * object and @ref OD_find() function, no direct access to custom structures, + * which define Object Dictionary, is required. Properties for specific + * OD variable is fetched with @ref OD_getSub() function. And access to actual + * variable is via @b read and @b write functions. Pointer to those two + * functions is fetched by @ref OD_getSub(). See @ref OD_stream_t and + * @ref OD_subEntry_t. See also shortcuts: @ref CO_ODgetSetters, for access to + * data of different type. + * + * ### Optional extensions + * There are some optional extensions to the Object Dictionary: fixed **low and + * high limit** prevent writing wrong value, PDO flags and IO extension. + * **PDO flags** informs application, if specific OD variable was received or + * sent by PDO. And also gives the application ability to request a TPDO, to + * which variable is possibly mapped. + * **IO extension** gives the application ability to take full control over the + * OD object. Application can specify own @b read and @b write functions and own + * object, on which they operate. + * + * ### Example usage + * @code +extern const OD_t ODxyz; + +void myFunc(const OD_t *od) { + ODR_t ret; + const OD_entry_t *entry; + OD_subEntry_t subEntry; + OD_IO_t io1008; + char buf[50]; + OD_size_t bytesRd; + int error = 0; + + //Init IO for "Manufacturer device name" at index 0x1008, sub-index 0x00 + entry = OD_find(od, 0x1008); + ret = OD_getSub(entry, 0x00, &subEntry, &io1008.stream); + io1008.read = subEntry.read; + //Read with io1008 + if (ret == ODR_OK) + bytesRd = io1008.read(&io1008.stream, 0x00, &buf[0], sizeof(buf), &ret); + if (ret != ODR_OK) error++; + + //Use helper and set "Producer heartbeat time" at index 0x1008, sub 0x00 + ret = OD_set_u16(OD_find(od, 0x1017), 0x00, 500); + if (ret != ODR_OK) error++; +} + * @endcode + * There is no need to include ODxyt.h file, it is only necessary to know, we + * have ODxyz defined somewhere. + * + * Second example is simpler and use helper function to access OD variable. + * However it is not very efficient, because it goes through all search + * procedures. + * + * If access to the same variable is very frequent, it is better to + * use first example. After initialization, application has to remember only + * "io1008" object. Frequent reading of the variable is then very efficient. + * + * ### Simple access to OD via globals + * Some simple user applications can also access some OD variables directly via + * globals. + * + * @warning + * If OD object has IO extension enabled, then direct access to its OD variables + * must not be used. Only valid access is via read or write or helper functions. + * + * @code +#include ODxyz.h + +void myFuncGlob(void) { + //Direct address instead of OD_find() + const OD_entry_t *entry_errReg = ODxyz_1001_errorRegister; + + //Direct access to OD variable + uint32_t devType = ODxyz_0.x1000_deviceType; + ODxyz_0.x1018_identity.serialNumber = 0x12345678; +} + * @endcode + * @} */ + +/** + * @defgroup CO_ODinterface_OD_example Object Dictionary example + * @{ + * Actual Object dictionary for one CANopen device is defined by pair of + * OD_xyz.h and ODxyz.h files. + * + * "xyz" is name of Object Dictionary, usually "0" is used for default. + * Configuration with multiple Object Dictionaries is also possible. + * + * Data for OD definition are arranged inside multiple structures. Structures + * are different for different configuration of OD. Data objects, created with + * those structures, are constant or are variable. + * + * Actual OD variables are arranged inside multiple structures, so called + * storage groups. Selected groups can be stored to non-volatile memory. + * + * @warning + * Manual editing of ODxyz.h/.c files is very error-prone. + * + * Pair of ODxyz.h/.c files can be generated by OD editor tool. The tool can + * edit standard CANopen device description file in xml format. Xml file may + * include also some non-standard elements, specific to CANopenNode. Xml file is + * then used for automatic generation of ODxyz.h/.c files. + * + * ### Example ODxyz.h file + * @code +typedef struct { + uint32_t x1000_deviceType; + uint8_t x1001_errorRegister; + struct { + uint8_t maxSubIndex; + uint32_t vendorID; + uint32_t productCode; + uint32_t revisionNumber; + uint32_t serialNumber; + } x1018_identity; +} ODxyz_0_t; + +typedef struct { + uint8_t x1001_errorRegister; +} ODxyz_1_t; + +extern ODxyz_0_t ODxyz_0; +extern ODxyz_1_t ODxyz_1; +extern const OD_t ODxyz; + +#define ODxyz_1000_deviceType &ODxyz.list[0] +#define ODxyz_1001_errorRegister &ODxyz.list[1] +#define ODxyz_1018_identity &ODxyz.list[2] + * @endcode + * + * ### Example ODxyz.c file + * @code +#define OD_DEFINITION +#include "301/CO_ODinterface.h" +#include "ODxyz.h" + +typedef struct { + OD_extensionIO_t xio_1001_errorRegister; +} ODxyz_ext_t; + +typedef struct { + OD_obj_var_t o_1000_deviceType; + OD_obj_var_t orig_1001_errorRegister; + OD_obj_extended_t o_1001_errorRegister; + OD_obj_var_t o_1018_identity[5]; +} ODxyz_objs_t; + +ODxyz_0_t ODxyz_0 = { + .x1000_deviceType = 0L, + .x1018_identity = { + .maxSubIndex = 4, + .vendorID = 0L, + .productCode = 0L, + .revisionNumber = 0L, + .serialNumber = 0L, + }, +}; + +ODxyz_1_t ODxyz_1 = { + .x1001_errorRegister = 0, +}; + +static ODxyz_ext_t ODxyz_ext = {0}; + +static const ODxyz_objs_t ODxyz_objs = { + .o_1000_deviceType = { + .data = &ODxyz_0.x1000_deviceType, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + .orig_1001_errorRegister = { + .data = &ODxyz_1.x1001_errorRegister, + .attribute = ODA_SDO_R, + .dataLength = 1, + }, + .o_1001_errorRegister = { + .flagsPDO = NULL, + .extIO = &ODxyz_ext.xio_1001_errorRegister, + .odObjectOriginal = &ODxyz_objs.orig_1001_errorRegister, + }, + .o_1018_identity = { + { + .data = &ODxyz_0.x1018_identity.maxSubIndex, + .attribute = ODA_SDO_R, + .dataLength = 1, + }, + { + .data = &ODxyz_0.x1018_identity.vendorID, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + { + .data = &ODxyz_0.x1018_identity.productCode, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + { + .data = &ODxyz_0.x1018_identity.revisionNumber, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + { + .data = &ODxyz_0.x1018_identity.serialNumber, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + } +}; + +const OD_t ODxyz = { + 3, { + {0x1000, 0, 0, ODT_VAR, &ODxyz_objs.o_1000_deviceType}, + {0x1001, 0, 1, ODT_EVAR, &ODxyz_objs.o_1001_errorRegister}, + {0x1018, 4, 0, ODT_REC, &ODxyz_objs.o_1018_identity}, + {0x0000, 0, 0, 0, NULL} +}}; + * @endcode + * @} */ + + +#ifndef OD_size_t +/** Variable of type OD_size_t contains data length in bytes of OD variable */ +#define OD_size_t uint32_t +/** Type of flagsPDO variable from OD_subEntry_t */ +#define OD_flagsPDO_t uint32_t +#endif + +/** Size of Object Dictionary attribute */ +#define OD_attr_t uint8_t + + +/** + * Attributes (bit masks) for OD sub-object. + */ +typedef enum { + ODA_SDO_R = 0x01, /**< SDO server may read from the variable */ + ODA_SDO_W = 0x02, /**< SDO server may write to the variable */ + ODA_SDO_RW = 0x03, /**< SDO server may read from or write to the variable */ + ODA_TPDO = 0x04, /**< Variable is mappable into TPDO (can be read) */ + ODA_RPDO = 0x08, /**< Variable is mappable into RPDO (can be written) */ + ODA_TRPDO = 0x0C, /**< Variable is mappable into TPDO or RPDO */ + ODA_TSRDO = 0x10, /**< Variable is mappable into transmitting SRDO */ + ODA_RSRDO = 0x20, /**< Variable is mappable into receiving SRDO */ + ODA_TRSRDO = 0x30, /**< Variable is mappable into tx or rx SRDO */ + ODA_MB = 0x40, /**< Variable is multi-byte (uint32_t, etc) */ + ODA_NOINIT = 0x80, /**< Variable has no initial value. Can be used with + OD objects, which has IO extension enabled. Object dictionary does not + reserve memory for the variable and storage is not used. */ +} OD_attributes_t; + + +/** + * Return codes from OD access functions + */ +typedef enum { +/* !!!! WARNING !!!! */ +/* If changing these values, change also OD_getSDOabortCode() function! */ + ODR_PARTIAL = -1, /**< Read/write is only partial, make more calls */ + ODR_OK = 0, /**< Read/write successfully finished */ + ODR_OUT_OF_MEM = 1, /**< Out of memory */ + ODR_UNSUPP_ACCESS = 2, /**< Unsupported access to an object */ + ODR_WRITEONLY = 3, /**< Attempt to read a write only object */ + ODR_READONLY = 4, /**< Attempt to write a read only object */ + ODR_IDX_NOT_EXIST = 5, /**< Object does not exist in the object dict. */ + ODR_NO_MAP = 6, /**< Object cannot be mapped to the PDO */ + ODR_MAP_LEN = 7, /**< PDO length exceeded */ + ODR_PAR_INCOMPAT = 8, /**< General parameter incompatibility reasons */ + ODR_DEV_INCOMPAT = 9, /**< General internal incompatibility in device */ + ODR_HW = 10, /**< Access failed due to hardware error */ + ODR_TYPE_MISMATCH = 11, /**< Data type does not match */ + ODR_DATA_LONG = 12, /**< Data type does not match, length too high */ + ODR_DATA_SHORT = 13, /**< Data type does not match, length too short */ + ODR_SUB_NOT_EXIST = 14, /**< Sub index does not exist */ + ODR_INVALID_VALUE = 15, /**< Invalid value for parameter (download only) */ + ODR_VALUE_HIGH = 16, /**< Value range of parameter written too high */ + ODR_VALUE_LOW = 17, /**< Value range of parameter written too low */ + ODR_MAX_LESS_MIN = 18, /**< Maximum value is less than minimum value */ + ODR_NO_RESOURCE = 19, /**< Resource not available: SDO connection */ + ODR_GENERAL = 20, /**< General error */ + ODR_DATA_TRANSF = 21, /**< Data cannot be transferred or stored to app */ + ODR_DATA_LOC_CTRL = 22, /**< Data can't be transf (local control) */ + ODR_DATA_DEV_STATE = 23, /**< Data can't be transf (present device state) */ + ODR_OD_MISSING = 23, /**< Object dictionary not present */ + ODR_NO_DATA = 25, /**< No data available */ + ODR_COUNT = 26 /**< Last element, number of responses */ +} ODR_t; + + +/** + * IO stream structure, used for read/write access to OD variable. + * + * Structure is initialized with @ref OD_getSub() function. + */ +typedef struct { + /** Pointer to data object, on which will operate read/write function */ + void *dataObject; + /** Data length in bytes or 0, if length is not specified */ + OD_size_t dataLength; + /** In case of large data, dataOffset indicates position of already + * transferred data */ + OD_size_t dataOffset; +} OD_stream_t; + + +/** + * Structure describing properties of a variable, located in specific index and + * sub-index inside the Object Dictionary. + * + * Structure is initialized with @ref OD_getSub() function. + */ +typedef struct { + /** Object Dictionary index */ + uint16_t index; + /** Object Dictionary sub-index */ + uint8_t subIndex; + /** Maximum sub-index in the OD object */ + uint8_t maxSubIndex; + /** Group for non-volatile storage of the OD object */ + uint8_t storageGroup; + /** Attribute bit-field of the OD sub-object, see OD_attributes_t */ + OD_attr_t attribute; + /** Low limit of the parameter value, not valid if greater than highLimit */ + int32_t lowLimit; + /** High limit of the parameter value, not valid if lower than lowLimit */ + int32_t highLimit; + /** + * Pointer to PDO flags bit-field. This is optional extension of OD object. + * If OD object has enabled this extension, then each sub-element is coupled + * with own flagsPDO variable of size 8 to 64 bits (size is configurable + * by @ref OD_flagsPDO_t). Flag is useful, when variable is mapped to RPDO + * or TPDO. + * + * If sub-element is mapped to RPDO, then bit0 is set to 1 each time, when + * any RPDO writes new data into variable. Application may clear bit0. + * + * If sub-element is mapped to TPDO, then TPDO will set one bit on the time, + * it is sent. First TPDO will set bit1, second TPDO will set bit2, etc. Up + * to 63 TPDOs can use flagsPDO. + * + * Another functionality is with asynchronous TPDOs, to which variable may + * be mapped. If corresponding bit is 0, TPDO will be sent. This means, that + * if application sets variable pointed by flagsPDO to zero, it will trigger + * sending all asynchronous TPDOs (up to first 63), to which variable is + * mapped. */ + OD_flagsPDO_t *flagsPDO; + /** + * Function pointer for reading value from specified variable from Object + * Dictionary. If OD variable is larger than buf, then this function must + * be called several times. After completed successful read function returns + * 'ODR_OK'. If read is partial, it returns 'ODR_PARTIAL'. In case of errors + * function returns code similar to SDO abort code. + * + * Read can be restarted with @ref OD_rwRestart() function. + * + * At the moment, when Object Dictionary is initialised, every variable has + * assigned the same "read" function. This default function simply copies + * data from Object Dictionary variable. Application can bind its own "read" + * function for specific object. In that case application is able to + * calculate data for reading from own internal state at the moment of + * "read" function call. For this functionality OD object must have IO + * extension enabled. OD object must also be initialised with + * @ref OD_extensionIO_init() function call. + * + * @param stream Object Dictionary stream object, returned from + * @ref OD_getSub() function, see @ref OD_stream_t. + * @param subIndex Object Dictionary subIndex of the accessed element. + * @param buf Pointer to external buffer, where to data will be copied. + * @param count Size of the external buffer in bytes. + * @param [out] returnCode Return value from @ref ODR_t. + * + * @return Number of bytes successfully read. + */ + OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, ODR_t *returnCode); + /** + * Function pointer for writing value into specified variable inside Object + * Dictionary. If OD variable is larger than buf, then this function must + * be called several times. After completed successful write function + * returns 'ODR_OK'. If read is partial, it returns 'ODR_PARTIAL'. In case + * of errors function returns code similar to SDO abort code. + * + * Write can be restarted with @ref OD_rwRestart() function. + * + * At the moment, when Object Dictionary is initialised, every variable has + * assigned the same "write" function, which simply copies data to Object + * Dictionary variable. Application can bind its own "write" function, + * similar as it can bind "read" function. + * + * @param stream Object Dictionary stream object, returned from + * @ref OD_getSub() function, see @ref OD_stream_t. + * @param subIndex Object Dictionary subIndex of the accessed element. + * @param buf Pointer to external buffer, from where data will be copied. + * @param count Size of the external buffer in bytes. + * @param [out] returnCode Return value from ODR_t. + * + * @return Number of bytes successfully written. + */ + OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, ODR_t *returnCode); +} OD_subEntry_t; + + +/** + * Helper structure for storing all objects necessary for frequent read from or + * write to specific OD variable. Structure can be used by application and can + * be filled inside and after @ref OD_getSub() function call. + */ +typedef struct { + /** Object passed to read or write */ + OD_stream_t stream; + /** Read function pointer, see @ref OD_subEntry_t */ + OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, ODR_t *returnCode); + /** Write function pointer, see @ref OD_subEntry_t */ + OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, ODR_t *returnCode); +} OD_IO_t; + + +/** + * Object Dictionary entry for one OD object. + * + * OD entries are collected inside OD_t as array (list). Each OD entry contains + * basic information about OD object (index, maxSubIndex and storageGroup) and + * access function together with a pointer to other details of the OD object. + */ +typedef struct { + /** Object Dictionary index */ + uint16_t index; + /** Maximum sub-index in the OD object */ + uint8_t maxSubIndex; + /** Group for non-volatile storage of the OD object */ + uint8_t storageGroup; + /** Type of the odObject, indicated by @ref OD_objectTypes_t enumerator. */ + uint8_t odObjectType; + /** OD object of type indicated by odObjectType, from which @ref OD_getSub() + * fetches the information */ + const void *odObject; +} OD_entry_t; + + +/** + * Object Dictionary + */ +typedef struct { + /** Number of elements in the list, without last element, which is blank */ + uint16_t size; + /** List OD entries (table of contents), ordered by index */ + OD_entry_t list[]; +} OD_t; + + +/** + * Find OD entry in Object Dictionary + * + * @param od Object Dictionary + * @param index CANopen Object Dictionary index of object in Object Dictionary + * + * @return Pointer to OD entry or NULL if not found + */ +const OD_entry_t *OD_find(const OD_t *od, uint16_t index); + + +/** + * Find sub-object with specified sub-index on OD entry returned by OD_find. + * Function populates subEntry and stream structures with sub-object data. + * + * @warning If this function is called on OD object, which has IO extension + * enabled and @ref OD_extensionIO_init() was not (yet) called on that object, + * then subEntry and stream structures are populated with properties of + * "original OD object". Call to this function after @ref OD_extensionIO_init() + * will populate subEntry and stream structures with properties of + * "newly initialised OD object". This is something very different. + * + * @param entry OD entry returned by @ref OD_find(). + * @param subIndex Sub-index of the variable from the OD object. + * @param [out] subEntry Structure will be populated on success. + * @param [out] stream Structure will be populated on success. + * + * @return Value from @ref ODR_t, "ODR_OK" in case of success. + */ +ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, + OD_subEntry_t *subEntry, OD_stream_t *stream); + + +/** + * Verify if value written to Object Dictionary is within limit values + * + * @param subEntry OD sub-entry data returned by @ref OD_getSub(). + * @param val Value to be verified. + * + * @return Value from @ref ODR_t, "ODR_OK" in case of success. + */ +static inline ODR_t OD_checkLimits(OD_subEntry_t *subEntry, int32_t val) { + int32_t lowLimit = subEntry->lowLimit; + int32_t highLimit = subEntry->highLimit; + + if (lowLimit <= highLimit) { + if (val < lowLimit) return ODR_VALUE_LOW; + if (val > highLimit) return ODR_VALUE_HIGH; + } + return ODR_OK; +} + + +/** + * Restart read or write operation on OD variable + * + * It is not necessary to call this function, if stream was initialised by + * @ref OD_getSub(). It is also not necessary to call this function, if prevous + * read or write was successfully finished. + * + * @param stream Object Dictionary stream object, returned from + * @ref OD_getSub() function, see @ref OD_stream_t. + */ +static inline void OD_rwRestart(OD_stream_t *stream) { + stream->dataOffset = 0; +} + + +/** + * Get SDO abort code from returnCode + * + * @param returnCode Returned from some OD access functions + * + * @return Corresponding @ref CO_SDO_abortCode_t + */ +uint32_t OD_getSDOabortCode(ODR_t returnCode); + + +/** + * Initialise extended OD object with own read/write functions + * + * This function works on OD object, which has IO extension enabled. It gives + * application very powerful tool: definition of own IO access on own OD + * object. Structure and attributes are the same as defined in original OD + * object, but data are read directly from (or written directly to) application + * specified object via custom function calls. + * + * One more feature is available on IO extended object. Before application calls + * @ref OD_extensionIO_init() it can read original OD object, which can contain + * initial values for the data. And also, as any data from OD, data can be + * loaded from or saved to nonvolatile storage. + * + * See also warning in @ref OD_getSub() function. + + * @param entry OD entry returned by @ref OD_find(). + * @param object Object, which will be passed to read or write function, must +* not be NULL. + * @param read Read function pointer, see @ref OD_subEntry_t. + * @param write Write function pointer, see @ref OD_subEntry_t. + * + * @return true on success, false if OD object doesn't exist or is not extended. + */ +bool_t OD_extensionIO_init(const OD_entry_t *entry, + void *object, + OD_size_t (*read)(OD_stream_t *stream, + uint8_t subIndex, + void *buf, + OD_size_t count, + ODR_t *returnCode), + OD_size_t (*write)(OD_stream_t *stream, + uint8_t subIndex, + const void *buf, + OD_size_t count, + ODR_t *returnCode)); + + +/** + * Update storage group data from OD object with IO extension. + * + * This function must be called, before OD variables from specified storageGroup + * will be save to non-volatile memory. This function must be called, because + * some OD objects have IO extension enabled. And those OD object are connected + * with application code, which have own control over the entire OD object data. + * Application does not use original data from the storageGroup. For that reason + * this function scans entire object dictionary, reads data from necessary + * OD objects and copies them to the original storageGroup. + * + * @param od Object Dictionary + * @param storageGroup Group of data to enable. + */ +void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup); + + +/** + * @defgroup CO_ODgetSetters Getters and setters + * @{ + * + * Getter and setter helpre functions for accessing different types of Object + * Dictionary variables. + */ +/** + * Get int8_t variable from Object Dictionary + * + * @param entry OD entry returned by @ref OD_find(). + * @param subIndex Sub-index of the variable from the OD object. + * @param [out] val Value will be written there. + * + * @return Value from @ref ODR_t, "ODR_OK" in case of success. + */ +ODR_t OD_get_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t *val); +/** Get int16_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t *val); +/** Get int32_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t *val); +/** Get int64_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_i64(const OD_entry_t *entry, uint16_t subIndex, int64_t *val); +/** Get uint8_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t *val); +/** Get uint16_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t *val); +/** Get uint32_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t *val); +/** Get uint64_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_u64(const OD_entry_t *entry, uint16_t subIndex, uint64_t *val); +/** Get float32_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_r32(const OD_entry_t *entry, uint16_t subIndex, float32_t *val); +/** Get float64_t variable from Object Dictionary, see @ref OD_get_i8 */ +ODR_t OD_get_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t *val); + +/** + * Set int8_t variable in Object Dictionary + * + * @param entry OD entry returned by @ref OD_find(). + * @param subIndex Sub-index of the variable from the OD object. + * @param val Value to write. + * + * @return Value from @ref ODR_t, "ODR_OK" in case of success. + */ +ODR_t OD_set_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t val); +/** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t val); +/** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t val); +/** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_i64(const OD_entry_t *entry, uint16_t subIndex, int64_t val); +/** Set uint8_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t val); +/** Set uint16_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t val); +/** Set uint32_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t val); +/** Set uint64_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_u64(const OD_entry_t *entry, uint16_t subIndex, uint64_t val); +/** Set float32_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_r32(const OD_entry_t *entry, uint16_t subIndex, float32_t val); +/** Set float64_t variable in Object Dictionary, see @ref OD_set_i8 */ +ODR_t OD_set_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t val); +/** @} */ /* CO_ODgetSetters */ + + +/** + * @defgroup CO_ODdefinition OD definition objects + * @{ + * + * Types and functions used only for definition of Object Dictionary + */ +#if defined OD_DEFINITION || defined CO_DOXYGEN + +/** + * Types for OD object. + */ +typedef enum { + /** This type corresponds to CANopen Object Dictionary object with object + * code equal to VAR. OD object is type of @ref OD_obj_var_t and represents + * single variable of any type (any length), located on sub-index 0. Other + * sub-indexes are not used. */ + ODT_VAR = 0x01, + /** This type corresponds to CANopen Object Dictionary object with object + * code equal to ARRAY. OD object is type of @ref OD_obj_array_t and + * represents array of variables with the same type, located on sub-indexes + * above 0. Sub-index 0 is of type uint8_t and usually represents length of + * the array. */ + ODT_ARR = 0x02, + /** This type corresponds to CANopen Object Dictionary object with object + * code equal to RECORD. This type of OD object represents structure of + * the variables. Each variable from the structure can have own type and + * own attribute. OD object is an array of elements of type + * @ref OD_obj_var_t. Variable at sub-index 0 is of type uint8_t and usually + * represents number of sub-elements in the structure. */ + ODT_REC = 0x03, + /** ODT_VAR with additional low and high limit of the parameter value */ + ODT_VARL = 0x04, + /** ODT_ARR with additional low and high limits of the parameter values */ + ODT_ARRL = 0x05, + /** ODT_REC with additional low and high limits of the parameter values */ + ODT_RECL = 0x06, + + /** Same as ODT_VAR, but extended with OD_obj_extended_t type. It includes + * additional pointer to IO extension and PDO flags */ + ODT_EVAR = 0x11, + /** Same as ODT_ARR, but extended with OD_obj_extended_t type */ + ODT_EARR = 0x12, + /** Same as ODT_REC, but extended with OD_obj_extended_t type */ + ODT_EREC = 0x13, + /** Same as ODT_VARL, but extended with OD_obj_extended_t type */ + ODT_EVARL = 0x14, + /** Same as ODT_ARRL, but extended with OD_obj_extended_t type. */ + ODT_EARRL = 0x15, + /** Same as ODT_RECL, but extended with OD_obj_extended_t type. */ + ODT_ERECL = 0x16, + + /** Mask for basic type */ + ODT_TYPE_MASK = 0x0F, + /** Mask for extension */ + ODT_EXTENSION_MASK = 0x10 +} OD_objectTypes_t; + +/** + * Object for single OD variable, used for "VAR" and "RECORD" type OD objects + */ +typedef struct { + void *data; /**< Pointer to data */ + OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ + OD_size_t dataLength; /**< Data length in bytes */ +} OD_obj_var_t; + +/** + * Limits of the parameter value. + */ +typedef struct { + int32_t low; /**< Low limit of the parameter value */ + int32_t high; /**< High limit of the parameter value */ +} OD_limits_t; + +/** + * Object for single OD variable, used for "VAR" and "RECORD" type OD objects. + * Additionally includes limits of the parameter value. + */ +typedef struct { + void *data; /**< Pointer to data */ + OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ + OD_size_t dataLength; /**< Data length in bytes */ + OD_limits_t limit; /**< Limits of the parameter value */ +} OD_obj_varLimits_t; + +/** + * Object for OD array of variables, used for "ARRAY" type OD objects + */ +typedef struct { + uint8_t *data0; /**< Pointer to data for sub-index 0 */ + void *data; /**< Pointer to array of data */ + OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see + @ref OD_attributes_t */ + OD_attr_t attribute; /**< Attribute bitfield for array elements */ + OD_size_t dataElementLength; /**< Data length of array elements in bytes */ + OD_size_t dataElementSizeof; /**< Sizeof one array element in bytes */ +} OD_obj_array_t; + +/** + * Object for OD array of variables, used for "ARRAY" type OD objects. + * Additionally includes limits of the parameter value for each array element + * and separate attribute for each array element. + */ +typedef struct { + uint8_t *data0; /**< Pointer to data for sub-index 0 */ + void *data; /**< Pointer to array of data */ + OD_limits_t *limits; /**< Pointer to array limits of the parameter value */ + OD_attr_t *attributes; /**< Pointer to array attributes */ + OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see + @ref OD_attributes_t */ + OD_size_t dataElementLength; /**< Data length of array elements in bytes */ + OD_size_t dataElementSizeof; /**< Sizeof one array element in bytes */ +} OD_obj_arrayLimAttr_t; + +/** + * Object pointed by @ref OD_obj_extended_t contains application specified + * parameters for extended OD object + */ +typedef struct { + /** Object on which read and write will operate */ + void *object; + /** Application specified function pointer, see @ref OD_subEntry_t. */ + OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, ODR_t *returnCode); + /** Application specified function pointer, see @ref OD_subEntry_t. */ + OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, ODR_t *returnCode); +} OD_extensionIO_t; + +/** + * Object for extended type of OD variable, configurable by + * @ref OD_extensionIO_init() function + */ +typedef struct { + /** Pointer to PDO flags bit-field, see @ref OD_subEntry_t, may be NULL. */ + OD_flagsPDO_t *flagsPDO; + /** Pointer to application specified IO extension, may be NULL. */ + OD_extensionIO_t *extIO; + /** Pointer to original odObject, see @ref OD_entry_t. */ + const void *odObjectOriginal; +} OD_obj_extended_t; + +#endif /* defined OD_DEFINITION */ + +/** @} */ /* CO_ODdefinition */ + + +/** @} */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* CO_OD_INTERFACE_H */ diff --git a/Makefile b/Makefile index d7892215..a3e87b39 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ SOURCES = \ $(DRV_SRC)/CO_error.c \ $(DRV_SRC)/CO_Linux_threads.c \ $(DRV_SRC)/CO_OD_storage.c \ + $(CANOPEN_SRC)/301/CO_ODinterface.c \ $(CANOPEN_SRC)/301/CO_SDOserver.c \ $(CANOPEN_SRC)/301/CO_Emergency.c \ $(CANOPEN_SRC)/301/CO_NMT_Heartbeat.c \ diff --git a/README.md b/README.md index 64b35482..e7698db0 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,16 @@ CANopenNode homepage is https://github.com/CANopenNode/CANopenNode Characteristics --------------- ### CANopen + - [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen/device-architecture/) + offers clear and flexible organisation of any variables. - [NMT](https://www.can-cia.org/can-knowledge/canopen/network-management/) slave to start, stop, reset device. Simple NMT master. - [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/) producer/consumer error control. - [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) linking - and dynamic mapping for fast exchange of process variables. + and dynamic mapping for fast exchange of process variables from Object Dictionary. - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) expedited, - segmented and block transfer for service access to all parameters. + segmented and block transfer for service access to all Object Dictionary variables. - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client. - [Emergency](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) producer/consumer. @@ -47,7 +49,7 @@ Characteristics - [Suitable for 16-bit microcontrollers and above](#device-support) - [Multithreaded, real-time](#flowchart-of-a-typical-canopennode-implementation) - [Object Dictionary editor](#object-dictionary-editor) - - Non-volatile storage. + - Non-volatile storage for Object Dictionary variables. - [Power saving possible](#power-saving) - [Bootloader possible](https://github.com/CANopenNode/CANopenNode/issues/111) (for firmware update) @@ -136,6 +138,7 @@ File structure - **301/** - CANopen application layer and communication profile. - **CO_config.h** - Configuration macros for CANopenNode. - **CO_driver.h** - Interface between CAN hardware and CANopenNode. + - **CO_ODinterface.h/.c** - CANopen Object Dictionary interface. - **CO_Emergency.h/.c** - CANopen Emergency protocol. - **CO_HBconsumer.h/.c** - CANopen Heartbeat consumer protocol. - **CO_NMT_Heartbeat.h/.c** - CANopen Network management and Heartbeat producer protocol. diff --git a/example/Makefile b/example/Makefile index b4264b7a..48e4876b 100644 --- a/example/Makefile +++ b/example/Makefile @@ -20,6 +20,7 @@ INCLUDE_DIRS = \ SOURCES = \ $(DRV_SRC)/CO_driver_blank.c \ $(DRV_SRC)/eeprom.c \ + $(CANOPEN_SRC)/301/CO_ODinterface.c \ $(CANOPEN_SRC)/301/CO_SDOserver.c \ $(CANOPEN_SRC)/301/CO_Emergency.c \ $(CANOPEN_SRC)/301/CO_NMT_Heartbeat.c \ From 1f92aee85abea77726be42b2c3c992b60606ae91 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 13 Jul 2020 15:12:40 +0200 Subject: [PATCH 100/520] SDO: fix broken block download #210 by lukegluke, same as commit in v1.3-master --- 301/CO_SDOserver.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 0667c44e..6ddeee85 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -100,24 +100,26 @@ static void CO_SDO_receive(void *object, void *msg){ /* check correct sequence number. */ if(seqno == (SDO->sequence + 1U)) { /* sequence is correct */ - uint8_t i; - SDO->sequence++; + /* check if buffer can store whole message just in case */ + if (CO_SDO_BUFFER_SIZE - SDO->bufferOffset >= 7) { + uint8_t i; - /* copy data */ - for(i=1; i<8; i++) { - SDO->ODF_arg.data[SDO->bufferOffset++] = data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer - if(SDO->bufferOffset >= CO_CONFIG_SDO_BUFFER_SIZE) { - /* buffer full, break reception */ + SDO->sequence++; + + /* copy data */ + for(i=1; i<8; i++) { + SDO->ODF_arg.data[SDO->bufferOffset++] = msg->data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer + } + + /* break reception if last segment, block ends or block sequence is too large */ + if(((CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) { SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; CO_SDO_receive_done(SDO); - break; } - } - - /* break reception if last segment, block ends or block sequence is too large */ - if(((CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) { - SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; + } else { + /* buffer is full, ignore this segment, send response without resetting sequence */ + SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2; CO_SDO_receive_done(SDO); } } From f68e9dade7137f6b1c267ffa1c96e3aca4e58b0e Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 14 Jul 2020 16:28:32 +0200 Subject: [PATCH 101/520] Fix previous commit --- 301/CO_SDOserver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 6ddeee85..cf53f01c 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -102,14 +102,14 @@ static void CO_SDO_receive(void *object, void *msg){ /* sequence is correct */ /* check if buffer can store whole message just in case */ - if (CO_SDO_BUFFER_SIZE - SDO->bufferOffset >= 7) { + if (CO_CONFIG_SDO_BUFFER_SIZE - SDO->bufferOffset >= 7) { uint8_t i; SDO->sequence++; /* copy data */ for(i=1; i<8; i++) { - SDO->ODF_arg.data[SDO->bufferOffset++] = msg->data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer + SDO->ODF_arg.data[SDO->bufferOffset++] = data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer } /* break reception if last segment, block ends or block sequence is too large */ From 7903f55ef26188b6ecc85b9461ff990a7f64de12 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 14 Jul 2020 16:33:40 +0200 Subject: [PATCH 102/520] Fixed Gateway timeout for small values (SDO read, write) #209 --- 309/CO_gateway_ascii.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index c708c1be..f88fb893 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -871,6 +871,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* indicate that gateway response didn't start yet */ gtwa->SDOdataCopyStatus = false; /* continue with state machine */ + timeDifference_us = 0; gtwa->state = CO_GTWA_ST_READ; } @@ -954,6 +955,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* continue with state machine */ gtwa->stateTimeoutTmr = 0; + timeDifference_us = 0; gtwa->state = CO_GTWA_ST_WRITE; } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ From 03df5f65b803e1c9a95736afb9043a46f0ef7c92 Mon Sep 17 00:00:00 2001 From: Norcio <68592418+Norcio@users.noreply.github.com> Date: Wed, 22 Jul 2020 07:31:56 +0200 Subject: [PATCH 103/520] fix for missing int cast which cause compilation warning/error when ctype,__cplusplus and esp32 is used (#212) error: array subscript has type 'char' [-Werror=char-subscripts] --- 301/CO_fifo.c | 22 +++++++++++----------- 309/CO_gateway_ascii.c | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index c4d7721b..11038901 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -391,7 +391,7 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo) { } break; } - else if (isgraph(c) != 0) { + else if (isgraph((int)c) != 0) { break; } if (++fifo->readPtr == fifo->bufSize) { @@ -428,7 +428,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, do { switch (step) { case 0: /* skip leading empty characters, stop on delimiter */ - if (isgraph(*c) != 0) { + if (isgraph((int)*c) != 0) { if (*c == DELIM_COMMENT) { delimCommentFound = true; } else { @@ -441,7 +441,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, } break; case 1: /* search for end of the token */ - if (isgraph(*c) != 0) { + if (isgraph((int)*c) != 0) { if (*c == DELIM_COMMENT) { delimCommentFound = true; } else if (tokenSize < count) { @@ -456,7 +456,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, } break; case 2: /* skip trailing empty characters */ - if (isgraph(*c) != 0) { + if (isgraph((int)*c) != 0) { if (*c == DELIM_COMMENT) { delimCommentFound = true; } else { @@ -1003,7 +1003,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (dest->started == false) { /* search for first of two hex digits in token */ - if (isxdigit(c) != 0) { + if (isxdigit((int)c) != 0) { /* first hex digit is known */ dest->aux = c; dest->started = true; @@ -1023,7 +1023,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } finished = true; } - else if (isgraph(c) != 0) { + else if (isgraph((int)c) != 0) { /* printable character, not hex digit, error */ st |= CO_fifo_st_errTok; } @@ -1031,7 +1031,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } else { /* one hex digit is known, what is next */ - if (isxdigit(c) != 0) { + if (isxdigit((int)c) != 0) { /* two hex digits are known */ char s[3]; int32_t num; @@ -1041,7 +1041,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { CO_fifo_putc(dest, (char) num); destSpace--; } - else if (isgraph(c) != 0 && c != DELIM_COMMENT) { + else if (isgraph((int)c) != 0 && c != DELIM_COMMENT) { /* printable character, not hex digit, error */ st |= CO_fifo_st_errTok; } @@ -1112,7 +1112,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { switch (dest->aux) { case 0: /* beginning of the string, first write into dest */ - if (isgraph(c) == 0 || c == DELIM_COMMENT) { + if (isgraph((int)c) == 0 || c == DELIM_COMMENT) { if (CO_fifo_trimSpaces(src)) { /* newline found without string, this is an error */ st |= CO_fifo_st_errTok; @@ -1138,7 +1138,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { * double quote (with two double quotes) */ dest->aux += 2; } - else if (isgraph(c) == 0 && dest->aux == 2) { + else if (isgraph((int)c) == 0 && dest->aux == 2) { /* end of single word string */ if (c == DELIM_COMMAND) { st |= CO_fifo_st_closed; @@ -1174,7 +1174,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { st |= CO_fifo_st_errTok; } else { - if (isgraph(c) == 0) { + if (isgraph((int)c) == 0) { /* string finished */ if (c == DELIM_COMMAND) { st |= CO_fifo_st_closed; diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index f88fb893..2fc7b600 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -564,7 +564,7 @@ static inline void convertToLower(char *token, size_t maxCount) { if (*c == 0) { break; } else { - *c = tolower(*c); + *c = tolower((int)*c); } c++; } @@ -657,7 +657,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* empty token, break on error */ err = true; break; - } else if (isdigit(tok[0]) == 0) { + } else if (isdigit((int)tok[0]) == 0) { /* found */ break; } else if (closed != 0) { From 756c76d08a86ceea72486f226d0bcb20ec920b96 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 23 Jul 2020 07:34:28 +0200 Subject: [PATCH 104/520] Added information about XML device description --- 301/CO_ODinterface.c | 22 ++-- 301/CO_ODinterface.h | 282 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 292 insertions(+), 12 deletions(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 734193f2..cd55bdaa 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -198,8 +198,8 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, if (odBasicType == ODT_VAR) { const OD_obj_var_t *odo = (const OD_obj_var_t *)odObject; - subEntry->lowLimit = 0; - subEntry->highLimit = -1; + subEntry->lowLimit = 1; + subEntry->highLimit = 0; subEntry->attribute = odo->attribute; if (!io_configured) stream->dataObject = odo->data; stream->dataLength = odo->dataLength; @@ -216,8 +216,8 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, else if (odBasicType == ODT_ARR) { const OD_obj_array_t *odo = (const OD_obj_array_t *)odObject; - subEntry->lowLimit = 0; - subEntry->highLimit = -1; + subEntry->lowLimit = 1; + subEntry->highLimit = 0; if (subIndex == 0) { subEntry->attribute = odo->attribute0; if (!io_configured) stream->dataObject = odo->data0; @@ -240,8 +240,8 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, (const OD_obj_arrayLimAttr_t *)odObject; if (subIndex == 0) { - subEntry->lowLimit = 0; - subEntry->highLimit = -1; + subEntry->lowLimit = 1; + subEntry->highLimit = 0; subEntry->attribute = odo->attribute0; if (!io_configured) stream->dataObject = odo->data0; stream->dataLength = 1; @@ -266,8 +266,8 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)odObject; const OD_obj_var_t *odo = &odo_rec[subIndex]; - subEntry->lowLimit = 0; - subEntry->highLimit = -1; + subEntry->lowLimit = 1; + subEntry->highLimit = 0; subEntry->attribute = odo->attribute; if (!io_configured) stream->dataObject = odo->data; stream->dataLength = odo->dataLength; @@ -628,12 +628,12 @@ ODR_t OD_set_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t val) { ODR_t OD_set_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); - int32_t lowLimit = subEntry.lowLimit; - int32_t highLimit = subEntry.highLimit; + uint32_t lowLimit = (uint32_t)subEntry.lowLimit; + uint32_t highLimit = (uint32_t)subEntry.highLimit; if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK && lowLimit <= highLimit) { - if (val > 0x7FFF || val > highLimit) ret = ODR_VALUE_HIGH; + if (val > highLimit) ret = ODR_VALUE_HIGH; else if (val < lowLimit) ret = ODR_VALUE_LOW; } if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index d0d71282..0552c917 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -286,6 +286,286 @@ const OD_t ODxyz = { * @} */ +/** + * @defgroup CO_ODinterface_XDD XML device description + * @{ + * CANopen device description - XML schema definition - is specified by CiA 311 + * standard. + * + * CiA 311 complies with standard ISO 15745-1:2005/Amd1 (Industrial automation + * systems and integration - Open systems application integration framework). + * + * CANopen device description is basically a XML file with all the information + * about CANopen device. The larges part of the file is a list of all object + * dictionary variables with all necessary properties and documentation. This + * file can be edited with OD editor application and can be used as data source, + * from which Object dictionary for CANopenNode is generated. Furthermore, this + * file can be used with CANopen configuration tool, which interacts with + * CANopen devices on running CANopen network. + * + * XML schema definitions are available at: http://www.canopen.org/xml/1.1 + * One of the tools for viewing XML schemas is "xsddiagram" + * (https://github.com/dgis/xsddiagram). + * + * CANopen specifies also another type of files for CANopen device description. + * These are EDS files, which are in INI format. It is possible to convert + * between those two formats. But CANopenNode uses XML format. + * + * The device description file has "XDD" file extension. The name of this file + * shall contain the vendor-ID of the CANopen device in the form of 8 + * hexadecimal digits in any position of the name and separated with + * underscores. For example "name1_12345678_name2.XDD". + * + * CANopenNode includes multiple profile definition files, one for each CANopen + * object. Those files have "XPD" extension. They are in the same XML format as + * XDD files. The XML editor tool can use XPD files to insert prepared data + * into device description file (XDD), which is being edited. + * + * ### XDD, XPD file example + * @code{.xml} + + + + ... + + ... + ... + + ... + + + + ... + + + + + + ... + + + + + + + + ... + + + + + ... + + + + + + ... + + + + + + ... + + + + + + ... + + + + + + ... + + + + + + + + ... + + + ... + + + + + + + + + + + ... + + + + + + + + + + + + + + + ... + + + + * @endcode + * + * ### Parameter description + * Above XML file example shows necessary data for OD interface used by + * CANopenNode and other parameters required by the standard. Standard specifies + * many other parameters, which are not used by CANopenNode for simplicity. + * + * XML file is divided into two parts: + * 1. "ProfileBody_Device_CANopen" - more standardized information + * 2. "ProfileBody_CommunicationNetwork_CANopen" - communication related info + * + * Most important part of the XML file is definition of each OD object. All + * OD objects are listed in "CANopenObjectList", which resides in the second + * part of the XML file. Each "CANopenObject" and "CANopenSubObject" of the list + * contains a link to parameter ("uniqueIDRef"), which resides in the first + * part of the XML file. So data for each OD object is split between two parts + * of the XML file. + * + * #### <CANopenObject> + * * "index" (required) - Object dictionary index + * * "name" (required) - Name of the parameter + * * "objectType" (required) - "7"=VAR, "8"=ARRAY, "9"=RECORD + * * "subNumber" (required if "objectType" is "8" or "9") + * * "PDOmapping" (optional if "objectType" is "7", default is "no"): + * * "no" - mapping not allowed + * * "default" - not used, same as "optional" + * * "optional" - mapping allowed to TPDO or RPDO + * * "TPDO" - mapping allowed to TPDO + * * "RPDO" mapping allowed to RPDO + * * "uniqueIDRef" (required or see below) - Reference to <parameter> + * + * #### <CANopenSubObject> + * * "subIndex" (required) - Object dictionary sub-index + * * "name" (required) - Name of the parameter + * * "objectType" (required, always "7") + * * "PDOmapping" (optional, same as above, default is "no") + * * "uniqueIDRef" (required or see below) - Reference to <parameter> + * + * #### uniqueIDRef + * This is required attribute from "CANopenObject" and "CANopenSubObject". It + * contains reference to <parameter> in "ProfileBody_Device_CANopen" + * section of the XML file. There are additional necessary properties. + * + * If "uniqueIDRef" attribute is not specified and "objectType" is 7(VAR), then + * "CANopenObject" or "CANopenSubObject" must contain additional attributes: + * * "dataType" (required for VAR) - CANopen basic data type, see below + * * "accessType" (required for VAR) - "ro", "wo", "rw" or "const" + * * "lowLimit" (optional) - 32 bit integer value, signed or unsigned + * * "highLimit" (optional) - 32 bit integer value, signed or unsigned + * * "defaultValue" (optional) - Default value for the variable. + * + * #### <parameter> + * * "uniqueID" (required) + * * "access" (required for VAR) - can be one of: + * * "const" - same as "read" + * * "read" - only read access with SDO or PDO + * * "write" - only write access with SDO or PDO + * * "readWrite" - read or write access with SDO or PDO + * * "readWriteInput" - same as "readWrite" + * * "readWriteOutput" - same as "readWrite" + * * "noAccess" - object will be in Object Dictionary, but no access. + * * <label lang="en"> (required) + * * <description lang="en"> (required) + * * <UINT and similar/> (required) - Basic or complex data type. Basic + * data type (for VAR) is specified in IEC 61131-3 (see below). If data type + * is complex (ARRAY or RECORD), then <dataTypeIDRef> must be + * specified and entry must be added in the <dataTypeList>. Such + * definition of complex data types is required by the standard, but it is + * not required by CANopenNode. + * * <defaultValue> (optional for VAR) - Default value for the variable. + * * limits (optional for VAR) - 32 bit integer values, signed or unsigned: +@code{.xml} + + + + +@endcode + * + * Additional, optional, CANopenNode specific properties, which can be used + * inside parameters describing <CANopenObject>s: + * * <property name="CO_storageGroup" value="..."> - group into which + * the C variable will belong. Valid value is from 0x00 (default) to 0x7F. + * * <property name="CO_extensionIO" value="..."> - Valid value is + * "false" (default) or "true", if IO extension is enabled. + * * <property name="CO_flagsPDO" value="..."> - Valid value is + * "false" (default) or "true", if PDO flags are enabled. + * + * Additional, optional, CANopenNode specific property, which can be used + * inside parameters describing VAR: + * * <property name="CO_accessSRDO" value="..."> - Valid values are: + * "tx", "rx", "trx", "no"(default). + * + * Additional, optional, CANopenNode specific property, which can be used + * inside parameters describing string or domain (VAR): + * * <property name="CO_byteLength" value="..."> - Length of the + * variable in bytes. If this is not specified, then length is calculated + * from <defaultValue>. + * + * #### CANopen basic data types + * | CANopenNode | IEC 61131-3 | CANopen | dataType | + * | ------------ | ------------ | --------------- | -------- | + * | bool_t | BOOL | BOOLEAN | 0x01 | + * | int8_t | CHAR, SINT | INTEGER8 | 0x02 | + * | int16_t | INT | INTEGER16 | 0x03 | + * | int32_t | DINT | INTEGER32 | 0x04 | + * | int64_t | LINT | INTEGER64 | 0x15 | + * | uint8_t | BYTE, USINT | UNSIGNED8 | 0x05 | + * | uint16_t | WORD, UINT | UNSIGNED16 | 0x06 | + * | uint32_t | DWORD, UDINT | UNSIGNED32 | 0x07 | + * | uint64_t | LWORD, ULINT | UNSIGNED64 | 0x1B | + * | float32_t | REAL | REAL32 | 0x08 | + * | float64_t | LREAL | REAL64 | 0x11 | + * | bytestring_t | STRING | VISIBLE_STRING | 0x09 | + * | bytestring_t | | OCTET_STRING | 0x0A | + * | bytestring_t | WSTRING | UNICODE_STRING | 0x0B | + * | bytestring_t | - | TIME_OF_DAY | 0x0C | + * | bytestring_t | - | TIME_DIFFERENCE | 0x0D | + * | bytestring_t | - | DOMAIN | 0x0F | + * | bytestring_t | BITSTRING | - | - | + * + + * #### <parameterGroupList> + * This is optional element and is not required by standard, nor by CANopenNode. + * This can be very useful for documentation, which can be organised into + * multiple chapters with multiple levels. CANopen objects can then be organised + * in any way, not only by index. + * + * #### Other elements + * Other elements listed in the above XML example are required by the standard + * and does not influence the CANopenNode object dictionary generator. + * @} */ + + #ifndef OD_size_t /** Variable of type OD_size_t contains data length in bytes of OD variable */ #define OD_size_t uint32_t @@ -646,7 +926,7 @@ bool_t OD_extensionIO_init(const OD_entry_t *entry, * OD objects and copies them to the original storageGroup. * * @param od Object Dictionary - * @param storageGroup Group of data to enable. + * @param storageGroup Group of data to update. */ void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup); From 1410a20e950034194dd668beea04279115647fdd Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 23 Jul 2020 13:37:50 +0200 Subject: [PATCH 105/520] Replace CO_memcpySwap4() --- 301/CO_Emergency.c | 29 ++++++++++++++++------------- 301/CO_SDOclient.c | 39 ++++++++++++++++++++------------------- 305/CO_LSSslave.c | 42 +++++++++++++++++++++++------------------- README.md | 4 ++-- extra/CO_trace.c | 7 +++++-- 5 files changed, 66 insertions(+), 55 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 7c1b44ce..e1ed1e10 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -52,13 +52,13 @@ static void CO_EM_receive(void *object, void *msg) { uint16_t errorCode; uint32_t infoCode; - CO_memcpySwap2(&errorCode, &data[0]); - CO_memcpySwap4(&infoCode, &data[4]); + memcpy(&errorCode, &data[0], sizeof(errorCode)); + memcpy(&infoCode, &data[4], sizeof(infoCode)); em->pFunctSignalRx(ident, - errorCode, - data[2], - data[3], - infoCode); + CO_SWAP_16(errorCode), + data[2], + data[3], + CO_SWAP_32(infoCode)); } } } @@ -384,13 +384,13 @@ void CO_EM_process( if (em->pFunctSignalRx != NULL) { uint16_t errorCode; uint32_t infoCode; - CO_memcpySwap2(&errorCode, &em->bufReadPtr[0]); - CO_memcpySwap4(&infoCode, &em->bufReadPtr[4]); + memcpy(&errorCode, &em->bufReadPtr[0], sizeof(errorCode)); + memcpy(&infoCode, &em->bufReadPtr[4], sizeof(infoCode)); em->pFunctSignalRx(0, - errorCode, + CO_SWAP_16(errorCode), em->bufReadPtr[2], em->bufReadPtr[3], - infoCode); + CO_SWAP_32(infoCode)); } #endif @@ -482,12 +482,14 @@ void CO_errorReport(CO_EM_t *em, const uint8_t errorBit, const uint16_t errorCod } else{ uint8_t bufCopy[8]; + uint16_t errorCodeSw = CO_SWAP_16(errorCode); + uint32_t infoCodeSw = CO_SWAP_32(infoCode); /* prepare data for emergency message */ - CO_memcpySwap2(&bufCopy[0], &errorCode); + memcpy(&bufCopy[0], &errorCodeSw, sizeof(errorCodeSw)); bufCopy[2] = 0; /* error register will be set later */ bufCopy[3] = errorBit; - CO_memcpySwap4(&bufCopy[4], &infoCode); + memcpy(&bufCopy[4], &infoCodeSw, sizeof(infoCodeSw)); /* copy data to the buffer, increment writePtr and verify buffer full */ CO_LOCK_EMCY(); @@ -542,13 +544,14 @@ void CO_errorReset(CO_EM_t *em, const uint8_t errorBit, const uint32_t infoCode) } else{ uint8_t bufCopy[8]; + uint32_t infoCodeSw = CO_SWAP_32(infoCode); /* prepare data for emergency message */ bufCopy[0] = 0; bufCopy[1] = 0; bufCopy[2] = 0; /* error register will be set later */ bufCopy[3] = errorBit; - CO_memcpySwap4(&bufCopy[4], &infoCode); + memcpy(&bufCopy[4], &infoCodeSw, sizeof(infoCodeSw)); /* copy data to the buffer, increment writePtr and verify buffer full */ CO_LOCK_EMCY(); diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 50a0558d..7896f4e7 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -440,8 +440,8 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80) { uint32_t code; - CO_memcpySwap4(&code , &SDO_C->CANrxData[4]); - abortCode = (CO_SDO_abortCode_t)code; + memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); + abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDOcli_endedWithServerAbort; } @@ -670,9 +670,9 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED /* segmented transfer, indicate data size */ if (SDO_C->sizeInd > 0) { - uint32_t size = SDO_C->sizeInd; + uint32_t size = CO_SWAP_32(SDO_C->sizeInd); SDO_C->CANtxBuff->data[0] |= 0x01; - CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &size); + memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); } #else SDO_C->state = CO_SDO_ST_IDLE; @@ -736,9 +736,9 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* indicate data size */ if (SDO_C->sizeInd > 0) { - uint32_t size = SDO_C->sizeInd; + uint32_t size = CO_SWAP_32(SDO_C->sizeInd); SDO_C->CANtxBuff->data[0] |= 0x02; - CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &size); + memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); } /* reset timeout timer and send message */ @@ -815,14 +815,14 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (ret == CO_SDOcli_waitingServerResponse) { if (SDO_C->state == CO_SDO_ST_ABORT) { - uint32_t code = (uint32_t)abortCode; + uint32_t code = CO_SWAP_32((uint32_t)abortCode); /* Send SDO abort message */ SDO_C->CANtxBuff->data[0] = 0x80; SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &code); + memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDOcli_endedWithClientAbort; @@ -966,8 +966,8 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80) { uint32_t code; - CO_memcpySwap4(&code , &SDO_C->CANrxData[4]); - abortCode = (CO_SDO_abortCode_t)code; + memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); + abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDOcli_endedWithServerAbort; } @@ -1006,8 +1006,8 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* segmented transfer, is size indicated? */ if (SDO_C->CANrxData[0] & 0x01) { uint32_t size; - CO_memcpySwap4(&size, &SDO_C->CANrxData[4]); - SDO_C->sizeInd = size; + memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + SDO_C->sizeInd = CO_SWAP_32(size); } SDO_C->toggle = 0x00; SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; @@ -1100,8 +1100,8 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } if (SDO_C->CANrxData[0] & 0x02) { uint32_t size; - CO_memcpySwap4(&size, &SDO_C->CANrxData[4]); - SDO_C->sizeInd = size; + memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + SDO_C->sizeInd = CO_SWAP_32(size); } /* verify index and subindex */ @@ -1149,8 +1149,8 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* segmented transfer, is size indicated? */ if (SDO_C->CANrxData[0] & 0x01) { uint32_t size; - CO_memcpySwap4(&size, &SDO_C->CANrxData[4]); - SDO_C->sizeInd = size; + memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + SDO_C->sizeInd = CO_SWAP_32(size); } SDO_C->toggle = 0x00; SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; @@ -1192,7 +1192,8 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* verify CRC */ if (SDO_C->block_crcEnabled) { uint16_t crcServer; - CO_memcpySwap2(&crcServer, &SDO_C->CANrxData[1]); + crcServer = ((uint16_t) SDO_C->CANrxData[2]) << 8; + crcServer |= SDO_C->CANrxData[1]; if (crcServer != SDO_C->block_crc) { abortCode = CO_SDO_AB_CRC; SDO_C->state = CO_SDO_ST_ABORT; @@ -1425,14 +1426,14 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, if (ret == CO_SDOcli_waitingServerResponse) { if (SDO_C->state == CO_SDO_ST_ABORT) { - uint32_t code = (uint32_t)abortCode; + uint32_t code = CO_SWAP_32((uint32_t)abortCode); /* Send SDO abort message */ SDO_C->CANtxBuff->data[0] = 0x80; SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &code); + memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDOcli_endedWithClientAbort; diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 7acb3704..01d251ea 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -74,25 +74,26 @@ static void CO_LSSslave_receive(void *object, void *msg) } } else if(LSSslave->lssState == CO_LSS_STATE_WAITING) { + uint32_t valSw; switch (cs) { case CO_LSS_SWITCH_STATE_SEL_VENDOR: { - CO_memcpySwap4(&LSSslave->lssSelect.identity.vendorID, - &data[1]); + memcpy(&valSw, &data[1], sizeof(valSw)); + LSSslave->lssSelect.identity.vendorID = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_PRODUCT: { - CO_memcpySwap4(&LSSslave->lssSelect.identity.productCode, - &data[1]); + memcpy(&valSw, &data[1], sizeof(valSw)); + LSSslave->lssSelect.identity.productCode = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_REV: { - CO_memcpySwap4(&LSSslave->lssSelect.identity.revisionNumber, - &data[1]); + memcpy(&valSw, &data[1], sizeof(valSw)); + LSSslave->lssSelect.identity.revisionNumber = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_SERIAL: { - CO_memcpySwap4(&LSSslave->lssSelect.identity.serialNumber, - &data[1]); + memcpy(&valSw, &data[1], sizeof(valSw)); + LSSslave->lssSelect.identity.serialNumber = CO_SWAP_32(valSw); if (CO_LSS_ADDRESS_EQUAL(LSSslave->lssAddress, LSSslave->lssSelect) @@ -111,6 +112,7 @@ static void CO_LSSslave_receive(void *object, void *msg) uint8_t bitCheck = data[5]; uint8_t lssSub = data[6]; uint8_t lssNext = data[7]; + uint32_t valSw; uint32_t idNumber; bool_t ack; @@ -121,7 +123,8 @@ static void CO_LSSslave_receive(void *object, void *msg) break; } - CO_memcpySwap4(&idNumber, &data[1]); + memcpy(&valSw, &data[1], sizeof(valSw)); + idNumber = CO_SWAP_32(valSw); ack = false; if (bitCheck == CO_LSS_FASTSCAN_CONFIRM) { @@ -317,6 +320,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { uint8_t tableSelector; uint8_t tableIndex; bool_t CANsend = false; + uint32_t valSw; memset(&LSSslave->TXbuff->data[0], 0, sizeof(LSSslave->TXbuff->data)); @@ -394,8 +398,8 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { /* notify application */ if (LSSslave->pFunctLSSactivateBitRate != NULL) { - uint16_t delay; - CO_memcpySwap2(&delay, &LSSslave->CANdata[1]); + uint16_t delay = ((uint16_t) LSSslave->CANdata[2]) << 8; + delay |= LSSslave->CANdata[1]; LSSslave->pFunctLSSactivateBitRate( LSSslave->functLSSactivateBitRateObject, delay); } @@ -429,29 +433,29 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { } case CO_LSS_INQUIRE_VENDOR: { LSSslave->TXbuff->data[0] = LSSslave->service; - CO_memcpySwap4(&LSSslave->TXbuff->data[1], - &LSSslave->lssAddress.identity.vendorID); + valSw = CO_SWAP_32(LSSslave->lssAddress.identity.vendorID); + memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_PRODUCT: { LSSslave->TXbuff->data[0] = LSSslave->service; - CO_memcpySwap4(&LSSslave->TXbuff->data[1], - &LSSslave->lssAddress.identity.productCode); + valSw = CO_SWAP_32(LSSslave->lssAddress.identity.productCode); + memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_REV: { LSSslave->TXbuff->data[0] = LSSslave->service; - CO_memcpySwap4(&LSSslave->TXbuff->data[1], - &LSSslave->lssAddress.identity.revisionNumber); + valSw = CO_SWAP_32(LSSslave->lssAddress.identity.revisionNumber); + memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_SERIAL: { LSSslave->TXbuff->data[0] = LSSslave->service; - CO_memcpySwap4(&LSSslave->TXbuff->data[1], - &LSSslave->lssAddress.identity.serialNumber); + valSw = CO_SWAP_32(LSSslave->lssAddress.identity.serialNumber); + memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); CANsend = true; break; } diff --git a/README.md b/README.md index e7698db0..f3ebba58 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ CANopenNode is free and open source CANopen protocol stack. CANopen is the internationally standardized (EN 50325-4) ([CiA301](http://can-cia.org/standardization/technical-documents)) -CAN-based higher-layer protocol for embedded control system. For more -information on CANopen see http://www.can-cia.org/ +higher-layer protocol for embedded control system built on top of CAN. +For more information on CANopen see http://www.can-cia.org/ CANopenNode is written in ANSI C in object-oriented way. It runs on different microcontrollers, as standalone application or with RTOS. diff --git a/extra/CO_trace.c b/extra/CO_trace.c index 80ce5531..2ef389ff 100644 --- a/extra/CO_trace.c +++ b/extra/CO_trace.c @@ -25,6 +25,7 @@ #include "extra/CO_trace.h" #include +#include #ifndef CO_OWN_INTTYPES #include /* for PRIu32("u" or "lu") and PRId32("d" or "ld") */ #endif @@ -47,8 +48,10 @@ static uint32_t printPointCsvUnsigned(char *s, uint32_t size, uint32_t timeStamp } static uint32_t printPointBinary(char *s, uint32_t size, uint32_t timeStamp, int32_t value) { if(size < 8) return 0; - CO_memcpySwap4(s, &timeStamp); - CO_memcpySwap4(s+4, &value); + uint32_t timeStampSw = CO_SWAP_32(timeStamp); + int32_t valueSw = CO_SWAP_32(value); + memcpy(s, &timeStampSw, sizeof(timeStampSw)); + memcpy(s+4, &valueSw, sizeof(valueSw)); return 8; } static uint32_t printPointSvgStart(char *s, uint32_t size, uint32_t timeStamp, int32_t value) { From 748086a751218c6e41c854824464a6e106405292 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 24 Jul 2020 10:10:05 +0200 Subject: [PATCH 106/520] Move enumerator CO_SDOclient_return_t to CO_SDO_return_t (from CO_SDOclient.h into CO_SDOserver.h) --- 301/CO_ODinterface.h | 24 ++++--- 301/CO_SDOclient.c | 148 ++++++++++++++++++++--------------------- 301/CO_SDOclient.h | 92 +++++++++---------------- 301/CO_SDOserver.h | 27 ++++++++ 309/CO_gateway_ascii.c | 28 ++++---- 5 files changed, 161 insertions(+), 158 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 0552c917..81766697 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -512,24 +512,29 @@ const OD_t ODxyz = { @endcode * * Additional, optional, CANopenNode specific properties, which can be used - * inside parameters describing <CANopenObject>s: + * inside parameters describing <CANopenObject>: * * <property name="CO_storageGroup" value="..."> - group into which - * the C variable will belong. Valid value is from 0x00 (default) to 0x7F. + * the C variable will belong. Variables from specific storage group may + * then be stored into non-volatile memory, automatically or by SDO command. + * Valid value is from 0x00 (default - not stored) to 0x7F. * * <property name="CO_extensionIO" value="..."> - Valid value is * "false" (default) or "true", if IO extension is enabled. * * <property name="CO_flagsPDO" value="..."> - Valid value is * "false" (default) or "true", if PDO flags are enabled. + * * <property name="CO_countLabel" value="..."> - Valid value is + * any string without spaces. OD exporter will generate a macro for each + * different string. For example, if four OD objects have "CO_countLabel" + * set to "TPDO", then macro "#define OD_NO_TPDO 4" will be generated by + * OD exporter. * * Additional, optional, CANopenNode specific property, which can be used - * inside parameters describing VAR: + * inside parameters describing "VAR": * * <property name="CO_accessSRDO" value="..."> - Valid values are: * "tx", "rx", "trx", "no"(default). - * - * Additional, optional, CANopenNode specific property, which can be used - * inside parameters describing string or domain (VAR): * * <property name="CO_byteLength" value="..."> - Length of the - * variable in bytes. If this is not specified, then length is calculated - * from <defaultValue>. + * variable in bytes, optionaly used by string or domain. If CO_byteLength + * is not specified for string, then length is calculated from string + * <defaultValue>. * * #### CANopen basic data types * | CANopenNode | IEC 61131-3 | CANopen | dataType | @@ -546,14 +551,13 @@ const OD_t ODxyz = { * | float32_t | REAL | REAL32 | 0x08 | * | float64_t | LREAL | REAL64 | 0x11 | * | bytestring_t | STRING | VISIBLE_STRING | 0x09 | - * | bytestring_t | | OCTET_STRING | 0x0A | + * | bytestring_t | - | OCTET_STRING | 0x0A | * | bytestring_t | WSTRING | UNICODE_STRING | 0x0B | * | bytestring_t | - | TIME_OF_DAY | 0x0C | * | bytestring_t | - | TIME_DIFFERENCE | 0x0D | * | bytestring_t | - | DOMAIN | 0x0F | * | bytestring_t | BITSTRING | - | - | * - * #### <parameterGroupList> * This is optional element and is not required by standard, nor by CANopenNode. * This can be very useful for documentation, which can be organised into diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 7896f4e7..14d9a26a 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -211,10 +211,10 @@ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, /******************************************************************************/ -CO_SDOclient_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient, - uint8_t nodeIDOfTheSDOServer) +CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, + uint32_t COB_IDClientToServer, + uint32_t COB_IDServerToClient, + uint8_t nodeIDOfTheSDOServer) { uint32_t idCtoS, idStoC; uint8_t idNode; @@ -225,7 +225,7 @@ CO_SDOclient_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, || (COB_IDServerToClient & 0x7FFFF800L) != 0 || nodeIDOfTheSDOServer > 127 ) { - return CO_SDOcli_wrongArguments; + return CO_SDO_RT_wrongArguments; } /* Configure object variables */ @@ -284,27 +284,27 @@ CO_SDOclient_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, SDO_C->COB_IDServerToClientPrev = idStoC; if (ret != CO_ERROR_NO || SDO_C->CANtxBuff == NULL) { - return CO_SDOcli_wrongArguments; + return CO_SDO_RT_wrongArguments; } } - return CO_SDOcli_ok_communicationEnd; + return CO_SDO_RT_ok_communicationEnd; } /****************************************************************************** * DOWNLOAD * ******************************************************************************/ -CO_SDOclient_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - size_t sizeIndicated, - uint16_t SDOtimeoutTime_ms, - bool_t blockEnable) +CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, + uint16_t index, + uint8_t subIndex, + size_t sizeIndicated, + uint16_t SDOtimeoutTime_ms, + bool_t blockEnable) { /* verify parameters */ if (SDO_C == NULL) { - return CO_SDOcli_wrongArguments; + return CO_SDO_RT_wrongArguments; } /* save parameters */ @@ -341,7 +341,7 @@ CO_SDOclient_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, CO_FLAG_CLEAR(SDO_C->CANrxNew); - return CO_SDOcli_ok_communicationEnd; + return CO_SDO_RT_ok_communicationEnd; } @@ -375,24 +375,24 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, /******************************************************************************/ -CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - bool_t abort, - CO_SDO_abortCode_t *SDOabortCode, - size_t *sizeTransferred, - uint32_t *timerNext_us) +CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, + uint32_t timeDifference_us, + bool_t abort, + CO_SDO_abortCode_t *SDOabortCode, + size_t *sizeTransferred, + uint32_t *timerNext_us) { (void)timerNext_us; /* may be unused */ - CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse; + CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; if (SDO_C == NULL) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - ret = CO_SDOcli_wrongArguments; + ret = CO_SDO_RT_wrongArguments; } else if (SDO_C->state == CO_SDO_ST_IDLE) { - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } else if (abort) { abortCode = @@ -404,7 +404,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else if (SDO_C->state == CO_SDO_ST_LOCAL_TRANSFER) { if (SDO_C->SDO->state != CO_SDO_ST_IDLE) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - ret = CO_SDOcli_endedWithClientAbort; + ret = CO_SDO_RT_endedWithClientAbort; } else { /* Max data size is limited to fifo size (for now). */ @@ -412,7 +412,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->sizeInd > 0 && SDO_C->sizeInd != count) { abortCode = CO_SDO_AB_TYPE_MISMATCH; - ret = CO_SDOcli_endedWithClientAbort; + ret = CO_SDO_RT_endedWithClientAbort; } else { /* init ODF_arg */ @@ -425,10 +425,10 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } if (abortCode == CO_SDO_AB_NONE) { SDO_C->sizeTran = count; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } else { - ret = CO_SDOcli_endedWithServerAbort; + ret = CO_SDO_RT_endedWithServerAbort; } } } @@ -443,7 +443,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_endedWithServerAbort; + ret = CO_SDO_RT_endedWithServerAbort; } else switch (SDO_C->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { @@ -464,7 +464,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->finished) { /* expedited transfer */ SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } else { /* segmented transfer - prepare the first segment */ @@ -474,7 +474,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, #else /* expedited transfer */ SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; #endif } else { @@ -499,7 +499,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* is end of transfer? */ if (SDO_C->finished) { SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } else { SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; @@ -582,7 +582,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->CANrxData[0] == 0xA1) { /* SDO block download successfully transferred */ SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } else { abortCode = CO_SDO_AB_CMD; @@ -604,7 +604,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* Timeout timers *********************************************************/ - if (ret == CO_SDOcli_waitingServerResponse) { + if (ret == CO_SDO_RT_waitingResponse) { if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { SDO_C->timeoutTimer += timeDifference_us; } @@ -622,12 +622,12 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } #endif if (SDO_C->CANtxBuff->bufferFull) { - ret = CO_SDOcli_transmittBufferFull; + ret = CO_SDO_RT_transmittBufferFull; } } /* Transmit CAN data ******************************************************/ - if (ret == CO_SDOcli_waitingServerResponse) { + if (ret == CO_SDO_RT_waitingResponse) { size_t count; memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); @@ -653,7 +653,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, ) { SDO_C->state = CO_SDO_ST_IDLE; abortCode = CO_SDO_AB_TYPE_MISMATCH; - ret = CO_SDOcli_endedWithClientAbort; + ret = CO_SDO_RT_endedWithClientAbort; break; } if (SDO_C->sizeInd > 0) { @@ -677,7 +677,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, #else SDO_C->state = CO_SDO_ST_IDLE; abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; - ret = CO_SDOcli_endedWithClientAbort; + ret = CO_SDO_RT_endedWithClientAbort; break; #endif } @@ -813,7 +813,7 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } } - if (ret == CO_SDOcli_waitingServerResponse) { + if (ret == CO_SDO_RT_waitingResponse) { if (SDO_C->state == CO_SDO_ST_ABORT) { uint32_t code = CO_SWAP_32((uint32_t)abortCode); /* Send SDO abort message */ @@ -825,11 +825,11 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_endedWithClientAbort; + ret = CO_SDO_RT_endedWithClientAbort; } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { - ret = CO_SDOcli_blockDownldInProgress; + ret = CO_SDO_RT_blockDownldInProgress; } #endif } @@ -848,15 +848,15 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /****************************************************************************** * UPLOAD * ******************************************************************************/ -CO_SDOclient_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - uint16_t SDOtimeoutTime_ms, - bool_t blockEnable) +CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, + uint16_t index, + uint8_t subIndex, + uint16_t SDOtimeoutTime_ms, + bool_t blockEnable) { /* verify parameters */ if (SDO_C == NULL) { - return CO_SDOcli_wrongArguments; + return CO_SDO_RT_wrongArguments; } /* save parameters */ @@ -894,36 +894,36 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, CO_FLAG_CLEAR(SDO_C->CANrxNew); - return CO_SDOcli_ok_communicationEnd; + return CO_SDO_RT_ok_communicationEnd; } /******************************************************************************/ -CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - CO_SDO_abortCode_t *SDOabortCode, - size_t *sizeIndicated, - size_t *sizeTransferred, - uint32_t *timerNext_us) +CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, + uint32_t timeDifference_us, + CO_SDO_abortCode_t *SDOabortCode, + size_t *sizeIndicated, + size_t *sizeTransferred, + uint32_t *timerNext_us) { (void)timerNext_us; /* may be unused */ - CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse; + CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; if (SDO_C == NULL) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - ret = CO_SDOcli_wrongArguments; + ret = CO_SDO_RT_wrongArguments; } else if (SDO_C->state == CO_SDO_ST_IDLE) { - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ else if (SDO_C->state == CO_SDO_ST_LOCAL_TRANSFER) { if (SDO_C->SDO->state != 0) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - ret = CO_SDOcli_endedWithClientAbort; + ret = CO_SDO_RT_endedWithClientAbort; } else { /* Max data size is limited to fifo size (for now). */ @@ -945,17 +945,17 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* is SDO buffer too small */ if (SDO_C->SDO->ODF_arg.lastSegment == 0) { abortCode = CO_SDO_AB_OUT_OF_MEM; /* Out of memory */ - ret = CO_SDOcli_endedWithServerAbort; + ret = CO_SDO_RT_endedWithServerAbort; } else { SDO_C->sizeTran = (size_t)SDO_C->SDO->ODF_arg.dataLength; /* fifo was written directly, indicate data size manually */ SDO_C->bufFifo.writePtr = SDO_C->sizeTran; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } } else { - ret = CO_SDOcli_endedWithServerAbort; + ret = CO_SDO_RT_endedWithServerAbort; } } SDO_C->state = CO_SDO_ST_IDLE; @@ -969,7 +969,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_endedWithServerAbort; + ret = CO_SDO_RT_endedWithServerAbort; } else switch (SDO_C->state) { case CO_SDO_ST_UPLOAD_INITIATE_RSP: { @@ -999,7 +999,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, count, NULL); SDO_C->sizeTran = count; SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } else { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED @@ -1071,7 +1071,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_ABORT; } else { SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } } else { @@ -1143,7 +1143,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, count, NULL); SDO_C->sizeTran = count; SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; } else { /* segmented transfer, is size indicated? */ @@ -1222,7 +1222,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* Timeout timers *********************************************************/ - if (ret == CO_SDOcli_waitingServerResponse) { + if (ret == CO_SDO_RT_waitingResponse) { if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { SDO_C->timeoutTimer += timeDifference_us; } @@ -1273,13 +1273,13 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ if (SDO_C->CANtxBuff->bufferFull) { - ret = CO_SDOcli_transmittBufferFull; + ret = CO_SDO_RT_transmittBufferFull; } } /* Transmit CAN data ******************************************************/ - if (ret == CO_SDOcli_waitingServerResponse) { + if (ret == CO_SDO_RT_waitingResponse) { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK size_t count; #endif @@ -1303,7 +1303,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { /* verify, if there is enough space in data buffer */ if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7) { - ret = CO_SDOcli_uploadDataBufferFull; + ret = CO_SDO_RT_uploadDataBufferFull; break; } SDO_C->CANtxBuff->data[0] = 0x60 | SDO_C->toggle; @@ -1383,7 +1383,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) > 0) { /* application must empty data buffer first */ - ret = CO_SDOcli_uploadDataBufferFull; + ret = CO_SDO_RT_uploadDataBufferFull; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT /* Inform OS to call this function again without delay. */ if (timerNext_us != NULL) { @@ -1413,7 +1413,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_ok_communicationEnd; + ret = CO_SDO_RT_ok_communicationEnd; break; } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ @@ -1424,7 +1424,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } } - if (ret == CO_SDOcli_waitingServerResponse) { + if (ret == CO_SDO_RT_waitingResponse) { if (SDO_C->state == CO_SDO_ST_ABORT) { uint32_t code = CO_SWAP_32((uint32_t)abortCode); /* Send SDO abort message */ @@ -1436,11 +1436,11 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDOcli_endedWithClientAbort; + ret = CO_SDO_RT_endedWithClientAbort; } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { - ret = CO_SDOcli_blockUploadInProgress; + ret = CO_SDO_RT_blockUploadInProgress; } #endif } diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 2f786bc8..f71d52ba 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -29,9 +29,7 @@ #define CO_SDO_CLIENT_H #include "301/CO_driver.h" -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) || defined CO_DOXYGEN #include "301/CO_SDOserver.h" -#endif #include "301/CO_fifo.h" #ifdef __cplusplus @@ -49,32 +47,6 @@ extern "C" { */ -/** - * Return values of SDO client functions. - */ -typedef enum { - /** Data buffer is full, data must be read before next upload cycle begins*/ - CO_SDOcli_uploadDataBufferFull = 5, - /** CAN transmit buffer is full. Waiting. */ - CO_SDOcli_transmittBufferFull = 4, - /** Block download is in progress. Sending train of messages. */ - CO_SDOcli_blockDownldInProgress = 3, - /** Block upload is in progress. Receiving train of messages. Data must not - * be read in this state. */ - CO_SDOcli_blockUploadInProgress = 2, - /** Waiting server response */ - CO_SDOcli_waitingServerResponse = 1, - /** Success, end of communication. Uploaded data must be read. */ - CO_SDOcli_ok_communicationEnd = 0, - /** Error in arguments */ - CO_SDOcli_wrongArguments = -2, - /** Communication ended with client abort */ - CO_SDOcli_endedWithClientAbort = -9, - /** Communication ended with server abort */ - CO_SDOcli_endedWithServerAbort = -10, -} CO_SDOclient_return_t; - - /** * SDO Client Parameter. The same as record from Object dictionary * (index 0x1280+). @@ -247,12 +219,12 @@ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, * object is not used. If it is the same as node-ID of this node, then data will * be exchanged with this node (without CAN communication). * - * @return #CO_SDOclient_return_t + * @return #CO_SDO_return_t */ -CO_SDOclient_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient, - uint8_t nodeIDOfTheSDOServer); +CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, + uint32_t COB_IDClientToServer, + uint32_t COB_IDServerToClient, + uint8_t nodeIDOfTheSDOServer); /** @@ -277,14 +249,14 @@ CO_SDOclient_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. * - * @return #CO_SDOclient_return_t + * @return #CO_SDO_return_t */ -CO_SDOclient_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - size_t sizeIndicated, - uint16_t SDOtimeoutTime_ms, - bool_t blockEnable); +CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, + uint16_t index, + uint8_t subIndex, + size_t sizeIndicated, + uint16_t SDOtimeoutTime_ms, + bool_t blockEnable); /** @@ -333,7 +305,7 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, * download communication initiated with CO_SDOclientDownloadInitiate(). * Function is non-blocking. * - * If function returns #CO_SDOcli_blockDownldInProgress and OS has buffer for + * If function returns #CO_SDO_RT_blockDownldInProgress and OS has buffer for * CAN tx messages, then this function may be called multiple times within own * loop. This can speed-up SDO block transfer. * @@ -347,12 +319,12 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, * @param [out] sizeTransferred Actual size of data transferred. Ignored if NULL * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * - * @return #CO_SDOclient_return_t. If less than 0, then error occurred, + * @return #CO_SDO_return_t. If less than 0, then error occurred, * SDOabortCode contains reason and state becomes idle. If 0, communication * ends successfully and state becomes idle. If greater than 0, then * communication is in progress. */ -CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, +CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, bool_t abort, CO_SDO_abortCode_t *SDOabortCode, @@ -373,13 +345,13 @@ CO_SDOclient_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. * - * @return #CO_SDOclient_return_t + * @return #CO_SDO_return_t */ -CO_SDOclient_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - uint16_t SDOtimeoutTime_ms, - bool_t blockEnable); +CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, + uint16_t index, + uint8_t subIndex, + uint16_t SDOtimeoutTime_ms, + bool_t blockEnable); /** @@ -389,11 +361,11 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, * upload communication initiated with CO_SDOclientUploadInitiate(). * Function is non-blocking. * - * If this function returns #CO_SDOcli_uploadDataBufferFull, then data must be + * If this function returns #CO_SDO_RT_uploadDataBufferFull, then data must be * read from fifo buffer to make it empty. This function can then be called * once again immediately to speed-up block transfer. Note also, that remaining - * data must be read after function returns #CO_SDOcli_ok_communicationEnd. - * Data must not be read, if function returns #CO_SDOcli_blockUploadInProgress. + * data must be read after function returns #CO_SDO_RT_ok_communicationEnd. + * Data must not be read, if function returns #CO_SDO_RT_blockUploadInProgress. * * @param SDO_C This object. * @param timeDifference_us Time difference from previous function call in @@ -405,17 +377,17 @@ CO_SDOclient_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, * @param [out] sizeTransferred Actual size of data transferred. Ignored if NULL * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * - * @return #CO_SDOclient_return_t. If less than 0, then error occurred, + * @return #CO_SDO_return_t. If less than 0, then error occurred, * SDOabortCode contains reason and state becomes idle. If 0, communication * ends successfully and state becomes idle. If greater than 0, then * communication is in progress. */ -CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - CO_SDO_abortCode_t *SDOabortCode, - size_t *sizeIndicated, - size_t *sizeTransferred, - uint32_t *timerNext_us); +CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, + uint32_t timeDifference_us, + CO_SDO_abortCode_t *SDOabortCode, + size_t *sizeIndicated, + size_t *sizeTransferred, + uint32_t *timerNext_us); /** @@ -430,7 +402,7 @@ CO_SDOclient_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, * CO_fifo_readU82a() or similar. * * @warning This function (or similar) must NOT be called when - * CO_SDOclientUpload() returns #CO_SDOcli_blockUploadInProgress! + * CO_SDOclientUpload() returns #CO_SDO_RT_blockUploadInProgress! * * @param SDO_C This object. * @param buf Buffer into which data will be copied diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 031f9a6d..aea1f5f6 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -619,6 +619,33 @@ typedef enum{ }CO_SDO_OD_flags_t; +/** + * Return values from SDO server or client functions. + */ +typedef enum { + /** Data buffer is full. + * SDO client: data must be read before next upload cycle begins. */ + CO_SDO_RT_uploadDataBufferFull = 5, + /** CAN transmit buffer is full. Waiting. */ + CO_SDO_RT_transmittBufferFull = 4, + /** Block download is in progress. Sending train of messages. */ + CO_SDO_RT_blockDownldInProgress = 3, + /** Block upload is in progress. Receiving train of messages. + * SDO client: Data must not be read in this state. */ + CO_SDO_RT_blockUploadInProgress = 2, + /** Waiting server or client response */ + CO_SDO_RT_waitingResponse = 1, + /** Success, end of communication. SDO client: uploaded data must be read.*/ + CO_SDO_RT_ok_communicationEnd = 0, + /** Error in arguments */ + CO_SDO_RT_wrongArguments = -2, + /** Communication ended with client abort */ + CO_SDO_RT_endedWithClientAbort = -9, + /** Communication ended with server abort */ + CO_SDO_RT_endedWithServerAbort = -10, +} CO_SDO_return_t; + + /** * Object for one entry with specific index in @ref CO_SDO_objectDictionary. */ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 2fc7b600..c621dd07 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -813,7 +813,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(tok, "r") == 0 || strcmp(tok, "read") == 0) { uint16_t idx; uint8_t subidx; - CO_SDOclient_return_t SDO_ret; + CO_SDO_return_t SDO_ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); if (closed != 0 || NodeErr) { @@ -852,7 +852,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* setup client */ SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, 0, 0, gtwa->node); - if (SDO_ret != CO_SDOcli_ok_communicationEnd) { + if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -862,7 +862,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, SDO_ret = CO_SDOclientUploadInitiate(gtwa->SDO_C, idx, subidx, gtwa->SDOtimeoutTime, gtwa->SDOblockTransferEnable); - if (SDO_ret != CO_SDOcli_ok_communicationEnd) { + if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -880,7 +880,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, uint16_t idx; uint8_t subidx; CO_fifo_st status; - CO_SDOclient_return_t SDO_ret; + CO_SDO_return_t SDO_ret; size_t size; bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); @@ -912,7 +912,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* setup client */ SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, 0, 0, gtwa->node); - if (SDO_ret != CO_SDOcli_ok_communicationEnd) { + if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -924,7 +924,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->SDOdataType->length, gtwa->SDOtimeoutTime, gtwa->SDOblockTransferEnable); - if (SDO_ret != CO_SDOcli_ok_communicationEnd) { + if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -1501,7 +1501,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (gtwa->state == CO_GTWA_ST_READ) { CO_SDO_abortCode_t abortCode; size_t sizeTransferred; - CO_SDOclient_return_t ret; + CO_SDO_return_t ret; ret = CO_SDOclientUpload(gtwa->SDO_C, timeDifference_us, @@ -1515,8 +1515,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_IDLE; } /* Response data must be read, partially or whole */ - else if (ret == CO_SDOcli_uploadDataBufferFull - || ret == CO_SDOcli_ok_communicationEnd + else if (ret == CO_SDO_RT_uploadDataBufferFull + || ret == CO_SDO_RT_ok_communicationEnd ) { size_t fifoRemain; @@ -1538,11 +1538,11 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, >wa->SDO_C->bufFifo, >wa->respBuf[gtwa->respBufCount], CO_GTWA_RESP_BUF_SIZE - 2 - gtwa->respBufCount, - ret == CO_SDOcli_ok_communicationEnd); + ret == CO_SDO_RT_ok_communicationEnd); fifoRemain = CO_fifo_getOccupied(>wa->SDO_C->bufFifo); /* end of communication, print newline and enter idle state */ - if (ret == CO_SDOcli_ok_communicationEnd && fifoRemain == 0) { + if (ret == CO_SDO_RT_ok_communicationEnd && fifoRemain == 0) { gtwa->respBufCount += sprintf(>wa->respBuf[gtwa->respBufCount], "\r\n"); gtwa->state = CO_GTWA_ST_IDLE; @@ -1560,7 +1560,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, size_t sizeTransferred; bool_t abort = false; bool_t hold = false; - CO_SDOclient_return_t ret; + CO_SDO_return_t ret; int loop = 0; /* copy data to the SDO buffer if more data available */ @@ -1610,14 +1610,14 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (++loop >= CO_CONFIG_GTW_BLOCK_DL_LOOP) { break; } - } while (ret == CO_SDOcli_blockDownldInProgress); + } while (ret == CO_SDO_RT_blockDownldInProgress); /* send response in case of error or finish */ if (ret < 0) { responseWithErrorSDO(gtwa, abortCode); gtwa->state = CO_GTWA_ST_IDLE; } - else if (ret == CO_SDOcli_ok_communicationEnd) { + else if (ret == CO_SDO_RT_ok_communicationEnd) { responseWithOK(gtwa); gtwa->state = CO_GTWA_ST_IDLE; } From 2d07d7af179d83efcdc125c738b1cc6142c94493 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 25 Jul 2020 13:17:01 +0200 Subject: [PATCH 107/520] OD interface: remove "lowLimit" and "highLimit" Too complicated to implement and litmited usefulness. IO extension is better. --- 301/CO_ODinterface.c | 125 ++++++++-------------------------------- 301/CO_ODinterface.h | 132 +++++++++++++------------------------------ 301/CO_SDOclient.c | 22 ++++---- 3 files changed, 76 insertions(+), 203 deletions(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index cd55bdaa..6684938c 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -111,6 +111,27 @@ static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, return n; } +/******************************************************************************/ +OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) +{ + (void) stream; (void) subIndex; (void) buf; (void) count; + + if (returnCode != NULL) *returnCode = ODR_WRITEONLY; + return 0; +} + +OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) +{ + (void) stream; (void) subIndex; (void) buf; (void) count; + + if (returnCode != NULL) *returnCode = ODR_READONLY; + return 0; +} + /******************************************************************************/ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { unsigned int cur; @@ -176,7 +197,9 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, if ((entry->odObjectType & ODT_EXTENSION_MASK) != 0) { const OD_obj_extended_t *odoe = (const OD_obj_extended_t *)odObject; - if (odoe->extIO != NULL && odoe->extIO->object != NULL) { + if (odoe->extIO != NULL && odoe->extIO->object != NULL + && odoe->extIO->read != NULL && odoe->extIO->write != NULL) + { subEntry->read = odoe->extIO->read; subEntry->write = odoe->extIO->write; stream->dataObject = odoe->extIO->object; @@ -198,17 +221,6 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, if (odBasicType == ODT_VAR) { const OD_obj_var_t *odo = (const OD_obj_var_t *)odObject; - subEntry->lowLimit = 1; - subEntry->highLimit = 0; - subEntry->attribute = odo->attribute; - if (!io_configured) stream->dataObject = odo->data; - stream->dataLength = odo->dataLength; - } - else if (odBasicType == ODT_VARL) { - const OD_obj_varLimits_t *odo = (const OD_obj_varLimits_t *)odObject; - - subEntry->lowLimit = odo->limit.low; - subEntry->highLimit = odo->limit.high; subEntry->attribute = odo->attribute; if (!io_configured) stream->dataObject = odo->data; stream->dataLength = odo->dataLength; @@ -216,8 +228,6 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, else if (odBasicType == ODT_ARR) { const OD_obj_array_t *odo = (const OD_obj_array_t *)odObject; - subEntry->lowLimit = 1; - subEntry->highLimit = 0; if (subIndex == 0) { subEntry->attribute = odo->attribute0; if (!io_configured) stream->dataObject = odo->data0; @@ -235,49 +245,10 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, stream->dataLength = odo->dataElementLength; } } - else if (odBasicType == ODT_ARRL) { - const OD_obj_arrayLimAttr_t *odo = - (const OD_obj_arrayLimAttr_t *)odObject; - - if (subIndex == 0) { - subEntry->lowLimit = 1; - subEntry->highLimit = 0; - subEntry->attribute = odo->attribute0; - if (!io_configured) stream->dataObject = odo->data0; - stream->dataLength = 1; - } - else { - char *data = (char *)odo->data; - int i = subIndex - 1; - - if (odo->limits == NULL || odo->attributes == NULL) - return ODR_DEV_INCOMPAT; - subEntry->lowLimit = odo->limits[i].low; - subEntry->highLimit = odo->limits[i].high; - subEntry->attribute = odo->attributes[i]; - if (!io_configured) { - if (data == NULL) return ODR_DEV_INCOMPAT; - stream->dataObject = data + odo->dataElementSizeof * i; - } - stream->dataLength = odo->dataElementLength; - } - } else if (odBasicType == ODT_REC) { const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)odObject; const OD_obj_var_t *odo = &odo_rec[subIndex]; - subEntry->lowLimit = 1; - subEntry->highLimit = 0; - subEntry->attribute = odo->attribute; - if (!io_configured) stream->dataObject = odo->data; - stream->dataLength = odo->dataLength; - } - else if (odBasicType == ODT_RECL) { - const OD_obj_varLimits_t *odo_rec = (const OD_obj_varLimits_t*)odObject; - const OD_obj_varLimits_t *odo = &odo_rec[subIndex]; - - subEntry->lowLimit = odo->limit.low; - subEntry->highLimit = odo->limit.high; subEntry->attribute = odo->attribute; if (!io_configured) stream->dataObject = odo->data; stream->dataLength = odo->dataLength; @@ -290,7 +261,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, } /******************************************************************************/ -uint32_t OD_getSDOabortCode(ODR_t returnCode) { +uint32_t OD_getSDOabCode(ODR_t returnCode) { static const uint32_t abortCodes[ODR_COUNT] = { 0x00000000UL, /* No abort */ 0x05040005UL, /* Out of memory */ @@ -390,13 +361,6 @@ void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup) { dataObject = odo->data; dataLength = odo->dataLength; } - else if (odBasicType == ODT_VARL) { - const OD_obj_varLimits_t *odo = (const OD_obj_varLimits_t*)orig; - - attr = odo->attribute; - dataObject = odo->data; - dataLength = odo->dataLength; - } else if (odBasicType == ODT_ARR) { const OD_obj_array_t *odo = (const OD_obj_array_t *)orig; @@ -415,25 +379,6 @@ void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup) { } } } - else if (odBasicType == ODT_ARRL) { - const OD_obj_arrayLimAttr_t *odo = - (const OD_obj_arrayLimAttr_t *)orig; - - if (subIndex == 0) { - attr = odo->attribute0; - dataObject = odo->data0; - dataLength = 1; - } - else { - char *data = (char *)odo->data; - if (data != NULL && odo->attributes != NULL) { - int i = subIndex - 1; - attr = odo->attributes[i]; - dataObject = data + odo->dataElementSizeof * i; - dataLength = odo->dataElementLength; - } - } - } else if (odBasicType == ODT_REC) { const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)orig; const OD_obj_var_t *odo = &odo_rec[subIndex]; @@ -442,15 +387,6 @@ void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup) { dataObject = odo->data; dataLength = odo->dataLength; } - else if (odBasicType == ODT_RECL) { - const OD_obj_varLimits_t *odo_rec - = (const OD_obj_varLimits_t*)orig; - const OD_obj_varLimits_t *odo = &odo_rec[subIndex]; - - attr = odo->attribute; - dataObject = odo->data; - dataLength = odo->dataLength; - } if (dataObject == NULL || (attr&ODA_NOINIT) != 0 || dataLength == 0) continue; @@ -571,7 +507,6 @@ ODR_t OD_set_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t val) { ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } @@ -581,7 +516,6 @@ ODR_t OD_set_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t val) { ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } @@ -591,7 +525,6 @@ ODR_t OD_set_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t val) { ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } @@ -610,7 +543,6 @@ ODR_t OD_set_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t val) { ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } @@ -620,7 +552,6 @@ ODR_t OD_set_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t val) { ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) ret = OD_checkLimits(&subEntry, val); if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } @@ -628,14 +559,8 @@ ODR_t OD_set_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t val) { ODR_t OD_set_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t val) { OD_subEntry_t subEntry; OD_stream_t st; ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); - uint32_t lowLimit = (uint32_t)subEntry.lowLimit; - uint32_t highLimit = (uint32_t)subEntry.highLimit; if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK && lowLimit <= highLimit) { - if (val > highLimit) ret = ODR_VALUE_HIGH; - else if (val < lowLimit) ret = ODR_VALUE_LOW; - } if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 81766697..a0164ebf 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -76,14 +76,13 @@ extern "C" { * data of different type. * * ### Optional extensions - * There are some optional extensions to the Object Dictionary: fixed **low and - * high limit** prevent writing wrong value, PDO flags and IO extension. - * **PDO flags** informs application, if specific OD variable was received or - * sent by PDO. And also gives the application ability to request a TPDO, to - * which variable is possibly mapped. - * **IO extension** gives the application ability to take full control over the - * OD object. Application can specify own @b read and @b write functions and own - * object, on which they operate. + * There are some optional extensions to the Object Dictionary: + * * **PDO flags** informs application, if specific OD variable was received + * or sent by PDO. And also gives the application ability to request a TPDO, + * to which variable is possibly mapped. + * * **IO extension** gives the application ability to take full control over + * the OD object. Application can specify own @b read and @b write functions + * and own object, on which they operate. * * ### Example usage * @code @@ -340,12 +339,14 @@ const OD_t ODxyz = { ... + ... ... + ... @@ -354,35 +355,41 @@ const OD_t ODxyz = { ... + ... ... + ... ... + ... ... + ... ... + ... ... + ... @@ -480,9 +487,8 @@ const OD_t ODxyz = { * "CANopenObject" or "CANopenSubObject" must contain additional attributes: * * "dataType" (required for VAR) - CANopen basic data type, see below * * "accessType" (required for VAR) - "ro", "wo", "rw" or "const" - * * "lowLimit" (optional) - 32 bit integer value, signed or unsigned - * * "highLimit" (optional) - 32 bit integer value, signed or unsigned * * "defaultValue" (optional) - Default value for the variable. + * * "denotation" (optional) - Not used by CANopenNode. * * #### <parameter> * * "uniqueID" (required) @@ -503,13 +509,6 @@ const OD_t ODxyz = { * definition of complex data types is required by the standard, but it is * not required by CANopenNode. * * <defaultValue> (optional for VAR) - Default value for the variable. - * * limits (optional for VAR) - 32 bit integer values, signed or unsigned: -@code{.xml} - - - - -@endcode * * Additional, optional, CANopenNode specific properties, which can be used * inside parameters describing <CANopenObject>: @@ -594,7 +593,7 @@ typedef enum { ODA_TSRDO = 0x10, /**< Variable is mappable into transmitting SRDO */ ODA_RSRDO = 0x20, /**< Variable is mappable into receiving SRDO */ ODA_TRSRDO = 0x30, /**< Variable is mappable into tx or rx SRDO */ - ODA_MB = 0x40, /**< Variable is multi-byte (uint32_t, etc) */ + ODA_MB = 0x40, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */ ODA_NOINIT = 0x80, /**< Variable has no initial value. Can be used with OD objects, which has IO extension enabled. Object dictionary does not reserve memory for the variable and storage is not used. */ @@ -606,7 +605,7 @@ typedef enum { */ typedef enum { /* !!!! WARNING !!!! */ -/* If changing these values, change also OD_getSDOabortCode() function! */ +/* If changing these values, change also OD_getSDOabCode() function! */ ODR_PARTIAL = -1, /**< Read/write is only partial, make more calls */ ODR_OK = 0, /**< Read/write successfully finished */ ODR_OUT_OF_MEM = 1, /**< Out of memory */ @@ -671,10 +670,6 @@ typedef struct { uint8_t storageGroup; /** Attribute bit-field of the OD sub-object, see OD_attributes_t */ OD_attr_t attribute; - /** Low limit of the parameter value, not valid if greater than highLimit */ - int32_t lowLimit; - /** High limit of the parameter value, not valid if lower than lowLimit */ - int32_t highLimit; /** * Pointer to PDO flags bit-field. This is optional extension of OD object. * If OD object has enabled this extension, then each sub-element is coupled @@ -728,7 +723,7 @@ typedef struct { * Function pointer for writing value into specified variable inside Object * Dictionary. If OD variable is larger than buf, then this function must * be called several times. After completed successful write function - * returns 'ODR_OK'. If read is partial, it returns 'ODR_PARTIAL'. In case + * returns 'ODR_OK'. If write is partial, it returns 'ODR_PARTIAL'. In case * of errors function returns code similar to SDO abort code. * * Write can be restarted with @ref OD_rwRestart() function. @@ -835,26 +830,6 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, OD_subEntry_t *subEntry, OD_stream_t *stream); -/** - * Verify if value written to Object Dictionary is within limit values - * - * @param subEntry OD sub-entry data returned by @ref OD_getSub(). - * @param val Value to be verified. - * - * @return Value from @ref ODR_t, "ODR_OK" in case of success. - */ -static inline ODR_t OD_checkLimits(OD_subEntry_t *subEntry, int32_t val) { - int32_t lowLimit = subEntry->lowLimit; - int32_t highLimit = subEntry->highLimit; - - if (lowLimit <= highLimit) { - if (val < lowLimit) return ODR_VALUE_LOW; - if (val > highLimit) return ODR_VALUE_HIGH; - } - return ODR_OK; -} - - /** * Restart read or write operation on OD variable * @@ -877,7 +852,7 @@ static inline void OD_rwRestart(OD_stream_t *stream) { * * @return Corresponding @ref CO_SDO_abortCode_t */ -uint32_t OD_getSDOabortCode(ODR_t returnCode); +uint32_t OD_getSDOabCode(ODR_t returnCode); /** @@ -917,6 +892,26 @@ bool_t OD_extensionIO_init(const OD_entry_t *entry, OD_size_t count, ODR_t *returnCode)); +/** + * Helper function for no read access + * + * This function can be used by application as argument to + * @ref OD_extensionIO_init(). It only returns ODR_WRITEONLY as returnCode. + */ +OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode); + +/** + * Helper function for no write access + * + * This function can be used by application as argument to + * @ref OD_extensionIO_init(). It only returns ODR_READONLY as returnCode. + */ +OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode); + /** * Update storage group data from OD object with IO extension. @@ -1032,12 +1027,6 @@ typedef enum { * @ref OD_obj_var_t. Variable at sub-index 0 is of type uint8_t and usually * represents number of sub-elements in the structure. */ ODT_REC = 0x03, - /** ODT_VAR with additional low and high limit of the parameter value */ - ODT_VARL = 0x04, - /** ODT_ARR with additional low and high limits of the parameter values */ - ODT_ARRL = 0x05, - /** ODT_REC with additional low and high limits of the parameter values */ - ODT_RECL = 0x06, /** Same as ODT_VAR, but extended with OD_obj_extended_t type. It includes * additional pointer to IO extension and PDO flags */ @@ -1046,12 +1035,6 @@ typedef enum { ODT_EARR = 0x12, /** Same as ODT_REC, but extended with OD_obj_extended_t type */ ODT_EREC = 0x13, - /** Same as ODT_VARL, but extended with OD_obj_extended_t type */ - ODT_EVARL = 0x14, - /** Same as ODT_ARRL, but extended with OD_obj_extended_t type. */ - ODT_EARRL = 0x15, - /** Same as ODT_RECL, but extended with OD_obj_extended_t type. */ - ODT_ERECL = 0x16, /** Mask for basic type */ ODT_TYPE_MASK = 0x0F, @@ -1068,25 +1051,6 @@ typedef struct { OD_size_t dataLength; /**< Data length in bytes */ } OD_obj_var_t; -/** - * Limits of the parameter value. - */ -typedef struct { - int32_t low; /**< Low limit of the parameter value */ - int32_t high; /**< High limit of the parameter value */ -} OD_limits_t; - -/** - * Object for single OD variable, used for "VAR" and "RECORD" type OD objects. - * Additionally includes limits of the parameter value. - */ -typedef struct { - void *data; /**< Pointer to data */ - OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ - OD_size_t dataLength; /**< Data length in bytes */ - OD_limits_t limit; /**< Limits of the parameter value */ -} OD_obj_varLimits_t; - /** * Object for OD array of variables, used for "ARRAY" type OD objects */ @@ -1100,22 +1064,6 @@ typedef struct { OD_size_t dataElementSizeof; /**< Sizeof one array element in bytes */ } OD_obj_array_t; -/** - * Object for OD array of variables, used for "ARRAY" type OD objects. - * Additionally includes limits of the parameter value for each array element - * and separate attribute for each array element. - */ -typedef struct { - uint8_t *data0; /**< Pointer to data for sub-index 0 */ - void *data; /**< Pointer to array of data */ - OD_limits_t *limits; /**< Pointer to array limits of the parameter value */ - OD_attr_t *attributes; /**< Pointer to array attributes */ - OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see - @ref OD_attributes_t */ - OD_size_t dataElementLength; /**< Data length of array elements in bytes */ - OD_size_t dataElementSizeof; /**< Sizeof one array element in bytes */ -} OD_obj_arrayLimAttr_t; - /** * Object pointed by @ref OD_obj_extended_t contains application specified * parameters for extended OD object diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 14d9a26a..55c6542b 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -460,7 +460,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED if (SDO_C->finished) { /* expedited transfer */ SDO_C->state = CO_SDO_ST_IDLE; @@ -484,7 +484,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { if ((SDO_C->CANrxData[0] & 0xEF) == 0x20) { /* verify and alternate toggle bit */ @@ -511,7 +511,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } break; } -#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED */ +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { @@ -667,7 +667,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->finished = true; } else { -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED /* segmented transfer, indicate data size */ if (SDO_C->sizeInd > 0) { uint32_t size = CO_SWAP_32(SDO_C->sizeInd); @@ -689,7 +689,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { /* fill data bytes */ count = CO_fifo_read(&SDO_C->bufFifo, @@ -725,7 +725,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; break; } -#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED */ +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { @@ -1002,7 +1002,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ret = CO_SDO_RT_ok_communicationEnd; } else { -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED /* segmented transfer, is size indicated? */ if (SDO_C->CANrxData[0] & 0x01) { uint32_t size; @@ -1024,7 +1024,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { if ((SDO_C->CANrxData[0] & 0xE0) == 0x00) { size_t count, countWr; @@ -1084,7 +1084,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } break; } -#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED */ +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { @@ -1299,7 +1299,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { /* verify, if there is enough space in data buffer */ if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7) { @@ -1314,7 +1314,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; break; } -#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_SEGMENTED */ +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { From 3fb0a3ee09555c1834cbfdce88ab3a1ba96bb9c1 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 3 Aug 2020 07:48:40 +0200 Subject: [PATCH 108/520] Fix compile error with older kernels #211 --- socketCAN/CO_error.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index 1e6e11c8..67a458b6 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -156,9 +156,11 @@ static CO_CANinterfaceState_t CO_CANerrorCrtl( CANerrorhandler->CANerrorStatus &= 0x7FFF ^ CO_CAN_ERRTX_PASSIVE; /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_WARNING; */ } +#ifdef CAN_ERR_CRTL_ACTIVE else if ((msg->data[1] & CAN_ERR_CRTL_ACTIVE) != 0) { log_printf(LOG_NOTICE, CAN_TX_LEVEL_ACTIVE, CANerrorhandler->ifName); } +#endif } return result; } From 102b503115cc8efcc70e798bad4c0bd2cf2dab42 Mon Sep 17 00:00:00 2001 From: Miles Simpson Date: Tue, 4 Aug 2020 14:09:51 -0700 Subject: [PATCH 109/520] Standardized 309 ASCII Gateway newlines to \r\n sequence (#215) --- 309/CO_gateway_ascii.c | 120 ++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index c621dd07..d76c5ba0 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -142,72 +142,72 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP /* help strings */ static const char CO_GTWA_helpString[] = -"\nCommand strings start with '\"[\"\"]\"' followed by:\n" \ -"[[] ] r[ead] [] # SDO upload.\n" \ -"[[] ] w[rite] # SDO download.\n" \ -"\n" \ -"[[] ] start # NMT Start node.\n" \ -"[[] ] stop # NMT Stop node.\n" \ -"[[] ] preop[erational] # NMT Set node to pre-operational.\n" \ -"[[] ] reset node # NMT Reset node.\n" \ -"[[] ] reset comm[unication] # NMT Reset communication.\n" \ -"\n" \ -"[] set network # Set default net.\n" \ -"[] set node # Set default node.\n" \ -"[] set sdo_timeout # Configure SDO time-out.\n" \ -"[] set sdo_block # Enable/disable SDO block transfer.\n" \ -"\n" \ -"help [datatype|lss] # Print this or datatype or lss help.\n" \ -"led # Print status LED diodes.\n" \ -"log # Print message log.\n" \ -"\n" \ -"Response:\n" \ -"\"[\"\"]\" OK | |\n" \ -" ERROR: | ERROR:\n" \ -"\n" \ -"* Every command must be terminated with ('\\r\\n'). characters. Same\n" \ -" is response. String is not null terminated, is optional in command.\n" \ -"* Comments started with '#' are ignored. They may be on the beginning of the\n" \ -" line or after the command string.\n" \ -"* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is\n" \ -" disabled by default.\n" \ -"* If '' or '' is not specified within commands, then value defined\n" \ +"\r\nCommand strings start with '\"[\"\"]\"' followed by:\r\n" \ +"[[] ] r[ead] [] # SDO upload.\r\n" \ +"[[] ] w[rite] # SDO download.\r\n" \ +"\r\n" \ +"[[] ] start # NMT Start node.\r\n" \ +"[[] ] stop # NMT Stop node.\r\n" \ +"[[] ] preop[erational] # NMT Set node to pre-operational.\r\n" \ +"[[] ] reset node # NMT Reset node.\r\n" \ +"[[] ] reset comm[unication] # NMT Reset communication.\r\n" \ +"\r\n" \ +"[] set network # Set default net.\r\n" \ +"[] set node # Set default node.\r\n" \ +"[] set sdo_timeout # Configure SDO time-out.\r\n" \ +"[] set sdo_block # Enable/disable SDO block transfer.\r\n" \ +"\r\n" \ +"help [datatype|lss] # Print this or datatype or lss help.\r\n" \ +"led # Print status LED diodes.\r\n" \ +"log # Print message log.\r\n" \ +"\r\n" \ +"Response:\r\n" \ +"\"[\"\"]\" OK | |\r\n" \ +" ERROR: | ERROR:\r\n" \ +"\r\n" \ +"* Every command must be terminated with ('\\r\\n'). characters. Same\r\n" \ +" is response. String is not null terminated, is optional in command.\r\n" \ +"* Comments started with '#' are ignored. They may be on the beginning of the\r\n" \ +" line or after the command string.\r\n" \ +"* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is\r\n" \ +" disabled by default.\r\n" \ +"* If '' or '' is not specified within commands, then value defined\r\n" \ " by 'set network' or 'set node' command is used.\r\n"; static const char CO_GTWA_helpStringDatatypes[] = -"\nDatatypes:\n" \ -"b # Boolean.\n" \ -"i8, i16, i32, i64 # Signed integers.\n" \ -"u8, u16, u32, u64 # Unsigned integers.\n" \ -"x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard.\n" \ -"r32, r64 # Real numbers.\n" \ -"t, td # Time of day, time difference.\n" \ -"vs # Visible string (between double quotes if multi-word).\n" \ -"os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line).\n" \ -"d # domain (mime-base64 (RFC2045) based, one line).\n" \ +"\r\nDatatypes:\r\n" \ +"b # Boolean.\r\n" \ +"i8, i16, i32, i64 # Signed integers.\r\n" \ +"u8, u16, u32, u64 # Unsigned integers.\r\n" \ +"x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard.\r\n" \ +"r32, r64 # Real numbers.\r\n" \ +"t, td # Time of day, time difference.\r\n" \ +"vs # Visible string (between double quotes if multi-word).\r\n" \ +"os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line).\r\n" \ +"d # domain (mime-base64 (RFC2045) based, one line).\r\n" \ "hex # Hexagonal data, optionally space separated, non-standard.\r\n"; static const char CO_GTWA_helpStringLss[] = -"\nLSS commands:\n" \ -"lss_switch_glob <0|1> # Switch state global command.\n" \ -"lss_switch_sel \\\n" \ -" #Switch state selective.\n" \ -"lss_set_node # Configure node-ID.\n" \ -"lss_conf_bitrate \\\n" \ -" # Configure bit-rate.\n" \ -"lss_activate_bitrate # Activate new bit-rate.\n" \ -"lss_store # LSS store configuration.\n" \ -"lss_inquire_addr [] # Inquire LSS address.\n" \ -"lss_get_node # Inquire node-ID.\n" \ -"_lss_fastscan [] # Identify fastscan, non-standard.\n" \ -"lss_allnodes [ [ \\\n" \ -" [ \\\n" \ -" ]]]\n" \ -" # Node-ID configuration of all nodes.\n" \ -"\n" \ -"* All LSS commands start with '\"[\"\"]\" []'.\n" \ -"* : 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\n" \ -" 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\n" \ +"\r\nLSS commands:\r\n" \ +"lss_switch_glob <0|1> # Switch state global command.\r\n" \ +"lss_switch_sel \\\r\n" \ +" #Switch state selective.\r\n" \ +"lss_set_node # Configure node-ID.\r\n" \ +"lss_conf_bitrate \\\r\n" \ +" # Configure bit-rate.\r\n" \ +"lss_activate_bitrate # Activate new bit-rate.\r\n" \ +"lss_store # LSS store configuration.\r\n" \ +"lss_inquire_addr [] # Inquire LSS address.\r\n" \ +"lss_get_node # Inquire node-ID.\r\n" \ +"_lss_fastscan [] # Identify fastscan, non-standard.\r\n" \ +"lss_allnodes [ [ \\\r\n" \ +" [ \\\r\n" \ +" ]]]\r\n" \ +" # Node-ID configuration of all nodes.\r\n" \ +"\r\n" \ +"* All LSS commands start with '\"[\"\"]\" []'.\r\n" \ +"* : 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\r\n" \ +" 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\r\n" \ "* : 0=fastscan, 1=ignore, 2=match value in next parameter\r\n"; #endif From 8783bfff051858738c70285deec14d63c42b4bda Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 Aug 2020 23:39:25 +0200 Subject: [PATCH 110/520] use crc16-ccitt.h in CO_fifo.c It was duplicated. Commited also some small changes + ODinterface --- 301/CO_ODinterface.c | 62 ++++++++++++++++++++++---------- 301/CO_ODinterface.h | 84 +++++++++++++++++++++++++++++++++++++++++--- 301/CO_SDOclient.c | 5 ++- 301/CO_SDOclient.h | 2 +- 301/CO_fifo.c | 78 +++------------------------------------- 301/crc16-ccitt.c | 11 ++++-- 301/crc16-ccitt.h | 20 ++++++++++- 7 files changed, 160 insertions(+), 102 deletions(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 6684938c..0a494d25 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -39,7 +39,7 @@ static OD_size_t OD_readDirect(OD_stream_t *stream, uint8_t subIndex, return 0; } - OD_size_t n = stream->dataLength; + OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ const char *odData = (const char *)stream->dataObject; if (odData == NULL) { @@ -49,15 +49,21 @@ static OD_size_t OD_readDirect(OD_stream_t *stream, uint8_t subIndex, *returnCode = ODR_OK; - if (stream->dataOffset > 0 || n > count) { - /* data will be (are) read in several segments */ - n -= stream->dataOffset; + /* If previous read was partial or OD variable length is larger than + * current buffer len, then data was (will be) read in several segments */ + if (stream->dataOffset > 0 || dataLenToCopy > count) { + if (stream->dataOffset >= dataLenToCopy) { + *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + /* reduce for allready copied data */ + dataLenToCopy -= stream->dataOffset; odData += stream->dataOffset; - if (n > count) { + if (dataLenToCopy > count) { /* not enough space in destionation buffer */ - n = count; - stream->dataOffset += n; + dataLenToCopy = count; + stream->dataOffset += dataLenToCopy; *returnCode = ODR_PARTIAL; } else { @@ -65,8 +71,10 @@ static OD_size_t OD_readDirect(OD_stream_t *stream, uint8_t subIndex, } } - memcpy(buf, odData, n); - return n; + CO_LOCK_OD(); + memcpy(buf, odData, dataLenToCopy); + CO_UNLOCK_OD(); + return dataLenToCopy; } /* Write value to variable from Object Dictionary, see OD_subEntry_t **********/ @@ -81,7 +89,7 @@ static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, return 0; } - OD_size_t n = stream->dataLength; + OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ char *odData = (char *)stream->dataObject; if (odData == NULL) { @@ -91,15 +99,22 @@ static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, *returnCode = ODR_OK; - if (stream->dataOffset > 0 || n > count) { - /* data will be (are) written in several segments */ - n -= stream->dataOffset; + /* If previous write was partial or OD variable length is larger than + * current data len, then data was (will be) written in several segments */ + if (stream->dataOffset > 0 || dataLenToCopy > count) { + if (stream->dataOffset >= dataLenToCopy) { + *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + /* reduce for allready copied data */ + dataLenToCopy -= stream->dataOffset; odData += stream->dataOffset; - if (n > count) { - /* OD variable is larger than current ammount of data */ - n = count; - stream->dataOffset += n; + if (dataLenToCopy > count) { + /* Reamining data space in OD variable is larger than current count + * of data, so only current count of data will be copied */ + dataLenToCopy = count; + stream->dataOffset += dataLenToCopy; *returnCode = ODR_PARTIAL; } else { @@ -107,8 +122,17 @@ static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, } } - memcpy(odData, buf, n); - return n; + if (dataLenToCopy < count) { + /* OD variable is smaller than current ammount of data */ + *returnCode = ODR_DATA_LONG; + return 0; + } + else { + CO_LOCK_OD(); + memcpy(odData, buf, dataLenToCopy); + CO_UNLOCK_OD(); + return dataLenToCopy; + } } /******************************************************************************/ diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index a0164ebf..7f4aad50 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -523,7 +523,7 @@ const OD_t ODxyz = { * * <property name="CO_countLabel" value="..."> - Valid value is * any string without spaces. OD exporter will generate a macro for each * different string. For example, if four OD objects have "CO_countLabel" - * set to "TPDO", then macro "#define OD_NO_TPDO 4" will be generated by + * set to "TPDO", then macro "#define ODxyz_NO_TPDO 4" will be generated by * OD exporter. * * Additional, optional, CANopenNode specific property, which can be used @@ -580,6 +580,67 @@ const OD_t ODxyz = { #define OD_attr_t uint8_t +/** + * Common DS301 object dictionary entries. + */ +typedef enum { + OD_H1000_DEV_TYPE = 0x1000U,/**< Device type */ + OD_H1001_ERR_REG = 0x1001U,/**< Error register */ + OD_H1002_MANUF_STATUS_REG = 0x1002U,/**< Manufacturer status register */ + OD_H1003_PREDEF_ERR_FIELD = 0x1003U,/**< Predefined error field */ + OD_H1004_RSV = 0x1004U,/**< Reserved */ + OD_H1005_COBID_SYNC = 0x1005U,/**< Sync message cob-id */ + OD_H1006_COMM_CYCL_PERIOD = 0x1006U,/**< Communication cycle period */ + OD_H1007_SYNC_WINDOW_LEN = 0x1007U,/**< Sync windows length */ + OD_H1008_MANUF_DEV_NAME = 0x1008U,/**< Manufacturer device name */ + OD_H1009_MANUF_HW_VERSION = 0x1009U,/**< Manufacturer hardware version */ + OD_H100A_MANUF_SW_VERSION = 0x100AU,/**< Manufacturer software version */ + OD_H100B_RSV = 0x100BU,/**< Reserved */ + OD_H100C_GUARD_TIME = 0x100CU,/**< Guard time */ + OD_H100D_LIFETIME_FACTOR = 0x100DU,/**< Life time factor */ + OD_H100E_RSV = 0x100EU,/**< Reserved */ + OD_H100F_RSV = 0x100FU,/**< Reserved */ + OD_H1010_STORE_PARAM_FUNC = 0x1010U,/**< Store params in persistent mem.*/ + OD_H1011_REST_PARAM_FUNC = 0x1011U,/**< Restore default parameters */ + OD_H1012_COBID_TIME = 0x1012U,/**< Timestamp message cob-id */ + OD_H1013_HIGH_RES_TIMESTAMP = 0x1013U,/**< High resolution timestamp */ + OD_H1014_COBID_EMERGENCY = 0x1014U,/**< Emergency message cob-id */ + OD_H1015_INHIBIT_TIME_MSG = 0x1015U,/**< Inhibit time message */ + OD_H1016_CONSUMER_HB_TIME = 0x1016U,/**< Consumer heartbeat time */ + OD_H1017_PRODUCER_HB_TIME = 0x1017U,/**< Producer heartbeat time */ + OD_H1018_IDENTITY_OBJECT = 0x1018U,/**< Identity object */ + OD_H1019_SYNC_CNT_OVERFLOW = 0x1019U,/**< Sync counter overflow value */ + OD_H1020_VERIFY_CONFIG = 0x1020U,/**< Verify configuration */ + OD_H1021_STORE_EDS = 0x1021U,/**< Store EDS */ + OD_H1022_STORE_FORMAT = 0x1022U,/**< Store format */ + OD_H1023_OS_CMD = 0x1023U,/**< OS command */ + OD_H1024_OS_CMD_MODE = 0x1024U,/**< OS command mode */ + OD_H1025_OS_DBG_INTERFACE = 0x1025U,/**< OS debug interface */ + OD_H1026_OS_PROMPT = 0x1026U,/**< OS prompt */ + OD_H1027_MODULE_LIST = 0x1027U,/**< Module list */ + OD_H1028_EMCY_CONSUMER = 0x1028U,/**< Emergency consumer object */ + OD_H1029_ERR_BEHAVIOR = 0x1029U,/**< Error behaviour */ + OD_H1200_SDO_SERVER_PARAM = 0x1200U,/**< SDO server parameters */ + OD_H1280_SDO_CLIENT_PARAM = 0x1280U,/**< SDO client parameters */ + OD_H1400_RXPDO_1_PARAM = 0x1400U,/**< RXPDO communication parameter */ + OD_H1401_RXPDO_2_PARAM = 0x1401U,/**< RXPDO communication parameter */ + OD_H1402_RXPDO_3_PARAM = 0x1402U,/**< RXPDO communication parameter */ + OD_H1403_RXPDO_4_PARAM = 0x1403U,/**< RXPDO communication parameter */ + OD_H1600_RXPDO_1_MAPPING = 0x1600U,/**< RXPDO mapping parameters */ + OD_H1601_RXPDO_2_MAPPING = 0x1601U,/**< RXPDO mapping parameters */ + OD_H1602_RXPDO_3_MAPPING = 0x1602U,/**< RXPDO mapping parameters */ + OD_H1603_RXPDO_4_MAPPING = 0x1603U,/**< RXPDO mapping parameters */ + OD_H1800_TXPDO_1_PARAM = 0x1800U,/**< TXPDO communication parameter */ + OD_H1801_TXPDO_2_PARAM = 0x1801U,/**< TXPDO communication parameter */ + OD_H1802_TXPDO_3_PARAM = 0x1802U,/**< TXPDO communication parameter */ + OD_H1803_TXPDO_4_PARAM = 0x1803U,/**< TXPDO communication parameter */ + OD_H1A00_TXPDO_1_MAPPING = 0x1A00U,/**< TXPDO mapping parameters */ + OD_H1A01_TXPDO_2_MAPPING = 0x1A01U,/**< TXPDO mapping parameters */ + OD_H1A02_TXPDO_3_MAPPING = 0x1A02U,/**< TXPDO mapping parameters */ + OD_H1A03_TXPDO_4_MAPPING = 0x1A03U /**< TXPDO mapping parameters */ +} OD_ObjDicId_301_t; + + /** * Attributes (bit masks) for OD sub-object. */ @@ -668,7 +729,7 @@ typedef struct { uint8_t maxSubIndex; /** Group for non-volatile storage of the OD object */ uint8_t storageGroup; - /** Attribute bit-field of the OD sub-object, see OD_attributes_t */ + /** Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */ OD_attr_t attribute; /** * Pointer to PDO flags bit-field. This is optional extension of OD object. @@ -708,6 +769,10 @@ typedef struct { * extension enabled. OD object must also be initialised with * @ref OD_extensionIO_init() function call. * + * "read" function must always copy all own data to buf, except if "buf" is + * not large enough. ("*returnCode" must not return 'ODR_PARTIAL', if there + * is still space in "buf".) + * * @param stream Object Dictionary stream object, returned from * @ref OD_getSub() function, see @ref OD_stream_t. * @param subIndex Object Dictionary subIndex of the accessed element. @@ -733,6 +798,9 @@ typedef struct { * Dictionary variable. Application can bind its own "write" function, * similar as it can bind "read" function. * + * "write" function must always copy all available data from buf. If OD + * variable expect more data, then "*returnCode" must return 'ODR_PARTIAL'. + * * @param stream Object Dictionary stream object, returned from * @ref OD_getSub() function, see @ref OD_stream_t. * @param subIndex Object Dictionary subIndex of the accessed element. @@ -740,7 +808,8 @@ typedef struct { * @param count Size of the external buffer in bytes. * @param [out] returnCode Return value from ODR_t. * - * @return Number of bytes successfully written. + * @return Number of bytes successfully written, must be equal to count on + * success or zero on error. */ OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode); @@ -869,11 +938,16 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); * initial values for the data. And also, as any data from OD, data can be * loaded from or saved to nonvolatile storage. * + * @warning + * Read and write functions may be called from different threads, so critical + * sections in custom functions must be protected with @ref CO_LOCK_OD() and + * @ref CO_UNLOCK_OD(). + * * See also warning in @ref OD_getSub() function. - + * * @param entry OD entry returned by @ref OD_find(). * @param object Object, which will be passed to read or write function, must -* not be NULL. + * not be NULL. * @param read Read function pointer, see @ref OD_subEntry_t. * @param write Write function pointer, see @ref OD_subEntry_t. * diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 55c6542b..486ccf81 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -108,7 +108,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { } else { /* Copy data. There is always enough space in fifo buffer, - * because block_seqno was calculated before */ + * because block_blksize was calculated before */ CO_fifo_write(&SDO_C->bufFifo, (const char *)&data[1], 7, &SDO_C->block_crc); @@ -530,6 +530,8 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->block_crc = 0; SDO_C->block_blksize = SDO_C->CANrxData[4]; + if (SDO_C->block_blksize < 1 || SDO_C->block_blksize > 127) + SDO_C->block_blksize = 127; SDO_C->block_seqno = 0; CO_fifo_altBegin(&SDO_C->bufFifo, 0); SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; @@ -1404,6 +1406,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; + SDO_C->block_timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); break; } diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index f71d52ba..e7a8f840 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -145,7 +145,7 @@ typedef struct { uint8_t block_noData; /** Server CRC support in block transfer */ bool_t block_crcEnabled; - /** Last 7 bytes of data at block download */ + /** Last 7 bytes of data at block upload */ uint8_t block_dataUploadLast[7]; /** Calculated CRC checksum */ uint16_t block_crc; diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 11038901..c97b8a89 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -29,6 +29,9 @@ #include #include #include +#if CO_CONFIG_FIFO_CRC16_CCITT == 1 +#include "crc16-ccitt.h" +#endif #if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 #include @@ -57,77 +60,6 @@ void CO_fifo_init(CO_fifo_t *fifo, char *buf, size_t bufSize) { } -#if CO_CONFIG_FIFO_CRC16_CCITT == 1 -/* CRC calculation algorithm - * Author of the original crc16 ccitt C code is Lammert Bies. - * - * CRC table is calculated by the following algorithm: - * - * void CO_fifo_crc16_ccitt_table_init(void) { - * uint16_t i, j; - * for (i = 0; i < 256; i++) { - * uint16_t crc = 0; - * uint16_t c = i << 8; - * for(j = 0; j < 8; j++) { - * if((crc ^ c) & 0x8000) crc = (crc << 1) ^ 0x1021; - * else crc = crc << 1; - * c = c << 1; - * } - * CO_fifo_crc16_ccitt_table[i] = crc; - * } - * } */ -static const uint16_t CO_fifo_crc16_ccitt_table[256] = { - 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50A5U, 0x60C6U, 0x70E7U, - 0x8108U, 0x9129U, 0xA14AU, 0xB16BU, 0xC18CU, 0xD1ADU, 0xE1CEU, 0xF1EFU, - 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52B5U, 0x4294U, 0x72F7U, 0x62D6U, - 0x9339U, 0x8318U, 0xB37BU, 0xA35AU, 0xD3BDU, 0xC39CU, 0xF3FFU, 0xE3DEU, - 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64E6U, 0x74C7U, 0x44A4U, 0x5485U, - 0xA56AU, 0xB54BU, 0x8528U, 0x9509U, 0xE5EEU, 0xF5CFU, 0xC5ACU, 0xD58DU, - 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76D7U, 0x66F6U, 0x5695U, 0x46B4U, - 0xB75BU, 0xA77AU, 0x9719U, 0x8738U, 0xF7DFU, 0xE7FEU, 0xD79DU, 0xC7BCU, - 0x48C4U, 0x58E5U, 0x6886U, 0x78A7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, - 0xC9CCU, 0xD9EDU, 0xE98EU, 0xF9AFU, 0x8948U, 0x9969U, 0xA90AU, 0xB92BU, - 0x5AF5U, 0x4AD4U, 0x7AB7U, 0x6A96U, 0x1A71U, 0x0A50U, 0x3A33U, 0x2A12U, - 0xDBFDU, 0xCBDCU, 0xFBBFU, 0xEB9EU, 0x9B79U, 0x8B58U, 0xBB3BU, 0xAB1AU, - 0x6CA6U, 0x7C87U, 0x4CE4U, 0x5CC5U, 0x2C22U, 0x3C03U, 0x0C60U, 0x1C41U, - 0xEDAEU, 0xFD8FU, 0xCDECU, 0xDDCDU, 0xAD2AU, 0xBD0BU, 0x8D68U, 0x9D49U, - 0x7E97U, 0x6EB6U, 0x5ED5U, 0x4EF4U, 0x3E13U, 0x2E32U, 0x1E51U, 0x0E70U, - 0xFF9FU, 0xEFBEU, 0xDFDDU, 0xCFFCU, 0xBF1BU, 0xAF3AU, 0x9F59U, 0x8F78U, - 0x9188U, 0x81A9U, 0xB1CAU, 0xA1EBU, 0xD10CU, 0xC12DU, 0xF14EU, 0xE16FU, - 0x1080U, 0x00A1U, 0x30C2U, 0x20E3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, - 0x83B9U, 0x9398U, 0xA3FBU, 0xB3DAU, 0xC33DU, 0xD31CU, 0xE37FU, 0xF35EU, - 0x02B1U, 0x1290U, 0x22F3U, 0x32D2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, - 0xB5EAU, 0xA5CBU, 0x95A8U, 0x8589U, 0xF56EU, 0xE54FU, 0xD52CU, 0xC50DU, - 0x34E2U, 0x24C3U, 0x14A0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, - 0xA7DBU, 0xB7FAU, 0x8799U, 0x97B8U, 0xE75FU, 0xF77EU, 0xC71DU, 0xD73CU, - 0x26D3U, 0x36F2U, 0x0691U, 0x16B0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, - 0xD94CU, 0xC96DU, 0xF90EU, 0xE92FU, 0x99C8U, 0x89E9U, 0xB98AU, 0xA9ABU, - 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18C0U, 0x08E1U, 0x3882U, 0x28A3U, - 0xCB7DU, 0xDB5CU, 0xEB3FU, 0xFB1EU, 0x8BF9U, 0x9BD8U, 0xABBBU, 0xBB9AU, - 0x4A75U, 0x5A54U, 0x6A37U, 0x7A16U, 0x0AF1U, 0x1AD0U, 0x2AB3U, 0x3A92U, - 0xFD2EU, 0xED0FU, 0xDD6CU, 0xCD4DU, 0xBDAAU, 0xAD8BU, 0x9DE8U, 0x8DC9U, - 0x7C26U, 0x6C07U, 0x5C64U, 0x4C45U, 0x3CA2U, 0x2C83U, 0x1CE0U, 0x0CC1U, - 0xEF1FU, 0xFF3EU, 0xCF5DU, 0xDF7CU, 0xAF9BU, 0xBFBAU, 0x8FD9U, 0x9FF8U, - 0x6E17U, 0x7E36U, 0x4E55U, 0x5E74U, 0x2E93U, 0x3EB2U, 0x0ED1U, 0x1EF0U -}; - -/* - * Update crc16_ccitt variable with one data byte - * - * This function updates crc variable for one data byte using crc16 ccitt - * algorithm. Function is used inside CO_fifo_write() and CO_fifo_altRead(). - * User can also provide own function for crc calculation. - * - * @param [in,out] crc Externally defined variable for CRC checksum - * @param chr One byte of data - */ -static inline void CO_fifo_crc16_ccitt(uint16_t *crc, const char chr) { - uint8_t tmp = (uint8_t)(*crc >> 8) ^ (uint8_t)chr; - *crc = (*crc << 8) ^ CO_fifo_crc16_ccitt_table[tmp]; -} -#endif /* CO_CONFIG_FIFO_CRC16_CCITT == 1 */ - - /* Circular FIFO buffer example for fifo->bufSize = 7 (usable size = 6): ****** * * * 0 * * * * * @@ -167,7 +99,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, #if CO_CONFIG_FIFO_CRC16_CCITT > 0 if (crc != NULL) { - CO_fifo_crc16_ccitt(crc, *buf); + crc16_ccitt_single(crc, (unsigned char)*buf); } #endif @@ -271,7 +203,7 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { const char *bufSrc = &fifo->buf[fifo->readPtr]; while (fifo->readPtr != fifo->altReadPtr) { #if CO_CONFIG_FIFO_CRC16_CCITT > 0 - CO_fifo_crc16_ccitt(crc, *bufSrc); + crc16_ccitt_single(crc, (unsigned char)*bufSrc); #endif /* increment variable */ if (++fifo->readPtr == fifo->bufSize) { diff --git a/301/crc16-ccitt.c b/301/crc16-ccitt.c index 2d0e7a2d..9a771b33 100644 --- a/301/crc16-ccitt.c +++ b/301/crc16-ccitt.c @@ -81,6 +81,13 @@ static const unsigned short crc16_ccitt_table[256] = { }; +/******************************************************************************/ +void crc16_ccitt_single(unsigned short *crc, const unsigned char chr) { + unsigned char tmp = (unsigned char)(*crc >> 8U) ^ chr; + *crc = (*crc << 8U) ^ crc16_ccitt_table[tmp]; +} + + /******************************************************************************/ unsigned short crc16_ccitt( const unsigned char block[], @@ -90,8 +97,8 @@ unsigned short crc16_ccitt( unsigned int i; for(i=0U; i> 8) ^ (unsigned short) block[i]; - crc = ((unsigned short)(crc << 8U)) ^ crc16_ccitt_table[tmp]; + unsigned char tmp = (unsigned char)(crc >> 8U) ^ block[i]; + crc = (crc << 8U) ^ crc16_ccitt_table[tmp]; } return crc; } diff --git a/301/crc16-ccitt.h b/301/crc16-ccitt.h index 791f2864..df3758da 100644 --- a/301/crc16-ccitt.h +++ b/301/crc16-ccitt.h @@ -45,6 +45,22 @@ extern "C" { */ +/** + * Update crc16_ccitt variable with one data byte + * + * This function updates crc variable for one data byte using crc16 ccitt + * algorithm. + * + * @param [in,out] crc Externally defined variable for CRC checksum. Before + * start of new CRC calculation, variable must be initialized (zero for xmodem). + * @param chr One byte of data + */ +#ifdef CO_USE_OWN_CRC16 +extern +#endif +void crc16_ccitt_single(unsigned short *crc, const unsigned char chr); + + /** * Calculate CRC sum on block of data. * @@ -63,9 +79,11 @@ unsigned short crc16_ccitt( unsigned int blockLength, unsigned short crc); + +/** @} */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ #endif From 2c5d6853437591286e15055ec847219550b165bb Mon Sep 17 00:00:00 2001 From: Miles Simpson Date: Tue, 11 Aug 2020 02:55:12 -0700 Subject: [PATCH 111/520] Differentiate between SDO_C states so state can be determined in a worker thread when passed a CO_SDOclient_t pointer (#218) Added #defines for SDO state flags for use by applications Changed CO_SDO_ST_ABORT to next sequential value --- 301/CO_SDOclient.c | 8 +++--- 301/CO_SDOserver.h | 61 +++++++++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 486ccf81..05dff9e1 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -323,7 +323,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, if (SDO_C->SDO != NULL && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId ) { - SDO_C->state = CO_SDO_ST_LOCAL_TRANSFER; + SDO_C->state = CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER; } else #endif @@ -401,7 +401,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ - else if (SDO_C->state == CO_SDO_ST_LOCAL_TRANSFER) { + else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) { if (SDO_C->SDO->state != CO_SDO_ST_IDLE) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; @@ -880,7 +880,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, if (SDO_C->SDO != NULL && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId ) { - SDO_C->state = CO_SDO_ST_LOCAL_TRANSFER; + SDO_C->state = CO_SDO_ST_UPLOAD_LOCAL_TRANSFER; } else #endif @@ -922,7 +922,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ - else if (SDO_C->state == CO_SDO_ST_LOCAL_TRANSFER) { + else if (SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) { if (SDO_C->SDO->state != 0) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index aea1f5f6..ac82324f 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -69,9 +69,24 @@ extern "C" { */ +/** + * Internal state flags indicate type of transfer + * + * These flags correspond to the upper nibble of the SDO state machine states + * and can be used to determine the type of state an SDO object is in. + */ +#define CO_SDO_ST_FLAG_DOWNLOAD 0x10U +#define CO_SDO_ST_FLAG_UPLOAD 0x20U +#define CO_SDO_ST_FLAG_BLOCK 0x40U + /** * Internal states of the SDO state machine. * + * Upper nibble of byte indicates type of state: + * 0x10: Download + * 0x20: Upload + * 0x40: Block Mode + * * Note: CANopen has little endian byte order. */ typedef enum { @@ -81,19 +96,19 @@ typedef enum { * communication. * - SDO server is waiting for client request. */ CO_SDO_ST_IDLE = 0x00U, -/** - * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, - * SDO client is the same device as SDO server. Transfer data directly without - * communication on CAN. - * - SDO server does not use this state. */ -CO_SDO_ST_LOCAL_TRANSFER = 0x01U, /** * - SDO client or server may send SDO abort message in case of error: * - byte 0: @b 10000000 binary. * - byte 1..3: Object index and subIndex. * - byte 4..7: #CO_SDO_abortCode_t. */ -CO_SDO_ST_ABORT = 0x02U, +CO_SDO_ST_ABORT = 0x01U, +/** + * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, + * SDO client is the same device as SDO server. Transfer data directly without + * communication on CAN. + * - SDO server does not use this state. */ +CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER = 0x10U, /** * - SDO client initiates SDO download: * - byte 0: @b 0010nnes binary: (nn: if e=s=1, number of data bytes, that do @@ -128,6 +143,12 @@ CO_SDO_ST_DOWNLOAD_SEGMENT_REQ = 0x13U, * - If c was set to 1, then communication ends here. */ CO_SDO_ST_DOWNLOAD_SEGMENT_RSP = 0x14U, +/** + * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, + * SDO client is the same device as SDO server. Transfer data directly without + * communication on CAN. + * - SDO server does not use this state. */ +CO_SDO_ST_UPLOAD_LOCAL_TRANSFER = 0x20U, /** * - SDO client initiates SDO upload: * - byte 0: @b 01000000 binary. @@ -169,7 +190,7 @@ CO_SDO_ST_UPLOAD_SEGMENT_RSP = 0x24U, * - byte 1..3: Object index and subIndex. * - byte 4..7: If s=1, then size of data for block download is indicated here. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ -CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ = 0x31U, +CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ = 0x51U, /** * - SDO client waits for response. * - SDO server responses: @@ -179,7 +200,7 @@ CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ = 0x31U, * - byte 4: blksize: Number of segments per block that shall be used by the * client for the following block download with 0 < blksize < 128. * - byte 5..7: Reserved. */ -CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP = 0x32U, +CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP = 0x52U, /** * - SDO client sends 'blksize' segments of data in sequence: * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be downloaded, @@ -187,7 +208,7 @@ CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP = 0x32U, * 1..127. * - byte 1..7: At most 7 bytes of segment data to be downloaded. * - SDO server reads sequence of 'blksize' blocks. */ -CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x33U, +CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x53U, /** * - SDO client waits for response. * - SDO server responses: @@ -202,7 +223,7 @@ CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x33U, * - byte 3..7: Reserved. * - If c was set to 1, then communication enters SDO block download end phase. */ -CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP = 0x34U, +CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP = 0x54U, /** * - SDO client sends SDO block download end: * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not @@ -210,7 +231,7 @@ CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP = 0x34U, * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. * - byte 3..7: Reserved. * - SDO server waits for client request. */ -CO_SDO_ST_DOWNLOAD_BLK_END_REQ = 0x35U, +CO_SDO_ST_DOWNLOAD_BLK_END_REQ = 0x55U, /** * - SDO client waits for response. * - SDO server responses: @@ -218,7 +239,7 @@ CO_SDO_ST_DOWNLOAD_BLK_END_REQ = 0x35U, * - byte 1..7: Reserved. * - Block download successfully ends here. */ -CO_SDO_ST_DOWNLOAD_BLK_END_RSP = 0x36U, +CO_SDO_ST_DOWNLOAD_BLK_END_RSP = 0x56U, /** * - SDO client initiates SDO block upload: @@ -231,7 +252,7 @@ CO_SDO_ST_DOWNLOAD_BLK_END_RSP = 0x36U, * upload protocol #CO_SDO_ST_UPLOAD_INITIATE_RSP. * - byte 6..7: Reserved. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ -CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x41U, +CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x61U, /** * - SDO client waits for response. * - SDO server responses: @@ -241,13 +262,13 @@ CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x41U, * - byte 4..7: If s=1, then size of data for block upload is indicated here. * - If enabled by pst, then server may alternatively response with * #CO_SDO_ST_UPLOAD_INITIATE_RSP */ -CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP = 0x42U, +CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP = 0x62U, /** * - SDO client sends second initiate for SDO block upload: * - byte 0: @b 10100011 binary. * - byte 1..7: Reserved. * - SDO server waits for client request. */ -CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2 = 0x43U, +CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2 = 0x63U, /** * - SDO client reads sequence of 'blksize' blocks. * - SDO server sends 'blksize' segments of data in sequence: @@ -255,7 +276,7 @@ CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2 = 0x43U, * enter SDO block upload end phase; nnnnnnn is sequence number of segment, * 1..127. * - byte 1..7: At most 7 bytes of segment data to be uploaded. */ -CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x44U, +CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x64U, /** * - SDO client responses: * - byte 0: @b 10100010 binary. @@ -269,7 +290,7 @@ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x44U, * - byte 3..7: Reserved. * - SDO server waits for response. * - If c was set to 1, then communication enters SDO block upload end phase. */ -CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x45U, +CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x65U, /** * - SDO client waits for server request. * - SDO server sends SDO block upload end: @@ -277,7 +298,7 @@ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x45U, * contain data) * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. * - byte 3..7: Reserved. */ -CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x46U, +CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x66U, /** * - SDO client responses: * - byte 0: @b 10100001 binary. @@ -287,7 +308,7 @@ CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x46U, * with client response. Client may then start next SDO communication * immediately. */ -CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x47U, +CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x67U, /* old state names, will be removed */ CO_SDO_ST_DOWNLOAD_INITIATE = 0xA1U, From 7b66b10dff430cd35f049a0de1cbb487ae8bc27d Mon Sep 17 00:00:00 2001 From: Carsten Frank <44053860+cfr-mir@users.noreply.github.com> Date: Thu, 13 Aug 2020 23:57:46 +0200 Subject: [PATCH 112/520] Fix lssAddress copy (#221) --- 305/CO_LSSslave.c | 4 ++-- 305/CO_LSSslave.h | 2 +- CANopen.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 01d251ea..2772ac59 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -192,7 +192,7 @@ static void CO_LSSslave_receive(void *object, void *msg) /******************************************************************************/ CO_ReturnError_t CO_LSSslave_init( CO_LSSslave_t *LSSslave, - CO_LSS_address_t lssAddress, + CO_LSS_address_t *lssAddress, uint16_t *pendingBitRate, uint8_t *pendingNodeID, CO_CANmodule_t *CANdevRx, @@ -218,7 +218,7 @@ CO_ReturnError_t CO_LSSslave_init( memset(LSSslave, 0, sizeof(CO_LSSslave_t)); /* Configure object variables */ - memcpy(&LSSslave->lssAddress, &lssAddress, sizeof(LSSslave->lssAddress)); + memcpy(&LSSslave->lssAddress, lssAddress, sizeof(LSSslave->lssAddress)); LSSslave->lssState = CO_LSS_STATE_WAITING; LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index 07c33b71..ac03670a 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -158,7 +158,7 @@ typedef struct{ */ CO_ReturnError_t CO_LSSslave_init( CO_LSSslave_t *LSSslave, - CO_LSS_address_t lssAddress, + CO_LSS_address_t *lssAddress, uint16_t *pendingBitRate, uint8_t *pendingNodeID, CO_CANmodule_t *CANdevRx, diff --git a/CANopen.c b/CANopen.c index 7ed99017..053a733c 100644 --- a/CANopen.c +++ b/CANopen.c @@ -611,7 +611,7 @@ CO_ReturnError_t CO_LSSinit(uint8_t *nodeId, lssAddress.identity.vendorID = OD_identity.vendorID; err = CO_LSSslave_init(CO->LSSslave, - lssAddress, + &lssAddress, bitRate, nodeId, CO->CANmodule[0], From a528eb1669e6582dae18c8ffcaeb961400cdce7d Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 14 Sep 2020 15:50:21 +0200 Subject: [PATCH 113/520] Better organised configuration macros (CO_config.h): - rearranged and better documented - default values moved from CO_driver.h into appropriate files - rearranged also in CO_driver_target.h files - parts of the stack or whole objects can be disabled. - configuration is verified for depencies Additional: - renamed some members of CO_Default_CAN_ID_t - moved helpers CO_setUint32() etc from CO_SDOserver.h into CO_driver.h. - change wrong CO_ERROR_PARAMETERS to CO_ERROR_ILLEGAL_ARGUMENT. - renamed CO_ERROR_PARAMETERS to CO_ERROR_OD_PARAMETERS --- 301/CO_Emergency.c | 7 +- 301/CO_Emergency.h | 27 +- 301/CO_HBconsumer.c | 4 + 301/CO_HBconsumer.h | 18 +- 301/CO_NMT_Heartbeat.h | 13 +- 301/CO_PDO.h | 19 +- 301/CO_SDOclient.c | 27 +- 301/CO_SDOclient.h | 18 +- 301/CO_SDOserver.c | 3 - 301/CO_SDOserver.h | 62 +--- 301/CO_SYNC.c | 5 +- 301/CO_SYNC.h | 17 +- 301/CO_TIME.h | 14 +- 301/CO_config.h | 535 +++++++++++++++++++++++++---------- 301/CO_driver.h | 118 ++++---- 301/CO_fifo.c | 35 ++- 301/CO_fifo.h | 50 ++-- 301/crc16-ccitt.c | 32 +-- 301/crc16-ccitt.h | 31 +- 303/CO_LEDs.c | 3 + 303/CO_LEDs.h | 16 +- 304/CO_GFC.c | 4 + 304/CO_GFC.h | 18 +- 304/CO_SRDO.c | 11 +- 304/CO_SRDO.h | 20 +- 305/CO_LSS.h | 12 + 305/CO_LSSmaster.c | 10 +- 305/CO_LSSmaster.h | 10 +- 305/CO_LSSslave.c | 9 +- 305/CO_LSSslave.h | 10 +- 309/CO_gateway_ascii.c | 19 +- 309/CO_gateway_ascii.h | 21 +- CANopen.c | 20 +- CANopen.h | 59 ++-- example/CO_driver_target.h | 139 +++++---- extra/CO_trace.c | 8 +- extra/CO_trace.h | 22 +- socketCAN/CO_Linux_threads.h | 2 + socketCAN/CO_driver.c | 6 +- socketCAN/CO_driver_target.h | 107 ++++--- 40 files changed, 988 insertions(+), 573 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index e1ed1e10..231f4c11 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -23,13 +23,16 @@ * limitations under the License. */ - #include -#include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" +/* verify configuration */ +#if CO_CONFIG_EM_ERR_STATUS_BITS_COUNT < (6*8) \ + || CO_CONFIG_EM_ERR_STATUS_BITS_COUNT > 256 +#error CO_CONFIG_EM_ERR_STATUS_BITS_COUNT is not correct +#endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER /* diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 3e5ff3bc..73e87173 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -23,10 +23,30 @@ * limitations under the License. */ - #ifndef CO_EMERGENCY_H #define CO_EMERGENCY_H +#include "301/CO_driver.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_EM +#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER) +#endif +#ifndef CO_CONFIG_EM_ERR_STATUS_BITS_COUNT +#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) +#endif +#ifndef CO_CONFIG_ERR_CONDITION_GENERIC +#define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0) +#endif +#ifndef CO_CONFIG_ERR_CONDITION_COMMUNICATION +#define CO_CONFIG_ERR_CONDITION_COMMUNICATION (em->errorStatusBits[2] \ + || em->errorStatusBits[3]) +#endif +#ifndef CO_CONFIG_ERR_CONDITION_MANUFACTURER +#define CO_CONFIG_ERR_CONDITION_MANUFACTURER (em->errorStatusBits[8] \ + || em->errorStatusBits[9]) +#endif + #ifdef __cplusplus extern "C" { #endif @@ -462,9 +482,10 @@ void CO_EM_process( #endif +/** @} */ /* CO_Emergency */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* CO_EMERGENCY_H */ diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index a9d90345..6d20662b 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -29,6 +29,8 @@ #include "301/CO_NMT_Heartbeat.h" #include "301/CO_HBconsumer.h" +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + /* * Read received message from CAN module. * @@ -513,3 +515,5 @@ int8_t CO_HBconsumer_getNmtState( return -1; } #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT */ + +#endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE */ diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index a8ded661..2a317599 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -23,10 +23,18 @@ * limitations under the License. */ - #ifndef CO_HB_CONS_H #define CO_HB_CONS_H +#include "301/CO_driver.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_HB_CONS +#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE) +#endif + +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif @@ -338,11 +346,15 @@ int8_t CO_HBconsumer_getNmtState( CO_HBconsumer_t *HBcons, uint8_t idx, CO_NMT_internalState_t *nmtState); + #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT */ +/** @} */ /* CO_HBconsumer */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE */ + +#endif /* CO_HB_CONS_H */ diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 5e235d5b..36816cdb 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -23,7 +23,6 @@ * limitations under the License. */ - #ifndef CO_NMT_HEARTBEAT_H #define CO_NMT_HEARTBEAT_H @@ -31,6 +30,11 @@ #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_NMT +#define CO_CONFIG_NMT (0) +#endif + #ifdef __cplusplus extern "C" { #endif @@ -270,12 +274,13 @@ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, CO_NMT_command_t command, uint8_t nodeID); -#endif -/** @} */ +#endif /* (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER */ + +/** @} */ /* CO_NMT_Heartbeat */ #ifdef __cplusplus } #endif /*__cplusplus*/ -#endif +#endif /* CO_NMT_HEARTBEAT_H */ diff --git a/301/CO_PDO.h b/301/CO_PDO.h index b1fd2498..14d56877 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -23,17 +23,21 @@ * limitations under the License. */ +#ifndef CO_PDO_H +#define CO_PDO_H + #include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" #include "301/CO_NMT_Heartbeat.h" -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE #include "301/CO_SYNC.h" -#endif - -#ifndef CO_PDO_H -#define CO_PDO_H +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_PDO +#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ + CO_CONFIG_TPDO_ENABLE | \ + CO_CONFIG_PDO_SYNC_ENABLE) +#endif #ifdef __cplusplus extern "C" { @@ -426,9 +430,10 @@ void CO_TPDO_process( uint32_t timeDifference_us, uint32_t *timerNext_us); +/** @} */ /* CO_PDO */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* CO_PDO_H */ diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 05dff9e1..4e859ef2 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -24,19 +24,28 @@ * limitations under the License. */ - #include "301/CO_SDOclient.h" +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) && \ - !((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) -#error If CO_CONFIG_SDO_CLI_BLOCK is enabled, then CO_CONFIG_SDO_CLI_SEGMENTED \ - must be enabled also! -#endif +/* verify configuration */ #if CO_CONFIG_SDO_CLI_BUFFER_SIZE < 7 -#error CO_CONFIG_SDO_CLI_BUFFER_SIZE must be set to 7 or more! + #error CO_CONFIG_SDO_CLI_BUFFER_SIZE must be set to 7 or more. +#endif +#if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) + #error CO_CONFIG_FIFO_ENABLE must be enabled. +#endif +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + #if !((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) + #error CO_CONFIG_SDO_CLI_SEGMENTED must be enabled. + #endif + #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) + #error CO_CONFIG_FIFO_ALT_READ must be enabled. + #endif + #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) + #error CO_CONFIG_FIFO_CRC16_CCITT must be enabled. + #endif #endif - /* default 'protocol switch threshold' size for block transfer */ #ifndef CO_CONFIG_SDO_CLI_PST @@ -1481,3 +1490,5 @@ void CO_SDOclientClose(CO_SDOclient_t *SDO_C) { SDO_C->state = CO_SDO_ST_IDLE; } } + +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE */ diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index e7a8f840..d8bf90fe 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -24,7 +24,6 @@ * limitations under the License. */ - #ifndef CO_SDO_CLIENT_H #define CO_SDO_CLIENT_H @@ -32,6 +31,16 @@ #include "301/CO_SDOserver.h" #include "301/CO_fifo.h" +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_SDO_CLI +#define CO_CONFIG_SDO_CLI (0) +#endif +#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 +#endif + +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif @@ -426,9 +435,12 @@ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, */ void CO_SDOclientClose(CO_SDOclient_t *SDO_C); +/** @} */ /* CO_SDOclient */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE */ + +#endif /* CO_SDO_CLIENT_H */ diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index cf53f01c..a02121b8 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -42,9 +42,6 @@ #if CO_CONFIG_SDO_BUFFER_SIZE < 7 #error CO_CONFIG_SDO_BUFFER_SIZE must be greater than 7 #endif -#if ((CO_CONFIG_SDO) & CO_CONFIG_SDO_BLOCK) && !((CO_CONFIG_SDO) & CO_CONFIG_SDO_SEGMENTED) - #error CO_CONFIG_SDO_BLOCK is enabled, CO_CONFIG_SDO_SEGMENTED must be enabled also. -#endif static void CO_SDO_receive_done(CO_SDO_t *SDO){ #if CO_SDO_RX_DATA_SIZE > 1 diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index ac82324f..b9011d0b 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -29,6 +29,20 @@ #include +#include "301/CO_driver.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_SDO_SRV +#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED) +#endif +#ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE +#define CO_CONFIG_SDO_SRV_BUFFER_SIZE 32 +#endif + +#define CO_CONFIG_SDO CO_CONFIG_SDO_SRV +#define CO_CONFIG_SDO_BUFFER_SIZE CO_CONFIG_SDO_SRV_BUFFER_SIZE + + #ifdef __cplusplus extern "C" { #endif @@ -849,54 +863,6 @@ typedef struct{ }CO_SDO_t; -/** - * Helper function returns uint16 from byte array. - * - * @param data Location of source data. - * @return Variable of type uint16_t. - */ -static inline uint16_t CO_getUint16(const uint8_t data[]){ - uint16_t value; - memcpy(&value, data, sizeof(value)); - return value; -} - - -/** - * Helper function returns uint32 from byte array. - * - * @param data Location of source data. - * @return Variable of type uint32_t. - */ -static inline uint32_t CO_getUint32(const uint8_t data[]){ - uint32_t value; - memcpy(&value, data, sizeof(value)); - return value; -} - - -/** - * Helper function writes uint16 to byte array. - * - * @param data Location of destination data. - * @param value Variable of type uint16_t to be written into data. - */ -static inline void CO_setUint16(uint8_t data[], const uint16_t value){ - memcpy(data, &value, sizeof(value)); -} - - -/** - * Helper function writes uint32 to byte array. - * - * @param data Location of destination data. - * @param value Variable of type uint32_t to be written into data. - */ -static inline void CO_setUint32(uint8_t data[], const uint32_t value){ - memcpy(data, &value, sizeof(value)); -} - - /** * Copy 2 data bytes from source to destination. Swap bytes if * microcontroller is big-endian. diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index a08dde2d..a9d63dd5 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -24,12 +24,13 @@ */ -#include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" #include "301/CO_NMT_Heartbeat.h" #include "301/CO_SYNC.h" +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + /* * Read received message from CAN module. * @@ -434,3 +435,5 @@ CO_SYNC_status_t CO_SYNC_process( return ret; } + +#endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE */ diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 9cad1ea6..f2e5836f 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -23,10 +23,18 @@ * limitations under the License. */ - #ifndef CO_SYNC_H #define CO_SYNC_H +#include "301/CO_driver.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_SYNC +#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER) +#endif + +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif @@ -189,9 +197,12 @@ CO_SYNC_status_t CO_SYNC_process( uint32_t ObjDict_synchronousWindowLength, uint32_t *timerNext_us); +/** @} */ /* CO_SYNC */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE */ + +#endif /* CO_SYNC_H */ diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 89a972df..f7dcefa7 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -23,12 +23,18 @@ * limitations under the License. */ - #ifndef CO_TIME_H #define CO_TIME_H +#include "301/CO_driver.h" #include "CO_OD.h" +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_TIME +#define CO_CONFIG_TIME (0) +#endif + +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -176,10 +182,12 @@ uint8_t CO_TIME_process( CO_TIME_t *TIME, uint32_t timeDifference_us); -/** @} */ +/** @} */ /* CO_TIME */ #ifdef __cplusplus } #endif /*__cplusplus*/ -#endif +#endif /* (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE */ + +#endif /* CO_TIME_H */ diff --git a/301/CO_config.h b/301/CO_config.h index 23970d3c..44410e0e 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -37,23 +37,28 @@ extern "C" { * * Stack configuration macros specify, which parts of the stack will be enabled. * - * Default values for stack configuration macros are set in CO_driver.h file. - * They can be overridden by CO_driver_target.h file. If specified so, they can - * further be overridden by CO_driver_custom.h file. + * Default values for stack configuration macros are set in corresponding + * header files. The same default values are also provided in this file, but + * only for documentation generator. Default values can be overridden by + * CO_driver_target.h file. If specified so, they can further be overridden by + * CO_driver_custom.h file. * * Stack configuration macro is specified as bits, where each bit * enables/disables some part of the configurable CANopenNode object. Flags are * used for enabling or checking specific bit. Multiple flags can be ORed * together. * - * Configuration macros may be in relation with @ref CO_NO_OBJ macros from - * CANopen.h file. Former enables/disables stack functionalities, latter - * enables/disables objects in object dictionary. Note that some objects in - * object dictionary may need some configuration macros to be enabled. + * Some functionalities of CANopenNode objects, enabled by configuration macros, + * requires some objects from Object Dictionary to exist. Object Dictionary + * configuration must match @ref CO_STACK_CONFIG. * @{ */ +/** + * @defgroup CO_STACK_CONFIG_COMMON Common definitions + * @{ + */ /** * Enable custom callback after CAN receive * @@ -72,7 +77,6 @@ extern "C" { */ #define CO_CONFIG_FLAG_CALLBACK_PRE 0x1000 - /** * Enable calculation of timerNext_us variable. * @@ -83,214 +87,254 @@ extern "C" { */ #define CO_CONFIG_FLAG_TIMERNEXT 0x2000 +/** + * Enable dynamic behaviour of Object Dictionary variables + * + * Some CANopen objects uses Object Dictionary variables as arguments to + * initialization functions, which are processed in communication reset section. + * If this flag is set, then writing to OD variable will reconfigure + * corresponding CANopen object also during CANopen normal operation. + * + * This flag is common to multiple configuration macros. + */ +#define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000 +/** @} */ /* CO_STACK_CONFIG_COMMON */ + +/** + * @defgroup CO_STACK_CONFIG_NMT_HB NMT master/slave and HB producer/consumer + * @{ + */ /** - * Configuration of NMT_Heartbeat object + * Configuration of @ref CO_NMT_Heartbeat. * * Possible flags, can be ORed: + * - CO_CONFIG_NMT_CALLBACK_CHANGE - Enable custom callback after NMT + * state changes. Callback is configured by + * CO_NMT_initCallbackChanged(). + * - CO_CONFIG_NMT_MASTER - Enable simple NMT master * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received NMT CAN message. * Callback is configured by CO_NMT_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_NMT_process(). - * - CO_CONFIG_NMT_CALLBACK_CHANGE - Enable custom callback after NMT - * state changes. Callback is configured by - * CO_NMT_initCallbackChanged(). - * - CO_CONFIG_NMT_MASTER - Enable simple NMT master */ #ifdef CO_DOXYGEN -#define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_NMT_MASTER0) +#define CO_CONFIG_NMT (0) #endif #define CO_CONFIG_NMT_CALLBACK_CHANGE 0x01 #define CO_CONFIG_NMT_MASTER 0x02 - /** - * Configuration of SDO server object + * Configuration of @ref CO_HBconsumer * * Possible flags, can be ORed: * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received SDO CAN message. - * Callback is configured by CO_SDO_initCallbackPre(). + * received heartbeat CAN message. + * Callback is configured by CO_HBconsumer_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable - * inside CO_SDO_process(). - * - CO_CONFIG_SDO_SEGMENTED - Enable SDO server segmented transfer. - * - CO_CONFIG_SDO_BLOCK - Enable SDO server block transfer. If set, then - * CO_CONFIG_SDO_SEGMENTED must also be set. + * inside CO_HBconsumer_process(). + * - CO_CONFIG_HB_CONS_ENABLE - Enable heartbeat consumer. + * - CO_CONFIG_HB_CONS_CALLBACK_CHANGE - Enable custom callback after NMT + * state of the monitored node changes. Callback is configured by + * CO_HBconsumer_initCallbackNmtChanged(). + * - CO_CONFIG_HB_CONS_CALLBACK_MULTI - Enable multiple custom callbacks, which + * can be configured for each monitored node. Callback are configured by + * CO_HBconsumer_initCallbackHeartbeatStarted(), + * CO_HBconsumer_initCallbackTimeout() and + * CO_HBconsumer_initCallbackRemoteReset() functions. + * - CO_CONFIG_HB_CONS_QUERY_FUNCT - Enable functions for query HB state or + * NMT state of the specific monitored node. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_SEGMENTED | CO_CONFIG_SDO_BLOCK) +#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE) #endif -/* TODO with new OD */ -#define CO_CONFIG_SDO_SEGMENTED 0x01 -#define CO_CONFIG_SDO_BLOCK 0x02 +#define CO_CONFIG_HB_CONS_ENABLE 0x01 +#define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x02 +#define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x04 +#define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x08 +/** @} */ /* CO_STACK_CONFIG_NMT_HB */ /** - * Size of the internal data buffer for the SDO server. - * - * Size must be at least equal to size of largest variable in - * @ref CO_SDO_objectDictionary. If data type is domain, data length is not - * limited to SDO buffer size. If block transfer is implemented, value should be - * set to 889. - * - * Value can be in range from 7 to 889 bytes. + * @defgroup CO_STACK_CONFIG_EMERGENCY Emergency producer/consumer + * @{ */ -#ifdef CO_DOXYGEN -#define CO_CONFIG_SDO_BUFFER_SIZE 32 -#endif - - /** - * Configuration of Emergency object + * Configuration of @ref CO_Emergency * * Possible flags, can be ORed: + * - CO_CONFIG_EM_PRODUCER - Enable emergency producer. + * - CO_CONFIG_EM_HISTORY - Enable error history - OD object 0x1003, + * "Pre-defined error field" + * - CO_CONFIG_EM_CONSUMER - Enable emergency consumer. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * emergency condition by CO_errorReport() or CO_errorReset() call. * Callback is configured by CO_EM_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_EM_process(). - * - CO_CONFIG_EM_CONSUMER - Enable emergency consumer. + * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of Emergency + * (Writing to object 0x1014 or 0x1015 re-configures the object). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_EM (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_EM_CONSUMER) +#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER) #endif -#define CO_CONFIG_EM_CONSUMER 0x01 - +#define CO_CONFIG_EM_PRODUCER 0x01 +#define CO_CONFIG_EM_HISTORY 0x02 +#define CO_CONFIG_EM_CONSUMER 0x04 /** - * Configuration of Heartbeat Consumer + * Maximum number of @ref CO_EM_errorStatusBits * - * Possible flags, can be ORed: - * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received heartbeat CAN message. - * Callback is configured by CO_HBconsumer_initCallbackPre(). - * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable - * inside CO_HBconsumer_process(). - * - CO_CONFIG_HB_CONS_CALLBACK_CHANGE - Enable custom callback after NMT - * state of the monitored node changes. Callback is configured by - * CO_HBconsumer_initCallbackNmtChanged(). - * - CO_CONFIG_HB_CONS_CALLBACK_MULTI - Enable multiple custom callbacks, which - * can be configured for each monitored node. Callback are configured by - * CO_HBconsumer_initCallbackHeartbeatStarted(), - * CO_HBconsumer_initCallbackTimeout() and - * CO_HBconsumer_initCallbackRemoteReset() functions. - * - CO_CONFIG_HB_CONS_QUERY_FUNCT - Enable functions for query HB state or - * NMT state of the specific monitored node. + * Stack uses 6*8 = 48 @ref CO_EM_errorStatusBits others are free to use by + * manufacturer. Allowable value range is from 48 to 256 bits. Default is 80. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_HB_CONS_CALLBACK_CHANGE | CO_CONFIG_HB_CONS_CALLBACK_MULTI | CO_CONFIG_HB_CONS_QUERY_FUNCT) +#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) #endif -#define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x01 -#define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x02 -#define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x04 /** - * Configuration of GFC - * - * Possible flags, can be ORed: - * - CO_CONFIG_GFC_CONSUMER - Enable the GFC consumer - * - CO_CONFIG_GFC_PRODUCER - Enable the GFC producer + * Condition for calculating CANopen Error register, "generic" error bit. + * + * Condition must observe suitable @ref CO_EM_errorStatusBits and use + * corresponding member of errorStatusBits array from CO_EM_t to calculate the + * condition. See also @ref CO_errorRegister_t. + * + * @warning Size of @ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT must be large + * enough. (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT/8) must be larger than index of + * array member in em->errorStatusBits[index]. + * + * em->errorStatusBits[5] should be included in the condition, because they are + * used by the stack. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_GFC (CO_CONFIG_GFC_CONSUMER | CO_CONFIG_GFC_PRODUCER) +#define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0) #endif -#define CO_CONFIG_GFC_CONSUMER 0x01 -#define CO_CONFIG_GFC_PRODUCER 0x02 /** - * Configuration of SRDO + * Condition for calculating CANopen Error register, "communication" error bit. + * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. * - * Possible flags, can be ORed: - * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received RSRDO CAN message. - * Callback is configured by CO_SRDO_initCallbackPre(). - * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable - * inside CO_SRDO_process() (Tx SRDO only). - * - CO_CONFIG_RSRDO_CALLS_EXTENSION - Enable calling configured extension - * callbacks when received RSRDO CAN message modifies OD entries. - * - CO_CONFIG_TRSRDO_CALLS_EXTENSION - Enable calling configured extension - * callbacks before TSRDO CAN message is sent. + * em->errorStatusBits[2] and em->errorStatusBits[3] must be included in the + * condition, because they are used by the stack. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SRDO (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SRDO_CHECK_TX | CO_CONFIG_RSRDO_CALLS_EXTENSION | CO_CONFIG_TSRDO_CALLS_EXTENSION) +#define CO_CONFIG_ERR_CONDITION_COMMUNICATION (em->errorStatusBits[2] || em->errorStatusBits[3]) #endif -#define CO_CONFIG_SRDO_CHECK_TX 0x01 -#define CO_CONFIG_RSRDO_CALLS_EXTENSION 0x02 -#define CO_CONFIG_TSRDO_CALLS_EXTENSION 0x04 /** - * SRDO Tx time delay - * - * minimum time between the first and second SRDO (Tx) message - * in us + * Condition for calculating CANopen Error register, "current" error bit. + * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. + * Macro is not defined by default, so no error is verified. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 +#define CO_CONFIG_ERR_CONDITION_CURRENT #endif /** - * Configuration of PDO + * Condition for calculating CANopen Error register, "voltage" error bit. + * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. + * Macro is not defined by default, so no error is verified. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_ERR_CONDITION_VOLTAGE +#endif + +/** + * Condition for calculating CANopen Error register, "temperature" error bit. + * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. + * Macro is not defined by default, so no error is verified. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_ERR_CONDITION_TEMPERATURE +#endif + +/** + * Condition for calculating CANopen Error register, "device profile" error bit. + * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. + * Macro is not defined by default, so no error is verified. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_ERR_CONDITION_DEV_PROFILE +#endif + +/** + * Condition for calculating CANopen Error register, "manufacturer" error bit. + * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. * - * Possible flags, can be ORed: - * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received RPDO CAN message. - * Callback is configured by CO_RPDO_initCallbackPre(). - * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable - * inside CO_TPDO_process(). - * - CO_CONFIG_PDO_SYNC_ENABLE - Enable SYNC object inside PDO objects. - * - CO_CONFIG_RPDO_CALLS_EXTENSION - Enable calling configured extension - * callbacks when received RPDO CAN message modifies OD entries. - * - CO_CONFIG_TPDO_CALLS_EXTENSION - Enable calling configured extension - * callbacks before TPDO CAN message is sent. + * em->errorStatusBits[8] and em->errorStatusBits[8] are pre-defined, but can + * be changed. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_RPDO_CALLS_EXTENSION | CO_CONFIG_TPDO_CALLS_EXTENSION) +#define CO_CONFIG_ERR_CONDITION_MANUFACTURER (em->errorStatusBits[8] || em->errorStatusBits[9]) #endif -#define CO_CONFIG_PDO_SYNC_ENABLE 0x01 -#define CO_CONFIG_RPDO_CALLS_EXTENSION 0x02 -#define CO_CONFIG_TPDO_CALLS_EXTENSION 0x04 +/** @} */ /* CO_STACK_CONFIG_EMERGENCY */ /** - * Configuration of SYNC + * @defgroup CO_STACK_CONFIG_SDO SDO server/client + * @{ + */ +/** + * Configuration of @ref CO_SDOserver * * Possible flags, can be ORed: + * - CO_CONFIG_SDO_SRV_SEGMENTED - Enable SDO server segmented transfer. + * - CO_CONFIG_SDO_SRV_BLOCK - Enable SDO server block transfer. If set, then + * CO_CONFIG_SDO_SRV_SEGMENTED must also be set. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received SYNC CAN message. - * Callback is configured by CO_SYNC_initCallbackPre(). + * received SDO CAN message. + * Callback is configured by CO_SDOserver_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable - * inside CO_SYNC_process(). + * inside CO_SDOserver_process(). + * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of additional SDO + * servers (Writing to object 0x1201+ re-configures the additional server). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT) +#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED) #endif +#define CO_CONFIG_SDO_SRV_SEGMENTED 0x02 +#define CO_CONFIG_SDO_SRV_BLOCK 0x04 +/** + * Size of the internal data buffer for the SDO server. + * + * If size is less than size of some variables in Object Dictionary, then data + * will be transferred to internal buffer in several segments. Minimum size is + * 8 or 899 (127*7) for block transfer. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SDO_SRV_BUFFER_SIZE 32 +#endif /** - * Configuration of SDO client object + * Configuration of @ref CO_SDOclient * * Possible flags, can be ORed: + * - CO_CONFIG_SDO_CLI_ENABLE - Enable SDO client. + * - CO_CONFIG_SDO_CLI_SEGMENTED - Enable SDO client segmented transfer. + * - CO_CONFIG_SDO_CLI_BLOCK - Enable SDO client block transfer. If set, then + * CO_CONFIG_SDO_CLI_SEGMENTED, CO_CONFIG_FIFO_ALT_READ and + * CO_CONFIG_FIFO_CRC16_CCITT must also be set. + * - CO_CONFIG_SDO_CLI_LOCAL - Enable local transfer, if Node-ID of the SDO + * server is the same as node-ID of the SDO client. (SDO client is the same + * device as SDO server.) Transfer data directly without communication on CAN. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received SDO CAN message. * Callback is configured by CO_SDOclient_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_SDOclientDownloadInitiate(), CO_SDOclientDownload(), * CO_SDOclientUploadInitiate(), CO_SDOclientUpload(). - * - CO_CONFIG_SDO_CLI_SEGMENTED - Enable SDO client segmented transfer. - * - CO_CONFIG_SDO_CLI_BLOCK - Enable SDO client block transfer. If set, then - * CO_CONFIG_SDO_CLI_SEGMENTED must also be set. - * - CO_CONFIG_SDO_CLI_LOCAL - Enable local transfer, if Node-ID of the SDO - * server is the same as node-ID of the SDO client. (SDO client is the same - * device as SDO server.) Transfer data directly without communication on CAN. + * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of SDO clients + * (Writing to object 0x1280+ re-configures the client). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO_CLI (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_SDO_CLI_SEGMENTED | CO_CONFIG_SDO_CLI_BLOCK | CO_CONFIG_SDO_CLI_LOCAL) +#define CO_CONFIG_SDO_CLI (0) #endif -#define CO_CONFIG_SDO_CLI_SEGMENTED 0x01 -#define CO_CONFIG_SDO_CLI_BLOCK 0x02 -#define CO_CONFIG_SDO_CLI_LOCAL 0x04 - +#define CO_CONFIG_SDO_CLI_ENABLE 0x01 +#define CO_CONFIG_SDO_CLI_SEGMENTED 0x02 +#define CO_CONFIG_SDO_CLI_BLOCK 0x04 +#define CO_CONFIG_SDO_CLI_LOCAL 0x08 /** * Size of the internal data buffer for the SDO client. @@ -306,57 +350,187 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 #endif +/** @} */ /* CO_STACK_CONFIG_SDO */ + + +/** + * @defgroup CO_STACK_CONFIG_SYNC_PDO SYNC and PDO producer/consumer + * @{ + */ +/** + * Configuration of @ref CO_SYNC + * + * Possible flags, can be ORed: + * - CO_CONFIG_SYNC_ENABLE - Enable SYNC object and SYNC consumer. + * - CO_CONFIG_SYNC_PRODUCER - Enable SYNC producer. + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received SYNC CAN message. + * Callback is configured by CO_SYNC_initCallbackPre(). + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_SYNC_process(). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER) +#endif +#define CO_CONFIG_SYNC_ENABLE 0x01 +#define CO_CONFIG_SYNC_PRODUCER 0x02 + +/** + * Configuration of @ref CO_PDO + * + * Possible flags, can be ORed: + * - CO_CONFIG_RPDO_ENABLE - Enable receive PDO objects. + * - CO_CONFIG_TPDO_ENABLE - Enable transmit PDO objects. + * - CO_CONFIG_RPDO_CALLS_EXTENSION - Enable calling configured extension + * callbacks when received RPDO CAN message modifies OD entries. + * - CO_CONFIG_TPDO_CALLS_EXTENSION - Enable calling configured extension + * callbacks before TPDO CAN message is sent. + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received RPDO CAN message. + * Callback is configured by CO_RPDO_initCallbackPre(). + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_TPDO_process(). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE) +#endif +#define CO_CONFIG_PDO_SYNC_ENABLE 0x01 +#define CO_CONFIG_RPDO_CALLS_EXTENSION 0x02 +#define CO_CONFIG_TPDO_CALLS_EXTENSION 0x04 +/** @} */ /* CO_STACK_CONFIG_SYNC_PDO */ /** - * Configuration of TIME + * @defgroup CO_STACK_CONFIG_TIME Time producer/consumer + * @{ + */ +/** + * Configuration of @ref CO_TIME * * Possible flags, can be ORed: + * - CO_CONFIG_TIME_ENABLE - Enable TIME object and TIME consumer. + * - CO_CONFIG_TIME_PRODUCER - Enable TIME producer. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received TIME CAN message. * Callback is configured by CO_TIME_initCallbackPre(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) +#define CO_CONFIG_TIME (0) #endif +#define CO_CONFIG_TIME_ENABLE 0x01 +#define CO_CONFIG_TIME_PRODUCER 0x02 +/** @} */ /* CO_STACK_CONFIG_TIME */ /** - * Configuration of LEDs object + * @defgroup CO_STACK_CONFIG_LEDS CANopen LED diodes + * Specified in standard CiA 303-3 + * @{ + */ +/** + * Configuration of @ref CO_LEDs * * Possible flags, can be ORed: + * - CO_CONFIG_LEDS_ENABLE - Enable calculation of the CANopen LED indicators. * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_NMT_process(). - * - CO_CONFIG_LEDS_ENABLE - Enable calculation of the CANopen LED indicators. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_LEDS (CO_CONFIG_FLAG_TIMERNEXT | CO_CONFIG_LEDS_ENABLE) +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE) #endif #define CO_CONFIG_LEDS_ENABLE 0x01 +/** @} */ /* CO_STACK_CONFIG_LEDS */ /** - * Configuration of LSS objects + * @defgroup CO_STACK_CONFIG_SRDO Safety Related Data Objects (SRDO) + * Specified in standard EN 50325-5 (CiA 304) + * @{ + */ +/** + * Configuration of @ref CO_GFC * * Possible flags, can be ORed: + * - CO_CONFIG_GFC_ENABLE - Enable the GFC object + * - CO_CONFIG_GFC_CONSUMER - Enable the GFC consumer + * - CO_CONFIG_GFC_PRODUCER - Enable the GFC producer + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GFC (0) +#endif +#define CO_CONFIG_GFC_ENABLE 0x01 +#define CO_CONFIG_GFC_CONSUMER 0x02 +#define CO_CONFIG_GFC_PRODUCER 0x04 + +/** + * Configuration of @ref CO_SRDO + * + * Possible flags, can be ORed: + * - CO_CONFIG_SRDO_ENABLE - Enable the SRDO object. + * - CO_CONFIG_SRDO_CHECK_TX - Enable checking data before sending. + * - CO_CONFIG_RSRDO_CALLS_EXTENSION - Enable calling configured extension + * callbacks when received RSRDO CAN message modifies OD entries. + * - CO_CONFIG_TRSRDO_CALLS_EXTENSION - Enable calling configured extension + * callbacks before TSRDO CAN message is sent. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received CAN message. - * Callback is configured by CO_LSSmaster_initCallbackPre(). + * received RSRDO CAN message. + * Callback is configured by CO_SRDO_initCallbackPre(). + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_SRDO_process() (Tx SRDO only). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SRDO (0) +#endif +#define CO_CONFIG_SRDO_ENABLE 0x01 +#define CO_CONFIG_SRDO_CHECK_TX 0x02 +#define CO_CONFIG_RSRDO_CALLS_EXTENSION 0x04 +#define CO_CONFIG_TSRDO_CALLS_EXTENSION 0x08 + +/** + * SRDO Tx time delay + * + * minimum time between the first and second SRDO (Tx) message + * in us + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 +#endif +/** @} */ /* CO_STACK_CONFIG_SRDO */ + + +/** + * @defgroup CO_STACK_CONFIG_LSS LSS master/slave + * Specified in standard CiA 305 + * @{ + */ +/** + * Configuration of @ref CO_LSS + * + * Possible flags, can be ORed: * - CO_CONFIG_LSS_SLAVE - Enable LSS slave * - CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND - Send LSS fastscan respond * directly from CO_LSSslave_receive() function. * - CO_CONFIG_LSS_MASTER - Enable LSS master + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received CAN message. + * Callback is configured by CO_LSSmaster_initCallbackPre(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | CO_CONFIG_LSS_MASTER ) +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE) #endif #define CO_CONFIG_LSS_SLAVE 0x01 #define CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND 0x02 #define CO_CONFIG_LSS_MASTER 0x10 +/** @} */ /* CO_STACK_CONFIG_LSS */ /** - * Configuration of gateway object usage. + * @defgroup CO_STACK_CONFIG_GATEWAY CANopen gateway + * Specified in standard CiA 309 + * @{ + */ +/** + * Configuration of @ref CO_CANopen_309_3 * * Gateway object is covered by standard CiA 309 - CANopen access from other * networks. It enables usage of the NMT master, SDO client and LSS master as a @@ -366,7 +540,9 @@ extern "C" { * - CO_CONFIG_GTW_MULTI_NET - Enable multiple network interfaces in gateway * device. This functionality is currently not implemented. * - CO_CONFIG_GTW_ASCII - Enable gateway device with ASCII mapping (CiA 309-3) - * - CO_CONFIG_GTW_ASCII_SDO - Enable SDO client + * If set, then CO_CONFIG_FIFO_ASCII_COMMANDS must also be set. + * - CO_CONFIG_GTW_ASCII_SDO - Enable SDO client. If set, then + * CO_CONFIG_FIFO_ASCII_DATATYPES must also be set. * - CO_CONFIG_GTW_ASCII_NMT - Enable NMT master * - CO_CONFIG_GTW_ASCII_LSS - Enable LSS master * - CO_CONFIG_GTW_ASCII_LOG - Enable non-standard message log read @@ -378,7 +554,7 @@ extern "C" { * LED diodes on terminal. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_GTW (CO_CONFIG_GTW_MULTI_NET | CO_CONFIG_GTW_ASCII | CO_CONFIG_GTW_ASCII_SDO | CO_CONFIG_GTW_ASCII_NMT | CO_CONFIG_GTW_ASCII_LSS | CO_CONFIG_GTW_ASCII_LOG | CO_CONFIG_GTW_ASCII_ERROR_DESC | CO_CONFIG_GTW_ASCII_PRINT_HELP | CO_CONFIG_GTW_ASCII_PRINT_LEDS) +#define CO_CONFIG_GTW (0) #endif #define CO_CONFIG_GTW_MULTI_NET 0x01 #define CO_CONFIG_GTW_ASCII 0x02 @@ -390,7 +566,6 @@ extern "C" { #define CO_CONFIG_GTW_ASCII_PRINT_HELP 0x80 #define CO_CONFIG_GTW_ASCII_PRINT_LEDS 0x100 - /** * Number of loops of #CO_SDOclientDownload() in case of block download * @@ -402,7 +577,6 @@ extern "C" { #define CO_CONFIG_GTW_BLOCK_DL_LOOP 1 #endif - /** * Size of command buffer in ASCII gateway object. * @@ -413,16 +587,93 @@ extern "C" { #define CO_CONFIG_GTWA_COMM_BUF_SIZE 200 #endif - /** * Size of message log buffer in ASCII gateway object. */ #ifdef CO_DOXYGEN #define CO_CONFIG_GTWA_LOG_BUF_SIZE 2000 #endif +/** @} */ /* CO_STACK_CONFIG_GATEWAY */ + + +/** + * @defgroup CO_STACK_CONFIG_CRC16 CRC 16 calculation + * Helper object + * @{ + */ +/** + * Configuration of @ref CO_crc16_ccitt calculation + * + * Possible flags, can be ORed: + * - CO_CONFIG_CRC16_ENABLE - Enable CRC16 calculation + * - CO_CONFIG_CRC16_EXTERNAL - CRC functions are defined externally + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_CRC16 (0) +#endif +#define CO_CONFIG_CRC16_ENABLE 0x01 +#define CO_CONFIG_CRC16_EXTERNAL 0x02 +/** @} */ /* CO_STACK_CONFIG_CRC16 */ + +/** + * @defgroup CO_STACK_CONFIG_FIFO FIFO buffer + * Helper object + * @{ + */ +/** + * Configuration of @ref CO_CANopen_301_fifo + * + * FIFO buffer is basically a simple first-in first-out circular data buffer. It + * is used by the SDO client and by the CANopen gateway. It has additional + * advanced functions for data passed to FIFO. + * + * + * Possible flags, can be ORed: + * - CO_CONFIG_FIFO_ENABLE - Enable FIFO buffer + * - CO_CONFIG_FIFO_ALT_READ - This must be enabled, when SDO client has + * CO_CONFIG_SDO_CLI_BLOCK enabled. See @ref CO_fifo_altRead(). + * - CO_CONFIG_FIFO_CRC16_CCITT - This must be enabled, when SDO client has + * CO_CONFIG_SDO_CLI_BLOCK enabled. It enables CRC calculation on data. + * - CO_CONFIG_FIFO_ASCII_COMMANDS - This must be enabled, when CANopen gateway + * has CO_CONFIG_GTW_ASCII enabled. It adds command handling functions. + * - CO_CONFIG_FIFO_ASCII_DATATYPES - This must be enabled, when CANopen gateway + * has CO_CONFIG_GTW_ASCII and CO_CONFIG_GTW_ASCII_SDO enabled. It adds + * datatype transform functions between binary and ascii, which are necessary + * for SDO client. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_FIFO (0) +#endif +#define CO_CONFIG_FIFO_ENABLE 0x01 +#define CO_CONFIG_FIFO_ALT_READ 0x02 +#define CO_CONFIG_FIFO_CRC16_CCITT 0x04 +#define CO_CONFIG_FIFO_ASCII_COMMANDS 0x08 +#define CO_CONFIG_FIFO_ASCII_DATATYPES 0x10 +/** @} */ /* CO_STACK_CONFIG_FIFO */ + + +/** + * @defgroup CO_STACK_CONFIG_TRACE Trace recorder + * Non standard object + * @{ + */ +/** + * Configuration of @ref CO_trace for recording variables over time. + * + * Possible flags, can be ORed: + * - CO_CONFIG_TRACE_ENABLE - Enable Trace recorder + * - CO_CONFIG_TRACE_OWN_INTTYPES - If set, then macros PRIu32("u" or "lu") + * and PRId32("d" or "ld") must be set. (File inttypes.h can not be included). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_TRACE (0) +#endif +#define CO_CONFIG_TRACE_ENABLE 0x01 +#define CO_CONFIG_TRACE_OWN_INTTYPES 0x02 +/** @} */ /* CO_STACK_CONFIG_TRACE */ -/** @} */ +/** @} */ /* CO_STACK_CONFIG */ #ifdef __cplusplus } diff --git a/301/CO_driver.h b/301/CO_driver.h index eca57bf8..1d87ab2c 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -23,10 +23,11 @@ * limitations under the License. */ - #ifndef CO_DRIVER_H #define CO_DRIVER_H +#include + #include "CO_config.h" #include "CO_driver_target.h" @@ -34,67 +35,6 @@ extern "C" { #endif - -/* Default stack configuration for most common configuration, may be overridden - * by CO_driver_target.h. For more information see file CO_config.h. */ -#ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT (0) -#endif - -#ifndef CO_CONFIG_SDO -#define CO_CONFIG_SDO (CO_CONFIG_SDO_SEGMENTED) -#endif - -#ifndef CO_CONFIG_SDO_BUFFER_SIZE -#define CO_CONFIG_SDO_BUFFER_SIZE 32 -#endif - -#ifndef CO_CONFIG_EM -#define CO_CONFIG_EM (0) -#endif - -#ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS (0) -#endif - -#ifndef CO_CONFIG_GFC -#define CO_CONFIG_GFC (0) -#endif - -#ifndef CO_CONFIG_SRDO -#define CO_CONFIG_SRDO (0) -#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 -#endif - -#ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO (CO_CONFIG_PDO_SYNC_ENABLE) -#endif - -#ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (0) -#endif - -#ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI (CO_CONFIG_SDO_CLI_SEGMENTED | \ - CO_CONFIG_SDO_CLI_LOCAL) -#endif - -#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE -#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 -#endif - -#ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE) -#endif - -#ifndef CO_CONFIG_LEDS -#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE) -#endif - -#ifndef CO_CONFIG_GTW -#define CO_CONFIG_GTW (0) -#endif - /** * @defgroup CO_driver Driver * @ingroup CO_CANopen_301 @@ -476,11 +416,11 @@ typedef enum { CO_CAN_ID_RPDO_3 = 0x400, /**< 0x400, Default RPDO3 (+nodeID) */ CO_CAN_ID_TPDO_4 = 0x480, /**< 0x480, Default TPDO4 (+nodeID) */ CO_CAN_ID_RPDO_4 = 0x500, /**< 0x500, Default RPDO5 (+nodeID) */ - CO_CAN_ID_TSDO = 0x580, /**< 0x580, SDO response from server (+nodeID) */ - CO_CAN_ID_RSDO = 0x600, /**< 0x600, SDO request from client (+nodeID) */ - CO_CAN_ID_HEARTBEAT = 0x700, /**< 0x700, Heartbeat message */ - CO_CAN_ID_LSS_CLI = 0x7E4, /**< 0x7E4, LSS response from server to client */ - CO_CAN_ID_LSS_SRV = 0x7E5 /**< 0x7E5, LSS request from client to server */ + CO_CAN_ID_SDO_SRV = 0x580, /**< 0x580, SDO response from server (+nodeID) */ + CO_CAN_ID_SDO_CLI = 0x600, /**< 0x600, SDO request from client (+nodeID) */ + CO_CAN_ID_HEARTBEAT = 0x700, /**< 0x700, Heartbeat message */ + CO_CAN_ID_LSS_SLV = 0x7E4, /**< 0x7E4, LSS response from slave */ + CO_CAN_ID_LSS_MST = 0x7E5 /**< 0x7E5, LSS request from master */ } CO_Default_CAN_ID_t; @@ -529,7 +469,7 @@ typedef enum { CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not confugured properly */ - CO_ERROR_PARAMETERS = -12, /**< Error in function function parameters*/ + CO_ERROR_OD_PARAMETERS = -12, /**< Error in Object Dictionary parameters*/ CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ CO_ERROR_CRC = -14, /**< CRC does not match */ CO_ERROR_TX_BUSY = -15, /**< Sending rejected because driver is @@ -697,7 +637,47 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); */ void CO_CANmodule_process(CO_CANmodule_t *CANmodule); -/** @} */ /* @defgroup CO_driver Driver */ + +/** + * Get uint8_t value from memory buffer + * + * @param buf Memory buffer to get value from. + * + * @return Value + */ +static inline uint8_t CO_getUint8(const void *buf) { + uint8_t value; memmove(&value, buf, sizeof(value)); return value; +} +/** Get uint16_t value from memory buffer, see @ref CO_getUint8 */ +static inline uint16_t CO_getUint16(const void *buf) { + uint16_t value; memmove(&value, buf, sizeof(value)); return value; +} +/** Get uint32_t value from memory buffer, see @ref CO_getUint8 */ +static inline uint32_t CO_getUint32(const void *buf) { + uint32_t value; memmove(&value, buf, sizeof(value)); return value; +} + +/** + * Write uint8_t value into memory buffer + * + * @param buf Memory buffer. + * @param value Value to be written into buf. + * + * @return number of bytes written. + */ +static inline uint8_t CO_setUint8(void *buf, uint8_t value) { + memmove(buf, &value, sizeof(value)); return sizeof(value); +} +/** Write uint16_t value into memory buffer, see @ref CO_setUint8 */ +static inline uint8_t CO_setUint16(void *buf, uint16_t value) { + memmove(buf, &value, sizeof(value)); return sizeof(value); +} +/** Write uint32_t value into memory buffer, see @ref CO_setUint8 */ +static inline uint8_t CO_setUint32(void *buf, uint32_t value) { + memmove(buf, &value, sizeof(value)); return sizeof(value); +} + +/** @} */ /* CO_driver */ #ifdef __cplusplus } diff --git a/301/CO_fifo.c b/301/CO_fifo.c index c97b8a89..1e362d94 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -23,17 +23,16 @@ * limitations under the License. */ - #include "301/CO_fifo.h" +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE + #include #include #include -#if CO_CONFIG_FIFO_CRC16_CCITT == 1 #include "crc16-ccitt.h" -#endif -#if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS #include #include @@ -41,8 +40,14 @@ #define DELIM_COMMAND '\n' /* Graphical character for comment delimiter */ #define DELIM_COMMENT '#' -#endif /* CO_CONFIG_FIFO_ASCII_COMMANDS == 1 */ +#endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ +/* verify configuration */ +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT + #if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) + #error CO_CONFIG_CRC16_ENABLE must be enabled. + #endif +#endif /******************************************************************************/ void CO_fifo_init(CO_fifo_t *fifo, char *buf, size_t bufSize) { @@ -97,7 +102,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, *bufDest = *buf; -#if CO_CONFIG_FIFO_CRC16_CCITT > 0 +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT if (crc != NULL) { crc16_ccitt_single(crc, (unsigned char)*buf); } @@ -152,7 +157,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, char *buf, size_t count, bool_t *eof) { } i--; -#if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS /* is delimiter? */ if (eof != NULL && c == DELIM_COMMAND) { *eof = true; @@ -165,7 +170,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, char *buf, size_t count, bool_t *eof) { } -#if CO_CONFIG_FIFO_ALT_READ == 1 +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ /******************************************************************************/ size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset) { size_t i; @@ -202,7 +207,7 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { else { const char *bufSrc = &fifo->buf[fifo->readPtr]; while (fifo->readPtr != fifo->altReadPtr) { -#if CO_CONFIG_FIFO_CRC16_CCITT > 0 +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT crc16_ccitt_single(crc, (unsigned char)*bufSrc); #endif /* increment variable */ @@ -244,10 +249,10 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count) { return count - i; } -#endif /* CO_CONFIG_FIFO_ALT_READ == 1 */ +#endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ */ -#if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS /******************************************************************************/ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { bool_t newCommand = false; @@ -461,10 +466,10 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, return tokenSize; } -#endif /* #if CO_CONFIG_FIFO_ASCII_COMMANDS == 1 */ +#endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ -#if CO_CONFIG_FIFO_ASCII_DATATYPES == 1 +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES /******************************************************************************/ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n; @@ -1139,4 +1144,6 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return destSpaceStart - destSpace; } -#endif /* CO_CONFIG_FIFO_ASCII_DATATYPES == 1 */ +#endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES */ + +#endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE */ diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 05c816cc..159ec29f 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -23,34 +23,17 @@ * limitations under the License. */ - #ifndef CO_FIFO_H #define CO_FIFO_H - #include "301/CO_driver.h" +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_FIFO +#define CO_CONFIG_FIFO (0) +#endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - #ifndef CO_CONFIG_FIFO_ALT_READ - #define CO_CONFIG_FIFO_ALT_READ 1 - #endif - #ifndef CO_CONFIG_FIFO_CRC16_CCITT - #define CO_CONFIG_FIFO_CRC16_CCITT 1 - #endif -#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - #ifndef CO_CONFIG_FIFO_ASCII_COMMANDS - #define CO_CONFIG_FIFO_ASCII_COMMANDS 1 - #endif - #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO - #ifndef CO_CONFIG_FIFO_ASCII_DATATYPES - #define CO_CONFIG_FIFO_ASCII_DATATYPES 1 - #endif - #endif -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ - +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -83,11 +66,11 @@ typedef struct { size_t writePtr; /** Location in the buffer, which will be next read. */ size_t readPtr; -#if CO_CONFIG_FIFO_ALT_READ > 0 || defined CO_DOXYGEN +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) || defined CO_DOXYGEN /** Location in the buffer, which will be next read. */ size_t altReadPtr; #endif -#if CO_CONFIG_FIFO_ASCII_DATATYPES > 0 || defined CO_DOXYGEN +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) || defined CO_DOXYGEN /** helper variable, set to false in CO_fifo_reset(), used in some * functions. */ bool_t started; @@ -118,7 +101,7 @@ static inline void CO_fifo_reset(CO_fifo_t *fifo) { if (fifo != NULL) { fifo->readPtr = 0; fifo->writePtr = 0; -#if CO_CONFIG_FIFO_ASCII_DATATYPES > 0 +#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES fifo->started = false; #endif } @@ -264,7 +247,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, size_t CO_fifo_read(CO_fifo_t *fifo, char *buf, size_t count, bool_t *eof); -#if CO_CONFIG_FIFO_ALT_READ > 0 || defined CO_DOXYGEN +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) || defined CO_DOXYGEN /** * Initializes alternate read with #CO_fifo_altRead * @@ -320,10 +303,10 @@ static inline size_t CO_fifo_altGetOccupied(CO_fifo_t *fifo) { * @return number of bytes actually read. */ size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count); -#endif /* CO_CONFIG_FIFO_ALT_READ > 0 */ +#endif /* #if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ */ -#if CO_CONFIG_FIFO_ASCII_COMMANDS > 0 || defined CO_DOXYGEN +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) || defined CO_DOXYGEN /** * Search command inside FIFO * @@ -407,10 +390,10 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, size_t count, char *closed, bool_t *err); -#endif /* CO_CONFIG_FIFO_ASCII_COMMANDS > 0 */ +#endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ -#if CO_CONFIG_FIFO_ASCII_DATATYPES > 0 || defined CO_DOXYGEN +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) || defined CO_DOXYGEN /** * Read uint8_t variable from fifo and output as ascii string. * @@ -513,11 +496,14 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); * the quotes are escaped by a second quotes. See CO_fifo_cpyTok2U8 */ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); -#endif /* CO_CONFIG_FIFO_ASCII_DATATYPES > 0 */ +#endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES */ + +/** @} */ /* CO_CANopen_301_fifo */ #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ +#endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE */ + #endif /* CO_FIFO_H */ diff --git a/301/crc16-ccitt.c b/301/crc16-ccitt.c index 9a771b33..682f6396 100644 --- a/301/crc16-ccitt.c +++ b/301/crc16-ccitt.c @@ -23,19 +23,19 @@ * limitations under the License. */ -#ifndef CO_USE_OWN_CRC16 - #include "301/crc16-ccitt.h" +#if (CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE +#if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_EXTERNAL) /* * CRC table calculated by the following algorithm: * * void crc16_ccitt_table_init(void){ - * unsigned short i, j; + * uint16_t i, j; * for(i=0; i<256; i++){ - * unsigned short crc = 0; - * unsigned short c = i << 8; + * uint16_t crc = 0; + * uint16_t c = i << 8; * for(j=0; j<8; j++){ * if((crc ^ c) & 0x8000) crc = (crc << 1) ^ 0x1021; * else crc = crc << 1; @@ -45,7 +45,7 @@ * } * } */ -static const unsigned short crc16_ccitt_table[256] = { +static const uint16_t crc16_ccitt_table[256] = { 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50A5U, 0x60C6U, 0x70E7U, 0x8108U, 0x9129U, 0xA14AU, 0xB16BU, 0xC18CU, 0xD1ADU, 0xE1CEU, 0xF1EFU, 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52B5U, 0x4294U, 0x72F7U, 0x62D6U, @@ -82,25 +82,25 @@ static const unsigned short crc16_ccitt_table[256] = { /******************************************************************************/ -void crc16_ccitt_single(unsigned short *crc, const unsigned char chr) { - unsigned char tmp = (unsigned char)(*crc >> 8U) ^ chr; +void crc16_ccitt_single(uint16_t *crc, const uint8_t chr) { + uint8_t tmp = (uint8_t)(*crc >> 8U) ^ chr; *crc = (*crc << 8U) ^ crc16_ccitt_table[tmp]; } /******************************************************************************/ -unsigned short crc16_ccitt( - const unsigned char block[], - unsigned int blockLength, - unsigned short crc) +uint16_t crc16_ccitt(const uint8_t block[], + size_t blockLength, + uint16_t crc) { - unsigned int i; + size_t i; - for(i=0U; i> 8U) ^ block[i]; + for (i = 0U; i < blockLength; i++) { + uint8_t tmp = (uint8_t)(crc >> 8U) ^ block[i]; crc = (crc << 8U) ^ crc16_ccitt_table[tmp]; } return crc; } -#endif /* CO_USE_OWN_CRC16 */ +#endif /* !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_EXTERNAL) */ +#endif /* (CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE */ diff --git a/301/crc16-ccitt.h b/301/crc16-ccitt.h index df3758da..186e5340 100644 --- a/301/crc16-ccitt.h +++ b/301/crc16-ccitt.h @@ -24,10 +24,18 @@ * limitations under the License. */ - #ifndef CRC16_CCITT_H #define CRC16_CCITT_H +#include "301/CO_driver.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_CRC16 +#define CO_CONFIG_CRC16 (0) +#endif + +#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif @@ -55,10 +63,7 @@ extern "C" { * start of new CRC calculation, variable must be initialized (zero for xmodem). * @param chr One byte of data */ -#ifdef CO_USE_OWN_CRC16 -extern -#endif -void crc16_ccitt_single(unsigned short *crc, const unsigned char chr); +void crc16_ccitt_single(uint16_t *crc, const uint8_t chr); /** @@ -71,19 +76,17 @@ void crc16_ccitt_single(unsigned short *crc, const unsigned char chr); * * @return Calculated CRC. */ -#ifdef CO_USE_OWN_CRC16 -extern -#endif -unsigned short crc16_ccitt( - const unsigned char block[], - unsigned int blockLength, - unsigned short crc); +uint16_t crc16_ccitt(const uint8_t block[], + size_t blockLength, + uint16_t crc); -/** @} */ +/** @} */ /* CO_crc16_ccitt */ #ifdef __cplusplus } #endif /*__cplusplus*/ -#endif +#endif /* (CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE */ + +#endif /* CRC16_CCITT_H */ diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index edf6aa26..9e3ce8c7 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -25,6 +25,7 @@ #include "303/CO_LEDs.h" +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE /******************************************************************************/ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { @@ -150,3 +151,5 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, } #endif } + +#endif /* (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE */ diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index e1a6dae3..75364f88 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -23,19 +23,25 @@ * limitations under the License. */ - #ifndef CO_LEDS_H #define CO_LEDS_H #include "301/CO_driver.h" #include "301/CO_NMT_Heartbeat.h" +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_LEDS +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE) +#endif + +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif /** - * @defgroup CO_LEDs LED indicator specification + * @defgroup CO_LEDs LED indicators * @ingroup CO_CANopen_303 * @{ * @@ -140,10 +146,12 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, bool_t firmwareDownload, uint32_t *timerNext_us); -/** @} */ +/** @} */ /* CO_LEDs */ #ifdef __cplusplus } #endif /*__cplusplus*/ -#endif +#endif /* (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE */ + +#endif /* CO_LEDS_H */ diff --git a/304/CO_GFC.c b/304/CO_GFC.c index 0c532d08..4b315c55 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -25,6 +25,8 @@ #include "304/CO_GFC.h" +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER static void CO_GFC_receive(void *object, void *msg) @@ -125,3 +127,5 @@ CO_ReturnError_t CO_GFCsend(CO_GFC_t *GFC) return CO_ERROR_NO; } #endif + +#endif /* (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE */ diff --git a/304/CO_GFC.h b/304/CO_GFC.h index e06cdb48..07a0b229 100644 --- a/304/CO_GFC.h +++ b/304/CO_GFC.h @@ -23,11 +23,18 @@ * limitations under the License. */ -#include "301/CO_driver.h" - #ifndef CO_GFC_H #define CO_GFC_H +#include "301/CO_driver.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_GFC +#define CO_CONFIG_GFC (0) +#endif + +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif @@ -120,9 +127,12 @@ void CO_GFC_initCallbackEnterSafeState(CO_GFC_t *GFC, CO_ReturnError_t CO_GFCsend(CO_GFC_t *GFC); #endif +/** @} */ /* CO_GFC */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE */ + +#endif /* CO_GFC_H */ diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 32641994..33d0a64e 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -25,8 +25,15 @@ #include "304/CO_SRDO.h" +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + #include "301/crc16-ccitt.h" +/* verify configuration */ +#if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) + #error CO_CONFIG_CRC16_ENABLE must be enabled. +#endif + #define CO_SRDO_INVALID (0U) #define CO_SRDO_TX (1U) #define CO_SRDO_RX (2U) @@ -321,7 +328,7 @@ static uint16_t CO_SRDOcalcCrc(const CO_SRDO_t *SRDO){ CO_memcpySwap2(&buffer[0], &com->safetyCycleTime); result = crc16_ccitt(&buffer[0], 2, result); result = crc16_ccitt(&com->safetyRelatedValidationTime, 1, result); - + /* adjust COB-ID if the default is used Caution: if the node id changes and you are using the default COB-ID you have to recalculate the checksum This behaviour is controversial and could be changed or made optional. @@ -836,3 +843,5 @@ void CO_SRDO_process( CO_FLAG_CLEAR(SRDO->CANrxNew[1]); } } + +#endif /* (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE */ diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index c1acfecf..10ef427b 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -23,13 +23,23 @@ * limitations under the License. */ +#ifndef CO_SRDO_H +#define CO_SRDO_H + #include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" #include "301/CO_NMT_Heartbeat.h" -#ifndef CO_SRDO_H -#define CO_SRDO_H +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_SRDO +#define CO_CONFIG_SRDO (0) +#endif +#ifndef CO_CONFIG_SRDO_MINIMUM_DELAY +#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 +#endif + +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -293,10 +303,12 @@ void CO_SRDO_process( uint32_t timeDifference_us, uint32_t *timerNext_us); +/** @} */ /* CO_SRDO */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE */ +#endif /* CO_SRDO_H */ diff --git a/305/CO_LSS.h b/305/CO_LSS.h index c3992b46..1540bc0e 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -27,6 +27,15 @@ #ifndef CO_LSS_H #define CO_LSS_H +#include "301/CO_driver.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_LSS +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE) +#endif + +#if ((CO_CONFIG_LSS) & (CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER)) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif @@ -232,8 +241,11 @@ static const uint16_t CO_LSS_bitTimingTableLookup[] = { a1.identity.vendorID == a2.identity.vendorID) /** @} */ /*@defgroup CO_LSS*/ + #ifdef __cplusplus } #endif /*__cplusplus*/ +#endif /* (CO_CONFIG_LSS) & (CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER) */ + #endif /*CO_LSS_H*/ diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 41dbf344..9a624e61 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -24,12 +24,12 @@ * limitations under the License. */ -#include - -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" /* for helper functions */ #include "305/CO_LSSmaster.h" +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + +#include + /* * LSS master slave select state machine. Compared to #CO_LSS_state_t this * has information if we currently have selected one or all slaves. This @@ -1112,3 +1112,5 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } return ret; } + +#endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER */ diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index bf5ad402..8be043d9 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -24,16 +24,17 @@ * limitations under the License. */ - #ifndef CO_LSSmaster_H #define CO_LSSmaster_H +#include "305/CO_LSS.h" + +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif -#include "305/CO_LSS.h" - /** * @defgroup CO_LSSmaster LSS Master * @ingroup CO_CANopen_305 @@ -469,8 +470,11 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( CO_LSSmaster_fastscan_t *fastscan); /** @} */ /*@defgroup CO_LSSmaster*/ + #ifdef __cplusplus } #endif /*__cplusplus*/ +#endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER */ + #endif /*CO_LSSmaster_H*/ diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 2772ac59..6e2f7e2c 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -25,12 +25,11 @@ * limitations under the License. */ -#include - -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" /* for helper functions */ #include "305/CO_LSSslave.h" +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + +#include /* * Read received message from CAN module. @@ -484,3 +483,5 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { return resetCommunication; } + +#endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE */ diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index ac03670a..2b500b2f 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -25,16 +25,17 @@ * limitations under the License. */ - #ifndef CO_LSSslave_H #define CO_LSSslave_H +#include "305/CO_LSS.h" + +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif -#include "305/CO_LSS.h" - /** * @defgroup CO_LSSslave LSS Slave * @ingroup CO_CANopen_305 @@ -271,8 +272,11 @@ void CO_LSSslave_initCfgStoreCallback( bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate)); /** @} */ /*@defgroup CO_LSSslave*/ + #ifdef __cplusplus } #endif /*__cplusplus*/ +#endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE */ + #endif /*CO_LSSslave_H*/ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index d76c5ba0..dab6fb0d 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -24,15 +24,28 @@ * limitations under the License. */ +#include "309/CO_gateway_ascii.h" + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + #include #include #include #include #include -#include "309/CO_gateway_ascii.h" - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +/* verify configuration */ +#if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) + #error CO_CONFIG_FIFO_ENABLE must be enabled. +#endif +#if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) + #error CO_CONFIG_FIFO_ASCII_COMMANDS must be enabled. +#endif +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO + #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) + #error CO_CONFIG_FIFO_ASCII_DATATYPES must be enabled. + #endif +#endif /******************************************************************************/ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 81e3b319..a0387819 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -24,35 +24,30 @@ * limitations under the License. */ - #ifndef CO_GATEWAY_ASCII_H #define CO_GATEWAY_ASCII_H #include "301/CO_driver.h" - -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN - #include "301/CO_fifo.h" -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN #include "301/CO_SDOserver.h" #include "301/CO_SDOclient.h" -#endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN #include "301/CO_NMT_Heartbeat.h" -#endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN #include "305/CO_LSSmaster.h" -#endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) || defined CO_DOXYGEN #include "303/CO_LEDs.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_GTW +#define CO_CONFIG_GTW (0) #endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif /** - * @defgroup CO_CANopen_309_3 ASCII mapping + * @defgroup CO_CANopen_309_3 Gateway ASCII mapping * @ingroup CO_CANopen_309 * @{ * @@ -524,6 +519,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, uint32_t timeDifference_us, uint32_t *timerNext_us); +/** @} */ /* CO_CANopen_309_3 */ #ifdef __cplusplus } @@ -531,5 +527,4 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ -/** @} */ #endif /* CO_GATEWAY_ASCII_H */ diff --git a/CANopen.c b/CANopen.c index 053a733c..2c193d22 100644 --- a/CANopen.c +++ b/CANopen.c @@ -616,10 +616,10 @@ CO_ReturnError_t CO_LSSinit(uint8_t *nodeId, nodeId, CO->CANmodule[0], CO_RXCAN_LSS_SLV, - CO_CAN_ID_LSS_SRV, + CO_CAN_ID_LSS_MST, CO->CANmodule[0], CO_TXCAN_LSS_SLV, - CO_CAN_ID_LSS_CLI); + CO_CAN_ID_LSS_SLV); return err; } @@ -640,24 +640,24 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { else #endif if (nodeId < 1 || nodeId > 127) { - return CO_ERROR_PARAMETERS; + return CO_ERROR_ILLEGAL_ARGUMENT; } /* Verify parameters from CO_OD */ #if CO_NO_SRDO != 0 if (sizeof(OD_SRDOCommunicationParameter_t) != sizeof(CO_SRDOCommPar_t) || sizeof(OD_SRDOMappingParameter_t) != sizeof(CO_SRDOMapPar_t)) { - return CO_ERROR_PARAMETERS; + return CO_ERROR_OD_PARAMETERS; } #endif if (sizeof(OD_TPDOCommunicationParameter_t) != sizeof(CO_TPDOCommPar_t) || sizeof(OD_TPDOMappingParameter_t) != sizeof(CO_TPDOMapPar_t) || sizeof(OD_RPDOCommunicationParameter_t) != sizeof(CO_RPDOCommPar_t) || sizeof(OD_RPDOMappingParameter_t) != sizeof(CO_RPDOMapPar_t)) { - return CO_ERROR_PARAMETERS; + return CO_ERROR_OD_PARAMETERS; } #if CO_NO_SDO_CLIENT != 0 if (sizeof(OD_SDOClientParameter_t) != sizeof(CO_SDOclientPar_t)) { - return CO_ERROR_PARAMETERS; + return CO_ERROR_OD_PARAMETERS; } #endif @@ -680,8 +680,8 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { uint32_t COB_IDServerToClient; if (i == 0) { /*Default SDO server must be located at first index*/ - COB_IDClientToServer = CO_CAN_ID_RSDO + nodeId; - COB_IDServerToClient = CO_CAN_ID_TSDO + nodeId; + COB_IDClientToServer = CO_CAN_ID_SDO_CLI + nodeId; + COB_IDServerToClient = CO_CAN_ID_SDO_SRV + nodeId; } else { COB_IDClientToServer = @@ -904,10 +904,10 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { CO_LSSmaster_DEFAULT_TIMEOUT, CO->CANmodule[0], CO_RXCAN_LSS_MST, - CO_CAN_ID_LSS_CLI, + CO_CAN_ID_LSS_SLV, CO->CANmodule[0], CO_TXCAN_LSS_MST, - CO_CAN_ID_LSS_SRV); + CO_CAN_ID_LSS_MST); if (err) return err; #endif diff --git a/CANopen.h b/CANopen.h index 5a0f9967..922e0579 100644 --- a/CANopen.h +++ b/CANopen.h @@ -28,6 +28,24 @@ #ifndef CANopen_H #define CANopen_H +#include "301/CO_driver.h" +#include "301/CO_SDOserver.h" +#include "301/CO_SDOclient.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" +#include "301/CO_TIME.h" +#include "301/CO_SYNC.h" +#include "301/CO_PDO.h" +#include "301/CO_HBconsumer.h" +#include "303/CO_LEDs.h" +#include "304/CO_GFC.h" +#include "304/CO_SRDO.h" +#include "305/CO_LSSslave.h" +#include "305/CO_LSSmaster.h" +#include "309/CO_gateway_ascii.h" +#include "extra/CO_trace.h" +#include "CO_OD.h" + #ifdef __cplusplus extern "C" { #endif @@ -141,16 +159,6 @@ extern "C" { * @{ */ - #include "301/CO_driver.h" - #include "301/CO_SDOserver.h" - #include "301/CO_Emergency.h" - #include "301/CO_NMT_Heartbeat.h" - #include "301/CO_TIME.h" - #include "301/CO_PDO.h" - #include "301/CO_HBconsumer.h" - #include "CO_OD.h" - - #ifdef CO_DOXYGEN /** * @defgroup CO_NO_OBJ CANopen configuration @@ -247,35 +255,6 @@ extern "C" { #endif /* CO_DOXYGEN */ -#if CO_NO_SYNC == 1 || defined CO_DOXYGEN - #include "301/CO_SYNC.h" -#endif -#if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN - #include "301/CO_SDOclient.h" -#endif -#if CO_NO_GFC != 0 || defined CO_DOXYGEN - #include "304/CO_GFC.h" -#endif -#if CO_NO_SRDO != 0 || defined CO_DOXYGEN - #include "304/CO_SRDO.h" -#endif -#if CO_NO_LSS_SLAVE != 0 || defined CO_DOXYGEN - #include "305/CO_LSSslave.h" -#endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN - #include "303/CO_LEDs.h" -#endif -#if CO_NO_LSS_MASTER != 0 || defined CO_DOXYGEN - #include "305/CO_LSSmaster.h" -#endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN - #include "309/CO_gateway_ascii.h" -#endif -#if CO_NO_TRACE != 0 || defined CO_DOXYGEN - #include "extra/CO_trace.h" -#endif - - /** * CANopen object with pointers to all CANopenNode objects. */ @@ -492,7 +471,7 @@ void CO_process_SRDO(CO_t *co, uint32_t *timerNext_us); #endif /* CO_NO_SRDO != 0 */ -/** @} */ +/** @} */ /* CO_CANopen */ #ifdef __cplusplus } diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index bcc7c89a..0860097f 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -42,96 +42,111 @@ extern "C" { #endif -/* Stack configuration override from CO_driver.h. Compile full stack. +/* Stack configuration override default values. * For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_NMT_CALLBACK_CHANGE | \ - CO_CONFIG_NMT_MASTER) +#define CO_CONFIG_NMT (CO_CONFIG_NMT_CALLBACK_CHANGE | \ + CO_CONFIG_NMT_MASTER | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif -#ifndef CO_CONFIG_SDO -#define CO_CONFIG_SDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_SDO_SEGMENTED | \ - CO_CONFIG_SDO_BLOCK) -#endif - -#ifndef CO_CONFIG_SDO_BUFFER_SIZE -#define CO_CONFIG_SDO_BUFFER_SIZE 1800 +#ifndef CO_CONFIG_HB_CONS +#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ + CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ + CO_CONFIG_HB_CONS_CALLBACK_MULTI | \ + CO_CONFIG_HB_CONS_QUERY_FUNCT | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM (CO_CONFIG_FLAG_CALLBACK_PRE | \ +#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ + CO_CONFIG_EM_HISTORY | \ + CO_CONFIG_EM_CONSUMER | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_EM_CONSUMER) + CO_CONFIG_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS (CO_CONFIG_FLAG_CALLBACK_PRE | \ +#ifndef CO_CONFIG_SDO_SRV +#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ + CO_CONFIG_SDO_SRV_BLOCK | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ - CO_CONFIG_HB_CONS_CALLBACK_MULTI | \ - CO_CONFIG_HB_CONS_QUERY_FUNCT) + CO_CONFIG_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_GFC -#define CO_CONFIG_GFC (CO_CONFIG_GFC_CONSUMER | \ - CO_CONFIG_GFC_PRODUCER) +#ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE +#define CO_CONFIG_SDO_SRV_BUFFER_SIZE (127*7) #endif -#ifndef CO_CONFIG_SRDO -#define CO_CONFIG_SRDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_SRDO_CHECK_TX | \ - CO_CONFIG_RSRDO_CALLS_EXTENSION | \ - CO_CONFIG_TSRDO_CALLS_EXTENSION) +#ifndef CO_CONFIG_SDO_CLI +#define CO_CONFIG_SDO_CLI (CO_CONFIG_SDO_CLI_ENABLE | \ + CO_CONFIG_SDO_CLI_SEGMENTED | \ + CO_CONFIG_SDO_CLI_BLOCK | \ + CO_CONFIG_SDO_CLI_LOCAL | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_SRDO_MINIMUM_DELAY -#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 +#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 +#endif + +#ifndef CO_CONFIG_SYNC +#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ + CO_CONFIG_SYNC_PRODUCER | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ +#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ + CO_CONFIG_TPDO_ENABLE | \ CO_CONFIG_PDO_SYNC_ENABLE | \ CO_CONFIG_RPDO_CALLS_EXTENSION | \ - CO_CONFIG_TPDO_CALLS_EXTENSION) + CO_CONFIG_TPDO_CALLS_EXTENSION | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif -#ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT) +#ifndef CO_CONFIG_TIME +#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ + CO_CONFIG_TIME_PRODUCER | \ + CO_CONFIG_FLAG_CALLBACK_PRE) #endif -#ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_SDO_CLI_SEGMENTED | \ - CO_CONFIG_SDO_CLI_BLOCK | \ - CO_CONFIG_SDO_CLI_LOCAL) +#ifndef CO_CONFIG_LEDS +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif -#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE -#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 +#ifndef CO_CONFIG_GFC +#define CO_CONFIG_GFC (CO_CONFIG_GFC_ENABLE | \ + CO_CONFIG_GFC_CONSUMER | \ + CO_CONFIG_GFC_PRODUCER) #endif -#ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) +#ifndef CO_CONFIG_SRDO +#define CO_CONFIG_SRDO (CO_CONFIG_SRDO_ENABLE | \ + CO_CONFIG_SRDO_CHECK_TX | \ + CO_CONFIG_RSRDO_CALLS_EXTENSION | \ + CO_CONFIG_TSRDO_CALLS_EXTENSION | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif -#ifndef CO_CONFIG_LEDS -#define CO_CONFIG_LEDS (CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_LEDS_ENABLE) +#ifndef CO_CONFIG_SRDO_MINIMUM_DELAY +#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 #endif #ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_LSS_SLAVE | \ +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ - CO_CONFIG_LSS_MASTER) + CO_CONFIG_LSS_MASTER | \ + CO_CONFIG_FLAG_CALLBACK_PRE) #endif #ifndef CO_CONFIG_GTW @@ -148,6 +163,22 @@ extern "C" { #define CO_CONFIG_GTWA_LOG_BUF_SIZE 2000 #endif +#ifndef CO_CONFIG_CRC16 +#define CO_CONFIG_CRC16 (CO_CONFIG_CRC16_ENABLE) +#endif + +#ifndef CO_CONFIG_FIFO +#define CO_CONFIG_FIFO (CO_CONFIG_FIFO_ENABLE | \ + CO_CONFIG_FIFO_ALT_READ | \ + CO_CONFIG_FIFO_CRC16_CCITT | \ + CO_CONFIG_FIFO_ASCII_COMMANDS | \ + CO_CONFIG_FIFO_ASCII_DATATYPES) +#endif + +#ifndef CO_CONFIG_TRACE +#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE) +#endif + /* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ #define CO_LITTLE_ENDIAN diff --git a/extra/CO_trace.c b/extra/CO_trace.c index 2ef389ff..96b3c76a 100644 --- a/extra/CO_trace.c +++ b/extra/CO_trace.c @@ -22,11 +22,13 @@ * limitations under the License. */ - #include "extra/CO_trace.h" + +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE + #include #include -#ifndef CO_OWN_INTTYPES +#if !((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_OWN_INTTYPES) #include /* for PRIu32("u" or "lu") and PRId32("d" or "ld") */ #endif @@ -501,3 +503,5 @@ void CO_trace_process(CO_trace_t *trace, uint32_t timestamp) { trace->lastTimeStamp = timestamp; } } + +#endif /* (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE */ diff --git a/extra/CO_trace.h b/extra/CO_trace.h index 17d2e9e3..8dc632b5 100644 --- a/extra/CO_trace.h +++ b/extra/CO_trace.h @@ -23,17 +23,22 @@ * limitations under the License. */ - #ifndef CO_TRACE_H #define CO_TRACE_H -#ifdef __cplusplus -extern "C" { -#endif - #include "301/CO_driver.h" #include "301/CO_SDOserver.h" +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_TRACE +#define CO_CONFIG_TRACE (0) +#endif + +#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif /** * @defgroup CO_trace Trace @@ -163,9 +168,12 @@ void CO_trace_init( */ void CO_trace_process(CO_trace_t *trace, uint32_t timestamp); +/** @} */ /* CO_trace */ + #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE */ + +#endif /* CO_TRACE_H */ diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h index 33ba786d..c0c3f5e6 100644 --- a/socketCAN/CO_Linux_threads.h +++ b/socketCAN/CO_Linux_threads.h @@ -29,6 +29,8 @@ #ifndef CO_LINUX_THREADS_H #define CO_LINUX_THREADS_H +#include "309/CO_gateway_ascii.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 409348e2..0b1022f9 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -604,13 +604,13 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface( index = CO_CANgetIndexFromIdent(CANmodule->txIdentToIndex, ident); if ((index == CO_INVALID_COB_ID) || (index > CANmodule->txSize)) { - return CO_ERROR_PARAMETERS; + return CO_ERROR_ILLEGAL_ARGUMENT; } CANmodule->txArray[index].CANptr = CANptrTx; return CO_ERROR_NO; } - return CO_ERROR_PARAMETERS; + return CO_ERROR_ILLEGAL_ARGUMENT; } #endif /* CO_DRIVER_MULTI_INTERFACE */ @@ -628,7 +628,7 @@ static CO_ReturnError_t CO_CANCheckSendInterface( ssize_t n; if (CANmodule==NULL || interface==NULL || interface->fd < 0) { - return CO_ERROR_PARAMETERS; + return CO_ERROR_ILLEGAL_ARGUMENT; } #if CO_DRIVER_ERROR_REPORTING > 0 diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 79eb6a82..4cccf60b 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -50,77 +50,90 @@ extern "C" { #endif -/* Stack configuration override from CO_driver.h. +/* Stack configuration override default values. * For more information see file CO_config.h. */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_NMT_CALLBACK_CHANGE | \ - CO_CONFIG_NMT_MASTER) +#define CO_CONFIG_NMT (CO_CONFIG_NMT_CALLBACK_CHANGE | \ + CO_CONFIG_NMT_MASTER | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif -#ifndef CO_CONFIG_SDO -#define CO_CONFIG_SDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_SDO_SEGMENTED | \ - CO_CONFIG_SDO_BLOCK) -#endif - -#ifndef CO_CONFIG_SDO_BUFFER_SIZE -#define CO_CONFIG_SDO_BUFFER_SIZE 1800 +#ifndef CO_CONFIG_HB_CONS +#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ + CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM (CO_CONFIG_FLAG_CALLBACK_PRE | \ +#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ + CO_CONFIG_EM_HISTORY | \ + CO_CONFIG_EM_CONSUMER | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_EM_CONSUMER) + CO_CONFIG_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS (CO_CONFIG_FLAG_CALLBACK_PRE | \ +#ifndef CO_CONFIG_SDO_SRV +#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ + CO_CONFIG_SDO_SRV_BLOCK | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_HB_CONS_CALLBACK_CHANGE) + CO_CONFIG_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_PDO_SYNC_ENABLE | \ - CO_CONFIG_RPDO_CALLS_EXTENSION | \ - CO_CONFIG_TPDO_CALLS_EXTENSION) -#endif - -#ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT) +#ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE +#define CO_CONFIG_SDO_SRV_BUFFER_SIZE (127*7) #endif #ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ +#define CO_CONFIG_SDO_CLI (CO_CONFIG_SDO_CLI_ENABLE | \ CO_CONFIG_SDO_CLI_SEGMENTED | \ CO_CONFIG_SDO_CLI_BLOCK | \ - CO_CONFIG_SDO_CLI_LOCAL) + CO_CONFIG_SDO_CLI_LOCAL | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT | \ + CO_CONFIG_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 #endif +#ifndef CO_CONFIG_SYNC +#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ + CO_CONFIG_SYNC_PRODUCER | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) +#endif + +#ifndef CO_CONFIG_PDO +#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ + CO_CONFIG_TPDO_ENABLE | \ + CO_CONFIG_PDO_SYNC_ENABLE | \ + CO_CONFIG_RPDO_CALLS_EXTENSION | \ + CO_CONFIG_TPDO_CALLS_EXTENSION | \ + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_TIMERNEXT) +#endif + #ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (CO_CONFIG_FLAG_CALLBACK_PRE) +#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ + CO_CONFIG_TIME_PRODUCER | \ + CO_CONFIG_FLAG_CALLBACK_PRE) #endif #ifndef CO_CONFIG_LEDS -#define CO_CONFIG_LEDS (CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_LEDS_ENABLE) +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | \ + CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_LSS_SLAVE | \ +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ - CO_CONFIG_LSS_MASTER) + CO_CONFIG_LSS_MASTER | \ + CO_CONFIG_FLAG_CALLBACK_PRE) #endif #ifndef CO_CONFIG_GTW @@ -137,6 +150,22 @@ extern "C" { #define CO_CONFIG_GTWA_LOG_BUF_SIZE 10000 #endif +#ifndef CO_CONFIG_CRC16 +#define CO_CONFIG_CRC16 (CO_CONFIG_CRC16_ENABLE) +#endif + +#ifndef CO_CONFIG_FIFO +#define CO_CONFIG_FIFO (CO_CONFIG_FIFO_ENABLE | \ + CO_CONFIG_FIFO_ALT_READ | \ + CO_CONFIG_FIFO_CRC16_CCITT | \ + CO_CONFIG_FIFO_ASCII_COMMANDS | \ + CO_CONFIG_FIFO_ASCII_DATATYPES) +#endif + +#ifndef CO_CONFIG_TRACE +#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE) +#endif + /** * @defgroup CO_socketCAN_driver_target CO_driver_target.h From 4b855d04f7a0a5269f865249998edc7f1be42a60 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 14 Sep 2020 16:45:05 +0200 Subject: [PATCH 114/520] CO_TIME.c can be disabled --- 301/CO_TIME.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 42ce457c..62c6c99c 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -25,11 +25,12 @@ #include -#include "301/CO_driver.h" +#include "301/CO_TIME.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" #include "301/CO_NMT_Heartbeat.h" -#include "301/CO_TIME.h" + +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE #define DIV_ROUND_UP(_n, _d) (((_n) + (_d) - 1) / (_d)) @@ -207,3 +208,5 @@ uint8_t CO_TIME_process( return ret; } + +#endif /* (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE */ From 9446aa5792a2d8e0023558c6191a48675cefae44 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 14 Sep 2020 16:49:48 +0200 Subject: [PATCH 115/520] CO_TIME.c can be disabled --- 301/CO_TIME.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 62c6c99c..403a9fb6 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -25,10 +25,10 @@ #include -#include "301/CO_TIME.h" #include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" #include "301/CO_NMT_Heartbeat.h" +#include "301/CO_TIME.h" #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE From 6cdc70fb4e8ce0e8a3f43f3458804bf757838a68 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 19 Sep 2020 09:58:49 +0200 Subject: [PATCH 116/520] Object dictionary interface, preview updated. --- 301/CO_ODinterface.c | 426 ++++++++++--------- 301/CO_ODinterface.h | 887 +++++++++++----------------------------- 301/CO_config.h | 65 ++- doc/objectDictionary.md | 429 +++++++++++++++++++ 4 files changed, 946 insertions(+), 861 deletions(-) create mode 100644 doc/objectDictionary.md diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 0a494d25..cdd2b8d9 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -27,10 +27,9 @@ #include "301/CO_ODinterface.h" -/* Read value from variable from Object Dictionary, see OD_subEntry_t *********/ -static OD_size_t OD_readDirect(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) +/******************************************************************************/ +OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, ODR_t *returnCode) { (void) subIndex; @@ -40,7 +39,7 @@ static OD_size_t OD_readDirect(OD_stream_t *stream, uint8_t subIndex, } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ - const char *odData = (const char *)stream->dataObject; + const char *odData = (const char *)stream->dataObjectOriginal; if (odData == NULL) { *returnCode = ODR_SUB_NOT_EXIST; @@ -56,7 +55,7 @@ static OD_size_t OD_readDirect(OD_stream_t *stream, uint8_t subIndex, *returnCode = ODR_DEV_INCOMPAT; return 0; } - /* reduce for allready copied data */ + /* reduce for already copied data */ dataLenToCopy -= stream->dataOffset; odData += stream->dataOffset; @@ -77,10 +76,9 @@ static OD_size_t OD_readDirect(OD_stream_t *stream, uint8_t subIndex, return dataLenToCopy; } -/* Write value to variable from Object Dictionary, see OD_subEntry_t **********/ -static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +/******************************************************************************/ +OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, ODR_t *returnCode) { (void) subIndex; @@ -90,7 +88,7 @@ static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ - char *odData = (char *)stream->dataObject; + char *odData = (char *)stream->dataObjectOriginal; if (odData == NULL) { *returnCode = ODR_SUB_NOT_EXIST; @@ -106,7 +104,7 @@ static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, *returnCode = ODR_DEV_INCOMPAT; return 0; } - /* reduce for allready copied data */ + /* reduce for already copied data */ dataLenToCopy -= stream->dataOffset; odData += stream->dataOffset; @@ -135,10 +133,10 @@ static OD_size_t OD_writeDirect(OD_stream_t *stream, uint8_t subIndex, } } -/******************************************************************************/ -OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) +/* Read value from variable from Object Dictionary disabled, see OD_subEntry_t*/ +static OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) { (void) stream; (void) subIndex; (void) buf; (void) count; @@ -146,9 +144,10 @@ OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, return 0; } -OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) +/* Write value to variable from Object Dictionary disabled, see OD_subEntry_t */ +static OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) { (void) stream; (void) subIndex; (void) buf; (void) count; @@ -156,6 +155,7 @@ OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, return 0; } + /******************************************************************************/ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { unsigned int cur; @@ -198,89 +198,83 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { /******************************************************************************/ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, - OD_subEntry_t *subEntry, OD_stream_t *stream) + OD_subEntry_t *subEntry, OD_stream_t *stream, bool_t odOrig) { - if (entry == NULL) return ODR_IDX_NOT_EXIST; + if (entry == NULL || entry->odObject == NULL) return ODR_IDX_NOT_EXIST; else if (subIndex > entry->maxSubIndex) return ODR_SUB_NOT_EXIST; else if (subEntry == NULL || stream == NULL) return ODR_DEV_INCOMPAT; - const void *odObject = entry->odObject; - bool_t io_configured = false; + const void *odObjectOrig = entry->odObject; + const OD_obj_extended_t *odObjectExt = NULL; uint8_t odBasicType = entry->odObjectType & ODT_TYPE_MASK; - if (odObject == NULL) return ODR_DEV_INCOMPAT; + /* Is object type extended? */ + if ((entry->odObjectType & ODT_EXTENSION_MASK) != 0) { + odObjectExt = (const OD_obj_extended_t *)odObjectOrig; + odObjectOrig = odObjectExt->odObjectOriginal; + if (odObjectOrig == NULL) return ODR_DEV_INCOMPAT; + } /* common properties */ subEntry->index = entry->index; subEntry->subIndex = subIndex; subEntry->maxSubIndex = entry->maxSubIndex; subEntry->storageGroup = entry->storageGroup; + subEntry->flagsPDO = (odObjectExt != NULL ) ? odObjectExt->flagsPDO : NULL; stream->dataOffset = 0; - /* Object type is extended */ - if ((entry->odObjectType & ODT_EXTENSION_MASK) != 0) { - const OD_obj_extended_t *odoe = (const OD_obj_extended_t *)odObject; - - if (odoe->extIO != NULL && odoe->extIO->object != NULL - && odoe->extIO->read != NULL && odoe->extIO->write != NULL) - { - subEntry->read = odoe->extIO->read; - subEntry->write = odoe->extIO->write; - stream->dataObject = odoe->extIO->object; - io_configured = true; - } - subEntry->flagsPDO = odoe->flagsPDO; - odObject = odoe->odObjectOriginal; - if (odObject == NULL) return ODR_DEV_INCOMPAT; - } - else { - subEntry->flagsPDO = NULL; - } - - if (!io_configured) { - subEntry->read = OD_readDirect; - subEntry->write = OD_writeDirect; - } - + /* attribute, dataObjectOriginal and dataLength, depends on object type */ if (odBasicType == ODT_VAR) { - const OD_obj_var_t *odo = (const OD_obj_var_t *)odObject; + const OD_obj_var_t *odo = (const OD_obj_var_t *)odObjectOrig; subEntry->attribute = odo->attribute; - if (!io_configured) stream->dataObject = odo->data; + stream->dataObjectOriginal = odo->data; stream->dataLength = odo->dataLength; } else if (odBasicType == ODT_ARR) { - const OD_obj_array_t *odo = (const OD_obj_array_t *)odObject; + const OD_obj_array_t *odo = (const OD_obj_array_t *)odObjectOrig; if (subIndex == 0) { subEntry->attribute = odo->attribute0; - if (!io_configured) stream->dataObject = odo->data0; + stream->dataObjectOriginal = odo->data0; stream->dataLength = 1; } else { char *data = (char *)odo->data; + int i = subIndex - 1; subEntry->attribute = odo->attribute; - if (!io_configured) { - int i = subIndex - 1; - if (data == NULL) return ODR_DEV_INCOMPAT; - stream->dataObject = data + odo->dataElementSizeof * i; - } + if (data == NULL) return ODR_DEV_INCOMPAT; + stream->dataObjectOriginal = data + odo->dataElementSizeof * i; stream->dataLength = odo->dataElementLength; } } else if (odBasicType == ODT_REC) { - const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)odObject; + const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)odObjectOrig; const OD_obj_var_t *odo = &odo_rec[subIndex]; subEntry->attribute = odo->attribute; - if (!io_configured) stream->dataObject = odo->data; + stream->dataObjectOriginal = odo->data; stream->dataLength = odo->dataLength; } else { return ODR_DEV_INCOMPAT; } + /* read, write and dataObject, direct or with IO extension */ + if (odObjectExt == NULL || odObjectExt->extIO == NULL || odOrig) { + subEntry->read = OD_readOriginal; + subEntry->write = OD_writeOriginal; + stream->object = NULL; + } + else { + subEntry->read = odObjectExt->extIO->read != NULL ? + odObjectExt->extIO->read : OD_readDisabled; + subEntry->write = odObjectExt->extIO->write != NULL ? + odObjectExt->extIO->write : OD_writeDisabled; + stream->object = odObjectExt->extIO->object; + } + return ODR_OK; } @@ -339,6 +333,10 @@ bool_t OD_extensionIO_init(const OD_entry_t *entry, const OD_obj_extended_t *odo = (const OD_obj_extended_t *) entry->odObject; + if (odo->extIO == NULL) { + return false; + } + odo->extIO->object = object; odo->extIO->read = read; odo->extIO->write = write; @@ -346,179 +344,112 @@ bool_t OD_extensionIO_init(const OD_entry_t *entry, return true; } -/******************************************************************************/ -void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup) { - if (od == NULL) return; - - int i; - - for (i = 0; i < od->size; i++) { - const OD_entry_t *entry = &od->list[i]; - const OD_obj_extended_t *odoe; - uint8_t subIndex; - uint8_t odBasicType; - const void *orig; - - /* skip non-matched storage group and non-extended OD objects */ - if (entry->storageGroup != storageGroup - || (entry->odObjectType & ODT_EXTENSION_MASK) != 0) - continue; - - /* skip if extIO read or original object is not specified */ - odoe = (const OD_obj_extended_t *)entry->odObject; - orig = odoe->odObjectOriginal; - if (odoe->extIO == NULL || orig == NULL - || odoe->extIO->object == NULL || odoe->extIO->read == NULL) - continue; - - /* update each sub-index separately */ - odBasicType = entry->odObjectType & ODT_TYPE_MASK; - for (subIndex = 0; subIndex < entry->maxSubIndex; subIndex++) { - OD_attr_t attr; - void *dataObject = NULL; - OD_size_t dataLength, dataReadTotal; - - if (odBasicType == ODT_VAR) { - const OD_obj_var_t *odo = (const OD_obj_var_t *)orig; - - attr = odo->attribute; - dataObject = odo->data; - dataLength = odo->dataLength; - } - else if (odBasicType == ODT_ARR) { - const OD_obj_array_t *odo = (const OD_obj_array_t *)orig; - - if (subIndex == 0) { - attr = odo->attribute0; - dataObject = odo->data0; - dataLength = 1; - } - else { - char *data = (char *)odo->data; - if (data != NULL) { - int i = subIndex - 1; - attr = odo->attribute; - dataObject = data + odo->dataElementSizeof * i; - dataLength = odo->dataElementLength; - } - } - } - else if (odBasicType == ODT_REC) { - const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)orig; - const OD_obj_var_t *odo = &odo_rec[subIndex]; - - attr = odo->attribute; - dataObject = odo->data; - dataLength = odo->dataLength; - } - - if (dataObject == NULL || (attr&ODA_NOINIT) != 0 || dataLength == 0) - continue; - - /* copy data to group structure, several times if data is large */ - dataReadTotal = 0; - do { - char buf[32]; - ODR_t returnCode; - char *dest = (char *)dataObject + dataReadTotal; - OD_size_t dataRead = odoe->extIO->read(odoe->extIO->object, - subIndex, - buf, sizeof(buf), - &returnCode); - dataReadTotal += dataRead; - if (dataRead == 0 || dataReadTotal > dataLength) break; - memcpy(dest, buf, dataRead); - } while (dataReadTotal == dataLength); - } /* for (subIndex) */ - } /* for (entry) */ -} - /******************************************************************************/ -ODR_t OD_get_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t *val) { +ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, + int8_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t *val) { +ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, + int16_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t *val) { +ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, + int32_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_i64(const OD_entry_t *entry, uint16_t subIndex, int64_t *val) { +ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, + int64_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t *val) { +ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, + uint8_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t *val) { +ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, + uint16_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t *val) { +ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, + uint32_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_u64(const OD_entry_t *entry, uint16_t subIndex, uint64_t *val) { +ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, + uint64_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_r32(const OD_entry_t *entry, uint16_t subIndex, float32_t *val){ +ODR_t OD_get_r32(const OD_entry_t *entry, uint8_t subIndex, + float32_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); return ret; } -ODR_t OD_get_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t *val){ +ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, + float64_t *val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); @@ -526,92 +457,213 @@ ODR_t OD_get_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t *val){ } /******************************************************************************/ -ODR_t OD_set_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t val) { +ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, + int8_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t val) { +ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, + int16_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t val) { +ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, + int32_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_i64(const OD_entry_t *entry, uint16_t subIndex, int64_t val) { +ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, + int64_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t val) { +ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, + uint8_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t val) { +ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, + uint16_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t val) { +ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, + uint32_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_u64(const OD_entry_t *entry, uint16_t subIndex, uint64_t val) { +ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, + uint64_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_r32(const OD_entry_t *entry, uint16_t subIndex, float32_t val) { +ODR_t OD_set_r32(const OD_entry_t *entry, uint8_t subIndex, + float32_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t val) { +ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, + float64_t val, bool_t odOrig) +{ OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st); + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); return ret; } + +/******************************************************************************/ +ODR_t OD_getPtr_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t **val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (int8_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t **val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (int16_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t **val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (int32_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t **val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (int64_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t **val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (uint8_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t **val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (uint16_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t **val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (uint32_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t **val) { + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (uint64_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t **val){ + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (float32_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} + +ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val){ + OD_subEntry_t subEntry; OD_stream_t st; + ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + + if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) *val = (float64_t *)st.dataObjectOriginal; + if (*val == NULL) ret = ODR_DEV_INCOMPAT; + return ret; +} diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 7f4aad50..6d2c5f8d 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -23,7 +23,6 @@ * limitations under the License. */ - #ifndef CO_OD_INTERFACE_H #define CO_OD_INTERFACE_H @@ -34,540 +33,11 @@ extern "C" { #endif /** - * @defgroup CO_ODinterface Object Dictionary interface + * @defgroup CO_ODinterface OD interface * @ingroup CO_CANopen_301 * @{ - * See @ref CO_ODinterface_operation + * See @ref doc/objectDictionary.md */ -/** - * @defgroup CO_ODinterface_operation Operation - * @{ - * The CANopen Object Dictionary is essentially a grouping of objects accessible - * via the network in an ordered pre-defined fashion. - * - * Each object within the object dictionary is addressed using a 16-bit index - * and a 8-bit sub-index. - * - * ### Terms - * The term **OD object** means object from Object Dictionary located at - * specific 16-bit index. There are different types of OD objects in CANopen: - * variables, arrays and records (structures). Each OD object contains pointer - * to actual data, data length(s) and attribute(s). See @ref OD_objectTypes_t. - * - * The term **OD variable** is basic variable of specified type. For example: - * int8_t, uint32_t, float64_t, ... or just sequence of binary data with known - * or unknown data length. Each OD variable resides in Object dictionary at - * specified 16-bit index and 8-bit sub-index. - * - * The term **OD entry** means structure element, which contains some basic - * properties of the OD object, indication of type of OD object and pointer to - * all necessary data for the OD object. An array of OD entries together with - * information about total number of OD entries represents Object Dictionary as - * defined inside CANopenNode. See @ref OD_entry_t and @ref OD_t. - * - * ### Access - * Application and the stack have access to OD objects via universal @ref OD_t - * object and @ref OD_find() function, no direct access to custom structures, - * which define Object Dictionary, is required. Properties for specific - * OD variable is fetched with @ref OD_getSub() function. And access to actual - * variable is via @b read and @b write functions. Pointer to those two - * functions is fetched by @ref OD_getSub(). See @ref OD_stream_t and - * @ref OD_subEntry_t. See also shortcuts: @ref CO_ODgetSetters, for access to - * data of different type. - * - * ### Optional extensions - * There are some optional extensions to the Object Dictionary: - * * **PDO flags** informs application, if specific OD variable was received - * or sent by PDO. And also gives the application ability to request a TPDO, - * to which variable is possibly mapped. - * * **IO extension** gives the application ability to take full control over - * the OD object. Application can specify own @b read and @b write functions - * and own object, on which they operate. - * - * ### Example usage - * @code -extern const OD_t ODxyz; - -void myFunc(const OD_t *od) { - ODR_t ret; - const OD_entry_t *entry; - OD_subEntry_t subEntry; - OD_IO_t io1008; - char buf[50]; - OD_size_t bytesRd; - int error = 0; - - //Init IO for "Manufacturer device name" at index 0x1008, sub-index 0x00 - entry = OD_find(od, 0x1008); - ret = OD_getSub(entry, 0x00, &subEntry, &io1008.stream); - io1008.read = subEntry.read; - //Read with io1008 - if (ret == ODR_OK) - bytesRd = io1008.read(&io1008.stream, 0x00, &buf[0], sizeof(buf), &ret); - if (ret != ODR_OK) error++; - - //Use helper and set "Producer heartbeat time" at index 0x1008, sub 0x00 - ret = OD_set_u16(OD_find(od, 0x1017), 0x00, 500); - if (ret != ODR_OK) error++; -} - * @endcode - * There is no need to include ODxyt.h file, it is only necessary to know, we - * have ODxyz defined somewhere. - * - * Second example is simpler and use helper function to access OD variable. - * However it is not very efficient, because it goes through all search - * procedures. - * - * If access to the same variable is very frequent, it is better to - * use first example. After initialization, application has to remember only - * "io1008" object. Frequent reading of the variable is then very efficient. - * - * ### Simple access to OD via globals - * Some simple user applications can also access some OD variables directly via - * globals. - * - * @warning - * If OD object has IO extension enabled, then direct access to its OD variables - * must not be used. Only valid access is via read or write or helper functions. - * - * @code -#include ODxyz.h - -void myFuncGlob(void) { - //Direct address instead of OD_find() - const OD_entry_t *entry_errReg = ODxyz_1001_errorRegister; - - //Direct access to OD variable - uint32_t devType = ODxyz_0.x1000_deviceType; - ODxyz_0.x1018_identity.serialNumber = 0x12345678; -} - * @endcode - * @} */ - -/** - * @defgroup CO_ODinterface_OD_example Object Dictionary example - * @{ - * Actual Object dictionary for one CANopen device is defined by pair of - * OD_xyz.h and ODxyz.h files. - * - * "xyz" is name of Object Dictionary, usually "0" is used for default. - * Configuration with multiple Object Dictionaries is also possible. - * - * Data for OD definition are arranged inside multiple structures. Structures - * are different for different configuration of OD. Data objects, created with - * those structures, are constant or are variable. - * - * Actual OD variables are arranged inside multiple structures, so called - * storage groups. Selected groups can be stored to non-volatile memory. - * - * @warning - * Manual editing of ODxyz.h/.c files is very error-prone. - * - * Pair of ODxyz.h/.c files can be generated by OD editor tool. The tool can - * edit standard CANopen device description file in xml format. Xml file may - * include also some non-standard elements, specific to CANopenNode. Xml file is - * then used for automatic generation of ODxyz.h/.c files. - * - * ### Example ODxyz.h file - * @code -typedef struct { - uint32_t x1000_deviceType; - uint8_t x1001_errorRegister; - struct { - uint8_t maxSubIndex; - uint32_t vendorID; - uint32_t productCode; - uint32_t revisionNumber; - uint32_t serialNumber; - } x1018_identity; -} ODxyz_0_t; - -typedef struct { - uint8_t x1001_errorRegister; -} ODxyz_1_t; - -extern ODxyz_0_t ODxyz_0; -extern ODxyz_1_t ODxyz_1; -extern const OD_t ODxyz; - -#define ODxyz_1000_deviceType &ODxyz.list[0] -#define ODxyz_1001_errorRegister &ODxyz.list[1] -#define ODxyz_1018_identity &ODxyz.list[2] - * @endcode - * - * ### Example ODxyz.c file - * @code -#define OD_DEFINITION -#include "301/CO_ODinterface.h" -#include "ODxyz.h" - -typedef struct { - OD_extensionIO_t xio_1001_errorRegister; -} ODxyz_ext_t; - -typedef struct { - OD_obj_var_t o_1000_deviceType; - OD_obj_var_t orig_1001_errorRegister; - OD_obj_extended_t o_1001_errorRegister; - OD_obj_var_t o_1018_identity[5]; -} ODxyz_objs_t; - -ODxyz_0_t ODxyz_0 = { - .x1000_deviceType = 0L, - .x1018_identity = { - .maxSubIndex = 4, - .vendorID = 0L, - .productCode = 0L, - .revisionNumber = 0L, - .serialNumber = 0L, - }, -}; - -ODxyz_1_t ODxyz_1 = { - .x1001_errorRegister = 0, -}; - -static ODxyz_ext_t ODxyz_ext = {0}; - -static const ODxyz_objs_t ODxyz_objs = { - .o_1000_deviceType = { - .data = &ODxyz_0.x1000_deviceType, - .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, - }, - .orig_1001_errorRegister = { - .data = &ODxyz_1.x1001_errorRegister, - .attribute = ODA_SDO_R, - .dataLength = 1, - }, - .o_1001_errorRegister = { - .flagsPDO = NULL, - .extIO = &ODxyz_ext.xio_1001_errorRegister, - .odObjectOriginal = &ODxyz_objs.orig_1001_errorRegister, - }, - .o_1018_identity = { - { - .data = &ODxyz_0.x1018_identity.maxSubIndex, - .attribute = ODA_SDO_R, - .dataLength = 1, - }, - { - .data = &ODxyz_0.x1018_identity.vendorID, - .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, - }, - { - .data = &ODxyz_0.x1018_identity.productCode, - .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, - }, - { - .data = &ODxyz_0.x1018_identity.revisionNumber, - .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, - }, - { - .data = &ODxyz_0.x1018_identity.serialNumber, - .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, - }, - } -}; - -const OD_t ODxyz = { - 3, { - {0x1000, 0, 0, ODT_VAR, &ODxyz_objs.o_1000_deviceType}, - {0x1001, 0, 1, ODT_EVAR, &ODxyz_objs.o_1001_errorRegister}, - {0x1018, 4, 0, ODT_REC, &ODxyz_objs.o_1018_identity}, - {0x0000, 0, 0, 0, NULL} -}}; - * @endcode - * @} */ - - -/** - * @defgroup CO_ODinterface_XDD XML device description - * @{ - * CANopen device description - XML schema definition - is specified by CiA 311 - * standard. - * - * CiA 311 complies with standard ISO 15745-1:2005/Amd1 (Industrial automation - * systems and integration - Open systems application integration framework). - * - * CANopen device description is basically a XML file with all the information - * about CANopen device. The larges part of the file is a list of all object - * dictionary variables with all necessary properties and documentation. This - * file can be edited with OD editor application and can be used as data source, - * from which Object dictionary for CANopenNode is generated. Furthermore, this - * file can be used with CANopen configuration tool, which interacts with - * CANopen devices on running CANopen network. - * - * XML schema definitions are available at: http://www.canopen.org/xml/1.1 - * One of the tools for viewing XML schemas is "xsddiagram" - * (https://github.com/dgis/xsddiagram). - * - * CANopen specifies also another type of files for CANopen device description. - * These are EDS files, which are in INI format. It is possible to convert - * between those two formats. But CANopenNode uses XML format. - * - * The device description file has "XDD" file extension. The name of this file - * shall contain the vendor-ID of the CANopen device in the form of 8 - * hexadecimal digits in any position of the name and separated with - * underscores. For example "name1_12345678_name2.XDD". - * - * CANopenNode includes multiple profile definition files, one for each CANopen - * object. Those files have "XPD" extension. They are in the same XML format as - * XDD files. The XML editor tool can use XPD files to insert prepared data - * into device description file (XDD), which is being edited. - * - * ### XDD, XPD file example - * @code{.xml} - - - - ... - - ... - ... - - ... - - - - ... - ... - - - - - - ... - ... - - - - - - - - ... - ... - - - - - ... - ... - - - - - - ... - ... - - - - - - ... - ... - - - - - - ... - ... - - - - - - ... - ... - - - - - - - - ... - - - ... - - - - - - - - - - - ... - - - - - - - - - - - - - - - ... - - - - * @endcode - * - * ### Parameter description - * Above XML file example shows necessary data for OD interface used by - * CANopenNode and other parameters required by the standard. Standard specifies - * many other parameters, which are not used by CANopenNode for simplicity. - * - * XML file is divided into two parts: - * 1. "ProfileBody_Device_CANopen" - more standardized information - * 2. "ProfileBody_CommunicationNetwork_CANopen" - communication related info - * - * Most important part of the XML file is definition of each OD object. All - * OD objects are listed in "CANopenObjectList", which resides in the second - * part of the XML file. Each "CANopenObject" and "CANopenSubObject" of the list - * contains a link to parameter ("uniqueIDRef"), which resides in the first - * part of the XML file. So data for each OD object is split between two parts - * of the XML file. - * - * #### <CANopenObject> - * * "index" (required) - Object dictionary index - * * "name" (required) - Name of the parameter - * * "objectType" (required) - "7"=VAR, "8"=ARRAY, "9"=RECORD - * * "subNumber" (required if "objectType" is "8" or "9") - * * "PDOmapping" (optional if "objectType" is "7", default is "no"): - * * "no" - mapping not allowed - * * "default" - not used, same as "optional" - * * "optional" - mapping allowed to TPDO or RPDO - * * "TPDO" - mapping allowed to TPDO - * * "RPDO" mapping allowed to RPDO - * * "uniqueIDRef" (required or see below) - Reference to <parameter> - * - * #### <CANopenSubObject> - * * "subIndex" (required) - Object dictionary sub-index - * * "name" (required) - Name of the parameter - * * "objectType" (required, always "7") - * * "PDOmapping" (optional, same as above, default is "no") - * * "uniqueIDRef" (required or see below) - Reference to <parameter> - * - * #### uniqueIDRef - * This is required attribute from "CANopenObject" and "CANopenSubObject". It - * contains reference to <parameter> in "ProfileBody_Device_CANopen" - * section of the XML file. There are additional necessary properties. - * - * If "uniqueIDRef" attribute is not specified and "objectType" is 7(VAR), then - * "CANopenObject" or "CANopenSubObject" must contain additional attributes: - * * "dataType" (required for VAR) - CANopen basic data type, see below - * * "accessType" (required for VAR) - "ro", "wo", "rw" or "const" - * * "defaultValue" (optional) - Default value for the variable. - * * "denotation" (optional) - Not used by CANopenNode. - * - * #### <parameter> - * * "uniqueID" (required) - * * "access" (required for VAR) - can be one of: - * * "const" - same as "read" - * * "read" - only read access with SDO or PDO - * * "write" - only write access with SDO or PDO - * * "readWrite" - read or write access with SDO or PDO - * * "readWriteInput" - same as "readWrite" - * * "readWriteOutput" - same as "readWrite" - * * "noAccess" - object will be in Object Dictionary, but no access. - * * <label lang="en"> (required) - * * <description lang="en"> (required) - * * <UINT and similar/> (required) - Basic or complex data type. Basic - * data type (for VAR) is specified in IEC 61131-3 (see below). If data type - * is complex (ARRAY or RECORD), then <dataTypeIDRef> must be - * specified and entry must be added in the <dataTypeList>. Such - * definition of complex data types is required by the standard, but it is - * not required by CANopenNode. - * * <defaultValue> (optional for VAR) - Default value for the variable. - * - * Additional, optional, CANopenNode specific properties, which can be used - * inside parameters describing <CANopenObject>: - * * <property name="CO_storageGroup" value="..."> - group into which - * the C variable will belong. Variables from specific storage group may - * then be stored into non-volatile memory, automatically or by SDO command. - * Valid value is from 0x00 (default - not stored) to 0x7F. - * * <property name="CO_extensionIO" value="..."> - Valid value is - * "false" (default) or "true", if IO extension is enabled. - * * <property name="CO_flagsPDO" value="..."> - Valid value is - * "false" (default) or "true", if PDO flags are enabled. - * * <property name="CO_countLabel" value="..."> - Valid value is - * any string without spaces. OD exporter will generate a macro for each - * different string. For example, if four OD objects have "CO_countLabel" - * set to "TPDO", then macro "#define ODxyz_NO_TPDO 4" will be generated by - * OD exporter. - * - * Additional, optional, CANopenNode specific property, which can be used - * inside parameters describing "VAR": - * * <property name="CO_accessSRDO" value="..."> - Valid values are: - * "tx", "rx", "trx", "no"(default). - * * <property name="CO_byteLength" value="..."> - Length of the - * variable in bytes, optionaly used by string or domain. If CO_byteLength - * is not specified for string, then length is calculated from string - * <defaultValue>. - * - * #### CANopen basic data types - * | CANopenNode | IEC 61131-3 | CANopen | dataType | - * | ------------ | ------------ | --------------- | -------- | - * | bool_t | BOOL | BOOLEAN | 0x01 | - * | int8_t | CHAR, SINT | INTEGER8 | 0x02 | - * | int16_t | INT | INTEGER16 | 0x03 | - * | int32_t | DINT | INTEGER32 | 0x04 | - * | int64_t | LINT | INTEGER64 | 0x15 | - * | uint8_t | BYTE, USINT | UNSIGNED8 | 0x05 | - * | uint16_t | WORD, UINT | UNSIGNED16 | 0x06 | - * | uint32_t | DWORD, UDINT | UNSIGNED32 | 0x07 | - * | uint64_t | LWORD, ULINT | UNSIGNED64 | 0x1B | - * | float32_t | REAL | REAL32 | 0x08 | - * | float64_t | LREAL | REAL64 | 0x11 | - * | bytestring_t | STRING | VISIBLE_STRING | 0x09 | - * | bytestring_t | - | OCTET_STRING | 0x0A | - * | bytestring_t | WSTRING | UNICODE_STRING | 0x0B | - * | bytestring_t | - | TIME_OF_DAY | 0x0C | - * | bytestring_t | - | TIME_DIFFERENCE | 0x0D | - * | bytestring_t | - | DOMAIN | 0x0F | - * | bytestring_t | BITSTRING | - | - | - * - * #### <parameterGroupList> - * This is optional element and is not required by standard, nor by CANopenNode. - * This can be very useful for documentation, which can be organised into - * multiple chapters with multiple levels. CANopen objects can then be organised - * in any way, not only by index. - * - * #### Other elements - * Other elements listed in the above XML example are required by the standard - * and does not influence the CANopenNode object dictionary generator. - * @} */ - #ifndef OD_size_t /** Variable of type OD_size_t contains data length in bytes of OD variable */ @@ -655,46 +125,75 @@ typedef enum { ODA_RSRDO = 0x20, /**< Variable is mappable into receiving SRDO */ ODA_TRSRDO = 0x30, /**< Variable is mappable into tx or rx SRDO */ ODA_MB = 0x40, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */ - ODA_NOINIT = 0x80, /**< Variable has no initial value. Can be used with - OD objects, which has IO extension enabled. Object dictionary does not - reserve memory for the variable and storage is not used. */ + ODA_RESERVED = 0x80, /**< Reserved for further use */ } OD_attributes_t; /** - * Return codes from OD access functions + * Return codes from OD access functions. + * + * @ref OD_getSDOabCode() can be used to retrive corresponding SDO abort code. */ typedef enum { -/* !!!! WARNING !!!! */ -/* If changing these values, change also OD_getSDOabCode() function! */ - ODR_PARTIAL = -1, /**< Read/write is only partial, make more calls */ - ODR_OK = 0, /**< Read/write successfully finished */ - ODR_OUT_OF_MEM = 1, /**< Out of memory */ - ODR_UNSUPP_ACCESS = 2, /**< Unsupported access to an object */ - ODR_WRITEONLY = 3, /**< Attempt to read a write only object */ - ODR_READONLY = 4, /**< Attempt to write a read only object */ - ODR_IDX_NOT_EXIST = 5, /**< Object does not exist in the object dict. */ - ODR_NO_MAP = 6, /**< Object cannot be mapped to the PDO */ - ODR_MAP_LEN = 7, /**< PDO length exceeded */ - ODR_PAR_INCOMPAT = 8, /**< General parameter incompatibility reasons */ - ODR_DEV_INCOMPAT = 9, /**< General internal incompatibility in device */ - ODR_HW = 10, /**< Access failed due to hardware error */ - ODR_TYPE_MISMATCH = 11, /**< Data type does not match */ - ODR_DATA_LONG = 12, /**< Data type does not match, length too high */ - ODR_DATA_SHORT = 13, /**< Data type does not match, length too short */ - ODR_SUB_NOT_EXIST = 14, /**< Sub index does not exist */ - ODR_INVALID_VALUE = 15, /**< Invalid value for parameter (download only) */ - ODR_VALUE_HIGH = 16, /**< Value range of parameter written too high */ - ODR_VALUE_LOW = 17, /**< Value range of parameter written too low */ - ODR_MAX_LESS_MIN = 18, /**< Maximum value is less than minimum value */ - ODR_NO_RESOURCE = 19, /**< Resource not available: SDO connection */ - ODR_GENERAL = 20, /**< General error */ - ODR_DATA_TRANSF = 21, /**< Data cannot be transferred or stored to app */ - ODR_DATA_LOC_CTRL = 22, /**< Data can't be transf (local control) */ - ODR_DATA_DEV_STATE = 23, /**< Data can't be transf (present device state) */ - ODR_OD_MISSING = 23, /**< Object dictionary not present */ - ODR_NO_DATA = 25, /**< No data available */ - ODR_COUNT = 26 /**< Last element, number of responses */ +/* !!!! WARNING !!!! + * If changing these values, change also OD_getSDOabCode() function! + */ + /** Read/write is only partial, make more calls */ + ODR_PARTIAL = -1, + /** SDO abort 0x00000000 - Read/write successfully finished */ + ODR_OK = 0, + /** SDO abort 0x05040005 - Out of memory */ + ODR_OUT_OF_MEM = 1, + /** SDO abort 0x06010000 - Unsupported access to an object */ + ODR_UNSUPP_ACCESS = 2, + /** SDO abort 0x06010001 - Attempt to read a write only object */ + ODR_WRITEONLY = 3, + /** SDO abort 0x06010002 - Attempt to write a read only object */ + ODR_READONLY = 4, + /** SDO abort 0x06020000 - Object does not exist in the object dict. */ + ODR_IDX_NOT_EXIST = 5, + /** SDO abort 0x06040041 - Object cannot be mapped to the PDO */ + ODR_NO_MAP = 6, + /** SDO abort 0x06040042 - PDO length exceeded */ + ODR_MAP_LEN = 7, + /** SDO abort 0x06040043 - General parameter incompatibility reasons */ + ODR_PAR_INCOMPAT = 8, + /** SDO abort 0x06040047 - General internal incompatibility in device */ + ODR_DEV_INCOMPAT = 9, + /** SDO abort 0x06060000 - Access failed due to hardware error */ + ODR_HW = 10, + /** SDO abort 0x06070010 - Data type does not match */ + ODR_TYPE_MISMATCH = 11, + /** SDO abort 0x06070012 - Data type does not match, length too high */ + ODR_DATA_LONG = 12, + /** SDO abort 0x06070013 - Data type does not match, length too short */ + ODR_DATA_SHORT = 13, + /** SDO abort 0x06090011 - Sub index does not exist */ + ODR_SUB_NOT_EXIST = 14, + /** SDO abort 0x06090030 - Invalid value for parameter (download only) */ + ODR_INVALID_VALUE = 15, + /** SDO abort 0x06090031 - Value range of parameter written too high */ + ODR_VALUE_HIGH = 16, + /** SDO abort 0x06090032 - Value range of parameter written too low */ + ODR_VALUE_LOW = 17, + /** SDO abort 0x06090036 - Maximum value is less than minimum value */ + ODR_MAX_LESS_MIN = 18, + /** SDO abort 0x060A0023 - Resource not available: SDO connection */ + ODR_NO_RESOURCE = 19, + /** SDO abort 0x08000000 - General error */ + ODR_GENERAL = 20, + /** SDO abort 0x08000020 - Data cannot be transferred or stored to app */ + ODR_DATA_TRANSF = 21, + /** SDO abort 0x08000021 - Data can't be transf (local control) */ + ODR_DATA_LOC_CTRL = 22, + /** SDO abort 0x08000022 - Data can't be transf (present device state) */ + ODR_DATA_DEV_STATE = 23, + /** SDO abort 0x08000023 - Object dictionary not present */ + ODR_OD_MISSING = 23, + /** SDO abort 0x08000024 - No data available */ + ODR_NO_DATA = 25, + /** Last element, number of responses */ + ODR_COUNT = 26 } ODR_t; @@ -704,8 +203,15 @@ typedef enum { * Structure is initialized with @ref OD_getSub() function. */ typedef struct { - /** Pointer to data object, on which will operate read/write function */ - void *dataObject; + /** Pointer to original data object, defined by Object Dictionary. If + * memory for data object is not specified by Object Dictionary, then + * dataObjectOriginal is NULL. Default read/write functions operate on it. + */ + void *dataObjectOriginal; + /** Pointer to object, passed by @ref OD_extensionIO_init(). Can be used + * inside read / write functions from IO extension. + */ + void *object; /** Data length in bytes or 0, if length is not specified */ OD_size_t dataLength; /** In case of large data, dataOffset indicates position of already @@ -749,7 +255,8 @@ typedef struct { * be mapped. If corresponding bit is 0, TPDO will be sent. This means, that * if application sets variable pointed by flagsPDO to zero, it will trigger * sending all asynchronous TPDOs (up to first 63), to which variable is - * mapped. */ + * mapped. + */ OD_flagsPDO_t *flagsPDO; /** * Function pointer for reading value from specified variable from Object @@ -866,6 +373,32 @@ typedef struct { } OD_t; +/** + * Read value from original OD location + * + * This function can be used inside read / write functions, specified by + * @ref OD_extensionIO_init(). It reads data directly from memory location + * specified by Object dictionary. If no IO extension is used on OD entry, then + * subEntry->read returned by @ref OD_getSub() equals to this function. See + * also @ref OD_subEntry_t. + */ +OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, ODR_t *returnCode); + + +/** + * Write value to original OD location + * + * This function can be used inside read / write functions, specified by + * @ref OD_extensionIO_init(). It writes data directly to memory location + * specified by Object dictionary. If no IO extension is used on OD entry, then + * subEntry->write returned by @ref OD_getSub() equals to this function. See + * also @ref OD_subEntry_t. + */ +OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, ODR_t *returnCode); + + /** * Find OD entry in Object Dictionary * @@ -881,22 +414,41 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index); * Find sub-object with specified sub-index on OD entry returned by OD_find. * Function populates subEntry and stream structures with sub-object data. * - * @warning If this function is called on OD object, which has IO extension - * enabled and @ref OD_extensionIO_init() was not (yet) called on that object, - * then subEntry and stream structures are populated with properties of - * "original OD object". Call to this function after @ref OD_extensionIO_init() - * will populate subEntry and stream structures with properties of - * "newly initialised OD object". This is something very different. - * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. * @param [out] subEntry Structure will be populated on success. * @param [out] stream Structure will be populated on success. + * @param odOrig If true, then potential IO extension on entry will be + * ignored and access to data entry in the original OD location will be returned * * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, - OD_subEntry_t *subEntry, OD_stream_t *stream); + OD_subEntry_t *subEntry, OD_stream_t *stream, bool_t odOrig); + + +/** + * Return index from OD entry + * + * @param entry OD entry returned by @ref OD_find(). + * + * @return OD index + */ +static inline uint16_t OD_getIndex(const OD_entry_t *entry) { + return entry->index; +} + + +/** + * Return maxSubIndex from OD entry + * + * @param entry OD entry returned by @ref OD_find(). + * + * @return OD maxSubIndex + */ +static inline uint8_t OD_getMaxSubIndex(const OD_entry_t *entry) { + return entry->maxSubIndex; +} /** @@ -933,23 +485,28 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); * object, but data are read directly from (or written directly to) application * specified object via custom function calls. * - * One more feature is available on IO extended object. Before application calls - * @ref OD_extensionIO_init() it can read original OD object, which can contain - * initial values for the data. And also, as any data from OD, data can be - * loaded from or saved to nonvolatile storage. + * If this function is not called yet, then normal access ("odOrig" argument is + * false) to OD entry is disabled. + * + * @warning + * Object dictionary storage works only directly on OD variables. It does not + * access read function specified here. So, if extended OD objects needs to be + * preserved, then @ref OD_writeOriginal can be used inside custom write + * function. * * @warning * Read and write functions may be called from different threads, so critical * sections in custom functions must be protected with @ref CO_LOCK_OD() and * @ref CO_UNLOCK_OD(). * - * See also warning in @ref OD_getSub() function. - * * @param entry OD entry returned by @ref OD_find(). - * @param object Object, which will be passed to read or write function, must - * not be NULL. - * @param read Read function pointer, see @ref OD_subEntry_t. - * @param write Write function pointer, see @ref OD_subEntry_t. + * @param object Object, which will be passed to read or write function. + * @param read Read function pointer. If NULL, then read will be disabled. + * @ref OD_readOriginal can be used here to keep original read function. + * For function description see @ref OD_subEntry_t. + * @param write Write function pointer. If NULL, then write will be disabled. + * @ref OD_writeOriginal can be used here to keep original write function. + * For function description see @ref OD_subEntry_t. * * @return true on success, false if OD object doesn't exist or is not extended. */ @@ -966,49 +523,12 @@ bool_t OD_extensionIO_init(const OD_entry_t *entry, OD_size_t count, ODR_t *returnCode)); -/** - * Helper function for no read access - * - * This function can be used by application as argument to - * @ref OD_extensionIO_init(). It only returns ODR_WRITEONLY as returnCode. - */ -OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode); - -/** - * Helper function for no write access - * - * This function can be used by application as argument to - * @ref OD_extensionIO_init(). It only returns ODR_READONLY as returnCode. - */ -OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode); - - -/** - * Update storage group data from OD object with IO extension. - * - * This function must be called, before OD variables from specified storageGroup - * will be save to non-volatile memory. This function must be called, because - * some OD objects have IO extension enabled. And those OD object are connected - * with application code, which have own control over the entire OD object data. - * Application does not use original data from the storageGroup. For that reason - * this function scans entire object dictionary, reads data from necessary - * OD objects and copies them to the original storageGroup. - * - * @param od Object Dictionary - * @param storageGroup Group of data to update. - */ -void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup); - /** * @defgroup CO_ODgetSetters Getters and setters * @{ * - * Getter and setter helpre functions for accessing different types of Object + * Getter and setter helper functions for accessing different types of Object * Dictionary variables. */ /** @@ -1016,29 +536,43 @@ void OD_updateStorageGroup(OD_t *od, uint8_t storageGroup); * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. - * @param [out] val Value will be written there. + * @param [out] val Value will be written here. + * @param odOrig If true, then potential IO extension on entry will be + * ignored and data in the original OD location will be returned. * - * @return Value from @ref ODR_t, "ODR_OK" in case of success. + * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if + * variable does not exist in object dictionary or it does not have the correct + * length or other reason. */ -ODR_t OD_get_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t *val); +ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, + int8_t *val, bool_t odOrig); /** Get int16_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t *val); +ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, + int16_t *val, bool_t odOrig); /** Get int32_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t *val); +ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, + int32_t *val, bool_t odOrig); /** Get int64_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_i64(const OD_entry_t *entry, uint16_t subIndex, int64_t *val); +ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, + int64_t *val, bool_t odOrig); /** Get uint8_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t *val); +ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, + uint8_t *val, bool_t odOrig); /** Get uint16_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t *val); +ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, + uint16_t *val, bool_t odOrig); /** Get uint32_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t *val); +ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, + uint32_t *val, bool_t odOrig); /** Get uint64_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_u64(const OD_entry_t *entry, uint16_t subIndex, uint64_t *val); +ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, + uint64_t *val, bool_t odOrig); /** Get float32_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_r32(const OD_entry_t *entry, uint16_t subIndex, float32_t *val); +ODR_t OD_get_r32(const OD_entry_t *entry, uint8_t subIndex, + float32_t *val, bool_t odOrig); /** Get float64_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t *val); +ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, + float64_t *val, bool_t odOrig); /** * Set int8_t variable in Object Dictionary @@ -1046,39 +580,87 @@ ODR_t OD_get_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t *val); * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. * @param val Value to write. + * @param odOrig If true, then potential IO extension on entry will be + * ignored and data in the original OD location will be written. * - * @return Value from @ref ODR_t, "ODR_OK" in case of success. + * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if + * variable does not exist in object dictionary or it does not have the correct + * length or other reason. */ -ODR_t OD_set_i8(const OD_entry_t *entry, uint16_t subIndex, int8_t val); +ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, + int8_t val, bool_t odOrig); /** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_i16(const OD_entry_t *entry, uint16_t subIndex, int16_t val); +ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, + int16_t val, bool_t odOrig); /** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_i32(const OD_entry_t *entry, uint16_t subIndex, int32_t val); +ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, + int32_t val, bool_t odOrig); /** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_i64(const OD_entry_t *entry, uint16_t subIndex, int64_t val); +ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, + int64_t val, bool_t odOrig); /** Set uint8_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_u8(const OD_entry_t *entry, uint16_t subIndex, uint8_t val); +ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, + uint8_t val, bool_t odOrig); /** Set uint16_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_u16(const OD_entry_t *entry, uint16_t subIndex, uint16_t val); +ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, + uint16_t val, bool_t odOrig); /** Set uint32_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_u32(const OD_entry_t *entry, uint16_t subIndex, uint32_t val); +ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, + uint32_t val, bool_t odOrig); /** Set uint64_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_u64(const OD_entry_t *entry, uint16_t subIndex, uint64_t val); +ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, + uint64_t val, bool_t odOrig); /** Set float32_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_r32(const OD_entry_t *entry, uint16_t subIndex, float32_t val); +ODR_t OD_set_r32(const OD_entry_t *entry, uint8_t subIndex, + float32_t val, bool_t odOrig); /** Set float64_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_r64(const OD_entry_t *entry, uint16_t subIndex, float64_t val); +ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, + float64_t val, bool_t odOrig); + +/** + * Get pointer to int8_t variable from Object Dictionary + * + * Function always returns "dataObjectOriginal" pointer, which points to data + * in the original OD location. Take care, if IO extension is enabled on OD + * entry. + * + * @param entry OD entry returned by @ref OD_find(). + * @param subIndex Sub-index of the variable from the OD object. + * @param [out] val Pointer to variable will be written here. + * + * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if + * variable does not exist in object dictionary or it does not have the correct + * length or other reason. + */ +ODR_t OD_getPtr_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t **val); +/** Get pointer to int16_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t **val); +/** Get pointer to int32_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t **val); +/** Get pointer to int64_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t **val); +/** Get pointer to uint8_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t **val); +/** Get pointer to uint16_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t **val); +/** Get pointer to uint32_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t **val); +/** Get pointer to uint64_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t **val); +/** Get pointer to float32_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t **val); +/** Get pointer to float64_t variable from OD, see @ref OD_getPtr_i8 */ +ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val); /** @} */ /* CO_ODgetSetters */ +#if defined OD_DEFINITION || defined CO_DOXYGEN /** * @defgroup CO_ODdefinition OD definition objects * @{ * * Types and functions used only for definition of Object Dictionary */ -#if defined OD_DEFINITION || defined CO_DOXYGEN - /** * Types for OD object. */ @@ -1166,12 +748,11 @@ typedef struct { const void *odObjectOriginal; } OD_obj_extended_t; -#endif /* defined OD_DEFINITION */ - /** @} */ /* CO_ODdefinition */ +#endif /* defined OD_DEFINITION */ -/** @} */ +/** @} */ /* CO_ODinterface */ #ifdef __cplusplus } diff --git a/301/CO_config.h b/301/CO_config.h index 44410e0e..56adde60 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -165,38 +165,61 @@ extern "C" { * * Possible flags, can be ORed: * - CO_CONFIG_EM_PRODUCER - Enable emergency producer. - * - CO_CONFIG_EM_HISTORY - Enable error history - OD object 0x1003, + * - CO_CONFIG_EM_PROD_CONFIGURABLE - Emergency producer COB-ID is configurable, + * OD object 0x1014. If not configurable, then 0x1014 is read-only, COB_ID + * is set to CO_CAN_ID_EMERGENCY + nodeId and write is not verified. + * - CO_CONFIG_EM_PROD_INHIBIT - Enable inhibit timer on emergency producer, + * OD object 0x1015. + * - CO_CONFIG_EM_HISTORY - Enable error history, OD object 0x1003, * "Pre-defined error field" * - CO_CONFIG_EM_CONSUMER - Enable emergency consumer. + * - CO_CONFIG_EM_STATUS_BITS - Access @ref CO_EM_errorStatusBits_t from OD. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * emergency condition by CO_errorReport() or CO_errorReset() call. * Callback is configured by CO_EM_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_EM_process(). - * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of Emergency - * (Writing to object 0x1014 or 0x1015 re-configures the object). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER) +#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) #endif #define CO_CONFIG_EM_PRODUCER 0x01 -#define CO_CONFIG_EM_HISTORY 0x02 -#define CO_CONFIG_EM_CONSUMER 0x04 +#define CO_CONFIG_EM_PROD_CONFIGURABLE 0x02 +#define CO_CONFIG_EM_PROD_INHIBIT 0x04 +#define CO_CONFIG_EM_HISTORY 0x08 +#define CO_CONFIG_EM_STATUS_BITS 0x10 +#define CO_CONFIG_EM_CONSUMER 0x20 /** - * Maximum number of @ref CO_EM_errorStatusBits + * Maximum number of @ref CO_EM_errorStatusBits_t * - * Stack uses 6*8 = 48 @ref CO_EM_errorStatusBits others are free to use by - * manufacturer. Allowable value range is from 48 to 256 bits. Default is 80. + * Stack uses 6*8 = 48 @ref CO_EM_errorStatusBits_t, others are free to use by + * manufacturer. Allowable value range is from 48 to 256 bits in steps of 8. + * Default is 80. */ #ifdef CO_DOXYGEN #define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) #endif +/** + * Size of the internal buffer, where emergencies are stored after error + * indication with @ref CO_error() function. Each emergency has to be post- + * processed by the @ref CO_EM_process() function. In case of overflow, error is + * indicated but emergency message is not sent. + * + * The same buffer is also used for OD object 0x1003, "Pre-defined error field". + * + * Each buffer element consumes 8 bytes. Valid values are 1 to 254. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_EM_BUFFER_SIZE 16 +#endif + + /** * Condition for calculating CANopen Error register, "generic" error bit. * - * Condition must observe suitable @ref CO_EM_errorStatusBits and use + * Condition must observe suitable @ref CO_EM_errorStatusBits_t and use * corresponding member of errorStatusBits array from CO_EM_t to calculate the * condition. See also @ref CO_errorRegister_t. * @@ -211,17 +234,6 @@ extern "C" { #define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0) #endif -/** - * Condition for calculating CANopen Error register, "communication" error bit. - * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. - * - * em->errorStatusBits[2] and em->errorStatusBits[3] must be included in the - * condition, because they are used by the stack. - */ -#ifdef CO_DOXYGEN -#define CO_CONFIG_ERR_CONDITION_COMMUNICATION (em->errorStatusBits[2] || em->errorStatusBits[3]) -#endif - /** * Condition for calculating CANopen Error register, "current" error bit. * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. @@ -249,6 +261,17 @@ extern "C" { #define CO_CONFIG_ERR_CONDITION_TEMPERATURE #endif +/** + * Condition for calculating CANopen Error register, "communication" error bit. + * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. + * + * em->errorStatusBits[2] and em->errorStatusBits[3] must be included in the + * condition, because they are used by the stack. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_ERR_CONDITION_COMMUNICATION (em->errorStatusBits[2] || em->errorStatusBits[3]) +#endif + /** * Condition for calculating CANopen Error register, "device profile" error bit. * See @ref CO_CONFIG_ERR_CONDITION_GENERIC for description. diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md new file mode 100644 index 00000000..c2ecaa48 --- /dev/null +++ b/doc/objectDictionary.md @@ -0,0 +1,429 @@ +Object Dictionary +================= + +Definitions from CiA 301 +------------------------ +The **Object Dictionary** is a collection of all the data items which have an influence on the behavior of the application objects, the communication objects and the state machine used on this device. It serves as an interface between the communication and the application. +The object dictionary is essentially a grouping of objects accessible via the network in an ordered pre-defined fashion. Each object within the object dictionary is addressed using a 16-bit index and a 8-bit sub-index. + +A **SDO** (Service Data Object) is providing direct access to object entries of a CANopen device's object dictionary. As these object entries may contain data of arbitrary size and data type. SDOs may be used to transfer multiple data sets (each containing an arbitrary large block of data) from a client to a server and vice versa. The client shall control via a multiplexer (index and sub-index of the object dictionary) which data set shall be transferred. The content of the data set is defined within the object dictionary. + +A **PDO** (Process Data Object) is providing real-time data transfer of object entries of a CANopen device's object dictionary. The transfer of PDO is performed with no protocol overhead. The PDO correspond to objects in the object dictionary and provide the interface to the application objects. Data type and mapping of application objects into a PDO is determined by a corresponding PDO mapping structure within the object dictionary. + + +Operation +--------- +### Terms +The term **OD object** means object from object dictionary located at specific 16-bit index. There are different types of OD objects in CANopen: variables, arrays and records (structures). Each OD object contains pointer to actual data, data length(s) and attribute(s). See @ref OD_objectTypes_t. + +The term **OD variable** is basic variable of specified type. For example: int8_t, uint32_t, float64_t, ... or just sequence of binary data with known +or unknown data length. Each OD variable resides in Object dictionary at specified 16-bit index and 8-bit sub-index. + +The term **OD entry** means structure element, which contains some basic properties of the OD object, indication of type of OD object and pointer to all necessary data for the OD object. An array of OD entries together with information about total number of OD entries represents object dictionary as defined inside CANopenNode. See @ref OD_entry_t and @ref OD_t. + +### Access +Application and the stack have access to OD objects via universal @ref OD_t object and @ref OD_find() function. No direct access to custom structures, which define object dictionary, is required. Properties for specific OD variable is fetched with @ref OD_getSub() function. Access to actual variable is via **read** and **write** functions. Pointer to those two functions is fetched by @ref OD_getSub(). See @ref OD_stream_t and @ref OD_subEntry_t. See also shortcuts: @ref CO_ODgetSetters, for access to data of different type. + +### Optional extensions +There are some optional extensions to the object dictionary: + * **PDO flags** informs application, if specific OD variable was received or sent by PDO. And also gives the application ability to request a TPDO, to which variable is possibly mapped. + * **IO extension** gives the application ability to take full control over the OD object. Application can specify own **read** and **write** functions and own object, on which they operate. + +### Example usage +```c +extern const OD_t ODxyz; + +void myFunc(const OD_t *od) { + ODR_t ret; + const OD_entry_t *entry; + OD_subEntry_t subEntry; + OD_IO_t io1008; + char buf[50]; + OD_size_t bytesRd; + int error = 0; + + /* Init IO for "Manufacturer device name" at index 0x1008, sub-index 0x00 */ + entry = OD_find(od, 0x1008); + ret = OD_getSub(entry, 0x00, &subEntry, &io1008.stream, false); + io1008.read = subEntry.read; + /* Read with io1008, subindex = 0x00 */ + if (ret == ODR_OK) + bytesRd = io1008.read(&io1008.stream, 0x00, &buf[0], sizeof(buf), &ret); + if (ret != ODR_OK) error++; + + /* Use helper and set "Producer heartbeat time" at index 0x1017, sub 0x00 */ + ret = OD_set_u16(OD_find(od, 0x1017), 0x00, 500, false); + if (ret != ODR_OK) error++; +} +``` +There is no need to include ODxyt.h file, it is only necessary to know, we have ODxyz defined somewhere. + +Second example is simpler and use helper function to access OD variable. However it is not very efficient, because it goes through all search procedures. + +If access to the same variable is very frequent, it is better to use first example. After initialization, application has to remember only "io1008" object. Frequent reading of the variable is then very efficient. + +### Simple access to OD via globals +Some simple user applications can also access some OD variables directly via globals. + +@warning +If OD object has IO extension enabled, then direct access to its OD variables must not be used. Only valid access is via read or write or helper functions. + +```c +#include ODxyz.h + +void myFuncGlob(void) { + //Direct address instead of OD_find() + const OD_entry_t *entry_errReg = ODxyz_1001_errorRegister; + + //Direct access to OD variable + uint32_t devType = ODxyz_0.x1000_deviceType; + ODxyz_0.x1018_identity.serialNumber = 0x12345678; +} +``` + + +Object dictionary example +------------------------- +Actual Object dictionary for one CANopen device is defined by pair of OD_xyz.h and ODxyz.h files. + +Suffix "xyz" is unique name of the object dictionary. If single default object dictionary is used, suffix is omitted. Such way configuration with multiple object dictionaries is possible. + +Data for OD definition are arranged inside multiple structures. Structures are different for different configuration of OD. Data objects, created with those structures, are constant or are variable. + +Actual OD variables are arranged inside multiple structures, so called storage groups. Selected groups can optionally be stored to non-volatile memory. + +@warning +Manual editing of ODxyz.h/.c files is very error-prone. + +Pair of ODxyz.h/.c files can be generated by OD editor tool. The tool can edit standard CANopen device description file in xml format. Xml file may include also some non-standard elements, specific to CANopenNode. Xml file is then used for automatic generation of ODxyz.h/.c files. + +### Example ODxyz.h file +```c +typedef struct { + uint32_t x1000_deviceType; + uint8_t x1001_errorRegister; + struct { + uint8_t maxSubIndex; + uint32_t vendorID; + uint32_t productCode; + uint32_t revisionNumber; + uint32_t serialNumber; + } x1018_identity; +} ODxyz_0_t; + +typedef struct { + uint8_t x1001_errorRegister; +} ODxyz_1_t; + +extern ODxyz_0_t ODxyz_0; +extern ODxyz_1_t ODxyz_1; +extern const OD_t ODxyz; + +#define ODxyz_1000_deviceType &ODxyz.list[0] +#define ODxyz_1001_errorRegister &ODxyz.list[1] +#define ODxyz_1018_identity &ODxyz.list[2] +``` + +### Example ODxyz.c file +```c +#define OD_DEFINITION +#include "301/CO_ODinterface.h" +#include "ODxyz.h" + +typedef struct { + OD_extensionIO_t xio_1001_errorRegister; +} ODxyz_ext_t; + +typedef struct { + OD_obj_var_t o_1000_deviceType; + OD_obj_var_t orig_1001_errorRegister; + OD_obj_extended_t o_1001_errorRegister; + OD_obj_var_t o_1018_identity[5]; +} ODxyz_objs_t; + +ODxyz_0_t ODxyz_0 = { + .x1000_deviceType = 0L, + .x1018_identity = { + .maxSubIndex = 4, + .vendorID = 0L, + .productCode = 0L, + .revisionNumber = 0L, + .serialNumber = 0L, + }, +}; + +ODxyz_1_t ODxyz_1 = { + .x1001_errorRegister = 0, +}; + +static ODxyz_ext_t ODxyz_ext = {0}; + +static const ODxyz_objs_t ODxyz_objs = { + .o_1000_deviceType = { + .data = &ODxyz_0.x1000_deviceType, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + .orig_1001_errorRegister = { + .data = &ODxyz_1.x1001_errorRegister, + .attribute = ODA_SDO_R, + .dataLength = 1, + }, + .o_1001_errorRegister = { + .flagsPDO = NULL, + .extIO = &ODxyz_ext.xio_1001_errorRegister, + .odObjectOriginal = &ODxyz_objs.orig_1001_errorRegister, + }, + .o_1018_identity = { + { + .data = &ODxyz_0.x1018_identity.maxSubIndex, + .attribute = ODA_SDO_R, + .dataLength = 1, + }, + { + .data = &ODxyz_0.x1018_identity.vendorID, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + { + .data = &ODxyz_0.x1018_identity.productCode, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + { + .data = &ODxyz_0.x1018_identity.revisionNumber, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + { + .data = &ODxyz_0.x1018_identity.serialNumber, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4, + }, + } +}; + +const OD_t ODxyz = { + 3, { + {0x1000, 0, 0, ODT_VAR, &ODxyz_objs.o_1000_deviceType}, + {0x1001, 0, 1, ODT_EVAR, &ODxyz_objs.o_1001_errorRegister}, + {0x1018, 4, 0, ODT_REC, &ODxyz_objs.o_1018_identity}, + {0x0000, 0, 0, 0, NULL} +}}; +``` + + +XML device description +---------------------- +CANopen device description - XML schema definition - is specified by CiA 311 standard. + +CiA 311 complies with standard ISO 15745-1:2005/Amd1 (Industrial automation systems and integration - Open systems application integration framework). + +CANopen device description is basically a XML file with all the information about CANopen device. The larges part of the file is a list of all object dictionary variables with all necessary properties and documentation. This file can be edited with OD editor application and can be used as data source, from which Object dictionary for CANopenNode is generated. Furthermore, this file can be used with CANopen configuration tool, which interacts with CANopen devices on running CANopen network. + +XML schema definitions are available at: http://www.canopen.org/xml/1.1 One of the tools for viewing XML schemas is "xsddiagram" (https://github.com/dgis/xsddiagram). + +CANopen specifies also another type of files for CANopen device description. These are EDS files, which are in INI format. It is possible to convert between those two formats. But CANopenNode uses XML format. + +The device description file has "XDD" file extension. The name of this file shall contain the vendor-ID of the CANopen device in the form of 8 hexadecimal digits in any position of the name and separated with underscores. For example "name1_12345678_name2.XDD". + +CANopenNode includes multiple profile definition files, one for each CANopen object. Those files have "XPD" extension. They are in the same XML format as XDD files. The XML editor tool can use XPD files to insert prepared data into device description file (XDD), which is being edited. + +### XDD, XPD file example +```xml + + + + ... + + ... + ... + + ... + + + + ... + ... + + + + + + ... + ... + + + + + + + + ... + ... + + + + + ... + ... + + + + + + ... + ... + + + + + + ... + ... + + + + + + ... + ... + + + + + + ... + ... + + + + + + + + ... + + + ... + + + + + + + + + + + ... + + + + + + + + + + + + + + + ... + + + +``` + +### Parameter description +Above XML file example shows necessary data for OD interface used by CANopenNode and other parameters required by the standard. Standard specifies many other parameters, which are not used by CANopenNode for simplicity. + +XML file is divided into two parts: + 1. "ProfileBody_Device_CANopen" - more standardized information + 2. "ProfileBody_CommunicationNetwork_CANopen" - communication related info + +Most important part of the XML file is definition of each OD object. All OD objects are listed in "CANopenObjectList", which resides in the second part of the XML file. Each "CANopenObject" and "CANopenSubObject" of the list contains a link to parameter ("uniqueIDRef"), which resides in the first part of the XML file. So data for each OD object is split between two parts of the XML file. + +#### <CANopenObject> + * "index" (required) - Object dictionary index + * "name" (required) - Name of the parameter + * "objectType" (required) - "7"=VAR, "8"=ARRAY, "9"=RECORD + * "subNumber" (required if "objectType" is "8" or "9") + * "PDOmapping" (optional if "objectType" is "7", default is "no"): + * "no" - mapping not allowed + * "default" - not used, same as "optional" + * "optional" - mapping allowed to TPDO or RPDO + * "TPDO" - mapping allowed to TPDO + * "RPDO" mapping allowed to RPDO + * "uniqueIDRef" (required or see below) - Reference to <parameter> + +#### <CANopenSubObject> + * "subIndex" (required) - Object dictionary sub-index + * "name" (required) - Name of the parameter + * "objectType" (required, always "7") + * "PDOmapping" (optional, same as above, default is "no") + * "uniqueIDRef" (required or see below) - Reference to <parameter> + +#### uniqueIDRef +This is required attribute from "CANopenObject" and "CANopenSubObject". It contains reference to <parameter> in "ProfileBody_Device_CANopen" section of the XML file. There are additional necessary properties. + +If "uniqueIDRef" attribute is not specified and "objectType" is 7(VAR), then "CANopenObject" or "CANopenSubObject" must contain additional attributes: + * "dataType" (required for VAR) - CANopen basic data type, see below + * "accessType" (required for VAR) - "ro", "wo", "rw" or "const" + * "defaultValue" (optional) - Default value for the variable. + * "denotation" (optional) - Not used by CANopenNode. + +#### <parameter> + * "uniqueID" (required) + * "access" (required for VAR) - can be one of: + * "const" - same as "read" + * "read" - only read access with SDO or PDO + * "write" - only write access with SDO or PDO + * "readWrite" - read or write access with SDO or PDO + * "readWriteInput" - same as "readWrite" + * "readWriteOutput" - same as "readWrite" + * "noAccess" - object will be in object dictionary, but no access. + * <label lang="en"> (required) + * <description lang="en"> (required) + * <UINT and similar/> (required) - Basic or complex data type. Basic data type (for VAR) is specified in IEC 61131-3 (see below). If data type is complex (ARRAY or RECORD), then <dataTypeIDRef> must be specified and entry must be added in the <dataTypeList>. Such definition of complex data types is required by the standard, but it is not required by CANopenNode. + * <defaultValue> (optional for VAR) - Default value for the variable. + +Additional, optional, CANopenNode specific properties, which can be used inside parameters describing <CANopenObject>: + * <property name="CO_storageGroup" value="..."> - group into which the C variable will belong. Variables from specific storage group may then be stored into non-volatile memory, automatically or by SDO command. Valid value is from 0x00 (default - not stored) to 0x7F. + * <property name="CO_extensionIO" value="..."> - Valid value is "false" (default) or "true", if IO extension is enabled. + * <property name="CO_flagsPDO" value="..."> - Valid value is "false" (default) or "true", if PDO flags are enabled. + * <property name="CO_countLabel" value="..."> - Valid value is any string without spaces. OD exporter will generate a macro for each different string. For example, if four OD objects have "CO_countLabel" set to "TPDO", then macro "#define ODxyz_NO_TPDO 4" will be generated by OD exporter. + +Additional, optional, CANopenNode specific property, which can be used inside parameters describing "VAR": + * <property name="CO_accessSRDO" value="..."> - Valid values are: "tx", "rx", "trx", "no"(default). + * <property name="CO_byteLength" value="..."> - Length of the variable in bytes, optionally used by string or domain. If CO_byteLength is not specified for string, then length is calculated from string <defaultValue>. + +#### CANopen basic data types +| CANopenNode | IEC 61131-3 | CANopen | dataType | +| ------------ | ------------ | --------------- | -------- | +| bool_t | BOOL | BOOLEAN | 0x01 | +| int8_t | CHAR, SINT | INTEGER8 | 0x02 | +| int16_t | INT | INTEGER16 | 0x03 | +| int32_t | DINT | INTEGER32 | 0x04 | +| int64_t | LINT | INTEGER64 | 0x15 | +| uint8_t | BYTE, USINT | UNSIGNED8 | 0x05 | +| uint16_t | WORD, UINT | UNSIGNED16 | 0x06 | +| uint32_t | DWORD, UDINT | UNSIGNED32 | 0x07 | +| uint64_t | LWORD, ULINT | UNSIGNED64 | 0x1B | +| float32_t | REAL | REAL32 | 0x08 | +| float64_t | LREAL | REAL64 | 0x11 | +| bytestring_t | STRING | VISIBLE_STRING | 0x09 | +| bytestring_t | - | OCTET_STRING | 0x0A | +| bytestring_t | WSTRING | UNICODE_STRING | 0x0B | +| bytestring_t | - | TIME_OF_DAY | 0x0C | +| bytestring_t | - | TIME_DIFFERENCE | 0x0D | +| bytestring_t | - | DOMAIN | 0x0F | +| bytestring_t | BITSTRING | - | - | + +#### <parameterGroupList> +This is optional element and is not required by standard, nor by CANopenNode. This can be very useful for documentation, which can be organised into multiple chapters with multiple levels. CANopen objects can then be organised in any way, not only by index. + +#### Other elements +Other elements listed in the above XML example are required by the standard and does not influence the CANopenNode object dictionary generator. From d4b78771b310f7e9077a336bd820293a1e4b09df Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 21 Sep 2020 18:46:41 +0200 Subject: [PATCH 117/520] socketCAN: Add CO_CANptrSocketCan_t object for "CANptr" argument for CO_CANmodule_init() function --- socketCAN/CO_driver.c | 59 +++++++++++++++++++++--------------- socketCAN/CO_driver_target.h | 22 ++++++++++---- socketCAN/CO_main_basic.c | 12 ++++---- 3 files changed, 56 insertions(+), 37 deletions(-) diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 0b1022f9..9e421ea2 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -46,7 +46,9 @@ pthread_mutex_t CO_EMCY_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; #if CO_DRIVER_MULTI_INTERFACE == 0 -static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, const void *CANptr); +static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, + int can_ifindex, + int epoll_fd); #endif @@ -269,21 +271,27 @@ CO_ReturnError_t CO_CANmodule_init( rxArray[i].mask = 0xFFFFFFFFU; rxArray[i].object = NULL; rxArray[i].CANrx_callback = NULL; - rxArray[i].CANptr = NULL; + rxArray[i].can_ifindex = 0; rxArray[i].timestamp.tv_sec = 0; rxArray[i].timestamp.tv_nsec = 0; } #if CO_DRIVER_MULTI_INTERFACE == 0 /* add one interface */ - ret = CO_CANmodule_addInterface(CANmodule, CANptr); + if (CANptr == NULL) { + CO_CANmodule_disable(CANmodule); + return CO_ERROR_ILLEGAL_ARGUMENT; + } + CO_CANptrSocketCan_t *CANptrReal = (CO_CANptrSocketCan_t *)CANptr; + ret = CO_CANmodule_addInterface(CANmodule, + CANptrReal->can_ifindex, + CANptrReal->epoll_fd); if (ret != CO_ERROR_NO) { CO_CANmodule_disable(CANmodule); + return ret; } -#else - ret = CO_ERROR_NO; #endif - return ret; + return CO_ERROR_NO; } @@ -291,9 +299,9 @@ CO_ReturnError_t CO_CANmodule_init( #if CO_DRIVER_MULTI_INTERFACE == 0 static #endif -CO_ReturnError_t CO_CANmodule_addInterface( - CO_CANmodule_t *CANmodule, - const void *CANptr) +CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, + int can_ifindex, + int epoll_fd) { int32_t ret; int32_t tmp; @@ -322,8 +330,9 @@ CO_ReturnError_t CO_CANmodule_addInterface( } interface = &CANmodule->CANinterfaces[CANmodule->CANinterfaceCount - 1]; - interface->CANptr = CANptr; - ifName = if_indextoname((uintptr_t)interface->CANptr, interface->ifName); + interface->can_ifindex = can_ifindex; + interface->epoll_fd = epoll_fd; + ifName = if_indextoname(can_ifindex, interface->ifName); if (ifName == NULL) { log_printf(LOG_DEBUG, DBG_ERRNO, "if_indextoname()"); return CO_ERROR_ILLEGAL_ARGUMENT; @@ -370,7 +379,7 @@ CO_ReturnError_t CO_CANmodule_addInterface( /* bind socket */ memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.can_family = AF_CAN; - sockAddr.can_ifindex = (uintptr_t)interface->CANptr; + sockAddr.can_ifindex = can_ifindex; ret = bind(interface->fd, (struct sockaddr*)&sockAddr, sizeof(sockAddr)); if(ret < 0){ log_printf(LOG_ERR, CAN_BINDING_FAILED, interface->ifName); @@ -492,7 +501,7 @@ CO_ReturnError_t CO_CANrxBufferInit( /* Configure object variables */ buffer->object = object; buffer->CANrx_callback = CANrx_callback; - buffer->CANptr = NULL; + buffer->can_ifindex = 0; buffer->timestamp.tv_nsec = 0; buffer->timestamp.tv_sec = 0; @@ -524,7 +533,7 @@ CO_ReturnError_t CO_CANrxBufferInit( bool_t CO_CANrxBuffer_getInterface( CO_CANmodule_t *CANmodule, uint16_t ident, - const void **const CANptrRx, + int *can_ifindexRx, struct timespec *timestamp) { CO_CANrx_t *buffer; @@ -540,13 +549,13 @@ bool_t CO_CANrxBuffer_getInterface( buffer = &CANmodule->rxArray[index]; /* return values */ - if (CANptrRx != NULL) { - *CANptrRx = buffer->CANptr; + if (can_ifindexRx != NULL) { + *can_ifindexRx = buffer->can_ifindex; } if (timestamp != NULL) { *timestamp = buffer->timestamp; } - if (buffer->CANptr != NULL) { + if (buffer->can_ifindex != 0) { return true; } else { @@ -576,7 +585,7 @@ CO_CANtx_t *CO_CANtxBufferInit( CO_CANsetIdentToIndex(CANmodule->txIdentToIndex, index, ident, buffer->ident); #endif - buffer->CANptr = NULL; + buffer->can_ifindex = 0; /* CAN identifier and rtr */ buffer->ident = ident & CAN_SFF_MASK; @@ -597,7 +606,7 @@ CO_CANtx_t *CO_CANtxBufferInit( CO_ReturnError_t CO_CANtxBuffer_setInterface( CO_CANmodule_t *CANmodule, uint16_t ident, - const void *CANptrTx) + int can_ifindexTx) { if (CANmodule != NULL) { uint32_t index; @@ -606,7 +615,7 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface( if ((index == CO_INVALID_COB_ID) || (index > CANmodule->txSize)) { return CO_ERROR_ILLEGAL_ARGUMENT; } - CANmodule->txArray[index].CANptr = CANptrTx; + CANmodule->txArray[index].can_ifindex = can_ifindexTx; return CO_ERROR_NO; } @@ -727,8 +736,8 @@ CO_ReturnError_t CO_CANCheckSend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) for (i = 0; i < CANmodule->CANinterfaceCount; i++) { CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; - if ((buffer->CANptr == NULL) || - buffer->CANptr == interface->CANptr) { + if ((buffer->can_ifindex == 0) || + buffer->can_ifindex == interface->can_ifindex) { CO_ReturnError_t tmp; @@ -885,7 +894,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff { int32_t retval; int32_t ret; - const void *CANptr = NULL; + int can_ifindex = 0; CO_ReturnError_t err; CO_CANinterface_t *interface = NULL; struct epoll_event ev[1]; @@ -945,7 +954,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff if (ev[0].data.fd == interface->fd) { /* get interface handle */ - CANptr = interface->CANptr; + can_ifindex = interface->can_ifindex; /* get message */ err = CO_CANread(CANmodule, interface, &msg, ×tamp); if (err != CO_ERROR_NO) { @@ -984,7 +993,7 @@ int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buff if (msgIndex > -1) { /* Store message info */ CANmodule->rxArray[msgIndex].timestamp = timestamp; - CANmodule->rxArray[msgIndex].CANptr = CANptr; + CANmodule->rxArray[msgIndex].can_ifindex = can_ifindex; } retval = msgIndex; } diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 4cccf60b..d9c7463e 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -279,8 +279,7 @@ typedef struct { uint32_t mask; void *object; void (*CANrx_callback)(void *object, void *message); - const void *CANptr; /* CAN Interface identifier from last - message */ + int can_ifindex; /* CAN Interface index from last message */ struct timespec timestamp; /* time of reception of last message */ } CO_CANrx_t; @@ -292,17 +291,26 @@ typedef struct { uint8_t data[8]; volatile bool_t bufferFull; /* not used */ volatile bool_t syncFlag; /* info about transmit message */ - const void *CANptr; /* CAN Interface identifier to use */ + int can_ifindex; /* CAN Interface index to use */ } CO_CANtx_t; /* Max COB ID for standard frame format */ #define CO_CAN_MSG_SFF_MAX_COB_ID (1 << CAN_SFF_ID_BITS) +/* CAN interface object (CANptr), passed to CO_CANinit() */ +typedef struct { + int can_ifindex; /* CAN Interface index */ + int epoll_fd; /* File descriptor for epoll, which waits for + CAN receive event */ +} CO_CANptrSocketCan_t; + /* socketCAN interface object */ typedef struct { - const void *CANptr; /* CAN Interface identifier */ + int can_ifindex; /* CAN Interface index */ char ifName[IFNAMSIZ]; /* CAN Interface name */ + int epoll_fd; /* File descriptor for epoll, which waits for + CAN receive event */ int fd; /* socketCAN file descriptor */ #if CO_DRIVER_ERROR_REPORTING > 0 || defined CO_DOXYGEN CO_CANinterfaceErrorhandler_t errorhandler; @@ -374,12 +382,14 @@ static inline void CO_UNLOCK_OD() { * Function must be called after CO_CANmodule_init. * * @param CANmodule This object will be initialized. - * @param CANptr CAN module interface index (return value if_nametoindex(), NO pointer!). + * @param can_ifindex CAN Interface index + * @param epoll_fd File descriptor for epoll, which waits for CAN receive event * @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, - const void *CANptr); + int can_ifindex, + int epoll_fd); /** * Check on which interface the last message for one message buffer was received diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index b2c76293..f2c734a4 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -217,7 +217,7 @@ int main (int argc, char *argv[]) { CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_ReturnError_t err; CO_ReturnError_t odStorStatus_rom, odStorStatus_eeprom; - intptr_t CANdevice0Index = 0; + CO_CANptrSocketCan_t CANptr = {0}; int opt; bool_t firstRun = true; @@ -297,7 +297,7 @@ int main (int argc, char *argv[]) { if(optind < argc) { CANdevice = argv[optind]; - CANdevice0Index = if_nametoindex(CANdevice); + CANptr.can_ifindex = if_nametoindex(CANdevice); } if(!nodeIdFromArgs) { @@ -322,7 +322,7 @@ int main (int argc, char *argv[]) { exit(EXIT_FAILURE); } - if(CANdevice0Index == 0) { + if(CANptr.can_ifindex == 0) { log_printf(LOG_CRIT, DBG_NO_CAN_DEVICE, CANdevice); exit(EXIT_FAILURE); } @@ -383,11 +383,11 @@ int main (int argc, char *argv[]) { /* Enter CAN configuration. */ CANopenConfiguredOK = false; - CO_CANsetConfigurationMode((void *)CANdevice0Index); + CO_CANsetConfigurationMode((void *)&CANptr); /* initialize CANopen */ - err = CO_CANinit((void *)CANdevice0Index, 0 /* bit rate not used */); + err = CO_CANinit((void *)&CANptr, 0 /* bit rate not used */); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANinit()", err); exit(EXIT_FAILURE); @@ -520,7 +520,7 @@ int main (int argc, char *argv[]) { /* delete objects from memory */ CANrx_threadTmr_close(); threadMainWait_close(); - CO_delete((void *)CANdevice0Index); + CO_delete((void *)&CANptr); log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "finished"); From ac4ca2893a01c7f763e5fc90446564086a348876 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 23 Sep 2020 09:06:57 +0200 Subject: [PATCH 118/520] Remove duplicated CANopenConfiguredOK from main functions. Use CO->nodeIdUnconfigured instead. --- example/main_blank.c | 9 ++------- socketCAN/CO_main_basic.c | 19 +++++++------------ 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/example/main_blank.c b/example/main_blank.c index 3dd2778a..b645e71c 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -38,7 +38,6 @@ /* Global variables and objects */ - volatile static bool_t CANopenConfiguredOK = false; /* Indication if CANopen modules are configured */ volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */ uint8_t LED_red, LED_green; @@ -83,7 +82,6 @@ int main (void){ log_printf("CANopenNode - Reset communication...\n"); /* disable CAN and CAN interrupts */ - CANopenConfiguredOK = false; /* initialize CANopen */ err = CO_CANinit(CANmoduleAddress, pendingBitRate); @@ -98,10 +96,7 @@ int main (void){ } activeNodeId = pendingNodeId; err = CO_CANopenInit(activeNodeId); - if(err == CO_ERROR_NO) { - CANopenConfiguredOK = true; - } - else if(err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { log_printf("Error: CANopen initialization failed: %d\n", err); return 0; } @@ -113,7 +108,7 @@ int main (void){ /* Configure CANopen callbacks, etc */ - if(CANopenConfiguredOK) { + if(!CO->nodeIdUnconfigured) { } diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index f2c734a4..03931fbd 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -71,7 +71,6 @@ /* Other variables and objects */ -volatile static bool_t CANopenConfiguredOK = false; /* Indication if CANopen modules are configured */ static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ static uint8_t CO_pendingNodeId = 0xFF;/* Use value from Object Dictionary or by arguments (set to 1..127 * or unconfigured=0xFF). Can be changed by LSS slave. */ @@ -382,7 +381,6 @@ int main (int argc, char *argv[]) { /* Enter CAN configuration. */ - CANopenConfiguredOK = false; CO_CANsetConfigurationMode((void *)&CANptr); @@ -402,19 +400,16 @@ int main (int argc, char *argv[]) { CO_activeNodeId = CO_pendingNodeId; err = CO_CANopenInit(CO_activeNodeId); - if(err == CO_ERROR_NO) { - CANopenConfiguredOK = true; - } - else if(err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); exit(EXIT_FAILURE); } /* initialize part of threadMain and callbacks */ - threadMainWait_init(CANopenConfiguredOK); + threadMainWait_init(!CO->nodeIdUnconfigured); CO_LSSslave_initCfgStoreCallback(CO->LSSslave, NULL, LSScfgStoreCallback); - if(CANopenConfiguredOK) { + if(!CO->nodeIdUnconfigured) { CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, @@ -468,14 +463,14 @@ int main (int argc, char *argv[]) { #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_programStart(CANopenConfiguredOK); + app_programStart(!CO->nodeIdUnconfigured); #endif } /* if(firstRun) */ #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_communicationReset(CANopenConfiguredOK); + app_communicationReset(!CO->nodeIdUnconfigured); #endif @@ -492,7 +487,7 @@ int main (int argc, char *argv[]) { uint32_t timer1usDiff = threadMainWait_process(&reset); #ifdef CO_USE_APPLICATION - app_programAsync(CANopenConfiguredOK, timer1usDiff); + app_programAsync(!CO->nodeIdUnconfigured, thrEpTm.timeDifference_us); #endif CO_OD_storage_autoSave(&odStorAuto, timer1usDiff, 60000000); @@ -558,7 +553,7 @@ static void* rt_thread(void* arg) { #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_program1ms(CANopenConfiguredOK); + app_program1ms(!CO->nodeIdUnconfigured); #endif } From 23bc5d38a7bb1988a9e2ebec66af3b3900f429f6 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 29 Sep 2020 09:00:31 +0200 Subject: [PATCH 119/520] Reorganize socketCAN/CO_Linux_threads - Rename files to CO_epoll_interface - Object oriented, more flexible, separate functions - move epoll, timerfd and eventfd system calls from CO_driver.c to CO_epoll_interface.c --- Makefile | 2 +- README.md | 3 +- doc/CHANGELOG.md | 1 + socketCAN/CO_Linux_threads.c | 587 ------------------------------ socketCAN/CO_Linux_threads.h | 173 --------- socketCAN/CO_driver.c | 224 ++++-------- socketCAN/CO_driver_target.h | 44 ++- socketCAN/CO_epoll_interface.c | 638 +++++++++++++++++++++++++++++++++ socketCAN/CO_epoll_interface.h | 307 ++++++++++++++++ socketCAN/CO_error_msgs.h | 4 +- socketCAN/CO_main_basic.c | 74 ++-- 11 files changed, 1091 insertions(+), 966 deletions(-) delete mode 100644 socketCAN/CO_Linux_threads.c delete mode 100644 socketCAN/CO_Linux_threads.h create mode 100644 socketCAN/CO_epoll_interface.c create mode 100644 socketCAN/CO_epoll_interface.h diff --git a/Makefile b/Makefile index a3e87b39..988a21b4 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ INCLUDE_DIRS = \ SOURCES = \ $(DRV_SRC)/CO_driver.c \ $(DRV_SRC)/CO_error.c \ - $(DRV_SRC)/CO_Linux_threads.c \ + $(DRV_SRC)/CO_epoll_interface.c \ $(DRV_SRC)/CO_OD_storage.c \ $(CANOPEN_SRC)/301/CO_ODinterface.c \ $(CANOPEN_SRC)/301/CO_SDOserver.c \ diff --git a/README.md b/README.md index f3ebba58..8c1040fe 100644 --- a/README.md +++ b/README.md @@ -179,13 +179,14 @@ File structure - **CO_driver.c** - Interface between Linux socketCAN and CANopenNode. - **CO_error.h/.c** - Linux socketCAN Error handling object. - **CO_error_msgs.h** - Error definition strings and logging function. - - **CO_Linux_threads.h/.c** - Helper functions for implementing CANopen threads in Linux. + - **CO_epoll_interface.h/.c** - Helper functions for Linux epoll interface to CANopenNode. - **CO_OD_storage.h/.c** - Object Dictionary storage object for Linux SocketCAN. - **CO_main_basic.c** - Mainline for socketCAN (basic usage). - **doc/** - Directory with documentation - **CHANGELOG.md** - Change Log file. - **deviceSupport.md** - Information about supported devices. - **gettingStarted.md, LSSusage.md, traceUsage.md** - Getting started and usage. + - **objectDictionary.md** - Description of CANopen object dictionary interface. - **index.html** - Soft link to html/md_README.html. - **html** - Directory with documentation - must be generated by Doxygen. - **CANopen.h/.c** - Initialization and processing of CANopen objects. diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index a7c81f7d..f1c369c3 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -30,6 +30,7 @@ Change Log - CO_Linux_threads.h, function `void CANrx_threadTmr_init(uint16_t interval_in_milliseconds (changed to) uint32_t interval_in_microseconds)` - CO_CANrxBufferInit(): remove check COB ID already used. - change macros CO_DRIVER_MULTI_INTERFACE and CO_DRIVER_ERROR_REPORTING. To enable(disable), set to 1(0). +- Rename CO_Linux_threads.h/.c to CO_epoll_interface.h/.c and reorganize them. Move epoll, timerfd and eventfd system calls from CO_driver.c to here. ### Fixed - Bugfix in `CO_HBconsumer_process()`: argument `timeDifference_us` was set to 0 inside for loop, fixed now. - BUG in CO_HBconsumer.c #168 diff --git a/socketCAN/CO_Linux_threads.c b/socketCAN/CO_Linux_threads.c deleted file mode 100644 index 78185aee..00000000 --- a/socketCAN/CO_Linux_threads.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Helper functions for implementing CANopen threads in Linux - * - * @file Linux_threads.c - * @author Janez Paternoster - * @author Martin Wagner - * @copyright 2004 - 2015 Janez Paternoster - * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* following macro is necessary for accept4() function call (sockets) */ -#define _GNU_SOURCE - -#include "CANopen.h" -#include "CO_Linux_threads.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -#include -#include -#include -#include -#include -#include -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ - - -#ifndef LISTEN_BACKLOG -#define LISTEN_BACKLOG 50 -#endif - - -/* Helper function - get monotonic clock time in microseconds */ -static inline uint64_t CO_LinuxThreads_clock_gettime_us(void) -{ - struct timespec ts; - - (void)clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; -} - - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -/* write response string from gateway-ascii object */ -static size_t gtwa_write_response(void *object, const char *buf, size_t count) { - int* fd = (int *)object; - /* nWritten = count -> in case of error (non-existing fd) data are purged */ - size_t nWritten = count; - - if (fd != NULL && *fd >= 0) { - ssize_t n = write(*fd, (const void *)buf, count); - if (n >= 0) { - nWritten = (size_t)n; - } - else { - log_printf(LOG_DEBUG, DBG_ERRNO, "write(gtwa_response)"); - } - } - return nWritten; -} -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ - - -/* Mainline thread - Blocking (threadMainWait) ********************************/ -static struct { - uint64_t start; /* time value CO_process() was called last time in us */ - int epoll_fd; /* epoll file descriptor */ - int event_fd; /* notification event file descriptor */ - int timer_fd; /* interval timer file descriptor */ - uint32_t interval_us; /* interval for threadMainWait_process */ - struct itimerspec tm; /* structure for timer configuration */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - int32_t commandInterface; /* command interface type or tcp port */ - uint32_t socketTimeout_us; - uint32_t socketTimeoutTmr_us; - char *localSocketPath;/* path in case of local socket */ - int gtwa_fdSocket; /* gateway socket file descriptor */ - int gtwa_fd; /* gateway io stream file descriptor */ - bool_t freshCommand; -#endif -} tmw; - -static void threadMainWait_callback(void *object) -{ - (void)object; - /* send event to wake threadMainWait_process() */ - uint64_t u = 1; - ssize_t s; - s = write(tmw.event_fd, &u, sizeof(uint64_t)); - if (s != sizeof(uint64_t)) { - log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); - } -} - -void threadMainWait_init(bool_t CANopenConfiguredOK) -{ - /* Configure LSS slave callback function */ -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - CO_LSSslave_initCallbackPre(CO->LSSslave, NULL, threadMainWait_callback); -#endif - - /* Initial value for time calculation */ - tmw.start = CO_LinuxThreads_clock_gettime_us(); - - if (!CANopenConfiguredOK) - return; - - /* Configure callback functions */ - CO_NMT_initCallbackPre(CO->NMT, NULL, threadMainWait_callback); - CO_SDO_initCallbackPre(CO->SDO[0], NULL, threadMainWait_callback); - CO_EM_initCallbackPre(CO->em, NULL, threadMainWait_callback); - CO_HBconsumer_initCallbackPre(CO->HBcons, NULL, threadMainWait_callback); -#if CO_NO_SDO_CLIENT != 0 - CO_SDOclient_initCallbackPre(CO->SDOclient[0], NULL, - threadMainWait_callback); -#endif -#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_TIME_initCallbackPre(CO->TIME, NULL, threadMainWait_callback); -#endif -#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER - CO_LSSmaster_initCallbackPre(CO->LSSmaster, NULL, threadMainWait_callback); -#endif -#endif - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - CO_GTWA_initRead(CO->gtwa, gtwa_write_response, (void *)&tmw.gtwa_fd); - tmw.freshCommand = true; -#endif -} - -void threadMainWait_initOnce(uint32_t interval_us, - int32_t commandInterface, - uint32_t socketTimeout_ms, - char *localSocketPath) -{ - int ret; - struct epoll_event ev; - - /* Configure epoll for mainline */ - tmw.epoll_fd = epoll_create(1); - if (tmw.epoll_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_create()"); - exit(EXIT_FAILURE); - } - - /* Configure eventfd for notifications and add it to epoll */ - tmw.event_fd = eventfd(0, EFD_NONBLOCK); - if (tmw.event_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "eventfd()"); - exit(EXIT_FAILURE); - } - ev.events = EPOLLIN; - ev.data.fd = tmw.event_fd; - ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(event_fd)"); - exit(EXIT_FAILURE); - } - - /* Configure timer for interval_us and add it to epoll */ - tmw.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); - if (tmw.timer_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_create()"); - exit(EXIT_FAILURE); - } - tmw.interval_us = interval_us; - tmw.tm.it_interval.tv_sec = interval_us / 1000000; - tmw.tm.it_interval.tv_nsec = (interval_us % 1000000) * 1000; - tmw.tm.it_value.tv_sec = 0; - tmw.tm.it_value.tv_nsec = 1; - ret = timerfd_settime(tmw.timer_fd, 0, &tmw.tm, NULL); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_settime"); - exit(EXIT_FAILURE); - } - ev.events = EPOLLIN; - ev.data.fd = tmw.timer_fd; - ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(timer_fd)"); - exit(EXIT_FAILURE); - } - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - /* Configure gateway-ascii command interface (CiA309-3) */ - tmw.commandInterface = commandInterface; - tmw.socketTimeout_us = (socketTimeout_ms < (UINT_MAX / 1000 - 1000000)) ? - socketTimeout_ms * 1000 : (UINT_MAX - 1000000); - tmw.gtwa_fdSocket = -1; - tmw.gtwa_fd = -1; - - if (commandInterface == CO_COMMAND_IF_STDIO) { - tmw.gtwa_fd = STDIN_FILENO; - log_printf(LOG_INFO, DBG_COMMAND_STDIO_INFO); - } - else if (commandInterface == CO_COMMAND_IF_LOCAL_SOCKET) { - struct sockaddr_un addr; - tmw.localSocketPath = localSocketPath; - - /* Create, bind and listen local socket */ - tmw.gtwa_fdSocket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); - if(tmw.gtwa_fdSocket < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "socket(local)"); - exit(EXIT_FAILURE); - } - - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, localSocketPath, sizeof(addr.sun_path) - 1); - ret = bind(tmw.gtwa_fdSocket, (struct sockaddr *) &addr, - sizeof(struct sockaddr_un)); - if(ret < 0) { - log_printf(LOG_CRIT, DBG_COMMAND_LOCAL_BIND, localSocketPath); - exit(EXIT_FAILURE); - } - - ret = listen(tmw.gtwa_fdSocket, LISTEN_BACKLOG); - if(ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "listen(local)"); - exit(EXIT_FAILURE); - } - - log_printf(LOG_INFO, DBG_COMMAND_LOCAL_INFO, localSocketPath); - } - else if (commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN && - commandInterface <= CO_COMMAND_IF_TCP_SOCKET_MAX - ) { - struct sockaddr_in addr; - const int yes = 1; - - /* Create, bind and listen socket */ - tmw.gtwa_fdSocket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - if(tmw.gtwa_fdSocket < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "socket(tcp)"); - exit(EXIT_FAILURE); - } - - setsockopt(tmw.gtwa_fdSocket, SOL_SOCKET, SO_REUSEADDR, - &yes, sizeof(int)); - - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(commandInterface); - addr.sin_addr.s_addr = INADDR_ANY; - - ret = bind(tmw.gtwa_fdSocket, (struct sockaddr *) &addr, - sizeof(struct sockaddr_in)); - if(ret < 0) { - log_printf(LOG_CRIT, DBG_COMMAND_TCP_BIND, commandInterface); - exit(EXIT_FAILURE); - } - - ret = listen(tmw.gtwa_fdSocket, LISTEN_BACKLOG); - if(ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "listen(tcp)"); - exit(EXIT_FAILURE); - } - - log_printf(LOG_INFO, DBG_COMMAND_TCP_INFO, commandInterface); - } - else { - tmw.commandInterface = CO_COMMAND_IF_DISABLED; - } - - if (tmw.gtwa_fd >= 0) { - ev.events = EPOLLIN; - ev.data.fd = tmw.gtwa_fd; - ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fd)"); - exit(EXIT_FAILURE); - } - } - if (tmw.gtwa_fdSocket >= 0) { - /* prepare epool for listening for new socket connection. After - * connection will be accepted, fd for io operation will be defined. */ - ev.events = EPOLLIN | EPOLLONESHOT; - ev.data.fd = tmw.gtwa_fdSocket; - ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fdSocket)"); - exit(EXIT_FAILURE); - } - } -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ -} - -void threadMainWait_close(void) -{ - close(tmw.epoll_fd); - tmw.epoll_fd = -1; - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - if (tmw.commandInterface == CO_COMMAND_IF_LOCAL_SOCKET) { - if (tmw.gtwa_fd > 0) { - close(tmw.gtwa_fd); - } - close(tmw.gtwa_fdSocket); - /* Remove local socket file from filesystem. */ - if(remove(tmw.localSocketPath) < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "remove(local)"); - } - } - else if (tmw.commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN) { - if (tmw.gtwa_fd > 0) { - close(tmw.gtwa_fd); - } - close(tmw.gtwa_fdSocket); - } - tmw.gtwa_fd = -1; - tmw.gtwa_fdSocket = -1; -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ - - close(tmw.event_fd); - tmw.event_fd = -1; - - close(tmw.timer_fd); - tmw.timer_fd = -1; -} - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -static inline void socetAcceptEnableForEpoll(void) { - struct epoll_event ev; - int ret; - - ev.events = EPOLLIN | EPOLLONESHOT; - ev.data.fd = tmw.gtwa_fdSocket; - ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_MOD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fdSocket)"); - } -} -#endif - -uint32_t threadMainWait_process(CO_NMT_reset_cmd_t *reset) -{ - int ready; - struct epoll_event ev; - uint64_t ull; - ssize_t s; - uint32_t diff, timerNext_us; - - /* wait for event or timer expiration and read data from file descriptors */ - ready = epoll_wait(tmw.epoll_fd, &ev, 1, -1); - if (ready != 1 && errno != EINTR) { - log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_wait"); - } - else if (ev.data.fd == tmw.event_fd) { - s = read(tmw.event_fd, &ull, sizeof(uint64_t)); - if (s != sizeof(uint64_t)) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(event_fd)"); - } - } - else if (ev.data.fd == tmw.timer_fd) { - s = read(tmw.timer_fd, &ull, sizeof(uint64_t)); - if (s != sizeof(uint64_t) && errno != EAGAIN) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(timer_fd)"); - } - } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - else if (ev.data.fd == tmw.gtwa_fdSocket) { - bool_t fail = false; - - tmw.gtwa_fd = accept4(tmw.gtwa_fdSocket, NULL, NULL, SOCK_NONBLOCK); - if (tmw.gtwa_fd < 0) { - fail = true; - if (errno != EAGAIN && errno != EWOULDBLOCK) { - log_printf(LOG_CRIT, DBG_ERRNO, "accept(gtwa_fdSocket)"); - } - } - else { - int ret; - /* add fd to epoll */ - struct epoll_event ev2; - ev2.events = EPOLLIN; - ev2.data.fd = tmw.gtwa_fd; - ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_ADD, ev2.data.fd, &ev2); - if (ret < 0) { - fail = true; - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(add, gtwa_fd)"); - } - tmw.socketTimeoutTmr_us = 0; - } - - if (fail) { - socetAcceptEnableForEpoll(); - } - } - else if (ev.data.fd == tmw.gtwa_fd) { - char buf[CO_CONFIG_GTWA_COMM_BUF_SIZE]; - size_t space = CO->nodeIdUnconfigured ? - CO_CONFIG_GTWA_COMM_BUF_SIZE : - CO_GTWA_write_getSpace(CO->gtwa); - - s = read(tmw.gtwa_fd, buf, space); - - if (CO->nodeIdUnconfigured) { - /* purge data */ - } - else if (s < 0 && errno != EAGAIN) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(gtwa_fd)"); - } - else if (s >= 0) { - if (tmw.commandInterface == CO_COMMAND_IF_STDIO) { - /* simplify command interface on stdio, make hard to type - * sequence optional, prepend "[0] " to string, if missing */ - const char sequence[] = "[0] "; - bool_t closed = (buf[s-1] == '\n'); /* is command closed? */ - - if (buf[0] != '[' && (space - s) >= strlen(sequence) - && isgraph(buf[0]) && buf[0] != '#' - && closed && tmw.freshCommand - ) { - CO_GTWA_write(CO->gtwa, sequence, strlen(sequence)); - } - tmw.freshCommand = closed; - CO_GTWA_write(CO->gtwa, buf, s); - } - else { /* socket, local or tcp */ - if (s == 0) { - int ret; - /* EOF received, close connection and enable socket accept*/ - ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_DEL, - tmw.gtwa_fd, NULL); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, - "epoll_ctl(del, gtwa_fd)"); - } - if (close(tmw.gtwa_fd) < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd)"); - } - tmw.gtwa_fd = -1; - socetAcceptEnableForEpoll(); - } - else { - CO_GTWA_write(CO->gtwa, buf, s); - } - } - } - tmw.socketTimeoutTmr_us = 0; - } -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ - - /* calculate time difference since last call */ - ull = CO_LinuxThreads_clock_gettime_us(); - diff = (uint32_t)(ull - tmw.start); - tmw.start = ull; - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - /* if socket connection is established, verify timeout */ - if (tmw.socketTimeout_us > 0 && tmw.gtwa_fdSocket > 0 && tmw.gtwa_fd > 0) { - if (tmw.socketTimeoutTmr_us > tmw.socketTimeout_us) { - int ret; - /* timout expired, close current connection and accept next */ - ret = epoll_ctl(tmw.epoll_fd, EPOLL_CTL_DEL, tmw.gtwa_fd, NULL); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(del, gtwa_fd), tmo"); - } - if (close(tmw.gtwa_fd) < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd), tmo"); - } - tmw.gtwa_fd = -1; - socetAcceptEnableForEpoll(); - } - else { - tmw.socketTimeoutTmr_us += diff; - } - } -#endif - - /* stack will lower this, if necessary */ - timerNext_us = tmw.interval_us; - - /* process CANopen objects */ - *reset = CO_process(CO, diff, &timerNext_us); - - /* lower next timer interval if necessary */ - if (timerNext_us < tmw.interval_us) { - int ret; - /* add one microsecond extra delay and make sure it is not zero */ - timerNext_us += 1; - if (tmw.interval_us < 1000000) { - tmw.tm.it_value.tv_nsec = timerNext_us * 1000; - } - else { - tmw.tm.it_value.tv_sec = timerNext_us / 1000000; - tmw.tm.it_value.tv_nsec = (timerNext_us % 1000000) * 1000; - } - ret = timerfd_settime(tmw.timer_fd, 0, &tmw.tm, NULL); - if (ret < 0) { - log_printf(LOG_DEBUG, DBG_ERRNO, "timerfd_settime"); - } - } - - return diff; -} - - -/* Realtime thread (threadRT) *************************************************/ -static struct { - uint32_t us_interval; /* configured interval in us */ - int interval_fd; /* timer fd */ -} threadRT; - -void CANrx_threadTmr_init(uint32_t interval_us) -{ - struct itimerspec itval; - - threadRT.us_interval = interval_us; - /* set up non-blocking interval timer */ - threadRT.interval_fd = timerfd_create(CLOCK_MONOTONIC, 0); - (void)fcntl(threadRT.interval_fd, F_SETFL, O_NONBLOCK); - itval.it_interval.tv_sec = 0; - itval.it_interval.tv_nsec = interval_us * 1000; - itval.it_value = itval.it_interval; - (void)timerfd_settime(threadRT.interval_fd, 0, &itval, NULL); -} - -void CANrx_threadTmr_close(void) -{ - (void)close(threadRT.interval_fd); - threadRT.interval_fd = -1; -} - -uint32_t CANrx_threadTmr_process(void) -{ - int32_t result; - uint64_t i; - bool_t syncWas; - uint64_t missed = 0; - - result = CO_CANrxWait(CO->CANmodule[0], threadRT.interval_fd, NULL); - if (result < 0) { - result = read(threadRT.interval_fd, &missed, sizeof(missed)); - if (result > 0) { - /* at least one timer interval occurred */ - CO_LOCK_OD(); - - if(CO->CANmodule[0]->CANnormal) { - - for (i = 0; i <= missed; i++) { - -#if CO_NO_SYNC == 1 - /* Process Sync */ - syncWas = CO_process_SYNC(CO, threadRT.us_interval, NULL); -#else - syncWas = false; -#endif - /* Read inputs */ - CO_process_RPDO(CO, syncWas); - - /* Write outputs */ - CO_process_TPDO(CO, syncWas, threadRT.us_interval, NULL); - } - } - - CO_UNLOCK_OD(); - } - } - - return (uint32_t) missed; -} diff --git a/socketCAN/CO_Linux_threads.h b/socketCAN/CO_Linux_threads.h deleted file mode 100644 index c0c3f5e6..00000000 --- a/socketCAN/CO_Linux_threads.h +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Helper functions for implementing CANopen threads in Linux. - * - * @file CO_Linux_threads.h - * @ingroup CO_socketCAN - * @author Janez Paternoster - * @author Martin Wagner - * @copyright 2004 - 2015 Janez Paternoster - * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CO_LINUX_THREADS_H -#define CO_LINUX_THREADS_H - -#include "309/CO_gateway_ascii.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -/** - * Command interface type for gateway-ascii - */ -typedef enum { - CO_COMMAND_IF_DISABLED = -100, - CO_COMMAND_IF_STDIO = -2, - CO_COMMAND_IF_LOCAL_SOCKET = -1, - CO_COMMAND_IF_TCP_SOCKET_MIN = 0, - CO_COMMAND_IF_TCP_SOCKET_MAX = 0xFFFF -} CO_commandInterface_t; -#endif - - -/** - * @defgroup CO_socketCAN socketCAN - * @{ - * - * Linux specific interface to CANopenNode. - * - * CANopenNode runs on top of SocketCAN interface, which is part of the Linux - * kernel. For more info on Linux SocketCAN see - * https://www.kernel.org/doc/html/latest/networking/can.html - * - * CANopenNode runs in two threads: - * - timer based real-time thread for CAN receive, SYNC and PDO, see - * CANrx_threadTmr_process() - * - mainline thread for other processing, see threadMainWait_process() - * - * The "threads" specified here do not fork threads themselves, but require - * that two threads are provided by the calling application. - * - * Main references for Linux functions used here are Linux man pages and the - * book: The Linux Programming Interface by Michael Kerrisk. - */ - - -/** - * Initialize mainline thread - blocking. - * - * Function must be called always in communication reset section, after - * CO_CANopenInit(). - * - * @param CANopenConfiguredOK True, if node has successfully passed NMT - * initialization - it has a valid CANopen node-id, all CANopen objects - * are configured and CANopen runs normally. - */ -void threadMainWait_init(bool_t CANopenConfiguredOK); - - -/** - * Initialize once mainline thread - blocking. - * - * Function must be called only once, before node starts operating. - * - * @param interval_us Interval of the threadMainWait_process() - * @param commandInterface Command interface type from CO_commandInterface_t - * @param socketTimeout_ms Timeout for established socket connection in [ms] - * @param localSocketPath File path, if commandInterface is local socket - */ -void threadMainWait_initOnce(uint32_t interval_us, - int32_t commandInterface, - uint32_t socketTimeout_ms, - char *localSocketPath); - - -/** - * Cleanup mainline thread - blocking. - */ -void threadMainWait_close(void); - - -/** - * Process mainline thread - blocking. - * - * threadMainWait is non-realtime thread for CANopenNode processing. It is - * initialized by threadMainWait_init(). There is no configuration for CANopen - * objects. But there is configuration for epool, interval timer and eventfd. - * Function must be called inside loop. It blocks for correct time and unblocks - * automatically in case of event. It calls CO_process() function for processing - * mainline CANopen objects. - * For more basic function see threadMain_process() alternative. - * - * @param reset return value from CO_process() function. - * - * @return time difference since last call in microseconds - */ -uint32_t threadMainWait_process(CO_NMT_reset_cmd_t *reset); - - -/** - * Initialize realtime thread. - * - * @param interval_us Interval of periodic timer in microseconds, recommended - * value for realtime response: 1000 us - */ -void CANrx_threadTmr_init(uint32_t interval_us); - - -/** - * Terminate realtime thread. - */ -void CANrx_threadTmr_close(void); - - -/** - * Process real-time thread. - * - * CANrx_threadTmr is realtime thread for CANopenNode processing. It is - * initialized by CANrx_threadTmr_init(). There is no configuration for CANopen - * objects. But configuration for epool event notification facility is included - * in CO_CANmodule_init() from CO_driver.c. Epool is configured to monitor the - * following file descriptors: notify pipe, CANrx sockets from all interfaces - * and interval timer. - * - * CANrx_threadTmr_process() blocks on epoll_wait(). This is implemented inside - * CO_CANrxWait() from CO_driver.c. New CAN message is processed in - * CANrx_threadTmr_process() function, which calls CO_process_SYNC(), - * CO_process_RPDO() and CO_process_TPDO() functions for each expired timer - * interval. This function must be called inside an infinite loop. - * - * @remark If realtime is required, this thread must be registered as such in - * the Linux kernel. - * - * @return Number of interval timer passes since last call. - */ -uint32_t CANrx_threadTmr_process(void); - -/** @} */ - -#ifdef __cplusplus -} -#endif /*__cplusplus*/ - -#endif /* CO_LINUX_THREADS_H */ diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 9e421ea2..480540fa 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include "301/CO_driver.h" @@ -47,8 +46,7 @@ pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; #if CO_DRIVER_MULTI_INTERFACE == 0 static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, - int can_ifindex, - int epoll_fd); + int can_ifindex); #endif @@ -207,40 +205,17 @@ CO_ReturnError_t CO_CANmodule_init( { int32_t ret; uint16_t i; - struct epoll_event ev; (void)CANbitRate; /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ + if(CANmodule==NULL || CANptr == NULL || rxArray==NULL || txArray==NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } - /* Create epoll FD */ - CANmodule->fdEpoll = epoll_create(1); - if(CANmodule->fdEpoll < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_create()"); - CO_CANmodule_disable(CANmodule); - return CO_ERROR_SYSCALL; - } - - /* Create notification event */ - CANmodule->fdEvent = eventfd(0, EFD_NONBLOCK); - if (CANmodule->fdEvent < 0) { - log_printf(LOG_DEBUG, DBG_ERRNO, "eventfd"); - CO_CANmodule_disable(CANmodule); - return CO_ERROR_OUT_OF_MEMORY; - } - /* ...and add it to epoll */ - ev.events = EPOLLIN; - ev.data.fd = CANmodule->fdEvent; - ret = epoll_ctl(CANmodule->fdEpoll, EPOLL_CTL_ADD, ev.data.fd, &ev); - if(ret < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_ctl(eventfd)"); - CO_CANmodule_disable(CANmodule); - return CO_ERROR_SYSCALL; - } + CO_CANptrSocketCan_t *CANptrReal = (CO_CANptrSocketCan_t *)CANptr; /* Configure object variables */ + CANmodule->epoll_fd = CANptrReal->epoll_fd; CANmodule->CANinterfaces = NULL; CANmodule->CANinterfaceCount = 0; CANmodule->rxArray = rxArray; @@ -249,7 +224,6 @@ CO_ReturnError_t CO_CANmodule_init( CANmodule->txSize = txSize; CANmodule->CANerrorStatus = 0; CANmodule->CANnormal = false; - CANmodule->fdTimerRead = -1; #if CO_DRIVER_MULTI_INTERFACE > 0 for (i = 0; i < CO_CAN_MSG_SFF_MAX_COB_ID; i++) { CANmodule->rxIdentToIndex[i] = CO_INVALID_COB_ID; @@ -278,14 +252,8 @@ CO_ReturnError_t CO_CANmodule_init( #if CO_DRIVER_MULTI_INTERFACE == 0 /* add one interface */ - if (CANptr == NULL) { - CO_CANmodule_disable(CANmodule); - return CO_ERROR_ILLEGAL_ARGUMENT; - } - CO_CANptrSocketCan_t *CANptrReal = (CO_CANptrSocketCan_t *)CANptr; ret = CO_CANmodule_addInterface(CANmodule, - CANptrReal->can_ifindex, - CANptrReal->epoll_fd); + CANptrReal->can_ifindex); if (ret != CO_ERROR_NO) { CO_CANmodule_disable(CANmodule); return ret; @@ -300,8 +268,7 @@ CO_ReturnError_t CO_CANmodule_init( static #endif CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, - int can_ifindex, - int epoll_fd) + int can_ifindex) { int32_t ret; int32_t tmp; @@ -331,7 +298,6 @@ CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, interface = &CANmodule->CANinterfaces[CANmodule->CANinterfaceCount - 1]; interface->can_ifindex = can_ifindex; - interface->epoll_fd = epoll_fd; ifName = if_indextoname(can_ifindex, interface->ifName); if (ifName == NULL) { log_printf(LOG_DEBUG, DBG_ERRNO, "if_indextoname()"); @@ -408,7 +374,7 @@ CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, /* Add socket to epoll */ ev.events = EPOLLIN; ev.data.fd = interface->fd; - ret = epoll_ctl(CANmodule->fdEpoll, EPOLL_CTL_ADD, ev.data.fd, &ev); + ret = epoll_ctl(CANmodule->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); if(ret < 0){ log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_ctl(can)"); return CO_ERROR_SYSCALL; @@ -425,12 +391,13 @@ CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) { uint32_t i; - struct timespec wait; if (CANmodule == NULL) { return; } + CANmodule->CANnormal = false; + /* clear interfaces */ for (i = 0; i < CANmodule->CANinterfaceCount; i++) { CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; @@ -439,34 +406,15 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) CO_CANerror_disable(&interface->errorhandler); #endif - epoll_ctl(CANmodule->fdEpoll, EPOLL_CTL_DEL, interface->fd, NULL); + epoll_ctl(CANmodule->epoll_fd, EPOLL_CTL_DEL, interface->fd, NULL); close(interface->fd); interface->fd = -1; } + CANmodule->CANinterfaceCount = 0; if (CANmodule->CANinterfaces != NULL) { free(CANmodule->CANinterfaces); } - CANmodule->CANinterfaceCount = 0; - - /* cancel rx */ - if (CANmodule->fdEvent != -1) { - uint64_t u = 1; - ssize_t s; - s = write(CANmodule->fdEvent, &u, sizeof(uint64_t)); - if (s != sizeof(uint64_t)) { - log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); - } - /* give some time for delivery */ - wait.tv_sec = 0; - wait.tv_nsec = 50 /* ms */ * 1000000; - nanosleep(&wait, NULL); - close(CANmodule->fdEvent); - } - - if (CANmodule->fdEpoll >= 0) { - close(CANmodule->fdEpoll); - } - CANmodule->fdEpoll = -1; + CANmodule->CANinterfaces = NULL; if (CANmodule->rxFilter != NULL) { free(CANmodule->rxFilter); @@ -890,113 +838,69 @@ static int32_t CO_CANrxMsg( /* return index of received message /******************************************************************************/ -int32_t CO_CANrxWait(CO_CANmodule_t *CANmodule, int fdTimer, CO_CANrxMsg_t *buffer) +bool_t CO_CANrxFromEpoll(CO_CANmodule_t *CANmodule, + struct epoll_event *ev, + CO_CANrxMsg_t *buffer, + int32_t *msgIndex) { - int32_t retval; - int32_t ret; - int can_ifindex = 0; - CO_ReturnError_t err; - CO_CANinterface_t *interface = NULL; - struct epoll_event ev[1]; - struct can_frame msg; - struct timespec timestamp; - - if (CANmodule==NULL || CANmodule->CANinterfaceCount==0) { - return -1; + if (CANmodule == NULL || ev == NULL || CANmodule->CANinterfaceCount == 0) { + return false; } - if (fdTimer>=0 && fdTimer!=CANmodule->fdTimerRead) { - /* new timer, timer changed */ - epoll_ctl(CANmodule->fdEpoll, EPOLL_CTL_DEL, CANmodule->fdTimerRead, NULL); - ev[0].events = EPOLLIN; - ev[0].data.fd = fdTimer; - ret = epoll_ctl(CANmodule->fdEpoll, EPOLL_CTL_ADD, ev[0].data.fd, &ev[0]); - if(ret < 0){ - return -1; - } - CANmodule->fdTimerRead = fdTimer; - } + /* Verify for epoll events in CAN socket */ + for (uint32_t i = 0; i < CANmodule->CANinterfaceCount; i ++) { + CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; - /* - * blocking read using epoll - */ - do { - errno = 0; - ret = epoll_wait(CANmodule->fdEpoll, ev, sizeof(ev) / sizeof(ev[0]), -1); - if (errno == EINTR) { - /* try again */ - continue; - } - else if (ret < 0) { - /* epoll failed */ - return -1; - } - else if ((ev[0].events & (EPOLLERR | EPOLLHUP)) != 0) { - /* epoll detected close/error on socket. Try to pull event */ - errno = 0; - recv(ev[0].data.fd, &msg, sizeof(msg), MSG_DONTWAIT); - log_printf(LOG_DEBUG, DBG_CAN_RX_EPOLL, ev[0].events, strerror(errno)); - continue; - } - else if ((ev[0].events & EPOLLIN) != 0) { - /* one of the sockets is ready */ - if ((ev[0].data.fd == CANmodule->fdEvent) || - (ev[0].data.fd == fdTimer)) { - /* timer or notification event */ - return -1; + if (ev->data.fd == interface->fd) { + if ((ev->events & (EPOLLERR | EPOLLHUP)) != 0) { + struct can_frame msg; + /* epoll detected close/error on socket. Try to pull event */ + errno = 0; + recv(ev->data.fd, &msg, sizeof(msg), MSG_DONTWAIT); + log_printf(LOG_DEBUG, DBG_CAN_RX_EPOLL, + ev->events, strerror(errno)); } - else { - /* CAN socket */ - uint32_t i; - - for (i = 0; i < CANmodule->CANinterfaceCount; i ++) { - interface = &CANmodule->CANinterfaces[i]; - - if (ev[0].data.fd == interface->fd) { - /* get interface handle */ - can_ifindex = interface->can_ifindex; - /* get message */ - err = CO_CANread(CANmodule, interface, &msg, ×tamp); - if (err != CO_ERROR_NO) { - return -1; - } - /* no need to continue search */ - break; - } - } - } - } - } while (errno != 0); + else if ((ev->events & EPOLLIN) != 0) { + struct can_frame msg; + struct timespec timestamp; + + /* get message */ + CO_ReturnError_t err = CO_CANread(CANmodule, interface, + &msg, ×tamp); - /* - * evaluate Rx - */ - retval = -1; - if(CANmodule->CANnormal){ + if(err == CO_ERROR_NO && CANmodule->CANnormal) { - if (msg.can_id & CAN_ERR_FLAG) { - /* error msg */ + if (msg.can_id & CAN_ERR_FLAG) { + /* error msg */ #if CO_DRIVER_ERROR_REPORTING > 0 - CO_CANerror_rxMsgError(&interface->errorhandler, &msg); + CO_CANerror_rxMsgError(&interface->errorhandler, &msg); #endif - } - else { - /* data msg */ - int32_t msgIndex; - + } + else { + /* data msg */ #if CO_DRIVER_ERROR_REPORTING > 0 - /* clear listenOnly and noackCounter if necessary */ - CO_CANerror_rxMsg(&interface->errorhandler); + /* clear listenOnly and noackCounter if necessary */ + CO_CANerror_rxMsg(&interface->errorhandler); #endif - - msgIndex = CO_CANrxMsg(CANmodule, &msg, buffer); - if (msgIndex > -1) { - /* Store message info */ - CANmodule->rxArray[msgIndex].timestamp = timestamp; - CANmodule->rxArray[msgIndex].can_ifindex = can_ifindex; + int32_t idx = CO_CANrxMsg(CANmodule, &msg, buffer); + if (idx > -1) { + /* Store message info */ + CANmodule->rxArray[idx].timestamp = timestamp; + CANmodule->rxArray[idx].can_ifindex = + interface->can_ifindex; + } + if (msgIndex != NULL) { + *msgIndex = idx; + } + } + } } - retval = msgIndex; - } + else { + log_printf(LOG_DEBUG, DBG_EPOLL_UNKNOWN, + ev->events, ev->data.fd); + } + return true; + } /* if (ev->data.fd == interface->fd) */ } - return retval; + return false; } diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index d9c7463e..7d062a01 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef CO_DRIVER_CUSTOM #include "CO_driver_custom.h" @@ -309,8 +310,6 @@ typedef struct { typedef struct { int can_ifindex; /* CAN Interface index */ char ifName[IFNAMSIZ]; /* CAN Interface name */ - int epoll_fd; /* File descriptor for epoll, which waits for - CAN receive event */ int fd; /* socketCAN file descriptor */ #if CO_DRIVER_ERROR_REPORTING > 0 || defined CO_DOXYGEN CO_CANinterfaceErrorhandler_t errorhandler; @@ -331,10 +330,8 @@ typedef struct { uint16_t txSize; uint16_t CANerrorStatus; volatile bool_t CANnormal; - int fdEvent; /* notification event file descriptor */ - int fdEpoll; /* epoll FD for event, CANrx sockets in all - interfaces and fdTimerRead */ - int fdTimerRead; /* timer handle from CANrxWait() */ + int epoll_fd; /* File descriptor for epoll, which waits for + CAN receive event */ #if CO_DRIVER_MULTI_INTERFACE > 0 || defined CO_DOXYGEN /* Lookup tables Cob ID to rx/tx array index. * Only feasible for SFF Messages. */ @@ -383,13 +380,11 @@ static inline void CO_UNLOCK_OD() { * * @param CANmodule This object will be initialized. * @param can_ifindex CAN Interface index - * @param epoll_fd File descriptor for epoll, which waits for CAN receive event * @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, - int can_ifindex, - int epoll_fd); + int can_ifindex); /** * Check on which interface the last message for one message buffer was received @@ -433,13 +428,15 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface(CO_CANmodule_t *CANmodule, /** - * Functions receives CAN messages (blocking) + * Receives CAN messages from matching epoll event + * + * This function verifies, if epoll event matches event from any CANinterface. + * In case of match, message is read from CAN and pre-processed for CANopenNode + * objects. CAN error frames are also processed. * - * This function waits for received CAN message, CAN error frame, notification - * event or fdTimer expiration. In case of CAN message it searches _rxArray_ - from* CO_CANmodule_t and if matched it calls the corresponding CANrx_callback, - * optionally copies received CAN message to _buffer_ and returns index of - * matched _rxArray_. + * In case of CAN message function searches _rxArray_ from CO_CANmodule_t and + * if matched it calls the corresponding CANrx_callback, optionally copies + * received CAN message to _buffer_ and returns index of matched _rxArray_. * * This function can be used in two ways, which can be combined: * - automatic mode: If CANrx_callback is specified for matched _rxArray_, then @@ -447,16 +444,17 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface(CO_CANmodule_t *CANmodule, * - manual mode: evaluate message filters, return received message * * @param CANmodule This object. - * @param fdTimer File descriptor with activated timeout. If set to -1, then - * timer will not be used. File descriptor must be read - * externally if retval == -1! Read must be nonblocking and - * provides number of timer expirations since last read. + * @param ev Epoll event, which vill be verified for matches. * @param [out] buffer Storage for received message or _NULL_ if not used. - * @retval >= 0 index of received message in array from CO_CANmodule_t - * _rxArray_, copy of CAN message is available in _buffer_. - * @retval -1 no message received (timer expired or notification event or error) + * @param [out] msgIndex Index of received message in array from CO_CANmodule_t + * _rxArray_, copy of CAN message is available in _buffer_. + * + * @return True, if epoll event matches any CAN interface. */ -int32_t CO_CANrxWait(CO_CANmodule_t* CANmodule, int fdTimer, CO_CANrxMsg_t* buffer); +bool_t CO_CANrxFromEpoll(CO_CANmodule_t *CANmodule, + struct epoll_event *ev, + CO_CANrxMsg_t *buffer, + int32_t *msgIndex); /** @} */ diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c new file mode 100644 index 00000000..a9a33628 --- /dev/null +++ b/socketCAN/CO_epoll_interface.c @@ -0,0 +1,638 @@ +/* + * Helper functions for Linux epoll interface to CANopenNode. + * + * @file CO_epoll_interface.c + * @author Janez Paternoster + * @author Martin Wagner + * @copyright 2004 - 2015 Janez Paternoster + * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH + * + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* following macro is necessary for accept4() function call (sockets) */ +#define _GNU_SOURCE + +#include "CO_epoll_interface.h" + +#include +#include +#include +#include +#include + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#include +#include +#include +#include +#include +#include + +#ifndef LISTEN_BACKLOG +#define LISTEN_BACKLOG 50 +#endif +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ + + +/* EPOLL **********************************************************************/ +/* Helper function - get monotonic clock time in microseconds */ +static inline uint64_t clock_gettime_us(void) { + struct timespec ts; + + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; +} + +CO_ReturnError_t CO_epoll_create(CO_epoll_t *ep, uint32_t timerInterval_us) { + int ret; + struct epoll_event ev; + + if (ep == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* Configure epoll for mainline */ + ep->epoll_new = false; + ep->epoll_fd = epoll_create(1); + if (ep->epoll_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_create()"); + return CO_ERROR_SYSCALL; + } + + /* Configure eventfd for notifications and add it to epoll */ + ep->event_fd = eventfd(0, EFD_NONBLOCK); + if (ep->event_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "eventfd()"); + return CO_ERROR_SYSCALL; + } + ev.events = EPOLLIN; + ev.data.fd = ep->event_fd; + ret = epoll_ctl(ep->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(event_fd)"); + return CO_ERROR_SYSCALL; + } + + /* Configure timer for timerInterval_us and add it to epoll */ + ep->timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (ep->timer_fd < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_create()"); + return CO_ERROR_SYSCALL; + } + ep->tm.it_interval.tv_sec = timerInterval_us / 1000000; + ep->tm.it_interval.tv_nsec = (timerInterval_us % 1000000) * 1000; + ep->tm.it_value.tv_sec = 0; + ep->tm.it_value.tv_nsec = 1; + ret = timerfd_settime(ep->timer_fd, 0, &ep->tm, NULL); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_settime"); + return CO_ERROR_SYSCALL; + } + ev.events = EPOLLIN; + ev.data.fd = ep->timer_fd; + ret = epoll_ctl(ep->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(timer_fd)"); + return CO_ERROR_SYSCALL; + } + ep->timerInterval_us = timerInterval_us; + ep->previousTime_us = clock_gettime_us(); + ep->timeDifference_us = 0; + + return CO_ERROR_NO; +} + +void CO_epoll_close(CO_epoll_t *ep) { + if (ep == NULL) { + return; + } + + close(ep->epoll_fd); + ep->epoll_fd = -1; + + close(ep->event_fd); + ep->event_fd = -1; + + close(ep->timer_fd); + ep->timer_fd = -1; +} + + +void CO_epoll_wait(CO_epoll_t *ep) { + if (ep == NULL) { + return; + } + + /* wait for an event */ + int ready = epoll_wait(ep->epoll_fd, &ep->ev, 1, -1); + ep->epoll_new = true; + ep->timerEvent = false; + + /* calculate time difference since last call */ + uint64_t now = clock_gettime_us(); + ep->timeDifference_us = (uint32_t)(now - ep->previousTime_us); + ep->previousTime_us = now; + /* application may will lower this */ + ep->timerNext_us = ep->timerInterval_us; + + /* process event */ + if (ready != 1 && errno == EINTR) { + /* event from interrupt or signal, nothing to process, continue */ + ep->epoll_new = false; + } + else if (ready != 1) { + log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_wait"); + ep->epoll_new = false; + } + else if ((ep->ev.events & EPOLLIN) != 0 + && ep->ev.data.fd == ep->event_fd + ) { + uint64_t val; + ssize_t s = read(ep->event_fd, &val, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) { + log_printf(LOG_DEBUG, DBG_ERRNO, "read(event_fd)"); + } + ep->epoll_new = false; + } + else if ((ep->ev.events & EPOLLIN) != 0 + && ep->ev.data.fd == ep->timer_fd + ) { + uint64_t val; + ssize_t s = read(ep->timer_fd, &val, sizeof(uint64_t)); + if (s != sizeof(uint64_t) && errno != EAGAIN) { + log_printf(LOG_DEBUG, DBG_ERRNO, "read(timer_fd)"); + } + ep->epoll_new = false; + ep->timerEvent = true; + } +} + +void CO_epoll_processLast(CO_epoll_t *ep) { + if (ep == NULL) { + return; + } + + if (ep->epoll_new) { + log_printf(LOG_DEBUG, DBG_EPOLL_UNKNOWN, + ep->ev.events, ep->ev.data.fd); + ep->epoll_new = false; + } + + /* lower next timer interval if changed by application */ + if (ep->timerNext_us < ep->timerInterval_us) { + /* add one microsecond extra delay and make sure it is not zero */ + ep->timerNext_us += 1; + if (ep->timerInterval_us < 1000000) { + ep->tm.it_value.tv_nsec = ep->timerNext_us * 1000; + } + else { + ep->tm.it_value.tv_sec = ep->timerNext_us / 1000000; + ep->tm.it_value.tv_nsec = + (ep->timerNext_us % 1000000) * 1000; + } + int ret = timerfd_settime(ep->timer_fd, 0, &ep->tm, NULL); + if (ret < 0) { + log_printf(LOG_DEBUG, DBG_ERRNO, "timerfd_settime"); + } + } +} + + +/* MAINLINE *******************************************************************/ +/* Send event to wake CO_epoll_processMain() */ +static void wakeupCallback(void *object) { + CO_epoll_t *ep = (CO_epoll_t *)object; + uint64_t u = 1; + ssize_t s; + s = write(ep->event_fd, &u, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) { + log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); + } +} + +void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co) { + if (ep == NULL || co == NULL) { + return; + } + + /* Configure LSS slave callback function */ +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + CO_LSSslave_initCallbackPre(co->LSSslave, + (void *)ep, wakeupCallback); +#endif + + if (co->nodeIdUnconfigured) { + return; + } + + /* Configure callback functions */ + CO_NMT_initCallbackPre(co->NMT, + (void *)ep, wakeupCallback); + CO_SDO_initCallbackPre(co->SDO[0], + (void *)ep, wakeupCallback); + CO_EM_initCallbackPre(co->em, + (void *)ep, wakeupCallback); + CO_HBconsumer_initCallbackPre(co->HBcons, + (void *)ep, wakeupCallback); +#if CO_NO_SDO_CLIENT != 0 + CO_SDOclient_initCallbackPre(co->SDOclient[0], + (void *)ep, wakeupCallback); +#endif +#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE + CO_TIME_initCallbackPre(co->TIME, + (void *)ep, wakeupCallback); +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + CO_LSSmaster_initCallbackPre(co->LSSmaster, + (void *)ep, wakeupCallback); +#endif +#endif +} + +void CO_epoll_processMain(CO_epoll_t *ep, + CO_t *co, + CO_NMT_reset_cmd_t *reset) +{ + if (ep == NULL || co == NULL || reset == NULL) { + return; + } + + /* process CANopen objects */ + *reset = CO_process(co, ep->timeDifference_us, &ep->timerNext_us); +} + + +/* CANrx and REALTIME *********************************************************/ +void CO_epoll_processRT(CO_epoll_t *ep, + CO_t *co, + bool_t realtime) +{ + if (co == NULL || ep == NULL) { + return; + } + + /* Verify for epoll events */ + if (ep->epoll_new) { + if (CO_CANrxFromEpoll(co->CANmodule[0], &ep->ev, NULL, NULL)) { + ep->epoll_new = false; + } + } + + if (!realtime || ep->timerEvent) { + uint32_t *pTimerNext_us = realtime ? NULL : &ep->timerNext_us; + + CO_LOCK_OD(); + if (!co->nodeIdUnconfigured && co->CANmodule[0]->CANnormal) { + bool_t syncWas = false; + +#if CO_NO_SYNC == 1 + /* Process Sync */ + syncWas = CO_process_SYNC(co, ep->timeDifference_us, + pTimerNext_us); +#endif + /* Read inputs */ + CO_process_RPDO(co, syncWas); + + /* Write outputs */ + CO_process_TPDO(co, syncWas, ep->timeDifference_us, + pTimerNext_us); + + } + CO_UNLOCK_OD(); + } +} + +/* GATEWAY ********************************************************************/ +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +/* write response string from gateway-ascii object */ +static size_t gtwa_write_response(void *object, const char *buf, size_t count) { + int* fd = (int *)object; + /* nWritten = count -> in case of error (non-existing fd) data are purged */ + size_t nWritten = count; + + if (fd != NULL && *fd >= 0) { + ssize_t n = write(*fd, (const void *)buf, count); + if (n >= 0) { + nWritten = (size_t)n; + } + else { + log_printf(LOG_DEBUG, DBG_ERRNO, "write(gtwa_response)"); + } + } + return nWritten; +} + +static inline void socetAcceptEnableForEpoll(CO_epoll_gtw_t *epGtw) { + struct epoll_event ev; + int ret; + + ev.events = EPOLLIN | EPOLLONESHOT; + ev.data.fd = epGtw->gtwa_fdSocket; + ret = epoll_ctl(epGtw->epoll_fd, EPOLL_CTL_MOD, ev.data.fd, &ev); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fdSocket)"); + } +} + +CO_ReturnError_t CO_epoll_createGtw(CO_epoll_gtw_t *epGtw, + int epoll_fd, + int32_t commandInterface, + uint32_t socketTimeout_ms, + char *localSocketPath) +{ + int ret; + struct epoll_event ev; + + if (epGtw == NULL || epoll_fd < 0) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + + epGtw->epoll_fd = epoll_fd; + epGtw->commandInterface = commandInterface; + + epGtw->socketTimeout_us = (socketTimeout_ms < (UINT_MAX / 1000 - 1000000)) ? + socketTimeout_ms * 1000 : (UINT_MAX - 1000000); + epGtw->gtwa_fdSocket = -1; + epGtw->gtwa_fd = -1; + + if (commandInterface == CO_COMMAND_IF_STDIO) { + epGtw->gtwa_fd = STDIN_FILENO; + log_printf(LOG_INFO, DBG_COMMAND_STDIO_INFO); + } + else if (commandInterface == CO_COMMAND_IF_LOCAL_SOCKET) { + struct sockaddr_un addr; + epGtw->localSocketPath = localSocketPath; + + /* Create, bind and listen local socket */ + epGtw->gtwa_fdSocket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); + if(epGtw->gtwa_fdSocket < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "socket(local)"); + return CO_ERROR_SYSCALL; + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, localSocketPath, sizeof(addr.sun_path) - 1); + ret = bind(epGtw->gtwa_fdSocket, (struct sockaddr *) &addr, + sizeof(struct sockaddr_un)); + if(ret < 0) { + log_printf(LOG_CRIT, DBG_COMMAND_LOCAL_BIND, localSocketPath); + return CO_ERROR_SYSCALL; + } + + ret = listen(epGtw->gtwa_fdSocket, LISTEN_BACKLOG); + if(ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "listen(local)"); + return CO_ERROR_SYSCALL; + } + + log_printf(LOG_INFO, DBG_COMMAND_LOCAL_INFO, localSocketPath); + } + else if (commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN && + commandInterface <= CO_COMMAND_IF_TCP_SOCKET_MAX + ) { + struct sockaddr_in addr; + const int yes = 1; + + /* Create, bind and listen socket */ + epGtw->gtwa_fdSocket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if(epGtw->gtwa_fdSocket < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "socket(tcp)"); + return CO_ERROR_SYSCALL; + } + + setsockopt(epGtw->gtwa_fdSocket, SOL_SOCKET, SO_REUSEADDR, + &yes, sizeof(int)); + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(commandInterface); + addr.sin_addr.s_addr = INADDR_ANY; + + ret = bind(epGtw->gtwa_fdSocket, (struct sockaddr *) &addr, + sizeof(struct sockaddr_in)); + if(ret < 0) { + log_printf(LOG_CRIT, DBG_COMMAND_TCP_BIND, commandInterface); + return CO_ERROR_SYSCALL; + } + + ret = listen(epGtw->gtwa_fdSocket, LISTEN_BACKLOG); + if(ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "listen(tcp)"); + return CO_ERROR_SYSCALL; + } + + log_printf(LOG_INFO, DBG_COMMAND_TCP_INFO, commandInterface); + } + else { + epGtw->commandInterface = CO_COMMAND_IF_DISABLED; + } + + if (epGtw->gtwa_fd >= 0) { + ev.events = EPOLLIN; + ev.data.fd = epGtw->gtwa_fd; + ret = epoll_ctl(epGtw->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fd)"); + return CO_ERROR_SYSCALL; + } + } + if (epGtw->gtwa_fdSocket >= 0) { + /* prepare epoll for listening for new socket connection. After + * connection will be accepted, fd for io operation will be defined. */ + ev.events = EPOLLIN | EPOLLONESHOT; + ev.data.fd = epGtw->gtwa_fdSocket; + ret = epoll_ctl(epGtw->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fdSocket)"); + return CO_ERROR_SYSCALL; + } + } + + return CO_ERROR_NO; +} + +void CO_epoll_closeGtw(CO_epoll_gtw_t *epGtw) { + if (epGtw == NULL) { + return; + } + + if (epGtw->commandInterface == CO_COMMAND_IF_LOCAL_SOCKET) { + if (epGtw->gtwa_fd > 0) { + close(epGtw->gtwa_fd); + } + close(epGtw->gtwa_fdSocket); + /* Remove local socket file from filesystem. */ + if(remove(epGtw->localSocketPath) < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "remove(local)"); + } + } + else if (epGtw->commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN) { + if (epGtw->gtwa_fd > 0) { + close(epGtw->gtwa_fd); + } + close(epGtw->gtwa_fdSocket); + } + epGtw->gtwa_fd = -1; + epGtw->gtwa_fdSocket = -1; +} + +void CO_epoll_initCANopenGtw(CO_epoll_gtw_t *epGtw, CO_t *co) { + if (epGtw == NULL || co == NULL || co->nodeIdUnconfigured) { + return; + } + + CO_GTWA_initRead(co->gtwa, gtwa_write_response, (void *)&epGtw->gtwa_fd); + epGtw->freshCommand = true; +} + +void CO_epoll_processGtw(CO_epoll_gtw_t *epGtw, + CO_t *co, + CO_epoll_t *ep) +{ + if (epGtw == NULL || co == NULL || ep == NULL) { + return; + } + + /* Verify for epoll events */ + if (ep->epoll_new + && (ep->ev.data.fd == epGtw->gtwa_fdSocket + || ep->ev.data.fd == epGtw->gtwa_fd) + ) { + if ((ep->ev.events & (EPOLLERR | EPOLLHUP)) != 0) { + log_printf(LOG_DEBUG, DBG_GENERAL, + "socket error or hangup, event=", ep->ev.events); + } + if ((ep->ev.events & EPOLLIN) != 0 + && ep->ev.data.fd == epGtw->gtwa_fdSocket + ) { + bool_t fail = false; + + epGtw->gtwa_fd = accept4(epGtw->gtwa_fdSocket, + NULL, NULL, SOCK_NONBLOCK); + if (epGtw->gtwa_fd < 0) { + fail = true; + if (errno != EAGAIN && errno != EWOULDBLOCK) { + log_printf(LOG_CRIT, DBG_ERRNO, "accept(gtwa_fdSocket)"); + } + } + else { + /* add fd to epoll */ + struct epoll_event ev2; + ev2.events = EPOLLIN; + ev2.data.fd = epGtw->gtwa_fd; + int ret = epoll_ctl(ep->epoll_fd, + EPOLL_CTL_ADD, ev2.data.fd, &ev2); + if (ret < 0) { + fail = true; + log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(add, gtwa_fd)"); + } + epGtw->socketTimeoutTmr_us = 0; + } + + if (fail) { + socetAcceptEnableForEpoll(epGtw); + } + ep->epoll_new = false; + } + else if ((ep->ev.events & EPOLLIN) != 0 + && ep->ev.data.fd == epGtw->gtwa_fd + ) { + char buf[CO_CONFIG_GTWA_COMM_BUF_SIZE]; + size_t space = co->nodeIdUnconfigured ? + CO_CONFIG_GTWA_COMM_BUF_SIZE : + CO_GTWA_write_getSpace(co->gtwa); + + ssize_t s = read(epGtw->gtwa_fd, buf, space); + + if (co->nodeIdUnconfigured) { + /* purge data */ + } + else if (s < 0 && errno != EAGAIN) { + log_printf(LOG_DEBUG, DBG_ERRNO, "read(gtwa_fd)"); + } + else if (s >= 0) { + if (epGtw->commandInterface == CO_COMMAND_IF_STDIO) { + /* simplify command interface on stdio, make hard to type + * sequence optional, prepend "[0] " to string, if missing */ + const char sequence[] = "[0] "; + bool_t closed = (buf[s-1] == '\n'); /* is command closed? */ + + if (buf[0] != '[' && (space - s) >= strlen(sequence) + && isgraph(buf[0]) && buf[0] != '#' + && closed && epGtw->freshCommand + ) { + CO_GTWA_write(co->gtwa, sequence, strlen(sequence)); + } + epGtw->freshCommand = closed; + CO_GTWA_write(co->gtwa, buf, s); + } + else { /* socket, local or tcp */ + if (s == 0) { + /* EOF received, close connection and enable socket + * accepting */ + int ret = epoll_ctl(ep->epoll_fd, EPOLL_CTL_DEL, + epGtw->gtwa_fd, NULL); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, + "epoll_ctl(del, gtwa_fd)"); + } + if (close(epGtw->gtwa_fd) < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd)"); + } + epGtw->gtwa_fd = -1; + socetAcceptEnableForEpoll(epGtw); + } + else { + CO_GTWA_write(co->gtwa, buf, s); + } + } + } + epGtw->socketTimeoutTmr_us = 0; + + ep->epoll_new = false; + } + } /* if (ep->epoll_new) */ + + /* if socket connection is established, verify timeout */ + if (epGtw->socketTimeout_us > 0 + && epGtw->gtwa_fdSocket > 0 && epGtw->gtwa_fd > 0) + { + if (epGtw->socketTimeoutTmr_us > epGtw->socketTimeout_us) { + /* timout expired, close current connection and accept next */ + int ret = epoll_ctl(ep->epoll_fd, + EPOLL_CTL_DEL, epGtw->gtwa_fd, NULL); + if (ret < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, + "epoll_ctl(del, gtwa_fd), tmo"); + } + if (close(epGtw->gtwa_fd) < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd), tmo"); + } + epGtw->gtwa_fd = -1; + socetAcceptEnableForEpoll(epGtw); + } + else { + epGtw->socketTimeoutTmr_us += ep->timeDifference_us; + } + } +} +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ diff --git a/socketCAN/CO_epoll_interface.h b/socketCAN/CO_epoll_interface.h new file mode 100644 index 00000000..8b01dac6 --- /dev/null +++ b/socketCAN/CO_epoll_interface.h @@ -0,0 +1,307 @@ +/** + * Helper functions for Linux epoll interface to CANopenNode. + * + * @file CO_epoll_interface.h + * @ingroup CO_epoll_interface + * @author Janez Paternoster + * @author Martin Wagner + * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH + * + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CO_EPOLL_INTERFACE_H +#define CO_EPOLL_INTERFACE_H + +#include "CANopen.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_socketCAN socketCAN + * @{ + * + * Linux specific interface to CANopenNode. + * + * Linux includes CAN interface inside its kernel, so called SocketCAN. It + * operates as a network device. For more information on Linux SocketCAN see + * https://www.kernel.org/doc/html/latest/networking/can.html + * + * Linux specific files for interfacing with Linux SocketCAN are located inside + * "CANopenNode/socketCAN" directory. + * + * CANopenNode runs as a set of non-blocking functions. It can run in single or + * multiple threads. Best approach for RT IO device can be with two threads: + * - timer based real-time thread for CAN receive, SYNC and PDO, see + * @ref CO_epoll_processRT() + * - mainline thread for other processing, see @ref CO_epoll_processMain() + * + * Main references for Linux functions used here are Linux man pages and the + * book: The Linux Programming Interface by Michael Kerrisk. + * @} + */ + +/** + * @defgroup CO_epoll_interface Epoll interface + * @ingroup CO_socketCAN + * @{ + * + * Linux epoll interface to CANopenNode. + * + * The Linux epoll API performs a monitoring multiple file descriptors to see + * if I/O is possible on any of them. + * + * CANopenNode uses epoll interface to provide an event based mechanism. Epoll + * waits for multiple different events, such as: interval timer event, + * notification event, CAN receive event or socket based event for gateway. + * CANopenNode non-blocking functions are processed after each event. + * + * CANopenNode itself offers functionality for calculation of time, when next + * interval timer event should trigger the processing. It can also trigger + * notification events in case of multi-thread operation. + */ + +/** + * Object for epoll, timer and event API. + */ +typedef struct { + /** Epoll file descriptor */ + int epoll_fd; + /** Notification event file descriptor */ + int event_fd; + /** Interval timer file descriptor */ + int timer_fd; + /** Interval of the timer in microseconds, from @ref CO_epoll_create() */ + uint32_t timerInterval_us; + /** Time difference since last @ref CO_epoll_wait() execution in + * microseconds */ + uint32_t timeDifference_us; + /** Timer value in microseconds, which can be changed by application and can + * shorten time of next @ref CO_epoll_wait() execution */ + uint32_t timerNext_us; + /** True,if timer event is inside @ref CO_epoll_wait() */ + bool_t timerEvent; + /** time value from the last process call in microseconds */ + uint64_t previousTime_us; + /** Structure for timerfd */ + struct itimerspec tm; + /** Structure for epoll_wait */ + struct epoll_event ev; + /** true, if new epoll event is necessary to process */ + bool_t epoll_new; +} CO_epoll_t; + +/** + * Create Linux epoll, timerfd and eventfd + * + * Create and configure multiple Linux notification facilities, which trigger + * execution of the task. Epoll blocks and monitors multiple file descriptors, + * timerfd triggers in constant timer intervals and eventfd triggers on external + * signal. + * + * @param ep This object + * @param timerInterval_us Timer interval in microseconds + * + * @return @ref CO_ReturnError_t CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or + * CO_ERROR_SYSCALL. + */ +CO_ReturnError_t CO_epoll_create(CO_epoll_t *ep, uint32_t timerInterval_us); + +/** + * Close epoll, timerfd and eventfd + * + * @param ep This object + */ +void CO_epoll_close(CO_epoll_t *ep); + +/** + * Wait for an epoll event + * + * This function blocks until event registered on epoll: timerfd, eventfd, or + * application specified event. Function also calculates timeDifference_us since + * last call and prepares timerNext_us. + * + * @param ep This object + */ +void CO_epoll_wait(CO_epoll_t *ep); + +/** + * Closing function for an epoll event + * + * This function must be called after @ref CO_epoll_wait(). Between them + * should be application specified processing functions, which can check for + * own events and do own processing. Application may also lower timerNext_us + * variable. If lowered, then interval timer will be reconfigured and + * @ref CO_epoll_wait() will be triggered earlier. + * + * @param ep This object + */ +void CO_epoll_processLast(CO_epoll_t *ep); + +/** + * Initialization of functions in CANopen reset-communication section + * + * Configure callbacks for CANopen objects. + * + * @param ep This object + * @param co CANopen object + */ +void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co); + +/** + * Process CANopen mainline functions + * + * This function calls @ref CO_process(). It is non-blocking and should execute + * cyclically. It should be between @ref CO_epoll_wait() and + * @ref CO_epoll_processLast() functions. + * + * @param ep This object + * @param co CANopen object + * @param [out] reset Return from @ref CO_process(). + */ +void CO_epoll_processMain(CO_epoll_t *ep, + CO_t *co, + CO_NMT_reset_cmd_t *reset); + + +/** + * Process CAN receive and realtime functions + * + * This function checks epoll for CAN receive event and processes CANopen + * realtime functions: @ref CO_process_SYNC(), @ref CO_process_RPDO() and + * @ref CO_process_TPDO(). It is non-blocking and should execute cyclically. + * It should be between @ref CO_epoll_wait() and @ref CO_epoll_processLast() + * functions. + * + * Function can be used in the mainline thread or in own realtime thread. + * + * Processing of CANopen realtime functions is protected with @ref CO_LOCK_OD. + * Also Node-Id must be configured and CANmodule must be in CANnormal for + * processing. + * + * @param ep Pointer to @ref CO_epoll_t object. + * @param co CANopen object + * @param realtime Set to true, if function is called from the own realtime + * thread, and is executed at short constant interval. + */ +void CO_epoll_processRT(CO_epoll_t *ep, + CO_t *co, + bool_t realtime); + + +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN +/** + * Command interface type for gateway-ascii + */ +typedef enum { + CO_COMMAND_IF_DISABLED = -100, + CO_COMMAND_IF_STDIO = -2, + CO_COMMAND_IF_LOCAL_SOCKET = -1, + CO_COMMAND_IF_TCP_SOCKET_MIN = 0, + CO_COMMAND_IF_TCP_SOCKET_MAX = 0xFFFF +} CO_commandInterface_t; + +/** + * Object for gateway + */ +typedef struct { + /** Epoll file descriptor, from @ref CO_epoll_createGtw() */ + int epoll_fd; + /** Command interface type or tcp port number, see + * @ref CO_commandInterface_t */ + int32_t commandInterface; + /** Socket timeout in microseconds */ + uint32_t socketTimeout_us; + /** Socket timeout timer in microseconds */ + uint32_t socketTimeoutTmr_us; + /** Path in case of local socket */ + char *localSocketPath; + /** Gateway socket file descriptor */ + int gtwa_fdSocket; + /** Gateway io stream file descriptor */ + int gtwa_fd; + /** Indication of fresh command */ + bool_t freshCommand; +} CO_epoll_gtw_t; + +/** + * Create socket for gateway-ascii command interface and add it to epoll + * + * Depending on arguments function configures stdio interface or local socket + * or IP socket. + * + * @param epGtw This object + * @param epoll_fd Already configured epoll file descriptor + * @param commandInterface Command interface type from CO_commandInterface_t + * @param socketTimeout_ms Timeout for established socket connection in [ms] + * @param localSocketPath File path, if commandInterface is local socket + * + * @return @ref CO_ReturnError_t CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or + * CO_ERROR_SYSCALL. + */ +CO_ReturnError_t CO_epoll_createGtw(CO_epoll_gtw_t *epGtw, + int epoll_fd, + int32_t commandInterface, + uint32_t socketTimeout_ms, + char *localSocketPath); + +/** + * Close gateway-ascii sockets + * + * @param epGtw This object + */ +void CO_epoll_closeGtw(CO_epoll_gtw_t *epGtw); + +/** + * Initialization of gateway functions in CANopen reset-communication section + * + * @param epGtw This object + * @param co CANopen object + */ +void CO_epoll_initCANopenGtw(CO_epoll_gtw_t *epGtw, CO_t *co); + +/** + * Process CANopen gateway functions + * + * This function checks for epoll events and verifies socket connection timeout. + * It is non-blocking and should execute cyclically. It should be between + * @ref CO_epoll_wait() and @ref CO_epoll_processLast() functions. + * + * @param epGtw This object + * @param co CANopen object + * @param ep Pointer to @ref CO_epoll_t object. + */ +void CO_epoll_processGtw(CO_epoll_gtw_t *epGtw, + CO_t *co, + CO_epoll_t *ep); +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ + +/** @} */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* CO_EPOLL_INTERFACE_H */ diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index 202138c0..fc799f20 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -57,6 +57,7 @@ extern "C" { /* * Message definitions for debugging */ +#define DBG_GENERAL "(%s) Error: %s%d", __func__ #define DBG_ERRNO "(%s) OS error \"%s\" in %s", __func__, strerror(errno) #define DBG_CAN_TX_FAILED "(%s) Transmitting CAN msg OID 0x%08x failed(%s)", __func__ #define DBG_CAN_RX_PARAM_FAILED "(%s) Setting CAN rx buffer failed (%s)", __func__ @@ -79,7 +80,8 @@ extern "C" { #define DBG_CAN_OPEN "(%s) CANopen error in %s, err=%d", __func__ #define DBG_CAN_OPEN_INFO "CANopen device, Node ID = 0x%02X, %s" -/* CO_Linux_threads */ +/* CO_epoll_interface */ +#define DBG_EPOLL_UNKNOWN "(%s) CAN Epoll error, events=0x%02x, fd=%d", __func__ #define DBG_COMMAND_LOCAL_BIND "(%s) Can't bind local socket to path \"%s\"", __func__ #define DBG_COMMAND_TCP_BIND "(%s) Can't bind tcp socket to port \"%d\"", __func__ #define DBG_COMMAND_STDIO_INFO "CANopen command interface on \"standard IO\" started" diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 03931fbd..93b3dfe8 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -42,7 +42,7 @@ #include "CANopen.h" #include "CO_OD_storage.h" #include "CO_error.h" -#include "CO_Linux_threads.h" +#include "CO_epoll_interface.h" /* Call external application functions. */ #if __has_include("CO_application.h") @@ -71,6 +71,7 @@ /* Other variables and objects */ +CO_epoll_t epRT; /* Epoll-timer object for realtime thread */ static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ static uint8_t CO_pendingNodeId = 0xFF;/* Use value from Object Dictionary or by arguments (set to 1..127 * or unconfigured=0xFF). Can be changed by LSS slave. */ @@ -212,6 +213,7 @@ printf( * Mainline thread ******************************************************************************/ int main (int argc, char *argv[]) { + CO_epoll_t epMain; pthread_t rt_thread_id; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_ReturnError_t err; @@ -224,6 +226,7 @@ int main (int argc, char *argv[]) { bool_t nodeIdFromArgs = false; /* True, if program arguments are used for CANopen Node Id */ bool_t rebootEnable = false; /* Configurable by arguments */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + CO_epoll_gtw_t epGtw; /* values from CO_commandInterface_t */ int32_t commandInterface = CO_COMMAND_IF_DISABLED; /* local socket path if commandInterface == CO_COMMAND_IF_LOCAL_SOCKET */ @@ -369,6 +372,32 @@ int main (int argc, char *argv[]) { } + /* Initialize thread functions: epoll, timer, events */ + err = CO_epoll_create(&epMain, MAIN_THREAD_INTERVAL_US); + if(err != CO_ERROR_NO) { + log_printf(LOG_CRIT, DBG_GENERAL, + "CO_epoll_create(main), err=", err); + exit(EXIT_FAILURE); + } + + err = CO_epoll_create(&epRT, TMR_THREAD_INTERVAL_US); + if(err != CO_ERROR_NO) { + log_printf(LOG_CRIT, DBG_GENERAL, + "CO_epoll_create(RT), err=", err); + exit(EXIT_FAILURE); + } + CANptr.epoll_fd = epRT.epoll_fd; + +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + err = CO_epoll_createGtw(&epGtw, epMain.epoll_fd, commandInterface, + socketTimeout_ms, localSocketPath); + if(err != CO_ERROR_NO) { + log_printf(LOG_CRIT, DBG_GENERAL, "CO_epoll_createGtw(), err=", err); + exit(EXIT_FAILURE); + } +#endif + + while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { /* CANopen communication reset - initialize CANopen objects *******************/ @@ -379,9 +408,9 @@ int main (int argc, char *argv[]) { CO_UNLOCK_OD(); } - /* Enter CAN configuration. */ CO_CANsetConfigurationMode((void *)&CANptr); + CO_CANmodule_disable(CO->CANmodule[0]); /* initialize CANopen */ @@ -406,9 +435,12 @@ int main (int argc, char *argv[]) { } /* initialize part of threadMain and callbacks */ - threadMainWait_init(!CO->nodeIdUnconfigured); + CO_epoll_initCANopenMain(&epMain, CO); +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + CO_epoll_initCANopenGtw(&epGtw, CO); +#endif CO_LSSslave_initCfgStoreCallback(CO->LSSslave, NULL, - LSScfgStoreCallback); + LSScfgStoreCallback); if(!CO->nodeIdUnconfigured) { CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); @@ -438,14 +470,6 @@ int main (int argc, char *argv[]) { if(firstRun) { firstRun = false; - - /* Init threadMainWait structure and file descriptors */ - threadMainWait_initOnce(MAIN_THREAD_INTERVAL_US, commandInterface, - socketTimeout_ms, localSocketPath); - - /* Init threadRT structure and file descriptors */ - CANrx_threadTmr_init(TMR_THREAD_INTERVAL_US); - /* Create rt_thread and set priority */ if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) { log_printf(LOG_CRIT, DBG_ERRNO, "pthread_create(rt_thread)"); @@ -484,15 +508,21 @@ int main (int argc, char *argv[]) { while(reset == CO_RESET_NOT && CO_endProgram == 0) { /* loop for normal program execution ******************************************/ - uint32_t timer1usDiff = threadMainWait_process(&reset); + CO_epoll_wait(&epMain); + CO_epoll_processMain(&epMain, CO, &reset); +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + CO_epoll_processGtw(&epGtw, CO, &epMain); +#endif + CO_epoll_processLast(&epMain); #ifdef CO_USE_APPLICATION - app_programAsync(!CO->nodeIdUnconfigured, thrEpTm.timeDifference_us); + app_programAsync(!CO->nodeIdUnconfigured, epMain.timeDifference_us); #endif - CO_OD_storage_autoSave(&odStorAuto, timer1usDiff, 60000000); + CO_OD_storage_autoSave(&odStorAuto, + epMain.timeDifference_us, 60000000); } - } + } /* while(reset != CO_RESET_APP */ /* program exit ***************************************************************/ @@ -513,8 +543,11 @@ int main (int argc, char *argv[]) { CO_OD_storage_autoSaveClose(&odStorAuto); /* delete objects from memory */ - CANrx_threadTmr_close(); - threadMainWait_close(); + CO_epoll_close(&epRT); + CO_epoll_close(&epMain); +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + CO_epoll_closeGtw(&epGtw); +#endif CO_delete((void *)&CANptr); log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "finished"); @@ -540,8 +573,9 @@ static void* rt_thread(void* arg) { /* Endless loop */ while(CO_endProgram == 0) { - /* function may skip some milliseconds. Number of missed is returned */ - CANrx_threadTmr_process(); + CO_epoll_wait(&epRT); + CO_epoll_processRT(&epRT, CO, true); + CO_epoll_processLast(&epRT); #if CO_NO_TRACE > 0 /* Monitor variables with trace objects */ From 87b293b3e64a4128331f38c4c396fa8a4deea31c Mon Sep 17 00:00:00 2001 From: Carsten Frank <44053860+cfr-mir@users.noreply.github.com> Date: Tue, 29 Sep 2020 09:19:06 +0200 Subject: [PATCH 120/520] Do ErrorReset of SYNC timeout (#220) --- 301/CO_SYNC.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index a9d63dd5..17d29471 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -409,10 +409,13 @@ CO_SYNC_status_t CO_SYNC_process( } /* Verify timeout of SYNC */ - if(SYNC->periodTime && *SYNC->operatingState == CO_NMT_OPERATIONAL) { + if(SYNC->periodTime && (*SYNC->operatingState == CO_NMT_OPERATIONAL || *SYNC->operatingState == CO_NMT_PRE_OPERATIONAL)){ if(SYNC->timer > SYNC->periodTimeoutTime) { CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); } + else { + CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION); + } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT else if(timerNext_us != NULL) { uint32_t diff = SYNC->periodTimeoutTime - SYNC->timer; From 28925a4e3cc32e360368a5e20919da3c8254cf43 Mon Sep 17 00:00:00 2001 From: Wilkins White Date: Tue, 29 Sep 2020 00:24:21 -0700 Subject: [PATCH 121/520] Add CO_SYNCsend() (#225) * add CO_SYNCsend function * change return type of CO_TPDOsend --- 301/CO_PDO.c | 2 +- 301/CO_PDO.h | 2 +- 301/CO_SYNC.c | 14 +++++++++----- 301/CO_SYNC.h | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 171e4b83..bad3480b 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -889,7 +889,7 @@ uint8_t CO_TPDOisCOS(CO_TPDO_t *TPDO){ } /******************************************************************************/ -int16_t CO_TPDOsend(CO_TPDO_t *TPDO){ +CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO){ int16_t i; uint8_t* pPDOdataByte; uint8_t** ppODdataByte; diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 14d56877..09a65876 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -396,7 +396,7 @@ uint8_t CO_TPDOisCOS(CO_TPDO_t *TPDO); * * @return Same as CO_CANsend(). */ -int16_t CO_TPDOsend(CO_TPDO_t *TPDO); +CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO); /** diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 17d29471..4e503ff3 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -346,6 +346,14 @@ void CO_SYNC_initCallbackPre( } #endif +/******************************************************************************/ +CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC){ + if(++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1; + SYNC->timer = 0; + SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; + SYNC->CANtxBuff->data[0] = SYNC->counter; + return CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff); +} /******************************************************************************/ CO_SYNC_status_t CO_SYNC_process( @@ -374,12 +382,8 @@ CO_SYNC_status_t CO_SYNC_process( /* SYNC producer */ if(SYNC->isProducer && SYNC->periodTime){ if(SYNC->timer >= SYNC->periodTime){ - if(++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1; - SYNC->timer = 0; ret = CO_SYNC_RECEIVED; - SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; - SYNC->CANtxBuff->data[0] = SYNC->counter; - CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff); + CO_SYNCsend(SYNC); } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT /* Calculate when next SYNC needs to be sent */ diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index f2e5836f..fa9ba819 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -178,6 +178,21 @@ void CO_SYNC_initCallbackPre( #endif +/** + * Send SYNC message. + * + * This function prepares and sends a SYNC object. The application should only + * call this if direct control of SYNC transmission is needed, otherwise use + * CO_SYNC_process(). + * + * + * @param TPDO TPDO object. + * + * @return Same as CO_CANsend(). + */ +CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC); + + /** * Process SYNC communication. * From ffa92310a771bf01d863da3f332f4f197bb2d29f Mon Sep 17 00:00:00 2001 From: oto313 Date: Tue, 29 Sep 2020 09:50:18 +0200 Subject: [PATCH 122/520] Update CO_HBconsumer.c (#229) When current node is CO_HBconsumer_UNCONFIGURED then other nodes are skipped --- 301/CO_HBconsumer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 6d20662b..a8515985 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -332,6 +332,7 @@ void CO_HBconsumer_process( if (monitoredNode->HBstate == CO_HBconsumer_UNCONFIGURED) { /* continue, if node is not monitored */ + monitoredNode++; continue; } /* Verify if received message is heartbeat or bootup */ From 7fe0555606d04e9b68a1dec9d732ae95421d4ab1 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 29 Sep 2020 09:58:31 +0200 Subject: [PATCH 123/520] Update documentation with further details on the Zephyr RTOS support (#230) --- doc/deviceSupport.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index 94e18eff..ab47409d 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -48,12 +48,12 @@ Zephyr RTOS * CANopenNode integration with Zephyr RTOS * https://github.com/zephyrproject-rtos/zephyr/tree/master/subsys/canbus/canopen * Example integration: https://docs.zephyrproject.org/latest/samples/subsys/canbus/canopen/README.html -* CANopenNode version: +* CANopenNode version: v1.3 * Status: stable -* Features: OD storage, LED indicators, SDO server demo for Zephyr RTOS +* Features: OD storage, LED indicators, Program Download, SDO server demo for Zephyr RTOS * Development tools: Zephyr SDK * Demo hardware: Any development board with CAN interface and Zephyr support (see https://docs.zephyrproject.org/latest/boards/index.html) -* Information updated 2020-01-21 +* Information updated 2020-09-28 Mbed-os RTOS + STM32 (F091RC, L496ZG) From 1385c763aaf1f578d5815f02070f499171ae3014 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 29 Sep 2020 12:26:26 +0200 Subject: [PATCH 124/520] small fix --- 301/CO_SYNC.c | 12 ++++++------ 301/CO_SYNC.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 4e503ff3..6669e1c3 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -419,15 +419,15 @@ CO_SYNC_status_t CO_SYNC_process( } else { CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION); - } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT - else if(timerNext_us != NULL) { - uint32_t diff = SYNC->periodTimeoutTime - SYNC->timer; - if(*timerNext_us > diff){ - *timerNext_us = diff; + if(timerNext_us != NULL) { + uint32_t diff = SYNC->periodTimeoutTime - SYNC->timer; + if(*timerNext_us > diff){ + *timerNext_us = diff; + } } - } #endif + } } } else { diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index fa9ba819..47828aee 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -186,7 +186,7 @@ void CO_SYNC_initCallbackPre( * CO_SYNC_process(). * * - * @param TPDO TPDO object. + * @param SYNC SYNC object. * * @return Same as CO_CANsend(). */ From f142e893adba885fb6013e694905a22f8abcf41d Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 29 Sep 2020 12:46:02 +0200 Subject: [PATCH 125/520] Can run in single thread in Linux. --- Makefile | 2 ++ doc/CHANGELOG.md | 1 + socketCAN/CO_driver.c | 3 ++- socketCAN/CO_driver_target.h | 39 +++++++++++++++++++++++--------- socketCAN/CO_epoll_interface.c | 6 +++++ socketCAN/CO_main_basic.c | 41 ++++++++++++++++++++++++++-------- 6 files changed, 72 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 988a21b4..4ce4a9ac 100644 --- a/Makefile +++ b/Makefile @@ -48,8 +48,10 @@ SOURCES = \ OBJS = $(SOURCES:%.c=%.o) CC ?= gcc OPT = -g +#OPT = -g -DCO_SINGLE_THREAD CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = -pthread +#LDFLAGS = .PHONY: all clean diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index f1c369c3..e4ba956a 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -31,6 +31,7 @@ Change Log - CO_CANrxBufferInit(): remove check COB ID already used. - change macros CO_DRIVER_MULTI_INTERFACE and CO_DRIVER_ERROR_REPORTING. To enable(disable), set to 1(0). - Rename CO_Linux_threads.h/.c to CO_epoll_interface.h/.c and reorganize them. Move epoll, timerfd and eventfd system calls from CO_driver.c to here. +- Can run in single thread, including gateway. ### Fixed - Bugfix in `CO_HBconsumer_process()`: argument `timeDifference_us` was set to 0 inside for loop, fixed now. - BUG in CO_HBconsumer.c #168 diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 480540fa..8f22aae8 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -40,9 +40,10 @@ #include "301/CO_driver.h" #include "CO_error.h" - +#ifndef CO_SINGLE_THREAD pthread_mutex_t CO_EMCY_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif #if CO_DRIVER_MULTI_INTERFACE == 0 static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 7d062a01..4e28bdbf 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -37,7 +37,9 @@ #include #include #include +#ifndef CO_SINGLE_THREAD #include +#endif #include #include #include @@ -53,17 +55,23 @@ extern "C" { /* Stack configuration override default values. * For more information see file CO_config.h. */ +#ifdef CO_SINGLE_THREAD +#define CO_CONFIG_FLAG_CALLBACK_PRE_USED 0 +#else +#define CO_CONFIG_FLAG_CALLBACK_PRE_USED CO_CONFIG_FLAG_CALLBACK_PRE +#endif + #ifndef CO_CONFIG_NMT #define CO_CONFIG_NMT (CO_CONFIG_NMT_CALLBACK_CHANGE | \ CO_CONFIG_NMT_MASTER | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_HB_CONS #define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ CO_CONFIG_FLAG_TIMERNEXT) #endif @@ -71,7 +79,7 @@ extern "C" { #define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ CO_CONFIG_EM_HISTORY | \ CO_CONFIG_EM_CONSUMER | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ CO_CONFIG_FLAG_TIMERNEXT | \ CO_CONFIG_FLAG_OD_DYNAMIC) #endif @@ -79,7 +87,7 @@ extern "C" { #ifndef CO_CONFIG_SDO_SRV #define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ CO_CONFIG_SDO_SRV_BLOCK | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ CO_CONFIG_FLAG_TIMERNEXT | \ CO_CONFIG_FLAG_OD_DYNAMIC) #endif @@ -93,7 +101,7 @@ extern "C" { CO_CONFIG_SDO_CLI_SEGMENTED | \ CO_CONFIG_SDO_CLI_BLOCK | \ CO_CONFIG_SDO_CLI_LOCAL | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ CO_CONFIG_FLAG_TIMERNEXT | \ CO_CONFIG_FLAG_OD_DYNAMIC) #endif @@ -105,7 +113,7 @@ extern "C" { #ifndef CO_CONFIG_SYNC #define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ CO_CONFIG_SYNC_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ CO_CONFIG_FLAG_TIMERNEXT) #endif @@ -115,14 +123,14 @@ extern "C" { CO_CONFIG_PDO_SYNC_ENABLE | \ CO_CONFIG_RPDO_CALLS_EXTENSION | \ CO_CONFIG_TPDO_CALLS_EXTENSION | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_TIME #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE) + CO_CONFIG_FLAG_CALLBACK_PRE_USED) #endif #ifndef CO_CONFIG_LEDS @@ -134,7 +142,7 @@ extern "C" { #define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ CO_CONFIG_LSS_MASTER | \ - CO_CONFIG_FLAG_CALLBACK_PRE) + CO_CONFIG_FLAG_CALLBACK_PRE_USED) #endif #ifndef CO_CONFIG_GTW @@ -340,6 +348,15 @@ typedef struct { #endif } CO_CANmodule_t; +#ifdef CO_SINGLE_THREAD +#define CO_LOCK_CAN_SEND() +#define CO_UNLOCK_CAN_SEND() +#define CO_LOCK_EMCY() +#define CO_UNLOCK_EMCY() +#define CO_LOCK_OD() +#define CO_UNLOCK_OD() +#define CO_MemoryBarrier() +#else /* (un)lock critical section in CO_CANsend() - unused */ #define CO_LOCK_CAN_SEND() @@ -365,11 +382,13 @@ static inline void CO_UNLOCK_OD() { /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() {__sync_synchronize();} +#endif /* CO_SINGLE_THREAD */ + #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) #define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} #define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} -#endif /* CO_DOXYGEN */ +#endif /* #ifndef CO_DOXYGEN */ #if CO_DRIVER_MULTI_INTERFACE > 0 || defined CO_DOXYGEN diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c index a9a33628..702a110b 100644 --- a/socketCAN/CO_epoll_interface.c +++ b/socketCAN/CO_epoll_interface.c @@ -215,6 +215,7 @@ void CO_epoll_processLast(CO_epoll_t *ep) { /* MAINLINE *******************************************************************/ +#ifndef CO_SINGLE_THREAD /* Send event to wake CO_epoll_processMain() */ static void wakeupCallback(void *object) { CO_epoll_t *ep = (CO_epoll_t *)object; @@ -225,12 +226,15 @@ static void wakeupCallback(void *object) { log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); } } +#endif void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co) { if (ep == NULL || co == NULL) { return; } +#ifndef CO_SINGLE_THREAD + /* Configure LSS slave callback function */ #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE CO_LSSslave_initCallbackPre(co->LSSslave, @@ -264,6 +268,8 @@ void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co) { (void *)ep, wakeupCallback); #endif #endif + +#endif /* CO_SINGLE_THREAD */ } void CO_epoll_processMain(CO_epoll_t *ep, diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 93b3dfe8..1b3f1170 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -71,8 +71,10 @@ /* Other variables and objects */ +#ifndef CO_SINGLE_THREAD CO_epoll_t epRT; /* Epoll-timer object for realtime thread */ static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ +#endif static uint8_t CO_pendingNodeId = 0xFF;/* Use value from Object Dictionary or by arguments (set to 1..127 * or unconfigured=0xFF). Can be changed by LSS slave. */ static uint8_t CO_activeNodeId = 0xFF;/* Copied from CO_pendingNodeId in the communication reset section */ @@ -86,8 +88,10 @@ static CO_time_t CO_time; /* Object for current time */ #endif /* Helper functions ***********************************************************/ +#ifndef CO_SINGLE_THREAD /* Realtime thread */ static void* rt_thread(void* arg); +#endif /* Signal handler */ volatile sig_atomic_t CO_endProgram = 0; @@ -181,9 +185,13 @@ printf( "\n" "Options:\n" " -i CANopen Node-id (1..127) or 0xFF(unconfigured). If not\n" -" specified, value from Object dictionary (0x2101) is used.\n" +" specified, value from Object dictionary (0x2101) is used.\n"); +#ifndef CO_SINGLE_THREAD +printf( " -p Real-time priority of RT thread (1 .. 99). If not set or\n" -" set to -1, then normal scheduler is used for RT thread.\n" +" set to -1, then normal scheduler is used for RT thread.\n"); +#endif +printf( " -r Enable reboot on CANopen NMT reset_node command. \n" " -s Set Filename for OD storage ('od_storage' is default).\n" " -a Set Filename for automatic storage variables from\n" @@ -214,7 +222,9 @@ printf( ******************************************************************************/ int main (int argc, char *argv[]) { CO_epoll_t epMain; +#ifndef CO_SINGLE_THREAD pthread_t rt_thread_id; +#endif CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_ReturnError_t err; CO_ReturnError_t odStorStatus_rom, odStorStatus_eeprom; @@ -255,8 +265,10 @@ int main (int argc, char *argv[]) { CO_pendingNodeId = (uint8_t)strtol(optarg, NULL, 0); nodeIdFromArgs = true; break; +#ifndef CO_SINGLE_THREAD case 'p': rtPriority = strtol(optarg, NULL, 0); break; +#endif case 'r': rebootEnable = true; break; #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII @@ -317,12 +329,14 @@ int main (int argc, char *argv[]) { exit(EXIT_FAILURE); } +#ifndef CO_SINGLE_THREAD if(rtPriority != -1 && (rtPriority < sched_get_priority_min(SCHED_FIFO) || rtPriority > sched_get_priority_max(SCHED_FIFO))) { log_printf(LOG_CRIT, DBG_WRONG_PRIORITY, rtPriority); printUsage(argv[0]); exit(EXIT_FAILURE); } +#endif if(CANptr.can_ifindex == 0) { log_printf(LOG_CRIT, DBG_NO_CAN_DEVICE, CANdevice); @@ -372,14 +386,14 @@ int main (int argc, char *argv[]) { } - /* Initialize thread functions: epoll, timer, events */ + /* Create epoll functions */ err = CO_epoll_create(&epMain, MAIN_THREAD_INTERVAL_US); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_GENERAL, "CO_epoll_create(main), err=", err); exit(EXIT_FAILURE); } - +#ifndef CO_SINGLE_THREAD err = CO_epoll_create(&epRT, TMR_THREAD_INTERVAL_US); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_GENERAL, @@ -387,7 +401,9 @@ int main (int argc, char *argv[]) { exit(EXIT_FAILURE); } CANptr.epoll_fd = epRT.epoll_fd; - +#else + CANptr.epoll_fd = epMain.epoll_fd; +#endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII err = CO_epoll_createGtw(&epGtw, epMain.epoll_fd, commandInterface, socketTimeout_ms, localSocketPath); @@ -469,7 +485,7 @@ int main (int argc, char *argv[]) { /* First time only initialization. */ if(firstRun) { firstRun = false; - +#ifndef CO_SINGLE_THREAD /* Create rt_thread and set priority */ if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) { log_printf(LOG_CRIT, DBG_ERRNO, "pthread_create(rt_thread)"); @@ -484,7 +500,7 @@ int main (int argc, char *argv[]) { exit(EXIT_FAILURE); } } - +#endif #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ app_programStart(!CO->nodeIdUnconfigured); @@ -509,6 +525,9 @@ int main (int argc, char *argv[]) { while(reset == CO_RESET_NOT && CO_endProgram == 0) { /* loop for normal program execution ******************************************/ CO_epoll_wait(&epMain); +#ifdef CO_SINGLE_THREAD + CO_epoll_processRT(&epMain, CO, false); +#endif CO_epoll_processMain(&epMain, CO, &reset); #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_processGtw(&epGtw, CO, &epMain); @@ -528,11 +547,12 @@ int main (int argc, char *argv[]) { /* program exit ***************************************************************/ /* join threads */ CO_endProgram = 1; +#ifndef CO_SINGLE_THREAD if (pthread_join(rt_thread_id, NULL) != 0) { log_printf(LOG_CRIT, DBG_ERRNO, "pthread_join()"); exit(EXIT_FAILURE); } - +#endif #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ app_programEnd(); @@ -543,7 +563,9 @@ int main (int argc, char *argv[]) { CO_OD_storage_autoSaveClose(&odStorAuto); /* delete objects from memory */ +#ifndef CO_SINGLE_THREAD CO_epoll_close(&epRT); +#endif CO_epoll_close(&epMain); #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_closeGtw(&epGtw); @@ -564,7 +586,7 @@ int main (int argc, char *argv[]) { exit(EXIT_SUCCESS); } - +#ifndef CO_SINGLE_THREAD /******************************************************************************* * Realtime thread for CAN receive and threadTmr ******************************************************************************/ @@ -594,3 +616,4 @@ static void* rt_thread(void* arg) { return NULL; } +#endif From 010c6ae6a1a7b07a6143088ee5eb260dabfa5fd1 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 2 Oct 2020 08:49:42 +0200 Subject: [PATCH 126/520] fix config macros in socketCAN/CO_epoll_interface.c --- socketCAN/CO_epoll_interface.c | 40 +++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c index 702a110b..4a6e5d62 100644 --- a/socketCAN/CO_epoll_interface.c +++ b/socketCAN/CO_epoll_interface.c @@ -236,38 +236,48 @@ void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co) { #ifndef CO_SINGLE_THREAD /* Configure LSS slave callback function */ -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + #if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE + #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE CO_LSSslave_initCallbackPre(co->LSSslave, (void *)ep, wakeupCallback); -#endif + #endif + #endif if (co->nodeIdUnconfigured) { return; } /* Configure callback functions */ + #if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE CO_NMT_initCallbackPre(co->NMT, (void *)ep, wakeupCallback); - CO_SDO_initCallbackPre(co->SDO[0], - (void *)ep, wakeupCallback); - CO_EM_initCallbackPre(co->em, - (void *)ep, wakeupCallback); + #endif + #if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE CO_HBconsumer_initCallbackPre(co->HBcons, (void *)ep, wakeupCallback); -#if CO_NO_SDO_CLIENT != 0 + #endif + #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE + CO_EM_initCallbackPre(co->em, + (void *)ep, wakeupCallback); + #endif + #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE + CO_SDO_initCallbackPre(co->SDO[0], + (void *)ep, wakeupCallback); + #endif + #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE CO_SDOclient_initCallbackPre(co->SDOclient[0], (void *)ep, wakeupCallback); -#endif -#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE + #endif + #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE CO_TIME_initCallbackPre(co->TIME, (void *)ep, wakeupCallback); -#endif -#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + #endif + #if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE + #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER CO_LSSmaster_initCallbackPre(co->LSSmaster, (void *)ep, wakeupCallback); -#endif -#endif + #endif + #endif #endif /* CO_SINGLE_THREAD */ } @@ -308,7 +318,7 @@ void CO_epoll_processRT(CO_epoll_t *ep, if (!co->nodeIdUnconfigured && co->CANmodule[0]->CANnormal) { bool_t syncWas = false; -#if CO_NO_SYNC == 1 +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE /* Process Sync */ syncWas = CO_process_SYNC(co, ep->timeDifference_us, pTimerNext_us); From 05b488c45cab2d09176167bbd14865adf4e03574 Mon Sep 17 00:00:00 2001 From: Miles Simpson Date: Mon, 5 Oct 2020 23:10:04 -0700 Subject: [PATCH 127/520] Added missing check for CO_NO_TIME definition to CANopen.h (#233) --- CANopen.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CANopen.h b/CANopen.h index 922e0579..4095ac02 100644 --- a/CANopen.h +++ b/CANopen.h @@ -268,7 +268,9 @@ typedef struct { #if CO_NO_SYNC == 1 || defined CO_DOXYGEN CO_SYNC_t *SYNC; /**< SYNC object */ #endif +#if CO_NO_TIME == 1 || defined CO_DOXYGEN CO_TIME_t *TIME; /**< TIME object */ +#endif CO_RPDO_t *RPDO[CO_NO_RPDO]; /**< RPDO objects */ CO_TPDO_t *TPDO[CO_NO_TPDO]; /**< TPDO objects */ CO_HBconsumer_t *HBcons; /**< Heartbeat consumer object*/ From 7a43f98f244acb795e25e0573334694eca52558f Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 7 Oct 2020 13:47:07 +0200 Subject: [PATCH 128/520] Configuration macros updated --- 301/CO_ODinterface.h | 27 +++++------- 301/CO_config.h | 66 +++++++++++++++++------------ doc/objectDictionary.md | 81 ++++++++++++++++++++++++++++++++---- example/CO_driver_target.h | 12 +++--- socketCAN/CO_driver_target.h | 14 +++---- socketCAN/CO_main_basic.c | 43 +++++++++++++++---- 6 files changed, 170 insertions(+), 73 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 6d2c5f8d..3040461c 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -75,7 +75,7 @@ typedef enum { OD_H1012_COBID_TIME = 0x1012U,/**< Timestamp message cob-id */ OD_H1013_HIGH_RES_TIMESTAMP = 0x1013U,/**< High resolution timestamp */ OD_H1014_COBID_EMERGENCY = 0x1014U,/**< Emergency message cob-id */ - OD_H1015_INHIBIT_TIME_MSG = 0x1015U,/**< Inhibit time message */ + OD_H1015_INHIBIT_TIME_EMCY = 0x1015U,/**< Inhibit time emergency message */ OD_H1016_CONSUMER_HB_TIME = 0x1016U,/**< Consumer heartbeat time */ OD_H1017_PRODUCER_HB_TIME = 0x1017U,/**< Producer heartbeat time */ OD_H1018_IDENTITY_OBJECT = 0x1018U,/**< Identity object */ @@ -90,25 +90,18 @@ typedef enum { OD_H1027_MODULE_LIST = 0x1027U,/**< Module list */ OD_H1028_EMCY_CONSUMER = 0x1028U,/**< Emergency consumer object */ OD_H1029_ERR_BEHAVIOR = 0x1029U,/**< Error behaviour */ - OD_H1200_SDO_SERVER_PARAM = 0x1200U,/**< SDO server parameters */ - OD_H1280_SDO_CLIENT_PARAM = 0x1280U,/**< SDO client parameters */ + OD_H1200_SDO_SERVER_1_PARAM = 0x1200U,/**< SDO server parameter */ + OD_H1280_SDO_CLIENT_1_PARAM = 0x1280U,/**< SDO client parameter */ + OD_H1300_GFC_PARAM = 0x1300U,/**< Global fail-safe command param */ + OD_H1301_SRDO_1_PARAM = 0x1301U,/**< SRDO communication parameter */ + OD_H1381_SRDO_1_MAPPING = 0x1381U,/**< SRDO mapping parameter */ + OD_H13FE_SRDO_VALID = 0x13FEU,/**< SRDO Configuration valid */ + OD_H13FF_SRDO_CHECKSUM = 0x13FFU,/**< SRDO configuration checksum */ OD_H1400_RXPDO_1_PARAM = 0x1400U,/**< RXPDO communication parameter */ - OD_H1401_RXPDO_2_PARAM = 0x1401U,/**< RXPDO communication parameter */ - OD_H1402_RXPDO_3_PARAM = 0x1402U,/**< RXPDO communication parameter */ - OD_H1403_RXPDO_4_PARAM = 0x1403U,/**< RXPDO communication parameter */ OD_H1600_RXPDO_1_MAPPING = 0x1600U,/**< RXPDO mapping parameters */ - OD_H1601_RXPDO_2_MAPPING = 0x1601U,/**< RXPDO mapping parameters */ - OD_H1602_RXPDO_3_MAPPING = 0x1602U,/**< RXPDO mapping parameters */ - OD_H1603_RXPDO_4_MAPPING = 0x1603U,/**< RXPDO mapping parameters */ OD_H1800_TXPDO_1_PARAM = 0x1800U,/**< TXPDO communication parameter */ - OD_H1801_TXPDO_2_PARAM = 0x1801U,/**< TXPDO communication parameter */ - OD_H1802_TXPDO_3_PARAM = 0x1802U,/**< TXPDO communication parameter */ - OD_H1803_TXPDO_4_PARAM = 0x1803U,/**< TXPDO communication parameter */ OD_H1A00_TXPDO_1_MAPPING = 0x1A00U,/**< TXPDO mapping parameters */ - OD_H1A01_TXPDO_2_MAPPING = 0x1A01U,/**< TXPDO mapping parameters */ - OD_H1A02_TXPDO_3_MAPPING = 0x1A02U,/**< TXPDO mapping parameters */ - OD_H1A03_TXPDO_4_MAPPING = 0x1A03U /**< TXPDO mapping parameters */ -} OD_ObjDicId_301_t; +} OD_ObjDicId_30x_t; /** @@ -369,7 +362,7 @@ typedef struct { /** Number of elements in the list, without last element, which is blank */ uint16_t size; /** List OD entries (table of contents), ordered by index */ - OD_entry_t list[]; + const OD_entry_t *list; } OD_t; diff --git a/301/CO_config.h b/301/CO_config.h index 56adde60..d455b99e 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -153,6 +153,16 @@ extern "C" { #define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x02 #define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x04 #define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x08 + +/** + * Number of heartbeat consumer objects, where each object corresponds to one + * sub-index in OD object 0x1016, "Consumer heartbeat time". + * + * If heartbeat consumer is enabled, then valid values are 1 to 127. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_HB_CONS_SIZE 8 +#endif /** @} */ /* CO_STACK_CONFIG_NMT_HB */ @@ -172,7 +182,7 @@ extern "C" { * OD object 0x1015. * - CO_CONFIG_EM_HISTORY - Enable error history, OD object 0x1003, * "Pre-defined error field" - * - CO_CONFIG_EM_CONSUMER - Enable emergency consumer. + * - CO_CONFIG_EM_CONSUMER - Enable simple emergency consumer with callback. * - CO_CONFIG_EM_STATUS_BITS - Access @ref CO_EM_errorStatusBits_t from OD. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * emergency condition by CO_errorReport() or CO_errorReset() call. @@ -215,7 +225,6 @@ extern "C" { #define CO_CONFIG_EM_BUFFER_SIZE 16 #endif - /** * Condition for calculating CANopen Error register, "generic" error bit. * @@ -376,6 +385,28 @@ extern "C" { /** @} */ /* CO_STACK_CONFIG_SDO */ +/** + * @defgroup CO_STACK_CONFIG_TIME Time producer/consumer + * @{ + */ +/** + * Configuration of @ref CO_TIME + * + * Possible flags, can be ORed: + * - CO_CONFIG_TIME_ENABLE - Enable TIME object and TIME consumer. + * - CO_CONFIG_TIME_PRODUCER - Enable TIME producer. + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received TIME CAN message. + * Callback is configured by CO_TIME_initCallbackPre(). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_TIME (0) +#endif +#define CO_CONFIG_TIME_ENABLE 0x01 +#define CO_CONFIG_TIME_PRODUCER 0x02 +/** @} */ /* CO_STACK_CONFIG_TIME */ + + /** * @defgroup CO_STACK_CONFIG_SYNC_PDO SYNC and PDO producer/consumer * @{ @@ -404,6 +435,7 @@ extern "C" { * Possible flags, can be ORed: * - CO_CONFIG_RPDO_ENABLE - Enable receive PDO objects. * - CO_CONFIG_TPDO_ENABLE - Enable transmit PDO objects. + * - CO_CONFIG_PDO_SYNC_ENABLE - Enable SYNC in PDO objects. * - CO_CONFIG_RPDO_CALLS_EXTENSION - Enable calling configured extension * callbacks when received RPDO CAN message modifies OD entries. * - CO_CONFIG_TPDO_CALLS_EXTENSION - Enable calling configured extension @@ -417,34 +449,14 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE) #endif -#define CO_CONFIG_PDO_SYNC_ENABLE 0x01 -#define CO_CONFIG_RPDO_CALLS_EXTENSION 0x02 -#define CO_CONFIG_TPDO_CALLS_EXTENSION 0x04 +#define CO_CONFIG_RPDO_ENABLE 0x01 +#define CO_CONFIG_TPDO_ENABLE 0x02 +#define CO_CONFIG_PDO_SYNC_ENABLE 0x04 +#define CO_CONFIG_RPDO_CALLS_EXTENSION 0x08 +#define CO_CONFIG_TPDO_CALLS_EXTENSION 0x10 /** @} */ /* CO_STACK_CONFIG_SYNC_PDO */ -/** - * @defgroup CO_STACK_CONFIG_TIME Time producer/consumer - * @{ - */ -/** - * Configuration of @ref CO_TIME - * - * Possible flags, can be ORed: - * - CO_CONFIG_TIME_ENABLE - Enable TIME object and TIME consumer. - * - CO_CONFIG_TIME_PRODUCER - Enable TIME producer. - * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received TIME CAN message. - * Callback is configured by CO_TIME_initCallbackPre(). - */ -#ifdef CO_DOXYGEN -#define CO_CONFIG_TIME (0) -#endif -#define CO_CONFIG_TIME_ENABLE 0x01 -#define CO_CONFIG_TIME_PRODUCER 0x02 -/** @} */ /* CO_STACK_CONFIG_TIME */ - - /** * @defgroup CO_STACK_CONFIG_LEDS CANopen LED diodes * Specified in standard CiA 303-3 diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index c2ecaa48..eebcab4e 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -119,9 +119,9 @@ extern ODxyz_0_t ODxyz_0; extern ODxyz_1_t ODxyz_1; extern const OD_t ODxyz; -#define ODxyz_1000_deviceType &ODxyz.list[0] -#define ODxyz_1001_errorRegister &ODxyz.list[1] -#define ODxyz_1018_identity &ODxyz.list[2] +#define ODxyz_ENTRY_H1000 &ODxyz.list[0] +#define ODxyz_ENTRY_H1001 &ODxyz.list[1] +#define ODxyz_ENTRY_H1018 &ODxyz.list[2] ``` ### Example ODxyz.c file @@ -203,13 +203,17 @@ static const ODxyz_objs_t ODxyz_objs = { } }; -const OD_t ODxyz = { - 3, { +static const OD_entry_t ODxyz_list[] = { {0x1000, 0, 0, ODT_VAR, &ODxyz_objs.o_1000_deviceType}, {0x1001, 0, 1, ODT_EVAR, &ODxyz_objs.o_1001_errorRegister}, {0x1018, 4, 0, ODT_REC, &ODxyz_objs.o_1018_identity}, {0x0000, 0, 0, 0, NULL} -}}; +}; + +const OD_t OD = { + (sizeof(OD_list) / sizeof(OD_list[0])) - 1, + &ODxyz_list[0] +}; ``` @@ -394,7 +398,7 @@ Additional, optional, CANopenNode specific properties, which can be used inside * <property name="CO_storageGroup" value="..."> - group into which the C variable will belong. Variables from specific storage group may then be stored into non-volatile memory, automatically or by SDO command. Valid value is from 0x00 (default - not stored) to 0x7F. * <property name="CO_extensionIO" value="..."> - Valid value is "false" (default) or "true", if IO extension is enabled. * <property name="CO_flagsPDO" value="..."> - Valid value is "false" (default) or "true", if PDO flags are enabled. - * <property name="CO_countLabel" value="..."> - Valid value is any string without spaces. OD exporter will generate a macro for each different string. For example, if four OD objects have "CO_countLabel" set to "TPDO", then macro "#define ODxyz_NO_TPDO 4" will be generated by OD exporter. + * <property name="CO_countLabel" value="..."> - Valid value is any string without spaces. OD exporter will generate a macro for each different string. For example, if four OD objects have "CO_countLabel" set to "TPDO", then macro "#define ODxyz_CNT_TPDO 4" will be generated by OD exporter. Additional, optional, CANopenNode specific property, which can be used inside parameters describing "VAR": * <property name="CO_accessSRDO" value="..."> - Valid values are: "tx", "rx", "trx", "no"(default). @@ -427,3 +431,66 @@ This is optional element and is not required by standard, nor by CANopenNode. Th #### Other elements Other elements listed in the above XML example are required by the standard and does not influence the CANopenNode object dictionary generator. + + +### Object dictionary requirements by CANopenNode +* **Used by** column indicates CANopenNode object or its part, which uses the OD object. It also indicates, if OD object is required or optional for actual configuration. For the configuration of the CANopenNode objects see [Stack configuration](301/CO_config.h). If CANopenNode object or its part is disabled in stack configuration, then OD object is not used. Note that OD objects: 1000, 1001 and 1017 and 1018 are mandatory for CANopen. +* **CO_extensionIO** column indicates, if OD object must have property "CO_extensionIO" set to true: + * "no" - no IO extension used + * "optional" - If IO extension is enabled, then writing to the OD parameter will reflect in CANopen run time, otherwise reset communication is required for changes to take effect. + * "required" - IO extension is required on OD object and init function will return error if not enabled. + * "req if DYNAMIC" - IO extension is required on OD object if CO_CONFIG_FLAG_OD_DYNAMIC is set. + * "yes, own data" - OD object don't need own data and IO extension is necessary for OD object to work. Init function will not return error, if OD object does not exist or doesn't have IO extension enabled. +* **CO_countLabel** column indicates, which value must have property "CO_countLabel" inside OD object. + +| index | Description | Used by | CO_extensionIO | CO_countLabel | +| ----- | ----------------------------- | ---------------------| -------------- | ------------- | +| 1000 | Device type | CANopen, req | no | NMT | +| 1001 | Error register | CANopen, EM, req | no | EM | +| 1002 | Manufacturer status register | | | | +| 1003 | Pre-defined error field | EM_HISTORY, opt | yes, own data | | +| 1005 | COB-ID SYNC message | SYNC, req | req if DYNAMIC | SYNC | +| 1006 | Communication cycle period | SYNC_PRODUCER, req | opt | SYNC_PROD | +| 1007 | Synchronous window length | SYNC, opt | opt | | +| 1008 | Manufacturer device name | | | | +| 1009 | Manufacturer hardware version | | | | +| 100A | Manufacturer software version | | | | +| 100C | Guard time | | | | +| 100D | Life time factor | | | | +| 1010 | Store parameters | | | | +| 1011 | Restore default parameters | | | | +| 1012 | COB-ID time stamp object | TIME, req | required | TIME | +| 1013 | High resolution time stamp | | | | +| 1014 | COB-ID EMCY | EM_PRODUCER, req | required | EM_PROD | +| 1015 | Inhibit time EMCY | EM_PROD_INHIBIT, opt | optional | | +| 1016 | Consumer heartbeat time | HB_CONS, req | optional | HB_CONS | +| 1017 | Producer heartbeat time | CANopen, NMT, req | optional | HB_PROD | +| 1018 | Identity object | CANopen, LSS_SL, req | no | | +| 1019 | Synch. counter overflow value | SYNC, opt | no | | +| 1020 | Verify configuration | | | | +| 1021 | Store EDS | | | | +| 1022 | Store format | | | | +| 1023 | OS command | | | | +| 1024 | OS command mode | | | | +| 1025 | OS debugger interface | | | | +| 1026 | OS prompt | | | | +| 1027 | Module list | | | | +| 1028 | Emergency consumer object | | | | +| 1029 | Error behavior object | | | | +| 1200 | SDO server parameter (first) | SDO optional | required | SDO_SRV | +| 1201+ | SDO server parameter | SDO+, req | req if DYNAMIC | SDO_SRV | +| 1280+ | SDO client parameter | SDO_CLI, req | req if DYNAMIC | SDO_CLI | +| 1300 | Global fail-safe command par | GFC, req | | GFC | +| 1301+ | SRDO communication parameter | SRDO, req | | SRDO | +| 1381+ | SRDO mapping parameter | SRDO, req | | | +| 13FE | Configuration valid | SRDO, req | | | +| 13FF | Safety configuration checksum | SRDO, req | | | +| 1400+ | RPDO communication parameter | RPDO, req | req if DYNAMIC | RPDO | +| 1600+ | RPDO mapping parameter | RPDO, req | req if DYNAMIC | | +| 1800+ | TPDO communication parameter | TPDO, req | req if DYNAMIC | TPDO | +| 1A00+ | TPDO mapping parameter | TPDO, req | req if DYNAMIC | | +| 1FA0+ | Object scanner list | | | | +| 1FD0+ | Object dispatching list | | | | +| | Custom objects | | | | +| any | Error status bits | EM_STATUS_BITS, opt | yes, own data | | +| any+ | Trace | TRACE, req | yes, own data | TRACE | diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 0860097f..c573a520 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -95,6 +95,12 @@ extern "C" { #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 #endif +#ifndef CO_CONFIG_TIME +#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ + CO_CONFIG_TIME_PRODUCER | \ + CO_CONFIG_FLAG_CALLBACK_PRE) +#endif + #ifndef CO_CONFIG_SYNC #define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ CO_CONFIG_SYNC_PRODUCER | \ @@ -112,12 +118,6 @@ extern "C" { CO_CONFIG_FLAG_TIMERNEXT) #endif -#ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ - CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE) -#endif - #ifndef CO_CONFIG_LEDS #define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | \ CO_CONFIG_FLAG_TIMERNEXT) diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 4e28bdbf..6d22de93 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -110,6 +110,12 @@ extern "C" { #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 #endif +#ifndef CO_CONFIG_TIME +#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ + CO_CONFIG_TIME_PRODUCER | \ + CO_CONFIG_FLAG_CALLBACK_PRE_USED) +#endif + #ifndef CO_CONFIG_SYNC #define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ CO_CONFIG_SYNC_PRODUCER | \ @@ -127,12 +133,6 @@ extern "C" { CO_CONFIG_FLAG_TIMERNEXT) #endif -#ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ - CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED) -#endif - #ifndef CO_CONFIG_LEDS #define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | \ CO_CONFIG_FLAG_TIMERNEXT) @@ -172,7 +172,7 @@ extern "C" { #endif #ifndef CO_CONFIG_TRACE -#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE) +//#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE) #endif diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 1b3f1170..3987f668 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -23,6 +23,9 @@ * limitations under the License. */ +#ifndef CO_OD_STORAGE +#define CO_OD_STORAGE 1 +#endif #include #include @@ -40,9 +43,11 @@ #include #include "CANopen.h" -#include "CO_OD_storage.h" #include "CO_error.h" #include "CO_epoll_interface.h" +#if CO_OD_STORAGE == 1 +#include "CO_OD_storage.h" +#endif /* Call external application functions. */ #if __has_include("CO_application.h") @@ -51,7 +56,7 @@ #endif /* Add trace functionality for recording variables over time */ -#if CO_NO_TRACE > 0 +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE #include "CO_time_trace.h" #endif @@ -79,11 +84,13 @@ static uint8_t CO_pendingNodeId = 0xFF;/* Use value from Object Dic * or unconfigured=0xFF). Can be changed by LSS slave. */ static uint8_t CO_activeNodeId = 0xFF;/* Copied from CO_pendingNodeId in the communication reset section */ static uint16_t CO_pendingBitRate = 0; /* CAN bitrate, not used here */ +#if CO_OD_STORAGE == 1 static CO_OD_storage_t odStor; /* Object Dictionary storage object for CO_OD_ROM */ static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ static char *odStorFile_rom = "od_storage"; /* Name of the file */ static char *odStorFile_eeprom = "od_storage_auto"; /* Name of the file */ -#if CO_NO_TRACE > 0 +#endif +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE static CO_time_t CO_time; /* Object for current time */ #endif @@ -169,6 +176,7 @@ static void HeartbeatNmtChangedCallback(uint8_t nodeId, nodeId, NmtState2Str(state), state); } +#if CO_OD_STORAGE == 1 /* callback for storing node id and bitrate */ static bool_t LSScfgStoreCallback(void *object, uint8_t id, uint16_t bitRate) { (void)object; @@ -176,6 +184,7 @@ static bool_t LSScfgStoreCallback(void *object, uint8_t id, uint16_t bitRate) { OD_CANBitRate = bitRate; return true; } +#endif /* Print usage */ static void printUsage(char *progName) { @@ -192,10 +201,13 @@ printf( " set to -1, then normal scheduler is used for RT thread.\n"); #endif printf( -" -r Enable reboot on CANopen NMT reset_node command. \n" +" -r Enable reboot on CANopen NMT reset_node command. \n"); +#if CO_OD_STORAGE == 1 +printf( " -s Set Filename for OD storage ('od_storage' is default).\n" " -a Set Filename for automatic storage variables from\n" " Object dictionary. ('od_storage_auto' is default).\n"); +#endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII printf( " -c Enable command interface for master functionality.\n" @@ -227,7 +239,9 @@ int main (int argc, char *argv[]) { #endif CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_ReturnError_t err; +#if CO_OD_STORAGE == 1 CO_ReturnError_t odStorStatus_rom, odStorStatus_eeprom; +#endif CO_CANptrSocketCan_t CANptr = {0}; int opt; bool_t firstRun = true; @@ -299,10 +313,12 @@ int main (int argc, char *argv[]) { socketTimeout_ms = strtoul(optarg, NULL, 0); break; #endif +#if CO_OD_STORAGE == 1 case 's': odStorFile_rom = optarg; break; case 'a': odStorFile_eeprom = optarg; break; +#endif default: printUsage(argv[0]); exit(EXIT_FAILURE); @@ -320,8 +336,8 @@ int main (int argc, char *argv[]) { } if((CO_pendingNodeId < 1 || CO_pendingNodeId > 127) -#if CO_NO_LSS_SLAVE == 1 - && CO_pendingNodeId != CO_LSS_NODE_ID_ASSIGNMENT +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + && CO_NO_LSS_SLAVE == 1 && CO_pendingNodeId != CO_LSS_NODE_ID_ASSIGNMENT #endif ) { log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_pendingNodeId); @@ -370,10 +386,11 @@ int main (int argc, char *argv[]) { } +#if CO_OD_STORAGE == 1 /* initialize Object Dictionary storage */ odStorStatus_rom = CO_OD_storage_init(&odStor, (uint8_t*) &CO_OD_ROM, sizeof(CO_OD_ROM), odStorFile_rom); odStorStatus_eeprom = CO_OD_storage_init(&odStorAuto, (uint8_t*) &CO_OD_EEPROM, sizeof(CO_OD_EEPROM), odStorFile_eeprom); - +#endif /* Catch signals SIGINT and SIGTERM */ if(signal(SIGINT, sigHandler) == SIG_ERR) { @@ -455,13 +472,16 @@ int main (int argc, char *argv[]) { #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_initCANopenGtw(&epGtw, CO); #endif +#if CO_OD_STORAGE == 1 CO_LSSslave_initCfgStoreCallback(CO->LSSslave, NULL, LSScfgStoreCallback); +#endif if(!CO->nodeIdUnconfigured) { CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, HeartbeatNmtChangedCallback); +#if CO_OD_STORAGE == 1 /* initialize OD objects 1010 and 1011 and verify errors. */ CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U); CO_OD_configure(CO->SDO[0], OD_H1011_REST_PARAM_FUNC, CO_ODF_1011, (void*)&odStor, 0, 0U); @@ -471,8 +491,9 @@ int main (int argc, char *argv[]) { if(odStorStatus_eeprom != CO_ERROR_NO) { CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_eeprom + 1000); } +#endif -#if CO_NO_TRACE > 0 +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE /* Initialize time */ CO_time_init(&CO_time, CO->SDO[0], &OD_time.epochTimeBaseMs, &OD_time.epochTimeOffsetMs, 0x2130); #endif @@ -538,8 +559,10 @@ int main (int argc, char *argv[]) { app_programAsync(!CO->nodeIdUnconfigured, epMain.timeDifference_us); #endif +#if CO_OD_STORAGE == 1 CO_OD_storage_autoSave(&odStorAuto, epMain.timeDifference_us, 60000000); +#endif } } /* while(reset != CO_RESET_APP */ @@ -558,9 +581,11 @@ int main (int argc, char *argv[]) { app_programEnd(); #endif +#if CO_OD_STORAGE == 1 /* Store CO_OD_EEPROM */ CO_OD_storage_autoSave(&odStorAuto, 0, 0); CO_OD_storage_autoSaveClose(&odStorAuto); +#endif /* delete objects from memory */ #ifndef CO_SINGLE_THREAD @@ -599,7 +624,7 @@ static void* rt_thread(void* arg) { CO_epoll_processRT(&epRT, CO, true); CO_epoll_processLast(&epRT); -#if CO_NO_TRACE > 0 +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE /* Monitor variables with trace objects */ CO_time_process(&CO_time); for(i=0; i Date: Wed, 7 Oct 2020 16:53:00 +0200 Subject: [PATCH 129/520] CANopenNode V2.0 pre-release --- 301/CO_Emergency.c | 1055 ++++++++------ 301/CO_Emergency.h | 787 +++++----- 301/CO_NMT_Heartbeat.c | 384 +++-- 301/CO_NMT_Heartbeat.h | 279 ++-- 301/CO_PDO.c | 3 + 301/CO_PDO.h | 4 + 301/CO_SDOclient.c | 476 +++++-- 301/CO_SDOclient.h | 108 +- 301/CO_SDOserver.c | 2445 ++++++++++++++++---------------- 301/CO_SDOserver.h | 963 +++---------- 309/CO_gateway_ascii.c | 11 +- 309/CO_gateway_ascii.h | 1 - CANopen.c | 2034 ++++++++++++++------------ CANopen.h | 464 +++--- Makefile | 21 +- README.md | 13 +- doc/CHANGELOG.md | 15 +- example/CO_driver_target.h | 6 +- example/OD.c | 12 + example/OD.h | 45 + socketCAN/CO_driver_target.h | 16 +- socketCAN/CO_epoll_interface.c | 26 +- socketCAN/CO_epoll_interface.h | 2 + socketCAN/CO_main_basic.c | 84 +- 24 files changed, 4933 insertions(+), 4321 deletions(-) create mode 100644 example/OD.c create mode 100644 example/OD.h diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 231f4c11..55091753 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -4,7 +4,7 @@ * @file CO_Emergency.c * @ingroup CO_Emergency * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -25,568 +25,733 @@ #include -#include "301/CO_SDOserver.h" #include "301/CO_Emergency.h" /* verify configuration */ #if CO_CONFIG_EM_ERR_STATUS_BITS_COUNT < (6*8) \ - || CO_CONFIG_EM_ERR_STATUS_BITS_COUNT > 256 -#error CO_CONFIG_EM_ERR_STATUS_BITS_COUNT is not correct + || CO_CONFIG_EM_ERR_STATUS_BITS_COUNT > 256 \ + || (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT % 8) != 0 + #error CO_CONFIG_EM_ERR_STATUS_BITS_COUNT is not correct #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +#if CO_CONFIG_EM_BUFFER_SIZE < 1 || CO_CONFIG_EM_BUFFER_SIZE > 254 + #error CO_CONFIG_EM_BUFFER_SIZE is not correct +#endif + +/* fifo buffer example for CO_CONFIG_EM_BUFFER_SIZE = 6 (em->fifo size = 6+1) * + * * + * 0 * * * * * + * 1 pp==wp fifoPpPtr fifoWrPtr * * + * 2 * * * * * + * 3 * * * fifoWrPtr * + * 4 * fifoWrPtr fifoPpPtr fifoPpPtr * + * 5 * * * * * + * 6 * * * * * + * * + * nothing 3 bytes 4 bytes buffer * + * to process to process to process full * + ******************************************************************************/ + +#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE /* - * Read received message from CAN module. + * Custom functions for read/write OD variable "COB-ID EMCY" * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * For more information see file CO_ODinterface.h, OD_subEntry_t. */ -static void CO_EM_receive(void *object, void *msg) { - CO_EM_t *em; +static OD_size_t OD_read_1014(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) +{ + (void)count; /* "count" is already verified in *_init() function */ + if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } - em = (CO_EM_t*)object; + CO_EM_t *em = (CO_EM_t *)stream->object; + *returnCode = ODR_OK; - if(em!=NULL && em->pFunctSignalRx!=NULL){ - uint16_t ident = CO_CANrxMsg_readIdent(msg); - if (ident != 0x80) { - /* ignore sync messages (necessary if sync object is not used) */ - uint8_t *data = CO_CANrxMsg_readData(msg); - uint16_t errorCode; - uint32_t infoCode; + uint16_t canId = em->producerCanId == CO_CAN_ID_EMERGENCY ? + CO_CAN_ID_EMERGENCY + em->nodeId : em->producerCanId; + uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; + COB_IDEmergency32 |= canId; + CO_setUint32(buf, COB_IDEmergency32); + return sizeof(uint32_t); +} - memcpy(&errorCode, &data[0], sizeof(errorCode)); - memcpy(&infoCode, &data[4], sizeof(infoCode)); - em->pFunctSignalRx(ident, - CO_SWAP_16(errorCode), - data[2], - data[3], - CO_SWAP_32(infoCode)); - } +static OD_size_t OD_write_1014(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + /* "count" is already verified in *_init() function */ + if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; } + + CO_EM_t *em = (CO_EM_t *)stream->object; + *returnCode = ODR_OK; + + /* Verify written value. COB ID must not change, if emergency is enabled */ + uint32_t COB_IDEmergency32 = CO_getUint32(buf); + uint16_t newCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); + uint16_t curCanId = em->producerCanId == CO_CAN_ID_EMERGENCY ? + CO_CAN_ID_EMERGENCY + em->nodeId : em->producerCanId; + bool_t newEnabled = (COB_IDEmergency32 & 0x80000000) == 0 && newCanId != 0; + if ((COB_IDEmergency32 & 0x7FFFF800) != 0 + || (em->producerEnabled && newEnabled && newCanId != curCanId) + ) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + + /* store values. If default CAN-ID is used, then store only value of + * CO_CAN_ID_EMERGENCY without node id. */ + em->producerEnabled = newEnabled; + em->producerCanId = newCanId == (CO_CAN_ID_EMERGENCY + em->nodeId) ? + CO_CAN_ID_EMERGENCY : newCanId; + + /* configure emergency message CAN transmission */ + if (newEnabled) { + em->CANtxBuff = CO_CANtxBufferInit( + em->CANdevTx, /* CAN device */ + em->CANdevTxIdx, /* index of specific buffer inside CAN module */ + newCanId, /* CAN identifier */ + 0, /* rtr */ + 8U, /* number of data bytes */ + 0); /* synchronous message flag bit */ + } + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); } -#endif + #else +/* + * Custom functions for read/write OD variable "COB-ID EMCY" + * + * For more information see file CO_ODinterface.h, OD_subEntry_t. + */ +static OD_size_t OD_read_1014_default(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) +{ + (void)count; /* "count" is already verified in *_init() function */ + if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + CO_EM_t *em = (CO_EM_t *)stream->object; + *returnCode = ODR_OK; + + uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; + COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + em->nodeId; + CO_setUint32(buf, COB_IDEmergency32); + return sizeof(uint32_t); +} + #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE */ + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT /* - * Function for accessing _Pre-Defined Error Field_ (index 0x1003) from SDO server. + * Custom function for writing OD variable "Inhibit time EMCY" * - * For more information see file CO_SDOserver.h. + * For more information see file CO_ODinterface.h, OD_subEntry_t. */ -static CO_SDO_abortCode_t CO_ODF_1003(CO_ODF_arg_t *ODF_arg); -static CO_SDO_abortCode_t CO_ODF_1003(CO_ODF_arg_t *ODF_arg){ - CO_EMpr_t *emPr; - uint8_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; +static OD_size_t OD_write_1015(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + /* "count" is already verified in *_init() function */ + if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } - emPr = (CO_EMpr_t*) ODF_arg->object; - value = ODF_arg->data[0]; + CO_EM_t *em = (CO_EM_t *)stream->object; + *returnCode = ODR_OK; - if(ODF_arg->reading){ - uint8_t noOfErrors; - noOfErrors = emPr->preDefErrNoOfErrors; + /* update object */ + em->inhibitEmTime_us = (uint32_t)CO_getUint16(buf) * 100; + em->inhibitEmTimer = 0; - if(ODF_arg->subIndex == 0U){ - ODF_arg->data[0] = noOfErrors; - } - else if(ODF_arg->subIndex > noOfErrors){ - ret = CO_SDO_AB_NO_DATA; - } - else{ - ret = CO_SDO_AB_NONE; - } + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); +} + #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ + +#if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY +/* + * Custom functions for read/write OD variable _OD_statusBits_, optional + * + * For more information see file CO_ODinterface.h, OD_subEntry_t. + */ +static OD_size_t OD_read_1003(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) +{ + if (stream == NULL || buf == NULL || count < 4 || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; } - else{ - /* only '0' may be written to subIndex 0 */ - if(ODF_arg->subIndex == 0U){ - if(value == 0U){ - emPr->preDefErrNoOfErrors = 0U; - } - else{ - ret = CO_SDO_AB_INVALID_VALUE; - } + + CO_EM_t *em = (CO_EM_t *)stream->object; + *returnCode = ODR_OK; + + if (subIndex == 0) { + CO_setUint8(buf, em->fifoCount); + return 1; + } + else if (subIndex <= em->fifoCount) { + /* newest error is reported on subIndex 1 and is stored just behind + * fifoWrPtr. Get correct index in FIFO buffer. */ + int16_t index = (int16_t)em->fifoWrPtr - subIndex; + if (index < 0) { + index += CO_CONFIG_EM_BUFFER_SIZE + 1; } - else{ - ret = CO_SDO_AB_READONLY; + else if (index >= (CO_CONFIG_EM_BUFFER_SIZE + 1)) { + *returnCode = ODR_DEV_INCOMPAT; + return 0; } + CO_setUint32(buf, em->fifo[index][0]); + return 4; + } + else { + *returnCode = ODR_NO_DATA; + return 0; } - - return ret; } +static OD_size_t OD_write_1003(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + if (stream == NULL || subIndex != 0 || buf == NULL || count != 1 + || returnCode == NULL) + { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + if (CO_getUint8(buf) != 0) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + + CO_EM_t *em = (CO_EM_t *)stream->object; + *returnCode = ODR_OK; + + /* clear error history */ + em->fifoCount = 0; + return sizeof(uint8_t); +} +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ + +#if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS /* - * Function for accessing _COB ID EMCY_ (index 0x1014) from SDO server. + * Custom functions for read/write OD variable _OD_statusBits_, optional * - * For more information see file CO_SDOserver.h. + * For more information see file CO_ODinterface.h, OD_subEntry_t. */ -static CO_SDO_abortCode_t CO_ODF_1014(CO_ODF_arg_t *ODF_arg); -static CO_SDO_abortCode_t CO_ODF_1014(CO_ODF_arg_t *ODF_arg){ - uint8_t *nodeId; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; +static OD_size_t OD_read_statusBits(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) +{ + if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } - nodeId = (uint8_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); + CO_EM_t *em = (CO_EM_t *)stream->object; + *returnCode = ODR_OK; - /* add nodeId to the value */ - if(ODF_arg->reading){ - CO_setUint32(ODF_arg->data, value + *nodeId); + /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ + size_t countRead = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; + if (countRead > count) { + countRead = count; + } + if (stream->dataLength != 0 && countRead > stream->dataLength) { + countRead = stream->dataLength; + } + else { + stream->dataLength = countRead; } - return ret; + memcpy (buf, &em->errorStatusBits[0], countRead); + return countRead; +} + +static OD_size_t OD_write_statusBits(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + CO_EM_t *em = (CO_EM_t *)stream->object; + *returnCode = ODR_OK; + + /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ + size_t countWrite = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; + if (countWrite > count) { + countWrite = count; + } + if (stream->dataLength != 0 && countWrite > stream->dataLength) { + countWrite = stream->dataLength; + } + else { + stream->dataLength = countWrite; + } + + memcpy (&em->errorStatusBits[0], buf, countWrite); + return countWrite; } +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ + +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +/* + * Read received message from CAN module. + * + * Function will be called (by CAN receive interrupt) every time, when CAN + * message with correct identifier will be received. For more information and + * description of parameters see file CO_driver.h. + */ +static void CO_EM_receive(void *object, void *msg) { + CO_EM_t *em = (CO_EM_t*)object; + + if (em != NULL && em->pFunctSignalRx != NULL) { + uint16_t ident = CO_CANrxMsg_readIdent(msg); + + /* ignore sync messages (necessary if sync object is not used) */ + if (ident != 0x80) { + uint8_t *data = CO_CANrxMsg_readData(msg); + uint16_t errorCode; + uint32_t infoCode; + + memcpy(&errorCode, &data[0], sizeof(errorCode)); + memcpy(&infoCode, &data[4], sizeof(infoCode)); + em->pFunctSignalRx(ident, + CO_SWAP_16(errorCode), + data[2], + data[3], + CO_SWAP_32(infoCode)); + } + } +} +#endif /******************************************************************************/ -CO_ReturnError_t CO_EM_init( - CO_EM_t *em, - CO_EMpr_t *emPr, - CO_SDO_t *SDO, - uint8_t *errorStatusBits, - uint8_t errorStatusBitsSize, - uint8_t *errorRegister, - uint32_t *preDefErr, - uint8_t preDefErrSize, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint16_t CANidTxEM) +CO_ReturnError_t CO_EM_init(CO_EM_t *em, + const OD_entry_t *OD_1001_errReg, +#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + const OD_entry_t *OD_1014_cobIdEm, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, +#if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + const OD_entry_t *OD_1015_InhTime, +#endif +#endif +#if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY + const OD_entry_t *OD_1003_preDefErr, +#endif +#if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS + const OD_entry_t *OD_statusBits, +#endif +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, +#endif + const uint8_t nodeId) { - uint8_t i; + (void) nodeId; /* may be unused */ CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if(em==NULL || emPr==NULL || SDO==NULL || errorStatusBits==NULL || errorStatusBitsSize<6U || - errorRegister==NULL || preDefErr==NULL || CANdevTx==NULL + if (em == NULL || OD_1001_errReg == NULL +#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + || OD_1014_cobIdEm == NULL || CANdevTx == NULL + || nodeId < 1 || nodeId > 127 +#endif +#if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY + || OD_1003_preDefErr == NULL +#endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER - || CANdevRx==NULL + || CANdevRx == NULL #endif - ){ + ) { return CO_ERROR_ILLEGAL_ARGUMENT; } - /* Configure object variables */ - em->errorStatusBits = errorStatusBits; - em->errorStatusBitsSize = errorStatusBitsSize; - em->bufEnd = em->buf + (CO_EM_INTERNAL_BUFFER_SIZE * 8); - em->bufWritePtr = em->buf; - em->bufReadPtr = em->buf; - em->bufFull = 0U; - em->wrongErrorReport = 0U; -#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE - em->pFunctSignalPre = NULL; - em->functSignalObjectPre = NULL; -#endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER - em->pFunctSignalRx = NULL; -#endif - emPr->em = em; - emPr->errorRegister = errorRegister; - emPr->preDefErr = preDefErr; - emPr->preDefErrSize = preDefErrSize; - emPr->preDefErrNoOfErrors = 0U; - emPr->inhibitEmTimer = 0U; - emPr->CANerrorStatusOld = 0U; + /* clear the object */ + memset(em, 0, sizeof(CO_EM_t)); - /* clear error status bits */ - for(i=0U; ierrorStatusBits[i] = 0U; + /* get and verify "Error register" from Object Dictionary */ + if (OD_getPtr_u8(OD_1001_errReg, 0, &em->errorRegister) != ODR_OK) { + return CO_ERROR_OD_PARAMETERS; + } + *em->errorRegister = 0; + +#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + /* get initial and verify "COB-ID EMCY" from Object Dictionary */ + uint32_t COB_IDEmergency32; + ODR_t odRet0 = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); + if (odRet0 != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { + return CO_ERROR_OD_PARAMETERS; } - /* Configure Object dictionary entry at index 0x1003 and 0x1014 */ - CO_OD_configure(SDO, OD_H1003_PREDEF_ERR_FIELD, CO_ODF_1003, (void*)emPr, 0, 0U); - CO_OD_configure(SDO, OD_H1014_COBID_EMERGENCY, CO_ODF_1014, (void*)&SDO->nodeId, 0, 0U); + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE + uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); + em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0 + && producerCanId != 0; + if (!OD_extensionIO_init(OD_1014_cobIdEm, + (void *) em, + OD_read_1014, + OD_write_1014)) { + return CO_ERROR_OD_PARAMETERS; + } + /* following two variables are used inside OD_read_1014 and OD_write_1014 */ + em->producerCanId = producerCanId; + em->CANdevTxIdx = CANdevTxIdx; + /* if default producerCanId is used, then value of CO_CAN_ID_EMERGENCY + * (0x80) is stored into non-volatile memory. In that case it is necessary + * to add nodeId of this node to the stored value. */ + if (producerCanId == CO_CAN_ID_EMERGENCY) producerCanId += nodeId; + #else + uint16_t producerCanId = CO_CAN_ID_EMERGENCY + nodeId; + em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0; + if (!OD_extensionIO_init(OD_1014_cobIdEm, + (void *) em, + OD_read_1014_default, + OD_writeOriginal)) { + return CO_ERROR_OD_PARAMETERS; + } + #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER - /* configure SDO server CAN reception */ - ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - CO_CAN_ID_EMERGENCY, /* CAN identifier */ - 0x780, /* mask */ - 0, /* rtr */ - (void*)em, /* object passed to receive function */ - CO_EM_receive); /* this function will process received message */ -#endif + /* configure parameters and emergency message CAN transmission */ + em->nodeId = nodeId; + em->CANdevTx = CANdevTx; - /* configure emergency message CAN transmission */ - emPr->CANdev = CANdevTx; - emPr->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ + em->CANtxBuff = CO_CANtxBufferInit( + CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ - CANidTxEM, /* CAN identifier */ + producerCanId, /* CAN identifier */ 0, /* rtr */ 8U, /* number of data bytes */ 0); /* synchronous message flag bit */ - if (emPr->CANtxBuff == NULL) { - ret = CO_ERROR_ILLEGAL_ARGUMENT; + if (em->CANtxBuff == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + /* get and verify optional "Inhibit time EMCY" from Object Dictionary */ + em->inhibitEmTime_us = 0; + em->inhibitEmTimer = 0; + uint16_t inhibitTime_100us; + ODR_t odRet1 = OD_get_u16(OD_1015_InhTime, 0, &inhibitTime_100us, true); + if (odRet1 == ODR_OK) { + em->inhibitEmTime_us = (uint32_t)inhibitTime_100us * 100; + OD_extensionIO_init(OD_1015_InhTime, + (void *) em, + OD_readOriginal, + OD_write_1015); } + #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ + + +#if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY + /* If OD entry available, make access to em->preDefErr */ + OD_extensionIO_init(OD_1003_preDefErr, + (void *) em, + OD_read_1003, + OD_write_1003); +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ + + +#if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS + /* If OD entry available, make access to em->errorStatusBits */ + OD_extensionIO_init(OD_statusBits, + (void *) em, + OD_read_statusBits, + OD_write_statusBits); +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ + + +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + em->pFunctSignalRx = NULL; + /* configure SDO server CAN reception */ + ret = CO_CANrxBufferInit( + CANdevRx, /* CAN device */ + CANdevRxIdx, /* rx buffer index */ + CO_CAN_ID_EMERGENCY, /* CAN identifier */ + 0x780, /* mask */ + 0, /* rtr */ + (void*)em, /* object passed to receive function */ + CO_EM_receive); /* this function will process received message*/ +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER */ return ret; } -#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ -void CO_EM_initCallbackPre( - CO_EM_t *em, - void *object, - void (*pFunctSignal)(void *object)) +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +void CO_EM_initCallbackRx(CO_EM_t *em, + void (*pFunctSignalRx)(const uint16_t ident, + const uint16_t errorCode, + const uint8_t errorRegister, + const uint8_t errorBit, + const uint32_t infoCode)) { - if(em != NULL){ - em->functSignalObjectPre = object; - em->pFunctSignalPre = pFunctSignal; + if (em != NULL) { + em->pFunctSignalRx = pFunctSignalRx; } } #endif - -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER -/******************************************************************************/ -void CO_EM_initCallbackRx( - CO_EM_t *em, - void (*pFunctSignalRx)(const uint16_t ident, - const uint16_t errorCode, - const uint8_t errorRegister, - const uint8_t errorBit, - const uint32_t infoCode)) +#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE +void CO_EM_initCallbackPre(CO_EM_t *em, + void *object, + void (*pFunctSignal)(void *object)) { - if(em != NULL){ - em->pFunctSignalRx = pFunctSignalRx; + if (em != NULL) { + em->functSignalObjectPre = object; + em->pFunctSignalPre = pFunctSignal; } } #endif /******************************************************************************/ -void CO_EM_process( - CO_EMpr_t *emPr, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint16_t emInhTime_100us, - uint32_t *timerNext_us) +void CO_EM_process(CO_EM_t *em, + bool_t NMTisPreOrOperational, + uint32_t timeDifference_us, + uint32_t *timerNext_us) { (void)timerNext_us; /* may be unused */ - CO_EM_t *em = emPr->em; - uint8_t errorRegister; - uint8_t errorMask; - uint8_t i; - uint32_t emInhTime_us = (uint32_t)emInhTime_100us * 100; - uint16_t CANerrSt = emPr->CANdev->CANerrorStatus; - /* verify errors from driver */ - if (CANerrSt != emPr->CANerrorStatusOld) { - uint16_t CANerrStChanged = CANerrSt ^ emPr->CANerrorStatusOld; - emPr->CANerrorStatusOld = CANerrSt; - - if (CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) { - if (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) - CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, 0); - else - CO_errorReset(em, CO_EM_CAN_BUS_WARNING, 0); - } - - if (CANerrStChanged & CO_CAN_ERRTX_PASSIVE) { - if (CANerrSt & CO_CAN_ERRTX_PASSIVE) - CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, - CO_EMC_CAN_PASSIVE, 0); - else - CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, 0); - } - - if (CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) { - if (CANerrSt & CO_CAN_ERRTX_BUS_OFF) - CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, - CO_EMC_BUS_OFF_RECOVERED, 0); - else - CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, 0); - } - - if (CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) { - if (CANerrSt & CO_CAN_ERRTX_OVERFLOW) - CO_errorReport(em, CO_EM_CAN_TX_OVERFLOW, - CO_EMC_CAN_OVERRUN, 0); - else - CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, 0); - } - - if (CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) { - if (CANerrSt & CO_CAN_ERRTX_PDO_LATE) - CO_errorReport(em, CO_EM_TPDO_OUTSIDE_WINDOW, - CO_EMC_COMMUNICATION, 0); - else - CO_errorReset(em, CO_EM_TPDO_OUTSIDE_WINDOW, 0); - } - - if (CANerrStChanged & CO_CAN_ERRRX_PASSIVE) { - if (CANerrSt & CO_CAN_ERRRX_PASSIVE) - CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, - CO_EMC_CAN_PASSIVE, 0); - else - CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, 0); - } - - if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) { - if (CANerrSt & CO_CAN_ERRRX_OVERFLOW) - CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, - CO_EMC_CAN_OVERRUN, 0); - else - CO_errorReset(em, CO_EM_CAN_RXB_OVERFLOW, 0); - } + uint16_t CANerrSt = em->CANdevTx->CANerrorStatus; + if (CANerrSt != em->CANerrorStatusOld) { + uint16_t CANerrStChanged = CANerrSt ^ em->CANerrorStatusOld; + em->CANerrorStatusOld = CANerrSt; + + if (CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) + CO_error(em, + (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0, + CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, 0); + + if (CANerrStChanged & CO_CAN_ERRTX_PASSIVE) + CO_error(em, (CANerrSt & CO_CAN_ERRTX_PASSIVE) != 0, + CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); + + if (CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) + CO_error(em, (CANerrSt & CO_CAN_ERRTX_BUS_OFF) != 0, + CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, 0); + + if (CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) + CO_error(em, (CANerrSt & CO_CAN_ERRTX_OVERFLOW) != 0, + CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); + + if (CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) + CO_error(em, (CANerrSt & CO_CAN_ERRTX_PDO_LATE) != 0, + CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, 0); + + if (CANerrStChanged & CO_CAN_ERRRX_PASSIVE) + CO_error(em, (CANerrSt & CO_CAN_ERRRX_PASSIVE) != 0, + CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); + + if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) + CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0, + CO_EM_CAN_RXB_OVERFLOW, CO_EM_CAN_RXB_OVERFLOW, 0); } - /* verify other errors */ - if(em->wrongErrorReport != 0U){ - CO_errorReport(em, CO_EM_WRONG_ERROR_REPORT, CO_EMC_SOFTWARE_INTERNAL, (uint32_t)em->wrongErrorReport); - em->wrongErrorReport = 0U; - } - - /* calculate Error register */ - errorRegister = 0U; - errorMask = (uint8_t)~(CO_ERR_REG_GENERIC_ERR | CO_ERR_REG_COMM_ERR | CO_ERR_REG_MANUFACTURER); - /* generic error */ - if(em->errorStatusBits[5]){ + uint8_t errorRegister = 0U; + if (CO_CONFIG_ERR_CONDITION_GENERIC) errorRegister |= CO_ERR_REG_GENERIC_ERR; - } - /* communication error (overrun, error state) */ - if(em->errorStatusBits[2] || em->errorStatusBits[3]){ - errorRegister |= CO_ERR_REG_COMM_ERR; - } - /* Manufacturer */ - for(i=6; ierrorStatusBitsSize; i++) { - if (em->errorStatusBits[i]) { - errorRegister |= CO_ERR_REG_MANUFACTURER; - } - } - *emPr->errorRegister = (*emPr->errorRegister & errorMask) | errorRegister; +#ifdef CO_CONFIG_ERR_CONDITION_CURRENT + if (CO_CONFIG_ERR_CONDITION_CURRENT) + errorRegister |= CO_ERR_REG_CURRENT; +#endif +#ifdef CO_CONFIG_ERR_CONDITION_VOLTAGE + if (CO_CONFIG_ERR_CONDITION_VOLTAGE) + errorRegister |= CO_ERR_REG_VOLTAGE; +#endif +#ifdef CO_CONFIG_ERR_CONDITION_TEMPERATURE + if (CO_CONFIG_ERR_CONDITION_TEMPERATURE) + errorRegister |= CO_ERR_REG_TEMPERATURE; +#endif + if (CO_CONFIG_ERR_CONDITION_COMMUNICATION) + errorRegister |= CO_ERR_REG_COMMUNICATION; +#ifdef CO_CONFIG_ERR_CONDITION_DEV_PROFILE + if (CO_CONFIG_ERR_CONDITION_DEV_PROFILE) + errorRegister |= CO_ERR_REG_DEV_PROFILE; +#endif + if (CO_CONFIG_ERR_CONDITION_MANUFACTURER) + errorRegister |= CO_ERR_REG_MANUFACTURER; + *em->errorRegister = errorRegister; + /* post-process Emergency message in fifo buffer. */ +#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER /* inhibit time */ - if (emPr->inhibitEmTimer < emInhTime_us) { - emPr->inhibitEmTimer += timeDifference_us; + if (em->inhibitEmTimer < em->inhibitEmTime_us) { + em->inhibitEmTimer += timeDifference_us; } - /* send Emergency message. */ - if( NMTisPreOrOperational && - !emPr->CANtxBuff->bufferFull && - (em->bufReadPtr != em->bufWritePtr || em->bufFull)) - { - uint32_t preDEF; /* preDefinedErrorField */ + uint8_t fifoPpPtr = em->fifoPpPtr; + if (fifoPpPtr != em->fifoWrPtr + && em->inhibitEmTimer >= em->inhibitEmTime_us + && !em->CANtxBuff->bufferFull + ) { + em->inhibitEmTimer = 0; - if (emPr->inhibitEmTimer >= emInhTime_us) { - /* inhibit time elapsed, send message */ + /* add error register to emergency message */ + em->fifo[fifoPpPtr][0] |= (uint32_t) errorRegister << 16; - /* add error register */ - em->bufReadPtr[2] = *emPr->errorRegister; + /* send emergency message */ + if (NMTisPreOrOperational) { + memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr][0], + sizeof(em->CANtxBuff->data)); -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER - /* report also own emergency messages */ - if (em->pFunctSignalRx != NULL) { - uint16_t errorCode; - uint32_t infoCode; - memcpy(&errorCode, &em->bufReadPtr[0], sizeof(errorCode)); - memcpy(&infoCode, &em->bufReadPtr[4], sizeof(infoCode)); - em->pFunctSignalRx(0, - CO_SWAP_16(errorCode), - em->bufReadPtr[2], - em->bufReadPtr[3], - CO_SWAP_32(infoCode)); - } -#endif + CO_CANsend(em->CANdevTx, em->CANtxBuff); + } - /* copy data to CAN emergency message */ - memcpy(emPr->CANtxBuff->data, em->bufReadPtr, sizeof(emPr->CANtxBuff->data)); - memcpy(&preDEF, em->bufReadPtr, sizeof(preDEF)); - em->bufReadPtr += 8; - - /* Update read buffer pointer and reset inhibit timer */ - if(em->bufReadPtr == em->bufEnd){ - em->bufReadPtr = em->buf; - } - emPr->inhibitEmTimer = 0U; - - /* verify message buffer overflow, then clear full flag */ - if(em->bufFull == 2U){ - em->bufFull = 0U; /* will be updated below */ - CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, CO_EMC_GENERIC, 0U); - } - else{ - em->bufFull = 0; - CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); - } - - /* write to 'pre-defined error field' (object dictionary, index 0x1003) */ - if(emPr->preDefErr){ - uint8_t j; - - if(emPr->preDefErrNoOfErrors < emPr->preDefErrSize) - emPr->preDefErrNoOfErrors++; - for(j=emPr->preDefErrNoOfErrors-1; j>0; j--) - emPr->preDefErr[j] = emPr->preDefErr[j-1]; - emPr->preDefErr[0] = preDEF; - } - - /* send CAN message */ - CO_CANsend(emPr->CANdev, emPr->CANtxBuff); + #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + /* report also own emergency messages */ + if (em->pFunctSignalRx != NULL) { + uint32_t errMsg = em->fifo[fifoPpPtr][0]; + em->pFunctSignalRx(0, + CO_SWAP_16((uint16_t) errMsg), + errorRegister, + (uint8_t) (errMsg >> 24), + CO_SWAP_32(em->fifo[fifoPpPtr][1])); + } + #endif + + /* increment pointer */ + em->fifoPpPtr = (++fifoPpPtr < (CO_CONFIG_EM_BUFFER_SIZE + 1)) ? + fifoPpPtr : 0; + /* verify message buffer overflow. Clear error condition if all messages + * from fifo buffer are processed */ + if (em->fifoOverflow == 1) { + em->fifoOverflow = 2; + CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, CO_EMC_GENERIC, 0); } -#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT - else if (timerNext_us != NULL) { - uint32_t diff; - /* check again after inhibit time elapsed */ - diff = emInhTime_us - emPr->inhibitEmTimer; - if (*timerNext_us > diff) { - *timerNext_us = diff; - } + else if (em->fifoOverflow == 2 && em->fifoPpPtr == em->fifoWrPtr) { + em->fifoOverflow = 0; + CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); } -#endif } + #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT + else if (timerNext_us != NULL && em->inhibitEmTimer < em->inhibitEmTime_us){ + /* check again after inhibit time elapsed */ + uint32_t diff = em->inhibitEmTime_us - em->inhibitEmTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } + #endif +#elif (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY + uint8_t fifoPpPtr = em->fifoPpPtr; + while (fifoPpPtr != em->fifoWrPtr) { + /* add error register to emergency message and increment pointers */ + em->fifo[fifoPpPtr][0] |= (uint32_t) errorRegister << 16; + + if (++fifoPpPtr >= (CO_CONFIG_EM_BUFFER_SIZE + 1)) { + fifoPpPtr = 0; + } + } + em->fifoPpPtr = fifoPpPtr; +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER, #elif CO_CONFIG_EM_HISTORY */ return; } /******************************************************************************/ -void CO_errorReport(CO_EM_t *em, const uint8_t errorBit, const uint16_t errorCode, const uint32_t infoCode){ +void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, + uint16_t errorCode, uint32_t infoCode) +{ + if (em == NULL) return; + uint8_t index = errorBit >> 3; uint8_t bitmask = 1 << (errorBit & 0x7); - uint8_t *errorStatusBits = 0; - bool_t sendEmergency = true; - - if(em == NULL){ - sendEmergency = false; - } - else if(index >= em->errorStatusBitsSize){ - /* if errorBit value not supported, send emergency 'CO_EM_WRONG_ERROR_REPORT' */ - em->wrongErrorReport = errorBit; - sendEmergency = false; - } - else{ - errorStatusBits = &em->errorStatusBits[index]; - /* if error was already reported, do nothing */ - if((*errorStatusBits & bitmask) != 0){ - sendEmergency = false; - } + + /* if unsupported errorBit, change to 'CO_EM_WRONG_ERROR_REPORT' */ + if (index >= (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8)) { + index = CO_EM_WRONG_ERROR_REPORT >> 3; + bitmask = 1 << (CO_EM_WRONG_ERROR_REPORT & 0x7); + errorCode = CO_EMC_SOFTWARE_INTERNAL; + infoCode = errorBit; } - if(sendEmergency){ - /* set error bit */ - if(errorBit){ - /* any error except NO_ERROR */ - *errorStatusBits |= bitmask; - } + uint8_t *errorStatusBits = &em->errorStatusBits[index]; + uint8_t errorStatusBitMasked = *errorStatusBits & bitmask; - /* verify buffer full, set overflow */ - if(em->bufFull){ - em->bufFull = 2; - } - else{ - uint8_t bufCopy[8]; - uint16_t errorCodeSw = CO_SWAP_16(errorCode); - uint32_t infoCodeSw = CO_SWAP_32(infoCode); - - /* prepare data for emergency message */ - memcpy(&bufCopy[0], &errorCodeSw, sizeof(errorCodeSw)); - bufCopy[2] = 0; /* error register will be set later */ - bufCopy[3] = errorBit; - memcpy(&bufCopy[4], &infoCodeSw, sizeof(infoCodeSw)); - - /* copy data to the buffer, increment writePtr and verify buffer full */ - CO_LOCK_EMCY(); - memcpy(em->bufWritePtr, bufCopy, sizeof(bufCopy)); - em->bufWritePtr += 8; - - if(em->bufWritePtr == em->bufEnd) em->bufWritePtr = em->buf; - if(em->bufWritePtr == em->bufReadPtr) em->bufFull = 1; - CO_UNLOCK_EMCY(); - -#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */ - if(em->pFunctSignalPre != NULL) { - em->pFunctSignalPre(em->functSignalObjectPre); - } -#endif + /* If error is already set (or unset), return without further actions, + * otherwise toggle bit and continue with error indication. */ + if (setError) { + if (errorStatusBitMasked != 0) { + return; } } -} - - -/******************************************************************************/ -void CO_errorReset(CO_EM_t *em, const uint8_t errorBit, const uint32_t infoCode){ - uint8_t index = errorBit >> 3; - uint8_t bitmask = 1 << (errorBit & 0x7); - uint8_t *errorStatusBits = 0; - bool_t sendEmergency = true; - - if(em == NULL){ - sendEmergency = false; - } - else if(index >= em->errorStatusBitsSize){ - /* if errorBit value not supported, send emergency 'CO_EM_WRONG_ERROR_REPORT' */ - em->wrongErrorReport = errorBit; - sendEmergency = false; - } - else{ - errorStatusBits = &em->errorStatusBits[index]; - /* if error was allready cleared, do nothing */ - if((*errorStatusBits & bitmask) == 0){ - sendEmergency = false; + else { + if (errorStatusBitMasked == 0) { + return; } + errorCode = CO_EMC_NO_ERROR; } - if(sendEmergency){ - /* erase error bit */ - *errorStatusBits &= ~bitmask; +#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + /* prepare emergency message. Error register will be added in post-process*/ + uint32_t errMsg = (uint32_t)errorBit << 24 | CO_SWAP_16(errorCode); + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + uint32_t infoCodeSwapped = CO_SWAP_32(infoCode); + #endif +#endif - /* verify buffer full */ - if(em->bufFull){ - em->bufFull = 2; - } - else{ - uint8_t bufCopy[8]; - uint32_t infoCodeSw = CO_SWAP_32(infoCode); - - /* prepare data for emergency message */ - bufCopy[0] = 0; - bufCopy[1] = 0; - bufCopy[2] = 0; /* error register will be set later */ - bufCopy[3] = errorBit; - memcpy(&bufCopy[4], &infoCodeSw, sizeof(infoCodeSw)); - - /* copy data to the buffer, increment writePtr and verify buffer full */ - CO_LOCK_EMCY(); - memcpy(em->bufWritePtr, bufCopy, sizeof(bufCopy)); - em->bufWritePtr += 8; - - if(em->bufWritePtr == em->bufEnd) em->bufWritePtr = em->buf; - if(em->bufWritePtr == em->bufReadPtr) em->bufFull = 1; - CO_UNLOCK_EMCY(); + /* safely write data, and increment pointers */ + CO_LOCK_EMCY(); + if (setError) *errorStatusBits |= bitmask; + else *errorStatusBits &= ~bitmask; -#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */ - if(em->pFunctSignalPre != NULL) { - em->pFunctSignalPre(em->functSignalObjectPre); - } -#endif - } +#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + uint8_t fifoWrPtr = em->fifoWrPtr; + uint8_t fifoWrPtrNext = fifoWrPtr + 1; + if (fifoWrPtrNext >= (CO_CONFIG_EM_BUFFER_SIZE + 1)) { + fifoWrPtrNext = 0; } -} + if (fifoWrPtrNext == em->fifoPpPtr) { + em->fifoOverflow = 1; + } + else { + em->fifo[fifoWrPtr][0] = errMsg; + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + em->fifo[fifoWrPtr][1] = infoCodeSwapped; + #endif + em->fifoWrPtr = fifoWrPtrNext; + if (em->fifoCount < CO_CONFIG_EM_BUFFER_SIZE) em->fifoCount++; + } +#endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ -/******************************************************************************/ -bool_t CO_isError(CO_EM_t *em, const uint8_t errorBit){ - uint8_t index = errorBit >> 3; - uint8_t bitmask = 1 << (errorBit & 0x7); - bool_t ret = false; + CO_UNLOCK_EMCY(); - if(em != NULL && index < em->errorStatusBitsSize){ - if((em->errorStatusBits[index] & bitmask) != 0){ - ret = true; - } +#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + /* Optional signal to RTOS, which can resume task, which handles + * CO_EM_process */ + if (em->pFunctSignalPre != NULL && em->producerEnabled) { + em->pFunctSignalPre(em->functSignalObjectPre); } - - return ret; + #endif +#endif } diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 73e87173..3bae91d0 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -4,7 +4,7 @@ * @file CO_Emergency.h * @ingroup CO_Emergency * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -27,14 +27,19 @@ #define CO_EMERGENCY_H #include "301/CO_driver.h" +#include "301/CO_ODinterface.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER) +#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ + CO_CONFIG_EM_HISTORY) #endif #ifndef CO_CONFIG_EM_ERR_STATUS_BITS_COUNT #define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) #endif +#ifndef CO_CONFIG_EM_BUFFER_SIZE +#define CO_CONFIG_EM_BUFFER_SIZE 16 +#endif #ifndef CO_CONFIG_ERR_CONDITION_GENERIC #define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0) #endif @@ -64,352 +69,425 @@ extern "C" { * In case of error condition stack or application calls CO_errorReport() * function with indication of the error. Specific error condition is reported * (with CANopen Emergency message) only the first time after it occurs. - * Internal state of the error condition is controlled with - * @ref CO_EM_errorStatusBits. Specific error condition can also be reset by - * CO_errorReset() function. If so, Emergency message is sent with - * CO_EM_NO_ERROR indication. + * Internal state of specific error condition is indicated by internal bitfield + * variable, with space for maximum @ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT + * bits. Meaning for each bit is described by @ref CO_EM_errorStatusBits_t. + * Specific error condition can be reset by CO_errorReset() function. In that + * case Emergency message is sent with CO_EM_NO_ERROR indication. * * Some error conditions are informative and some are critical. Critical error - * conditions sets the #CO_errorRegisterBitmask_t. - * - * Latest errors can be read from _Pre Defined Error Field_ (object dictionary, - * index 0x1003). @ref CO_EM_errorStatusBits can also be read form CANopen - * object dictionary. + * conditions set the corresponding bit in @ref CO_errorRegister_t. Critical + * error conditions for generic error are specified by + * @ref CO_CONFIG_ERR_CONDITION_GENERIC macro. Similar macros are defined for + * other error bits in in @ref CO_errorRegister_t. * - * ###Emergency message contents: + * ### Emergency producer + * If @ref CO_CONFIG_EM has CO_CONFIG_EM_PRODUCER enabled, then CANopen + * Emergency message will be sent on each change of any error condition. + * Emergency message contents are: * * Byte | Description * -----|----------------------------------------------------------- - * 0..1 | @ref CO_EM_errorCodes. - * 2 | #CO_errorRegisterBitmask_t. - * 3 | Index of error condition (see @ref CO_EM_errorStatusBits). - * 4..7 | Additional argument informative to CO_errorReport() function. - * - * ####Contents of _Pre Defined Error Field_ (object dictionary, index 0x1003): - * bytes 0..3 are equal to bytes 0..3 in the Emergency message. - * - * @see #CO_Default_CAN_ID_t + * 0..1 | @ref CO_EM_errorCode_t + * 2 | @ref CO_errorRegister_t + * 3 | Index of error condition (see @ref CO_EM_errorStatusBits_t). + * 4..7 | Additional informative argument to CO_errorReport() function. + * + * ### Error history + * If @ref CO_CONFIG_EM has CO_CONFIG_EM_HISTORY enabled, then latest errors + * can be read from _Pre Defined Error Field_ (object dictionary, index 0x1003). + * Contents corresponds to bytes 0..3 from the Emergency message. + * + * ### Emergency consumer + * If @ref CO_CONFIG_EM has CO_CONFIG_EM_CONSUMER enabled, then callback can be + * registered by @ref CO_EM_initCallbackRx() function. */ /** * CANopen Error register. * - * In object dictionary on index 0x1001. + * Mandatory for CANopen, resides in object dictionary, index 0x1001. * - * Error register is calculated from critical internal @ref CO_EM_errorStatusBits. - * Generic and communication bits are calculated in CO_EM_process - * function, device profile or manufacturer specific bits may be calculated - * inside the application. + * Error register is calculated from internal bitfield variable, critical bits. + * See @ref CO_EM_errorStatusBits_t and @ref CO_STACK_CONFIG_EMERGENCY for error + * condition macros. * - * Internal errors may prevent device to stay in NMT Operational state. Details - * are described in _Error Behavior_ object in Object Dictionary at index 0x1029. + * Internal errors may prevent device to stay in NMT Operational state and + * changes may switch between the states. See @ref CO_NMT_control_t for details. */ -typedef enum{ - CO_ERR_REG_GENERIC_ERR = 0x01U, /**< bit 0, generic error */ - CO_ERR_REG_CURRENT = 0x02U, /**< bit 1, current */ - CO_ERR_REG_VOLTAGE = 0x04U, /**< bit 2, voltage */ - CO_ERR_REG_TEMPERATURE = 0x08U, /**< bit 3, temperature */ - CO_ERR_REG_COMM_ERR = 0x10U, /**< bit 4, communication error (overrun, error state) */ - CO_ERR_REG_DEV_PROFILE = 0x20U, /**< bit 5, device profile specific */ - CO_ERR_REG_RESERVED = 0x40U, /**< bit 6, reserved (always 0) */ - CO_ERR_REG_MANUFACTURER = 0x80U /**< bit 7, manufacturer specific */ -}CO_errorRegisterBitmask_t; +typedef enum { + CO_ERR_REG_GENERIC_ERR = 0x01U, /**< bit 0, generic error */ + CO_ERR_REG_CURRENT = 0x02U, /**< bit 1, current */ + CO_ERR_REG_VOLTAGE = 0x04U, /**< bit 2, voltage */ + CO_ERR_REG_TEMPERATURE = 0x08U, /**< bit 3, temperature */ + CO_ERR_REG_COMMUNICATION = 0x10U, /**< bit 4, communication error */ + CO_ERR_REG_DEV_PROFILE = 0x20U, /**< bit 5, device profile specific */ + CO_ERR_REG_RESERVED = 0x40U, /**< bit 6, reserved (always 0) */ + CO_ERR_REG_MANUFACTURER = 0x80U /**< bit 7, manufacturer specific */ +} CO_errorRegister_t; /** - * @defgroup CO_EM_errorCodes CANopen Error codes - * @{ + * CANopen Error code * * Standard error codes according to CiA DS-301 and DS-401. */ -#define CO_EMC_NO_ERROR 0x0000U /**< 0x00xx, error Reset or No Error */ -#define CO_EMC_GENERIC 0x1000U /**< 0x10xx, Generic Error */ -#define CO_EMC_CURRENT 0x2000U /**< 0x20xx, Current */ -#define CO_EMC_CURRENT_INPUT 0x2100U /**< 0x21xx, Current, device input side */ -#define CO_EMC_CURRENT_INSIDE 0x2200U /**< 0x22xx, Current inside the device */ -#define CO_EMC_CURRENT_OUTPUT 0x2300U /**< 0x23xx, Current, device output side */ -#define CO_EMC_VOLTAGE 0x3000U /**< 0x30xx, Voltage */ -#define CO_EMC_VOLTAGE_MAINS 0x3100U /**< 0x31xx, Mains Voltage */ -#define CO_EMC_VOLTAGE_INSIDE 0x3200U /**< 0x32xx, Voltage inside the device */ -#define CO_EMC_VOLTAGE_OUTPUT 0x3300U /**< 0x33xx, Output Voltage */ -#define CO_EMC_TEMPERATURE 0x4000U /**< 0x40xx, Temperature */ -#define CO_EMC_TEMP_AMBIENT 0x4100U /**< 0x41xx, Ambient Temperature */ -#define CO_EMC_TEMP_DEVICE 0x4200U /**< 0x42xx, Device Temperature */ -#define CO_EMC_HARDWARE 0x5000U /**< 0x50xx, Device Hardware */ -#define CO_EMC_SOFTWARE_DEVICE 0x6000U /**< 0x60xx, Device Software */ -#define CO_EMC_SOFTWARE_INTERNAL 0x6100U /**< 0x61xx, Internal Software */ -#define CO_EMC_SOFTWARE_USER 0x6200U /**< 0x62xx, User Software */ -#define CO_EMC_DATA_SET 0x6300U /**< 0x63xx, Data Set */ -#define CO_EMC_ADDITIONAL_MODUL 0x7000U /**< 0x70xx, Additional Modules */ -#define CO_EMC_MONITORING 0x8000U /**< 0x80xx, Monitoring */ -#define CO_EMC_COMMUNICATION 0x8100U /**< 0x81xx, Communication */ -#define CO_EMC_CAN_OVERRUN 0x8110U /**< 0x8110, CAN Overrun (Objects lost) */ -#define CO_EMC_CAN_PASSIVE 0x8120U /**< 0x8120, CAN in Error Passive Mode */ -#define CO_EMC_HEARTBEAT 0x8130U /**< 0x8130, Life Guard Error or Heartbeat Error */ -#define CO_EMC_BUS_OFF_RECOVERED 0x8140U /**< 0x8140, recovered from bus off */ -#define CO_EMC_CAN_ID_COLLISION 0x8150U /**< 0x8150, CAN-ID collision */ -#define CO_EMC_PROTOCOL_ERROR 0x8200U /**< 0x82xx, Protocol Error */ -#define CO_EMC_PDO_LENGTH 0x8210U /**< 0x8210, PDO not processed due to length error */ -#define CO_EMC_PDO_LENGTH_EXC 0x8220U /**< 0x8220, PDO length exceeded */ -#define CO_EMC_DAM_MPDO 0x8230U /**< 0x8230, DAM MPDO not processed, destination object not available */ -#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /**< 0x8240, Unexpected SYNC data length */ -#define CO_EMC_RPDO_TIMEOUT 0x8250U /**< 0x8250, RPDO timeout */ -#define CO_EMC_TIME_DATA_LENGTH 0x8260U /**< 0x8260, Unexpected TIME data length */ -#define CO_EMC_EXTERNAL_ERROR 0x9000U /**< 0x90xx, External Error */ -#define CO_EMC_ADDITIONAL_FUNC 0xF000U /**< 0xF0xx, Additional Functions */ -#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /**< 0xFFxx, Device specific */ - -#define CO_EMC401_OUT_CUR_HI 0x2310U /**< 0x2310, DS401, Current at outputs too high (overload) */ -#define CO_EMC401_OUT_SHORTED 0x2320U /**< 0x2320, DS401, Short circuit at outputs */ -#define CO_EMC401_OUT_LOAD_DUMP 0x2330U /**< 0x2330, DS401, Load dump at outputs */ -#define CO_EMC401_IN_VOLT_HI 0x3110U /**< 0x3110, DS401, Input voltage too high */ -#define CO_EMC401_IN_VOLT_LOW 0x3120U /**< 0x3120, DS401, Input voltage too low */ -#define CO_EMC401_INTERN_VOLT_HI 0x3210U /**< 0x3210, DS401, Internal voltage too high */ -#define CO_EMC401_INTERN_VOLT_LO 0x3220U /**< 0x3220, DS401, Internal voltage too low */ -#define CO_EMC401_OUT_VOLT_HIGH 0x3310U /**< 0x3310, DS401, Output voltage too high */ -#define CO_EMC401_OUT_VOLT_LOW 0x3320U /**< 0x3320, DS401, Output voltage too low */ -/** @} */ +typedef enum { + /** 0x00xx, error Reset or No Error */ + CO_EMC_NO_ERROR = 0x0000U, + /** 0x10xx, Generic Error */ + CO_EMC_GENERIC = 0x1000U, + /** 0x20xx, Current */ + CO_EMC_CURRENT = 0x2000U, + /** 0x21xx, Current, device input side */ + CO_EMC_CURRENT_INPUT = 0x2100U, + /** 0x22xx, Current inside the device */ + CO_EMC_CURRENT_INSIDE = 0x2200U, + /** 0x23xx, Current, device output side */ + CO_EMC_CURRENT_OUTPUT = 0x2300U, + /** 0x30xx, Voltage */ + CO_EMC_VOLTAGE = 0x3000U, + /** 0x31xx, Mains Voltage */ + CO_EMC_VOLTAGE_MAINS = 0x3100U, + /** 0x32xx, Voltage inside the device */ + CO_EMC_VOLTAGE_INSIDE = 0x3200U, + /** 0x33xx, Output Voltage */ + CO_EMC_VOLTAGE_OUTPUT = 0x3300U, + /** 0x40xx, Temperature */ + CO_EMC_TEMPERATURE = 0x4000U, + /** 0x41xx, Ambient Temperature */ + CO_EMC_TEMP_AMBIENT = 0x4100U, + /** 0x42xx, Device Temperature */ + CO_EMC_TEMP_DEVICE = 0x4200U, + /** 0x50xx, Device Hardware */ + CO_EMC_HARDWARE = 0x5000U, + /** 0x60xx, Device Software */ + CO_EMC_SOFTWARE_DEVICE = 0x6000U, + /** 0x61xx, Internal Software */ + CO_EMC_SOFTWARE_INTERNAL = 0x6100U, + /** 0x62xx, User Software */ + CO_EMC_SOFTWARE_USER = 0x6200U, + /** 0x63xx, Data Set */ + CO_EMC_DATA_SET = 0x6300U, + /** 0x70xx, Additional Modules */ + CO_EMC_ADDITIONAL_MODUL = 0x7000U, + /** 0x80xx, Monitoring */ + CO_EMC_MONITORING = 0x8000U, + /** 0x81xx, Communication */ + CO_EMC_COMMUNICATION = 0x8100U, + /** 0x8110, CAN Overrun (Objects lost) */ + CO_EMC_CAN_OVERRUN = 0x8110U, + /** 0x8120, CAN in Error Passive Mode */ + CO_EMC_CAN_PASSIVE = 0x8120U, + /** 0x8130, Life Guard Error or Heartbeat Error */ + CO_EMC_HEARTBEAT = 0x8130U, + /** 0x8140, recovered from bus off */ + CO_EMC_BUS_OFF_RECOVERED = 0x8140U, + /** 0x8150, CAN-ID collision */ + CO_EMC_CAN_ID_COLLISION = 0x8150U, + /** 0x82xx, Protocol Error */ + CO_EMC_PROTOCOL_ERROR = 0x8200U, + /** 0x8210, PDO not processed due to length error */ + CO_EMC_PDO_LENGTH = 0x8210U, + /** 0x8220, PDO length exceeded */ + CO_EMC_PDO_LENGTH_EXC = 0x8220U, + /** 0x8230, DAM MPDO not processed, destination object not available */ + CO_EMC_DAM_MPDO = 0x8230U, + /** 0x8240, Unexpected SYNC data length */ + CO_EMC_SYNC_DATA_LENGTH = 0x8240U, + /** 0x8250, RPDO timeout */ + CO_EMC_RPDO_TIMEOUT = 0x8250U, + /** 0x8260, Unexpected TIME data length */ + CO_EMC_TIME_DATA_LENGTH = 0x8260U, + /** 0x90xx, External Error */ + CO_EMC_EXTERNAL_ERROR = 0x9000U, + /** 0xF0xx, Additional Functions */ + CO_EMC_ADDITIONAL_FUNC = 0xF000U, + /** 0xFFxx, Device specific */ + CO_EMC_DEVICE_SPECIFIC = 0xFF00U, + + /** 0x2310, DS401, Current at outputs too high (overload) */ + CO_EMC401_OUT_CUR_HI = 0x2310U, + /** 0x2320, DS401, Short circuit at outputs */ + CO_EMC401_OUT_SHORTED = 0x2320U, + /** 0x2330, DS401, Load dump at outputs */ + CO_EMC401_OUT_LOAD_DUMP = 0x2330U, + /** 0x3110, DS401, Input voltage too high */ + CO_EMC401_IN_VOLT_HI = 0x3110U, + /** 0x3120, DS401, Input voltage too low */ + CO_EMC401_IN_VOLT_LOW = 0x3120U, + /** 0x3210, DS401, Internal voltage too high */ + CO_EMC401_INTERN_VOLT_HI = 0x3210U, + /** 0x3220, DS401, Internal voltage too low */ + CO_EMC401_INTERN_VOLT_LO = 0x3220U, + /** 0x3310, DS401, Output voltage too high */ + CO_EMC401_OUT_VOLT_HIGH = 0x3310U, + /** 0x3320, DS401, Output voltage too low */ + CO_EMC401_OUT_VOLT_LOW = 0x3320U, +} CO_EM_errorCode_t; /** - * @defgroup CO_EM_errorStatusBits Error status bits - * @{ + * Error status bits * - * Internal indication of the error condition. - * - * Each error condition is specified by unique index from 0x00 up to 0xFF. - * Variable (from manufacturer section in the Object - * Dictionary) contains up to 0xFF bits (32bytes) for the identification of the - * specific error condition. (Type of the variable is CANopen OCTET_STRING.) + * Bits for internal indication of the error condition. Each error condition is + * specified by unique index from 0x00 up to 0xFF. * * If specific error occurs in the stack or in the application, CO_errorReport() - * sets specific bit in the _Error Status Bits_ variable. If bit was already - * set, function returns without any action. Otherwise it prepares emergency - * message. - * - * CO_errorReport(), CO_errorReset() or CO_isError() functions are called - * with unique index as an argument. (However CO_errorReport(), for example, may - * be used with the same index on multiple places in the code.) - * - * Macros defined below are combination of two constants: index and - * @ref CO_EM_errorCodes. They represents specific error conditions. They are - * used as double argument for CO_errorReport(), CO_errorReset() and - * CO_isError() functions. - * - * Stack uses first 6 bytes of the _Error Status Bits_ variable. Device profile - * or application may define own macros for Error status bits using - * @ref CO_EM_MANUFACTURER_START and @ref CO_EM_MANUFACTURER_END values. Note that - * _Error Status Bits_ must be large enough (up to 32 bytes). + * sets specific bit in the _errorStatusBit_ variable from @ref CO_EM_t. If bit + * was already set, function returns without any action. Otherwise it prepares + * emergency message. + * + * Maximum size (in bits) of the _errorStatusBit_ variable is specified by + * @ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (set to 10*8 bits by default). Stack + * uses first 6 bytes. Additional 4 bytes are pre-defined for manufacturer + * or device specific error indications, by default. */ -#define CO_EM_NO_ERROR 0x00U /**< 0x00, Error Reset or No Error */ -#define CO_EM_CAN_BUS_WARNING 0x01U /**< 0x01, communication, info, CAN bus warning limit reached */ -#define CO_EM_RXMSG_WRONG_LENGTH 0x02U /**< 0x02, communication, info, Wrong data length of the received CAN message */ -#define CO_EM_RXMSG_OVERFLOW 0x03U /**< 0x03, communication, info, Previous received CAN message wasn't processed yet */ -#define CO_EM_RPDO_WRONG_LENGTH 0x04U /**< 0x04, communication, info, Wrong data length of received PDO */ -#define CO_EM_RPDO_OVERFLOW 0x05U /**< 0x05, communication, info, Previous received PDO wasn't processed yet */ -#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /**< 0x06, communication, info, CAN receive bus is passive */ -#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /**< 0x07, communication, info, CAN transmit bus is passive */ -#define CO_EM_NMT_WRONG_COMMAND 0x08U /**< 0x08, communication, info, Wrong NMT command received */ -#define CO_EM_TIME_TIMEOUT 0x09U /**< 0x09, communication, info, TIME message timeout */ -#define CO_EM_TIME_LENGTH 0x0AU /**< 0x0A, communication, info, Unexpected TIME data length */ -#define CO_EM_0B_unused 0x0BU /**< 0x0B, (unused) */ -#define CO_EM_0C_unused 0x0CU /**< 0x0C, (unused) */ -#define CO_EM_0D_unused 0x0DU /**< 0x0D, (unused) */ -#define CO_EM_0E_unused 0x0EU /**< 0x0E, (unused) */ -#define CO_EM_0F_unused 0x0FU /**< 0x0F, (unused) */ - -#define CO_EM_10_unused 0x10U /**< 0x10, (unused) */ -#define CO_EM_11_unused 0x11U /**< 0x11, (unused) */ -#define CO_EM_CAN_TX_BUS_OFF 0x12U /**< 0x12, communication, critical, CAN transmit bus is off */ -#define CO_EM_CAN_RXB_OVERFLOW 0x13U /**< 0x13, communication, critical, CAN module receive buffer has overflowed */ -#define CO_EM_CAN_TX_OVERFLOW 0x14U /**< 0x14, communication, critical, CAN transmit buffer has overflowed */ -#define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /**< 0x15, communication, critical, TPDO is outside SYNC window */ -#define CO_EM_16_unused 0x16U /**< 0x16, (unused) */ -#define CO_EM_17_unused 0x17U /**< 0x17, (unused) */ -#define CO_EM_SYNC_TIME_OUT 0x18U /**< 0x18, communication, critical, SYNC message timeout */ -#define CO_EM_SYNC_LENGTH 0x19U /**< 0x19, communication, critical, Unexpected SYNC data length */ -#define CO_EM_PDO_WRONG_MAPPING 0x1AU /**< 0x1A, communication, critical, Error with PDO mapping */ -#define CO_EM_HEARTBEAT_CONSUMER 0x1BU /**< 0x1B, communication, critical, Heartbeat consumer timeout */ -#define CO_EM_HB_CONSUMER_REMOTE_RESET 0x1CU /**< 0x1C, communication, critical, Heartbeat consumer detected remote node reset */ -#define CO_EM_1D_unused 0x1DU /**< 0x1D, (unused) */ -#define CO_EM_1E_unused 0x1EU /**< 0x1E, (unused) */ -#define CO_EM_1F_unused 0x1FU /**< 0x1F, (unused) */ - -#define CO_EM_EMERGENCY_BUFFER_FULL 0x20U /**< 0x20, generic, info, Emergency buffer is full, Emergency message wasn't sent */ -#define CO_EM_21_unused 0x21U /**< 0x21, (unused) */ -#define CO_EM_MICROCONTROLLER_RESET 0x22U /**< 0x22, generic, info, Microcontroller has just started */ -#define CO_EM_23_unused 0x23U /**< 0x23, (unused) */ -#define CO_EM_24_unused 0x24U /**< 0x24, (unused) */ -#define CO_EM_25_unused 0x25U /**< 0x25, (unused) */ -#define CO_EM_26_unused 0x26U /**< 0x26, (unused) */ -#define CO_EM_27_unused 0x27U /**< 0x27, (unused) */ - -#define CO_EM_WRONG_ERROR_REPORT 0x28U /**< 0x28, generic, critical, Wrong parameters to CO_errorReport() function */ -#define CO_EM_ISR_TIMER_OVERFLOW 0x29U /**< 0x29, generic, critical, Timer task has overflowed */ -#define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /**< 0x2A, generic, critical, Unable to allocate memory for objects */ -#define CO_EM_GENERIC_ERROR 0x2BU /**< 0x2B, generic, critical, Generic error, test usage */ -#define CO_EM_GENERIC_SOFTWARE_ERROR 0x2CU /**< 0x2C, generic, critical, Software error */ -#define CO_EM_INCONSISTENT_OBJECT_DICT 0x2DU /**< 0x2D, generic, critical, Object dictionary does not match the software */ -#define CO_EM_CALCULATION_OF_PARAMETERS 0x2EU /**< 0x2E, generic, critical, Error in calculation of device parameters */ -#define CO_EM_NON_VOLATILE_MEMORY 0x2FU /**< 0x2F, generic, critical, Error with access to non volatile device memory */ - -#define CO_EM_MANUFACTURER_START 0x30U /**< 0x30, manufacturer, info, This can be used by macros to calculate error codes */ -#define CO_EM_MANUFACTURER_END 0xFFU /**< 0xFF, manufacturer, info, This can be used by macros to check error codes */ -/** @} */ +typedef enum { + /** 0x00, Error Reset or No Error */ + CO_EM_NO_ERROR = 0x00U, + /** 0x01, communication, info, CAN bus warning limit reached */ + CO_EM_CAN_BUS_WARNING = 0x01U, + /** 0x02, communication, info, Wrong data length of the received CAN + * message */ + CO_EM_RXMSG_WRONG_LENGTH = 0x02U, + /** 0x03, communication, info, Previous received CAN message wasn't + * processed yet */ + CO_EM_RXMSG_OVERFLOW = 0x03U, + /** 0x04, communication, info, Wrong data length of received PDO */ + CO_EM_RPDO_WRONG_LENGTH = 0x04U, + /** 0x05, communication, info, Previous received PDO wasn't processed yet */ + CO_EM_RPDO_OVERFLOW = 0x05U, + /** 0x06, communication, info, CAN receive bus is passive */ + CO_EM_CAN_RX_BUS_PASSIVE = 0x06U, + /** 0x07, communication, info, CAN transmit bus is passive */ + CO_EM_CAN_TX_BUS_PASSIVE = 0x07U, + /** 0x08, communication, info, Wrong NMT command received */ + CO_EM_NMT_WRONG_COMMAND = 0x08U, + /** 0x09, communication, info, TIME message timeout */ + CO_EM_TIME_TIMEOUT = 0x09U, + /** 0x0A, communication, info, Unexpected TIME data length */ + CO_EM_TIME_LENGTH = 0x0AU, + /** 0x0B, communication, info, (unused) */ + CO_EM_0B_unused = 0x0BU, + /** 0x0C, communication, info, (unused) */ + CO_EM_0C_unused = 0x0CU, + /** 0x0D, communication, info, (unused) */ + CO_EM_0D_unused = 0x0DU, + /** 0x0E, communication, info, (unused) */ + CO_EM_0E_unused = 0x0EU, + /** 0x0F, communication, info, (unused) */ + CO_EM_0F_unused = 0x0FU, + + /** 0x10, communication, critical, (unused) */ + CO_EM_10_unused = 0x10U, + /** 0x11, communication, critical, (unused) */ + CO_EM_11_unused = 0x11U, + /** 0x12, communication, critical, CAN transmit bus is off */ + CO_EM_CAN_TX_BUS_OFF = 0x12U, + /** 0x13, communication, critical, CAN module receive buffer has + * overflowed */ + CO_EM_CAN_RXB_OVERFLOW = 0x13U, + /** 0x14, communication, critical, CAN transmit buffer has overflowed */ + CO_EM_CAN_TX_OVERFLOW = 0x14U, + /** 0x15, communication, critical, TPDO is outside SYNC window */ + CO_EM_TPDO_OUTSIDE_WINDOW = 0x15U, + /** 0x16, communication, critical, (unused) */ + CO_EM_16_unused = 0x16U, + /** 0x17, communication, critical, (unused) */ + CO_EM_17_unused = 0x17U, + /** 0x18, communication, critical, SYNC message timeout */ + CO_EM_SYNC_TIME_OUT = 0x18U, + /** 0x19, communication, critical, Unexpected SYNC data length */ + CO_EM_SYNC_LENGTH = 0x19U, + /** 0x1A, communication, critical, Error with PDO mapping */ + CO_EM_PDO_WRONG_MAPPING = 0x1AU, + /** 0x1B, communication, critical, Heartbeat consumer timeout */ + CO_EM_HEARTBEAT_CONSUMER = 0x1BU, + /** 0x1C, communication, critical, Heartbeat consumer detected remote node + * reset */ + CO_EM_HB_CONSUMER_REMOTE_RESET = 0x1CU, + /** 0x1D, communication, critical, (unused) */ + CO_EM_1D_unused = 0x1DU, + /** 0x1E, communication, critical, (unused) */ + CO_EM_1E_unused = 0x1EU, + /** 0x1F, communication, critical, (unused) */ + CO_EM_1F_unused = 0x1FU, + + /** 0x20, generic, info, Emergency buffer is full, Emergency message wasn't + * sent */ + CO_EM_EMERGENCY_BUFFER_FULL = 0x20U, + /** 0x21, generic, info, (unused) */ + CO_EM_21_unused = 0x21U, + /** 0x22, generic, info, Microcontroller has just started */ + CO_EM_MICROCONTROLLER_RESET = 0x22U, + /** 0x23, generic, info, (unused) */ + CO_EM_23_unused = 0x23U, + /** 0x24, generic, info, (unused) */ + CO_EM_24_unused = 0x24U, + /** 0x25, generic, info, (unused) */ + CO_EM_25_unused = 0x25U, + /** 0x26, generic, info, (unused) */ + CO_EM_26_unused = 0x26U, + /** 0x27, generic, info, (unused) */ + CO_EM_27_unused = 0x27U, + + /** 0x28, generic, critical, Wrong parameters to CO_errorReport() function*/ + CO_EM_WRONG_ERROR_REPORT = 0x28U, + /** 0x29, generic, critical, Timer task has overflowed */ + CO_EM_ISR_TIMER_OVERFLOW = 0x29U, + /** 0x2A, generic, critical, Unable to allocate memory for objects */ + CO_EM_MEMORY_ALLOCATION_ERROR = 0x2AU, + /** 0x2B, generic, critical, Generic error, test usage */ + CO_EM_GENERIC_ERROR = 0x2BU, + /** 0x2C, generic, critical, Software error */ + CO_EM_GENERIC_SOFTWARE_ERROR = 0x2CU, + /** 0x2D, generic, critical, Object dictionary does not match the software*/ + CO_EM_INCONSISTENT_OBJECT_DICT = 0x2DU, + /** 0x2E, generic, critical, Error in calculation of device parameters */ + CO_EM_CALCULATION_OF_PARAMETERS = 0x2EU, + /** 0x2F, generic, critical, Error with access to non volatile device memory + */ + CO_EM_NON_VOLATILE_MEMORY = 0x2FU, + + /** 0x30+, manufacturer, info or critical, Error status buts, free to use by + * manufacturer. By default bits 0x30..0x3F are set as informational and + * bits 0x40..0x4F are set as critical. Manufacturer critical bits sets the + * error register, as specified by @ref CO_CONFIG_ERR_CONDITION_MANUFACTURER + */ + CO_EM_MANUFACTURER_START = 0x30U, + /** (@ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1), largest value of the + * Error status bit. */ + CO_EM_MANUFACTURER_END = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1 +} CO_EM_errorStatusBits_t; /** - * Size of internal buffer, whwre emergencies are stored after CO_errorReport(). - * Buffer is cleared by CO_EM_process(). + * Emergency object. */ -#define CO_EM_INTERNAL_BUFFER_SIZE 10 +typedef struct { + /** Bitfield for the internal indication of the error condition. */ + uint8_t errorStatusBits[CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8]; + /** Pointer to error register in object dictionary at 0x1001,00. */ + uint8_t *errorRegister; + /** Old CAN error status bitfield */ + uint16_t CANerrorStatusOld; + +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ + || defined CO_DOXYGEN + /** Internal circular FIFO buffer for storing pre-processed emergency + * messages. Messages are added by @ref CO_error() function. All messages + * are later post-processed by @ref CO_EM_process() function. Fifo is also + * used for error history - OD object 0x1003, "Pre-defined error field". */ +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN + uint32_t fifo[CO_CONFIG_EM_BUFFER_SIZE + 1][2]; +#else + uint32_t fifo[CO_CONFIG_EM_BUFFER_SIZE + 1][1]; +#endif + /** Pointer for the fifo buffer, where next emergency message will be + * written by @ref CO_error() function. */ + uint8_t fifoWrPtr; + /** Pointer for the fifo, where next emergency message has to be + * post-processed by @ref CO_EM_process() function. If equal to bufWrPtr, + * then all messages has been post-processed. */ + uint8_t fifoPpPtr; + /** Indication of overflow - messages in buffer are not post-processed */ + uint8_t fifoOverflow; + /** Count of emergency messages in fifo, used for OD object 0x1003 */ + uint8_t fifoCount; +#endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ + +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN + /** True, if emergency producer is enabled, from Object dictionary */ + bool_t producerEnabled; + /** Copy of CANopen node ID, from CO_EM_init() */ + uint8_t nodeId; + /** From CO_EM_init() */ + CO_CANmodule_t *CANdevTx; + /** CAN transmit buffer */ + CO_CANtx_t *CANtxBuff; +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) || defined CO_DOXYGEN + /** COB ID of emergency message, from Object dictionary */ + uint16_t producerCanId; + /** From CO_EM_init() */ + uint16_t CANdevTxIdx; +#endif +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) || defined CO_DOXYGEN + /** Inhibit time for emergency message, from Object dictionary */ + uint32_t inhibitEmTime_us; + /**< Internal timer for inhibit time */ + uint32_t inhibitEmTimer; +#endif +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN + /** From CO_EM_initCallbackRx() or NULL */ + void (*pFunctSignalRx)(const uint16_t ident, + const uint16_t errorCode, + const uint8_t errorRegister, + const uint8_t errorBit, + const uint32_t infoCode); +#endif -/** - * Emergerncy object for CO_errorReport(). It contains error buffer, to which new emergency - * messages are written, when CO_errorReport() is called. This object is included in - * CO_EMpr_t object. - */ -typedef struct{ - uint8_t *errorStatusBits; /**< From CO_EM_init() */ - uint8_t errorStatusBitsSize; /**< From CO_EM_init() */ - - /** Internal buffer for storing unsent emergency messages.*/ - uint8_t buf[CO_EM_INTERNAL_BUFFER_SIZE * 8]; - uint8_t *bufEnd; /**< End+1 address of the above buffer */ - uint8_t *bufWritePtr; /**< Write pointer in the above buffer */ - uint8_t *bufReadPtr; /**< Read pointer in the above buffer */ - uint8_t bufFull; /**< True if above buffer is full */ - uint8_t wrongErrorReport; /**< Error in arguments to CO_errorReport() */ #if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_EM_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_EM_initCallbackPre() or NULL */ - void *functSignalObjectPre; -#endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN - /** From CO_EM_initCallbackRx() or NULL */ - void (*pFunctSignalRx)(const uint16_t ident, - const uint16_t errorCode, - const uint8_t errorRegister, - const uint8_t errorBit, - const uint32_t infoCode); + void *functSignalObjectPre; #endif -}CO_EM_t; - - -/** - * Report error condition. - * - * Function is called on any error condition inside CANopen stack and may also - * be called by application on custom error condition. Emergency message is sent - * after the first occurance of specific error. In case of critical error, device - * will not be able to stay in NMT_OPERATIONAL state. - * - * Function is short and may be used form any task or interrupt. - * - * @param em Emergency object. - * @param errorBit from @ref CO_EM_errorStatusBits. - * @param errorCode from @ref CO_EM_errorCodes. - * @param infoCode 32 bit value is passed to bytes 4...7 of the Emergency message. - * It contains optional additional information inside emergency message. - */ -void CO_errorReport(CO_EM_t *em, const uint8_t errorBit, const uint16_t errorCode, const uint32_t infoCode); - - -/** - * Reset error condition. - * - * Function is called if any error condition is solved. Emergency message is sent - * with @ref CO_EM_errorCodes 0x0000. - * - * Function is short and may be used form any task or interrupt. - * - * @param em Emergency object. - * @param errorBit from @ref CO_EM_errorStatusBits. - * @param infoCode 32 bit value is passed to bytes 4...7 of the Emergency message. - */ -void CO_errorReset(CO_EM_t *em, const uint8_t errorBit, const uint32_t infoCode); +} CO_EM_t; /** - * Check specific error condition. - * - * Function returns 1, if specific internal error is present. Otherwise it returns 0. - * - * @param em Emergency object. - * @param errorBit from @ref CO_EM_errorStatusBits. - * - * @return false: Error is not present. - * @return true: Error is present. - */ -bool_t CO_isError(CO_EM_t *em, const uint8_t errorBit); - - -#ifdef CO_DOXYGEN -/** Skip section, if CO_SDOserver.h is not included */ - #define CO_SDO_SERVER_H -#endif -#ifdef CO_SDO_SERVER_H - - -/** - * Error control and Emergency object. It controls internal error state and - * sends emergency message, if error condition was reported. Object is initialized - * by CO_EM_init(). It contains CO_EM_t object. - */ -typedef struct{ - uint8_t *errorRegister; /**< From CO_EM_init() */ - uint32_t *preDefErr; /**< From CO_EM_init() */ - uint8_t preDefErrSize; /**< From CO_EM_init() */ - uint8_t preDefErrNoOfErrors;/**< Number of active errors in preDefErr */ - uint32_t inhibitEmTimer; /**< Internal timer for emergency message */ - CO_EM_t *em; /**< CO_EM_t sub object is included here */ - uint16_t CANerrorStatusOld;/**< Old CAN error status bitfield */ - CO_CANmodule_t *CANdev; /**< From CO_EM_init() */ - CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer */ -}CO_EMpr_t; - - -/** - * Initialize Error control and Emergency object. + * Initialize Emergency object. * * Function must be called in the communication reset section. * - * @param emPr This object will be initialized. - * @param em Emergency object defined separately. Will be included in emPr and - * initialized too. - * @param SDO SDO server object. - * @param errorStatusBits Pointer to _Error Status Bits_ array from Object Dictionary - * (manufacturer specific section). See @ref CO_EM_errorStatusBits. - * @param errorStatusBitsSize Total size of the above array. Must be >= 6. - * @param errorRegister Pointer to _Error Register_ (Object dictionary, index 0x1001). - * @param preDefErr Pointer to _Pre defined error field_ array from Object - * dictionary, index 0x1003. - * @param preDefErrSize Size of the above array. - * @param CANdevRx CAN device for Emergency reception. - * @param CANdevRxIdx Index of receive buffer in the above CAN device. + * @param em This object will be initialized. + * @param OD_1001_errReg OD entry for 0x1001 - "Error register", entry is + * required, without IO extension. + * @param OD_1014_cobIdEm OD entry for 0x1014 - "COB-ID EMCY", entry is + * required, IO extension is required. * @param CANdevTx CAN device for Emergency transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. - * @param CANidTxEM CAN identifier for Emergency message. + * @param OD_1015_InhTime OD entry for 0x1015 - "Inhibit time EMCY", entry is + * optional (can be NULL), IO extension is optional for runtime configuration. + * @param OD_1003_preDefErr OD entry for 0x1003 - "Pre-defined error field". + * Emergency object has own memory buffer for this entry. Entry is optional, + * IO extension is required. + * @param OD_statusBits Custom OD entry for accessing errorStatusBits from + * @ref CO_EM_t. Entry must have bytestring_t of size + * (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT/8) bytes available for read/write access + * on subindex 0. Emergency object has own memory buffer for this entry. Entry + * is optional, IO extension is required. + * @param CANdevRx CAN device for Emergency consumer reception. + * @param CANdevRxIdx Index of receive buffer in the above CAN device. + * @param nodeId CANopen node ID of this device (for default emergency producer) * - * @return #CO_ReturnError_t CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_EM_init( - CO_EM_t *em, - CO_EMpr_t *emPr, - CO_SDO_t *SDO, - uint8_t *errorStatusBits, - uint8_t errorStatusBitsSize, - uint8_t *errorRegister, - uint32_t *preDefErr, - uint8_t preDefErrSize, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint16_t CANidTxEM); +CO_ReturnError_t CO_EM_init(CO_EM_t *em, + const OD_entry_t *OD_1001_errReg, +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN + const OD_entry_t *OD_1014_cobIdEm, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) || defined CO_DOXYGEN + const OD_entry_t *OD_1015_InhTime, + #endif +#endif +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) || defined CO_DOXYGEN + const OD_entry_t *OD_1003_preDefErr, +#endif +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) || defined CO_DOXYGEN + const OD_entry_t *OD_statusBits, +#endif +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, +#endif + const uint8_t nodeId); #if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN @@ -423,13 +501,13 @@ CO_ReturnError_t CO_EM_init( * immediately start mainline thread, which calls CO_EM_process() function. * * @param em This object. - * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignal(). Can + * be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_EM_initCallbackPre( - CO_EM_t *em, - void *object, - void (*pFunctSignal)(void *object)); +void CO_EM_initCallbackPre(CO_EM_t *em, + void *object, + void (*pFunctSignal)(void *object)); #endif @@ -449,13 +527,12 @@ void CO_EM_initCallbackPre( * @param em This object. * @param pFunctSignalRx Pointer to the callback function. Not called if NULL. */ -void CO_EM_initCallbackRx( - CO_EM_t *em, - void (*pFunctSignalRx)(const uint16_t ident, - const uint16_t errorCode, - const uint8_t errorRegister, - const uint8_t errorBit, - const uint32_t infoCode)); +void CO_EM_initCallbackRx(CO_EM_t *em, + void (*pFunctSignalRx)(const uint16_t ident, + const uint16_t errorCode, + const uint8_t errorRegister, + const uint8_t errorBit, + const uint32_t infoCode)); #endif @@ -463,24 +540,86 @@ void CO_EM_initCallbackRx( * Process Error control and Emergency object. * * Function must be called cyclically. It verifies some communication errors, - * calculates bit 0 and bit 4 from _Error register_ and sends emergency message + * calculates OD object 0x1001 - "Error register" and sends emergency message * if necessary. * - * @param emPr This object. - * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. - * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param emInhTime _Inhibit time EMCY_ in [100*us] (object dictionary, index 0x1015). + * @param em This object. + * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or + * NMT_OPERATIONAL state. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_EM_process( - CO_EMpr_t *emPr, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint16_t emInhTime, - uint32_t *timerNext_us); +void CO_EM_process(CO_EM_t *em, + bool_t NMTisPreOrOperational, + uint32_t timeDifference_us, + uint32_t *timerNext_us); -#endif +/** + * Set or reset error condition. + * + * Function can be called on any error condition inside CANopen stack or + * application. Function first checks change of error condition (setError is + * true and error bit wasn't set or setError is false and error bit was set + * before). If changed, then Emergency message is prepared and record in history + * is added. Emergency message is later sent by CO_EM_process() function. + * + * Function is short and thread safe. + * + * @param em Emergency object. + * @param setError True if error occurred or false if error resolved. + * @param errorBit from @ref CO_EM_errorStatusBits_t. + * @param errorCode from @ref CO_EM_errorCode_t. + * @param infoCode 32 bit value is passed to bytes 4...7 of the Emergency + * message. It contains optional additional information. + */ +void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, + uint16_t errorCode, uint32_t infoCode); + + +/** + * Report error condition, for description of parameters see @ref CO_error. + */ +#define CO_errorReport(em, errorBit, errorCode, infoCode) \ + CO_error(em, true, errorBit, errorCode, infoCode) + + +/** + * Reset error condition, for description of parameters see @ref CO_error. + */ +#define CO_errorReset(em, errorBit, infoCode) \ + CO_error(em, false, errorBit, CO_EMC_NO_ERROR, infoCode) + + +/** + * Check specific error condition. + * + * Function returns true, if specific internal error is present. + * + * @param em Emergency object. + * @param errorBit from @ref CO_EM_errorStatusBits_t. + * + * @return true if Error is present. + */ +static inline bool_t CO_isError(CO_EM_t *em, const uint8_t errorBit) { + uint8_t index = errorBit >> 3; + uint8_t bitmask = 1 << (errorBit & 0x7); + + return (em == NULL || index >= (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8) + || (em->errorStatusBits[index] & bitmask) != 0) ? true : false; +} + +/** + * Get error register + * + * @param em Emergency object. + * + * @return Error register or 0 if doesn't exist. + */ +static inline uint8_t CO_getErrorRegister(CO_EM_t *em) { + return (em == NULL || em->errorRegister == NULL) ? 0 : *em->errorRegister; +} /** @} */ /* CO_Emergency */ diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index c7513edb..eeb7ab6b 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -33,79 +33,78 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_NMT_receive(void *object, void *msg){ - CO_NMT_t *NMT; - uint8_t nodeId; +static void CO_NMT_receive(void *object, void *msg) { uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); + uint8_t command = data[0]; + uint8_t nodeId = data[1]; - NMT = (CO_NMT_t*)object; /* this is the correct pointer type of the first argument */ + CO_NMT_t *NMT = (CO_NMT_t*)object; - nodeId = data[1]; + if (DLC == 2 && (nodeId == 0 || nodeId == NMT->nodeId)) { + NMT->internalCommand = command; - if((DLC == 2) && ((nodeId == 0) || (nodeId == NMT->nodeId))){ - uint8_t command = data[0]; -#if (CO_CONFIG_NMT) & (CO_CONFIG_NMT_CALLBACK_CHANGE | CO_CONFIG_FLAG_CALLBACK_PRE) - CO_NMT_internalState_t currentOperatingState = NMT->operatingState; -#endif - - switch(command){ - case CO_NMT_ENTER_OPERATIONAL: - if((*NMT->emPr->errorRegister) == 0U){ - NMT->operatingState = CO_NMT_OPERATIONAL; - } - break; - case CO_NMT_ENTER_STOPPED: - NMT->operatingState = CO_NMT_STOPPED; - break; - case CO_NMT_ENTER_PRE_OPERATIONAL: - NMT->operatingState = CO_NMT_PRE_OPERATIONAL; - break; - case CO_NMT_RESET_NODE: - NMT->resetCommand = CO_RESET_APP; - break; - case CO_NMT_RESET_COMMUNICATION: - NMT->resetCommand = CO_RESET_COMM; - break; - default: - break; - } - -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE - if(NMT->pFunctNMT!=NULL && currentOperatingState!=NMT->operatingState){ - NMT->pFunctNMT(NMT->operatingState); +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles NMT. */ + if (NMT->pFunctSignalPre != NULL) { + NMT->pFunctSignalPre(NMT->functSignalObjectPre); } #endif -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles NMT. */ - if(NMT->pFunctSignalPre != NULL && currentOperatingState!=NMT->operatingState) { - NMT->pFunctSignalPre(NMT->functSignalObjectPre); } -#endif +} + + +/* + * Custom function for writing OD variable "Producer heartbeat time" + * + * For more information see file CO_ODinterface.h, OD_subEntry_t. + */ +static OD_size_t OD_write_1017(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + /* "count" is already verified in *_init() function */ + if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; } + + CO_NMT_t *NMT = (CO_NMT_t *)stream->object; + *returnCode = ODR_OK; + + /* update object, send Heartbeat immediately */ + NMT->HBproducerTime_us = (uint32_t)CO_getUint16(buf) * 1000; + NMT->HBproducerTimer = 0; + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); } /******************************************************************************/ -CO_ReturnError_t CO_NMT_init( - CO_NMT_t *NMT, - CO_EMpr_t *emPr, - uint8_t nodeId, - uint16_t firstHBTime_ms, - CO_CANmodule_t *NMT_CANdevRx, - uint16_t NMT_rxIdx, - uint16_t CANidRxNMT, - CO_CANmodule_t *NMT_CANdevTx, - uint16_t NMT_txIdx, - uint16_t CANidTxNMT, - CO_CANmodule_t *HB_CANdevTx, - uint16_t HB_txIdx, - uint16_t CANidTxHB) +CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, + const OD_entry_t *OD_1017_ProducerHbTime, + CO_EM_t *em, + uint8_t nodeId, + CO_NMT_control_t NMTcontrol, + uint16_t firstHBTime_ms, + CO_CANmodule_t *NMT_CANdevRx, + uint16_t NMT_rxIdx, + uint16_t CANidRxNMT, +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER + CO_CANmodule_t *NMT_CANdevTx, + uint16_t NMT_txIdx, + uint16_t CANidTxNMT, +#endif + CO_CANmodule_t *HB_CANdevTx, + uint16_t HB_txIdx, + uint16_t CANidTxHB) { CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if (NMT == NULL || emPr == NULL || NMT_CANdevRx == NULL || HB_CANdevTx == NULL + if (NMT == NULL || OD_1017_ProducerHbTime == NULL || em == NULL + || NMT_CANdevRx == NULL || HB_CANdevTx == NULL #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER || NMT_CANdevTx == NULL #endif @@ -117,11 +116,26 @@ CO_ReturnError_t CO_NMT_init( memset(NMT, 0, sizeof(CO_NMT_t)); /* Configure object variables */ - NMT->operatingState = CO_NMT_INITIALIZING; - NMT->operatingStatePrev = CO_NMT_INITIALIZING; - NMT->nodeId = nodeId; - NMT->firstHBTime = (int32_t)firstHBTime_ms * 1000; - NMT->emPr = emPr; + NMT->operatingState = CO_NMT_INITIALIZING; + NMT->operatingStatePrev = CO_NMT_INITIALIZING; + NMT->nodeId = nodeId; + NMT->NMTcontrol = NMTcontrol; + NMT->em = em; + NMT->HBproducerTimer = (int32_t)firstHBTime_ms * 1000; + + /* get and verify required "Producer heartbeat time" from Object Dict. */ + uint16_t HBprodTime_ms; + if (OD_get_u16(OD_1017_ProducerHbTime, 0, &HBprodTime_ms, true) != ODR_OK) { + return CO_ERROR_OD_PARAMETERS; + } + NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000; + OD_extensionIO_init(OD_1017_ProducerHbTime, + (void *) NMT, + OD_readOriginal, + OD_write_1017); + if (NMT->HBproducerTimer > NMT->HBproducerTime_us) { + NMT->HBproducerTimer = NMT->HBproducerTime_us; + } /* configure NMT CAN reception */ ret = CO_CANrxBufferInit( @@ -131,7 +145,10 @@ CO_ReturnError_t CO_NMT_init( 0x7FF, /* mask */ 0, /* rtr */ (void*)NMT, /* object passed to receive function */ - CO_NMT_receive); /* this function will process received message */ + CO_NMT_receive); /* this function will process received message*/ + if (ret != CO_ERROR_NO) { + return ret; + } #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER /* configure NMT CAN transmission */ @@ -144,7 +161,7 @@ CO_ReturnError_t CO_NMT_init( 2, /* number of data bytes */ 0); /* synchronous message flag bit */ if (NMT->NMT_TXbuff == NULL) { - ret = CO_ERROR_ILLEGAL_ARGUMENT; + return CO_ERROR_ILLEGAL_ARGUMENT; } #endif @@ -157,9 +174,8 @@ CO_ReturnError_t CO_NMT_init( 0, /* rtr */ 1, /* number of data bytes */ 0); /* synchronous message flag bit */ - if (NMT->HB_TXbuff == NULL) { - ret = CO_ERROR_ILLEGAL_ARGUMENT; + return CO_ERROR_ILLEGAL_ARGUMENT; } return ret; @@ -167,10 +183,9 @@ CO_ReturnError_t CO_NMT_init( #if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE -void CO_NMT_initCallbackPre( - CO_NMT_t *NMT, - void *object, - void (*pFunctSignal)(void *object)) +void CO_NMT_initCallbackPre(CO_NMT_t *NMT, + void *object, + void (*pFunctSignal)(void *object)) { if (NMT != NULL) { NMT->pFunctSignalPre = pFunctSignal; @@ -182,13 +197,12 @@ void CO_NMT_initCallbackPre( #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE /******************************************************************************/ -void CO_NMT_initCallbackChanged( - CO_NMT_t *NMT, - void (*pFunctNMT)(CO_NMT_internalState_t state)) +void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, + void (*pFunctNMT)(CO_NMT_internalState_t state)) { - if(NMT != NULL){ + if (NMT != NULL) { NMT->pFunctNMT = pFunctNMT; - if(NMT->pFunctNMT != NULL){ + if (NMT->pFunctNMT != NULL) { NMT->pFunctNMT(NMT->operatingState); } } @@ -197,135 +211,112 @@ void CO_NMT_initCallbackChanged( /******************************************************************************/ -CO_NMT_reset_cmd_t CO_NMT_process( - CO_NMT_t *NMT, - uint32_t timeDifference_us, - uint16_t HBtime_ms, - uint32_t NMTstartup, - uint8_t errorRegister, - const uint8_t errorBehavior[], - uint32_t *timerNext_us) +CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, + CO_NMT_internalState_t *NMTstate, + uint32_t timeDifference_us, + uint32_t *timerNext_us) { (void)timerNext_us; /* may be unused */ + CO_NMT_internalState_t NMTstateCpy = NMT->operatingState; + CO_NMT_reset_cmd_t resetCommand = CO_RESET_NOT; + bool_t NNTinit = NMTstateCpy == CO_NMT_INITIALIZING; - uint8_t CANpassive; - CO_NMT_internalState_t currentOperatingState = NMT->operatingState; - uint32_t HBtime = (uint32_t)HBtime_ms * 1000; - - NMT->HBproducerTimer += timeDifference_us; + NMT->HBproducerTimer = (NMT->HBproducerTimer > timeDifference_us ) + ? (NMT->HBproducerTimer - timeDifference_us) : 0; /* Send heartbeat producer message if: * - First start, send bootup message or - * - HB producer and Timer expired or - * - HB producer and NMT->operatingState changed, but not from initialised */ - if ((NMT->operatingState == CO_NMT_INITIALIZING) || - (HBtime != 0 && (NMT->HBproducerTimer >= HBtime || - NMT->operatingState != NMT->operatingStatePrev) + * - HB producer enabled and: Timer expired or NMT->operatingState changed*/ + if (NNTinit || (NMT->HBproducerTime_us != 0 + && (NMT->HBproducerTimer == 0 + || NMTstateCpy != NMT->operatingStatePrev) )) { - /* Start from the beginning. If OS is slow, time sliding may occur. However, - * heartbeat is not for synchronization, it is for health report. */ - NMT->HBproducerTimer = 0; - - NMT->HB_TXbuff->data[0] = (uint8_t) NMT->operatingState; + NMT->HB_TXbuff->data[0] = (uint8_t) NMTstateCpy; CO_CANsend(NMT->HB_CANdevTx, NMT->HB_TXbuff); - if (NMT->operatingState == CO_NMT_INITIALIZING) { - /* After bootup messages send first heartbeat earlier */ - if (HBtime > NMT->firstHBTime) { - NMT->HBproducerTimer = HBtime - NMT->firstHBTime; - } - + if (NMTstateCpy == CO_NMT_INITIALIZING) { /* NMT slave self starting */ - if (NMTstartup == 0x00000008U) NMT->operatingState = CO_NMT_OPERATIONAL; - else NMT->operatingState = CO_NMT_PRE_OPERATIONAL; + NMTstateCpy = (NMT->NMTcontrol & CO_NMT_STARTUP_TO_OPERATIONAL) != 0 + ? CO_NMT_OPERATIONAL : CO_NMT_PRE_OPERATIONAL; + } + else { + /* Start timer from the beginning. If OS is slow, time sliding may + * occur. However, heartbeat is not for synchronization, it is for + * health report. In case of initializing, timer is set in the + * CO_NMT_init() function with pre-defined value. */ + NMT->HBproducerTimer = NMT->HBproducerTime_us; } } - NMT->operatingStatePrev = NMT->operatingState; - - /* CAN passive flag */ - CANpassive = 0; - if(CO_isError(NMT->emPr->em, CO_EM_CAN_TX_BUS_PASSIVE) || CO_isError(NMT->emPr->em, CO_EM_CAN_RX_BUS_PASSIVE)) - CANpassive = 1; - - /* in case of error enter pre-operational state */ - if(errorBehavior && (NMT->operatingState == CO_NMT_OPERATIONAL)){ - if(CANpassive && (errorBehavior[2] == 0 || errorBehavior[2] == 2)) errorRegister |= 0x10; - - if(errorRegister){ - /* Communication error */ - if(errorRegister & CO_ERR_REG_COMM_ERR){ - if(errorBehavior[1] == 0){ - NMT->operatingState = CO_NMT_PRE_OPERATIONAL; - } - else if(errorBehavior[1] == 2){ - NMT->operatingState = CO_NMT_STOPPED; - } - else if(CO_isError(NMT->emPr->em, CO_EM_CAN_TX_BUS_OFF) - || CO_isError(NMT->emPr->em, CO_EM_HEARTBEAT_CONSUMER) - || CO_isError(NMT->emPr->em, CO_EM_HB_CONSUMER_REMOTE_RESET)) - { - if(errorBehavior[0] == 0){ - NMT->operatingState = CO_NMT_PRE_OPERATIONAL; - } - else if(errorBehavior[0] == 2){ - NMT->operatingState = CO_NMT_STOPPED; - } - } - } - - /* Generic error */ - if(errorRegister & CO_ERR_REG_GENERIC_ERR){ - if (errorBehavior[3] == 0) NMT->operatingState = CO_NMT_PRE_OPERATIONAL; - else if (errorBehavior[3] == 2) NMT->operatingState = CO_NMT_STOPPED; - } - - /* Device profile error */ - if(errorRegister & CO_ERR_REG_DEV_PROFILE){ - if (errorBehavior[4] == 0) NMT->operatingState = CO_NMT_PRE_OPERATIONAL; - else if (errorBehavior[4] == 2) NMT->operatingState = CO_NMT_STOPPED; - } - - /* Manufacturer specific error */ - if(errorRegister & CO_ERR_REG_MANUFACTURER){ - if (errorBehavior[5] == 0) NMT->operatingState = CO_NMT_PRE_OPERATIONAL; - else if (errorBehavior[5] == 2) NMT->operatingState = CO_NMT_STOPPED; - } - - /* if operational state is lost, send HB immediately. */ - if(NMT->operatingState != CO_NMT_OPERATIONAL) - NMT->HBproducerTimer = HBtime; + NMT->operatingStatePrev = NMTstateCpy; + + /* process internal NMT commands, received from CO_NMT_receive() or + * CO_NMT_sendCommand() */ + if (NMT->internalCommand != 0) { + switch (NMT->internalCommand) { + case CO_NMT_ENTER_OPERATIONAL: + NMTstateCpy = CO_NMT_OPERATIONAL; + break; + case CO_NMT_ENTER_STOPPED: + NMTstateCpy = CO_NMT_STOPPED; + break; + case CO_NMT_ENTER_PRE_OPERATIONAL: + NMTstateCpy = CO_NMT_PRE_OPERATIONAL; + break; + case CO_NMT_RESET_NODE: + resetCommand = CO_RESET_APP; + break; + case CO_NMT_RESET_COMMUNICATION: + resetCommand = CO_RESET_COMM; + break; + default: + break; } + NMT->internalCommand = 0; + } + + /* verify NMT transitions based on error register */ + bool_t busOff_HB = (NMT->NMTcontrol & CO_NMT_ERR_ON_BUSOFF_HB) != 0 + && (CO_isError(NMT->em, CO_EM_CAN_TX_BUS_OFF) + || CO_isError(NMT->em, CO_EM_HEARTBEAT_CONSUMER) + || CO_isError(NMT->em, CO_EM_HB_CONSUMER_REMOTE_RESET)); + bool_t errRegMasked = (NMT->NMTcontrol & CO_NMT_ERR_ON_ERR_REG) != 0 + && (CO_getErrorRegister(NMT->em) & NMT->NMTcontrol) != 0; + + if (NMTstateCpy == CO_NMT_OPERATIONAL && (busOff_HB || errRegMasked)) { + NMTstateCpy = (NMT->NMTcontrol & CO_NMT_ERR_TO_STOPPED) != 0 + ? CO_NMT_STOPPED : CO_NMT_PRE_OPERATIONAL; + } + else if ((NMT->NMTcontrol & CO_NMT_ERR_FREE_TO_OPERATIONAL) != 0 + && NMTstateCpy == CO_NMT_PRE_OPERATIONAL && !busOff_HB && !errRegMasked + ) { + NMTstateCpy = CO_NMT_OPERATIONAL; } - if (currentOperatingState != NMT->operatingState) { #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE + /* Notify operating state change */ + if (NMT->operatingStatePrev != NMTstateCpy || NNTinit) { if (NMT->pFunctNMT != NULL) { - NMT->pFunctNMT(NMT->operatingState); - } -#endif -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT - /* execute next CANopen processing immediately */ - if (timerNext_us != NULL) { - *timerNext_us = 0; + NMT->pFunctNMT(NMTstateCpy); } -#endif } +#endif #if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT - /* Calculate, when next Heartbeat needs to be send and lower timerNext_us if necessary. */ - if (HBtime != 0 && timerNext_us != NULL) { - if (NMT->HBproducerTimer < HBtime) { - uint32_t diff = HBtime - NMT->HBproducerTimer; - if (*timerNext_us > diff) { - *timerNext_us = diff; - } - } else { + /* Calculate, when next Heartbeat needs to be send */ + if (NMT->HBproducerTime_us != 0 && timerNext_us != NULL) { + if (NMT->operatingStatePrev != NMTstateCpy) { *timerNext_us = 0; } + else if (*timerNext_us > NMT->HBproducerTimer) { + *timerNext_us = NMT->HBproducerTimer; + } } #endif - return (CO_NMT_reset_cmd_t) NMT->resetCommand; + NMT->operatingState = NMTstateCpy; + if (NMTstate != NULL) *NMTstate = NMTstateCpy; + + return resetCommand; } @@ -335,46 +326,19 @@ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, CO_NMT_command_t command, uint8_t nodeID) { - CO_ReturnError_t error = CO_ERROR_NO; - /* verify arguments */ if (NMT == NULL) { - error = CO_ERROR_TX_UNCONFIGURED; + return CO_ERROR_ILLEGAL_ARGUMENT; } /* Apply NMT command also to this node, if set so. */ - if (error == CO_ERROR_NO && (nodeID == 0 || nodeID == NMT->nodeId)) { - switch (command) { - case CO_NMT_ENTER_OPERATIONAL: - if ((*NMT->emPr->errorRegister) == 0) { - NMT->operatingState = CO_NMT_OPERATIONAL; - } - break; - case CO_NMT_ENTER_STOPPED: - NMT->operatingState = CO_NMT_STOPPED; - break; - case CO_NMT_ENTER_PRE_OPERATIONAL: - NMT->operatingState = CO_NMT_PRE_OPERATIONAL; - break; - case CO_NMT_RESET_NODE: - NMT->resetCommand = CO_RESET_APP; - break; - case CO_NMT_RESET_COMMUNICATION: - NMT->resetCommand = CO_RESET_COMM; - break; - default: - error = CO_ERROR_ILLEGAL_ARGUMENT; - break; - } + if (nodeID == 0 || nodeID == NMT->nodeId) { + NMT->internalCommand = command; } /* Send NMT master message. */ - if (error == CO_ERROR_NO) { - NMT->NMT_TXbuff->data[0] = command; - NMT->NMT_TXbuff->data[1] = nodeID; - error = CO_CANsend(NMT->NMT_CANdevTx, NMT->NMT_TXbuff); - } - - return error; + NMT->NMT_TXbuff->data[0] = command; + NMT->NMT_TXbuff->data[1] = nodeID; + return CO_CANsend(NMT->NMT_CANdevTx, NMT->NMT_TXbuff); } #endif diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 36816cdb..cd657cb0 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -27,7 +27,7 @@ #define CO_NMT_HEARTBEAT_H #include "301/CO_driver.h" -#include "301/CO_SDOserver.h" +#include "301/CO_ODinterface.h" #include "301/CO_Emergency.h" /* default configuration, see CO_config.h */ @@ -46,95 +46,158 @@ extern "C" { * * CANopen Network management and Heartbeat producer protocol. * - * CANopen device can be in one of the #CO_NMT_internalState_t + * CANopen device can be in one of the @ref CO_NMT_internalState_t * - Initializing. It is active before CANopen is initialized. * - Pre-operational. All CANopen objects are active, except PDOs. * - Operational. Process data objects (PDOs) are active too. * - Stopped. Only Heartbeat producer and NMT consumer are active. * * NMT master can change the internal state of the devices by sending - * #CO_NMT_command_t. + * @ref CO_NMT_command_t. * - * ###NMT message contents: + * ### NMT message contents: * * Byte | Description * -----|----------------------------------------------------------- - * 0 | #CO_NMT_command_t + * 0 | @ref CO_NMT_command_t * 1 | Node ID. If zero, command addresses all nodes. * - * ###Heartbeat message contents: + * ### Heartbeat message contents: * * Byte | Description * -----|----------------------------------------------------------- - * 0 | #CO_NMT_internalState_t + * 0 | @ref CO_NMT_internalState_t * - * @see #CO_Default_CAN_ID_t + * See @ref CO_Default_CAN_ID_t for CAN identifiers. */ - /** * Internal network state of the CANopen node */ -typedef enum{ - CO_NMT_UNKNOWN = -1, /**< Device state is unknown (for heartbeat consumer) */ - CO_NMT_INITIALIZING = 0, /**< Device is initializing */ - CO_NMT_PRE_OPERATIONAL = 127, /**< Device is in pre-operational state */ - CO_NMT_OPERATIONAL = 5, /**< Device is in operational state */ - CO_NMT_STOPPED = 4 /**< Device is stopped */ -}CO_NMT_internalState_t; +typedef enum { + /** -1, Device state is unknown (for heartbeat consumer) */ + CO_NMT_UNKNOWN = -1, + /** 0, Device is initializing */ + CO_NMT_INITIALIZING = 0, + /** 127, Device is in pre-operational state */ + CO_NMT_PRE_OPERATIONAL = 127, + /** 5, Device is in operational state */ + CO_NMT_OPERATIONAL = 5, + /** 4, Device is stopped */ + CO_NMT_STOPPED = 4 +} CO_NMT_internalState_t; /** * Commands from NMT master. */ -typedef enum{ - CO_NMT_ENTER_OPERATIONAL = 1, /**< Start device */ - CO_NMT_ENTER_STOPPED = 2, /**< Stop device */ - CO_NMT_ENTER_PRE_OPERATIONAL = 128, /**< Put device into pre-operational */ - CO_NMT_RESET_NODE = 129, /**< Reset device */ - CO_NMT_RESET_COMMUNICATION = 130 /**< Reset CANopen communication on device */ -}CO_NMT_command_t; +typedef enum { + /** 1, Start device */ + CO_NMT_ENTER_OPERATIONAL = 1, + /** 2, Stop device */ + CO_NMT_ENTER_STOPPED = 2, + /** 128, Put device into pre-operational */ + CO_NMT_ENTER_PRE_OPERATIONAL = 128, + /** 129, Reset device */ + CO_NMT_RESET_NODE = 129, + /** 130, Reset CANopen communication on device */ + CO_NMT_RESET_COMMUNICATION = 130 +} CO_NMT_command_t; /** - * Return code for CO_NMT_process() that tells application code what to + * Return code from CO_NMT_process() that tells application code what to * reset. */ -typedef enum{ - CO_RESET_NOT = 0,/**< Normal return, no action */ - CO_RESET_COMM = 1,/**< Application must provide communication reset. */ - CO_RESET_APP = 2,/**< Application must provide complete device reset */ - CO_RESET_QUIT = 3 /**< Application must quit, no reset of microcontroller (command is not requested by the stack.) */ -}CO_NMT_reset_cmd_t; +typedef enum { + /** 0, Normal return, no action */ + CO_RESET_NOT = 0, + /** 1, Application must provide communication reset. */ + CO_RESET_COMM = 1, + /** 2, Application must provide complete device reset */ + CO_RESET_APP = 2, + /** 3, Application must quit, no reset of microcontroller (command is not + * requested by the stack.) */ + CO_RESET_QUIT = 3 +} CO_NMT_reset_cmd_t; /** - * NMT consumer and Heartbeat producer object, initialized by CO_NMT_init() + * NMT control bitfield for NMT internal state. + * + * Variable of this type is passed to @ref CO_NMT_process() function. It + * controls behavior of the @ref CO_NMT_internalState_t of the device according + * to CANopen error register. + * + * Internal NMT state is controlled also with external NMT command, + * @ref CO_NMT_setInternalState() or @ref CO_NMT_sendCommand() functions. */ -typedef struct{ - CO_NMT_internalState_t operatingState; /**< Current NMT operating state. */ - CO_NMT_internalState_t operatingStatePrev; /**< Previous NMT operating state. */ - uint8_t resetCommand; /**< If different than zero, device will reset */ - uint8_t nodeId; /**< CANopen Node ID of this device */ - uint32_t HBproducerTimer;/**< Internal timer for HB producer */ - uint32_t firstHBTime; /**< From CO_NMT_init() */ - CO_EMpr_t *emPr; /**< From CO_NMT_init() */ +typedef enum { + /** First 8 bits can be used to specify bitmask for the + * @ref CO_errorRegister_t, to get relevant bits for the calculation. */ + CO_NMT_ERR_REG_MASK = 0x00FFU, + /** If bit is set, then device enters NMT operational state after the + * initialization phase, otherwise it enters NMT pre-operational state. */ + CO_NMT_STARTUP_TO_OPERATIONAL = 0x0100U, + /** If bit is set and device is operational, it enters NMT pre-operational + * or stopped state, if CAN bus is off or heartbeat consumer timeout is + * detected. */ + CO_NMT_ERR_ON_BUSOFF_HB = 0x1000U, + /** If bit is set and device is operational, it enters NMT pre-operational + * or stopped state, if masked CANopen error register is different than + * zero. */ + CO_NMT_ERR_ON_ERR_REG = 0x2000U, + /** If bit is set and CO_NMT_ERR_ON_xx condition is met, then device will + * enter NMT stopped state, otherwise it will enter NMT pre-op state. */ + CO_NMT_ERR_TO_STOPPED = 0x4000U, + /** If bit is set and device is pre-operational, it enters NMT operational + * state automatically, if conditions from CO_NMT_ERR_ON_xx are all false.*/ + CO_NMT_ERR_FREE_TO_OPERATIONAL = 0x8000U +} CO_NMT_control_t; + + +/** + * NMT consumer and Heartbeat producer object + */ +typedef struct { + /** Current NMT operating state. */ + uint8_t operatingState; + /** Previous NMT operating state. */ + uint8_t operatingStatePrev; + /** NMT internal command from CO_NMT_receive() or CO_NMT_sendCommand(), + * processed in CO_NMT_process(). 0 if no command or CO_NMT_command_t */ + uint8_t internalCommand; + /** From CO_NMT_init() */ + uint8_t nodeId; + /** From CO_NMT_init() */ + CO_NMT_control_t NMTcontrol; + /** Producer heartbeat time, calculated from OD 0x1017 */ + uint32_t HBproducerTime_us; + /** Internal timer for HB producer */ + uint32_t HBproducerTimer; + /** From CO_NMT_init() */ + CO_EM_t *em; #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN - CO_CANmodule_t *NMT_CANdevTx; /**< From CO_NMT_init() */ - CO_CANtx_t *NMT_TXbuff; /**< CAN transmit buffer for NMT master message */ + /** From CO_NMT_init() */ + CO_CANmodule_t *NMT_CANdevTx; + /** CAN transmit buffer for NMT master message */ + CO_CANtx_t *NMT_TXbuff; #endif - CO_CANmodule_t *HB_CANdevTx; /**< From CO_NMT_init() */ - CO_CANtx_t *HB_TXbuff; /**< CAN transmit buffer for heartbeat message */ + /** From CO_NMT_init() */ + CO_CANmodule_t *HB_CANdevTx; + /** CAN transmit buffer for heartbeat message */ + CO_CANtx_t *HB_TXbuff; #if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_NMT_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_NMT_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void *functSignalObjectPre; #endif #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) || defined CO_DOXYGEN - void (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallbackChanged() or NULL */ + /** From CO_NMT_initCallbackChanged() or NULL */ + void (*pFunctNMT)(CO_NMT_internalState_t state); #endif -}CO_NMT_t; +} CO_NMT_t; /** @@ -143,11 +206,16 @@ typedef struct{ * Function must be called in the communication reset section. * * @param NMT This object will be initialized. - * @param emPr Emergency main object. + * @param OD_1017_ProducerHbTime OD entry for 0x1017 -"Producer heartbeat time", + * entry is required, IO extension is optional for runtime configuration. + * @param em Emergency object. * @param nodeId CANopen Node ID of this device. - * @param firstHBTime_ms Time between bootup and first heartbeat message in milliseconds. - * If firstHBTime is greater than _Producer Heartbeat time_ - * (object dictionary, index 0x1017), latter is used instead. + * @param NMTcontrol Control variable for calculation of NMT internal state, + * based on error register, startup and runtime behavior. + * @param firstHBTime_ms Time between bootup and first heartbeat message in + * milliseconds. If firstHBTime_ms is greater than "Producer Heartbeat time" + * (OD object 0x1017), latter is used instead. Entry is required, IO extension + * is optional. * @param NMT_CANdevRx CAN device for NMT reception. * @param NMT_rxIdx Index of receive buffer in above CAN device. * @param CANidRxNMT CAN identifier for NMT receive message. @@ -158,22 +226,25 @@ typedef struct{ * @param HB_txIdx Index of transmit buffer in the above CAN device. * @param CANidTxHB CAN identifier for HB message. * - * @return #CO_ReturnError_t CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_NMT_init( - CO_NMT_t *NMT, - CO_EMpr_t *emPr, - uint8_t nodeId, - uint16_t firstHBTime_ms, - CO_CANmodule_t *NMT_CANdevRx, - uint16_t NMT_rxIdx, - uint16_t CANidRxNMT, - CO_CANmodule_t *NMT_CANdevTx, - uint16_t NMT_txIdx, - uint16_t CANidTxNMT, - CO_CANmodule_t *HB_CANdevTx, - uint16_t HB_txIdx, - uint16_t CANidTxHB); +CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, + const OD_entry_t *OD_1017_ProducerHbTime, + CO_EM_t *em, + uint8_t nodeId, + CO_NMT_control_t NMTcontrol, + uint16_t firstHBTime_ms, + CO_CANmodule_t *NMT_CANdevRx, + uint16_t NMT_rxIdx, + uint16_t CANidRxNMT, +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN + CO_CANmodule_t *NMT_CANdevTx, + uint16_t NMT_txIdx, + uint16_t CANidTxNMT, +#endif + CO_CANmodule_t *HB_CANdevTx, + uint16_t HB_txIdx, + uint16_t CANidTxHB); #if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN @@ -185,13 +256,13 @@ CO_ReturnError_t CO_NMT_init( * Callback is called after NMT message is received from the CAN bus. * * @param NMT This object. - * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignal(). + * Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_NMT_initCallbackPre( - CO_NMT_t *NMT, - void *object, - void (*pFunctSignal)(void *object)); +void CO_NMT_initCallbackPre(CO_NMT_t *NMT, + void *object, + void (*pFunctSignal)(void *object)); #endif @@ -200,19 +271,15 @@ void CO_NMT_initCallbackPre( * Initialize NMT callback function. * * Function initializes optional callback function, which is called after - * NMT State change has occured. Function may wake up external task which - * handles NMT events. - * The first call is made immediately to give the consumer the current NMT state. - * - * @remark Be aware that the callback function is run inside the CAN receive - * function context. Depending on the driver, this might be inside an interrupt! + * NMT State change has occurred. Function may wake up external task which + * handles NMT events. The first call is made immediately to give the consumer + * the current NMT state. * * @param NMT This object. * @param pFunctNMT Pointer to the callback function. Not called if NULL. */ -void CO_NMT_initCallbackChanged( - CO_NMT_t *NMT, - void (*pFunctNMT)(CO_NMT_internalState_t state)); +void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, + void (*pFunctNMT)(CO_NMT_internalState_t state)); #endif @@ -222,25 +289,17 @@ void CO_NMT_initCallbackChanged( * Function must be called cyclically. * * @param NMT This object. - * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param HBtime_ms _Producer Heartbeat time_ (object dictionary, index 0x1017). - * @param NMTstartup _NMT startup behavior_ (object dictionary, index 0x1F80). - * @param errorRegister _Error register_ (object dictionary, index 0x1001). - * @param errorBehavior pointer to _Error behavior_ array (object dictionary, index 0x1029). - * Object controls, if device should leave NMT operational state. - * Length of array must be 6. If pointer is NULL, no calculation is made. + * @param [out] NMTstate If not NULL, CANopen NMT internal state is returned. + * @param timeDifference_us Time difference from previous function call in + * microseconds. * @param [out] timerNext_us info to OS - see CO_process(). * * @return #CO_NMT_reset_cmd_t */ -CO_NMT_reset_cmd_t CO_NMT_process( - CO_NMT_t *NMT, - uint32_t timeDifference_us, - uint16_t HBtime_ms, - uint32_t NMTstartup, - uint8_t errorRegister, - const uint8_t errorBehavior[], - uint32_t *timerNext_us); +CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, + CO_NMT_internalState_t *NMTstate, + uint32_t timeDifference_us, + uint32_t *timerNext_us); /** @@ -248,28 +307,44 @@ CO_NMT_reset_cmd_t CO_NMT_process( * * @param NMT This object. * - * @return #CO_NMT_internalState_t + * @return @ref CO_NMT_internalState_t */ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { return (NMT == NULL) ? CO_NMT_INITIALIZING : NMT->operatingState; } +/** + * Set internal NMT state + * + * Functions sets state directly, without any checking. @ref CO_NMT_process() + * may also switch between states automatically, see @ref CO_NMT_control_t. + * + * @param NMT This object. + * @param state New state. + */ +static inline void CO_NMT_setInternalState(CO_NMT_t *NMT, + CO_NMT_internalState_t state) +{ + if (NMT != NULL) NMT->operatingState = state; +} + + #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN /** * Send NMT master command. * - * This functionality can only be used from NMT master. There is one exception - * where application from slave node may send NMT master command: If CANopen - * object 0x1F80 has value of **0x2**, then NMT slave shall execute the NMT - * service start remote node (CO_NMT_ENTER_OPERATIONAL) with nodeID set to 0. + * This functionality may only be used from NMT master, as specified by + * standard CiA302-2. Standard provides one exception, where application from + * slave node may send NMT master command: "If CANopen object 0x1F80 has value + * of **0x2**, then NMT slave shall execute the NMT service start remote node + * (CO_NMT_ENTER_OPERATIONAL) with nodeID set to 0." * * @param NMT This object. * @param command NMT command from CO_NMT_command_t. * @param nodeID Node ID of the remote node. 0 for all nodes including self. * - * @return 0: Operation completed successfully. - * @return other: same as CO_CANsend(). + * @return CO_ERROR_NO on success or CO_ReturnError_t from CO_CANsend(). */ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, CO_NMT_command_t command, diff --git a/301/CO_PDO.c b/301/CO_PDO.c index bad3480b..420a7845 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -28,6 +28,8 @@ #include "301/CO_PDO.h" +#if (CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE) + /* * Read received message from CAN module. * @@ -1093,3 +1095,4 @@ void CO_TPDO_process( else TPDO->sendRequest = 0; } } +#endif /* (CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE) */ diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 09a65876..be3f9156 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -39,6 +39,8 @@ CO_CONFIG_PDO_SYNC_ENABLE) #endif +#if ((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) || defined CO_DOXYGEN + #ifdef __cplusplus extern "C" { #endif @@ -436,4 +438,6 @@ void CO_TPDO_process( } #endif /*__cplusplus*/ +#endif /* (CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE) */ + #endif /* CO_PDO_H */ diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 4e859ef2..879077dc 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -156,17 +156,100 @@ static void CO_SDOclient_receive(void *object, void *msg) { } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC +/* + * Custom function for writing OD variable _SDO client parameter_ + * + * For more information see file CO_ODinterface.h, OD_subEntry_t. + */ +static OD_size_t OD_write_1280(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + /* "count" is already verified in *_init() function */ + if (stream == NULL || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + CO_SDOclient_t *SDO_C = (CO_SDOclient_t *)stream->object; + *returnCode = ODR_OK; + uint32_t COB_ID; + uint8_t nodeId; + + switch (subIndex) { + case 0: /* Highest sub-index supported */ + *returnCode = ODR_READONLY; + return 0; + + case 1: /* COB-ID client -> server */ + COB_ID = CO_getUint32(buf); + + /* SDO client must not be valid when changing COB_ID */ + if ((COB_ID & 0x3FFFF800) != 0 + || ((uint16_t)COB_ID != (uint16_t)SDO_C->COB_IDClientToServer + && SDO_C->valid && (COB_ID & 0x80000000) == 0) + ) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + CO_SDOclient_setup(SDO_C, + COB_ID, + SDO_C->COB_IDServerToClient, + SDO_C->nodeIDOfTheSDOServer); + break; + + case 2: /* COB-ID server -> client */ + COB_ID = CO_getUint32(buf); + + /* SDO client must not be valid when changing COB_ID */ + if ((COB_ID & 0x3FFFF800) != 0 + || ((uint16_t)COB_ID != (uint16_t)SDO_C->COB_IDServerToClient + && SDO_C->valid && (COB_ID & 0x80000000) == 0) + ) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + CO_SDOclient_setup(SDO_C, + SDO_C->COB_IDClientToServer, + COB_ID, + SDO_C->nodeIDOfTheSDOServer); + break; + + case 3: /* Node-ID of the SDO server */ + nodeId = CO_getUint8(buf); + if (nodeId > 127) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + SDO_C->nodeIDOfTheSDOServer = nodeId; + break; + + default: + *returnCode = ODR_SUB_NOT_EXIST; + return 0; + } + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); +} +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC */ + + /******************************************************************************/ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, - void *SDO, - CO_SDOclientPar_t *SDOClientPar, + const OD_t *OD, + const OD_entry_t *OD_1280_SDOcliPar, + uint8_t nodeId, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx) { /* verify arguments */ - if (SDO_C == NULL || SDOClientPar == NULL || SDOClientPar->maxSubIndex != 3 + if (SDO_C == NULL || OD_1280_SDOcliPar == NULL + || OD_getIndex(OD_1280_SDOcliPar) < OD_H1280_SDO_CLIENT_1_PARAM + || OD_getIndex(OD_1280_SDOcliPar) > (OD_H1280_SDO_CLIENT_1_PARAM + 0x7F) || CANdevRx==NULL || CANdevTx==NULL ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -174,32 +257,57 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, /* Configure object variables */ #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL - SDO_C->SDO = (CO_SDO_t *)SDO; + SDO_C->OD = OD; + SDO_C->nodeId = nodeId; #endif - SDO_C->SDOClientPar = SDOClientPar; SDO_C->CANdevRx = CANdevRx; SDO_C->CANdevRxIdx = CANdevRxIdx; SDO_C->CANdevTx = CANdevTx; SDO_C->CANdevTxIdx = CANdevTxIdx; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE + SDO_C->pFunctSignal = NULL; + SDO_C->functSignalObject = NULL; +#endif /* prepare circular fifo buffer */ CO_fifo_init(&SDO_C->bufFifo, SDO_C->buf, CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1); -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE - SDO_C->pFunctSignal = NULL; - SDO_C->functSignalObject = NULL; + /* Get parameters from Object Dictionary (initial values) */ + uint8_t maxSubIndex, nodeIDOfTheSDOServer; + uint32_t COB_IDClientToServer, COB_IDServerToClient; + ODR_t odRet0 = OD_get_u8(OD_1280_SDOcliPar, 0, &maxSubIndex, true); + ODR_t odRet1 = OD_get_u32(OD_1280_SDOcliPar, 1, &COB_IDClientToServer, true); + ODR_t odRet2 = OD_get_u32(OD_1280_SDOcliPar, 2, &COB_IDServerToClient, true); + ODR_t odRet3 = OD_get_u8(OD_1280_SDOcliPar, 3, &nodeIDOfTheSDOServer, true); + + if (odRet0 != ODR_OK || maxSubIndex != 3 + || odRet1 != ODR_OK || odRet2 != ODR_OK || odRet3 != ODR_OK + ) { + return CO_ERROR_OD_PARAMETERS; + } + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC + if (!OD_extensionIO_init(OD_1280_SDOcliPar, + (void *)SDO_C, + OD_readOriginal, + OD_write_1280)) { + return CO_ERROR_OD_PARAMETERS; + } + + /* set to zero to make sure CO_SDOclient_setup() will reconfigure CAN */ + SDO_C->COB_IDClientToServer = 0; + SDO_C->COB_IDServerToClient = 0; #endif - SDO_C->state = CO_SDO_ST_IDLE; - CO_FLAG_CLEAR(SDO_C->CANrxNew); + CO_SDO_return_t cliSetupRet = CO_SDOclient_setup(SDO_C, + COB_IDClientToServer, + COB_IDServerToClient, + nodeIDOfTheSDOServer); - SDO_C->COB_IDClientToServerPrev = 0; - SDO_C->COB_IDServerToClientPrev = 0; - CO_SDOclient_setup(SDO_C, - SDO_C->SDOClientPar->COB_IDClientToServer, - SDO_C->SDOClientPar->COB_IDServerToClient, - SDO_C->SDOClientPar->nodeIDOfTheSDOServer); + if (cliSetupRet != CO_SDO_RT_ok_communicationEnd) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } return CO_ERROR_NO; } @@ -225,76 +333,65 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, uint32_t COB_IDServerToClient, uint8_t nodeIDOfTheSDOServer) { - uint32_t idCtoS, idStoC; - uint8_t idNode; - /* verify parameters */ - if (SDO_C == NULL - || (COB_IDClientToServer & 0x7FFFF800L) != 0 - || (COB_IDServerToClient & 0x7FFFF800L) != 0 - || nodeIDOfTheSDOServer > 127 - ) { + if (SDO_C == NULL) { return CO_SDO_RT_wrongArguments; } /* Configure object variables */ SDO_C->state = CO_SDO_ST_IDLE; CO_FLAG_CLEAR(SDO_C->CANrxNew); + SDO_C->nodeIDOfTheSDOServer = nodeIDOfTheSDOServer; - /* setup Object Dictionary variables */ - if ((COB_IDClientToServer & 0x80000000L) != 0 - || (COB_IDServerToClient & 0x80000000L) != 0 - || nodeIDOfTheSDOServer == 0 +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC + /* proceed only, if parameters change */ + if (COB_IDClientToServer == SDO_C->COB_IDClientToServer + && COB_IDServerToClient == SDO_C->COB_IDServerToClient ) { - /* SDO is NOT used */ - idCtoS = 0x80000000L; - idStoC = 0x80000000L; - idNode = 0; + return CO_SDO_RT_ok_communicationEnd; + } + /* store variables */ + SDO_C->COB_IDClientToServer = COB_IDClientToServer; + SDO_C->COB_IDServerToClient = COB_IDServerToClient; +#endif + + /* verify valid bit */ + uint16_t CanIdC2S = ((COB_IDClientToServer & 0x80000000L) == 0) ? + (uint16_t)(COB_IDClientToServer & 0x7FF) : 0; + uint16_t CanIdS2C = ((COB_IDServerToClient & 0x80000000L) == 0) ? + (uint16_t)(COB_IDServerToClient & 0x7FF) : 0; + if (CanIdC2S != 0 && CanIdS2C != 0) { + SDO_C->valid = true; } else { - if (COB_IDClientToServer == 0 || COB_IDServerToClient == 0) { - idCtoS = 0x600 + nodeIDOfTheSDOServer; - idStoC = 0x580 + nodeIDOfTheSDOServer; - } - else { - idCtoS = COB_IDClientToServer; - idStoC = COB_IDServerToClient; - } - idNode = nodeIDOfTheSDOServer; + CanIdC2S = 0; + CanIdS2C = 0; + SDO_C->valid = false; } - SDO_C->SDOClientPar->COB_IDClientToServer = idCtoS; - SDO_C->SDOClientPar->COB_IDServerToClient = idStoC; - SDO_C->SDOClientPar->nodeIDOfTheSDOServer = idNode; - - /* configure SDO client CAN reception, if differs. */ - if (SDO_C->COB_IDClientToServerPrev != idCtoS - || SDO_C->COB_IDServerToClientPrev != idStoC - ) { - CO_ReturnError_t ret = CO_CANrxBufferInit( - SDO_C->CANdevRx, /* CAN device */ - SDO_C->CANdevRxIdx, /* rx buffer index */ - (uint16_t)idStoC, /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void*)SDO_C, /* object passed to receive function */ - CO_SDOclient_receive); /* this function will process rx msg */ - - /* configure SDO client CAN transmission */ - SDO_C->CANtxBuff = CO_CANtxBufferInit( - SDO_C->CANdevTx, /* CAN device */ - SDO_C->CANdevTxIdx, /* index of buffer inside CAN module */ - (uint16_t)idCtoS, /* CAN identifier */ - 0, /* rtr */ - 8, /* number of data bytes */ - 0); /* synchronous message flag bit */ - - SDO_C->COB_IDClientToServerPrev = idCtoS; - SDO_C->COB_IDServerToClientPrev = idStoC; - - if (ret != CO_ERROR_NO || SDO_C->CANtxBuff == NULL) { - return CO_SDO_RT_wrongArguments; - } + /* configure SDO client CAN reception */ + CO_ReturnError_t ret = CO_CANrxBufferInit( + SDO_C->CANdevRx, /* CAN device */ + SDO_C->CANdevRxIdx, /* rx buffer index */ + CanIdS2C, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)SDO_C, /* object passed to receive function */ + CO_SDOclient_receive); /* this function will process rx msg */ + + /* configure SDO client CAN transmission */ + SDO_C->CANtxBuff = CO_CANtxBufferInit( + SDO_C->CANdevTx, /* CAN device */ + SDO_C->CANdevTxIdx, /* index of buffer inside CAN module */ + CanIdC2S, /* CAN identifier */ + 0, /* rtr */ + 8, /* number of data bytes */ + 0); /* synchronous message flag bit */ + + + if (ret != CO_ERROR_NO || SDO_C->CANtxBuff == NULL) { + return CO_SDO_RT_wrongArguments; + SDO_C->valid = false; } return CO_SDO_RT_ok_communicationEnd; @@ -312,7 +409,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, bool_t blockEnable) { /* verify parameters */ - if (SDO_C == NULL) { + if (SDO_C == NULL || !SDO_C->valid) { return CO_SDO_RT_wrongArguments; } @@ -329,9 +426,10 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ - if (SDO_C->SDO != NULL - && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId + if (SDO_C->OD != NULL && SDO_C->nodeId != 0 + && SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId ) { + SDO_C->OD_IO.write = NULL; SDO_C->state = CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER; } else @@ -372,8 +470,8 @@ void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, /******************************************************************************/ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, - const char *buf, - size_t count) + const char *buf, + size_t count) { size_t ret = 0; if (SDO_C != NULL && buf != NULL) { @@ -387,16 +485,17 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, bool_t abort, + bool_t bufferPartial, CO_SDO_abortCode_t *SDOabortCode, size_t *sizeTransferred, uint32_t *timerNext_us) { - (void)timerNext_us; /* may be unused */ + (void)timerNext_us; (void) bufferPartial; /* may be unused */ CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; - if (SDO_C == NULL) { + if (SDO_C == NULL || !SDO_C->valid) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_wrongArguments; } @@ -411,37 +510,96 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) { - if (SDO_C->SDO->state != CO_SDO_ST_IDLE) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - ret = CO_SDO_RT_endedWithClientAbort; + /* search object dictionary in first pass */ + if (SDO_C->OD_IO.write == NULL) { + ODR_t odRet; + OD_subEntry_t subEntry; + + odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, + &subEntry, &SDO_C->OD_IO.stream, false); + + if (odRet != ODR_OK) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + ret = CO_SDO_RT_endedWithClientAbort; + } + else if ((subEntry.attribute & ODA_SDO_W) == 0) { + abortCode = CO_SDO_AB_READONLY; + ret = CO_SDO_RT_endedWithClientAbort; + } + else if (subEntry.write == NULL) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + ret = CO_SDO_RT_endedWithClientAbort; + } + else { + SDO_C->OD_IO.write = subEntry.write; + } } - else { - /* Max data size is limited to fifo size (for now). */ + /* write data, in several passes if necessary */ + if (SDO_C->OD_IO.write != NULL) { size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo); + char buf[count]; - if (SDO_C->sizeInd > 0 && SDO_C->sizeInd != count) { - abortCode = CO_SDO_AB_TYPE_MISMATCH; + CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); + SDO_C->sizeTran += count; + + /* error: no data */ + if (count == 0) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + ret = CO_SDO_RT_endedWithClientAbort; + } + /* verify if sizeTran is too large */ + else if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + SDO_C->sizeTran -= count; + abortCode = CO_SDO_AB_DATA_LONG; ret = CO_SDO_RT_endedWithClientAbort; } else { - /* init ODF_arg */ - abortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index, - SDO_C->subIndex); - if (abortCode == CO_SDO_AB_NONE) { - /* set buffer and write data to the Object dictionary */ - SDO_C->SDO->ODF_arg.data = (uint8_t *)SDO_C->buf; - abortCode = CO_SDO_writeOD(SDO_C->SDO, count); + ODR_t odRet; + + /* write data to Object Dictionary */ + SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, SDO_C->subIndex, + buf, count, &odRet); + + /* verify for errors in write */ + if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + ret = CO_SDO_RT_endedWithServerAbort; } - if (abortCode == CO_SDO_AB_NONE) { - SDO_C->sizeTran = count; - ret = CO_SDO_RT_ok_communicationEnd; + /* error if OD variable was written completelly, + * but SDO download still has data */ + else if (bufferPartial && odRet == ODR_OK) { + abortCode = CO_SDO_AB_DATA_LONG; + ret = CO_SDO_RT_endedWithClientAbort; + } + /* is end of transfer? */ + else if (!bufferPartial) { + /* error if OD variable was not written completely, but SDO + * download finished */ + if (odRet == ODR_PARTIAL) { + abortCode = CO_SDO_AB_DATA_SHORT; + ret = CO_SDO_RT_endedWithClientAbort; + } + /* Verify size transferred */ + else if (SDO_C->sizeInd > 0 + && SDO_C->sizeTran < SDO_C->sizeInd + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + ret = CO_SDO_RT_endedWithClientAbort; + } + /* data transfer finished successfully */ + else { + ret = CO_SDO_RT_ok_communicationEnd; + } } else { - ret = CO_SDO_RT_endedWithServerAbort; + ret = CO_SDO_RT_waitingLocalTransfer; } } } - SDO_C->state = CO_SDO_ST_IDLE; + + if (ret != CO_SDO_RT_waitingLocalTransfer) { + SDO_C->state = CO_SDO_ST_IDLE; + } } #endif /* CAN data received ******************************************************/ @@ -720,7 +878,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[0] = SDO_C->toggle | ((7 - count) << 1); /* is end of transfer? Verify also sizeTran */ - if (CO_fifo_getOccupied(&SDO_C->bufFifo) == 0) { + if (CO_fifo_getOccupied(&SDO_C->bufFifo) == 0 && !bufferPartial) { if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; @@ -777,7 +935,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* is end of transfer? Verify also sizeTran */ - if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0) { + if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0 && bufferPartial) { if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; @@ -866,7 +1024,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, bool_t blockEnable) { /* verify parameters */ - if (SDO_C == NULL) { + if (SDO_C == NULL || !SDO_C->valid) { return CO_SDO_RT_wrongArguments; } @@ -886,9 +1044,10 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ - if (SDO_C->SDO != NULL - && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId + if (SDO_C->OD != NULL && SDO_C->nodeId != 0 + && SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId ) { + SDO_C->OD_IO.read = NULL; SDO_C->state = CO_SDO_ST_UPLOAD_LOCAL_TRANSFER; } else @@ -922,7 +1081,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; - if (SDO_C == NULL) { + if (SDO_C == NULL || !SDO_C->valid) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_wrongArguments; } @@ -932,44 +1091,88 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ else if (SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) { - if (SDO_C->SDO->state != 0) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - ret = CO_SDO_RT_endedWithClientAbort; + /* search object dictionary in first pass */ + if (SDO_C->OD_IO.read == NULL) { + ODR_t odRet; + OD_subEntry_t subEntry; + + odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, + &subEntry, &SDO_C->OD_IO.stream, false); + + if (odRet != ODR_OK) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + ret = CO_SDO_RT_endedWithClientAbort; + } + else if ((subEntry.attribute & ODA_SDO_R) == 0) { + abortCode = CO_SDO_AB_WRITEONLY; + ret = CO_SDO_RT_endedWithClientAbort; + } + else if (subEntry.read == NULL) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + ret = CO_SDO_RT_endedWithClientAbort; + } + else { + SDO_C->OD_IO.read = subEntry.read; + } } - else { - /* Max data size is limited to fifo size (for now). */ - size_t count = CO_fifo_getSpace(&SDO_C->bufFifo); - - /* init ODF_arg */ - abortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index, - SDO_C->subIndex); - if (abortCode == CO_SDO_AB_NONE) { - /* set buffer and read data from the Object dictionary */ - SDO_C->SDO->ODF_arg.data = (uint8_t *)SDO_C->buf; - if (SDO_C->SDO->ODF_arg.ODdataStorage == 0) { - /* set length if domain */ - SDO_C->SDO->ODF_arg.dataLength = count; - } - abortCode = CO_SDO_readOD(SDO_C->SDO, count); + + size_t countFifo = CO_fifo_getSpace(&SDO_C->bufFifo); + + /* skip copying if buffer full */ + if (countFifo == 0) { + ret = CO_SDO_RT_uploadDataBufferFull; + } + /* read data, in several passes if necessary */ + else if (SDO_C->OD_IO.read != NULL) { + /* Get size of data in Object Dictionary. If size is not indicated + * use maximum SDO client buffer size. Prepare temp buffer. */ + OD_size_t countData = SDO_C->OD_IO.stream.dataLength; + OD_size_t countBuf = (countData > 0 && countData <= countFifo) + ? countData : countFifo; + char buf[countBuf]; + ODR_t odRet; + + /* load data from OD variable into the buffer */ + OD_size_t countRd = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, + SDO_C->subIndex, + buf, countBuf, &odRet); + + if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + ret = CO_SDO_RT_endedWithServerAbort; } - if (abortCode == CO_SDO_AB_NONE) { - /* is SDO buffer too small */ - if (SDO_C->SDO->ODF_arg.lastSegment == 0) { - abortCode = CO_SDO_AB_OUT_OF_MEM; /* Out of memory */ - ret = CO_SDO_RT_endedWithServerAbort; + else { + CO_fifo_write(&SDO_C->bufFifo, buf, countRd, NULL); + SDO_C->sizeTran += countRd; + + /* verify if size of data uploaded is too large */ + SDO_C->sizeInd = SDO_C->OD_IO.stream.dataLength; + if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + abortCode = CO_SDO_AB_DATA_LONG; + ret = CO_SDO_RT_endedWithClientAbort; + } + /* If no more segments to be upload, finish */ + else if (odRet == ODR_OK) { + /* verify size of data uploaded */ + if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd){ + abortCode = CO_SDO_AB_DATA_SHORT; + ret = CO_SDO_RT_endedWithClientAbort; + } + else { + ret = CO_SDO_RT_ok_communicationEnd; + } } else { - SDO_C->sizeTran = (size_t)SDO_C->SDO->ODF_arg.dataLength; - /* fifo was written directly, indicate data size manually */ - SDO_C->bufFifo.writePtr = SDO_C->sizeTran; - ret = CO_SDO_RT_ok_communicationEnd; + ret = CO_SDO_RT_waitingLocalTransfer; } } - else { - ret = CO_SDO_RT_endedWithServerAbort; - } } - SDO_C->state = CO_SDO_ST_IDLE; + + if (ret != CO_SDO_RT_uploadDataBufferFull + && ret != CO_SDO_RT_waitingLocalTransfer + ) { + SDO_C->state = CO_SDO_ST_IDLE; + } } #endif /* CAN data received ******************************************************/ @@ -1289,7 +1492,6 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* Transmit CAN data ******************************************************/ - if (ret == CO_SDO_RT_waitingResponse) { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK size_t count; diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index d8bf90fe..33b35b87 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -28,6 +28,7 @@ #define CO_SDO_CLIENT_H #include "301/CO_driver.h" +#include "301/CO_ODinterface.h" #include "301/CO_SDOserver.h" #include "301/CO_fifo.h" @@ -56,40 +57,18 @@ extern "C" { */ -/** - * SDO Client Parameter. The same as record from Object dictionary - * (index 0x1280+). - */ -typedef struct { - /** Equal to 3 */ - uint8_t maxSubIndex; - /** Communication object identifier for client transmission. - * Meaning of the specific bits: - - Bit 0...10: 11-bit CAN identifier. - - Bit 11..30: reserved, set to 0. - - Bit 31: if 1, SDO client object is not used. */ - uint32_t COB_IDClientToServer; - /** Communication object identifier for message received from server. - * Meaning of the specific bits: - - Bit 0...10: 11-bit CAN identifier. - - Bit 11..30: reserved, set to 0. - - Bit 31: if 1, SDO client object is not used. */ - uint32_t COB_IDServerToClient; - /** Node-ID of the SDO server */ - uint8_t nodeIDOfTheSDOServer; -} CO_SDOclientPar_t; - - /** * SDO client object */ typedef struct { #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) || defined CO_DOXYGEN /** From CO_SDOclient_init() */ - CO_SDO_t *SDO; -#endif + const OD_t *OD; /** From CO_SDOclient_init() */ - CO_SDOclientPar_t *SDOClientPar; + uint8_t nodeId; + /** Object dictionary interface for locally transferred object */ + OD_IO_t OD_IO; +#endif /** From CO_SDOclient_init() */ CO_CANmodule_t *CANdevRx; /** From CO_SDOclient_init() */ @@ -100,6 +79,19 @@ typedef struct { uint16_t CANdevTxIdx; /** CAN transmit buffer inside CANdevTx for CAN tx message */ CO_CANtx_t *CANtxBuff; +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN + /** Copy of CANopen COB_ID Client -> Server, meaning of the specific bits: + - Bit 0...10: 11-bit CAN identifier. + - Bit 11..30: reserved, must be 0. + - Bit 31: if 1, SDO client object is not used. */ + uint32_t COB_IDClientToServer; + /** Copy of CANopen COB_ID Server -> Client, similar as above */ + uint32_t COB_IDServerToClient; +#endif + /** Node-ID of the SDO server */ + uint8_t nodeIDOfTheSDOServer; + /* If true, SDO channel is valid */ + bool_t valid; /** Index of current object in Object Dictionary */ uint16_t index; /** Subindex of current object in Object Dictionary */ @@ -127,10 +119,6 @@ typedef struct { volatile void *CANrxNew; /** 8 data bytes of the received message */ uint8_t CANrxData[8]; - /** Previous value of the COB_IDClientToServer */ - uint32_t COB_IDClientToServerPrev; - /** Previous value of the COB_IDServerToClient */ - uint32_t COB_IDServerToClientPrev; #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_SDOclient_initCallbackPre() or NULL */ void (*pFunctSignal)(void *object); @@ -168,10 +156,13 @@ typedef struct { * Function must be called in the communication reset section. * * @param SDO_C This object will be initialized. - * @param SDO SDO server object. It is used in case, if client is accessing + * @param OD Object Dictionary. It is used in case, if client is accessing * object dictionary from its own device. If NULL, it will be ignored. - * @param SDOClientPar Pointer to _SDO Client Parameter_ record from Object - * dictionary (index 0x1280+). Will be written. + * @param OD_1280_SDOcliPar OD entry for SDO client parameter (0x1280+). It + * may have IO extension enabled to allow dynamic configuration (see also + * @ref CO_CONFIG_FLAG_OD_DYNAMIC). Entry is required. + * @param nodeId CANopen Node ID of this device. It is used in case, if client + * is accessing object dictionary from its own device. If 0, it will be ignored. * @param CANdevRx CAN device for SDO client reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for SDO client transmission. @@ -180,8 +171,9 @@ typedef struct { * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, - void *SDO, - CO_SDOclientPar_t *SDOClientPar, + const OD_t *OD, + const OD_entry_t *OD_1280_SDOcliPar, + uint8_t nodeId, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t *CANdevTx, @@ -212,23 +204,20 @@ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, /** * Setup SDO client object. * - * Function must be called before new SDO communication. If previous SDO - * communication was with the same node, function does not need to be called. - * - * @remark If configuring SDO client from network is required, this function - * should be set as callback for the corresponding SDO client parameter OD - * entry. + * Function is called in from CO_SDOclient_init() and each time when + * "SDO client parameter" is written. Application can call this function before + * new SDO communication. If parameters to this function are the same as before, + * then CAN is not reconfigured. * * @param SDO_C This object. - * @param COB_IDClientToServer See CO_SDOclientPar_t. If zero, then - * nodeIDOfTheSDOServer is used with default COB-ID. - * @param COB_IDServerToClient See CO_SDOclientPar_t. If zero, then - * nodeIDOfTheSDOServer is used with default COB-ID. - * @param nodeIDOfTheSDOServer Node-ID of the SDO server. If zero, SDO client - * object is not used. If it is the same as node-ID of this node, then data will - * be exchanged with this node (without CAN communication). - * - * @return #CO_SDO_return_t + * @param COB_IDClientToServer See @ref CO_SDOclient_t. + * @param COB_IDServerToClient See @ref CO_SDOclient_t. + * @param nodeIDOfTheSDOServer Node-ID of the SDO server. If it is the same as + * node-ID of this node, then data will be exchanged with this node + * (without CAN communication). + * + * @return #CO_SDO_return_t, CO_SDO_RT_ok_communicationEnd or + * CO_SDO_RT_wrongArguments */ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, uint32_t COB_IDClientToServer, @@ -303,8 +292,8 @@ void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, * @return number of bytes actually written. */ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, - const char *buf, - size_t count); + const char *buf, + size_t count); /** @@ -323,6 +312,8 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, * [microseconds]. * @param abort If true, SDO client will send abort message from SDOabortCode * and transmission will be aborted. + * @param bufferPartial True indicates, not all data were copied to internal + * buffer yet. Buffer will be refilled later with #CO_SDOclientDownloadBufWrite. * @param [out] SDOabortCode In case of error in communication, SDO abort code * contains reason of error. Ignored if NULL. * @param [out] sizeTransferred Actual size of data transferred. Ignored if NULL @@ -334,11 +325,12 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, * communication is in progress. */ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - bool_t abort, - CO_SDO_abortCode_t *SDOabortCode, - size_t *sizeTransferred, - uint32_t *timerNext_us); + uint32_t timeDifference_us, + bool_t abort, + bool_t bufferPartial, + CO_SDO_abortCode_t *SDOabortCode, + size_t *sizeTransferred, + uint32_t *timerNext_us); /** diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index a02121b8..266ddad7 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -4,7 +4,7 @@ * @file CO_SDOserver.c * @ingroup CO_SDOserver * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -23,39 +23,28 @@ * limitations under the License. */ +#include -#include "301/CO_driver.h" #include "301/CO_SDOserver.h" #include "301/crc16-ccitt.h" - -/* Client command specifier, see DS301 */ -#define CCS_DOWNLOAD_INITIATE 1U -#define CCS_DOWNLOAD_SEGMENT 0U -#define CCS_UPLOAD_INITIATE 2U -#define CCS_UPLOAD_SEGMENT 3U -#define CCS_DOWNLOAD_BLOCK 6U -#define CCS_UPLOAD_BLOCK 5U -#define CCS_ABORT 0x80U - - -#if CO_CONFIG_SDO_BUFFER_SIZE < 7 - #error CO_CONFIG_SDO_BUFFER_SIZE must be greater than 7 +/* verify configuration */ +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 8 + #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 8. + #endif #endif - -static void CO_SDO_receive_done(CO_SDO_t *SDO){ -#if CO_SDO_RX_DATA_SIZE > 1 - uint8_t rcv = SDO->CANrxRcv; - uint8_t newRcv = rcv; - - if (++newRcv >= CO_SDO_RX_DATA_SIZE) - newRcv = 0; - SDO->CANrxRcv = newRcv; - CO_FLAG_SET(SDO->CANrxNew[rcv]); -#else - CO_FLAG_SET(SDO->CANrxNew[0]); +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + #if !((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) + #error CO_CONFIG_SDO_SRV_SEGMENTED must be enabled. + #endif + #if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) + #error CO_CONFIG_CRC16_ENABLE must be enabled. + #endif + #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < (127*7) + #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than (127*7). + #endif #endif -} /* * Read received message from CAN module. @@ -64,1415 +53,1503 @@ static void CO_SDO_receive_done(CO_SDO_t *SDO){ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_SDO_receive(void *object, void *msg); -static void CO_SDO_receive(void *object, void *msg){ - CO_SDO_t *SDO; - uint8_t rcv, *CANrxData; +static void CO_SDO_receive(void *object, void *msg) { + CO_SDOserver_t *SDO = (CO_SDOserver_t *)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); - SDO = (CO_SDO_t*)object; /* this is the correct pointer type of the first argument */ - rcv = SDO->CANrxRcv; - CANrxData = SDO->CANrxData[rcv]; - /* verify message length and message queue overflow (if previous messages were not processed yet) */ - if((DLC == 8U) && (!CO_FLAG_READ(SDO->CANrxNew[rcv]))){ - if(SDO->state != CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) { - /* copy data and set 'new message' flag */ - memcpy(CANrxData, data, DLC); - CO_SDO_receive_done(SDO); + /* verify message length and message queue overflow (if previous message + * was not processed yet) */ + if (DLC == 8 && !CO_FLAG_READ(SDO->CANrxNew)) { + if (data[0] == 0x80) { + /* abort from client, just make idle */ + SDO->state = CO_SDO_ST_IDLE; } - else { - /* block download, copy data directly */ - uint8_t seqno; - - CANrxData[0] = data[0]; - seqno = CANrxData[0] & 0x7fU; - SDO->timeoutTimer = 0; - /* clear timeout in sub-block transfer indication if set before */ - if (SDO->timeoutSubblockDownolad) { - SDO->timeoutSubblockDownolad = false; - } - - /* check correct sequence number. */ - if(seqno == (SDO->sequence + 1U)) { - /* sequence is correct */ - - /* check if buffer can store whole message just in case */ - if (CO_CONFIG_SDO_BUFFER_SIZE - SDO->bufferOffset >= 7) { - uint8_t i; - - SDO->sequence++; - - /* copy data */ - for(i=1; i<8; i++) { - SDO->ODF_arg.data[SDO->bufferOffset++] = data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + else if (SDO->state == CO_SDO_ST_UPLOAD_BLK_END_CRSP && data[0]==0xA1) { + /* SDO block download successfully transferred, just make idle */ + SDO->state = CO_SDO_ST_IDLE; + } + else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { + /* just in case, condition should always pass */ + if (SDO->bufOffsetWr <= (CO_CONFIG_SDO_SRV_BUFFER_SIZE - 7)) { + /* block download, copy data directly */ + uint8_t seqno; + CO_SDO_state_t state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; + + seqno = data[0] & 0x7F; + SDO->timeoutTimer = 0; + SDO->block_timeoutTimer = 0; + + /* break sub-block if sequence number is too large */ + if (seqno > SDO->block_blksize) { + state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; + } + /* verify if sequence number is correct */ + else if (seqno == (SDO->block_seqno + 1)) { + SDO->block_seqno = seqno; + + /* Copy data. There is always enough space in buffer, + * because block_blksize was calculated before */ + memcpy(SDO->buf + SDO->bufOffsetWr, &data[1], 7); + SDO->bufOffsetWr += 7; + SDO->sizeTran += 7; + + /* is this the last segment? */ + if ((data[0] & 0x80) != 0) { + SDO->finished = true; + state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; + } + else if (seqno == SDO->block_blksize) { + /* all segments in sub-block has been transferred */ + state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; } + } + else if (seqno == SDO->block_seqno || SDO->block_seqno == 0U) { + /* Ignore message, if it is duplicate or if sequence didn't + * start yet. */ + } + else { + /* seqno is totally wrong, break sub-block. Data after last + * good seqno will be re-transmitted. */ + state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; + } - /* break reception if last segment, block ends or block sequence is too large */ - if(((CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) { - SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP; - CO_SDO_receive_done(SDO); + if (state != CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { + /* SDO->state has changed, processing will continue in + * another thread. Make memory barrier here with + * CO_FLAG_CLEAR() call. */ + CO_FLAG_CLEAR(SDO->CANrxNew); + SDO->state = state; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which + * handles SDO server processing. */ + if (SDO->pFunctSignalPre != NULL) { + SDO->pFunctSignalPre(SDO->functSignalObjectPre); } - } else { - /* buffer is full, ignore this segment, send response without resetting sequence */ - SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2; - CO_SDO_receive_done(SDO); +#endif } } - else if((seqno == SDO->sequence) || (SDO->sequence == 0U)) { - /* Ignore message, if it is duplicate or if sequence didn't started yet. */ - } - else { - /* seqno is wrong, send response without resetting sequence */ - SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2; - CO_SDO_receive_done(SDO); - } - } - -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles SDO server. */ - if(CO_FLAG_READ(SDO->CANrxNew[rcv]) && SDO->pFunctSignalPre != NULL) { - SDO->pFunctSignalPre(SDO->functSignalObjectPre); } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ + else { + /* copy data and set 'new message' flag, data will be processed in + * CO_SDOserver_process() */ + memcpy(SDO->CANrxData, data, DLC); + CO_FLAG_SET(SDO->CANrxNew); +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles + * SDO server processing. */ + if (SDO->pFunctSignalPre != NULL) { + SDO->pFunctSignalPre(SDO->functSignalObjectPre); + } #endif + } } } /* - * Function for accessing _SDO server parameter_ for default SDO (index 0x1200) - * from SDO server. + * Custom function for reading OD variable _SDO server parameter_, default + * channel * - * For more information see file CO_SDOserver.h. + * For more information see file CO_ODinterface.h, OD_subEntry_t. */ -static CO_SDO_abortCode_t CO_ODF_1200(CO_ODF_arg_t *ODF_arg); -static CO_SDO_abortCode_t CO_ODF_1200(CO_ODF_arg_t *ODF_arg){ - uint8_t *nodeId; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - nodeId = (uint8_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - /* if SDO reading Object dictionary 0x1200, add nodeId to the value */ - if((ODF_arg->reading) && (ODF_arg->subIndex > 0U)){ - CO_setUint32(ODF_arg->data, value + *nodeId); +static OD_size_t OD_read_1200_default(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, + ODR_t *returnCode) +{ + if (stream == NULL || buf == NULL || returnCode == NULL + || count < 1 || (count < 4 && subIndex > 0) + ) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; } - return ret; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_SDO_init( - CO_SDO_t *SDO, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient, - uint16_t ObjDictIndex_SDOServerParameter, - CO_SDO_t *parentSDO, - const CO_OD_entry_t OD[], - uint16_t ODSize, - CO_OD_extension_t *ODExtensions, - uint8_t nodeId, - uint16_t SDOtimeoutTime_ms, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx) -{ - CO_ReturnError_t ret = CO_ERROR_NO; + CO_SDOserver_t *SDO = (CO_SDOserver_t *)stream->object; + *returnCode = ODR_OK; - /* verify arguments */ - if(SDO==NULL || CANdevRx==NULL || CANdevTx==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } + switch (subIndex) { + case 0: /* Highest sub-index supported */ + CO_setUint8(buf, 2); + return stream->dataLength = sizeof(uint8_t); - /* configure own object dictionary */ - if(parentSDO == NULL){ - uint16_t i; + case 1: /* COB-ID client -> server */ + CO_setUint32(buf, CO_CAN_ID_SDO_CLI + SDO->nodeId); + return stream->dataLength = sizeof(uint32_t); - SDO->ownOD = true; - SDO->OD = OD; - SDO->ODSize = ODSize; - SDO->ODExtensions = ODExtensions; + case 2: /* COB-ID server -> client */ + CO_setUint32(buf, CO_CAN_ID_SDO_SRV + SDO->nodeId); + return stream->dataLength = sizeof(uint32_t); - /* clear pointers in ODExtensions */ - for(i=0U; iODExtensions[i].pODFunc = NULL; - SDO->ODExtensions[i].object = NULL; - SDO->ODExtensions[i].flags = NULL; - } - } - /* copy object dictionary from parent */ - else{ - SDO->ownOD = false; - SDO->OD = parentSDO->OD; - SDO->ODSize = parentSDO->ODSize; - SDO->ODExtensions = parentSDO->ODExtensions; + default: + *returnCode = ODR_SUB_NOT_EXIST; + return 0; } +} - /* Configure object variables */ - SDO->nodeId = nodeId; - SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; - SDO->state = CO_SDO_ST_IDLE; - uint8_t i; - for(i=0U; iCANrxNew[i]); +/* helper for configuring CANrx and CANtx *************************************/ +static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + uint16_t CANdevTxIdx, + uint32_t COB_IDClientToServer, + uint32_t COB_IDServerToClient) +{ +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC + /* proceed only, if parameters change */ + if (COB_IDClientToServer == SDO->COB_IDClientToServer + && COB_IDServerToClient == SDO->COB_IDServerToClient + ) { + return CO_ERROR_NO; } - SDO->CANrxRcv = 0; - SDO->CANrxProc = 0; - -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE - SDO->pFunctSignalPre = NULL; - SDO->functSignalObjectPre = NULL; + /* store variables */ + SDO->COB_IDClientToServer = COB_IDClientToServer; + SDO->COB_IDServerToClient = COB_IDServerToClient; #endif - /* Configure Object dictionary entry at index 0x1200 */ - if(ObjDictIndex_SDOServerParameter == OD_H1200_SDO_SERVER_PARAM){ - CO_OD_configure(SDO, ObjDictIndex_SDOServerParameter, CO_ODF_1200, (void*)&SDO->nodeId, 0U, 0U); + /* verify valid bit */ + uint16_t idC2S = ((COB_IDClientToServer & 0x80000000L) == 0) ? + (uint16_t)COB_IDClientToServer : 0; + uint16_t idS2C = ((COB_IDServerToClient & 0x80000000L) == 0) ? + (uint16_t)COB_IDServerToClient : 0; + if (idC2S != 0 && idS2C != 0) { + SDO->valid = true; } - - if((COB_IDClientToServer & 0x80000000) != 0 || (COB_IDServerToClient & 0x80000000) != 0 ){ - // SDO is invalid - COB_IDClientToServer = 0; - COB_IDServerToClient = 0; + else { + idC2S = 0; + idS2C = 0; + SDO->valid = false; } + /* configure SDO server CAN reception */ - ret = CO_CANrxBufferInit( + CO_ReturnError_t ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ - COB_IDClientToServer, /* CAN identifier */ + idC2S, /* CAN identifier */ 0x7FF, /* mask */ 0, /* rtr */ (void*)SDO, /* object passed to receive function */ - CO_SDO_receive); /* this function will process received message */ + CO_SDO_receive); /* this function will process rx msg */ /* configure SDO server CAN transmission */ - SDO->CANdevTx = CANdevTx; SDO->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - COB_IDServerToClient, /* CAN identifier */ + SDO->CANdevTx, /* CAN device */ + CANdevTxIdx, /* index of buffer inside CAN module */ + idS2C, /* CAN identifier */ 0, /* rtr */ 8, /* number of data bytes */ 0); /* synchronous message flag bit */ if (SDO->CANtxBuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; + SDO->valid = false; } return ret; } -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE -/******************************************************************************/ -void CO_SDO_initCallbackPre( - CO_SDO_t *SDO, - void *object, - void (*pFunctSignalPre)(void *object)) +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC +/* + * Custom function for writing OD variable _SDO server parameter_, additional + * channels + * + * For more information see file CO_ODinterface.h, OD_subEntry_t. + */ +static OD_size_t OD_write_1201_additional(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) { - if(SDO != NULL){ - SDO->functSignalObjectPre = object; - SDO->pFunctSignalPre = pFunctSignalPre; + /* "count" is already verified in *_init() function */ + if (stream == NULL || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; } -} -#endif + CO_SDOserver_t *SDO = (CO_SDOserver_t *)stream->object; + *returnCode = ODR_OK; + uint32_t COB_ID; + uint8_t nodeId; -/******************************************************************************/ -void CO_OD_configure( - CO_SDO_t *SDO, - uint16_t index, - CO_SDO_abortCode_t (*pODFunc)(CO_ODF_arg_t *ODF_arg), - void *object, - uint8_t *flags, - uint8_t flagsSize) -{ - uint16_t entryNo; - - entryNo = CO_OD_find(SDO, index); - if(entryNo < 0xFFFFU){ - CO_OD_extension_t *ext = &SDO->ODExtensions[entryNo]; - uint8_t maxSubIndex = SDO->OD[entryNo].maxSubIndex; - - ext->pODFunc = pODFunc; - ext->object = object; - if((flags != NULL) && (flagsSize != 0U) && (flagsSize == maxSubIndex)){ - uint16_t i; - ext->flags = flags; - for(i=0U; i<=maxSubIndex; i++){ - ext->flags[i] = 0U; - } - } - else{ - ext->flags = NULL; - } - } -} + switch (subIndex) { + case 0: /* Highest sub-index supported */ + *returnCode = ODR_READONLY; + return 0; + case 1: /* COB-ID client -> server */ + COB_ID = CO_getUint32(buf); -/******************************************************************************/ -uint16_t CO_OD_find(CO_SDO_t *SDO, uint16_t index){ - /* Fast search in ordered Object Dictionary. If indexes are mixed, this won't work. */ - /* If Object Dictionary has up to 2^N entries, then N is max number of loop passes. */ - uint16_t cur, min, max; - const CO_OD_entry_t* object; - - min = 0U; - max = SDO->ODSize - 1U; - while(min < max){ - cur = (min + max) / 2; - object = &SDO->OD[cur]; - /* Is object matched */ - if(index == object->index){ - return cur; - } - if(index < object->index){ - max = cur; - if(max) max--; - } - else - min = cur + 1U; - } - - if(min == max){ - object = &SDO->OD[min]; - /* Is object matched */ - if(index == object->index){ - return min; - } - } + /* SDO client must not be valid when changing COB_ID */ + if ((COB_ID & 0x3FFFF800) != 0 + || ((uint16_t)COB_ID != (uint16_t)SDO->COB_IDClientToServer + && SDO->valid && (COB_ID & 0x80000000)) + ) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + CO_SDOserver_init_canRxTx(SDO, + SDO->CANdevRx, + SDO->CANdevRxIdx, + SDO->CANdevTxIdx, + COB_ID, + SDO->COB_IDServerToClient); + break; - return 0xFFFFU; /* object does not exist in OD */ -} + case 2: /* COB-ID server -> client */ + COB_ID = CO_getUint32(buf); + /* SDO client must not be valid when changing COB_ID */ + if ((COB_ID & 0x3FFFF800) != 0 + || ((uint16_t)COB_ID != (uint16_t)SDO->COB_IDServerToClient + && SDO->valid && (COB_ID & 0x80000000)) + ) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + CO_SDOserver_init_canRxTx(SDO, + SDO->CANdevRx, + SDO->CANdevRxIdx, + SDO->CANdevTxIdx, + SDO->COB_IDClientToServer, + COB_ID); + break; -/******************************************************************************/ -uint16_t CO_OD_getLength(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ - const CO_OD_entry_t* object = &SDO->OD[entryNo]; + case 3: /* Node-ID of the SDO server */ + if (count != 1) { + *returnCode = ODR_TYPE_MISMATCH; + return 0; + } + nodeId = CO_getUint8(buf); + if (nodeId < 1 || nodeId > 127) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + break; - if(entryNo == 0xFFFFU){ - return 0U; + default: + *returnCode = ODR_SUB_NOT_EXIST; + return 0; } - if(object->maxSubIndex == 0U){ /* Object type is Var */ - if(object->pData == 0){ /* data type is domain */ - return CO_CONFIG_SDO_BUFFER_SIZE; - } - else{ - return object->length; - } - } - else if(object->attribute != 0U){ /* Object type is Array */ - if(subIndex == 0U){ - return 1U; - } - else if(object->pData == 0){ - /* data type is domain */ - return CO_CONFIG_SDO_BUFFER_SIZE; - } - else{ - return object->length; - } - } - else{ /* Object type is Record */ - if(((const CO_OD_entryRecord_t*)(object->pData))[subIndex].pData == 0){ - /* data type is domain */ - return CO_CONFIG_SDO_BUFFER_SIZE; - } - else{ - return ((const CO_OD_entryRecord_t*)(object->pData))[subIndex].length; - } - } + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC */ /******************************************************************************/ -uint16_t CO_OD_getAttribute(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ - const CO_OD_entry_t* object = &SDO->OD[entryNo]; - - if(entryNo == 0xFFFFU){ - return 0U; +CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, + const OD_t *OD, + const OD_entry_t *OD_1200_SDOsrvPar, + uint8_t nodeId, + uint16_t SDOtimeoutTime_ms, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx) +{ + /* verify arguments */ + if (SDO == NULL || OD == NULL || CANdevRx == NULL || CANdevTx == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; } - if(object->maxSubIndex == 0U){ /* Object type is Var */ - return object->attribute; - } - else if(object->attribute != 0U){/* Object type is Array */ - bool_t exception_1003 = false; - uint16_t attr = object->attribute; - - /* Special exception: Object 1003,00 should be writable */ - if(object->index == 0x1003 && subIndex == 0) { - exception_1003 = true; - attr |= CO_ODA_WRITEABLE; - } + /* Configure object variables */ + SDO->OD = OD; + SDO->nodeId = nodeId; + SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; + SDO->state = CO_SDO_ST_IDLE; - if(subIndex == 0U && !exception_1003){ - /* First subIndex is readonly */ - attr &= ~(CO_ODA_WRITEABLE | CO_ODA_RPDO_MAPABLE); - attr |= CO_ODA_READABLE; - } - return attr; - } - else{ /* Object type is Record */ - return ((const CO_OD_entryRecord_t*)(object->pData))[subIndex].attribute; - } -} +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE + SDO->pFunctSignalPre = NULL; + SDO->functSignalObjectPre = NULL; +#endif + /* configure CAN identifiers and SDO server parameters if available */ + uint16_t CanId_ClientToServer, CanId_ServerToClient; -/******************************************************************************/ -void* CO_OD_getDataPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ - const CO_OD_entry_t* object = &SDO->OD[entryNo]; + if (OD_1200_SDOsrvPar == NULL) { + /* configure default SDO channel */ + if (nodeId < 1 || nodeId > 127) return CO_ERROR_ILLEGAL_ARGUMENT; - if(entryNo == 0xFFFFU){ - return 0; + CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; + CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; + SDO->valid = true; } - - if(object->maxSubIndex == 0U){ /* Object type is Var */ - return object->pData; + else if (OD_getIndex(OD_1200_SDOsrvPar) == OD_H1200_SDO_SERVER_1_PARAM) { + /* configure default SDO channel and SDO server parameters for it */ + if (nodeId < 1 || nodeId > 127) return CO_ERROR_ILLEGAL_ARGUMENT; + + CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; + CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; + SDO->valid = true; + if (!OD_extensionIO_init(OD_1200_SDOsrvPar, + (void *) SDO, + OD_read_1200_default, + NULL)) { + return CO_ERROR_OD_PARAMETERS; } - else if(object->maxSubIndex < subIndex){ - /* Object type Array/Record, request is out of bounds */ - return 0; } - else if(object->attribute != 0U){/* Object type is Array */ - if(subIndex==0){ - /* this is the data, for the subIndex 0 in the array */ - return (void*) &object->maxSubIndex; + else if (OD_getIndex(OD_1200_SDOsrvPar) > OD_H1200_SDO_SERVER_1_PARAM + && OD_getIndex(OD_1200_SDOsrvPar) <= (OD_H1200_SDO_SERVER_1_PARAM+0x7F) + ) { + /* configure additional SDO channel and SDO server parameters for it */ + uint8_t maxSubIndex; + uint32_t COB_IDClientToServer32, COB_IDServerToClient32; + + /* get and verify parameters from Object Dictionary (initial values) */ + ODR_t odRet0 = OD_get_u8(OD_1200_SDOsrvPar, 0, &maxSubIndex, true); + ODR_t odRet1 = OD_get_u32(OD_1200_SDOsrvPar, 1, + &COB_IDClientToServer32, true); + ODR_t odRet2 = OD_get_u32(OD_1200_SDOsrvPar, 2, + &COB_IDServerToClient32, true); + + if (odRet0 != ODR_OK || (maxSubIndex != 2 && maxSubIndex != 3) + || odRet1 != ODR_OK || odRet2 != ODR_OK + ) { + return CO_ERROR_OD_PARAMETERS; } - else if(object->pData == 0){ - /* data type is domain */ - return 0; - } - else{ - return (void*)(((int8_t*)object->pData) + ((subIndex-1) * object->length)); - } - } - else{ /* Object Type is Record */ - return ((const CO_OD_entryRecord_t*)(object->pData))[subIndex].pData; - } -} - - -/******************************************************************************/ -uint8_t* CO_OD_getFlagsPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){ - if(entryNo == 0xFFFF || SDO->ODExtensions == NULL){ - return NULL; - } - - CO_OD_extension_t* ext = &SDO->ODExtensions[entryNo]; - if (ext->flags == NULL){ - return NULL; - } - - return &ext->flags[subIndex]; -} - - -/******************************************************************************/ -uint32_t CO_SDO_initTransfer(CO_SDO_t *SDO, uint16_t index, uint8_t subIndex){ - - SDO->ODF_arg.index = index; - SDO->ODF_arg.subIndex = subIndex; - - /* find object in Object Dictionary */ - SDO->entryNo = CO_OD_find(SDO, index); - if(SDO->entryNo == 0xFFFFU){ - return CO_SDO_AB_NOT_EXIST ; /* object does not exist in OD */ - } - - /* verify existance of subIndex */ - if(subIndex > SDO->OD[SDO->entryNo].maxSubIndex && - SDO->OD[SDO->entryNo].pData != NULL) - { - return CO_SDO_AB_SUB_UNKNOWN; /* Sub-index does not exist. */ - } - - /* pointer to data in Object dictionary */ - SDO->ODF_arg.ODdataStorage = CO_OD_getDataPointer(SDO, SDO->entryNo, subIndex); - - /* fill ODF_arg */ - SDO->ODF_arg.object = NULL; - if(SDO->ODExtensions){ - CO_OD_extension_t *ext = &SDO->ODExtensions[SDO->entryNo]; - SDO->ODF_arg.object = ext->object; - } - SDO->ODF_arg.data = SDO->databuffer; - SDO->ODF_arg.dataLength = CO_OD_getLength(SDO, SDO->entryNo, subIndex); - SDO->ODF_arg.attribute = CO_OD_getAttribute(SDO, SDO->entryNo, subIndex); - SDO->ODF_arg.pFlags = CO_OD_getFlagsPointer(SDO, SDO->entryNo, subIndex); - - SDO->ODF_arg.firstSegment = true; - SDO->ODF_arg.lastSegment = true; - - /* indicate total data length, if not domain */ - SDO->ODF_arg.dataLengthTotal = (SDO->ODF_arg.ODdataStorage) ? SDO->ODF_arg.dataLength : 0U; - - SDO->ODF_arg.offset = 0U; - - /* verify length */ - if(SDO->ODF_arg.dataLength > CO_CONFIG_SDO_BUFFER_SIZE){ - return CO_SDO_AB_DEVICE_INCOMPAT; /* general internal incompatibility in the device */ - } - - return 0U; -} - -/******************************************************************************/ -uint32_t CO_SDO_readOD(CO_SDO_t *SDO, uint16_t SDOBufferSize){ - uint8_t *SDObuffer = SDO->ODF_arg.data; - uint8_t *ODdata = (uint8_t*)SDO->ODF_arg.ODdataStorage; - uint16_t length = SDO->ODF_arg.dataLength; - CO_OD_extension_t *ext = NULL; - - /* is object readable? */ - if((SDO->ODF_arg.attribute & CO_ODA_READABLE) == 0) - return CO_SDO_AB_WRITEONLY; /* attempt to read a write-only object */ - - /* find extension */ - if(SDO->ODExtensions != NULL){ - ext = &SDO->ODExtensions[SDO->entryNo]; - } - CO_LOCK_OD(); + CanId_ClientToServer = ((COB_IDClientToServer32 & 0x80000000) == 0) + ? (uint16_t)(COB_IDClientToServer32 & 0x7FF) : 0; + CanId_ServerToClient = ((COB_IDServerToClient32 & 0x80000000) == 0) + ? (uint16_t)(COB_IDServerToClient32 & 0x7FF) : 0; - /* copy data from OD to SDO buffer if not domain */ - if(ODdata != NULL){ - while(length--) *(SDObuffer++) = *(ODdata++); +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC + if (!OD_extensionIO_init(OD_1200_SDOsrvPar, + (void *) SDO, + OD_readOriginal, + OD_write_1201_additional)) { + return CO_ERROR_OD_PARAMETERS; } - /* if domain, Object dictionary function MUST exist */ - else{ - if(ext && ext->pODFunc == NULL){ - CO_UNLOCK_OD(); - return CO_SDO_AB_DEVICE_INCOMPAT; /* general internal incompatibility in the device */ - } +#endif } - - /* call Object dictionary function if registered */ - SDO->ODF_arg.reading = true; - if(ext && ext->pODFunc != NULL){ - uint32_t abortCode = ext->pODFunc(&SDO->ODF_arg); - if(abortCode != 0U){ - CO_UNLOCK_OD(); - return abortCode; - } - - /* dataLength (upadted by pODFunc) must be inside limits */ - if((SDO->ODF_arg.dataLength == 0U) || (SDO->ODF_arg.dataLength > SDOBufferSize)){ - CO_UNLOCK_OD(); - return CO_SDO_AB_DEVICE_INCOMPAT; /* general internal incompatibility in the device */ - } + else { + return CO_ERROR_ILLEGAL_ARGUMENT; } - CO_UNLOCK_OD(); - - SDO->ODF_arg.offset += SDO->ODF_arg.dataLength; - SDO->ODF_arg.firstSegment = false; + CO_FLAG_CLEAR(SDO->CANrxNew); - /* swap data if processor is not little endian (CANopen is) */ -#ifdef CO_BIG_ENDIAN - if((SDO->ODF_arg.attribute & CO_ODA_MB_VALUE) != 0){ - uint16_t len = SDO->ODF_arg.dataLength; - uint8_t *buf1 = SDO->ODF_arg.data; - uint8_t *buf2 = buf1 + len - 1; - - len /= 2; - while(len--){ - uint8_t b = *buf1; - *(buf1++) = *buf2; - *(buf2--) = b; - } - } + /* store the parameters and configure CANrx and CANtx */ +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC + SDO->CANdevRx = CANdevRx; + SDO->CANdevRxIdx = CANdevRxIdx; + SDO->CANdevTxIdx = CANdevTxIdx; + /* set to zero to make sure CO_SDOserver_init_canRxTx() will reconfig CAN */ + SDO->COB_IDClientToServer = 0; + SDO->COB_IDServerToClient = 0; #endif + SDO->CANdevTx = CANdevTx; - return 0U; + return CO_SDOserver_init_canRxTx(SDO, + CANdevRx, + CANdevRxIdx, + CANdevTxIdx, + CanId_ClientToServer, + CanId_ServerToClient); } +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE /******************************************************************************/ -uint32_t CO_SDO_writeOD(CO_SDO_t *SDO, uint16_t length){ - uint8_t *SDObuffer = SDO->ODF_arg.data; - uint8_t *ODdata = (uint8_t*)SDO->ODF_arg.ODdataStorage; - bool_t exception_1003 = false; - - /* is object writeable? */ - if((SDO->ODF_arg.attribute & CO_ODA_WRITEABLE) == 0){ - return CO_SDO_AB_READONLY; /* attempt to write a read-only object */ - } - - /* length of domain data is application specific and not verified */ - if(ODdata == 0){ - SDO->ODF_arg.dataLength = length; - } - - /* verify length except for domain data type */ - else if(SDO->ODF_arg.dataLength != length){ - return CO_SDO_AB_TYPE_MISMATCH; /* Length of service parameter does not match */ - } - - /* swap data if processor is not little endian (CANopen is) */ -#ifdef CO_BIG_ENDIAN - if((SDO->ODF_arg.attribute & CO_ODA_MB_VALUE) != 0){ - uint16_t len = SDO->ODF_arg.dataLength; - uint8_t *buf1 = SDO->ODF_arg.data; - uint8_t *buf2 = buf1 + len - 1; - - len /= 2; - while(len--){ - uint8_t b = *buf1; - *(buf1++) = *buf2; - *(buf2--) = b; - } +void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, + void *object, + void (*pFunctSignalPre)(void *object)) +{ + if (SDO != NULL) { + SDO->functSignalObjectPre = object; + SDO->pFunctSignalPre = pFunctSignalPre; } +} #endif - CO_LOCK_OD(); - /* call Object dictionary function if registered */ - SDO->ODF_arg.reading = false; - if(SDO->ODExtensions != NULL){ - CO_OD_extension_t *ext = &SDO->ODExtensions[SDO->entryNo]; - - if(ext->pODFunc != NULL){ - uint32_t abortCode = ext->pODFunc(&SDO->ODF_arg); - if(abortCode != 0U){ - CO_UNLOCK_OD(); - return abortCode; - } - } - } - SDO->ODF_arg.offset += SDO->ODF_arg.dataLength; - SDO->ODF_arg.firstSegment = false; - - /* Special exception: 1003,00 is writable from network, but not in OD */ - if(SDO->ODF_arg.index == 0x1003 && SDO->ODF_arg.subIndex == 0) { - exception_1003 = true; - } - - /* copy data from SDO buffer to OD if not domain */ - if((ODdata != NULL) && !exception_1003){ - while(length--){ - *(ODdata++) = *(SDObuffer++); - } +#ifdef CO_BIG_ENDIAN +static inline void reverseBytes(void *start, int size) { + unsigned char *lo = start; + unsigned char *hi = start + size - 1; + unsigned char swap; + while (lo < hi) { + swap = *lo; + *lo++ = *hi; + *hi-- = swap; } - - CO_UNLOCK_OD(); - - return 0; } - -/******************************************************************************/ -static void CO_SDO_process_done(CO_SDO_t *SDO, uint32_t *timerNext_us) { - (void)timerNext_us; /* may be unused */ - -#if CO_SDO_RX_DATA_SIZE > 1 - uint8_t proc = SDO->CANrxProc; - uint8_t newProc = proc; - - /* check if buffer needs to be free */ - if (!CO_FLAG_READ(SDO->CANrxNew[proc])) { - return; - } - - if (++newProc >= CO_SDO_RX_DATA_SIZE) - newProc = 0; - - SDO->CANrxProc = newProc; - CO_FLAG_CLEAR(SDO->CANrxNew[proc]); - -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - if ((timerNext_us != NULL) && (CO_FLAG_READ(SDO->CANrxNew[newProc]))) - timerNext_us = 0; /* Set timerNext_us to 0 to inform OS to call CO_SDO_process function again without delay. */ -#endif -#else - CO_FLAG_CLEAR(SDO->CANrxNew[0]); #endif -} - -/******************************************************************************/ -static void CO_SDO_abort(CO_SDO_t *SDO, uint32_t code){ - SDO->CANtxBuff->data[0] = 0x80; - SDO->CANtxBuff->data[1] = SDO->ODF_arg.index & 0xFF; - SDO->CANtxBuff->data[2] = (SDO->ODF_arg.index>>8) & 0xFF; - SDO->CANtxBuff->data[3] = SDO->ODF_arg.subIndex; - CO_memcpySwap4(&SDO->CANtxBuff->data[4], &code); - SDO->state = CO_SDO_ST_IDLE; - /* skip all received messages in queue if any */ - while (CO_FLAG_READ(SDO->CANrxNew[SDO->CANrxProc])) - CO_SDO_process_done(SDO, NULL); - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); -} /******************************************************************************/ -int8_t CO_SDO_process( - CO_SDO_t *SDO, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us) +CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, + bool_t NMTisPreOrOperational, + uint32_t timeDifference_us, + uint32_t *timerNext_us) { - CO_SDO_state_t state = CO_SDO_ST_IDLE; - bool_t sendResponse = false; - uint8_t proc, *CANrxData; - bool_t isNew; + (void)timerNext_us; /* may be unused */ - proc = SDO->CANrxProc; - isNew = CO_FLAG_READ(SDO->CANrxNew[proc]); + CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; + CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; + bool_t isNew = CO_FLAG_READ(SDO->CANrxNew); - /* return if idle */ - if((SDO->state == CO_SDO_ST_IDLE) && (!isNew)){ - return 0; - } - /* SDO is allowed to work only in operational or pre-operational NMT state */ - if(!NMTisPreOrOperational){ + if (SDO == NULL) { + ret = CO_SDO_RT_wrongArguments; + } + else if (SDO->valid && SDO->state == CO_SDO_ST_IDLE && !isNew) { + /* Idle and nothing new */ + ret = CO_SDO_RT_ok_communicationEnd; + } + else if (!NMTisPreOrOperational || !SDO->valid) { + /* SDO is allowed only in operational or pre-operational NMT state + * and must be valid */ SDO->state = CO_SDO_ST_IDLE; - /* free receive buffer if it is not empty */ - CO_SDO_process_done(SDO, timerNext_us); - return 0; + CO_FLAG_CLEAR(SDO->CANrxNew); + ret = CO_SDO_RT_ok_communicationEnd; } + /* CAN data received ******************************************************/ + else if (isNew) { + if (SDO->state == CO_SDO_ST_IDLE) { /* new SDO communication? */ + bool_t upload = false; - CANrxData = SDO->CANrxData[proc]; - - /* Is something new to process? */ - if((!SDO->CANtxBuff->bufferFull) && (isNew || (SDO->state == CO_SDO_ST_UPLOAD_BL_SUBBLOCK))){ - /* reset timeout */ - if(SDO->state != CO_SDO_ST_UPLOAD_BL_SUBBLOCK) { - SDO->timeoutTimer = 0; - timeDifference_us = 0; - } - - /* clear response buffer */ - memset(SDO->CANtxBuff->data, 0, sizeof(SDO->CANtxBuff->data)); - - /* Is abort from client? */ - if(isNew && (CANrxData[0] == CCS_ABORT)){ - SDO->state = CO_SDO_ST_IDLE; - CO_SDO_process_done(SDO, timerNext_us); - return -1; - } - - /* continue with previous SDO communication or start new */ - if(SDO->state != CO_SDO_ST_IDLE){ - state = SDO->state; - } - else{ - uint32_t abortCode; - uint16_t index; - uint8_t CCS = CANrxData[0] >> 5; /* Client command specifier */ - - /* Is client command specifier valid */ - if((CCS != CCS_DOWNLOAD_INITIATE) && (CCS != CCS_UPLOAD_INITIATE) && - (CCS != CCS_DOWNLOAD_BLOCK) && (CCS != CCS_UPLOAD_BLOCK)){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; + if ((SDO->CANrxData[0] & 0xF0) == 0x20) { + SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; } - - /* init ODF_arg */ - index = CANrxData[2]; - index = index << 8 | CANrxData[1]; - abortCode = CO_SDO_initTransfer(SDO, index, CANrxData[3]); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; + else if (SDO->CANrxData[0] == 0x40) { + upload = true; + SDO->state = CO_SDO_ST_UPLOAD_INITIATE_REQ; + } +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + else if ((SDO->CANrxData[0] & 0xF9) == 0xC0) { + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ; + } + else if ((SDO->CANrxData[0] & 0xFB) == 0xA0) { + upload = true; + SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ; + } +#endif + else { + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; } - /* download */ - if((CCS == CCS_DOWNLOAD_INITIATE) || (CCS == CCS_DOWNLOAD_BLOCK)){ - if((SDO->ODF_arg.attribute & CO_ODA_WRITEABLE) == 0U){ - CO_SDO_abort(SDO, CO_SDO_AB_READONLY); /* attempt to write a read-only object */ - return -1; - } - - /* set state machine to normal or block download */ - if(CCS == CCS_DOWNLOAD_INITIATE){ - state = CO_SDO_ST_DOWNLOAD_INITIATE; + /* if no error search object dictionary for new SDO request */ + if (abortCode == CO_SDO_AB_NONE) { + ODR_t odRet; + OD_subEntry_t subEntry; + + SDO->index = ((uint16_t)SDO->CANrxData[2]) << 8 + | SDO->CANrxData[1]; + SDO->subIndex = SDO->CANrxData[3]; + odRet = OD_getSub(OD_find(SDO->OD, SDO->index), SDO->subIndex, + &subEntry, &SDO->OD_IO.stream, false); + if (odRet != ODR_OK) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; } - else{ - state = CO_SDO_ST_DOWNLOAD_BL_INITIATE; + else { + SDO->attribute = subEntry.attribute; + SDO->OD_IO.read = subEntry.read; + SDO->OD_IO.write = subEntry.write; + + /* verify read/write attributes */ + if (upload && (SDO->attribute & ODA_SDO_R) == 0) { + abortCode = CO_SDO_AB_WRITEONLY; + SDO->state = CO_SDO_ST_ABORT; + } + else if (!upload && (SDO->attribute & ODA_SDO_W) == 0) { + abortCode = CO_SDO_AB_READONLY; + SDO->state = CO_SDO_ST_ABORT; + } } } - /* upload */ - else{ - abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + /* load data from object dictionary, if upload and no error */ + if (upload && abortCode == CO_SDO_AB_NONE) { + ODR_t odRet; + + /* load data from OD variable into the buffer */ + SDO->bufOffsetWr = SDO->OD_IO.read(&SDO->OD_IO.stream, + SDO->subIndex, + SDO->buf, + CO_CONFIG_SDO_SRV_BUFFER_SIZE, + &odRet); + SDO->bufOffsetRd = 0; + + if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; } - - /* if data size is large enough set state machine to block upload, otherwise set to normal transfer */ - if((CCS == CCS_UPLOAD_BLOCK) && (SDO->ODF_arg.dataLength > CANrxData[5])){ - state = CO_SDO_ST_UPLOAD_BL_INITIATE; + else if (odRet == ODR_PARTIAL && SDO->bufOffsetWr < 7) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; } - else{ - state = CO_SDO_ST_UPLOAD_INITIATE; + else { + SDO->finished = (odRet != ODR_PARTIAL); +#ifdef CO_BIG_ENDIAN + /* swap data if necessary */ + if ((SDO->attribute & ODA_MB) != 0) { + if (!SDO->finished) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; + } + else { + reverseBytes(SDO->buf, SDO->bufOffsetWr); + } + } +#endif } } - } - } - - /* verify SDO timeout */ - if (SDO->timeoutTimer < SDO->SDOtimeoutTime_us) { - SDO->timeoutTimer += timeDifference_us; - } - if (SDO->timeoutTimer >= SDO->SDOtimeoutTime_us) { - if((SDO->state == CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) && (!SDO->timeoutSubblockDownolad) && (!SDO->CANtxBuff->bufferFull)){ - /* set indication timeout in sub-block transfer and reset timeout */ - SDO->timeoutSubblockDownolad = true; - SDO->timeoutTimer = 0; - /* send response without resetting sequence */ - state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2; - } - else{ - CO_SDO_abort(SDO, CO_SDO_AB_TIMEOUT); /* SDO protocol timed out */ - return -1; - } - } -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - else if (timerNext_us != NULL) { - /* check again after timeout time elapsed */ - uint32_t diff = SDO->SDOtimeoutTime_us - SDO->timeoutTimer; - if (*timerNext_us > diff) { - *timerNext_us = diff; - } - } -#endif - - /* return immediately if still idle */ - if(state == CO_SDO_ST_IDLE){ - return 0; - } - - /* state machine (buffer is freed with process_done() at the end) */ - switch(state){ - uint32_t abortCode; - uint16_t len, i; - bool_t lastSegmentInSubblock; - - case CO_SDO_ST_DOWNLOAD_INITIATE:{ - /* default response */ - SDO->CANtxBuff->data[0] = 0x60; - SDO->CANtxBuff->data[1] = CANrxData[1]; - SDO->CANtxBuff->data[2] = CANrxData[2]; - SDO->CANtxBuff->data[3] = CANrxData[3]; - - /* Expedited transfer */ - if((CANrxData[0] & 0x02U) != 0U){ - /* is size indicated? Get message length */ - if((CANrxData[0] & 0x01U) != 0U){ - len = 4U - ((CANrxData[0] >> 2U) & 0x03U); + /* get and verify OD data size, if upload and still no error */ + if (upload && abortCode == CO_SDO_AB_NONE) { + /* Size of variable in OD (may not be known yet) */ + SDO->sizeInd = SDO->OD_IO.stream.dataLength; + SDO->sizeTran = 0; + if (SDO->finished) { + /* OD variable was completely read, so its size is known */ + if (SDO->sizeInd == 0) { + SDO->sizeInd = SDO->bufOffsetWr; + } + else if (SDO->sizeInd != SDO->bufOffsetWr) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; + } } - else{ - len = SDO->ODF_arg.dataLength; + } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + } /* (SDO->state == CO_SDO_ST_IDLE) */ + + if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) + switch (SDO->state) { + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { + if (SDO->CANrxData[0] & 0x02) { + /* Expedited transfer, max 4 bytes of data */ + OD_size_t sizeIndicated = 4; + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + ODR_t odRet; + + /* is size indicated? */ + if (SDO->CANrxData[0] & 0x01) { + sizeIndicated -= (SDO->CANrxData[0] >> 2) & 0x03; + if (sizeInOd > 0 && sizeIndicated != sizeInOd) { + abortCode = (sizeIndicated < sizeInOd) ? + CO_SDO_AB_DATA_SHORT : + CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } } - - /* copy data to SDO buffer */ - SDO->ODF_arg.data[0] = CANrxData[4]; - SDO->ODF_arg.data[1] = CANrxData[5]; - SDO->ODF_arg.data[2] = CANrxData[6]; - SDO->ODF_arg.data[3] = CANrxData[7]; - - /* write data to the Object dictionary */ - abortCode = CO_SDO_writeOD(SDO, len); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; + else { + if (sizeInOd > 4) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + else { + sizeIndicated = sizeInOd; + } } - /* finish the communication and run mainline processing again */ - SDO->state = CO_SDO_ST_IDLE; - sendResponse = true; -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - if (timerNext_us != NULL) - *timerNext_us = 0; + /* swap data if necessary, then copy data */ +#ifdef CO_BIG_ENDIAN + if ((SDO->attribute & ODA_MB) != 0) { + reverseBytes(&SDO->CANrxData[4], sizeIndicated); + } #endif + SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, + &SDO->CANrxData[4], sizeIndicated, &odRet); + if (odRet != ODR_OK) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; + } + else { + SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + SDO->finished = true; +#endif + } } - - /* Segmented transfer */ - else{ - /* verify length if size is indicated */ - if((CANrxData[0]&0x01) != 0){ - uint32_t lenRx; - CO_memcpySwap4(&lenRx, &CANrxData[4]); - SDO->ODF_arg.dataLengthTotal = lenRx; - - /* verify length except for domain data type */ - if((lenRx != SDO->ODF_arg.dataLength) && (SDO->ODF_arg.ODdataStorage != 0)){ - CO_SDO_abort(SDO, CO_SDO_AB_TYPE_MISMATCH); /* Length of service parameter does not match */ - return -1; + else { +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + /* segmented transfer, is size indicated? */ + if (SDO->CANrxData[0] & 0x01) { + uint32_t size; + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + + memcpy(&size, &SDO->CANrxData[4], sizeof(size)); + SDO->sizeInd = CO_SWAP_32(size); + + /* Indicated size of SDO matches sizeof OD variable? */ + if (sizeInOd > 0 && SDO->sizeInd != sizeInOd) { + abortCode = (SDO->sizeInd < sizeInOd) ? + CO_SDO_AB_DATA_SHORT : + CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; } } - SDO->bufferOffset = 0U; - SDO->sequence = 0U; - SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENTED; - sendResponse = true; + else { + SDO->sizeInd = 0; + } + SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; + SDO->finished = false; +#else + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; + SDO->state = CO_SDO_ST_ABORT; +#endif } break; } - case CO_SDO_ST_DOWNLOAD_SEGMENTED:{ - /* verify client command specifier */ - if((CANrxData[0]&0xE0) != 0x00U){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; - } - - /* verify toggle bit */ - i = (CANrxData[0]&0x10U) ? 1U : 0U; - if(i != SDO->sequence){ - CO_SDO_abort(SDO, CO_SDO_AB_TOGGLE_BIT);/* toggle bit not alternated */ - return -1; - } - - /* get size of data in message */ - len = 7U - ((CANrxData[0] >> 1U) & 0x07U); - - /* verify length. Domain data type enables length larger than SDO buffer size */ - if((SDO->bufferOffset + len) > SDO->ODF_arg.dataLength){ - if(SDO->ODF_arg.ODdataStorage != 0){ - CO_SDO_abort(SDO, CO_SDO_AB_DATA_LONG); /* Length of service parameter too high */ - return -1; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { + if ((SDO->CANrxData[0] & 0xE0) == 0x00) { + OD_size_t count; + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + bool_t lastSegment = (SDO->CANrxData[0] & 0x01) != 0; + + /* verify and alternate toggle bit */ + uint8_t toggle = SDO->CANrxData[0] & 0x10; + if (toggle != SDO->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO->state = CO_SDO_ST_ABORT; + break; } - else{ - /* empty buffer in domain data type */ - SDO->ODF_arg.lastSegment = false; - abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; - } - - SDO->ODF_arg.dataLength = CO_CONFIG_SDO_BUFFER_SIZE; - SDO->bufferOffset = 0U; + SDO->toggle = (toggle == 0x00) ? 0x10 : 0x00; + + /* get data size and write data to the buffer */ + count = 7 - ((SDO->CANrxData[0] >> 1) & 0x07); + memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); + SDO->bufOffsetWr += count; + SDO->sizeTran += count; + + /* verify if size of data downloaded is too large */ + if ((SDO->sizeInd > 0 && SDO->sizeTran > SDO->sizeInd) + || (sizeInOd > 0 && SDO->sizeTran > sizeInOd) + ) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; } - } - /* copy data to buffer */ - for(i=0U; iODF_arg.data[SDO->bufferOffset++] = CANrxData[i+1]; - - /* If no more segments to be downloaded, write data to the Object dictionary */ - if((CANrxData[0] & 0x01U) != 0U){ - SDO->ODF_arg.lastSegment = true; - abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; + /* if necessary, empty the buffer */ + if (lastSegment + || (CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr) < 7 + ) { + ODR_t odRet; +#ifdef CO_BIG_ENDIAN + /* swap data if necessary */ + if ((SDO->attribute & ODA_MB) != 0) { + reverseBytes(SDO->buf, SDO->bufOffsetWr); + } +#endif + /* write data */ + SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, + SDO->buf, SDO->bufOffsetWr, &odRet); + SDO->bufOffsetWr = 0; + + if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; + } + else if (lastSegment && odRet == ODR_PARTIAL) { + /* OD variable was not written completelly, but SDO + * download finished */ + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + else if (!lastSegment && odRet == ODR_OK) { + /* OD variable was written completelly, but SDO download + * still has data */ + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } } - /* finish the communication and run mainline processing again */ - SDO->state = CO_SDO_ST_IDLE; -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - if (timerNext_us != NULL) - *timerNext_us = 0; -#endif + /* If no more segments to be downloaded, finish */ + if (lastSegment) { + /* verify size of data */ + if (SDO->sizeInd > 0 && SDO->sizeTran < SDO->sizeInd) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + else { + SDO->finished = true; + } + } + SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; + } + else { + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; } + break; + } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - /* download segment response and alternate toggle bit */ - SDO->CANtxBuff->data[0] = 0x20 | (SDO->sequence ? 0x10 : 0x00); - SDO->sequence = (SDO->sequence) ? 0 : 1; - sendResponse = true; + case CO_SDO_ST_UPLOAD_INITIATE_REQ: { + SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; break; } - case CO_SDO_ST_DOWNLOAD_BL_INITIATE:{ - /* verify client command specifier and subcommand */ - if((CANrxData[0]&0xE1U) != 0xC0U){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { + if ((SDO->CANrxData[0] & 0xEF) == 0x60) { + /* verify and alternate toggle bit */ + uint8_t toggle = SDO->CANrxData[0] & 0x10; + if (toggle != SDO->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; } - - /* prepare response */ - SDO->CANtxBuff->data[0] = 0xA4; - SDO->CANtxBuff->data[1] = CANrxData[1]; - SDO->CANtxBuff->data[2] = CANrxData[2]; - SDO->CANtxBuff->data[3] = CANrxData[3]; - - /* blksize */ - SDO->blksize = (CO_CONFIG_SDO_BUFFER_SIZE > (7*127)) ? 127 : (CO_CONFIG_SDO_BUFFER_SIZE / 7); - SDO->CANtxBuff->data[4] = SDO->blksize; - - /* is CRC enabled */ - SDO->crcEnabled = (CANrxData[0] & 0x04) ? true : false; - SDO->crc = 0; - - /* verify length if size is indicated */ - if((CANrxData[0]&0x02) != 0U){ - uint32_t lenRx; - CO_memcpySwap4(&lenRx, &CANrxData[4]); - SDO->ODF_arg.dataLengthTotal = lenRx; - - /* verify length except for domain data type */ - if((lenRx != SDO->ODF_arg.dataLength) && (SDO->ODF_arg.ODdataStorage != 0)){ - CO_SDO_abort(SDO, CO_SDO_AB_TYPE_MISMATCH); /* Length of service parameter does not match */ - return -1; + else { + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; + } + break; + } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { + SDO->block_crcEnabled = (SDO->CANrxData[0] & 0x04) != 0; + + /* is size indicated? */ + if ((SDO->CANrxData[0] & 0x02) != 0) { + uint32_t size; + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + + memcpy(&size, &SDO->CANrxData[4], sizeof(size)); + SDO->sizeInd = CO_SWAP_32(size); + + /* Indicated size of SDO matches sizeof OD variable? */ + if (sizeInOd > 0 && SDO->sizeInd != sizeInOd) { + abortCode = (SDO->sizeInd < sizeInOd) ? + CO_SDO_AB_DATA_SHORT : + CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; } } - - SDO->bufferOffset = 0U; - SDO->sequence = 0U; - SDO->timeoutSubblockDownolad = false; - SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK; - - /* send response */ - sendResponse = true; + else { + SDO->sizeInd = 0; + } + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; + SDO->finished = false; break; } - case CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK:{ - /* data are copied directly in receive function */ + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { + /* data are copied directly in the receive function */ break; } - case CO_SDO_ST_DOWNLOAD_BL_SUB_RESP: - case CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2:{ - /* check if last segment received */ - lastSegmentInSubblock = (!SDO->timeoutSubblockDownolad && - ((CANrxData[0] & 0x80U) == 0x80U)) ? true : false; - - /* prepare response */ - SDO->CANtxBuff->data[0] = 0xA2; - SDO->CANtxBuff->data[1] = SDO->sequence; - - /* reset sequence on reception break */ - if (state == CO_SDO_ST_DOWNLOAD_BL_SUB_RESP) { - SDO->sequence = 0U; - } - - /* empty buffer in domain data type if not last segment */ - if((SDO->ODF_arg.ODdataStorage == 0) && (SDO->bufferOffset != 0) && !lastSegmentInSubblock){ - /* calculate CRC on next bytes, if enabled */ - if(SDO->crcEnabled){ - SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->bufferOffset, SDO->crc); + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { + if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { + ODR_t odRet; + + /* Get number of data bytes in last segment, that do not + * contain data. Then reduce buffer. */ + uint8_t noData = ((SDO->CANrxData[0] >> 2) & 0x07); + if (SDO->bufOffsetWr <= noData) { + /* just in case, should never happen */ + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + SDO->sizeTran -= noData; + SDO->bufOffsetWr -= noData; + + /* verify length */ + if (SDO->sizeInd > 0 && SDO->sizeTran != SDO->sizeInd) { + abortCode = (SDO->sizeTran > SDO->sizeInd) ? + CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; } - /* write data to the Object dictionary */ - SDO->ODF_arg.lastSegment = false; - abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; +#ifdef CO_BIG_ENDIAN + /* swap data if necessary */ + if ((SDO->attribute & ODA_MB) != 0) { + reverseBytes(SDO->buf, SDO->bufOffsetWr); } +#endif - SDO->ODF_arg.dataLength = CO_CONFIG_SDO_BUFFER_SIZE; - SDO->bufferOffset = 0U; - } + /* calculeate and verify CRC */ + if (SDO->block_crcEnabled) { + uint16_t crcClient; + SDO->block_crc = crc16_ccitt((unsigned char *)SDO->buf, + SDO->bufOffsetWr, + SDO->block_crc); + + crcClient = ((uint16_t) SDO->CANrxData[2]) << 8; + crcClient |= SDO->CANrxData[1]; + if (crcClient != SDO->block_crc) { + abortCode = CO_SDO_AB_CRC; + SDO->state = CO_SDO_ST_ABORT; + break; + } + } - /* blksize */ - len = CO_CONFIG_SDO_BUFFER_SIZE - SDO->bufferOffset; - SDO->blksize = (len > (7*127)) ? 127 : (len / 7); - SDO->CANtxBuff->data[2] = SDO->blksize; + /* write the data */ + SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, + SDO->buf, SDO->bufOffsetWr, &odRet); + SDO->bufOffsetWr = 0; + if (odRet == ODR_PARTIAL) { + /* OD variable was not written completelly, but SDO + * download finished */ + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + else if (odRet != ODR_OK) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; + } - /* set next state */ - if(lastSegmentInSubblock) { - SDO->state = CO_SDO_ST_DOWNLOAD_BL_END; - } - else if(SDO->bufferOffset >= CO_CONFIG_SDO_BUFFER_SIZE) { - CO_SDO_abort(SDO, CO_SDO_AB_DEVICE_INCOMPAT); - return -1; + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; } else { - SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK; + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; } - - /* send response */ - sendResponse = true; - break; } - case CO_SDO_ST_DOWNLOAD_BL_END:{ - /* verify client command specifier and subcommand */ - if((CANrxData[0]&0xE1U) != 0xC1U){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { + /* if pst (protocol switch threshold, byte5) is larger than data + * size of OD variable, then switch to segmented transfer */ + if (SDO->sizeInd > 0 && SDO->CANrxData[5] > 0 + && SDO->CANrxData[5] >= SDO->sizeInd) + { + SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; } + else { + /* data were already loaded from OD variable, verify crc */ + if ((SDO->CANrxData[0] & 0x04) != 0) { + SDO->block_crcEnabled = true; + SDO->block_crc = crc16_ccitt((unsigned char *)SDO->buf, + SDO->bufOffsetWr, + 0); + } + else { + SDO->block_crcEnabled = false; + } - /* number of bytes in the last segment of the last block that do not contain data. */ - len = (CANrxData[0]>>2U) & 0x07U; - SDO->bufferOffset -= len; - - /* calculate and verify CRC, if enabled */ - if(SDO->crcEnabled){ - uint16_t crc; - SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->bufferOffset, SDO->crc); - - CO_memcpySwap2(&crc, &CANrxData[1]); + /* get blksize and verify it */ + SDO->block_blksize = SDO->CANrxData[4]; + if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { + SDO->block_blksize = 127; + } - if(SDO->crc != crc){ - CO_SDO_abort(SDO, CO_SDO_AB_CRC); /* CRC error (block mode only). */ - return -1; + /* verify, if there is enough data */ + if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize*7) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; } + SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; } + break; + } - /* write data to the Object dictionary */ - SDO->ODF_arg.lastSegment = true; - abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { + if (SDO->CANrxData[0] == 0xA3) { + SDO->block_seqno = 0; + SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + } + else { + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; } - - /* finish the communication and run mainline processing again */ - SDO->CANtxBuff->data[0] = 0xA1; - SDO->state = CO_SDO_ST_IDLE; - sendResponse = true; -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - if (timerNext_us != NULL) - *timerNext_us = 0; -#endif break; } - case CO_SDO_ST_UPLOAD_INITIATE:{ - /* default response */ - SDO->CANtxBuff->data[1] = CANrxData[1]; - SDO->CANtxBuff->data[2] = CANrxData[2]; - SDO->CANtxBuff->data[3] = CANrxData[3]; + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { + if (SDO->CANrxData[0] == 0xA2) { + OD_size_t countRemain, countMinimum; - /* Expedited transfer */ - if(SDO->ODF_arg.dataLength <= 4U){ - for(i=0U; iODF_arg.dataLength; i++) - SDO->CANtxBuff->data[4U+i] = SDO->ODF_arg.data[i]; + SDO->block_blksize = SDO->CANrxData[2]; + if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { + SDO->block_blksize = 127; + } + + /* check number of segments */ + if (SDO->CANrxData[1] < SDO->block_seqno) { + /* NOT all segments transferred successfully. + * Re-transmit data after erroneous segment. */ + OD_size_t cntFailed = SDO->block_seqno - SDO->CANrxData[1]; + cntFailed = cntFailed * 7 - SDO->block_noData; + SDO->bufOffsetRd -= cntFailed; + SDO->sizeTran -= cntFailed; + } + else if (SDO->CANrxData[1] > SDO->block_seqno) { + /* something strange from server, break transmission */ + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; + break; + } - SDO->CANtxBuff->data[0] = 0x43U | ((4U-SDO->ODF_arg.dataLength) << 2U); + /* refill data buffer if necessary */ + countRemain = SDO->bufOffsetWr - SDO->bufOffsetRd; + countMinimum = SDO->block_blksize * 7; + if (!SDO->finished && countRemain < countMinimum) { + ODR_t odRet; + OD_size_t countRd; + + /* first move remaining data to the start of the buffer */ + memmove(SDO->buf, SDO->buf + SDO->bufOffsetRd, countRemain); + SDO->bufOffsetRd = 0; + SDO->bufOffsetWr = countRemain; + + /* load data from OD variable into the buffer */ + countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, + SDO->buf + SDO->bufOffsetWr, + CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr, + &odRet); + + countRemain += countRd; + if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; + } + else if (odRet == ODR_PARTIAL) { + SDO->finished = false; + if (countRemain < countMinimum) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + } + else { + SDO->finished = true; + } - /* finish the communication and run mainline processing again */ - SDO->state = CO_SDO_ST_IDLE; - sendResponse = true; -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - if (timerNext_us != NULL) - *timerNext_us = 0; -#endif - } + /* update the crc */ + if (SDO->block_crcEnabled) { + SDO->block_crc = crc16_ccitt( + (unsigned char *)SDO->buf + SDO->bufOffsetWr, + countRd, + SDO->block_crc); + } + SDO->bufOffsetWr = countRemain; + } - /* Segmented transfer */ - else{ - SDO->bufferOffset = 0U; - SDO->sequence = 0U; - SDO->state = CO_SDO_ST_UPLOAD_SEGMENTED; - - /* indicate data size, if known */ - if(SDO->ODF_arg.dataLengthTotal != 0U){ - uint32_t dlentot = SDO->ODF_arg.dataLengthTotal; - CO_memcpySwap4(&SDO->CANtxBuff->data[4], &dlentot); - SDO->CANtxBuff->data[0] = 0x41U; + if (countRemain == 0) { + SDO->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; } - else{ - SDO->CANtxBuff->data[0] = 0x40U; + else { + SDO->block_seqno = 0; + SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; } - - /* send response */ - sendResponse = true; + } + else { + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; } break; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ - case CO_SDO_ST_UPLOAD_SEGMENTED:{ - /* verify client command specifier */ - if((CANrxData[0]&0xE0U) != 0x60U){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; + default: { + /* unknown message received */ + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; + } + } /* switch (SDO->state) */ + SDO->timeoutTimer = 0; + timeDifference_us = 0; + CO_FLAG_CLEAR(SDO->CANrxNew); + } /* if (isNew) */ + + /* Timeout timers *********************************************************/ +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + if (ret == CO_SDO_RT_waitingResponse) { + if (SDO->timeoutTimer < SDO->SDOtimeoutTime_us) { + SDO->timeoutTimer += timeDifference_us; + } + if (SDO->timeoutTimer >= SDO->SDOtimeoutTime_us) { + abortCode = CO_SDO_AB_TIMEOUT; + SDO->state = CO_SDO_ST_ABORT; + } +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT + else if (timerNext_us != NULL) { + /* check again after timeout time elapsed */ + uint32_t diff = SDO->SDOtimeoutTime_us - SDO->timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; } + } +#endif - /* verify toggle bit */ - i = ((CANrxData[0]&0x10U) != 0) ? 1U : 0U; - if(i != SDO->sequence){ - CO_SDO_abort(SDO, CO_SDO_AB_TOGGLE_BIT);/* toggle bit not alternated */ - return -1; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + /* Timeout for sub-block transmission */ + if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { + if (SDO->block_timeoutTimer < SDO->block_SDOtimeoutTime_us) { + SDO->block_timeoutTimer += timeDifference_us; } - - /* calculate length to be sent */ - len = SDO->ODF_arg.dataLength - SDO->bufferOffset; - if(len > 7U) len = 7U; - - /* If data type is domain, re-fill the data buffer if neccessary and indicated so. */ - if((SDO->ODF_arg.ODdataStorage == 0) && (len < 7U) && (!SDO->ODF_arg.lastSegment)){ - /* copy previous data to the beginning */ - for(i=0U; iODF_arg.data[i] = SDO->ODF_arg.data[SDO->bufferOffset+i]; - } - - /* move the beginning of the data buffer */ - SDO->ODF_arg.data += len; - SDO->ODF_arg.dataLength = CO_OD_getLength(SDO, SDO->entryNo, SDO->ODF_arg.subIndex) - len; - - /* read next data from Object dictionary function */ - abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; + if (SDO->block_timeoutTimer >= SDO->block_SDOtimeoutTime_us) { + /* SDO->state will change, processing will continue in this + * thread. Make memory barrier here with CO_FLAG_CLEAR() call.*/ + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; + CO_FLAG_CLEAR(SDO->CANrxNew); + } +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT + else if (timerNext_us != NULL) { + /* check again after timeout time elapsed */ + uint32_t diff = SDO->block_SDOtimeoutTime_us - + SDO->block_timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; } - - /* return to the original data buffer */ - SDO->ODF_arg.data -= len; - SDO->ODF_arg.dataLength += len; - SDO->bufferOffset = 0; - - /* re-calculate the length */ - len = SDO->ODF_arg.dataLength; - if(len > 7U) len = 7U; } +#endif + } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ - /* fill response data bytes */ - for(i=0U; iCANtxBuff->data[i+1] = SDO->ODF_arg.data[SDO->bufferOffset++]; + if (SDO->CANtxBuff->bufferFull) { + ret = CO_SDO_RT_transmittBufferFull; + } + } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - /* first response byte */ - SDO->CANtxBuff->data[0] = 0x00 | (SDO->sequence ? 0x10 : 0x00) | ((7-len)<<1); - SDO->sequence = (SDO->sequence) ? 0 : 1; + /* Transmit CAN data ******************************************************/ + if (ret == CO_SDO_RT_waitingResponse) { + /* clear response buffer */ + memset(SDO->CANtxBuff->data, 0, sizeof(SDO->CANtxBuff->data)); - /* verify end of transfer */ - if((SDO->bufferOffset == SDO->ODF_arg.dataLength) && (SDO->ODF_arg.lastSegment)){ - SDO->CANtxBuff->data[0] |= 0x01; + switch (SDO->state) { + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { + SDO->CANtxBuff->data[0] = 0x60; + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; - /* finish the communication and run mainline processing again */ + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + if (SDO->finished) { SDO->state = CO_SDO_ST_IDLE; -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - if (timerNext_us != NULL) - *timerNext_us = 0; -#endif + ret = CO_SDO_RT_ok_communicationEnd; } - - /* send response */ - sendResponse = true; + else { + SDO->toggle = 0x00; + SDO->sizeTran = 0; + SDO->bufOffsetWr = 0; + SDO->bufOffsetRd = 0; + SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; + } +#else + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; +#endif break; } - case CO_SDO_ST_UPLOAD_BL_INITIATE:{ - /* default response */ - SDO->CANtxBuff->data[1] = CANrxData[1]; - SDO->CANtxBuff->data[2] = CANrxData[2]; - SDO->CANtxBuff->data[3] = CANrxData[3]; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { + SDO->CANtxBuff->data[0] = 0x20 | SDO->toggle; - /* calculate CRC, if enabled */ - if((CANrxData[0] & 0x04U) != 0U){ - SDO->crcEnabled = true; - SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->ODF_arg.dataLength, 0); - } - else{ - SDO->crcEnabled = false; - SDO->crc = 0; + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + if (SDO->finished) { + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; } - - /* Number of segments per block */ - SDO->blksize = CANrxData[4]; - - /* verify client subcommand */ - if((CANrxData[0]&0x03U) != 0x00U){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; + else { + SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; } + break; + } +#endif - /* verify blksize and if SDO data buffer is large enough */ - if((SDO->blksize < 1U) || (SDO->blksize > 127U) || - (((SDO->blksize*7U) > SDO->ODF_arg.dataLength) && (!SDO->ODF_arg.lastSegment))){ - CO_SDO_abort(SDO, CO_SDO_AB_BLOCK_SIZE); /* Invalid block size (block mode only). */ - return -1; + case CO_SDO_ST_UPLOAD_INITIATE_RSP: { +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + /* data were already loaded from OD variable */ + if (SDO->sizeInd > 0 && SDO->sizeInd <= 4) { + /* expedited transfer */ + SDO->CANtxBuff->data[0] = 0x43 | ((4 - SDO->sizeInd) << 2); + memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, + sizeof(SDO->sizeInd)); + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; } - - /* indicate data size, if known */ - if(SDO->ODF_arg.dataLengthTotal != 0U){ - uint32_t dlentot = SDO->ODF_arg.dataLengthTotal; - CO_memcpySwap4(&SDO->CANtxBuff->data[4], &dlentot); - SDO->CANtxBuff->data[0] = 0xC6U; + else { + /* data will be transfered with segmented transfer */ + if (SDO->sizeInd > 0) { + /* indicate data size, if known */ + uint32_t sizeInd = SDO->sizeInd; + uint32_t sizeIndSw = CO_SWAP_32(sizeInd); + SDO->CANtxBuff->data[0] = 0x41; + memcpy(&SDO->CANtxBuff->data[4], + &sizeIndSw, sizeof(sizeIndSw)); + } + SDO->toggle = 0x00; + SDO->timeoutTimer = 0; + SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; } - else{ - SDO->CANtxBuff->data[0] = 0xC4U; +#else /* Expedited transfer only */ + /* load data from OD variable */ + ODR_t odRet; + OD_size_t count = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, + &SDO->CANtxBuff->data[4], 4, + &odRet); + if (odRet != ODR_OK || count == 0) { + abortCode = (odRet == ODR_OK) ? CO_SDO_AB_DEVICE_INCOMPAT : + (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; } - /* send response */ - SDO->state = CO_SDO_ST_UPLOAD_BL_INITIATE_2; - sendResponse = true; +#ifdef CO_BIG_ENDIAN + /* swap data if necessary */ + if ((SDO->attribute & ODA_MB) != 0) { + reverseBytes(&SDO->CANtxBuff->data[4], count); + } +#endif + SDO->CANtxBuff->data[0] = 0x43 | ((4 - count) << 2); + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + + /* send message */ + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); break; } - case CO_SDO_ST_UPLOAD_BL_INITIATE_2:{ - /* verify client command specifier and subcommand */ - if((CANrxData[0]&0xE3U) != 0xA3U){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; - } - - SDO->bufferOffset = 0U; - SDO->sequence = 0U; - SDO->endOfTransfer = false; - CO_SDO_process_done(SDO, timerNext_us); - isNew = false; - SDO->state = CO_SDO_ST_UPLOAD_BL_SUBBLOCK; - /* continue in next case */ - } - // fallthrough - - case CO_SDO_ST_UPLOAD_BL_SUBBLOCK:{ - /* is block confirmation received */ - if(isNew){ - uint8_t ackseq; - uint16_t j; - - /* verify client command specifier and subcommand */ - if((CANrxData[0]&0xE3U) != 0xA2U){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { + /* refill the data buffer if necessary */ + if (!SDO->finished && (SDO->bufOffsetWr - SDO->bufOffsetRd) < 7) { + /* first move remaining data to the start of the buffer */ + SDO->bufOffsetWr -= SDO->bufOffsetRd; + memmove(SDO->buf, SDO->buf + SDO->bufOffsetRd, + SDO->bufOffsetWr); + SDO->bufOffsetRd = 0; + + /* load data from OD variable into the buffer */ + ODR_t odRet; + OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, + SDO->subIndex, + SDO->buf + SDO->bufOffsetWr, + CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr, + &odRet); + SDO->bufOffsetWr += countRd; + + if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; } - - ackseq = CANrxData[1]; /* sequence number of the last segment, that was received correctly. */ - - /* verify if response is too early */ - if(ackseq > SDO->sequence){ - CO_SDO_abort(SDO, CO_SDO_AB_SEQ_NUM); /* Invalid sequence */ - return -1; + else if (odRet == ODR_PARTIAL) { + SDO->finished = false; + if (SDO->bufOffsetWr < 7) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; + break; + } } + else { + SDO->finished = true; + } + } - /* end of transfer */ - if((SDO->endOfTransfer) && (ackseq == SDO->blksize)){ - /* first response byte */ - SDO->CANtxBuff->data[0] = 0xC1 | ((7 - SDO->lastLen) << 2); - - /* CRC */ - if(SDO->crcEnabled) - CO_memcpySwap2(&SDO->CANtxBuff->data[1], &SDO->crc); + /* SDO command specifier with toggle bit */ + SDO->CANtxBuff->data[0] = SDO->toggle; + SDO->toggle = (SDO->toggle == 0x00) ? 0x10 : 0x00; - SDO->state = CO_SDO_ST_UPLOAD_BL_END; + OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; + /* verify, if this is the last segment */ + if (count <= 7) { + /* indicate last segment and nnn */ + SDO->CANtxBuff->data[0] |= ((7 - count) << 1) | 0x01; + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } + else { + SDO->timeoutTimer = 0; + SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; + count = 7; + } - /* send response */ - sendResponse = true; + /* copy data segment to CAN message */ + memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, + count); + SDO->bufOffsetRd += count; + SDO->sizeTran += count; + + /* verify if sizeTran is too large or too short if last segment */ + if (SDO->sizeInd > 0) { + if (SDO->sizeTran > SDO->sizeInd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; break; } + else if (ret == CO_SDO_RT_ok_communicationEnd + && SDO->sizeTran < SDO->sizeInd + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + } - /* move remaining data to the beginning */ - for(i=ackseq*7, j=0; iODF_arg.dataLength; i++, j++) - SDO->ODF_arg.data[j] = SDO->ODF_arg.data[i]; - - /* set remaining data length in buffer */ - SDO->ODF_arg.dataLength -= ackseq * 7U; + /* send message */ + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + break; + } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - /* new block size */ - SDO->blksize = CANrxData[2]; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { + SDO->CANtxBuff->data[0] = 0xA4; + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; + + /* calculate number of block segments from free buffer space */ + OD_size_t count = CO_CONFIG_SDO_SRV_BUFFER_SIZE / 7; + if (count > 127) { + count = 127; + } + SDO->block_blksize = (uint8_t)count; + SDO->CANtxBuff->data[4] = SDO->block_blksize; + + /* reset variables */ + SDO->sizeTran = 0; + SDO->finished = false; + SDO->bufOffsetWr = 0; + SDO->bufOffsetRd = 0; + SDO->block_seqno = 0; + SDO->block_crc = 0; + SDO->timeoutTimer = 0; + SDO->block_timeoutTimer = 0; - /* If data type is domain, re-fill the data buffer if necessary and indicated so. */ - if((SDO->ODF_arg.ODdataStorage == 0) && (SDO->ODF_arg.dataLength < (SDO->blksize*7U)) && (!SDO->ODF_arg.lastSegment)){ - /* move the beginning of the data buffer */ - len = SDO->ODF_arg.dataLength; /* length of valid data in buffer */ - SDO->ODF_arg.data += len; - SDO->ODF_arg.dataLength = CO_OD_getLength(SDO, SDO->entryNo, SDO->ODF_arg.subIndex) - len; + /* Block segments will be received in different thread. Make memory + * barrier here with CO_FLAG_CLEAR() call. */ + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; + CO_FLAG_CLEAR(SDO->CANrxNew); + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + break; + } - /* read next data from Object dictionary function */ - abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE); - if(abortCode != 0U){ - CO_SDO_abort(SDO, abortCode); - return -1; - } + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { + SDO->CANtxBuff->data[0] = 0xA2; + SDO->CANtxBuff->data[1] = SDO->block_seqno; - /* calculate CRC on next bytes, if enabled */ - if(SDO->crcEnabled){ - SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->ODF_arg.dataLength, SDO->crc); - } + /* Is last segment? */ + if (SDO->finished) { + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_REQ; + } + else { + /* verify if size of data downloaded is too large */ + if (SDO->sizeInd > 0 && SDO->sizeTran > SDO->sizeInd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } - /* return to the original data buffer */ - SDO->ODF_arg.data -= len; - SDO->ODF_arg.dataLength += len; + /* calculate number of block segments from free buffer space */ + OD_size_t count; + count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr) / 7; + if (count >= 127) { + count = 127; } + else if (SDO->bufOffsetWr > 0) { + /* it is necessary to empty the buffer */ +#ifdef CO_BIG_ENDIAN + /* swap data if necessary */ + if ((SDO->attribute & ODA_MB) != 0) { + reverseBytes(SDO->buf, SDO->bufOffsetWr); + } +#endif + /* calculate crc on current data */ + SDO->block_crc = crc16_ccitt((unsigned char *)SDO->buf, + SDO->bufOffsetWr, + SDO->block_crc); + + /* write data */ + ODR_t odRet; + SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, + SDO->buf, SDO->bufOffsetWr, &odRet); + SDO->bufOffsetWr = 0; + + if (odRet == ODR_OK) { + /* OD variable was written completelly, but SDO download + * still has data */ + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } + else if (odRet != ODR_PARTIAL) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; + } - /* verify if SDO data buffer is large enough */ - if(((SDO->blksize*7U) > SDO->ODF_arg.dataLength) && (!SDO->ODF_arg.lastSegment)){ - CO_SDO_abort(SDO, CO_SDO_AB_BLOCK_SIZE); /* Invalid block size (block mode only). */ - return -1; + count = CO_CONFIG_SDO_SRV_BUFFER_SIZE / 7; + if (count >= 127) count = 127; } - SDO->bufferOffset = 0U; - SDO->sequence = 0U; - SDO->endOfTransfer = false; + SDO->block_blksize = (uint8_t)count; + SDO->block_seqno = 0; + /* Block segments will be received in different thread. Make + * memory barrier here with CO_FLAG_CLEAR() call. */ + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; + CO_FLAG_CLEAR(SDO->CANrxNew); } - /* return, if all segments was already transfered or on end of transfer */ - if((SDO->sequence == SDO->blksize) || (SDO->endOfTransfer)){ - break; - } + SDO->CANtxBuff->data[2] = SDO->block_blksize; - /* reset timeout */ + /* reset timeout timer and send message */ SDO->timeoutTimer = 0; + SDO->block_timeoutTimer = 0; + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + break; + } - /* calculate length to be sent */ - len = SDO->ODF_arg.dataLength - SDO->bufferOffset; - if(len > 7U){ - len = 7U; - } + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { + SDO->CANtxBuff->data[0] = 0xA1; - /* fill response data bytes */ - for(i=0U; iCANtxBuff->data[i+1] = SDO->ODF_arg.data[SDO->bufferOffset++]; + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + break; + } + + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { + SDO->CANtxBuff->data[0] = 0xC4; + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; + + /* indicate data size */ + if (SDO->sizeInd > 0) { + uint32_t size = CO_SWAP_32(SDO->sizeInd); + SDO->CANtxBuff->data[0] |= 0x02; + memcpy(&SDO->CANtxBuff->data[4], &size, sizeof(size)); } - /* first response byte */ - SDO->CANtxBuff->data[0] = ++SDO->sequence; + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; + break; + } - /* verify end of transfer */ - if((SDO->bufferOffset == SDO->ODF_arg.dataLength) && (SDO->ODF_arg.lastSegment)){ + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: { + /* write header and get current count */ + SDO->CANtxBuff->data[0] = ++SDO->block_seqno; + OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; + /* verify, if this is the last segment */ + if (count <= 7) { SDO->CANtxBuff->data[0] |= 0x80; - SDO->lastLen = len; - SDO->blksize = SDO->sequence; - SDO->endOfTransfer = true; + } + else { + count = 7; } - /* send response */ - sendResponse = true; + /* copy data segment to CAN message */ + memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, + count); + SDO->bufOffsetRd += count; + SDO->block_noData = 7 - count; + SDO->sizeTran += count; + + /* verify if sizeTran is too large or too short if last segment */ + if (SDO->sizeInd > 0) { + if (SDO->sizeTran > SDO->sizeInd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } + else if (SDO->bufOffsetWr == SDO->bufOffsetRd + && SDO->sizeTran < SDO->sizeInd + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + } -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - /* Inform OS to call this function again without delay. */ - if (timerNext_us != NULL) { - *timerNext_us = 0; + /* is last segment or all segments in current block transferred? */ + if (SDO->bufOffsetWr == SDO->bufOffsetRd + || SDO->block_seqno >= SDO->block_blksize + ) { + SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; + } +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT + else { + /* Inform OS to call this function again without delay. */ + if (timerNext_us != NULL) { + *timerNext_us = 0; + } } #endif - + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); break; } - case CO_SDO_ST_UPLOAD_BL_END:{ - /* verify client command specifier */ - if((CANrxData[0]&0xE1U) != 0xA1U){ - CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */ - return -1; - } + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { + SDO->CANtxBuff->data[0] = 0xC1 | (SDO->block_noData << 2); + SDO->CANtxBuff->data[1] = (uint8_t) SDO->block_crc; + SDO->CANtxBuff->data[2] = (uint8_t) (SDO->block_crc >> 8); - /* finish the communication and run mainline processing again */ - SDO->state = CO_SDO_ST_IDLE; -#if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT - if (timerNext_us != NULL) - *timerNext_us = 0; -#endif + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + SDO->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; break; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ - case CO_SDO_ST_IDLE: - { - /* Nothing to do, this never happens. */ + default: { break; } - - default:{ - CO_SDO_abort(SDO, CO_SDO_AB_DEVICE_INCOMPAT);/* general internal incompatibility in the device */ - return -1; - } + } /* switch (SDO->state) */ } - /* free receive buffer if it is not empty */ - CO_SDO_process_done(SDO, timerNext_us); - - /* send message */ - if(sendResponse) { - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - } - - if(SDO->state != CO_SDO_ST_IDLE){ - return 1; + if (ret == CO_SDO_RT_waitingResponse) { + if (SDO->state == CO_SDO_ST_ABORT) { + uint32_t code = CO_SWAP_32((uint32_t)abortCode); + /* Send SDO abort message */ + SDO->CANtxBuff->data[0] = 0x80; + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; + + memcpy(&SDO->CANtxBuff->data[4], &code, sizeof(code)); + CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_endedWithServerAbort; + } +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { + ret = CO_SDO_RT_blockDownldInProgress; + } + else if (SDO->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { + ret = CO_SDO_RT_blockUploadInProgress; + } +#endif } - return 0; + return ret; } diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index b9011d0b..28f34b22 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -4,7 +4,7 @@ * @file CO_SDOserver.h * @ingroup CO_SDOserver * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2020 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -23,13 +23,11 @@ * limitations under the License. */ - #ifndef CO_SDO_SERVER_H #define CO_SDO_SERVER_H -#include - #include "301/CO_driver.h" +#include "301/CO_ODinterface.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_SDO_SRV @@ -39,10 +37,6 @@ #define CO_CONFIG_SDO_SRV_BUFFER_SIZE 32 #endif -#define CO_CONFIG_SDO CO_CONFIG_SDO_SRV -#define CO_CONFIG_SDO_BUFFER_SIZE CO_CONFIG_SDO_SRV_BUFFER_SIZE - - #ifdef __cplusplus extern "C" { #endif @@ -55,10 +49,10 @@ extern "C" { * CANopen Service Data Object - server protocol. * * Service data objects (SDOs) allow the access to any entry of the CANopen - * Object dictionary. An SDO establishes a peer-to-peer communication channel - * between two devices. In addition, the SDO protocol enables to transfer any - * amount of data in a segmented way. Therefore the SDO protocol is mainly used - * in order to communicate configuration data. + * Object dictionary. By SDO a peer-to-peer communication channel between two + * CANopen devices is established. In addition, the SDO protocol enables to + * transfer any amount of data in a segmented way. Therefore the SDO protocol is + * mainly used in order to communicate configuration data. * * All CANopen devices must have implemented SDO server and first SDO server * channel. Servers serves data from Object dictionary. Object dictionary @@ -80,6 +74,8 @@ extern "C" { * data in secure way with little protocol overhead. If error occurs during SDO * transfer #CO_SDO_abortCode_t is send by client or server and transfer is * terminated. For more details see #CO_SDO_state_t. + * + * Access to Object dictionary is specified in @ref CO_ODinterface. */ @@ -303,7 +299,8 @@ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x64U, * the following block upload with 0 < blksize < 128. * - byte 3..7: Reserved. * - SDO server waits for response. - * - If c was set to 1, then communication enters SDO block upload end phase. */ + * - If c was set to 1 and all segments were successfull received, then + * communication enters SDO block upload end phase. */ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x65U, /** * - SDO client waits for server request. @@ -323,21 +320,6 @@ CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x66U, * immediately. */ CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x67U, - -/* old state names, will be removed */ -CO_SDO_ST_DOWNLOAD_INITIATE = 0xA1U, -CO_SDO_ST_DOWNLOAD_SEGMENTED = 0xA2U, -CO_SDO_ST_DOWNLOAD_BL_INITIATE = 0xA4U, -CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK = 0xA5U, -CO_SDO_ST_DOWNLOAD_BL_SUB_RESP = 0xA6U, -CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2 = 0xA7U, -CO_SDO_ST_DOWNLOAD_BL_END = 0xA8U, -CO_SDO_ST_UPLOAD_INITIATE = 0xB1U, -CO_SDO_ST_UPLOAD_SEGMENTED = 0xB2U, -CO_SDO_ST_UPLOAD_BL_INITIATE = 0xB4U, -CO_SDO_ST_UPLOAD_BL_INITIATE_2 = 0xB5U, -CO_SDO_ST_UPLOAD_BL_SUBBLOCK = 0xB6U, -CO_SDO_ST_UPLOAD_BL_END = 0xB7U } CO_SDO_state_t; @@ -348,316 +330,86 @@ CO_SDO_ST_UPLOAD_BL_END = 0xB7U * * The abort codes not listed here are reserved. */ -typedef enum{ - CO_SDO_AB_NONE = 0x00000000UL, /**< 0x00000000, No abort */ - CO_SDO_AB_TOGGLE_BIT = 0x05030000UL, /**< 0x05030000, Toggle bit not altered */ - CO_SDO_AB_TIMEOUT = 0x05040000UL, /**< 0x05040000, SDO protocol timed out */ - CO_SDO_AB_CMD = 0x05040001UL, /**< 0x05040001, Command specifier not valid or unknown */ - CO_SDO_AB_BLOCK_SIZE = 0x05040002UL, /**< 0x05040002, Invalid block size in block mode */ - CO_SDO_AB_SEQ_NUM = 0x05040003UL, /**< 0x05040003, Invalid sequence number in block mode */ - CO_SDO_AB_CRC = 0x05040004UL, /**< 0x05040004, CRC error (block mode only) */ - CO_SDO_AB_OUT_OF_MEM = 0x05040005UL, /**< 0x05040005, Out of memory */ - CO_SDO_AB_UNSUPPORTED_ACCESS = 0x06010000UL, /**< 0x06010000, Unsupported access to an object */ - CO_SDO_AB_WRITEONLY = 0x06010001UL, /**< 0x06010001, Attempt to read a write only object */ - CO_SDO_AB_READONLY = 0x06010002UL, /**< 0x06010002, Attempt to write a read only object */ - CO_SDO_AB_NOT_EXIST = 0x06020000UL, /**< 0x06020000, Object does not exist in the object dictionary */ - CO_SDO_AB_NO_MAP = 0x06040041UL, /**< 0x06040041, Object cannot be mapped to the PDO */ - CO_SDO_AB_MAP_LEN = 0x06040042UL, /**< 0x06040042, Number and length of object to be mapped exceeds PDO length */ - CO_SDO_AB_PRAM_INCOMPAT = 0x06040043UL, /**< 0x06040043, General parameter incompatibility reasons */ - CO_SDO_AB_DEVICE_INCOMPAT = 0x06040047UL, /**< 0x06040047, General internal incompatibility in device */ - CO_SDO_AB_HW = 0x06060000UL, /**< 0x06060000, Access failed due to hardware error */ - CO_SDO_AB_TYPE_MISMATCH = 0x06070010UL, /**< 0x06070010, Data type does not match, length of service parameter does not match */ - CO_SDO_AB_DATA_LONG = 0x06070012UL, /**< 0x06070012, Data type does not match, length of service parameter too high */ - CO_SDO_AB_DATA_SHORT = 0x06070013UL, /**< 0x06070013, Data type does not match, length of service parameter too short */ - CO_SDO_AB_SUB_UNKNOWN = 0x06090011UL, /**< 0x06090011, Sub index does not exist */ - CO_SDO_AB_INVALID_VALUE = 0x06090030UL, /**< 0x06090030, Invalid value for parameter (download only). */ - CO_SDO_AB_VALUE_HIGH = 0x06090031UL, /**< 0x06090031, Value range of parameter written too high */ - CO_SDO_AB_VALUE_LOW = 0x06090032UL, /**< 0x06090032, Value range of parameter written too low */ - CO_SDO_AB_MAX_LESS_MIN = 0x06090036UL, /**< 0x06090036, Maximum value is less than minimum value. */ - CO_SDO_AB_NO_RESOURCE = 0x060A0023UL, /**< 0x060A0023, Resource not available: SDO connection */ - CO_SDO_AB_GENERAL = 0x08000000UL, /**< 0x08000000, General error */ - CO_SDO_AB_DATA_TRANSF = 0x08000020UL, /**< 0x08000020, Data cannot be transferred or stored to application */ - CO_SDO_AB_DATA_LOC_CTRL = 0x08000021UL, /**< 0x08000021, Data cannot be transferred or stored to application because of local control */ - CO_SDO_AB_DATA_DEV_STATE = 0x08000022UL, /**< 0x08000022, Data cannot be transferred or stored to application because of present device state */ - CO_SDO_AB_DATA_OD = 0x08000023UL, /**< 0x08000023, Object dictionary not present or dynamic generation fails */ - CO_SDO_AB_NO_DATA = 0x08000024UL /**< 0x08000024, No data available */ -}CO_SDO_abortCode_t; - - -/** - * @defgroup CO_SDO_objectDictionary Object dictionary - * - * CANopen Object dictionary implementation in CANopenNode. - * - * CANopen Object dictionary is a collection of different data items, which can - * be used by the stack or by the application. - * - * Each Object dictionary entry is located under 16-bit index, as specified - * by the CANopen: - * - 0x0001..0x025F: Data type definitions. - * - 0x1000..0x1FFF: Communication profile area. - * - 0x2000..0x5FFF: Manufacturer-specific profile area. - * - 0x6000..0x9FFF: Standardized device profile area for eight logical devices. - * - 0xA000..0xAFFF: Standardized network variable area. - * - 0xB000..0xBFFF: Standardized system variable area. - * - Other: Reserved. - * - * If Object dictionary entry has complex data type (array or structure), - * then 8-bit subIndex specifies the sub-member of the entry. In that case - * subIndex 0x00 is encoded as uint8_t and specifies the highest available - * subIndex with that entry. Subindex 0xFF has special meaning in the standard - * and is not supported by CANopenNode. - * - * ####Object type of one Object dictionary entry - * - NULL: Not used by CANopenNode. - * - DOMAIN: Block of data of variable length. Data and length are - * under control of the application. - * - DEFTYPE: Definition of CANopen basic data type, for example - * INTEGER16. - * - DEFSTRUCT: Definition of complex data type - structure, which is - * used with RECORD. - * - VAR: Variable of CANopen basic data type. Subindex is 0. - * - ARRAY: Array of multiple variables of the same CANopen basic - * data type. Subindex 1..arrayLength specifies sub-member. - * - RECORD: Record or structure of multiple variables of different - * CANopen basic data type. Subindex specifies sub-member. - * - * - * ####Implementation in CANopenNode - * Object dictionary in CANopenNode is implemented in CO_OD.h and CO_OD.c files. - * These files are application specific and must be generated by Object - * dictionary editor (application is included by the stack). - * - * CO_OD.h and CO_OD.c files include: - * - Structure definitions for records. - * - Global declaration and initialization of all variables, arrays and records - * mapped to Object dictionary. Variables are distributed in multiple objects, - * depending on memory location. This eases storage to different memories in - * microcontroller, like eeprom or flash. - * - Constant array of multiple Object dictionary entries of type - * CO_OD_entry_t. If object type is record, then entry includes additional - * constant array with members of type CO_OD_entryRecord_t. Each OD entry - * includes information: index, maxSubIndex, #CO_SDO_OD_attributes_t, data size and - * pointer to variable. - * - * - * Function CO_SDO_init() initializes object CO_SDO_t, which includes SDO - * server and Object dictionary. - * - * Application doesn't need to know anything about the Object dictionary. It can - * use variables specified in CO_OD.h file directly. If it needs more control - * over the CANopen communication with the variables, it can configure additional - * functionality with function CO_OD_configure(). Additional functionality - * include: @ref CO_SDO_OD_function and #CO_SDO_OD_flags_t. - * - * Interface to Object dictionary is provided by following functions: CO_OD_find() - * finds OD entry by index, CO_OD_getLength() returns length of variable, - * CO_OD_getAttribute returns attribute and CO_OD_getDataPointer() returns pointer - * to data. These functions are used by SDO server and by PDO configuration. They - * can also be used to access the OD by index like this. - * - * \code{.c} - * index = CO_OD_find(CO->SDO[0], OD_H1001_ERR_REG); - * if (index == 0xffff) { - * return; - * } - * length = CO_OD_getLength(CO->SDO[0], index, 1); - * if (length != sizeof(new_data)) { - * return; - * } - * - * p = CO_OD_getDataPointer(CO->SDO[0], index, 1); - * if (p == NULL) { - * return; - * } - * CO_LOCK_OD(); - * *p = new_data; - * CO_UNLOCK_OD(); - * \endcode - * - * Be aware that accessing the OD directly using CO_OD.h files is more CPU - * efficient as CO_OD_find() has to do a search everytime it is called. - * - */ - - -/** - * @defgroup CO_SDO_OD_function Object Dictionary function - * - * Optional application specific function, which may manipulate data downloaded - * or uploaded via SDO. - * - * Object dictionary function is external function defined by application or - * by other stack files. It may be registered for specific Object dictionary - * entry (with specific index). If it is registered, it is called (through - * function pointer) from SDO server. It may verify and manipulate data during - * SDO transfer. Object dictionary function can be registered by function - * CO_OD_configure(). - * - * ####SDO download (writing to Object dictionary) - * After SDO client transfers data to the server, data are stored in internal - * buffer. If data contains multibyte variable and processor is big endian, - * then data bytes are swapped. Object dictionary function is called if - * registered. Data may be verified and manipulated inside that function. After - * function exits, data are copied to location as specified in CO_OD_entry_t. - * - * ####SDO upload (reading from Object dictionary) - * Before start of SDO upload, data are read from Object dictionary into - * internal buffer. If necessary, bytes are swapped. - * Object dictionary function is called if registered. Data may be - * manipulated inside that function. After function exits, data are - * transferred via SDO server. - * - * ####Domain data type - * If data type is domain, then length is not specified by Object dictionary. - * In that case Object dictionary function must be used. In case of - * download it must store the data in own location. In case of upload it must - * write the data (maximum size is specified by length) into data buffer and - * specify actual length. With domain data type it is possible to transfer - * data, which are longer than #CO_CONFIG_SDO_BUFFER_SIZE. In that case - * Object dictionary function is called multiple times between SDO transfer. - * - * ####Parameter to function: - * ODF_arg - Pointer to CO_ODF_arg_t object filled before function call. - * - * ####Return from function: - * - 0: Data transfer is successful - * - Different than 0: Failure. See #CO_SDO_abortCode_t. - */ - - -/** - * Size of fifo queue for SDO received messages. - * - * If block transfers are used size of fifo queue should be more that 1 message - * to avoid possible drops in consecutive SDO block upload transfers. - * To increase performance, value can be set to 1 if block transfers are not used - * - * Min value is 1. - */ - #ifndef CO_SDO_RX_DATA_SIZE - #define CO_SDO_RX_DATA_SIZE 2 - #endif - - -/** - * Object Dictionary attributes. Bit masks for attribute in CO_OD_entry_t. - */ -typedef enum{ - CO_ODA_MEM_ROM = 0x0001U, /**< Variable is located in ROM memory */ - CO_ODA_MEM_RAM = 0x0002U, /**< Variable is located in RAM memory */ - CO_ODA_MEM_EEPROM = 0x0003U, /**< Variable is located in EEPROM memory */ - CO_ODA_READABLE = 0x0004U, /**< SDO server may read from the variable */ - CO_ODA_WRITEABLE = 0x0008U, /**< SDO server may write to the variable */ - CO_ODA_RPDO_MAPABLE = 0x0010U, /**< Variable is mappable for RPDO */ - CO_ODA_TPDO_MAPABLE = 0x0020U, /**< Variable is mappable for TPDO */ - CO_ODA_TPDO_DETECT_COS = 0x0040U, /**< If variable is mapped to any PDO, then - PDO is automatically send, if variable - changes its value */ - CO_ODA_MB_VALUE = 0x0080U /**< True when variable is a multibyte value */ -}CO_SDO_OD_attributes_t; - - -/** - * Common DS301 object dictionary entries. - */ -typedef enum{ - OD_H1000_DEV_TYPE = 0x1000U,/**< Device type */ - OD_H1001_ERR_REG = 0x1001U,/**< Error register */ - OD_H1002_MANUF_STATUS_REG = 0x1002U,/**< Manufacturer status register */ - OD_H1003_PREDEF_ERR_FIELD = 0x1003U,/**< Predefined error field */ - OD_H1004_RSV = 0x1004U,/**< Reserved */ - OD_H1005_COBID_SYNC = 0x1005U,/**< Sync message cob-id */ - OD_H1006_COMM_CYCL_PERIOD = 0x1006U,/**< Communication cycle period */ - OD_H1007_SYNC_WINDOW_LEN = 0x1007U,/**< Sync windows length */ - OD_H1008_MANUF_DEV_NAME = 0x1008U,/**< Manufacturer device name */ - OD_H1009_MANUF_HW_VERSION = 0x1009U,/**< Manufacturer hardware version */ - OD_H100A_MANUF_SW_VERSION = 0x100AU,/**< Manufacturer software version */ - OD_H100B_RSV = 0x100BU,/**< Reserved */ - OD_H100C_GUARD_TIME = 0x100CU,/**< Guard time */ - OD_H100D_LIFETIME_FACTOR = 0x100DU,/**< Life time factor */ - OD_H100E_RSV = 0x100EU,/**< Reserved */ - OD_H100F_RSV = 0x100FU,/**< Reserved */ - OD_H1010_STORE_PARAM_FUNC = 0x1010U,/**< Store parameter in persistent memory function */ - OD_H1011_REST_PARAM_FUNC = 0x1011U,/**< Restore default parameter function */ - OD_H1012_COBID_TIME = 0x1012U,/**< Timestamp message cob-id */ - OD_H1013_HIGH_RES_TIMESTAMP = 0x1013U,/**< High resolution timestamp */ - OD_H1014_COBID_EMERGENCY = 0x1014U,/**< Emergency message cob-id */ - OD_H1015_INHIBIT_TIME_MSG = 0x1015U,/**< Inhibit time message */ - OD_H1016_CONSUMER_HB_TIME = 0x1016U,/**< Consumer heartbeat time */ - OD_H1017_PRODUCER_HB_TIME = 0x1017U,/**< Producer heartbeat time */ - OD_H1018_IDENTITY_OBJECT = 0x1018U,/**< Identity object */ - OD_H1019_SYNC_CNT_OVERFLOW = 0x1019U,/**< Sync counter overflow value */ - OD_H1020_VERIFY_CONFIG = 0x1020U,/**< Verify configuration */ - OD_H1021_STORE_EDS = 0x1021U,/**< Store EDS */ - OD_H1022_STORE_FORMAT = 0x1022U,/**< Store format */ - OD_H1023_OS_CMD = 0x1023U,/**< OS command */ - OD_H1024_OS_CMD_MODE = 0x1024U,/**< OS command mode */ - OD_H1025_OS_DBG_INTERFACE = 0x1025U,/**< OS debug interface */ - OD_H1026_OS_PROMPT = 0x1026U,/**< OS prompt */ - OD_H1027_MODULE_LIST = 0x1027U,/**< Module list */ - OD_H1028_EMCY_CONSUMER = 0x1028U,/**< Emergency consumer object */ - OD_H1029_ERR_BEHAVIOR = 0x1029U,/**< Error behaviour */ - OD_H1200_SDO_SERVER_PARAM = 0x1200U,/**< SDO server parameters */ - OD_H1280_SDO_CLIENT_PARAM = 0x1280U,/**< SDO client parameters */ - OD_H1300_GFC_PARAM = 0x1300U,/**< GFC parameter */ - OD_H1301_SRDO_1_PARAM = 0x1301U,/**< SRDO communication parameters */ - OD_H1381_SRDO_1_MAPPING = 0x1381U,/**< SRDO mapping parameters */ - OD_H13FE_SRDO_VALID = 0x13FEU,/**< SRDO valid flag */ - OD_H13FF_SRDO_CHECKSUM = 0x13FFU,/**< SRDO checksum */ - OD_H1400_RXPDO_1_PARAM = 0x1400U,/**< RXPDO communication parameter */ - OD_H1401_RXPDO_2_PARAM = 0x1401U,/**< RXPDO communication parameter */ - OD_H1402_RXPDO_3_PARAM = 0x1402U,/**< RXPDO communication parameter */ - OD_H1403_RXPDO_4_PARAM = 0x1403U,/**< RXPDO communication parameter */ - OD_H1600_RXPDO_1_MAPPING = 0x1600U,/**< RXPDO mapping parameters */ - OD_H1601_RXPDO_2_MAPPING = 0x1601U,/**< RXPDO mapping parameters */ - OD_H1602_RXPDO_3_MAPPING = 0x1602U,/**< RXPDO mapping parameters */ - OD_H1603_RXPDO_4_MAPPING = 0x1603U,/**< RXPDO mapping parameters */ - OD_H1800_TXPDO_1_PARAM = 0x1800U,/**< TXPDO communication parameter */ - OD_H1801_TXPDO_2_PARAM = 0x1801U,/**< TXPDO communication parameter */ - OD_H1802_TXPDO_3_PARAM = 0x1802U,/**< TXPDO communication parameter */ - OD_H1803_TXPDO_4_PARAM = 0x1803U,/**< TXPDO communication parameter */ - OD_H1A00_TXPDO_1_MAPPING = 0x1A00U,/**< TXPDO mapping parameters */ - OD_H1A01_TXPDO_2_MAPPING = 0x1A01U,/**< TXPDO mapping parameters */ - OD_H1A02_TXPDO_3_MAPPING = 0x1A02U,/**< TXPDO mapping parameters */ - OD_H1A03_TXPDO_4_MAPPING = 0x1A03U /**< TXPDO mapping parameters */ -}CO_ObjDicId_t; - - -/** - * Bit masks for flags associated with variable from @ref CO_SDO_objectDictionary. - * - * This additional functionality of any variable in @ref CO_SDO_objectDictionary can be - * enabled by function CO_OD_configure(). Location of the flag byte can be - * get from function CO_OD_getFlagsPointer(). - */ -typedef enum{ - /** Variable was written by RPDO. Flag can be cleared by application */ - CO_ODFL_RPDO_WRITTEN = 0x01U, - /** Variable is mapped to TPDO */ - CO_ODFL_TPDO_MAPPED = 0x02U, - /** Change of state bit, initially copy of attribute from CO_OD_entry_t. - If set and variable is mapped to TPDO, TPDO will be automatically send, - if variable changed */ - CO_ODFL_TPDO_COS_ENABLE = 0x04U, - /** PDO send bit, can be set by application. If variable is mapped into - TPDO, TPDO will be send and bit will be cleared. */ - CO_ODFL_TPDO_SEND = 0x08U, - /** Variable was accessed by SDO download */ - CO_ODFL_SDO_DOWNLOADED = 0x10U, - /** Variable was accessed by SDO upload */ - CO_ODFL_SDO_UPLOADED = 0x20U, - /** Reserved */ - CO_ODFL_BIT_6 = 0x40U, - /** Reserved */ - CO_ODFL_BIT_7 = 0x80U -}CO_SDO_OD_flags_t; +typedef enum { + /** 0x00000000, No abort */ + CO_SDO_AB_NONE = 0x00000000UL, + /** 0x05030000, Toggle bit not altered */ + CO_SDO_AB_TOGGLE_BIT = 0x05030000UL, + /** 0x05040000, SDO protocol timed out */ + CO_SDO_AB_TIMEOUT = 0x05040000UL, + /** 0x05040001, Command specifier not valid or unknown */ + CO_SDO_AB_CMD = 0x05040001UL, + /** 0x05040002, Invalid block size in block mode */ + CO_SDO_AB_BLOCK_SIZE = 0x05040002UL, + /** 0x05040003, Invalid sequence number in block mode */ + CO_SDO_AB_SEQ_NUM = 0x05040003UL, + /** 0x05040004, CRC error (block mode only) */ + CO_SDO_AB_CRC = 0x05040004UL, + /** 0x05040005, Out of memory */ + CO_SDO_AB_OUT_OF_MEM = 0x05040005UL, + /** 0x06010000, Unsupported access to an object */ + CO_SDO_AB_UNSUPPORTED_ACCESS = 0x06010000UL, + /** 0x06010001, Attempt to read a write only object */ + CO_SDO_AB_WRITEONLY = 0x06010001UL, + /** 0x06010002, Attempt to write a read only object */ + CO_SDO_AB_READONLY = 0x06010002UL, + /** 0x06020000, Object does not exist in the object dictionary */ + CO_SDO_AB_NOT_EXIST = 0x06020000UL, + /** 0x06040041, Object cannot be mapped to the PDO */ + CO_SDO_AB_NO_MAP = 0x06040041UL, + /** 0x06040042, Number and length of object to be mapped exceeds PDO + * length */ + CO_SDO_AB_MAP_LEN = 0x06040042UL, + /** 0x06040043, General parameter incompatibility reasons */ + CO_SDO_AB_PRAM_INCOMPAT = 0x06040043UL, + /** 0x06040047, General internal incompatibility in device */ + CO_SDO_AB_DEVICE_INCOMPAT = 0x06040047UL, + /** 0x06060000, Access failed due to hardware error */ + CO_SDO_AB_HW = 0x06060000UL, + /** 0x06070010, Data type does not match, length of service parameter does + * not match */ + CO_SDO_AB_TYPE_MISMATCH = 0x06070010UL, + /** 0x06070012, Data type does not match, length of service parameter too + * high */ + CO_SDO_AB_DATA_LONG = 0x06070012UL, + /** 0x06070013, Data type does not match, length of service parameter too + * short */ + CO_SDO_AB_DATA_SHORT = 0x06070013UL, + /** 0x06090011, Sub index does not exist */ + CO_SDO_AB_SUB_UNKNOWN = 0x06090011UL, + /** 0x06090030, Invalid value for parameter (download only). */ + CO_SDO_AB_INVALID_VALUE = 0x06090030UL, + /** 0x06090031, Value range of parameter written too high */ + CO_SDO_AB_VALUE_HIGH = 0x06090031UL, + /** 0x06090032, Value range of parameter written too low */ + CO_SDO_AB_VALUE_LOW = 0x06090032UL, + /** 0x06090036, Maximum value is less than minimum value. */ + CO_SDO_AB_MAX_LESS_MIN = 0x06090036UL, + /** 0x060A0023, Resource not available: SDO connection */ + CO_SDO_AB_NO_RESOURCE = 0x060A0023UL, + /** 0x08000000, General error */ + CO_SDO_AB_GENERAL = 0x08000000UL, + /** 0x08000020, Data cannot be transferred or stored to application */ + CO_SDO_AB_DATA_TRANSF = 0x08000020UL, + /** 0x08000021, Data cannot be transferred or stored to application because + * of local control */ + CO_SDO_AB_DATA_LOC_CTRL = 0x08000021UL, + /** 0x08000022, Data cannot be transferred or stored to application because + * of present device state */ + CO_SDO_AB_DATA_DEV_STATE = 0x08000022UL, + /** 0x08000023, Object dictionary not present or dynamic generation fails */ + CO_SDO_AB_DATA_OD = 0x08000023UL, + /** 0x08000024, No data available */ + CO_SDO_AB_NO_DATA = 0x08000024UL +} CO_SDO_abortCode_t; /** * Return values from SDO server or client functions. */ typedef enum { + /** Waiting in client local transfer. */ + CO_SDO_RT_waitingLocalTransfer = 6, /** Data buffer is full. * SDO client: data must be read before next upload cycle begins. */ CO_SDO_RT_uploadDataBufferFull = 5, @@ -668,7 +420,7 @@ typedef enum { /** Block upload is in progress. Receiving train of messages. * SDO client: Data must not be read in this state. */ CO_SDO_RT_blockUploadInProgress = 2, - /** Waiting server or client response */ + /** Waiting server or client response. */ CO_SDO_RT_waitingResponse = 1, /** Success, end of communication. SDO client: uploaded data must be read.*/ CO_SDO_RT_ok_communicationEnd = 0, @@ -681,260 +433,95 @@ typedef enum { } CO_SDO_return_t; -/** - * Object for one entry with specific index in @ref CO_SDO_objectDictionary. - */ -typedef struct { - /** The index of Object from 0x1000 to 0xFFFF */ - uint16_t index; - /** Number of (sub-objects - 1). If Object Type is variable, then - maxSubIndex is 0, otherwise maxSubIndex is equal or greater than 1. */ - uint8_t maxSubIndex; - /** If Object Type is record, attribute is set to zero. Attribute for - each member is then set in special array with members of type - CO_OD_entryRecord_t. If Object Type is Array, attribute is common for - all array members. See #CO_SDO_OD_attributes_t. */ - uint16_t attribute; - /** If Object Type is Variable, length is the length of variable in bytes. - If Object Type is Array, length is the length of one array member. - If Object Type is Record, length is zero. Length for each member is - set in special array with members of type CO_OD_entryRecord_t. - If Object Type is Domain, length is zero. Length is specified - by application in @ref CO_SDO_OD_function. */ - uint16_t length; - /** If Object Type is Variable, pData is pointer to data. - If Object Type is Array, pData is pointer to data. Data doesn't - include Sub-Object 0. - If object type is Record, pData is pointer to special array - with members of type CO_OD_entryRecord_t. - If object type is Domain, pData is null. */ - void *pData; -}CO_OD_entry_t; - - -/** - * Object for record type entry in @ref CO_SDO_objectDictionary. - * - * See CO_OD_entry_t. - */ -typedef struct{ - /** Pointer to data. If object type is Domain, pData is null */ - void *pData; - /** See #CO_SDO_OD_attributes_t */ - uint16_t attribute; - /** Length of variable in bytes. If object type is Domain, length is zero */ - uint16_t length; -}CO_OD_entryRecord_t; - - -/** - * Object contains all information about the object being transferred by SDO server. - * - * Object is used as an argument to @ref CO_SDO_OD_function. It is also - * part of the CO_SDO_t object. - */ -typedef struct{ - /** Informative parameter. It may point to object, which is connected - with this OD entry. It can be used inside @ref CO_SDO_OD_function, ONLY - if it was registered by CO_OD_configure() function before. */ - void *object; - /** SDO data buffer contains data, which are exchanged in SDO transfer. - @ref CO_SDO_OD_function may verify or manipulate that data before (after) - they are written to (read from) Object dictionary. Data have the same - endianes as processor. Pointer must NOT be changed. (Data up to length - can be changed.) */ - uint8_t *data; - /** Pointer to location in object dictionary, where data are stored. - (informative reference to old data, read only). Data have the same - endianes as processor. If data type is Domain, this variable is null. */ - const void *ODdataStorage; - /** Length of data in the above buffer. Read only, except for domain. If - data type is domain see @ref CO_SDO_OD_function for special rules by upload. */ - uint16_t dataLength; - /** Attribute of object in Object dictionary (informative, must NOT be changed). */ - uint16_t attribute; - /** Pointer to the #CO_SDO_OD_flags_t byte. */ - uint8_t *pFlags; - /** Index of object in Object dictionary (informative, must NOT be changed). */ - uint16_t index; - /** Subindex of object in Object dictionary (informative, must NOT be changed). */ - uint8_t subIndex; - /** True, if SDO upload is in progress, false if SDO download is in progress. */ - bool_t reading; - /** Used by domain data type. Indicates the first segment. Variable is informative. */ - bool_t firstSegment; - /** Used by domain data type. If false by download, then application will - receive more segments during SDO communication cycle. If uploading, - application may set variable to false, so SDO server will call - @ref CO_SDO_OD_function again for filling the next data. */ - bool_t lastSegment; - /** Used by domain data type. By upload @ref CO_SDO_OD_function may write total - data length, so this information will be send in SDO upload initiate phase. It - is not necessary to specify this variable. By download this variable contains - total data size, if size is indicated in SDO download initiate phase */ - uint32_t dataLengthTotal; - /** Used by domain data type. In case of multiple segments, this indicates the offset - into the buffer this segment starts at. */ - uint32_t offset; -}CO_ODF_arg_t; - - -/** - * Object is used as array inside CO_SDO_t, parallel to @ref CO_SDO_objectDictionary. - * - * Object is generated by function CO_OD_configure(). It is then used as - * extension to Object dictionary entry at specific index. - */ -typedef struct{ - /** Pointer to @ref CO_SDO_OD_function */ - CO_SDO_abortCode_t (*pODFunc)(CO_ODF_arg_t *ODF_arg); - /** Pointer to object, which will be passed to @ref CO_SDO_OD_function */ - void *object; - /** Pointer to #CO_SDO_OD_flags_t. If object type is array or record, this - variable points to array with length equal to number of subindexes. */ - uint8_t *flags; -}CO_OD_extension_t; - - /** * SDO server object. */ -typedef struct{ - /** FIFO queue of the received message 8 data bytes each */ - uint8_t CANrxData[CO_SDO_RX_DATA_SIZE][8]; - /** SDO data buffer of size #CO_CONFIG_SDO_BUFFER_SIZE. */ - uint8_t databuffer[CO_CONFIG_SDO_BUFFER_SIZE]; - /** Internal flag indicates, that this object has own OD */ - bool_t ownOD; - /** Pointer to the @ref CO_SDO_objectDictionary (array) */ - const CO_OD_entry_t *OD; - /** Size of the @ref CO_SDO_objectDictionary */ - uint16_t ODSize; - /** Pointer to array of CO_OD_extension_t objects. Size of the array is - equal to ODSize. */ - CO_OD_extension_t *ODExtensions; - /** Offset in buffer of next data segment being read/written */ - uint16_t bufferOffset; - /** Sequence number of OD entry as returned from CO_OD_find() */ - uint16_t entryNo; - /** CO_ODF_arg_t object with additional variables. Reference to this object - is passed to @ref CO_SDO_OD_function */ - CO_ODF_arg_t ODF_arg; - /** From CO_SDO_init() */ - uint8_t nodeId; - /** Current internal state of the SDO server state machine #CO_SDO_state_t */ - CO_SDO_state_t state; - /** Toggle bit in segmented transfer or block sequence in block transfer */ - uint8_t sequence; - /** Maximum timeout time between request and response in microseconds. */ - uint32_t SDOtimeoutTime_us; - /** Timeout timer for SDO communication */ - uint32_t timeoutTimer; - /** Number of segments per block with 1 <= blksize <= 127 */ - uint8_t blksize; - /** True, if CRC calculation by block transfer is enabled */ - bool_t crcEnabled; - /** Calculated CRC code */ - uint16_t crc; - /** Length of data in the last segment in block upload */ - uint8_t lastLen; - /** Indication timeout in sub-block transfer */ - bool_t timeoutSubblockDownolad; - /** Indication end of block transfer */ - bool_t endOfTransfer; - /** Variables indicates, if new SDO message received from CAN bus */ - volatile void *CANrxNew[CO_SDO_RX_DATA_SIZE]; - /** Index of CANrxData for new received SDO message */ - uint8_t CANrxRcv; - /** Index of CANrxData SDO message to processed */ - uint8_t CANrxProc; - /** Number of new SDO messages in CANrxData to process */ - uint8_t CANrxSize; -#if ((CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN - /** From CO_SDO_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); - /** From CO_SDO_initCallbackPre() or NULL */ - void *functSignalObjectPre; -#endif - /** From CO_SDO_init() */ - CO_CANmodule_t *CANdevTx; - /** CAN transmit buffer inside CANdev for CAN tx message */ - CO_CANtx_t *CANtxBuff; -}CO_SDO_t; - - -/** - * Copy 2 data bytes from source to destination. Swap bytes if - * microcontroller is big-endian. - * - * @param dest Destination location. - * @param src Source location. - */ -#ifdef CO_LITTLE_ENDIAN -#define CO_memcpySwap2(dest, src) memcpy(dest, src, 2) -#endif -#if defined CO_BIG_ENDIAN || defined CO_DOXYGEN -static inline void CO_memcpySwap2(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[1]; - cdest[1] = csrc[0]; -} +typedef struct { + /** From CO_SDOserver_init() */ + CO_CANmodule_t *CANdevTx; + /** CAN transmit buffer inside CANdevTx for CAN tx message */ + CO_CANtx_t *CANtxBuff; + /** From CO_SDOserver_init() */ + const OD_t *OD; + /** From CO_SDOserver_init() */ + uint8_t nodeId; + /* If true, SDO channel is valid */ + bool_t valid; + /** Internal state of the SDO server */ + volatile CO_SDO_state_t state; + /** Object dictionary interface for current object. */ + OD_IO_t OD_IO; + /** Index of the current object in Object Dictionary */ + uint16_t index; + /** Subindex of the current object in Object Dictionary */ + uint8_t subIndex; + /** Attribute bit-field of the current OD sub-object, see OD_attributes_t */ + OD_attr_t attribute; + /** Indicates, if new SDO message received from CAN bus. It is not cleared, + * until received message is completely processed. */ + volatile void *CANrxNew; + /** 8 data bytes of the received message */ + uint8_t CANrxData[8]; +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN + /** From CO_SDOserver_init() */ + CO_CANmodule_t *CANdevRx; + /** From CO_SDOserver_init() */ + uint16_t CANdevRxIdx; + /** From CO_SDOserver_init() */ + uint16_t CANdevTxIdx; + /** Copy of CANopen COB_ID Client -> Server, meaning of the specific bits: + - Bit 0...10: 11-bit CAN identifier. + - Bit 11..30: reserved, must be 0. + - Bit 31: if 1, SDO client object is not used. */ + uint32_t COB_IDClientToServer; + /** Copy of CANopen COB_ID Server -> Client, similar as above */ + uint32_t COB_IDServerToClient; #endif - - -/** - * Copy 4 data bytes from source to destination. Swap bytes if - * microcontroller is big-endian. - * - * @param dest Destination location. - * @param src Source location. - */ -#ifdef CO_LITTLE_ENDIAN -#define CO_memcpySwap4(dest, src) memcpy(dest, src, 4) +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) || defined CO_DOXYGEN + /** Size of data, which will be transferred. It is optionally indicated by + * client in case of download or by server in case of upload. */ + OD_size_t sizeInd; + /** Size of data which is actually transferred. */ + OD_size_t sizeTran; + /** Toggle bit toggled in each segment in segmented transfer */ + uint8_t toggle; + /** If true, then: data transfer is finished (by download) or read from OD + * variable is finished (by upload) */ + bool_t finished; + /** Maximum timeout time between request and response in microseconds */ + uint32_t SDOtimeoutTime_us; + /** Timeout timer for SDO communication */ + uint32_t timeoutTimer; + /** Interim data buffer for segmented or block transfer */ + char buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE]; + /** Offset of next free data byte available for write in the buffer. */ + OD_size_t bufOffsetWr; + /** Offset of first data available for read in the buffer */ + OD_size_t bufOffsetRd; #endif -#if defined CO_BIG_ENDIAN || defined CO_DOXYGEN -static inline void CO_memcpySwap4(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[3]; - cdest[1] = csrc[2]; - cdest[2] = csrc[1]; - cdest[3] = csrc[0]; -} +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) || defined CO_DOXYGEN + /** Timeout time for SDO sub-block download, half of #SDOtimeoutTime_us */ + uint32_t block_SDOtimeoutTime_us; + /** Timeout timer for SDO sub-block download */ + uint32_t block_timeoutTimer; + /** Sequence number of segment in block, 1..127 */ + uint8_t block_seqno; + /** Number of segments per block, 1..127 */ + uint8_t block_blksize; + /** Number of bytes in last segment that do not contain data */ + uint8_t block_noData; + /** Client CRC support in block transfer */ + bool_t block_crcEnabled; + /** Calculated CRC checksum */ + uint16_t block_crc; #endif - - -/** - * Copy 8 data bytes from source to destination. Swap bytes if - * microcontroller is big-endian. - * - * @param dest Destination location. - * @param src Source location. - */ -#ifdef CO_LITTLE_ENDIAN -#define CO_memcpySwap8(dest, src) memcpy(dest, src, 8) -#endif -#if defined CO_BIG_ENDIAN || defined CO_DOXYGEN -static inline void CO_memcpySwap8(void* dest, const void* src){ - char *cdest; - char *csrc; - cdest = (char *) dest; - csrc = (char *) src; - cdest[0] = csrc[7]; - cdest[1] = csrc[6]; - cdest[2] = csrc[5]; - cdest[3] = csrc[4]; - cdest[4] = csrc[3]; - cdest[5] = csrc[2]; - cdest[6] = csrc[1]; - cdest[7] = csrc[0]; -} +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN + /** From CO_SDOserver_initCallbackPre() or NULL */ + void (*pFunctSignalPre)(void *object); + /** From CO_SDOserver_initCallbackPre() or NULL */ + void *functSignalObjectPre; #endif +} CO_SDOserver_t; /** @@ -943,60 +530,49 @@ static inline void CO_memcpySwap8(void* dest, const void* src){ * Function must be called in the communication reset section. * * @param SDO This object will be initialized. - * @param COB_IDClientToServer COB ID for client to server for this SDO object. - * @param COB_IDServerToClient COB ID for server to client for this SDO object. - * @param ObjDictIndex_SDOServerParameter Index in Object dictionary. - * @param parentSDO Pointer to SDO object, which contains object dictionary and - * its extension. For first (default) SDO object this argument must be NULL. - * If this argument is specified, then OD, ODSize and ODExtensions arguments - * are ignored. - * @param OD Pointer to @ref CO_SDO_objectDictionary array defined externally. - * @param ODSize Size of the above array. - * @param ODExtensions Pointer to the externally defined array of the same size - * as ODSize. - * @param nodeId CANopen Node ID of this device. + * @param OD Object Dictionary. + * @param OD_1200_SDOsrvPar OD entry for SDO server parameter (0x1200+), can be + * NULL for default single SDO server and must not be NULL for additional SDO + * servers. With additional SDO servers it may also have IO extension enabled, + * to allow dynamic configuration (see also @ref CO_CONFIG_FLAG_OD_DYNAMIC). + * @param nodeId If this is first SDO channel, then "nodeId" is CANopen Node ID + * of this device. In all additional channels "nodeId" is ignored. * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param CANdevRx CAN device for SDO server reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for SDO server transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. * - * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_SDO_init( - CO_SDO_t *SDO, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient, - uint16_t ObjDictIndex_SDOServerParameter, - CO_SDO_t *parentSDO, - const CO_OD_entry_t OD[], - uint16_t ODSize, - CO_OD_extension_t ODExtensions[], - uint8_t nodeId, - uint16_t SDOtimeoutTime_ms, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx); +CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, + const OD_t *OD, + const OD_entry_t *OD_1200_SDOsrvPar, + uint8_t nodeId, + uint16_t SDOtimeoutTime_ms, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx); -#if ((CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** * Initialize SDOrx callback function. * * Function initializes optional callback function, which should immediately - * start processing of CO_SDO_process() function. + * start processing of CO_SDOserver_process() function. * Callback is called after SDOserver message is received from the CAN bus or * when new call without delay is necessary (SDO block transfer is in progress). * * @param SDO This object. - * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignalPre(). + * Can be NULL * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_SDO_initCallbackPre( - CO_SDO_t *SDO, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, + void *object, + void (*pFunctSignalPre)(void *object)); #endif @@ -1006,160 +582,23 @@ void CO_SDO_initCallbackPre( * Function must be called cyclically. * * @param SDO This object. - * @param NMTisPreOrOperational Different than zero, if #CO_NMT_internalState_t is + * @param NMTisPreOrOperational True if #CO_NMT_internalState_t is * NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. - * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). * - * @return 0: SDO server is idle. - * @return 1: SDO server is in transfer state. - * @return -1: SDO abort just occurred. - */ -int8_t CO_SDO_process( - CO_SDO_t *SDO, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us); - - -/** - * Configure additional functionality to one @ref CO_SDO_objectDictionary entry. - * - * Additional functionality include: @ref CO_SDO_OD_function and - * #CO_SDO_OD_flags_t. It is optional feature and can be used on any object in - * Object dictionary. If OD entry does not exist, function returns silently. - * - * @param SDO This object. - * @param index Index of object in the Object dictionary. - * @param pODFunc Pointer to @ref CO_SDO_OD_function, specified by application. - * If NULL, @ref CO_SDO_OD_function will not be used on this object. - * @param object Pointer to object, which will be passed to @ref CO_SDO_OD_function. - * @param flags Pointer to array of #CO_SDO_OD_flags_t defined externally. If - * zero, #CO_SDO_OD_flags_t will not be used on this OD entry. - * @param flagsSize Size of the above array. It must be equal to number - * of sub-objects in object dictionary entry. Otherwise #CO_SDO_OD_flags_t will - * not be used on this OD entry. - */ -void CO_OD_configure( - CO_SDO_t *SDO, - uint16_t index, - CO_SDO_abortCode_t (*pODFunc)(CO_ODF_arg_t *ODF_arg), - void *object, - uint8_t *flags, - uint8_t flagsSize); - - -/** - * Find object with specific index in Object dictionary. - * - * @param SDO This object. - * @param index Index of the object in Object dictionary. - * - * @return Sequence number of the @ref CO_SDO_objectDictionary entry, 0xFFFF if not found. - */ -uint16_t CO_OD_find(CO_SDO_t *SDO, uint16_t index); - - -/** - * Get length of the given object with specific subIndex. - * - * @param SDO This object. - * @param entryNo Sequence number of OD entry as returned from CO_OD_find(). - * @param subIndex Sub-index of the object in Object dictionary. - * - * @return Data length of the variable. - */ -uint16_t CO_OD_getLength(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex); - - -/** - * Get attribute of the given object with specific subIndex. See #CO_SDO_OD_attributes_t. - * - * If Object Type is array and subIndex is zero, function always returns - * 'read-only' attribute. An exception to this rule is ID1003 (Error field). - * However, this is supposed to be only written by network. - * - * @param SDO This object. - * @param entryNo Sequence number of OD entry as returned from CO_OD_find(). - * @param subIndex Sub-index of the object in Object dictionary. - * - * @return Attribute of the variable. - */ -uint16_t CO_OD_getAttribute(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex); - - -/** - * Get pointer to data of the given object with specific subIndex. - * - * If Object Type is array and subIndex is zero, function returns pointer to - * object->maxSubIndex variable. - * - * @param SDO This object. - * @param entryNo Sequence number of OD entry as returned from CO_OD_find(). - * @param subIndex Sub-index of the object in Object dictionary. - * - * @return Pointer to the variable in @ref CO_SDO_objectDictionary. - */ -void* CO_OD_getDataPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex); - - -/** - * Get pointer to the #CO_SDO_OD_flags_t byte of the given object with - * specific subIndex. - * - * @param SDO This object. - * @param entryNo Sequence number of OD entry as returned from CO_OD_find(). - * @param subIndex Sub-index of the object in Object dictionary. - * - * @return Pointer to the #CO_SDO_OD_flags_t of the variable. - */ -uint8_t* CO_OD_getFlagsPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex); - - -/** - * Initialize SDO transfer. - * - * Find object in OD, verify, fill ODF_arg s. - * - * @param SDO This object. - * @param index Index of the object in Object dictionary. - * @param subIndex subIndex of the object in Object dictionary. - * - * @return 0 on success, otherwise #CO_SDO_abortCode_t. + * @return #CO_SDO_return_t */ -uint32_t CO_SDO_initTransfer(CO_SDO_t *SDO, uint16_t index, uint8_t subIndex); +CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, + bool_t NMTisPreOrOperational, + uint32_t timeDifference_us, + uint32_t *timerNext_us); - -/** - * Read data from @ref CO_SDO_objectDictionary to internal buffer. - * - * ODF_arg s must be initialized before with CO_SDO_initTransfer(). - * @ref CO_SDO_OD_function is called if configured. - * - * @param SDO This object. - * @param SDOBufferSize Total size of the SDO buffer. - * - * @return 0 on success, otherwise #CO_SDO_abortCode_t. - */ -uint32_t CO_SDO_readOD(CO_SDO_t *SDO, uint16_t SDOBufferSize); - - -/** - * Write data from internal buffer to @ref CO_SDO_objectDictionary. - * - * ODF_arg s must be initialized before with CO_SDO_initTransfer(). - * @ref CO_SDO_OD_function is called if configured. - * - * @param SDO This object. - * @param length Length of data (received from network) to write. - * - * @return 0 on success, otherwise #CO_SDO_abortCode_t. - */ -uint32_t CO_SDO_writeOD(CO_SDO_t *SDO, uint16_t length); +/** @} */ /* CO_SDOserver */ #ifdef __cplusplus } #endif /*__cplusplus*/ -/** @} */ -#endif +#endif /* CO_SDO_SERVER_H */ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index dab6fb0d..8b7fd67a 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -864,7 +864,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* setup client */ - SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, 0, 0, gtwa->node); + SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, + CO_CAN_ID_SDO_CLI + gtwa->node, + CO_CAN_ID_SDO_SRV + gtwa->node, + gtwa->node); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; @@ -924,7 +927,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (err) break; /* setup client */ - SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, 0, 0, gtwa->node); + SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, + CO_CAN_ID_SDO_CLI + gtwa->node, + CO_CAN_ID_SDO_SRV + gtwa->node, + gtwa->node); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; @@ -1617,6 +1623,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, ret = CO_SDOclientDownload(gtwa->SDO_C, timeDifference_us, abort, + gtwa->SDOdataCopyStatus, &abortCode, &sizeTransferred, timerNext_us); diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index a0387819..095a8327 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -29,7 +29,6 @@ #include "301/CO_driver.h" #include "301/CO_fifo.h" -#include "301/CO_SDOserver.h" #include "301/CO_SDOclient.h" #include "301/CO_NMT_Heartbeat.h" #include "305/CO_LSSmaster.h" diff --git a/CANopen.c b/CANopen.c index 2c193d22..113afb38 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1,6 +1,5 @@ /* - * Main CANopen stack file. It combines Object dictionary (CO_OD) and all other - * CANopen source files. Configuration information are read from CO_OD.h file. + * Main CANopenNode file. * * @file CANopen.c * @ingroup CO_CANopen @@ -24,572 +23,849 @@ * limitations under the License. */ - #include "CANopen.h" -#include +/* Get values from CO_config_t or from single default OD.h ********************/ +#ifdef CO_MULTIPLE_OD +#define CO_GET_CO(obj) co->obj +#define CO_GET_CNT(obj) co->config->CNT_##obj +#define OD_GET(entry, index) co->config->ENTRY_##entry +#else +#include "OD.h" +#define CO_GET_CO(obj) CO_##obj +#define CO_GET_CNT(obj) CO_CNT_##obj +#define OD_GET(entry, index) OD_ENTRY_##entry + +/* Verify parameters from "OD.h" and calculate necessary values for each object: + * - verify CO_CNT_xx or set default + * - calculate number of CANrx and CYNtx messages: CO_RX_CNT_xx and CO_TX_CNT_xx + * - set optional undefined OD_ENTRY_Hxxxx to NULL. + * - calculate indexes: CO_RX_IDX_xx and CO_TX_IDX_xx + * - calculate total count of CAN message buffers: CO_CNT_ALL_RX_MSGS and + * CO_CNT_ALL_TX_MSGS. */ +#if CO_CNT_NMT != 1 + #error CO_CNT_NMT from OD.h not correct! +#endif +#define CO_RX_CNT_NMT_SLV CO_CNT_NMT +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER + #define CO_TX_CNT_NMT_MST 1 +#else + #define CO_TX_CNT_NMT_MST 0 +#endif -/* Global variables ***********************************************************/ -/* #define CO_USE_GLOBALS */ /* If defined, global variables will be used - instead of dynamically allocated. */ -extern const CO_OD_entry_t CO_OD[CO_OD_NoOfElements]; /* Object Dictionary */ -static CO_t COO; /* Pointers to CANopen objects */ -CO_t *CO = NULL; /* Pointer to COO */ - -static CO_CANrx_t *CO_CANmodule_rxArray0; -static CO_CANtx_t *CO_CANmodule_txArray0; -static CO_OD_extension_t *CO_SDO_ODExtensions; -static CO_HBconsNode_t *CO_HBcons_monitoredNodes; - -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) && !defined CO_GTWA_ENABLE -#define CO_GTWA_ENABLE true -#endif -#if CO_NO_TRACE > 0 -static uint32_t *CO_traceTimeBuffers[CO_NO_TRACE]; -static int32_t *CO_traceValueBuffers[CO_NO_TRACE]; -static uint32_t CO_traceBufferSize[CO_NO_TRACE]; -#endif -#ifndef CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS -#define CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS 0 -#endif - - -/* Verify number of CANopenNode objects from CO_OD.h **************************/ -#if CO_NO_SYNC > 1 \ - || CO_NO_EMERGENCY != 1 \ - || (CO_NO_SDO_SERVER < 1 || CO_NO_SDO_SERVER > 128) \ - || CO_NO_TIME > 1 \ - || CO_NO_SDO_CLIENT > 128 \ - || CO_NO_GFC > 1 \ - || CO_NO_SRDO > 64 \ - || (CO_NO_RPDO < 1 || CO_NO_RPDO > 0x200) \ - || (CO_NO_TPDO < 1 || CO_NO_TPDO > 0x200) \ - || ODL_consumerHeartbeatTime_arrayLength == 0 \ - || ODL_errorStatusBits_stringLength < 10 \ - || CO_NO_LSS_SLAVE > 1 \ - || CO_NO_LSS_MASTER > 1 -#error Features from CO_OD.h file are not corectly configured for this project! -#endif - -/* Indexes of CO_CANrx_t objects in CO_CANmodule_t and total number of them. **/ -#define CO_RXCAN_NMT 0 -#define CO_RXCAN_SYNC (CO_RXCAN_NMT + CO_NO_NMT) -#define CO_RXCAN_EMERG (CO_RXCAN_SYNC + CO_NO_SYNC) -#define CO_RXCAN_TIME (CO_RXCAN_EMERG + CO_NO_EM_CONS) -#define CO_RXCAN_GFC (CO_RXCAN_TIME + CO_NO_TIME) -#define CO_RXCAN_SRDO (CO_RXCAN_GFC + CO_NO_GFC) -#define CO_RXCAN_RPDO (CO_RXCAN_SRDO + CO_NO_SRDO*2) -#define CO_RXCAN_SDO_SRV (CO_RXCAN_RPDO + CO_NO_RPDO) -#define CO_RXCAN_SDO_CLI (CO_RXCAN_SDO_SRV + CO_NO_SDO_SERVER) -#define CO_RXCAN_CONS_HB (CO_RXCAN_SDO_CLI + CO_NO_SDO_CLIENT) -#define CO_RXCAN_LSS_SLV (CO_RXCAN_CONS_HB + CO_NO_HB_CONS) -#define CO_RXCAN_LSS_MST (CO_RXCAN_LSS_SLV + CO_NO_LSS_SLAVE) -#define CO_RXCAN_NO_MSGS (CO_NO_NMT + \ - CO_NO_SYNC + \ - CO_NO_EM_CONS + \ - CO_NO_TIME + \ - CO_NO_GFC + \ - CO_NO_SRDO*2 + \ - CO_NO_RPDO + \ - CO_NO_SDO_SERVER + \ - CO_NO_SDO_CLIENT + \ - CO_NO_HB_CONS + \ - CO_NO_LSS_SLAVE + \ - CO_NO_LSS_MASTER) - -/* Indexes of CO_CANtx_t objects in CO_CANmodule_t and total number of them. **/ -#define CO_TXCAN_NMT 0 -#define CO_TXCAN_SYNC (CO_TXCAN_NMT + CO_NO_NMT_MST) -#define CO_TXCAN_EMERG (CO_TXCAN_SYNC + CO_NO_SYNC) -#define CO_TXCAN_TIME (CO_TXCAN_EMERG + CO_NO_EMERGENCY) -#define CO_TXCAN_GFC (CO_TXCAN_TIME + CO_NO_TIME) -#define CO_TXCAN_SRDO (CO_TXCAN_GFC + CO_NO_GFC) -#define CO_TXCAN_TPDO (CO_TXCAN_SRDO + CO_NO_SRDO*2) -#define CO_TXCAN_SDO_SRV (CO_TXCAN_TPDO + CO_NO_TPDO) -#define CO_TXCAN_SDO_CLI (CO_TXCAN_SDO_SRV + CO_NO_SDO_SERVER) -#define CO_TXCAN_HB (CO_TXCAN_SDO_CLI + CO_NO_SDO_CLIENT) -#define CO_TXCAN_LSS_SLV (CO_TXCAN_HB + CO_NO_HB_PROD) -#define CO_TXCAN_LSS_MST (CO_TXCAN_LSS_SLV + CO_NO_LSS_SLAVE) -#define CO_TXCAN_NO_MSGS (CO_NO_NMT_MST + \ - CO_NO_SYNC + \ - CO_NO_EMERGENCY + \ - CO_NO_TIME + \ - CO_NO_GFC + \ - CO_NO_SRDO*2 + \ - CO_NO_TPDO + \ - CO_NO_SDO_SERVER + \ - CO_NO_SDO_CLIENT + \ - CO_NO_HB_PROD + \ - CO_NO_LSS_SLAVE + \ - CO_NO_LSS_MASTER) - - -/* Create objects from heap ***************************************************/ -#ifndef CO_USE_GLOBALS -CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { - int16_t i; - uint16_t errCnt = 0; - uint32_t CO_memoryUsed = 0; - - /* If CANopen was initialized before, return. */ - if (CO != NULL) { - return CO_ERROR_NO; - } +#if CO_CNT_HB_PROD != 1 + #error CO_CNT_HB_PROD from OD.h not correct! +#endif +#define CO_TX_CNT_HB_PROD CO_CNT_HB_PROD +#if !defined CO_CNT_HB_CONS + #define CO_CNT_HB_CONS 0 +#elif CO_CNT_HB_CONS < 0 || CO_CNT_HB_CONS > 1 + #error CO_CNT_HB_CONS from OD.h not correct! +#endif +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) && CO_CNT_HB_CONS == 1 + #define CO_RX_CNT_HB_CONS CO_CONFIG_HB_CONS_SIZE +#else + #define CO_RX_CNT_HB_CONS 0 +#endif - /* globals */ - CO = &COO; +#if CO_CNT_EM != 1 + #error CO_CNT_EM from OD.h not correct! +#endif +#ifndef OD_ENTRY_H1003 + #define OD_ENTRY_H1003 NULL +#endif +#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + #if CO_CNT_EM_PROD == 1 + #define CO_TX_CNT_EM_PROD CO_CNT_EM_PROD + #else + #error wrong CO_CNT_EM_PROD + #endif + #ifndef OD_ENTRY_H1015 + #define OD_ENTRY_H1015 NULL + #endif +#else + #define CO_TX_CNT_EM_PROD 0 +#endif +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + #define CO_RX_CNT_EM_CONS 1 +#else + #define CO_RX_CNT_EM_CONS 0 +#endif + +#if !defined CO_CNT_SDO_SRV + #define CO_CNT_SDO_SRV 1 + #define OD_ENTRY_H1200 NULL +#elif CO_CNT_SDO_SRV < 1 || CO_CNT_SDO_SRV > 128 + #error CO_CNT_SDO_SRV from OD.h not correct! +#endif +#define CO_RX_CNT_SDO_SRV CO_CNT_SDO_SRV +#define CO_TX_CNT_SDO_SRV CO_CNT_SDO_SRV + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE + #if !defined CO_CNT_SDO_CLI + #define CO_CNT_SDO_CLI 0 + #define OD_ENTRY_H1280 NULL + #elif CO_CNT_SDO_CLI < 0 || CO_CNT_SDO_CLI > 128 + #error CO_CNT_SDO_CLI from OD.h not correct! + #endif + #define CO_RX_CNT_SDO_CLI CO_CNT_SDO_CLI + #define CO_TX_CNT_SDO_CLI CO_CNT_SDO_CLI +#else + #define CO_RX_CNT_SDO_CLI 0 + #define CO_TX_CNT_SDO_CLI 0 +#endif + +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + #if !defined CO_CNT_TIME + #define CO_CNT_TIME 0 + #define OD_ENTRY_H1012 NULL + #elif CO_CNT_TIME < 0 || CO_CNT_TIME > 1 + #error CO_CNT_TIME from OD.h not correct! + #endif + #define CO_RX_CNT_TIME CO_CNT_TIME + #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER + #define CO_TX_CNT_TIME CO_CNT_TIME + #else + #define CO_TX_CNT_TIME 0 + #endif +#else + #define CO_RX_CNT_TIME 0 + #define CO_TX_CNT_TIME 0 +#endif + +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + #if !defined CO_CNT_SYNC + #define CO_CNT_SYNC 0 + #define OD_ENTRY_H1005 NULL + #define OD_ENTRY_H1006 NULL + #elif CO_CNT_SYNC < 0 || CO_CNT_SYNC > 1 + #error CO_CNT_SYNC from OD.h not correct! + #endif + #define CO_RX_CNT_SYNC CO_CNT_SYNC + #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + #define CO_TX_CNT_SYNC CO_CNT_SYNC + #else + #define CO_TX_CNT_SYNC 0 + #endif + #ifndef OD_ENTRY_H1007 + #define OD_ENTRY_H1007 NULL + #endif + #ifndef OD_ENTRY_H1019 + #define OD_ENTRY_H1019 NULL + #endif +#else + #define CO_RX_CNT_SYNC 0 + #define CO_TX_CNT_SYNC 0 +#endif + +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + #if !defined CO_CNT_RPDO + #define CO_CNT_RPDO 0 + #define OD_ENTRY_H1400 NULL + #define OD_ENTRY_H1600 NULL + #elif CO_CNT_RPDO < 0 || CO_CNT_RPDO > 0x200 + #error CO_CNT_RPDO from OD.h not correct! + #endif + #define CO_RX_CNT_RPDO CO_CNT_RPDO +#else + #define CO_RX_CNT_RPDO 0 +#endif + +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + #if !defined CO_CNT_TPDO + #define CO_CNT_TPDO 0 + #define OD_ENTRY_H1800 NULL + #define OD_ENTRY_H1A00 NULL + #elif CO_CNT_TPDO < 0 || CO_CNT_TPDO > 0x200 + #error CO_CNT_TPDO from OD.h not correct! + #endif + #define CO_TX_CNT_TPDO CO_CNT_TPDO +#else + #define CO_TX_CNT_TPDO 0 +#endif - /* CANmodule */ - CO->CANmodule[0] = (CO_CANmodule_t *)calloc(1, sizeof(CO_CANmodule_t)); - if (CO->CANmodule[0] == NULL) errCnt++; - CO_CANmodule_rxArray0 = - (CO_CANrx_t *)calloc(CO_RXCAN_NO_MSGS, sizeof(CO_CANrx_t)); - if (CO_CANmodule_rxArray0 == NULL) errCnt++; - CO_CANmodule_txArray0 = - (CO_CANtx_t *)calloc(CO_TXCAN_NO_MSGS, sizeof(CO_CANtx_t)); - if (CO_CANmodule_txArray0 == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_CANmodule_t) + - sizeof(CO_CANrx_t) * CO_RXCAN_NO_MSGS + - sizeof(CO_CANtx_t) * CO_TXCAN_NO_MSGS; +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + #define CO_CNT_LEDS 1 +#endif + +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + #if !defined CO_CNT_GFC + #define CO_CNT_GFC 0 + #define OD_ENTRY_H1300 NULL + #elif CO_CNT_GFC < 0 || CO_CNT_GFC > 1 + #error CO_CNT_GFC from OD.h not correct! + #endif + #define CO_RX_CNT_GFC CO_CNT_GFC + #define CO_TX_CNT_GFC CO_CNT_GFC +#else + #define CO_RX_CNT_GFC 0 + #define CO_TX_CNT_GFC 0 +#endif + +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + #if !defined CO_CNT_SRDO + #define CO_CNT_SRDO 0 + #define OD_ENTRY_H1301 NULL + #define OD_ENTRY_H1381 NULL + #define OD_ENTRY_H13FE NULL + #define OD_ENTRY_H13FF NULL + #elif CO_CNT_SRDO < 0 || CO_CNT_SRDO > 64 + #error CO_CNT_SRDO from OD.h not correct! + #endif + #define CO_RX_CNT_SRDO CO_CNT_SRDO + #define CO_TX_CNT_SRDO CO_CNT_SRDO +#else + #define CO_RX_CNT_SRDO 0 + #define CO_TX_CNT_SRDO 0 +#endif - /* SDOserver */ - for (i = 0; i < CO_NO_SDO_SERVER; i++) { - CO->SDO[i] = (CO_SDO_t *)calloc(1, sizeof(CO_SDO_t)); - if (CO->SDO[i] == NULL) errCnt++; - } - CO_SDO_ODExtensions = (CO_OD_extension_t *)calloc( - CO_OD_NoOfElements, sizeof(CO_OD_extension_t)); - if (CO_SDO_ODExtensions == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_SDO_t) * CO_NO_SDO_SERVER + - sizeof(CO_OD_extension_t) * CO_OD_NoOfElements; +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + #define CO_CNT_LSS_SLV 1 +#else + #define CO_CNT_LSS_SLV 0 +#endif +#define CO_RX_CNT_LSS_SLV CO_CNT_LSS_SLV +#define CO_TX_CNT_LSS_SLV CO_CNT_LSS_SLV - /* Emergency */ - CO->em = (CO_EM_t *)calloc(1, sizeof(CO_EM_t)); - if (CO->em == NULL) errCnt++; - CO->emPr = (CO_EMpr_t *)calloc(1, sizeof(CO_EMpr_t)); - if (CO->emPr == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_EM_t) + sizeof(CO_EMpr_t); +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + #define CO_CNT_LSS_MST 1 +#else + #define CO_CNT_LSS_MST 0 +#endif +#define CO_RX_CNT_LSS_MST CO_CNT_LSS_MST +#define CO_TX_CNT_LSS_MST CO_CNT_LSS_MST - /* NMT_Heartbeat */ - CO->NMT = (CO_NMT_t *)calloc(1, sizeof(CO_NMT_t)); - if (CO->NMT == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_NMT_t); - -#if CO_NO_SYNC == 1 - /* SYNC */ - CO->SYNC = (CO_SYNC_t *)calloc(1, sizeof(CO_SYNC_t)); - if (CO->SYNC == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_SYNC_t); -#endif - -#if CO_NO_TIME == 1 - /* TIME */ - CO->TIME = (CO_TIME_t *)calloc(1, sizeof(CO_TIME_t)); - if (CO->TIME == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_TIME_t); +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + #define CO_CNT_GTWA 1 +#endif + +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE + #if !defined CO_CNT_TRACE + #define CO_CNT_TRACE 0 + #elif CO_CNT_TRACE < 0 + #error CO_CNT_TRACE from OD.h not correct! + #endif +#endif + +/* Indexes of CO_CANrx_t and CO_CANtx_t objects in CO_CANmodule_t and total + * number of them. Indexes are sorted in a way, that objects with highest + * priority of the CAN identifier are listed first. */ +#define CO_RX_IDX_NMT_SLV 0 +#define CO_RX_IDX_SYNC (CO_RX_IDX_NMT_SLV + CO_RX_CNT_NMT_SLV) +#define CO_RX_IDX_EM_CONS (CO_RX_IDX_SYNC + CO_RX_CNT_SYNC) +#define CO_RX_IDX_TIME (CO_RX_IDX_EM_CONS + CO_RX_CNT_EM_CONS) +#define CO_RX_IDX_GFC (CO_RX_IDX_TIME + CO_RX_CNT_TIME) +#define CO_RX_IDX_SRDO (CO_RX_IDX_GFC + CO_RX_CNT_GFC) +#define CO_RX_IDX_RPDO (CO_RX_IDX_SRDO + CO_RX_CNT_SRDO * 2) +#define CO_RX_IDX_SDO_SRV (CO_RX_IDX_RPDO + CO_RX_CNT_RPDO) +#define CO_RX_IDX_SDO_CLI (CO_RX_IDX_SDO_SRV + CO_RX_CNT_SDO_SRV) +#define CO_RX_IDX_HB_CONS (CO_RX_IDX_SDO_CLI + CO_RX_CNT_SDO_CLI) +#define CO_RX_IDX_LSS_SLV (CO_RX_IDX_HB_CONS + CO_RX_CNT_HB_CONS) +#define CO_RX_IDX_LSS_MST (CO_RX_IDX_LSS_SLV + CO_RX_CNT_LSS_SLV) +#define CO_CNT_ALL_RX_MSGS (CO_RX_IDX_LSS_MST + CO_RX_CNT_LSS_MST) + +#define CO_TX_IDX_NMT_MST 0 +#define CO_TX_IDX_SYNC (CO_TX_IDX_NMT_MST + CO_TX_CNT_NMT_MST) +#define CO_TX_IDX_EM_PROD (CO_TX_IDX_SYNC + CO_TX_CNT_SYNC) +#define CO_TX_IDX_TIME (CO_TX_IDX_EM_PROD + CO_TX_CNT_EM_PROD) +#define CO_TX_IDX_GFC (CO_TX_IDX_TIME + CO_TX_CNT_TIME) +#define CO_TX_IDX_SRDO (CO_TX_IDX_GFC + CO_TX_CNT_GFC) +#define CO_TX_IDX_TPDO (CO_TX_IDX_SRDO + CO_TX_CNT_SRDO * 2) +#define CO_TX_IDX_SDO_SRV (CO_TX_IDX_TPDO + CO_TX_CNT_TPDO) +#define CO_TX_IDX_SDO_CLI (CO_TX_IDX_SDO_SRV + CO_TX_CNT_SDO_SRV) +#define CO_TX_IDX_HB_PROD (CO_TX_IDX_SDO_CLI + CO_TX_CNT_SDO_CLI) +#define CO_TX_IDX_LSS_SLV (CO_TX_IDX_HB_PROD + CO_TX_CNT_HB_PROD) +#define CO_TX_IDX_LSS_MST (CO_TX_IDX_LSS_SLV + CO_TX_CNT_LSS_SLV) +#define CO_CNT_ALL_TX_MSGS (CO_TX_IDX_LSS_MST + CO_TX_CNT_LSS_MST) +#endif /* #ifdef #else CO_MULTIPLE_OD */ + + +/* Objects from heap **********************************************************/ +#ifndef CO_USE_GLOBALS +#include + +#ifdef CO_MULTIPLE_OD +#define ON_MULTI_OD(sentence) sentence +#else +#define ON_MULTI_OD(sentence) +#endif + +CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { + CO_t *co = NULL; + /* return values */ + CO_t *coFinal = NULL; + uint32_t mem = 0; + + /* For each object: + * - allocate memory, verify allocation and calculate size of heap used + * - if CO_MULTIPLE_OD is defined: + * - use config structure + * - calculate number of CANrx and CYNtx messages: RX_CNT_xx and TX_CNT_xx + * - calculate indexes: RX_IDX_xx and TX_IDX_xx + * - calculate total count of CAN message buffers: CNT_ALL_RX_MSGS and + * CNT_ALL_TX_MSGS. */ + + do { +#ifdef CO_MULTIPLE_OD + /* verify arguments */ + if (config == NULL || config->CNT_NMT > 1 || config->CNT_HB_CONS > 1 + || config->CNT_EM > 1 || config->CNT_SDO_SRV > 128 + || config->CNT_SDO_CLI > 128 || config->CNT_SYNC > 1 + || config->CNT_RPDO > 512 || config->CNT_TPDO > 512 + || config->CNT_TIME > 1 || config->CNT_LEDS > 1 + || config->CNT_GFC > 1 || config->CNT_SRDO > 64 + || config->CNT_LSS_SLV > 1 || config->CNT_LSS_MST > 1 + || config->CNT_GTWA > 1 + ) { + break; + } #else - CO->TIME = NULL; + (void) config; +#endif + + /* CANopen object */ + void *p = calloc(1, sizeof(CO_t)); + if (p == NULL) break; + else co = (CO_t *)p; + mem += sizeof(CO_t); + +#ifdef CO_MULTIPLE_OD + co->config = config; +#endif + + /* NMT_Heartbeat */ + ON_MULTI_OD(uint8_t RX_CNT_NMT_SLV = 0); + ON_MULTI_OD(uint8_t TX_CNT_NMT_MST = 0); + ON_MULTI_OD(uint8_t TX_CNT_HB_PROD = 0); + if (CO_GET_CNT(NMT) == 1) { + p = calloc(1, sizeof(CO_NMT_t)); + if (p == NULL) break; + else co->NMT = (CO_NMT_t *)p; + mem += sizeof(CO_NMT_t); + ON_MULTI_OD(RX_CNT_NMT_SLV = 1); + #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER + ON_MULTI_OD(TX_CNT_NMT_MST = 1); + #endif + ON_MULTI_OD(TX_CNT_HB_PROD = 1); + } + +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + ON_MULTI_OD(uint8_t RX_CNT_HB_CONS = 0); + if (CO_GET_CNT(HB_CONS) == 1) { + p = calloc(1, sizeof(CO_HBconsumer_t)); + if (p == NULL) break; + else co->HBcons = (CO_HBconsumer_t *)p; + mem += sizeof(CO_HBconsumer_t); + ON_MULTI_OD(RX_CNT_HB_CONS = CO_CONFIG_HB_CONS_SIZE); + } +#endif + + /* Emergency */ + ON_MULTI_OD(uint8_t RX_CNT_EM_CONS = 0); + ON_MULTI_OD(uint8_t TX_CNT_EM_PROD = 0); + if (CO_GET_CNT(EM) == 1) { + p = calloc(1, sizeof(CO_EM_t)); + if (p == NULL) break; + else co->em = (CO_EM_t *)p; + mem += sizeof(CO_EM_t); + #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + ON_MULTI_OD(RX_CNT_EM_CONS = 1); + #endif + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + ON_MULTI_OD(TX_CNT_EM_PROD = 1); + #endif + } + + /* SDOserver */ + ON_MULTI_OD(uint8_t RX_CNT_SDO_SRV = 0); + ON_MULTI_OD(uint8_t TX_CNT_SDO_SRV = 0); + if (CO_GET_CNT(SDO_SRV) > 0) { + p = calloc(CO_GET_CNT(SDO_SRV), sizeof(CO_SDOserver_t)); + if (p == NULL) break; + else co->SDOserver = (CO_SDOserver_t *)p; + mem += sizeof(CO_SDOserver_t) * CO_GET_CNT(SDO_SRV); + ON_MULTI_OD(RX_CNT_SDO_SRV = config->CNT_SDO_SRV); + ON_MULTI_OD(TX_CNT_SDO_SRV = config->CNT_SDO_SRV); + } + +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE + ON_MULTI_OD(uint8_t RX_CNT_SDO_CLI = 0); + ON_MULTI_OD(uint8_t TX_CNT_SDO_CLI = 0); + if (CO_GET_CNT(SDO_CLI) > 0) { + p = calloc(CO_GET_CNT(SDO_CLI), sizeof(CO_SDOclient_t)); + if (p == NULL) break; + else co->SDOclient = (CO_SDOclient_t *)p; + mem += sizeof(CO_SDOclient_t) * CO_GET_CNT(SDO_CLI); + ON_MULTI_OD(RX_CNT_SDO_CLI = config->CNT_SDO_CLI); + ON_MULTI_OD(TX_CNT_SDO_CLI = config->CNT_SDO_CLI); + } #endif -#if CO_NO_GFC == 1 - CO->GFC = (CO_GFC_t *)calloc(1, sizeof(CO_GFC_t)); - if (CO->GFC == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_GFC_t); +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + ON_MULTI_OD(uint8_t RX_CNT_TIME = 0); + ON_MULTI_OD(uint8_t TX_CNT_TIME = 0); + if (CO_GET_CNT(TIME) == 1) { + p = calloc(1, sizeof(CO_TIME_t)); + if (p == NULL) break; + else co->TIME = (CO_TIME_t *)p; + mem += sizeof(CO_TIME_t); + ON_MULTI_OD(RX_CNT_TIME = 1); + #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER + ON_MULTI_OD(TX_CNT_TIME = 1); + #endif + } #endif -#if CO_NO_SRDO != 0 - /* SRDO */ - CO->SRDOGuard = (CO_SRDOGuard_t *)calloc(1, sizeof(CO_SRDOGuard_t)); - if (CO->SRDOGuard == NULL) errCnt++; - for (i = 0; i < CO_NO_SRDO; i++) { - CO->SRDO[i] = (CO_SRDO_t *)calloc(1, sizeof(CO_SRDO_t)); - if (CO->SRDO[i] == NULL) errCnt++; - } - CO_memoryUsed += sizeof(CO_SRDO_t) * CO_NO_SRDO + sizeof(CO_SRDOGuard_t); +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + ON_MULTI_OD(uint8_t RX_CNT_SYNC = 0); + ON_MULTI_OD(uint8_t TX_CNT_SYNC = 0); + if (CO_GET_CNT(SYNC) == 1) { + p = calloc(1, sizeof(CO_SYNC_t)); + if (p == NULL) break; + else co->SYNC = (CO_SYNC_t *)p; + mem += sizeof(CO_SYNC_t); + ON_MULTI_OD(RX_CNT_SYNC = 1); + #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + ON_MULTI_OD(TX_CNT_SYNC = 1); + #endif + } #endif - /* RPDO */ - for (i = 0; i < CO_NO_RPDO; i++) { - CO->RPDO[i] = (CO_RPDO_t *)calloc(1, sizeof(CO_RPDO_t)); - if (CO->RPDO[i] == NULL) errCnt++; - } - CO_memoryUsed += sizeof(CO_RPDO_t) * CO_NO_RPDO; - /* TPDO */ - for (i = 0; i < CO_NO_TPDO; i++) { - CO->TPDO[i] = (CO_TPDO_t *)calloc(1, sizeof(CO_TPDO_t)); - if (CO->TPDO[i] == NULL) errCnt++; - } - CO_memoryUsed += sizeof(CO_TPDO_t) * CO_NO_TPDO; - - /* Heartbeat consumer */ - CO->HBcons = (CO_HBconsumer_t *)calloc(1, sizeof(CO_HBconsumer_t)); - if (CO->HBcons == NULL) errCnt++; - CO_HBcons_monitoredNodes = - (CO_HBconsNode_t *)calloc(CO_NO_HB_CONS, sizeof(CO_HBconsNode_t)); - if (CO_HBcons_monitoredNodes == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_HBconsumer_t) + - sizeof(CO_HBconsNode_t) * CO_NO_HB_CONS; - -#if CO_NO_SDO_CLIENT != 0 - /* SDOclient */ - for (i = 0; i < CO_NO_SDO_CLIENT; i++) { - CO->SDOclient[i] = - (CO_SDOclient_t *)calloc(1, sizeof(CO_SDOclient_t)); - if (CO->SDOclient[i] == NULL) errCnt++; - } - CO_memoryUsed += sizeof(CO_SDOclient_t) * CO_NO_SDO_CLIENT; +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + ON_MULTI_OD(uint16_t RX_CNT_RPDO = 0); + if (CO_GET_CNT(RPDO) > 0) { + p = calloc(CO_GET_CNT(RPDO), sizeof(CO_RPDO_t)); + if (p == NULL) break; + else co->RPDO = (CO_RPDO_t *)p; + mem += sizeof(CO_RPDO_t) * CO_GET_CNT(RPDO); + ON_MULTI_OD(co->CNT_RPDO = config->CNT_RPDO); + ON_MULTI_OD(RX_CNT_RPDO = config->CNT_RPDO); + } +#endif + +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + ON_MULTI_OD(uint16_t TX_CNT_TPDO = 0); + if (CO_GET_CNT(TPDO) > 0) { + p = calloc(CO_GET_CNT(TPDO), sizeof(CO_TPDO_t)); + if (p == NULL) break; + else co->TPDO = (CO_TPDO_t *)p; + mem += sizeof(CO_TPDO_t) * CO_GET_CNT(TPDO); + ON_MULTI_OD(co->CNT_TPDO = config->CNT_TPDO); + ON_MULTI_OD(TX_CNT_TPDO = config->CNT_TPDO); + } #endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE - /* LEDs */ - CO->LEDs = (CO_LEDs_t *)calloc(1, sizeof(CO_LEDs_t)); - if (CO->LEDs == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_LEDs_t); + if (CO_GET_CNT(LEDS) == 1) { + p = calloc(1, sizeof(CO_LEDs_t)); + if (p == NULL) break; + else co->LEDs = (CO_LEDs_t *)p; + mem += sizeof(CO_LEDs_t); + } #endif -#if CO_NO_LSS_SLAVE == 1 - /* LSSslave */ - CO->LSSslave = (CO_LSSslave_t *)calloc(1, sizeof(CO_LSSslave_t)); - if (CO->LSSslave == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_LSSslave_t); +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + ON_MULTI_OD(uint8_t RX_CNT_GFC = 0); + ON_MULTI_OD(uint8_t TX_CNT_GFC = 0); + if (CO_GET_CNT(GFC) == 1) { + p = calloc(1, sizeof(CO_GFC_t)); + if (p == NULL) break; + else co->GFC = (CO_GFC_t *)p; + mem += sizeof(CO_GFC_t); + ON_MULTI_OD(RX_CNT_GFC = 1); + ON_MULTI_OD(TX_CNT_GFC = 1); + } #endif -#if CO_NO_LSS_MASTER == 1 - /* LSSmaster */ - CO->LSSmaster = (CO_LSSmaster_t *)calloc(1, sizeof(CO_LSSmaster_t)); - if (CO->LSSmaster == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_LSSmaster_t); +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + ON_MULTI_OD(uint8_t RX_CNT_SRDO = 0); + ON_MULTI_OD(uint8_t TX_CNT_SRDO = 0); + if (CO_GET_CNT(SRDO) > 0) { + p = calloc(1, sizeof(CO_SRDOGuard_t)); + if (p == NULL) break; + else co->SRDOGuard = (CO_SRDOGuard_t *)p; + mem += sizeof(CO_SRDOGuard_t); + p = calloc(CO_GET_CNT(SRDO), sizeof(CO_SRDO_t)); + if (p == NULL) break; + else co->SRDO = (CO_SRDO_t *)p; + mem += sizeof(CO_SRDO_t) * CO_GET_CNT(SRDO); + ON_MULTI_OD(RX_CNT_SRDO = config->CNT_SRDO * 2); + ON_MULTI_OD(TX_CNT_SRDO = config->CNT_SRDO * 2); + } +#endif + +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + ON_MULTI_OD(uint8_t RX_CNT_LSS_SLV = 0); + ON_MULTI_OD(uint8_t TX_CNT_LSS_SLV = 0); + if (CO_GET_CNT(LSS_SLV) == 1) { + p = calloc(1, sizeof(CO_LSSslave_t)); + if (p == NULL) break; + else co->LSSslave = (CO_LSSslave_t *)p; + mem += sizeof(CO_LSSslave_t); + ON_MULTI_OD(RX_CNT_LSS_SLV = 1); + ON_MULTI_OD(TX_CNT_LSS_SLV = 1); + } +#endif + +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + ON_MULTI_OD(uint8_t RX_CNT_LSS_MST = 0); + ON_MULTI_OD(uint8_t TX_CNT_LSS_MST = 0); + if (CO_GET_CNT(LSS_MST) == 1) { + p = calloc(1, sizeof(CO_LSSmaster_t)); + if (p == NULL) break; + else co->LSSmaster = (CO_LSSmaster_t *)p; + mem += sizeof(CO_LSSmaster_t); + ON_MULTI_OD(RX_CNT_LSS_MST = 1); + ON_MULTI_OD(TX_CNT_LSS_MST = 1); + } #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - /* Gateway-ascii */ - CO->gtwa = (CO_GTWA_t *)calloc(1, sizeof(CO_GTWA_t)); - if (CO->gtwa == NULL) errCnt++; - CO_memoryUsed += sizeof(CO_GTWA_t); + if (CO_GET_CNT(GTWA) == 1) { + p = calloc(1, sizeof(CO_GTWA_t)); + if (p == NULL) break; + else co->gtwa = (CO_GTWA_t *)p; + mem += sizeof(CO_GTWA_t); + } #endif -#if CO_NO_TRACE > 0 - /* Trace */ - for (i = 0; i < CO_NO_TRACE; i++) { - CO->trace[i] = (CO_trace_t *)calloc(1, sizeof(CO_trace_t)); - if (CO->trace[i] == NULL) errCnt++; - } - CO_memoryUsed += sizeof(CO_trace_t) * CO_NO_TRACE; - for (i = 0; i < CO_NO_TRACE; i++) { - CO_traceTimeBuffers[i] = - (uint32_t *)calloc(OD_traceConfig[i].size, sizeof(uint32_t)); - CO_traceValueBuffers[i] = - (int32_t *)calloc(OD_traceConfig[i].size, sizeof(int32_t)); - if (CO_traceTimeBuffers[i] != NULL && - CO_traceValueBuffers[i] != NULL) { - CO_traceBufferSize[i] = OD_traceConfig[i].size; - } else { - CO_traceBufferSize[i] = 0; +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE + if (CO_GET_CNT(TRACE) > 0) { + p = calloc(CO_GET_CNT(TRACE), sizeof(CO_trace_t)); + if (p == NULL) break; + else co->trace = (CO_trace_t *)p; + mem += sizeof(CO_trace_t) * CO_GET_CNT(TRACE); } - CO_memoryUsed += CO_traceBufferSize[i] * sizeof(uint32_t) * 2; - } #endif - if(heapMemoryUsed != NULL) { - *heapMemoryUsed = CO_memoryUsed; - } +#ifdef CO_MULTIPLE_OD + /* Indexes of CO_CANrx_t and CO_CANtx_t objects in CO_CANmodule_t and + * total number of them. Indexes are sorted in a way, that objects with + * highest priority of the CAN identifier are listed first. */ + int16_t idxRx = 0; + co->RX_IDX_NMT_SLV = idxRx; idxRx += RX_CNT_NMT_SLV; +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + co->RX_IDX_SYNC = idxRx; idxRx += RX_CNT_SYNC; +#endif + co->RX_IDX_EM_CONS = idxRx; idxRx += RX_CNT_EM_CONS; +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + co->RX_IDX_TIME = idxRx; idxRx += RX_CNT_TIME; +#endif +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + co->RX_IDX_GFC = idxRx; idxRx += RX_CNT_GFC; +#endif +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + co->RX_IDX_SRDO = idxRx; idxRx += RX_CNT_SRDO * 2; +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + co->RX_IDX_RPDO = idxRx; idxRx += RX_CNT_RPDO; +#endif + co->RX_IDX_SDO_SRV = idxRx; idxRx += RX_CNT_SDO_SRV; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE + co->RX_IDX_SDO_CLI = idxRx; idxRx += RX_CNT_SDO_CLI; +#endif +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + co->RX_IDX_HB_CONS = idxRx; idxRx += RX_CNT_HB_CONS; +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + co->RX_IDX_LSS_SLV = idxRx; idxRx += RX_CNT_LSS_SLV; +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + co->RX_IDX_LSS_MST = idxRx; idxRx += RX_CNT_LSS_MST; +#endif + co->CNT_ALL_RX_MSGS = idxRx; - return (errCnt == 0) ? CO_ERROR_NO : CO_ERROR_OUT_OF_MEMORY; -} + int16_t idxTx = 0; + co->TX_IDX_NMT_MST = idxTx; idxTx += TX_CNT_NMT_MST; +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + co->TX_IDX_SYNC = idxTx; idxTx += TX_CNT_SYNC; +#endif + co->TX_IDX_EM_PROD = idxTx; idxTx += TX_CNT_EM_PROD; +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + co->TX_IDX_TIME = idxTx; idxTx += TX_CNT_TIME; +#endif +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + co->TX_IDX_GFC = idxTx; idxTx += TX_CNT_GFC; +#endif +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + co->TX_IDX_SRDO = idxTx; idxTx += TX_CNT_SRDO * 2; +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + co->TX_IDX_TPDO = idxTx; idxTx += TX_CNT_TPDO; +#endif + co->TX_IDX_SDO_SRV = idxTx; idxTx += TX_CNT_SDO_SRV; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE + co->TX_IDX_SDO_CLI = idxTx; idxTx += TX_CNT_SDO_CLI; +#endif + co->TX_IDX_HB_PROD = idxTx; idxTx += TX_CNT_HB_PROD; +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + co->TX_IDX_LSS_SLV = idxTx; idxTx += TX_CNT_LSS_SLV; +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + co->TX_IDX_LSS_MST = idxTx; idxTx += TX_CNT_LSS_MST; +#endif + co->CNT_ALL_TX_MSGS = idxTx; +#endif /* #ifdef CO_MULTIPLE_OD */ + /* CANmodule */ + p = calloc(1, sizeof(CO_CANmodule_t)); + if (p == NULL) break; + else co->CANmodule = (CO_CANmodule_t *)p; + mem += sizeof(CO_CANmodule_t); + p = calloc(CO_GET_CO(CNT_ALL_RX_MSGS), sizeof(CO_CANrx_t)); + if (p == NULL) break; + else co->CANrx = (CO_CANrx_t *)p; + mem += sizeof(CO_CANrx_t) * CO_GET_CO(CNT_ALL_RX_MSGS); + p = calloc(CO_GET_CO(CNT_ALL_TX_MSGS), sizeof(CO_CANtx_t)); + if (p == NULL) break; + else co->CANtx = (CO_CANtx_t *)p; + mem += sizeof(CO_CANtx_t) * CO_GET_CO(CNT_ALL_TX_MSGS); -/******************************************************************************/ -void CO_delete(void *CANptr) { - int16_t i; + /* finish successfully, set other parameters */ + co->nodeIdUnconfigured = true; + coFinal = co; + } while(false); - CO_CANsetConfigurationMode(CANptr); + if (coFinal == NULL) CO_delete(co); + + if (heapMemoryUsed != NULL) *heapMemoryUsed = mem; - /* If CANopen isn't initialized, return. */ - if (CO == NULL) { + return coFinal; +} + +void CO_delete(CO_t *co) { + if (co == NULL) { return; } - CO_CANmodule_disable(CO->CANmodule[0]); + CO_CANmodule_disable(co->CANmodule); -#if CO_NO_TRACE > 0 - /* Trace */ - for (i = 0; i < CO_NO_TRACE; i++) { - free(CO->trace[i]); - free(CO_traceTimeBuffers[i]); - free(CO_traceValueBuffers[i]); - } + /* CANmodule */ + free(co->CANtx); + free(co->CANrx); + free(co->CANmodule); + +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE + free(co->trace); #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - /* Gateway-ascii */ - free(CO->gtwa); + free(co->gtwa); #endif -#if CO_NO_LSS_MASTER == 1 - /* LSSmaster */ - free(CO->LSSmaster); +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + free(co->LSSmaster); #endif -#if CO_NO_LSS_SLAVE == 1 - /* LSSslave */ - free(CO->LSSslave); +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + free(co->LSSslave); #endif -#if CO_NO_SDO_CLIENT != 0 - /* SDOclient */ - for (i = 0; i < CO_NO_SDO_CLIENT; i++) { - free(CO->SDOclient[i]); - } +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + free(co->SRDO); + free(co->SRDOGuard); #endif - /* Heartbeat consumer */ - free(CO_HBcons_monitoredNodes); - free(CO->HBcons); +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + free(co->GFC); +#endif -#if CO_NO_GFC == 1 - /* GFC */ - free(CO->GFC); +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + free(co->LEDs); #endif -#if CO_NO_SRDO != 0 - /* SRDO */ - for (i = 0; i < CO_NO_SRDO; i++) { - free(CO->SRDO[i]); - } - free(CO->SRDOGuard); +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + free(co->TPDO); #endif - /* TPDO */ - for (i = 0; i < CO_NO_TPDO; i++) { - free(CO->TPDO[i]); - } +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + free(co->RPDO); +#endif - /* RPDO */ - for (i = 0; i < CO_NO_RPDO; i++) { - free(CO->RPDO[i]); - } +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + free(co->SYNC); +#endif -#if CO_NO_TIME == 1 - /* TIME */ - free(CO->TIME); +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + free(co->TIME); #endif -#if CO_NO_SYNC == 1 - /* SYNC */ - free(CO->SYNC); +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE + free(co->SDOclient); #endif - /* NMT_Heartbeat */ - free(CO->NMT); + /* SDOserver */ + free(co->SDOserver); /* Emergency */ - free(CO->emPr); - free(CO->em); + free(co->em); - /* SDOserver */ - free(CO_SDO_ODExtensions); - for (i = 0; i < CO_NO_SDO_SERVER; i++) { - free(CO->SDO[i]); - } +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + free(co->HBcons); +#endif - /* CANmodule */ - free(CO_CANmodule_txArray0); - free(CO_CANmodule_rxArray0); - free(CO->CANmodule[0]); + /* NMT_Heartbeat */ + free(co->NMT); - /* globals */ - CO = NULL; + /* CANopen object */ + free(co); } #endif /* #ifndef CO_USE_GLOBALS */ -/* Alternatively create objects as globals ************************************/ +/* Objects as globals *********************************************************/ #ifdef CO_USE_GLOBALS - static CO_CANmodule_t COO_CANmodule; - static CO_CANrx_t COO_CANmodule_rxArray0[CO_RXCAN_NO_MSGS]; - static CO_CANtx_t COO_CANmodule_txArray0[CO_TXCAN_NO_MSGS]; - static CO_SDO_t COO_SDO[CO_NO_SDO_SERVER]; - static CO_OD_extension_t COO_SDO_ODExtensions[CO_OD_NoOfElements]; - static CO_EM_t COO_EM; - static CO_EMpr_t COO_EMpr; - static CO_NMT_t COO_NMT; -#if CO_NO_SYNC == 1 - static CO_SYNC_t COO_SYNC; -#endif -#if CO_NO_TIME == 1 - static CO_TIME_t COO_TIME; -#endif -#if CO_NO_GFC == 1 - static CO_GFC_t COO_GFC; -#endif -#if CO_NO_SRDO != 0 - static CO_SRDOGuard_t COO_SRDOGuard; - static CO_SRDO_t COO_SRDO[CO_NO_SRDO]; -#endif - static CO_RPDO_t COO_RPDO[CO_NO_RPDO]; - static CO_TPDO_t COO_TPDO[CO_NO_TPDO]; - static CO_HBconsumer_t COO_HBcons; - static CO_HBconsNode_t COO_HBcons_monitoredNodes[CO_NO_HB_CONS]; -#if CO_NO_SDO_CLIENT != 0 - static CO_SDOclient_t COO_SDOclient[CO_NO_SDO_CLIENT]; + #ifdef CO_MULTIPLE_OD + #error CO_MULTIPLE_OD can not be used with CO_USE_GLOBALS + #endif + static CO_t COO; + static CO_CANmodule_t COO_CANmodule; + static CO_CANrx_t COO_CANmodule_rxArray[CO_CNT_ALL_RX_MSGS]; + static CO_CANtx_t COO_CANmodule_txArray[CO_CNT_ALL_TX_MSGS]; + static CO_NMT_t COO_NMT; +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + static CO_HBconsumer_t COO_HBcons; +#endif + static CO_EM_t COO_EM; + static CO_SDOserver_t COO_SDOserver[CO_CNT_SDO_SRV]; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE + static CO_SDOclient_t COO_SDOclient[CO_CNT_SDO_CLI]; +#endif +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + static CO_TIME_t COO_TIME; +#endif +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + static CO_SYNC_t COO_SYNC; +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + static CO_RPDO_t COO_RPDO[CO_CNT_RPDO]; +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + static CO_TPDO_t COO_TPDO[CO_CNT_TPDO]; #endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE - static CO_LEDs_t COO_LEDs; + static CO_LEDs_t COO_LEDs; +#endif +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + static CO_GFC_t COO_GFC; #endif -#if CO_NO_LSS_SLAVE == 1 - static CO_LSSslave_t COO_LSSslave; +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + static CO_SRDOGuard_t COO_SRDOGuard; + static CO_SRDO_t COO_SRDO[CO_CNT_SRDO]; #endif -#if CO_NO_LSS_MASTER == 1 - static CO_LSSmaster_t COO_LSSmaster; +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + static CO_LSSslave_t COO_LSSslave; +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + static CO_LSSmaster_t COO_LSSmaster; #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - static CO_GTWA_t COO_gtwa; + static CO_GTWA_t COO_gtwa; #endif -#if CO_NO_TRACE > 0 +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE #ifndef CO_TRACE_BUFFER_SIZE_FIXED #define CO_TRACE_BUFFER_SIZE_FIXED 100 #endif - static CO_trace_t COO_trace[CO_NO_TRACE]; - static uint32_t COO_traceTimeBuffers[CO_NO_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; - static int32_t COO_traceValueBuffers[CO_NO_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; + static CO_trace_t COO_trace[CO_CNT_TRACE]; + static uint32_t COO_traceTimeBuffers[CO_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; + static int32_t COO_traceValueBuffers[CO_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; #endif -CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed) { - int16_t i; - - /* If CANopen was initialized before, return. */ - if (CO != NULL) { - return CO_ERROR_NO; - } - - /* globals */ - CO = &COO; - - /* CANmodule */ - CO->CANmodule[0] = &COO_CANmodule; - CO_CANmodule_rxArray0 = &COO_CANmodule_rxArray0[0]; - CO_CANmodule_txArray0 = &COO_CANmodule_txArray0[0]; +CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { + (void)config; (void)heapMemoryUsed; - /* SDOserver */ - for (i = 0; i < CO_NO_SDO_SERVER; i++) { - CO->SDO[i] = &COO_SDO[i]; - } - CO_SDO_ODExtensions = &COO_SDO_ODExtensions[0]; + CO_t *co = &COO; - /* Emergency */ - CO->em = &COO_EM; - CO->emPr = &COO_EMpr; + co->CANmodule = &COO_CANmodule; + co->CANrx = &COO_CANmodule_rxArray[0]; + co->CANtx = &COO_CANmodule_txArray[0]; - /* NMT_Heartbeat */ - CO->NMT = &COO_NMT; - -#if CO_NO_SYNC == 1 - /* SYNC */ - CO->SYNC = &COO_SYNC; + co->NMT = &COO_NMT; +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + co->HBcons = &COO_HBcons; #endif - -#if CO_NO_TIME == 1 - /* TIME */ - CO->TIME = &COO_TIME; -#else - CO->TIME = NULL; + co->em = &COO_EM; + co->SDOserver = &COO_SDOserver[0]; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE + co->SDOclient = &COO_SDOclient[0]; #endif - -#if CO_NO_GFC == 1 - /* GFC */ - CO->GFC = &COO_GFC; +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + co->TIME = &COO_TIME; #endif - -#if CO_NO_SRDO != 0 - /* SRDO */ - CO->SRDOGuard = &COO_SRDOGuard; - for (i = 0; i < CO_NO_SRDO; i++) { - CO->SRDO[i] = &COO_SRDO[i]; - } +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + co->SYNC = &COO_SYNC; #endif - - /* RPDO */ - for (i = 0; i < CO_NO_RPDO; i++) { - CO->RPDO[i] = &COO_RPDO[i]; - } - - /* TPDO */ - for (i = 0; i < CO_NO_TPDO; i++) { - CO->TPDO[i] = &COO_TPDO[i]; - } - - /* Heartbeat consumer */ - CO->HBcons = &COO_HBcons; - CO_HBcons_monitoredNodes = &COO_HBcons_monitoredNodes[0]; - -#if CO_NO_SDO_CLIENT != 0 - /* SDOclient */ - for (i = 0; i < CO_NO_SDO_CLIENT; i++) { - CO->SDOclient[i] = &COO_SDOclient[i]; - } +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + co->RPDO = &COO_RPDO[0]; +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + co->TPDO = &COO_TPDO[0]; #endif - #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE - /* LEDs */ - CO->LEDs = &COO_LEDs; + co->LEDs = &COO_LEDs; #endif - -#if CO_NO_LSS_SLAVE == 1 - /* LSSslave */ - CO->LSSslave = &COO_LSSslave; +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + co->GFC = &COO_GFC; #endif - -#if CO_NO_LSS_MASTER == 1 - /* LSSmaster */ - CO->LSSmaster = &COO_LSSmaster; +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + co->SRDOGuard = &COO_SRDOGuard; + co->SRDO = &COO_SRDO[0]; +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + co->LSSslave = &COO_LSSslave; +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + co->LSSmaster = &COO_LSSmaster; #endif - #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - /* Gateway-ascii */ - CO->gtwa = &COO_gtwa; + co->gtwa = &COO_gtwa; #endif - -#if CO_NO_TRACE > 0 - /* Trace */ - for (i = 0; i < CO_NO_TRACE; i++) { - CO->trace[i] = &COO_trace[i]; - CO_traceTimeBuffers[i] = &COO_traceTimeBuffers[i][0]; - CO_traceValueBuffers[i] = &COO_traceValueBuffers[i][0]; - CO_traceBufferSize[i] = CO_TRACE_BUFFER_SIZE_FIXED; - } +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE + co->trace = &COO_trace[0]; + co->traceTimeBuffers = &COO_traceTimeBuffers[0][0]; + co->traceValueBuffers = &COO_traceValueBuffers[0][0]; + co->traceBufferSize = CO_TRACE_BUFFER_SIZE_FIXED; #endif - return CO_ERROR_NO; + return co; } +void CO_delete(CO_t *co) { + if (co == NULL) { + return; + } -/******************************************************************************/ -void CO_delete(void *CANptr) { - CO_CANsetConfigurationMode(CANptr); - - /* globals */ - CO = NULL; + CO_CANmodule_disable(co->CANmodule); } #endif /* #ifdef CO_USE_GLOBALS */ +/* Helper functions ***********************************************************/ +bool_t CO_isLSSslaveEnabled(CO_t *co) { + (void) co; /* may be unused */ + bool_t en = false; +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + if (CO_GET_CNT(LSS_SLV) == 1) en = true; +#endif + return en; +} /******************************************************************************/ -CO_ReturnError_t CO_CANinit(void *CANptr, - uint16_t bitRate) -{ +CO_ReturnError_t CO_CANinit(CO_t *co, void *CANptr, uint16_t bitRate) { CO_ReturnError_t err; - CO->CANmodule[0]->CANnormal = false; + if (co == NULL) return CO_ERROR_ILLEGAL_ARGUMENT; + + co->CANmodule->CANnormal = false; CO_CANsetConfigurationMode(CANptr); /* CANmodule */ - err = CO_CANmodule_init(CO->CANmodule[0], + err = CO_CANmodule_init(co->CANmodule, CANptr, - CO_CANmodule_rxArray0, - CO_RXCAN_NO_MSGS, - CO_CANmodule_txArray0, - CO_TXCAN_NO_MSGS, + co->CANrx, + CO_GET_CO(CNT_ALL_RX_MSGS), + co->CANtx, + CO_GET_CO(CNT_ALL_TX_MSGS), bitRate); return err; @@ -597,361 +873,377 @@ CO_ReturnError_t CO_CANinit(void *CANptr, /******************************************************************************/ -#if CO_NO_LSS_SLAVE == 1 -CO_ReturnError_t CO_LSSinit(uint8_t *nodeId, - uint16_t *bitRate) +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +CO_ReturnError_t CO_LSSinit(CO_t *co, + CO_LSS_address_t *lssAddress, + uint8_t *pendingNodeID, + uint16_t *pendingBitRate) { - CO_LSS_address_t lssAddress; CO_ReturnError_t err; + if (co == NULL || CO_GET_CNT(LSS_SLV) != 1) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + /* LSSslave */ - lssAddress.identity.productCode = OD_identity.productCode; - lssAddress.identity.revisionNumber = OD_identity.revisionNumber; - lssAddress.identity.serialNumber = OD_identity.serialNumber; - lssAddress.identity.vendorID = OD_identity.vendorID; - - err = CO_LSSslave_init(CO->LSSslave, - &lssAddress, - bitRate, - nodeId, - CO->CANmodule[0], - CO_RXCAN_LSS_SLV, + err = CO_LSSslave_init(co->LSSslave, + lssAddress, + pendingBitRate, + pendingNodeID, + co->CANmodule, + CO_GET_CO(RX_IDX_LSS_SLV), CO_CAN_ID_LSS_MST, - CO->CANmodule[0], - CO_TXCAN_LSS_SLV, + co->CANmodule, + CO_GET_CO(TX_IDX_LSS_SLV), CO_CAN_ID_LSS_SLV); return err; } -#endif /* CO_NO_LSS_SLAVE == 1 */ +#endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE */ /******************************************************************************/ -CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { - int16_t i; +CO_ReturnError_t CO_CANopenInit(CO_t *co, + CO_NMT_t *NMT, + CO_EM_t *em, + const OD_t *od, + const OD_entry_t *OD_statusBits, + CO_NMT_control_t NMTcontrol, + uint16_t firstHBTime_ms, + uint16_t SDOtimeoutTime_ms, + uint8_t nodeId) +{ CO_ReturnError_t err; + if (co == NULL + || (CO_GET_CNT(NMT) == 0 && NMT == NULL) + || (CO_GET_CNT(EM) == 0 && em == NULL) + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* alternatives */ + if (CO_GET_CNT(NMT) == 0) { + co->NMT = NMT; + } + if (em == NULL) { + em = co->em; + } + /* Verify CANopen Node-ID */ - CO->nodeIdUnconfigured = false; -#if CO_NO_LSS_SLAVE == 1 - if (nodeId == CO_LSS_NODE_ID_ASSIGNMENT) { - CO->nodeIdUnconfigured = true; + co->nodeIdUnconfigured = false; +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + if (CO_GET_CNT(LSS_SLV) == 1 && nodeId == CO_LSS_NODE_ID_ASSIGNMENT) { + co->nodeIdUnconfigured = true; } else #endif if (nodeId < 1 || nodeId > 127) { return CO_ERROR_ILLEGAL_ARGUMENT; } - /* Verify parameters from CO_OD */ -#if CO_NO_SRDO != 0 - if (sizeof(OD_SRDOCommunicationParameter_t) != sizeof(CO_SRDOCommPar_t) || - sizeof(OD_SRDOMappingParameter_t) != sizeof(CO_SRDOMapPar_t)) { - return CO_ERROR_OD_PARAMETERS; + +#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE + if (CO_GET_CNT(LEDS) == 1) { + err = CO_LEDs_init(co->LEDs); + if (err) return err; } #endif - if (sizeof(OD_TPDOCommunicationParameter_t) != sizeof(CO_TPDOCommPar_t) || - sizeof(OD_TPDOMappingParameter_t) != sizeof(CO_TPDOMapPar_t) || - sizeof(OD_RPDOCommunicationParameter_t) != sizeof(CO_RPDOCommPar_t) || - sizeof(OD_RPDOMappingParameter_t) != sizeof(CO_RPDOMapPar_t)) { - return CO_ERROR_OD_PARAMETERS; - } -#if CO_NO_SDO_CLIENT != 0 - if (sizeof(OD_SDOClientParameter_t) != sizeof(CO_SDOclientPar_t)) { - return CO_ERROR_OD_PARAMETERS; + + /* CANopen Node ID is unconfigured, stop initialization here */ + if (co->nodeIdUnconfigured) { + return CO_ERROR_NODE_ID_UNCONFIGURED_LSS; } -#endif -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE - /* LEDs */ - err = CO_LEDs_init(CO->LEDs); + /* Emergency */ + if (CO_GET_CNT(EM) == 1) { + err = CO_EM_init(co->em, + OD_GET(H1001, OD_H1001_ERR_REG), + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + OD_GET(H1014, OD_H1014_COBID_EMERGENCY), + co->CANmodule, + CO_GET_CO(TX_IDX_EM_PROD), + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + OD_GET(H1015, OD_H1015_INHIBIT_TIME_EMCY), + #endif + #endif + #if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY + OD_GET(H1003, OD_H1003_PREDEF_ERR_FIELD), + #endif + #if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS + OD_statusBits, + #endif + #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + co->CANmodule, + CO_GET_CO(RX_IDX_EM_CONS), + #endif + nodeId); + if (err) return err; + } - if (err) return err; -#endif + /* NMT_Heartbeat */ + if (CO_GET_CNT(NMT) == 1) { + err = CO_NMT_init(co->NMT, + OD_GET(H1017, OD_H1017_PRODUCER_HB_TIME), + em, + nodeId, + NMTcontrol, + firstHBTime_ms, + co->CANmodule, + CO_GET_CO(RX_IDX_NMT_SLV), + CO_CAN_ID_NMT_SERVICE, + #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER + co->CANmodule, + CO_GET_CO(TX_IDX_NMT_MST), + CO_CAN_ID_NMT_SERVICE, + #endif + co->CANmodule, + CO_GET_CO(TX_IDX_HB_PROD), + CO_CAN_ID_HEARTBEAT + nodeId); + if (err) return err; + } -#if CO_NO_LSS_SLAVE == 1 - if (CO->nodeIdUnconfigured) { - return CO_ERROR_NODE_ID_UNCONFIGURED_LSS; +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + if (CO_GET_CNT(HB_CONS) == 1) { + err = CO_HBconsumer_init(co->HBcons, + em, + co->SDO[0], + &OD_consumerHeartbeatTime[0], + CO_HBcons_monitoredNodes, + CO_GET_CNT(HB_CONS), + co->CANmodule, + CO_GET_CO(RX_IDX_HB_CONS)); + if (err) return err; } #endif /* SDOserver */ - for (i = 0; i < CO_NO_SDO_SERVER; i++) { - uint32_t COB_IDClientToServer; - uint32_t COB_IDServerToClient; - if (i == 0) { - /*Default SDO server must be located at first index*/ - COB_IDClientToServer = CO_CAN_ID_SDO_CLI + nodeId; - COB_IDServerToClient = CO_CAN_ID_SDO_SRV + nodeId; - } - else { - COB_IDClientToServer = - OD_SDOServerParameter[i].COB_IDClientToServer; - COB_IDServerToClient = - OD_SDOServerParameter[i].COB_IDServerToClient; + if (CO_GET_CNT(SDO_SRV) > 0) { + const OD_entry_t *SDOsrvPar = OD_GET(H1200,OD_H1200_SDO_SERVER_1_PARAM); + for (int16_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { + err = CO_SDOserver_init(&co->SDOserver[i], + od, + SDOsrvPar++, + nodeId, + SDOtimeoutTime_ms, + co->CANmodule, + CO_GET_CO(RX_IDX_SDO_SRV) + i, + co->CANmodule, + CO_GET_CO(TX_IDX_SDO_SRV) + i); + if (err) return err; } + } - err = CO_SDO_init(CO->SDO[i], - COB_IDClientToServer, - COB_IDServerToClient, - OD_H1200_SDO_SERVER_PARAM + i, - i == 0 ? 0 : CO->SDO[0], - &CO_OD[0], - CO_OD_NoOfElements, - CO_SDO_ODExtensions, - nodeId, - 1000, - CO->CANmodule[0], - CO_RXCAN_SDO_SRV + i, - CO->CANmodule[0], - CO_TXCAN_SDO_SRV + i); +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE + if (CO_GET_CNT(SDO_CLI) > 0) { + const OD_entry_t *SDOcliPar = OD_GET(H1280,OD_H1280_SDO_CLIENT_1_PARAM); + for (int16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { + err = CO_SDOclient_init(&co->SDOclient[i], + od, + SDOcliPar++, + nodeId, + co->CANmodule, + CO_GET_CO(RX_IDX_SDO_CLI) + i, + co->CANmodule, + CO_GET_CO(TX_IDX_SDO_CLI) + i); + if (err) return err; + } + } +#endif +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + if (CO_GET_CNT(TIME) == 1) { + err = CO_TIME_init(co->TIME, + em, + co->SDO[0], + &co->NMT->operatingState, + OD_COB_ID_TIME, + 0, + co->CANmodule, + CO_GET_CO(RX_IDX_TIME), + co->CANmodule, + CO_GET_CO(TX_IDX_TIME)); if (err) return err; } +#endif - - /* Emergency */ - err = CO_EM_init(CO->em, - CO->emPr, - CO->SDO[0], - &OD_errorStatusBits[0], - ODL_errorStatusBits_stringLength, - &OD_errorRegister, - &OD_preDefinedErrorField[0], - ODL_preDefinedErrorField_arrayLength, - CO->CANmodule[0], - CO_RXCAN_EMERG, - CO->CANmodule[0], - CO_TXCAN_EMERG, - (uint16_t)CO_CAN_ID_EMERGENCY + nodeId); - - if (err) return err; - - /* NMT_Heartbeat */ - err = CO_NMT_init(CO->NMT, - CO->emPr, - nodeId, - 500, - CO->CANmodule[0], - CO_RXCAN_NMT, - CO_CAN_ID_NMT_SERVICE, - CO->CANmodule[0], - CO_TXCAN_NMT, - CO_CAN_ID_NMT_SERVICE, - CO->CANmodule[0], - CO_TXCAN_HB, - CO_CAN_ID_HEARTBEAT + nodeId); - - if (err) return err; - -#if CO_NO_SYNC == 1 - /* SYNC */ - err = CO_SYNC_init(CO->SYNC, - CO->em, - CO->SDO[0], - &CO->NMT->operatingState, - OD_COB_ID_SYNCMessage, - OD_communicationCyclePeriod, - OD_synchronousCounterOverflowValue, - CO->CANmodule[0], - CO_RXCAN_SYNC, - CO->CANmodule[0], - CO_TXCAN_SYNC); - - if (err) return err; -#endif - -#if CO_NO_TIME == 1 - /* TIME */ - err = CO_TIME_init(CO->TIME, - CO->em, - CO->SDO[0], - &CO->NMT->operatingState, - OD_COB_ID_TIME, - 0, - CO->CANmodule[0], - CO_RXCAN_TIME, - CO->CANmodule[0], - CO_TXCAN_TIME); - - if (err) return err; -#endif - -#if CO_NO_GFC == 1 - /* GFC */ - CO_GFC_init(CO->GFC, - &OD_globalFailSafeCommandParameter, - CO->CANmodule[0], - CO_RXCAN_GFC, - CO_CAN_ID_GFC, - CO->CANmodule[0], - CO_TXCAN_GFC, - CO_CAN_ID_GFC); -#endif - -#if CO_NO_SRDO != 0 - /* SRDO */ - err = CO_SRDOGuard_init(CO->SRDOGuard, - CO->SDO[0], - &CO->NMT->operatingState, - &OD_configurationValid, - OD_H13FE_SRDO_VALID, - OD_H13FF_SRDO_CHECKSUM); - if (err) return err; - - for (i = 0; i < CO_NO_SRDO; i++) { - CO_CANmodule_t *CANdev = CO->CANmodule[0]; - uint16_t CANdevRxIdx = CO_RXCAN_SRDO + 2*i; - uint16_t CANdevTxIdx = CO_TXCAN_SRDO + 2*i; - - err = CO_SRDO_init(CO->SRDO[i], - CO->SRDOGuard, - CO->em, - CO->SDO[0], - nodeId, - ((i == 0) ? CO_CAN_ID_SRDO_1 : 0), - (CO_SRDOCommPar_t*)&OD_SRDOCommunicationParameter[i], - (CO_SRDOMapPar_t *)&OD_SRDOMappingParameter[i], - &OD_safetyConfigurationChecksum[i], - OD_H1301_SRDO_1_PARAM + i, - OD_H1381_SRDO_1_MAPPING + i, - CANdev, - CANdevRxIdx, - CANdevRxIdx + 1, - CANdev, - CANdevTxIdx, - CANdevTxIdx + 1); +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + if (CO_GET_CNT(SYNC) == 1) { + err = CO_SYNC_init(co->SYNC, + em, + co->SDO[0], + &co->NMT->operatingState, + OD_COB_ID_SYNCMessage, + OD_communicationCyclePeriod, + OD_synchronousCounterOverflowValue, + co->CANmodule, + CO_GET_CO(RX_IDX_SYNC), + co->CANmodule, + CO_GET_CO(TX_IDX_SYNC)); if (err) return err; } #endif - /* RPDO */ - for (i = 0; i < CO_NO_RPDO; i++) { - CO_CANmodule_t *CANdevRx = CO->CANmodule[0]; - uint16_t CANdevRxIdx = CO_RXCAN_RPDO + i; +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + if (CO_GET_CNT(RPDO) > 0) { + const OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); + const OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); + for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { + err = CO_RPDO_init(co->RPDO[i], + em, + co->SDO[0], + #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + co->SYNC, + #endif + &co->NMT->operatingState, + nodeId, + ((i < 4) ? (CO_CAN_ID_RPDO_1 + i * 0x100) : 0), + 0, + RPDOcomm++, + RPDOmap++, + OD_H1400_RXPDO_1_PARAM + i, + OD_H1600_RXPDO_1_MAPPING + i, + co->CANmodule, + CO_GET_CO(RX_IDX_RPDO) + i); + if (err) return err; + } + } +#endif - err = CO_RPDO_init(CO->RPDO[i], - CO->em, - CO->SDO[0], -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - CO->SYNC, +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + if (CO_GET_CNT(TPDO) > 0) { + const OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); + const OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); + for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { + err = CO_TPDO_init(co->TPDO[i], + em, + co->SDO[0], + #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + co->SYNC, + #endif + &co->NMT->operatingState, + nodeId, + ((i < 4) ? (CO_CAN_ID_TPDO_1 + i * 0x100) : 0), + 0, + TPDOcomm++, + TPDOmap++, + OD_H1800_TXPDO_1_PARAM + i, + OD_H1A00_TXPDO_1_MAPPING + i, + co->CANmodule, + CO_GET_CO(TX_IDX_TPDO) + i); + if (err) return err; + } + } #endif - &CO->NMT->operatingState, - nodeId, - ((i < 4) ? (CO_CAN_ID_RPDO_1 + i * 0x100) : 0), - 0, - (CO_RPDOCommPar_t*)&OD_RPDOCommunicationParameter[i], - (CO_RPDOMapPar_t *)&OD_RPDOMappingParameter[i], - OD_H1400_RXPDO_1_PARAM + i, - OD_H1600_RXPDO_1_MAPPING + i, - CANdevRx, - CANdevRxIdx); +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + if (CO_GET_CNT(GFC) == 1) { + err = CO_GFC_init(co->GFC, + &OD_globalFailSafeCommandParameter, + co->CANmodule, + CO_GET_CO(RX_IDX_GFC), + CO_CAN_ID_GFC, + co->CANmodule, + CO_GET_CO(TX_IDX_GFC), + CO_CAN_ID_GFC); if (err) return err; } +#endif - /* TPDO */ - for (i = 0; i < CO_NO_TPDO; i++) { - err = CO_TPDO_init(CO->TPDO[i], - CO->em, - CO->SDO[0], -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - CO->SYNC, -#endif - &CO->NMT->operatingState, - nodeId, - ((i < 4) ? (CO_CAN_ID_TPDO_1 + i * 0x100) : 0), - 0, - (CO_TPDOCommPar_t*)&OD_TPDOCommunicationParameter[i], - (CO_TPDOMapPar_t *)&OD_TPDOMappingParameter[i], - OD_H1800_TXPDO_1_PARAM + i, - OD_H1A00_TXPDO_1_MAPPING + i, - CO->CANmodule[0], - CO_TXCAN_TPDO + i); - +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + if (CO_GET_CNT(SRDO) > 0) { + err = CO_SRDOGuard_init(co->SRDOGuard, + co->SDO[0], + &co->NMT->operatingState, + &OD_configurationValid, + OD_H13FE_SRDO_VALID, + OD_H13FF_SRDO_CHECKSUM); if (err) return err; - } - /* Heartbeat consumer */ - err = CO_HBconsumer_init(CO->HBcons, - CO->em, - CO->SDO[0], - &OD_consumerHeartbeatTime[0], - CO_HBcons_monitoredNodes, - CO_NO_HB_CONS, - CO->CANmodule[0], - CO_RXCAN_CONS_HB); - - if (err) return err; - -#if CO_NO_SDO_CLIENT != 0 - /* SDOclient */ - for (i = 0; i < CO_NO_SDO_CLIENT; i++) { - err = CO_SDOclient_init(CO->SDOclient[i], - (void *)CO->SDO[0], - (CO_SDOclientPar_t *)&OD_SDOClientParameter[i], - CO->CANmodule[0], - CO_RXCAN_SDO_CLI + i, - CO->CANmodule[0], - CO_TXCAN_SDO_CLI + i); + const OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); + const OD_entry_t *SRDOmap = OD_GET(H1318, OD_H1381_SRDO_1_MAPPING); + for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { + uint16_t CANdevRxIdx = CO_GET_CO(RX_IDX_SRDO) + 2 * i; + uint16_t CANdevTxIdx = CO_GET_CO(TX_IDX_SRDO) + 2 * i; + + err = CO_SRDO_init(&co->SRDO[i], + co->SRDOGuard, + em, + co->SDO[0], + nodeId, + ((i == 0) ? CO_CAN_ID_SRDO_1 : 0), + SRDOcomm++, + SRDOmap++, + &OD_safetyConfigurationChecksum[i], + OD_H1301_SRDO_1_PARAM + i, + OD_H1381_SRDO_1_MAPPING + i, + co->CANmodule, + CANdevRxIdx, + CANdevRxIdx + 1, + co->CANmodule, + CANdevTxIdx, + CANdevTxIdx + 1); + if (err) return err; + } + } +#endif +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER + if (CO_GET_CNT(LSS_MST) == 1) { + err = CO_LSSmaster_init(co->LSSmaster, + CO_LSSmaster_DEFAULT_TIMEOUT, + co->CANmodule, + CO_GET_CO(RX_IDX_LSS_MST), + CO_CAN_ID_LSS_SLV, + co->CANmodule, + CO_GET_CO(TX_IDX_LSS_MST), + CO_CAN_ID_LSS_MST); if (err) return err; } #endif -#if CO_NO_LSS_MASTER == 1 - /* LSSmaster */ - err = CO_LSSmaster_init(CO->LSSmaster, - CO_LSSmaster_DEFAULT_TIMEOUT, - CO->CANmodule[0], - CO_RXCAN_LSS_MST, - CO_CAN_ID_LSS_SLV, - CO->CANmodule[0], - CO_TXCAN_LSS_MST, - CO_CAN_ID_LSS_MST); - - if (err) return err; +#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII + if (CO_GET_CNT(GTWA) == 1) { + err = CO_GTWA_init(co->gtwa, + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO + &co->SDOclient[0], + 500, + false, + #endif + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT + co->NMT, + #endif + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS + co->LSSmaster, + #endif + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS + co->LEDs, + #endif + 0); + if (err) return err; + } #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - /* Gateway-ascii */ - err = CO_GTWA_init(CO->gtwa, -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO - CO->SDOclient[0], - 500, - false, -#endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT - CO->NMT, -#endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS - CO->LSSmaster, -#endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS - CO->LEDs, -#endif - 0); - if (err) return err; -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ - -#if CO_NO_TRACE > 0 - /* Trace */ - for (i = 0; i < CO_NO_TRACE; i++) { - CO_trace_init(CO->trace[i], - CO->SDO[0], - OD_traceConfig[i].axisNo, - CO_traceTimeBuffers[i], - CO_traceValueBuffers[i], - CO_traceBufferSize[i], - &OD_traceConfig[i].map, - &OD_traceConfig[i].format, - &OD_traceConfig[i].trigger, - &OD_traceConfig[i].threshold, - &OD_trace[i].value, - &OD_trace[i].min, - &OD_trace[i].max, - &OD_trace[i].triggerTime, - OD_INDEX_TRACE_CONFIG + i, - OD_INDEX_TRACE + i); +#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE + if (CO_GET_CNT(TRACE) > 0) { + for (uint16_t i = 0; i < CO_GET_CNT(TRACE); i++) { + err = CO_trace_init(co->trace[i], + co->SDO[0], + OD_traceConfig[i].axisNo, + CO_traceTimeBuffers[i], + CO_traceValueBuffers[i], + CO_traceBufferSize[i], + &OD_traceConfig[i].map, + &OD_traceConfig[i].format, + &OD_traceConfig[i].trigger, + &OD_traceConfig[i].threshold, + &OD_trace[i].value, + &OD_trace[i].min, + &OD_trace[i].max, + &OD_trace[i].triggerTime, + OD_INDEX_TRACE_CONFIG + i, + OD_INDEX_TRACE + i); + if (err) return err; + } } #endif @@ -961,97 +1253,111 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId) { /******************************************************************************/ CO_NMT_reset_cmd_t CO_process(CO_t *co, + bool_t enableGateway, uint32_t timeDifference_us, uint32_t *timerNext_us) { - uint8_t i; - bool_t NMTisPreOrOperational = false; + (void) enableGateway; (void) timerNext_us; /* may be unused */ CO_NMT_reset_cmd_t reset = CO_RESET_NOT; + CO_NMT_internalState_t NMTstate = CO_NMT_getInternalState(co->NMT); - CO_CANmodule_process(CO->CANmodule[0]); + /* CAN module */ + CO_CANmodule_process(co->CANmodule); -#if CO_NO_LSS_SLAVE == 1 - bool_t resetLSS = CO_LSSslave_process(co->LSSslave); +#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + if (CO_GET_CNT(LSS_SLV) == 1) { + if (CO_LSSslave_process(co->LSSslave)) { + reset = CO_RESET_COMM; + } + } #endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE bool_t unc = co->nodeIdUnconfigured; - uint16_t CANerrorStatus = CO->CANmodule[0]->CANerrorStatus; - CO_LEDs_process(co->LEDs, - timeDifference_us, - unc ? CO_NMT_INITIALIZING : co->NMT->operatingState, - #if CO_NO_LSS_SLAVE == 1 - CO_LSSslave_getState(co->LSSslave) - == CO_LSS_STATE_CONFIGURATION, - #else - false, - #endif - (CANerrorStatus & CO_CAN_ERRTX_BUS_OFF) != 0, - (CANerrorStatus & CO_CAN_ERR_WARN_PASSIVE) != 0, - 0, /* RPDO event timer timeout */ - unc ? false : CO_isError(co->em, CO_EM_SYNC_TIME_OUT), - unc ? false : (CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) + uint16_t CANerrorStatus = co->CANmodule->CANerrorStatus; + bool_t LSSslave_configuration = false; + #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + if (CO_GET_CNT(LSS_SLV) == 1 + && CO_LSSslave_getState(co->LSSslave) == CO_LSS_STATE_CONFIGURATION + ) { + LSSslave_configuration = true; + } + #endif + /* default macro, can be defined externally */ + #ifndef CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS + #define CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS 0 + #endif + + if (CO_GET_CNT(LEDS) == 1) { + CO_LEDs_process(co->LEDs, + timeDifference_us, + unc ? CO_NMT_INITIALIZING : NMTstate, + LSSslave_configuration, + (CANerrorStatus & CO_CAN_ERRTX_BUS_OFF) != 0, + (CANerrorStatus & CO_CAN_ERR_WARN_PASSIVE) != 0, + 0, /* RPDO event timer timeout */ + unc ? false : CO_isError(co->em, CO_EM_SYNC_TIME_OUT), + unc ? false : (CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) || CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET)), - OD_errorRegister != 0, - CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS, - timerNext_us); -#endif /* (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE */ - -#if CO_NO_LSS_SLAVE == 1 - if (resetLSS) { - reset = CO_RESET_COMM; + CO_getErrorRegister(co->em) != 0, + CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS, + timerNext_us); } +#endif + + /* CANopen Node ID is unconfigured (LSS slave), stop processing here */ if (co->nodeIdUnconfigured) { return reset; } + + /* NMT_Heartbeat */ + if (CO_GET_CNT(NMT) == 1) { + reset = CO_NMT_process(co->NMT, + &NMTstate, + timeDifference_us, + timerNext_us); + } + bool_t NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL + || NMTstate == CO_NMT_OPERATIONAL); + +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + if (CO_GET_CNT(HB_CONS) == 1) { + CO_HBconsumer_process(co->HBcons, + NMTisPreOrOperational, + timeDifference_us, + timerNext_us); + } #endif - if (co->NMT->operatingState == CO_NMT_PRE_OPERATIONAL || - co->NMT->operatingState == CO_NMT_OPERATIONAL) - NMTisPreOrOperational = true; + /* Emergency */ + if (CO_GET_CNT(EM) == 1) { + CO_EM_process(co->em, + NMTisPreOrOperational, + timeDifference_us, + timerNext_us); + } /* SDOserver */ - for (i = 0; i < CO_NO_SDO_SERVER; i++) { - CO_SDO_process(co->SDO[i], - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); + for (uint8_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { + CO_SDOserver_process(co->SDOserver, + NMTisPreOrOperational, + timeDifference_us, + timerNext_us); } - /* Emergency */ - CO_EM_process(co->emPr, - NMTisPreOrOperational, - timeDifference_us, - OD_inhibitTimeEMCY, - timerNext_us); - - /* NMT_Heartbeat */ - reset = CO_NMT_process(co->NMT, - timeDifference_us, - OD_producerHeartbeatTime, - OD_NMTStartup, - OD_errorRegister, - OD_errorBehavior, - timerNext_us); - -#if CO_NO_TIME == 1 - /* TIME */ - CO_TIME_process(co->TIME, - timeDifference_us); -#endif - - /* Heartbeat consumer */ - CO_HBconsumer_process(co->HBcons, - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE + if (CO_GET_CNT(TIME) == 1) { + CO_TIME_process(co->TIME, timeDifference_us); + } +#endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - /* Gateway-ascii */ - CO_GTWA_process(co->gtwa, - CO_GTWA_ENABLE, - timeDifference_us, - timerNext_us); + if (CO_GET_CNT(GTWA) == 1) { + CO_GTWA_process(co->gtwa, + enableGateway, + timeDifference_us, + timerNext_us); + } #endif return reset; @@ -1059,100 +1365,86 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, /******************************************************************************/ -#if CO_NO_SYNC == 1 +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE bool_t CO_process_SYNC(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { bool_t syncWas = false; -#if CO_NO_LSS_SLAVE == 1 - if (co->nodeIdUnconfigured) { - return syncWas; - } -#endif - - const CO_SYNC_status_t sync_process = CO_SYNC_process(co->SYNC, - timeDifference_us, - OD_synchronousWindowLength, - timerNext_us); - - switch (sync_process) { - case CO_SYNC_NONE: - break; - case CO_SYNC_RECEIVED: - syncWas = true; - break; - case CO_SYNC_OUTSIDE_WINDOW: - CO_CANclearPendingSyncPDOs(co->CANmodule[0]); - break; + if (!co->nodeIdUnconfigured && CO_GET_CNT(SYNC) == 1) { + const CO_SYNC_status_t sync_process = + CO_SYNC_process(co->SYNC, + timeDifference_us, + OD_synchronousWindowLength, + timerNext_us); + + switch (sync_process) { + case CO_SYNC_NONE: + break; + case CO_SYNC_RECEIVED: + syncWas = true; + break; + case CO_SYNC_OUTSIDE_WINDOW: + CO_CANclearPendingSyncPDOs(co->CANmodule); + break; + } } return syncWas; } -#endif /* CO_NO_SYNC == 1 */ +#endif /******************************************************************************/ -void CO_process_RPDO(CO_t *co, - bool_t syncWas) -{ - int16_t i; - -#if CO_NO_LSS_SLAVE == 1 +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +void CO_process_RPDO(CO_t *co, bool_t syncWas) { if (co->nodeIdUnconfigured) { return; } -#endif - for (i = 0; i < CO_NO_RPDO; i++) { - CO_RPDO_process(co->RPDO[i], syncWas); + for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { + CO_RPDO_process(&co->RPDO[i], syncWas); } } +#endif /******************************************************************************/ +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE void CO_process_TPDO(CO_t *co, bool_t syncWas, uint32_t timeDifference_us, uint32_t *timerNext_us) { - int16_t i; - -#if CO_NO_LSS_SLAVE == 1 if (co->nodeIdUnconfigured) { return; } -#endif - /* Verify PDO Change Of State and process PDOs */ - for (i = 0; i < CO_NO_TPDO; i++) { - if (!co->TPDO[i]->sendRequest) - co->TPDO[i]->sendRequest = CO_TPDOisCOS(co->TPDO[i]); - CO_TPDO_process(co->TPDO[i], syncWas, timeDifference_us, timerNext_us); + for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { + CO_TPDO_process(&co->TPDO[i], syncWas, timeDifference_us, timerNext_us); } } +#endif + /******************************************************************************/ -#if CO_NO_SRDO != 0 +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE void CO_process_SRDO(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { - int16_t i; - uint8_t firstOperational; - -#if CO_NO_LSS_SLAVE == 1 if (co->nodeIdUnconfigured) { return; } -#endif - firstOperational = CO_SRDOGuard_process(co->SRDOGuard); + uint8_t firstOperational = CO_SRDOGuard_process(co->SRDOGuard); - /* Verify PDO Change Of State and process PDOs */ - for (i = 0; i < CO_NO_SRDO; i++) { - CO_SRDO_process(co->SRDO[i], firstOperational, timeDifference_us, timerNext_us); + for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { + CO_SRDO_process(&co->SRDO[i], + firstOperational, + timeDifference_us, + timerNext_us); } } #endif diff --git a/CANopen.h b/CANopen.h index 4095ac02..e7ebec21 100644 --- a/CANopen.h +++ b/CANopen.h @@ -29,14 +29,15 @@ #define CANopen_H #include "301/CO_driver.h" +#include "301/CO_ODinterface.h" +#include "301/CO_NMT_Heartbeat.h" +#include "301/CO_HBconsumer.h" +#include "301/CO_Emergency.h" #include "301/CO_SDOserver.h" #include "301/CO_SDOclient.h" -#include "301/CO_Emergency.h" -#include "301/CO_NMT_Heartbeat.h" -#include "301/CO_TIME.h" #include "301/CO_SYNC.h" #include "301/CO_PDO.h" -#include "301/CO_HBconsumer.h" +#include "301/CO_TIME.h" #include "303/CO_LEDs.h" #include "304/CO_GFC.h" #include "304/CO_SRDO.h" @@ -44,7 +45,6 @@ #include "305/CO_LSSmaster.h" #include "309/CO_gateway_ascii.h" #include "extra/CO_trace.h" -#include "CO_OD.h" #ifdef __cplusplus extern "C" { @@ -63,12 +63,12 @@ extern "C" { * * CANopenNode homepage is https://github.com/CANopenNode/CANopenNode * - * CANopen.h file combines Object dictionary (CO_OD) and all other CANopen - * source files. Configuration information are read from CO_OD.h file. - * CO_OD.h/.c files defines CANopen Object Dictionary and are generated by - * external tool. - * CANopen.h file contains most common configuration of CANopenNode objects - * and can also be a template for custom, more complex configurations. + * CANopen.h file combines all CANopenNode source files. @ref CO_STACK_CONFIG + * is first defined in "CO_config.h" file. Number of different CANopenNode + * objects used is configured with @ref CO_config_t structure or is read + * directly from "OD.h" file, if single object dictionary definition is used. + * "OD.h" and "OD.c" files defines CANopen Object Dictionary and are generated + * by external tool. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -112,8 +112,8 @@ extern "C" { * CANopen Safety (EN 50325­-5:2010 (formerly CiA 304)) * * Standard defines the usage of Safety Related Data Objects (SRDO) and the GFC. - * This is an additional protocol (to SDO, PDO) to exchange data. - * The meaning of "security" here refers not to security (crypto) but to data consistency. + * This is an additional protocol (to SDO, PDO) to exchange data. The meaning of + * "security" here refers not to security (crypto) but to data consistency. * @} */ @@ -159,178 +159,274 @@ extern "C" { * @{ */ -#ifdef CO_DOXYGEN /** - * @defgroup CO_NO_OBJ CANopen configuration - * - * Definitions specify, which and how many CANopenNode communication objects - * will be used in current configuration. Usage of some objects is mandatory and - * is fixed. Others are defined in CO_OD.h. - * @{ + * If macro is defined externally, then configuration with multiple object + * dictionaries will be possible. If macro is not defined, default "OD.h" file + * with necessary definitions, such as CO_CNT_xxx, will be used, and also memory + * consumption and startup time will be lower. */ -/* Definitions valid only for documentation. */ -/** Number of NMT objects, fixed to 1 slave(CANrx) */ -#define CO_NO_NMT (1) -/** Number of NMT master objects, 0 or 1 master(CANtx). It depends on - * @ref CO_CONFIG_NMT setting. */ -#define CO_NO_NMT_MST (0 - 1) -/** Number of SYNC objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ -#define CO_NO_SYNC (0 - 1) -/** Number of Emergency producer objects, fixed to 1 producer(CANtx) */ -#define CO_NO_EMERGENCY (1) -/** Number of Emergency consumer objects, 0 or 1 consumer(CANrx). It depends on - * @ref CO_CONFIG_EM setting. */ -#define CO_NO_EM_CONS (0 - 1) -/** Number of Time-stamp objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ -#define CO_NO_TIME (0 - 1) -/** Number of GFC objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */ -#define CO_NO_GFC (0 - 1) -/** Number of SRDO objects, 0 to 64 (consumer(CANrx) + producer(CANtx)) */ -#define CO_NO_RPDO (0 - 64) -/** Number of RPDO objects, 1 to 512 consumers (CANrx) */ -#define CO_NO_RPDO (1 - 512) -/** Number of TPDO objects, 1 to 512 producers (CANtx) */ -#define CO_NO_TPDO (1 - 512) -/** Number of SDO server objects, from 1 to 128 (CANrx + CANtx) */ -#define CO_NO_SDO_SERVER (1 - 128) -/** Number of SDO client objects, from 0 to 128 (CANrx + CANtx) */ -#define CO_NO_SDO_CLIENT (0 - 128) -/** Number of HB producer objects, fixed to 1 producer(CANtx) */ -#define CO_NO_HB_PROD (1) -/** Number of HB consumer objects, from 0 to 127 consumers(CANrx) */ -#define CO_NO_HB_CONS (0 - 127) -/** Number of LSS slave objects, 0 or 1 (CANrx + CANtx). It depends on - * @ref CO_CONFIG_LSS setting. */ -#define CO_NO_LSS_SLAVE (0 - 1) -/** Number of LSS master objects, 0 or 1 (CANrx + CANtx). It depends on - * @ref CO_CONFIG_LSS setting. */ -#define CO_NO_LSS_MASTER (0 - 1) -/** Number of Trace objects, 0 to many */ -#define CO_NO_TRACE (0 - ) -/** @} */ - -#else /* CO_DOXYGEN */ - -/* Valid Definitions for program. */ -/* NMT slave count (fixed) */ -#define CO_NO_NMT 1 - -/* NMT master count depends on stack configuration */ -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER -#define CO_NO_NMT_MST 1 -#else -#define CO_NO_NMT_MST 0 -#endif - -/* Emergency consumer depends on stack configuration */ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER -#define CO_NO_EM_CONS 1 -#else -#define CO_NO_EM_CONS 0 +#ifdef CO_DOXYGEN +#define CO_MULTIPLE_OD #endif -/* Heartbeat producer count (fixed) */ -#define CO_NO_HB_PROD 1 - -/* Heartbeat consumer count depends on Object Dictionary configuration */ -#ifdef ODL_consumerHeartbeatTime_arrayLength - #define CO_NO_HB_CONS ODL_consumerHeartbeatTime_arrayLength -#else - #define CO_NO_HB_CONS 0 +/** + * If macro is defined externally, then global variables for CANopen objects + * will be used instead of heap. This is possible only if CO_MULTIPLE_OD is not + * defined. + */ +#ifdef CO_DOXYGEN +#define CO_USE_GLOBALS #endif -/* LSS slave count depends on stack configuration */ -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE -#define CO_NO_LSS_SLAVE 1 -#else -#define CO_NO_LSS_SLAVE 0 -#endif -/* LSS master count depends on stack configuration */ -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER -#define CO_NO_LSS_MASTER 1 +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN +/** + * CANopen configuration, used with @ref CO_new() + * + * This structure is used only, if @ref CO_MULTIPLE_OD is enabled. Otherwise + * parameters are retrieved from default "OD.h" file. + */ +typedef struct { + /** Number of NMT objects, 0 or 1: NMT slave (CANrx) + Heartbeat producer + * (CANtx) + optional NMT master (CANtx), configurable by + * @ref CO_CONFIG_NMT. Start indexes inside CANrx and CANtx are always 0. + * There must be one NMT object in the device. */ + uint8_t CNT_NMT; + const OD_entry_t *ENTRY_H1017; /**< OD entry for @ref CO_NMT_init() */ + /** Number of Heartbeat consumer objects, 0 or 1: object uses from 1 to 127 + * internal consumers (CANrx), as specified by @ref CO_CONFIG_HB_CONS_SIZE. + */ + uint8_t CNT_HB_CONS; + const OD_entry_t *ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init()*/ + /** Number of Emergency objects, 0 or 1: optional producer (CANtx) + + * optional consumer (CANrx), configurable by @ref CO_CONFIG_EM. + * There must be one Emergency object in the device. */ + uint8_t CNT_EM; + const OD_entry_t *ENTRY_H1001; /**< OD entry for @ref CO_EM_init() */ + const OD_entry_t *ENTRY_H1014; /**< OD entry for @ref CO_EM_init() */ + const OD_entry_t *ENTRY_H1015; /**< OD entry for @ref CO_EM_init() */ + const OD_entry_t *ENTRY_H1003; /**< OD entry for @ref CO_EM_init() */ + /** Number of SDO server objects, from 0 to 128 (CANrx + CANtx). There must + * be at least one SDO server object in the device. */ + uint8_t CNT_SDO_SRV; + const OD_entry_t *ENTRY_H1200; /**< OD entry for @ref CO_SDOserver_init()*/ + /** Number of SDO client objects, from 0 to 128 (CANrx + CANtx). */ + uint8_t CNT_SDO_CLI; + const OD_entry_t *ENTRY_H1280; /**< OD entry for @ref CO_SDOclient_init()*/ + /** Number of TIME objects, 0 or 1: consumer (CANrx) + optional producer + * (CANtx), configurable by @ref CO_CONFIG_TIME. */ + uint8_t CNT_TIME; + const OD_entry_t *ENTRY_H1012; /**< OD entry for @ref CO_TIME_init() */ + /** Number of SYNC objects, 0 or 1: consumer (CANrx) + optional producer + * (CANtx), configurable by @ref CO_CONFIG_SYNC. */ + uint8_t CNT_SYNC; + const OD_entry_t *ENTRY_H1005; /**< OD entry for @ref CO_SYNC_init() */ + const OD_entry_t *ENTRY_H1006; /**< OD entry for @ref CO_SYNC_init() */ + const OD_entry_t *ENTRY_H1007; /**< OD entry for @ref CO_SYNC_init() */ + const OD_entry_t *ENTRY_H1019; /**< OD entry for @ref CO_SYNC_init() */ + /** Number of RPDO objects, from 0 to 512 consumers (CANrx) */ + uint16_t CNT_RPDO; + const OD_entry_t *ENTRY_H1400; /**< OD entry for @ref CO_RPDO_init() */ + const OD_entry_t *ENTRY_H1600; /**< OD entry for @ref CO_RPDO_init() */ + /** Number of TPDO objects, from 0 to 512 producers (CANtx) */ + uint16_t CNT_TPDO; + const OD_entry_t *ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */ + const OD_entry_t *ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */ + /** Number of LEDs objects, 0 or 1. */ + uint8_t CNT_LEDS; + /** Number of GFC objects, 0 or 1 (CANrx + CANtx). */ + uint8_t CNT_GFC; + const OD_entry_t *ENTRY_H1300; /**< OD entry for @ref CO_GFC_init() */ + /** Number of SRDO objects, from 0 to 64 (2*CANrx + 2*CANtx). */ + uint8_t CNT_SRDO; + const OD_entry_t *ENTRY_H1301; /**< OD entry for @ref CO_SRDO_init() */ + const OD_entry_t *ENTRY_H1381; /**< OD entry for @ref CO_SRDO_init() */ + const OD_entry_t *ENTRY_H13FE; /**< OD entry for @ref CO_SRDOGuard_init() */ + const OD_entry_t *ENTRY_H13FF; /**< OD entry for @ref CO_SRDOGuard_init() */ + /** Number of LSSslave objects, 0 or 1 (CANrx + CANtx). */ + uint8_t CNT_LSS_SLV; + /** Number of LSSmaster objects, 0 or 1 (CANrx + CANtx). */ + uint8_t CNT_LSS_MST; + /** Number of gateway ascii objects, 0 or 1. */ + uint8_t CNT_GTWA; + /** Number of trace objects, 0 or more. */ + uint16_t CNT_TRACE; +} CO_config_t; #else -#define CO_NO_LSS_MASTER 0 -#endif -#endif /* CO_DOXYGEN */ +typedef void CO_config_t; +#endif /* CO_MULTIPLE_OD */ /** - * CANopen object with pointers to all CANopenNode objects. + * CANopen object - collection of all CANopenNode objects */ typedef struct { - bool_t nodeIdUnconfigured; /**< True in unconfigured LSS slave */ - CO_CANmodule_t *CANmodule[1]; /**< CAN module objects */ - CO_SDO_t *SDO[CO_NO_SDO_SERVER]; /**< SDO object */ - CO_EM_t *em; /**< Emergency report object */ - CO_EMpr_t *emPr; /**< Emergency process object */ - CO_NMT_t *NMT; /**< NMT object */ -#if CO_NO_SYNC == 1 || defined CO_DOXYGEN - CO_SYNC_t *SYNC; /**< SYNC object */ + bool_t nodeIdUnconfigured; /**< True in un-configured LSS slave */ + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_config_t *config; /**< Remember the configuration parameters */ + #endif + /** One CAN module object, initialised by @ref CO_CANmodule_init() */ + CO_CANmodule_t *CANmodule; + CO_CANrx_t *CANrx; /**< CAN receive message objects */ + CO_CANtx_t *CANtx; /**< CAN transmit message objects */ + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t CNT_ALL_RX_MSGS; /**< Number of all CAN receive message objects. */ + uint16_t CNT_ALL_TX_MSGS; /**< Number of all CAN transmit message objects.*/ + #endif + /** NMT and heartbeat object, initialised by @ref CO_NMT_init() */ + CO_NMT_t *NMT; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_NMT_SLV; /**< Start index in CANrx. */ + uint16_t TX_IDX_NMT_MST; /**< Start index in CANtx. */ + uint16_t TX_IDX_HB_PROD; /**< Start index in CANtx. */ + #endif +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN + /** Heartbeat consumer object, initialised by @ref CO_HBconsumer_init() */ + CO_HBconsumer_t *HBcons; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_HB_CONS; /**< Start index in CANrx. */ + #endif +#endif + /** Emergency object, initialised by @ref CO_EM_init() */ + CO_EM_t *em; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_EM_CONS; /**< Start index in CANrx. */ + uint16_t TX_IDX_EM_PROD; /**< Start index in CANtx. */ + #endif + /** SDO server objects, initialised by @ref CO_SDOserver_init() */ + CO_SDOserver_t *SDOserver; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_SDO_SRV; /**< Start index in CANrx. */ + uint16_t TX_IDX_SDO_SRV; /**< Start index in CANtx. */ + #endif +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) || defined CO_DOXYGEN + /** SDO client objects, initialised by @ref CO_SDOclient_init() */ + CO_SDOclient_t *SDOclient; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_SDO_CLI; /**< Start index in CANrx. */ + uint16_t TX_IDX_SDO_CLI; /**< Start index in CANtx. */ + #endif +#endif +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) || defined CO_DOXYGEN + /** TIME object, initialised by @ref CO_TIME_init() */ + CO_TIME_t *TIME; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_TIME; /**< Start index in CANrx. */ + uint16_t TX_IDX_TIME; /**< Start index in CANtx. */ + #endif +#endif +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN + /** SYNC object, initialised by @ref CO_SYNC_init() */ + CO_SYNC_t *SYNC; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_SYNC; /**< Start index in CANrx. */ + uint16_t TX_IDX_SYNC; /**< Start index in CANtx. */ + #endif #endif -#if CO_NO_TIME == 1 || defined CO_DOXYGEN - CO_TIME_t *TIME; /**< TIME object */ +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) || defined CO_DOXYGEN + /** RPDO objects, initialised by @ref CO_RPDO_init() */ + CO_RPDO_t *RPDO; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_RPDO; /**< Start index in CANrx. */ + #endif #endif - CO_RPDO_t *RPDO[CO_NO_RPDO]; /**< RPDO objects */ - CO_TPDO_t *TPDO[CO_NO_TPDO]; /**< TPDO objects */ - CO_HBconsumer_t *HBcons; /**< Heartbeat consumer object*/ -#if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN - CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */ +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) || defined CO_DOXYGEN + /** TPDO objects, initialised by @ref CO_TPDO_init() */ + CO_TPDO_t *TPDO; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t TX_IDX_TPDO; /**< Start index in CANtx. */ + #endif #endif #if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN - CO_LEDs_t *LEDs; /**< LEDs object */ + /** LEDs object, initialised by @ref CO_LEDs_init() */ + CO_LEDs_t *LEDs; #endif -#if CO_NO_GFC != 0 || defined CO_DOXYGEN - CO_GFC_t *GFC; /**< GFC objects */ +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || defined CO_DOXYGEN + /** GFC object, initialised by @ref CO_GFC_init() */ + CO_GFC_t *GFC; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_GFC; /**< Start index in CANrx. */ + uint16_t TX_IDX_GFC; /**< Start index in CANtx. */ + #endif #endif -#if CO_NO_SRDO != 0 || defined CO_DOXYGEN - CO_SRDOGuard_t *SRDOGuard; /**< SRDO objects */ - CO_SRDO_t *SRDO[CO_NO_SRDO]; /**< SRDO objects */ +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN + /** SRDO object, initialised by @ref CO_SRDOGuard_init(), single SRDOGuard + * object is included inside all SRDO objects */ + CO_SRDOGuard_t *SRDOGuard; + /** SRDO objects, initialised by @ref CO_SRDO_init() */ + CO_SRDO_t *SRDO; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_SRDO; /**< Start index in CANrx. */ + uint16_t TX_IDX_SRDO; /**< Start index in CANtx. */ + #endif #endif -#if CO_NO_LSS_SLAVE == 1 || defined CO_DOXYGEN - CO_LSSslave_t *LSSslave; /**< LSS slave object */ +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) || defined CO_DOXYGEN + /** LSS slave object, initialised by @ref CO_LSSslave_init(). */ + CO_LSSslave_t *LSSslave; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_LSS_SLV; /**< Start index in CANrx. */ + uint16_t TX_IDX_LSS_SLV; /**< Start index in CANtx. */ + #endif #endif -#if CO_NO_LSS_MASTER == 1 || defined CO_DOXYGEN - CO_LSSmaster_t *LSSmaster; /**< LSS master object */ +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) || defined CO_DOXYGEN + /** LSS master object, initialised by @ref CO_LSSmaster_init(). */ + CO_LSSmaster_t *LSSmaster; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_LSS_MST; /**< Start index in CANrx. */ + uint16_t TX_IDX_LSS_MST; /**< Start index in CANtx. */ + #endif #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN - CO_GTWA_t *gtwa; /**< Gateway-ascii object (CiA309-3) */ + /** Gateway-ascii object, initialised by @ref CO_GTWA_init(). */ + CO_GTWA_t *gtwa; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + #endif #endif -#if CO_NO_TRACE > 0 || defined CO_DOXYGEN - CO_trace_t *trace[CO_NO_TRACE]; /**< Trace object for recording variables */ +#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) || defined CO_DOXYGEN + /** Trace object, initialised by @ref CO_trace_init(). */ + CO_trace_t *trace; #endif } CO_t; -/** CANopen object */ -extern CO_t *CO; - - /** - * Allocate and initialize memory for CANopen object + * Create new CANopen object * - * Function must be called the first time, after program starts. + * If CO_USE_GLOBALS is defined, then function uses global static variables for + * all the CANopenNode objects. Otherwise it allocates all objects from heap. * * @remark * With some microcontrollers it is necessary to specify Heap size within - * linker configuration. + * linker configuration, if heap is used. * + * @param config Configuration structure, used if @ref CO_MULTIPLE_OD is + * defined. It must stay in memory permanently. If CO_MULTIPLE_OD is not + * defined, config should be NULL and parameters are retrieved from default + * "OD.h" file. * @param [out] heapMemoryUsed Information about heap memory used. Ignored if * NULL. * - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, - * CO_ERROR_OUT_OF_MEMORY + * @return Successfully allocated and configured CO_t object or NULL. */ -CO_ReturnError_t CO_new(uint32_t *heapMemoryUsed); +CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed); /** * Delete CANopen object and free memory. Must be called at program exit. * - * @param CANptr Pointer to the user-defined CAN base structure, passed to - * CO_CANmodule_init(). + * @param co CANopen object. */ -void CO_delete(void *CANptr); +void CO_delete(CO_t *co); + + +/** + * Test if LSS slave is enabled + * + * @param co CANopen object. + * + * @return True if enabled + */ +bool_t CO_isLSSslaveEnabled(CO_t *co); /** @@ -338,31 +434,35 @@ void CO_delete(void *CANptr); * * Function must be called in the communication reset section. * + * @param co CANopen object. * @param CANptr Pointer to the user-defined CAN base structure, passed to * CO_CANmodule_init(). * @param bitRate CAN bit rate. - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT, - * CO_ERROR_ILLEGAL_BAUDRATE, CO_ERROR_OUT_OF_MEMORY + * @return CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_CANinit(void *CANptr, - uint16_t bitRate); +CO_ReturnError_t CO_CANinit(CO_t *co, void *CANptr, uint16_t bitRate); -#if CO_NO_LSS_SLAVE == 1 || defined CO_DOXYGEN +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) || defined CO_DOXYGEN /** * Initialize CANopen LSS slave * * Function must be called before CO_CANopenInit. * - * See #CO_LSSslave_init() for description of parameters. + * See @ref CO_LSSslave_init() for description of parameters. * - * @param [in,out] pendingNodeID Pending node ID or 0xFF(unconfigured) + * @param co CANopen object. + * @param lssAddress LSS slave address, from OD object 0x1018 + * @param [in,out] pendingNodeID Pending node ID or 0xFF (unconfigured) * @param [in,out] pendingBitRate Pending bit rate of the CAN interface - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT + * + * @return CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_LSSinit(uint8_t *pendingNodeID, +CO_ReturnError_t CO_LSSinit(CO_t *co, + CO_LSS_address_t *lssAddress, + uint8_t *pendingNodeID, uint16_t *pendingBitRate); -#endif /* CO_NO_LSS_SLAVE == 1 */ +#endif /** @@ -370,13 +470,34 @@ CO_ReturnError_t CO_LSSinit(uint8_t *pendingNodeID, * * Function must be called in the communication reset section. * + * @param co CANopen object. + * @param em Emergency object, which is used inside different CANopen objects, + * usually for error reporting. If NULL, then 'co->em' will be used. + * if NULL and 'co->CNT_EM' is 0, then function returns with error. + * @param NMT If 'co->CNT_NMT' is 0, this object must be specified, If + * 'co->CNT_NMT' is 1,then it is ignored and can be NULL. NMT object is used for + * retrieving NMT internal state inside CO_process(). + * @param od CANopen Object dictionary + * @param OD_statusBits Argument passed to @ref CO_EM_init(). May be NULL. + * @param NMTcontrol Argument passed to @ref CO_NMT_init(). + * @param firstHBTime_ms Argument passed to @ref CO_NMT_init(). + * @param SDOtimeoutTime_ms Argument passed to @ref CO_SDOserver_init(). * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). In the * CANopen initialization it is the same as pendingBitRate from CO_LSSinit(). * If it is unconfigured, then some CANopen objects will not be initialized nor * processed. - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT + * + * @return CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); +CO_ReturnError_t CO_CANopenInit(CO_t *co, + CO_NMT_t *NMT, + CO_EM_t *em, + const OD_t *od, + const OD_entry_t *OD_statusBits, + CO_NMT_control_t NMTcontrol, + uint16_t firstHBTime_ms, + uint16_t SDOtimeoutTime_ms, + uint8_t nodeId); /** @@ -386,6 +507,7 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); * objects. * * @param co CANopen object. + * @param enableGateway If true, gateway to external world will be enabled. * @param timeDifference_us Time difference from previous function call in * microseconds. * @param [out] timerNext_us info to OS - maximum delay time after this function @@ -398,19 +520,21 @@ CO_ReturnError_t CO_CANopenInit(uint8_t nodeId); * trigger calling of CO_process() function. Parameter is ignored if * NULL. See also @ref CO_CONFIG_FLAG_CALLBACK_PRE configuration macro. * - * @return #CO_NMT_reset_cmd_t from CO_NMT_process(). + * @return Node or communication reset request, from @ref CO_NMT_process(). */ CO_NMT_reset_cmd_t CO_process(CO_t *co, + bool_t enableGateway, uint32_t timeDifference_us, uint32_t *timerNext_us); -#if CO_NO_SYNC == 1 || defined CO_DOXYGEN +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN /** * Process CANopen SYNC objects. * - * Function must be called cyclically from real time thread with constant - * interval (1ms typically). It processes SYNC CANopen objects. + * Function must be called cyclically. For time critical applications it may be + * called from real time thread with constant interval (1ms typically). It + * processes SYNC CANopen objects. * * @param co CANopen object. * @param timeDifference_us Time difference from previous function call in @@ -422,27 +546,32 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, bool_t CO_process_SYNC(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us); -#endif /* CO_NO_SYNC == 1 */ +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE /** * Process CANopen RPDO objects. * - * Function must be called cyclically from real time thread with constant. - * interval (1ms typically). It processes receive PDO CANopen objects. + * Function must be called cyclically. For time critical applications it may be + * called from real time thread with constant interval (1ms typically). It + * processes receive PDO CANopen objects. * * @param co CANopen object. * @param syncWas True, if CANopen SYNC message was just received or * transmitted. */ void CO_process_RPDO(CO_t *co, bool_t syncWas); +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE /** * Process CANopen TPDO objects. * - * Function must be called cyclically from real time thread with constant. - * interval (1ms typically). It processes transmit PDO CANopen objects. + * Function must be called cyclically. For time critical applications it may be + * called from real time thread with constant interval (1ms typically). It + * processes transmit PDO CANopen objects. * * @param co CANopen object. * @param syncWas True, if CANopen SYNC message was just received or @@ -455,13 +584,16 @@ void CO_process_TPDO(CO_t *co, bool_t syncWas, uint32_t timeDifference_us, uint32_t *timerNext_us); +#endif + -#if CO_NO_SRDO != 0 || defined CO_DOXYGEN +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN /** * Process CANopen SRDO objects. * - * Function must be called cyclically from real time thread with constant. - * interval (1ms typically). It processes receive SRDO CANopen objects. + * Function must be called cyclically. For time critical applications it may be + * called from real time thread with constant interval (1ms typically). It + * processes SRDO CANopen objects. * * @param co CANopen object. * @param timeDifference_us Time difference from previous function call in @@ -471,7 +603,7 @@ void CO_process_TPDO(CO_t *co, void CO_process_SRDO(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us); -#endif /* CO_NO_SRDO != 0 */ +#endif /** @} */ /* CO_CANopen */ diff --git a/Makefile b/Makefile index 4ce4a9ac..dad8ffe6 100644 --- a/Makefile +++ b/Makefile @@ -16,21 +16,21 @@ INCLUDE_DIRS = \ -I$(OD_SRC) \ -I$(APPL_SRC) +# $(DRV_SRC)/CO_OD_storage.c \ SOURCES = \ $(DRV_SRC)/CO_driver.c \ $(DRV_SRC)/CO_error.c \ $(DRV_SRC)/CO_epoll_interface.c \ - $(DRV_SRC)/CO_OD_storage.c \ $(CANOPEN_SRC)/301/CO_ODinterface.c \ - $(CANOPEN_SRC)/301/CO_SDOserver.c \ - $(CANOPEN_SRC)/301/CO_Emergency.c \ $(CANOPEN_SRC)/301/CO_NMT_Heartbeat.c \ $(CANOPEN_SRC)/301/CO_HBconsumer.c \ + $(CANOPEN_SRC)/301/CO_Emergency.c \ + $(CANOPEN_SRC)/301/CO_SDOserver.c \ + $(CANOPEN_SRC)/301/CO_SDOclient.c \ + $(CANOPEN_SRC)/301/CO_TIME.c \ $(CANOPEN_SRC)/301/CO_SYNC.c \ $(CANOPEN_SRC)/301/CO_PDO.c \ - $(CANOPEN_SRC)/301/CO_TIME.c \ - $(CANOPEN_SRC)/301/CO_SDOclient.c \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ $(CANOPEN_SRC)/301/CO_fifo.c \ $(CANOPEN_SRC)/303/CO_LEDs.c \ @@ -41,18 +41,23 @@ SOURCES = \ $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ - $(OD_SRC)/CO_OD.c \ + $(OD_SRC)/OD.c \ $(APPL_SRC)/CO_main_basic.c OBJS = $(SOURCES:%.c=%.o) CC ?= gcc -OPT = -g -#OPT = -g -DCO_SINGLE_THREAD +OPT = -g -pedantic +#OPT = -g -pedantic -fanalyzer +#OPT = -g -pedantic -DCO_USE_GLOBALS +#OPT = -g -pedantic -DCO_MULTIPLE_OD +#OPT = -g -pedantic -DCO_SINGLE_THREAD CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = -pthread #LDFLAGS = +#Options can be passed via make: 'make OPT="-g -DCO_SINGLE_THREAD" LDFLAGS=""' + .PHONY: all clean diff --git a/README.md b/README.md index 8c1040fe..7741a452 100644 --- a/README.md +++ b/README.md @@ -232,19 +232,10 @@ Some details RTR (remote transmission request) is a feature of CAN bus. Usage of RTR is not recommended for CANopen and it is not implemented in CANopenNode. -### Self start -Object **0x1F80** from Object Dictionary enables the NMT slaves to start -automatically or allows it to start the whole network. It is specified in -DSP302-2 standard. Standard allows two values for slaves for object 0x1F80: -- Object 0x1F80, value = **0x8** - "NMT slave shall enter the NMT state - Operational after the NMT state Initialization autonomously (self starting)" -- Object 0x1F80, value = **0x2** - "NMT slave shall execute the NMT service - start remote node with node-ID set to 0" - ### Error control -When node is stated (in NMT operational state), it is allowed to send or +When node is started (in NMT operational state), it is allowed to send or receive Process Data Objects (PDO). If Error Register (object 0x1001) is set, -then NMT operational state is not allowed. +then NMT operational state may not be allowed. ### Power saving All CANopen objects calculates next timer info for OS. Calculation is based on diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index e4ba956a..dd8515d5 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,10 +1,20 @@ Change Log ========== +[newOD] +------------------------- +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/master...newOD) +### Changed +- New Object dictionary interface. It has very similar principles as before. All parts of CANopenNode objects, which works with OD entries, are rewritten. +- New OD.h and OD.c files, replaces CO_OD files. +- CANopen.c and CANopen.h files redesigned. Integration of "OD.h" is optional. Configuration of multiple object dictionaries is possible with one CANopen device. Interface is the same, with some changes to function arguments. +- Rewritten SDO server. Object dictionary part is removed. +- CO_Emergency is mostly rewritten. Now is much easier customization. +- CO_NMT_Heartbeat is redesigned. + [Unreleased master] ------------------------- - [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.3...master) -- See {TODO diff} for example of change in user application interface. ### Removed - All drivers removed from this project, except Neuberger-socketCAN for Linux. ### Changed @@ -38,7 +48,7 @@ Change Log ### Added - Documentation added to `doc` directory: CHANGELOG.md, deviceSupport.md, gettingStarted.md, LSSusage.md and traceUsage.md. - All CANopen objects calculates next timer info for OS. Useful for energy saving. -- Added file CO_config.h for stack configuration. Can be overridden by target specific or by custom definitions. +- Added file CO_config.h for stack configuration. Can be overridden by target specific or by custom definitions. It enables/disables whole CanOpenNode objects or parts of them. It also specifies some constants. - CO_fifo.h/c for fifo data buffer, used with rewritten SDO client, etc. - CANopen gateway-ascii command interface according to CiA309-3 as a microcontroller independent module. It includes NMT master, LSS master and SDO client interface. Interface is non-blocking, it is added to mainline. Example for Linux stdio and socket is included. @@ -92,6 +102,7 @@ Change Log Changelog written according to recommendations from https://keepachangelog.com/ +[newOD]: https://github.com/CANopenNode/CANopenNode/tree/newOD [Unreleased master]: https://github.com/CANopenNode/CANopenNode [v1.3]: https://github.com/CANopenNode/CANopenNode/tree/v1.3 [v1.2]: https://github.com/CANopenNode/CANopenNode/tree/v1.2 diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index c573a520..b0eed35c 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -62,11 +62,13 @@ extern "C" { #ifndef CO_CONFIG_EM #define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ + CO_CONFIG_EM_PROD_CONFIGURABLE | \ + CO_CONFIG_EM_PROD_INHIBIT | \ CO_CONFIG_EM_HISTORY | \ + CO_CONFIG_EM_STATUS_BITS | \ CO_CONFIG_EM_CONSUMER | \ CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_FLAG_OD_DYNAMIC) + CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SDO_SRV diff --git a/example/OD.c b/example/OD.c new file mode 100644 index 00000000..206e3051 --- /dev/null +++ b/example/OD.c @@ -0,0 +1,12 @@ +#define OD_DEFINITION +#include "301/CO_ODinterface.h" +#include "OD.h" + +static const OD_entry_t OD_list[] = { + {0x1000, 0, 0, 0, NULL} +}; + +const OD_t OD = { + sizeof(OD_list) / sizeof(OD_list[0]), + &OD_list[0] +}; diff --git a/example/OD.h b/example/OD.h new file mode 100644 index 00000000..b78928cb --- /dev/null +++ b/example/OD.h @@ -0,0 +1,45 @@ +/* blank OD for pre-release */ + +extern const OD_t OD; + +#define CO_CNT_NMT 1 +#define CO_CNT_HB_PROD 1 +#define CO_CNT_EM 1 +#define CO_CNT_EM_PROD 1 +#define CO_CNT_SDO_SRV 1 +#define CO_CNT_SDO_CLI 1 + +#if 0 +#define CO_CNT_HB_CONS 1 +#define CO_CNT_TIME 1 +#define CO_CNT_SYNC 1 +#define CO_CNT_SYNC_PROD 1 +#define CO_CNT_RPDO 4 +#define CO_CNT_TPDO 4 +#define CO_CNT_GFC 0 +#define CO_CNT_SRDO 0 +#define CO_CNT_TRACE 0 +#endif + +#define OD_ENTRY_H1017 &OD.list[0] +#define OD_ENTRY_H1016 &OD.list[0] +#define OD_ENTRY_H1001 &OD.list[0] +#define OD_ENTRY_H1014 &OD.list[0] +#define OD_ENTRY_H1015 &OD.list[0] +#define OD_ENTRY_H1003 &OD.list[0] +#define OD_ENTRY_H1200 &OD.list[0] +#define OD_ENTRY_H1280 &OD.list[0] +#define OD_ENTRY_H1012 &OD.list[0] +#define OD_ENTRY_H1005 &OD.list[0] +#define OD_ENTRY_H1006 &OD.list[0] +#define OD_ENTRY_H1007 &OD.list[0] +#define OD_ENTRY_H1019 &OD.list[0] +#define OD_ENTRY_H1400 &OD.list[0] +#define OD_ENTRY_H1600 &OD.list[0] +#define OD_ENTRY_H1800 &OD.list[0] +#define OD_ENTRY_H1A00 &OD.list[0] +#define OD_ENTRY_H1300 &OD.list[0] +#define OD_ENTRY_H1301 &OD.list[0] +#define OD_ENTRY_H1381 &OD.list[0] +#define OD_ENTRY_H13FE &OD.list[0] +#define OD_ENTRY_H13FF &OD.list[0] diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 6d22de93..de97cd03 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -53,6 +53,14 @@ extern "C" { #endif +/* TODO some parts are disabled in non-finished pre-release */ +#define CO_CONFIG_HB_CONS (0) +#define CO_CONFIG_TIME (0) +#define CO_CONFIG_SYNC (0) +#define CO_CONFIG_PDO (0) +#define CO_CONFIG_TRACE (0) + + /* Stack configuration override default values. * For more information see file CO_config.h. */ #ifdef CO_SINGLE_THREAD @@ -77,11 +85,13 @@ extern "C" { #ifndef CO_CONFIG_EM #define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ + CO_CONFIG_EM_PROD_CONFIGURABLE | \ + CO_CONFIG_EM_PROD_INHIBIT | \ CO_CONFIG_EM_HISTORY | \ + CO_CONFIG_EM_STATUS_BITS | \ CO_CONFIG_EM_CONSUMER | \ CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_FLAG_OD_DYNAMIC) + CO_CONFIG_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SDO_SRV @@ -172,7 +182,7 @@ extern "C" { #endif #ifndef CO_CONFIG_TRACE -//#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE) +#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE) #endif diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c index 4a6e5d62..de2f7c72 100644 --- a/socketCAN/CO_epoll_interface.c +++ b/socketCAN/CO_epoll_interface.c @@ -261,11 +261,11 @@ void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co) { (void *)ep, wakeupCallback); #endif #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_SDO_initCallbackPre(co->SDO[0], - (void *)ep, wakeupCallback); + CO_SDOserver_initCallbackPre(&co->SDOserver[0], + (void *)ep, wakeupCallback); #endif #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_SDOclient_initCallbackPre(co->SDOclient[0], + CO_SDOclient_initCallbackPre(&co->SDOclient[0], (void *)ep, wakeupCallback); #endif #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE @@ -284,6 +284,7 @@ void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co) { void CO_epoll_processMain(CO_epoll_t *ep, CO_t *co, + bool_t enableGateway, CO_NMT_reset_cmd_t *reset) { if (ep == NULL || co == NULL || reset == NULL) { @@ -291,7 +292,10 @@ void CO_epoll_processMain(CO_epoll_t *ep, } /* process CANopen objects */ - *reset = CO_process(co, ep->timeDifference_us, &ep->timerNext_us); + *reset = CO_process(co, + enableGateway, + ep->timeDifference_us, + &ep->timerNext_us); } @@ -306,7 +310,7 @@ void CO_epoll_processRT(CO_epoll_t *ep, /* Verify for epoll events */ if (ep->epoll_new) { - if (CO_CANrxFromEpoll(co->CANmodule[0], &ep->ev, NULL, NULL)) { + if (CO_CANrxFromEpoll(co->CANmodule, &ep->ev, NULL, NULL)) { ep->epoll_new = false; } } @@ -315,21 +319,21 @@ void CO_epoll_processRT(CO_epoll_t *ep, uint32_t *pTimerNext_us = realtime ? NULL : &ep->timerNext_us; CO_LOCK_OD(); - if (!co->nodeIdUnconfigured && co->CANmodule[0]->CANnormal) { + if (!co->nodeIdUnconfigured && co->CANmodule->CANnormal) { bool_t syncWas = false; #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE - /* Process Sync */ syncWas = CO_process_SYNC(co, ep->timeDifference_us, pTimerNext_us); #endif - /* Read inputs */ +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE CO_process_RPDO(co, syncWas); - - /* Write outputs */ +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE CO_process_TPDO(co, syncWas, ep->timeDifference_us, pTimerNext_us); - +#endif + (void) syncWas; (void) pTimerNext_us; } CO_UNLOCK_OD(); } diff --git a/socketCAN/CO_epoll_interface.h b/socketCAN/CO_epoll_interface.h index 8b01dac6..4244be79 100644 --- a/socketCAN/CO_epoll_interface.h +++ b/socketCAN/CO_epoll_interface.h @@ -179,10 +179,12 @@ void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co); * * @param ep This object * @param co CANopen object + * @param enableGateway If true, gateway to external world will be enabled. * @param [out] reset Return from @ref CO_process(). */ void CO_epoll_processMain(CO_epoll_t *ep, CO_t *co, + bool_t enableGateway, CO_NMT_reset_cmd_t *reset); diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 3987f668..52281a59 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -24,7 +24,7 @@ */ #ifndef CO_OD_STORAGE -#define CO_OD_STORAGE 1 +#define CO_OD_STORAGE 0 #endif #include @@ -43,6 +43,7 @@ #include #include "CANopen.h" +#include "OD.h" #include "CO_error.h" #include "CO_epoll_interface.h" #if CO_OD_STORAGE == 1 @@ -74,14 +75,31 @@ #define TMR_THREAD_INTERVAL_US 1000 #endif +/* default values */ +#ifndef NMT_CONTROL +#define NMT_CONTROL \ + CO_NMT_STARTUP_TO_OPERATIONAL \ + || CO_NMT_ERR_ON_ERR_REG \ + || CO_ERR_REG_GENERIC_ERR \ + || CO_ERR_REG_COMMUNICATION +#endif +#ifndef FIRST_HB_TIME +#define FIRST_HB_TIME 500 +#endif +#ifndef SDO_TIMEOUT_TIME +#define SDO_TIMEOUT_TIME 1000 +#endif +#ifndef GATEWAY_ENABLE +#define GATEWAY_ENABLE true +#endif /* Other variables and objects */ #ifndef CO_SINGLE_THREAD CO_epoll_t epRT; /* Epoll-timer object for realtime thread */ static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ #endif -static uint8_t CO_pendingNodeId = 0xFF;/* Use value from Object Dictionary or by arguments (set to 1..127 - * or unconfigured=0xFF). Can be changed by LSS slave. */ +CO_t *CO = NULL; /* CANopen object */ +static uint8_t CO_pendingNodeId = 0xFF; /* Set by arguments or by OD_CAN_NODE_ID macro, if defined. Can be changed by LSS slave. */ static uint8_t CO_activeNodeId = 0xFF;/* Copied from CO_pendingNodeId in the communication reset section */ static uint16_t CO_pendingBitRate = 0; /* CAN bitrate, not used here */ #if CO_OD_STORAGE == 1 @@ -166,6 +184,7 @@ static void NmtChangedCallback(CO_NMT_internalState_t state) log_printf(LOG_NOTICE, DBG_NMT_CHANGE, NmtState2Str(state), state); } +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE /* callback for monitoring Heartbeat remote NMT state change */ static void HeartbeatNmtChangedCallback(uint8_t nodeId, CO_NMT_internalState_t state, @@ -175,6 +194,7 @@ static void HeartbeatNmtChangedCallback(uint8_t nodeId, log_printf(LOG_NOTICE, DBG_HB_CONS_NMT_CHANGE, nodeId, NmtState2Str(state), state); } +#endif #if CO_OD_STORAGE == 1 /* callback for storing node id and bitrate */ @@ -193,8 +213,7 @@ printf( printf( "\n" "Options:\n" -" -i CANopen Node-id (1..127) or 0xFF(unconfigured). If not\n" -" specified, value from Object dictionary (0x2101) is used.\n"); +" -i CANopen Node-id (1..127) or 0xFF (LSS unconfigured).\n"); #ifndef CO_SINGLE_THREAD printf( " -p Real-time priority of RT thread (1 .. 99). If not set or\n" @@ -331,14 +350,15 @@ int main (int argc, char *argv[]) { } if(!nodeIdFromArgs) { +#ifdef OD_CAN_NODE_ID /* use value from Object dictionary, if not set by program arguments */ - CO_pendingNodeId = OD_CANNodeID; + CO_pendingNodeId = OD_CAN_NODE_ID; +#endif } if((CO_pendingNodeId < 1 || CO_pendingNodeId > 127) -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - && CO_NO_LSS_SLAVE == 1 && CO_pendingNodeId != CO_LSS_NODE_ID_ASSIGNMENT -#endif + && CO_isLSSslaveEnabled(CO) + && CO_pendingNodeId != CO_LSS_NODE_ID_ASSIGNMENT ) { log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_pendingNodeId); printUsage(argv[0]); @@ -364,13 +384,16 @@ int main (int argc, char *argv[]) { /* Allocate memory for CANopen objects */ - err = CO_new(NULL); - if (err != CO_ERROR_NO) { - log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_new()", err); + uint32_t heapMemoryUsed = 0; + CO = CO_new(NULL, &heapMemoryUsed); + if (CO == NULL) { + log_printf(LOG_CRIT, DBG_GENERAL, + "CO_new(), heapMemoryUsed=", heapMemoryUsed); exit(EXIT_FAILURE); } +#if CO_OD_STORAGE == 1 /* Verify, if OD structures have proper alignment of initial values */ if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) { log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, "CO_OD_RAM"); @@ -386,7 +409,6 @@ int main (int argc, char *argv[]) { } -#if CO_OD_STORAGE == 1 /* initialize Object Dictionary storage */ odStorStatus_rom = CO_OD_storage_init(&odStor, (uint8_t*) &CO_OD_ROM, sizeof(CO_OD_ROM), odStorFile_rom); odStorStatus_eeprom = CO_OD_storage_init(&odStorAuto, (uint8_t*) &CO_OD_EEPROM, sizeof(CO_OD_EEPROM), odStorFile_eeprom); @@ -437,23 +459,30 @@ int main (int argc, char *argv[]) { /* Wait rt_thread. */ if(!firstRun) { CO_LOCK_OD(); - CO->CANmodule[0]->CANnormal = false; + CO->CANmodule->CANnormal = false; CO_UNLOCK_OD(); } /* Enter CAN configuration. */ CO_CANsetConfigurationMode((void *)&CANptr); - CO_CANmodule_disable(CO->CANmodule[0]); + CO_CANmodule_disable(CO->CANmodule); /* initialize CANopen */ - err = CO_CANinit((void *)&CANptr, 0 /* bit rate not used */); + err = CO_CANinit(CO, (void *)&CANptr, 0 /* bit rate not used */); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANinit()", err); exit(EXIT_FAILURE); } - err = CO_LSSinit(&CO_pendingNodeId, &CO_pendingBitRate); + CO_LSS_address_t lssAddress = {.identity = { + .vendorID = 1, + .productCode = 2, + .revisionNumber = 3, + .serialNumber = 4 + }}; + err = CO_LSSinit(CO, &lssAddress, + &CO_pendingNodeId, &CO_pendingBitRate); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_LSSinit()", err); exit(EXIT_FAILURE); @@ -461,7 +490,15 @@ int main (int argc, char *argv[]) { CO_activeNodeId = CO_pendingNodeId; - err = CO_CANopenInit(CO_activeNodeId); + err = CO_CANopenInit(CO, /* CANopen object */ + NULL, /* alternate NMT */ + NULL, /* alternate em */ + &OD, /* Object dictionary */ + NULL, /* Optional OD_statusBits */ + NMT_CONTROL, /* CO_NMT_control_t */ + FIRST_HB_TIME, /* firstHBTime_ms */ + SDO_TIMEOUT_TIME, /* SDOtimeoutTime_ms */ + CO_activeNodeId); if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); exit(EXIT_FAILURE); @@ -479,8 +516,10 @@ int main (int argc, char *argv[]) { if(!CO->nodeIdUnconfigured) { CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, HeartbeatNmtChangedCallback); +#endif #if CO_OD_STORAGE == 1 /* initialize OD objects 1010 and 1011 and verify errors. */ CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U); @@ -536,7 +575,7 @@ int main (int argc, char *argv[]) { /* start CAN */ - CO_CANsetNormalMode(CO->CANmodule[0]); + CO_CANsetNormalMode(CO->CANmodule); reset = CO_RESET_NOT; @@ -549,7 +588,7 @@ int main (int argc, char *argv[]) { #ifdef CO_SINGLE_THREAD CO_epoll_processRT(&epMain, CO, false); #endif - CO_epoll_processMain(&epMain, CO, &reset); + CO_epoll_processMain(&epMain, CO, GATEWAY_ENABLE, &reset); #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_processGtw(&epGtw, CO, &epMain); #endif @@ -595,7 +634,8 @@ int main (int argc, char *argv[]) { #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_closeGtw(&epGtw); #endif - CO_delete((void *)&CANptr); + CO_CANsetConfigurationMode((void *)&CANptr); + CO_delete(CO); log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "finished"); @@ -627,7 +667,7 @@ static void* rt_thread(void* arg) { #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE /* Monitor variables with trace objects */ CO_time_process(&CO_time); - for(i=0; iCNT_TRACE; i++) { CO_trace_process(CO->trace[i], *CO_time.epochTimeOffsetMs); } #endif From cf9fb2a54720be1b716b5ae8c3f06b4baf5d4ce9 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 21 Oct 2020 11:29:03 +0200 Subject: [PATCH 130/520] Some updates in OD interface. It matches newly generated OD.h and OD.c files from libedssharp --- 301/CO_Emergency.h | 2 +- 301/CO_ODinterface.c | 30 ++++--- 301/CO_ODinterface.h | 48 +++++----- CANopen.c | 176 ++++++++++++++++++------------------- CANopen.h | 6 +- doc/objectDictionary.md | 190 ++++++++++++++++++++++++---------------- example/OD.c | 2 +- example/OD.h | 30 +++---- 8 files changed, 265 insertions(+), 219 deletions(-) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 3bae91d0..dfbdf6a7 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -457,7 +457,7 @@ typedef struct { * Emergency object has own memory buffer for this entry. Entry is optional, * IO extension is required. * @param OD_statusBits Custom OD entry for accessing errorStatusBits from - * @ref CO_EM_t. Entry must have bytestring_t of size + * @ref CO_EM_t. Entry must have variable of size * (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT/8) bytes available for read/write access * on subindex 0. Emergency object has own memory buffer for this entry. Entry * is optional, IO extension is required. diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index cdd2b8d9..886b76cf 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -201,7 +201,6 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, OD_subEntry_t *subEntry, OD_stream_t *stream, bool_t odOrig) { if (entry == NULL || entry->odObject == NULL) return ODR_IDX_NOT_EXIST; - else if (subIndex > entry->maxSubIndex) return ODR_SUB_NOT_EXIST; else if (subEntry == NULL || stream == NULL) return ODR_DEV_INCOMPAT; const void *odObjectOrig = entry->odObject; @@ -218,13 +217,13 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, /* common properties */ subEntry->index = entry->index; subEntry->subIndex = subIndex; - subEntry->maxSubIndex = entry->maxSubIndex; - subEntry->storageGroup = entry->storageGroup; + subEntry->subEntriesCount = entry->subEntriesCount; subEntry->flagsPDO = (odObjectExt != NULL ) ? odObjectExt->flagsPDO : NULL; stream->dataOffset = 0; /* attribute, dataObjectOriginal and dataLength, depends on object type */ if (odBasicType == ODT_VAR) { + if (subIndex > 0) return ODR_SUB_NOT_EXIST; const OD_obj_var_t *odo = (const OD_obj_var_t *)odObjectOrig; subEntry->attribute = odo->attribute; @@ -232,6 +231,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, stream->dataLength = odo->dataLength; } else if (odBasicType == ODT_ARR) { + if (subIndex >= entry->subEntriesCount) return ODR_SUB_NOT_EXIST; const OD_obj_array_t *odo = (const OD_obj_array_t *)odObjectOrig; if (subIndex == 0) { @@ -240,18 +240,28 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, stream->dataLength = 1; } else { - char *data = (char *)odo->data; - int i = subIndex - 1; - subEntry->attribute = odo->attribute; - if (data == NULL) return ODR_DEV_INCOMPAT; - stream->dataObjectOriginal = data + odo->dataElementSizeof * i; + if (odo->data == NULL) { + stream->dataObjectOriginal = NULL; + } + else { + char *data = (char *)odo->data; + int i = subIndex - 1; + stream->dataObjectOriginal = data + odo->dataElementSizeof * i; + } stream->dataLength = odo->dataElementLength; } } else if (odBasicType == ODT_REC) { - const OD_obj_var_t *odo_rec = (const OD_obj_var_t *)odObjectOrig; - const OD_obj_var_t *odo = &odo_rec[subIndex]; + const OD_obj_record_t *odoArr = (const OD_obj_record_t *)odObjectOrig; + const OD_obj_record_t *odo = NULL; + for (int i; i< entry->subEntriesCount; i++) { + if (odoArr[i].subIndex == subIndex) { + odo = &odoArr[i]; + break; + } + } + if (odo == NULL) return ODR_SUB_NOT_EXIST; subEntry->attribute = odo->attribute; stream->dataObjectOriginal = odo->data; diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 3040461c..b85bd10b 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -196,9 +196,9 @@ typedef enum { * Structure is initialized with @ref OD_getSub() function. */ typedef struct { - /** Pointer to original data object, defined by Object Dictionary. If - * memory for data object is not specified by Object Dictionary, then - * dataObjectOriginal is NULL. Default read/write functions operate on it. + /** Pointer to original data object, defined by Object Dictionary. Default + * read/write functions operate on it. If memory for data object is not + * specified by Object Dictionary, then dataObjectOriginal is NULL. */ void *dataObjectOriginal; /** Pointer to object, passed by @ref OD_extensionIO_init(). Can be used @@ -224,10 +224,10 @@ typedef struct { uint16_t index; /** Object Dictionary sub-index */ uint8_t subIndex; - /** Maximum sub-index in the OD object */ - uint8_t maxSubIndex; - /** Group for non-volatile storage of the OD object */ - uint8_t storageGroup; + /** Number of sub-entries in OD object. For VAR is 1, for ARRAY is + * maxSubIndex + 1, for RECORD maxSubIndex may be larger, if there is a gap + * between sub-indexes. */ + uint8_t subEntriesCount; /** Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */ OD_attr_t attribute; /** @@ -337,16 +337,14 @@ typedef struct { * Object Dictionary entry for one OD object. * * OD entries are collected inside OD_t as array (list). Each OD entry contains - * basic information about OD object (index, maxSubIndex and storageGroup) and + * basic information about OD object (index and subEntriesCount) and * access function together with a pointer to other details of the OD object. */ typedef struct { /** Object Dictionary index */ uint16_t index; /** Maximum sub-index in the OD object */ - uint8_t maxSubIndex; - /** Group for non-volatile storage of the OD object */ - uint8_t storageGroup; + uint8_t subEntriesCount; /** Type of the odObject, indicated by @ref OD_objectTypes_t enumerator. */ uint8_t odObjectType; /** OD object of type indicated by odObjectType, from which @ref OD_getSub() @@ -432,18 +430,6 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { } -/** - * Return maxSubIndex from OD entry - * - * @param entry OD entry returned by @ref OD_find(). - * - * @return OD maxSubIndex - */ -static inline uint8_t OD_getMaxSubIndex(const OD_entry_t *entry) { - return entry->maxSubIndex; -} - - /** * Restart read or write operation on OD variable * @@ -692,7 +678,7 @@ typedef enum { } OD_objectTypes_t; /** - * Object for single OD variable, used for "VAR" and "RECORD" type OD objects + * Object for single OD variable, used for "VAR" type OD objects */ typedef struct { void *data; /**< Pointer to data */ @@ -713,6 +699,16 @@ typedef struct { OD_size_t dataElementSizeof; /**< Sizeof one array element in bytes */ } OD_obj_array_t; +/** + * Object for OD sub-elements, used in "RECORD" type OD objects + */ +typedef struct { + void *data; /**< Pointer to data */ + uint8_t subIndex; /**< Sub index of element. */ + OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ + OD_size_t dataLength; /**< Data length in bytes */ +} OD_obj_record_t; + /** * Object pointed by @ref OD_obj_extended_t contains application specified * parameters for extended OD object @@ -733,10 +729,10 @@ typedef struct { * @ref OD_extensionIO_init() function */ typedef struct { - /** Pointer to PDO flags bit-field, see @ref OD_subEntry_t, may be NULL. */ - OD_flagsPDO_t *flagsPDO; /** Pointer to application specified IO extension, may be NULL. */ OD_extensionIO_t *extIO; + /** Pointer to PDO flags bit-field, see @ref OD_subEntry_t, may be NULL. */ + OD_flagsPDO_t *flagsPDO; /** Pointer to original odObject, see @ref OD_entry_t. */ const void *odObjectOriginal; } OD_obj_extended_t; diff --git a/CANopen.c b/CANopen.c index 113afb38..dafe2124 100644 --- a/CANopen.c +++ b/CANopen.c @@ -34,52 +34,52 @@ #else #include "OD.h" #define CO_GET_CO(obj) CO_##obj -#define CO_GET_CNT(obj) CO_CNT_##obj +#define CO_GET_CNT(obj) OD_CNT_##obj #define OD_GET(entry, index) OD_ENTRY_##entry /* Verify parameters from "OD.h" and calculate necessary values for each object: - * - verify CO_CNT_xx or set default + * - verify OD_CNT_xx or set default * - calculate number of CANrx and CYNtx messages: CO_RX_CNT_xx and CO_TX_CNT_xx * - set optional undefined OD_ENTRY_Hxxxx to NULL. * - calculate indexes: CO_RX_IDX_xx and CO_TX_IDX_xx * - calculate total count of CAN message buffers: CO_CNT_ALL_RX_MSGS and * CO_CNT_ALL_TX_MSGS. */ -#if CO_CNT_NMT != 1 - #error CO_CNT_NMT from OD.h not correct! +#if OD_CNT_NMT != 1 + #error OD_CNT_NMT from OD.h not correct! #endif -#define CO_RX_CNT_NMT_SLV CO_CNT_NMT +#define CO_RX_CNT_NMT_SLV OD_CNT_NMT #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER #define CO_TX_CNT_NMT_MST 1 #else #define CO_TX_CNT_NMT_MST 0 #endif -#if CO_CNT_HB_PROD != 1 - #error CO_CNT_HB_PROD from OD.h not correct! +#if OD_CNT_HB_PROD != 1 + #error OD_CNT_HB_PROD from OD.h not correct! #endif -#define CO_TX_CNT_HB_PROD CO_CNT_HB_PROD -#if !defined CO_CNT_HB_CONS - #define CO_CNT_HB_CONS 0 -#elif CO_CNT_HB_CONS < 0 || CO_CNT_HB_CONS > 1 - #error CO_CNT_HB_CONS from OD.h not correct! +#define CO_TX_CNT_HB_PROD OD_CNT_HB_PROD +#if !defined OD_CNT_HB_CONS + #define OD_CNT_HB_CONS 0 +#elif OD_CNT_HB_CONS < 0 || OD_CNT_HB_CONS > 1 + #error OD_CNT_HB_CONS from OD.h not correct! #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) && CO_CNT_HB_CONS == 1 +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) && OD_CNT_HB_CONS == 1 #define CO_RX_CNT_HB_CONS CO_CONFIG_HB_CONS_SIZE #else #define CO_RX_CNT_HB_CONS 0 #endif -#if CO_CNT_EM != 1 - #error CO_CNT_EM from OD.h not correct! +#if OD_CNT_EM != 1 + #error OD_CNT_EM from OD.h not correct! #endif #ifndef OD_ENTRY_H1003 #define OD_ENTRY_H1003 NULL #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER - #if CO_CNT_EM_PROD == 1 - #define CO_TX_CNT_EM_PROD CO_CNT_EM_PROD + #if OD_CNT_EM_PROD == 1 + #define CO_TX_CNT_EM_PROD OD_CNT_EM_PROD #else - #error wrong CO_CNT_EM_PROD + #error wrong OD_CNT_EM_PROD #endif #ifndef OD_ENTRY_H1015 #define OD_ENTRY_H1015 NULL @@ -93,39 +93,39 @@ #define CO_RX_CNT_EM_CONS 0 #endif -#if !defined CO_CNT_SDO_SRV - #define CO_CNT_SDO_SRV 1 +#if !defined OD_CNT_SDO_SRV + #define OD_CNT_SDO_SRV 1 #define OD_ENTRY_H1200 NULL -#elif CO_CNT_SDO_SRV < 1 || CO_CNT_SDO_SRV > 128 - #error CO_CNT_SDO_SRV from OD.h not correct! +#elif OD_CNT_SDO_SRV < 1 || OD_CNT_SDO_SRV > 128 + #error OD_CNT_SDO_SRV from OD.h not correct! #endif -#define CO_RX_CNT_SDO_SRV CO_CNT_SDO_SRV -#define CO_TX_CNT_SDO_SRV CO_CNT_SDO_SRV +#define CO_RX_CNT_SDO_SRV OD_CNT_SDO_SRV +#define CO_TX_CNT_SDO_SRV OD_CNT_SDO_SRV #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE - #if !defined CO_CNT_SDO_CLI - #define CO_CNT_SDO_CLI 0 + #if !defined OD_CNT_SDO_CLI + #define OD_CNT_SDO_CLI 0 #define OD_ENTRY_H1280 NULL - #elif CO_CNT_SDO_CLI < 0 || CO_CNT_SDO_CLI > 128 - #error CO_CNT_SDO_CLI from OD.h not correct! + #elif OD_CNT_SDO_CLI < 0 || OD_CNT_SDO_CLI > 128 + #error OD_CNT_SDO_CLI from OD.h not correct! #endif - #define CO_RX_CNT_SDO_CLI CO_CNT_SDO_CLI - #define CO_TX_CNT_SDO_CLI CO_CNT_SDO_CLI + #define CO_RX_CNT_SDO_CLI OD_CNT_SDO_CLI + #define CO_TX_CNT_SDO_CLI OD_CNT_SDO_CLI #else #define CO_RX_CNT_SDO_CLI 0 #define CO_TX_CNT_SDO_CLI 0 #endif #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE - #if !defined CO_CNT_TIME - #define CO_CNT_TIME 0 + #if !defined OD_CNT_TIME + #define OD_CNT_TIME 0 #define OD_ENTRY_H1012 NULL - #elif CO_CNT_TIME < 0 || CO_CNT_TIME > 1 - #error CO_CNT_TIME from OD.h not correct! + #elif OD_CNT_TIME < 0 || OD_CNT_TIME > 1 + #error OD_CNT_TIME from OD.h not correct! #endif - #define CO_RX_CNT_TIME CO_CNT_TIME + #define CO_RX_CNT_TIME OD_CNT_TIME #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER - #define CO_TX_CNT_TIME CO_CNT_TIME + #define CO_TX_CNT_TIME OD_CNT_TIME #else #define CO_TX_CNT_TIME 0 #endif @@ -135,16 +135,16 @@ #endif #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE - #if !defined CO_CNT_SYNC - #define CO_CNT_SYNC 0 + #if !defined OD_CNT_SYNC + #define OD_CNT_SYNC 0 #define OD_ENTRY_H1005 NULL #define OD_ENTRY_H1006 NULL - #elif CO_CNT_SYNC < 0 || CO_CNT_SYNC > 1 - #error CO_CNT_SYNC from OD.h not correct! + #elif OD_CNT_SYNC < 0 || OD_CNT_SYNC > 1 + #error OD_CNT_SYNC from OD.h not correct! #endif - #define CO_RX_CNT_SYNC CO_CNT_SYNC + #define CO_RX_CNT_SYNC OD_CNT_SYNC #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER - #define CO_TX_CNT_SYNC CO_CNT_SYNC + #define CO_TX_CNT_SYNC OD_CNT_SYNC #else #define CO_TX_CNT_SYNC 0 #endif @@ -160,91 +160,91 @@ #endif #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE - #if !defined CO_CNT_RPDO - #define CO_CNT_RPDO 0 + #if !defined OD_CNT_RPDO + #define OD_CNT_RPDO 0 #define OD_ENTRY_H1400 NULL #define OD_ENTRY_H1600 NULL - #elif CO_CNT_RPDO < 0 || CO_CNT_RPDO > 0x200 - #error CO_CNT_RPDO from OD.h not correct! + #elif OD_CNT_RPDO < 0 || OD_CNT_RPDO > 0x200 + #error OD_CNT_RPDO from OD.h not correct! #endif - #define CO_RX_CNT_RPDO CO_CNT_RPDO + #define CO_RX_CNT_RPDO OD_CNT_RPDO #else #define CO_RX_CNT_RPDO 0 #endif #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE - #if !defined CO_CNT_TPDO - #define CO_CNT_TPDO 0 + #if !defined OD_CNT_TPDO + #define OD_CNT_TPDO 0 #define OD_ENTRY_H1800 NULL #define OD_ENTRY_H1A00 NULL - #elif CO_CNT_TPDO < 0 || CO_CNT_TPDO > 0x200 - #error CO_CNT_TPDO from OD.h not correct! + #elif OD_CNT_TPDO < 0 || OD_CNT_TPDO > 0x200 + #error OD_CNT_TPDO from OD.h not correct! #endif - #define CO_TX_CNT_TPDO CO_CNT_TPDO + #define CO_TX_CNT_TPDO OD_CNT_TPDO #else #define CO_TX_CNT_TPDO 0 #endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE - #define CO_CNT_LEDS 1 + #define OD_CNT_LEDS 1 #endif #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE - #if !defined CO_CNT_GFC - #define CO_CNT_GFC 0 + #if !defined OD_CNT_GFC + #define OD_CNT_GFC 0 #define OD_ENTRY_H1300 NULL - #elif CO_CNT_GFC < 0 || CO_CNT_GFC > 1 - #error CO_CNT_GFC from OD.h not correct! + #elif OD_CNT_GFC < 0 || OD_CNT_GFC > 1 + #error OD_CNT_GFC from OD.h not correct! #endif - #define CO_RX_CNT_GFC CO_CNT_GFC - #define CO_TX_CNT_GFC CO_CNT_GFC + #define CO_RX_CNT_GFC OD_CNT_GFC + #define CO_TX_CNT_GFC OD_CNT_GFC #else #define CO_RX_CNT_GFC 0 #define CO_TX_CNT_GFC 0 #endif #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE - #if !defined CO_CNT_SRDO - #define CO_CNT_SRDO 0 + #if !defined OD_CNT_SRDO + #define OD_CNT_SRDO 0 #define OD_ENTRY_H1301 NULL #define OD_ENTRY_H1381 NULL #define OD_ENTRY_H13FE NULL #define OD_ENTRY_H13FF NULL - #elif CO_CNT_SRDO < 0 || CO_CNT_SRDO > 64 - #error CO_CNT_SRDO from OD.h not correct! + #elif OD_CNT_SRDO < 0 || OD_CNT_SRDO > 64 + #error OD_CNT_SRDO from OD.h not correct! #endif - #define CO_RX_CNT_SRDO CO_CNT_SRDO - #define CO_TX_CNT_SRDO CO_CNT_SRDO + #define CO_RX_CNT_SRDO OD_CNT_SRDO + #define CO_TX_CNT_SRDO OD_CNT_SRDO #else #define CO_RX_CNT_SRDO 0 #define CO_TX_CNT_SRDO 0 #endif #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - #define CO_CNT_LSS_SLV 1 + #define OD_CNT_LSS_SLV 1 #else - #define CO_CNT_LSS_SLV 0 + #define OD_CNT_LSS_SLV 0 #endif -#define CO_RX_CNT_LSS_SLV CO_CNT_LSS_SLV -#define CO_TX_CNT_LSS_SLV CO_CNT_LSS_SLV +#define CO_RX_CNT_LSS_SLV OD_CNT_LSS_SLV +#define CO_TX_CNT_LSS_SLV OD_CNT_LSS_SLV #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER - #define CO_CNT_LSS_MST 1 + #define OD_CNT_LSS_MST 1 #else - #define CO_CNT_LSS_MST 0 + #define OD_CNT_LSS_MST 0 #endif -#define CO_RX_CNT_LSS_MST CO_CNT_LSS_MST -#define CO_TX_CNT_LSS_MST CO_CNT_LSS_MST +#define CO_RX_CNT_LSS_MST OD_CNT_LSS_MST +#define CO_TX_CNT_LSS_MST OD_CNT_LSS_MST #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - #define CO_CNT_GTWA 1 + #define OD_CNT_GTWA 1 #endif #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE - #if !defined CO_CNT_TRACE - #define CO_CNT_TRACE 0 - #elif CO_CNT_TRACE < 0 - #error CO_CNT_TRACE from OD.h not correct! + #if !defined OD_CNT_TRACE + #define OD_CNT_TRACE 0 + #elif OD_CNT_TRACE < 0 + #error OD_CNT_TRACE from OD.h not correct! #endif #endif @@ -721,16 +721,16 @@ void CO_delete(CO_t *co) { #endif static CO_t COO; static CO_CANmodule_t COO_CANmodule; - static CO_CANrx_t COO_CANmodule_rxArray[CO_CNT_ALL_RX_MSGS]; - static CO_CANtx_t COO_CANmodule_txArray[CO_CNT_ALL_TX_MSGS]; + static CO_CANrx_t COO_CANmodule_rxArray[OD_CNT_ALL_RX_MSGS]; + static CO_CANtx_t COO_CANmodule_txArray[OD_CNT_ALL_TX_MSGS]; static CO_NMT_t COO_NMT; #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE static CO_HBconsumer_t COO_HBcons; #endif static CO_EM_t COO_EM; - static CO_SDOserver_t COO_SDOserver[CO_CNT_SDO_SRV]; + static CO_SDOserver_t COO_SDOserver[OD_CNT_SDO_SRV]; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE - static CO_SDOclient_t COO_SDOclient[CO_CNT_SDO_CLI]; + static CO_SDOclient_t COO_SDOclient[OD_CNT_SDO_CLI]; #endif #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE static CO_TIME_t COO_TIME; @@ -739,10 +739,10 @@ void CO_delete(CO_t *co) { static CO_SYNC_t COO_SYNC; #endif #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE - static CO_RPDO_t COO_RPDO[CO_CNT_RPDO]; + static CO_RPDO_t COO_RPDO[OD_CNT_RPDO]; #endif #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE - static CO_TPDO_t COO_TPDO[CO_CNT_TPDO]; + static CO_TPDO_t COO_TPDO[OD_CNT_TPDO]; #endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE static CO_LEDs_t COO_LEDs; @@ -752,7 +752,7 @@ void CO_delete(CO_t *co) { #endif #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE static CO_SRDOGuard_t COO_SRDOGuard; - static CO_SRDO_t COO_SRDO[CO_CNT_SRDO]; + static CO_SRDO_t COO_SRDO[OD_CNT_SRDO]; #endif #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE static CO_LSSslave_t COO_LSSslave; @@ -767,9 +767,9 @@ void CO_delete(CO_t *co) { #ifndef CO_TRACE_BUFFER_SIZE_FIXED #define CO_TRACE_BUFFER_SIZE_FIXED 100 #endif - static CO_trace_t COO_trace[CO_CNT_TRACE]; - static uint32_t COO_traceTimeBuffers[CO_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; - static int32_t COO_traceValueBuffers[CO_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; + static CO_trace_t COO_trace[OD_CNT_TRACE]; + static uint32_t COO_traceTimeBuffers[OD_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; + static int32_t COO_traceValueBuffers[OD_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; #endif CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { diff --git a/CANopen.h b/CANopen.h index e7ebec21..450fb11c 100644 --- a/CANopen.h +++ b/CANopen.h @@ -162,7 +162,7 @@ extern "C" { /** * If macro is defined externally, then configuration with multiple object * dictionaries will be possible. If macro is not defined, default "OD.h" file - * with necessary definitions, such as CO_CNT_xxx, will be used, and also memory + * with necessary definitions, such as OD_CNT_xxx, will be used, and also memory * consumption and startup time will be lower. */ #ifdef CO_DOXYGEN @@ -549,7 +549,7 @@ bool_t CO_process_SYNC(CO_t *co, #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) || defined CO_DOXYGEN /** * Process CANopen RPDO objects. * @@ -565,7 +565,7 @@ void CO_process_RPDO(CO_t *co, bool_t syncWas); #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) || defined CO_DOXYGEN /** * Process CANopen TPDO objects. * diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index eebcab4e..3a1e76bb 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -99,9 +99,9 @@ Pair of ODxyz.h/.c files can be generated by OD editor tool. The tool can edit s ### Example ODxyz.h file ```c +/* OD data declaration of all groups ******************************************/ typedef struct { uint32_t x1000_deviceType; - uint8_t x1001_errorRegister; struct { uint8_t maxSubIndex; uint32_t vendorID; @@ -109,19 +109,28 @@ typedef struct { uint32_t revisionNumber; uint32_t serialNumber; } x1018_identity; -} ODxyz_0_t; +} ODxyz_PERSIST_COMM_t; typedef struct { uint8_t x1001_errorRegister; -} ODxyz_1_t; + uint8_t x1003_preDefinedErrorField_sub0; + uint32_t x1003_preDefinedErrorField[8]; +} ODxyz_RAM_t; -extern ODxyz_0_t ODxyz_0; -extern ODxyz_1_t ODxyz_1; +extern ODxyz_PERSIST_COMM_t ODxyz_PERSIST_COMM; +extern ODxyz_RAM_t ODxyz_RAM; extern const OD_t ODxyz; +/* Object dictionary entries - shortcuts **************************************/ #define ODxyz_ENTRY_H1000 &ODxyz.list[0] #define ODxyz_ENTRY_H1001 &ODxyz.list[1] -#define ODxyz_ENTRY_H1018 &ODxyz.list[2] +#define ODxyz_ENTRY_H1003 &ODxyz.list[2] +#define ODxyz_ENTRY_H1018 &ODxyz.list[3] + +#define ODxyz_ENTRY_H1000_deviceType &ODxyz.list[0] +#define ODxyz_ENTRY_H1001_errorRegister &ODxyz.list[1] +#define ODxyz_ENTRY_H1003_preDefinedErrorField &ODxyz.list[2] +#define ODxyz_ENTRY_H1018_identity &ODxyz.list[3] ``` ### Example ODxyz.c file @@ -130,89 +139,110 @@ extern const OD_t ODxyz; #include "301/CO_ODinterface.h" #include "ODxyz.h" -typedef struct { - OD_extensionIO_t xio_1001_errorRegister; -} ODxyz_ext_t; - -typedef struct { - OD_obj_var_t o_1000_deviceType; - OD_obj_var_t orig_1001_errorRegister; - OD_obj_extended_t o_1001_errorRegister; - OD_obj_var_t o_1018_identity[5]; -} ODxyz_objs_t; - -ODxyz_0_t ODxyz_0 = { +/* OD data initialization of all groups ***************************************/ +ODxyz_PERSIST_COMM_t ODxyz_PERSIST_COMM = { .x1000_deviceType = 0L, .x1018_identity = { .maxSubIndex = 4, .vendorID = 0L, .productCode = 0L, .revisionNumber = 0L, - .serialNumber = 0L, - }, + .serialNumber = 0L + } }; -ODxyz_1_t ODxyz_1 = { +ODxyz_RAM_t ODxyz_RAM = { .x1001_errorRegister = 0, + .x1003_preDefinedErrorField_sub0 = 0, + .x1003_preDefinedErrorField = {0, 0, 0, 0, 0, 0, 0, 0} }; -static ODxyz_ext_t ODxyz_ext = {0}; +/* IO extensions and flagsPDO (configurable by application) *******************/ +typedef struct { + OD_extensionIO_t xio_1003_preDefinedErrorField; +} ODxyzExts_t; -static const ODxyz_objs_t ODxyz_objs = { +static ODxyzExts_t ODxyzExts = {0}; + +/* All OD objects (constant) **************************************************/ +typedef struct { + OD_obj_var_t o_1000_deviceType; + OD_obj_var_t o_1001_errorRegister; + OD_obj_array_t o_1003_preDefinedErrorField; + OD_obj_extended_t oE_1003_preDefinedErrorField; + OD_obj_record_t o_1018_identity[5]; +} ODxyzObjs_t; + +static const ODxyzObjs_t ODxyzObjs = { .o_1000_deviceType = { - .data = &ODxyz_0.x1000_deviceType, + .data = &ODxyz_PERSIST_COMM.x1000_deviceType, .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, + .dataLength = 4 }, - .orig_1001_errorRegister = { - .data = &ODxyz_1.x1001_errorRegister, + .o_1001_errorRegister = { + .data = &ODxyz_RAM.x1001_errorRegister, .attribute = ODA_SDO_R, - .dataLength = 1, + .dataLength = 1 }, - .o_1001_errorRegister = { + .o_1003_preDefinedErrorField = { + .data0 = &ODxyz_RAM.x1003_preDefinedErrorField_sub0, + .data = &ODxyz_RAM.x1003_preDefinedErrorField[0], + .attribute0 = ODA_SDO_RW, + .attribute = ODA_SDO_R | ODA_MB, + .dataElementLength = 4, + .dataElementSizeof = sizeof(uint32_t) + }, + .oE_1003_preDefinedErrorField = { + .extIO = &ODxyzExts.xio_1003_preDefinedErrorField, .flagsPDO = NULL, - .extIO = &ODxyz_ext.xio_1001_errorRegister, - .odObjectOriginal = &ODxyz_objs.orig_1001_errorRegister, + .odObjectOriginal = &ODxyzObjs.o_1003_preDefinedErrorField }, .o_1018_identity = { { - .data = &ODxyz_0.x1018_identity.maxSubIndex, + .data = &ODxyz_PERSIST_COMM.x1018_identity.maxSubIndex, + .subIndex = 0, .attribute = ODA_SDO_R, - .dataLength = 1, + .dataLength = 1 }, { - .data = &ODxyz_0.x1018_identity.vendorID, + .data = &ODxyz_PERSIST_COMM.x1018_identity.vendorID, + .subIndex = 1, .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, + .dataLength = 4 }, { - .data = &ODxyz_0.x1018_identity.productCode, + .data = &ODxyz_PERSIST_COMM.x1018_identity.productCode, + .subIndex = 2, .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, + .dataLength = 4 }, { - .data = &ODxyz_0.x1018_identity.revisionNumber, + .data = &ODxyz_PERSIST_COMM.x1018_identity.revisionNumber, + .subIndex = 3, .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, + .dataLength = 4 }, { - .data = &ODxyz_0.x1018_identity.serialNumber, + .data = &ODxyz_PERSIST_COMM.x1018_identity.serialNumber, + .subIndex = 4, .attribute = ODA_SDO_R | ODA_MB, - .dataLength = 4, - }, + .dataLength = 4 + } } }; -static const OD_entry_t ODxyz_list[] = { - {0x1000, 0, 0, ODT_VAR, &ODxyz_objs.o_1000_deviceType}, - {0x1001, 0, 1, ODT_EVAR, &ODxyz_objs.o_1001_errorRegister}, - {0x1018, 4, 0, ODT_REC, &ODxyz_objs.o_1018_identity}, - {0x0000, 0, 0, 0, NULL} +/* Object dictionary **********************************************************/ +static const OD_entry_t ODxyzList[] = { + {0x1000, 1, ODT_VAR, &ODxyzObjs.o_1000_deviceType}, + {0x1001, 1, ODT_VAR, &ODxyzObjs.o_1001_errorRegister}, + {0x1003, 9, ODT_EVAR, &ODxyzObjs.oE_1003_preDefinedErrorField}, + {0x1018, 5, ODT_REC, &ODxyzObjs.o_1018_identity}, + {0x0000, 0, 0, NULL} }; -const OD_t OD = { - (sizeof(OD_list) / sizeof(OD_list[0])) - 1, - &ODxyz_list[0] +const OD_t ODxyz = { + (sizeof(ODxyzList) / sizeof(ODxyzList[0])) - 1, + &ODxyzList[0] }; ``` @@ -258,7 +288,7 @@ CANopenNode includes multiple profile definition files, one for each CANopen obj ... - + @@ -391,40 +421,50 @@ If "uniqueIDRef" attribute is not specified and "objectType" is 7(VAR), then "CA * "noAccess" - object will be in object dictionary, but no access. * <label lang="en"> (required) * <description lang="en"> (required) - * <UINT and similar/> (required) - Basic or complex data type. Basic data type (for VAR) is specified in IEC 61131-3 (see below). If data type is complex (ARRAY or RECORD), then <dataTypeIDRef> must be specified and entry must be added in the <dataTypeList>. Such definition of complex data types is required by the standard, but it is not required by CANopenNode. - * <defaultValue> (optional for VAR) - Default value for the variable. + * <INT and similar/> (required) - Basic or complex data type. Basic data type (for VAR) is specified in IEC 61131-3 (see below). If data type is complex (ARRAY or RECORD), then <dataTypeIDRef> must be specified and entry must be added in the <dataTypeList>. Such definition of complex data types is required by the standard, but it is not required by CANopenNode. + * <defaultValue> (optional for VAR) - Default value for the variable. If it is empty, then data is not stored inside object dictionary. Application should provide own data via IO extension. Additional, optional, CANopenNode specific properties, which can be used inside parameters describing <CANopenObject>: - * <property name="CO_storageGroup" value="..."> - group into which the C variable will belong. Variables from specific storage group may then be stored into non-volatile memory, automatically or by SDO command. Valid value is from 0x00 (default - not stored) to 0x7F. + * <property name="CO_storageGroup" value="..."> - group name (string) into which the C variable will belong. Variables from specific storage group may then be stored into non-volatile memory, automatically or by SDO command. * <property name="CO_extensionIO" value="..."> - Valid value is "false" (default) or "true", if IO extension is enabled. * <property name="CO_flagsPDO" value="..."> - Valid value is "false" (default) or "true", if PDO flags are enabled. * <property name="CO_countLabel" value="..."> - Valid value is any string without spaces. OD exporter will generate a macro for each different string. For example, if four OD objects have "CO_countLabel" set to "TPDO", then macro "#define ODxyz_CNT_TPDO 4" will be generated by OD exporter. Additional, optional, CANopenNode specific property, which can be used inside parameters describing "VAR": * <property name="CO_accessSRDO" value="..."> - Valid values are: "tx", "rx", "trx", "no"(default). - * <property name="CO_byteLength" value="..."> - Length of the variable in bytes, optionally used by string or domain. If CO_byteLength is not specified for string, then length is calculated from string <defaultValue>. + * <property name="CO_stringLength" value="..."> - Minimum length of the string. Used with "VISIBLE_STRING", "OCTET_STRING" and "UNICODE_STRING". If CO_stringLength smaller than length of string in <defaultValue>, then it is ignored. Byte length of unicode string is 2 * CO_stringLength. If <defaultValue> is empty and CO_stringLength is 0, then data is not stored inside object dictionary. #### CANopen basic data types -| CANopenNode | IEC 61131-3 | CANopen | dataType | -| ------------ | ------------ | --------------- | -------- | -| bool_t | BOOL | BOOLEAN | 0x01 | -| int8_t | CHAR, SINT | INTEGER8 | 0x02 | -| int16_t | INT | INTEGER16 | 0x03 | -| int32_t | DINT | INTEGER32 | 0x04 | -| int64_t | LINT | INTEGER64 | 0x15 | -| uint8_t | BYTE, USINT | UNSIGNED8 | 0x05 | -| uint16_t | WORD, UINT | UNSIGNED16 | 0x06 | -| uint32_t | DWORD, UDINT | UNSIGNED32 | 0x07 | -| uint64_t | LWORD, ULINT | UNSIGNED64 | 0x1B | -| float32_t | REAL | REAL32 | 0x08 | -| float64_t | LREAL | REAL64 | 0x11 | -| bytestring_t | STRING | VISIBLE_STRING | 0x09 | -| bytestring_t | - | OCTET_STRING | 0x0A | -| bytestring_t | WSTRING | UNICODE_STRING | 0x0B | -| bytestring_t | - | TIME_OF_DAY | 0x0C | -| bytestring_t | - | TIME_DIFFERENCE | 0x0D | -| bytestring_t | - | DOMAIN | 0x0F | -| bytestring_t | BITSTRING | - | - | +| CANopenNode | IEC 61131-3 | CANopen | dataType | +| -------------- | -------------- | --------------- | -------- | +| bool_t | BOOL | BOOLEAN | 0x01 | +| int8_t | SINT, (CHAR) | INTEGER8 | 0x02 | +| int16_t | INT | INTEGER16 | 0x03 | +| int32_t | DINT | INTEGER32 | 0x04 | +| int64_t | LINT | INTEGER64 | 0x15 | +| uint8_t | USINT, (BYTE) | UNSIGNED8 | 0x05 | +| uint16_t | UINT, (WORD) | UNSIGNED16 | 0x06 | +| uint32_t | UDINT, (DWORD) | UNSIGNED32 | 0x07 | +| uint64_t | ULINT, (LWORD) | UNSIGNED64 | 0x1B | +| float32_t | REAL | REAL32 | 0x08 | +| float64_t | LREAL | REAL64 | 0x11 | +| uint8_t [] (1) | BITSTRING (2) | INTEGER24 | 0x10 | +| uint8_t [] (1) | BITSTRING (2) | INTEGER40 | 0x12 | +| uint8_t [] (1) | BITSTRING (2) | INTEGER48 | 0x13 | +| uint8_t [] (1) | BITSTRING (2) | INTEGER56 | 0x14 | +| uint8_t [] (1) | BITSTRING (2) | UNSIGNED24 | 0x16 | +| uint8_t [] (1) | BITSTRING (2) | UNSIGNED40 | 0x18 | +| uint8_t [] (1) | BITSTRING (2) | UNSIGNED48 | 0x19 | +| uint8_t [] (1) | BITSTRING (2) | UNSIGNED56 | 0x1A | +| char [] | STRING | VISIBLE_STRING | 0x09 | +| uint8_t [] | BITSTRING (2) | OCTET_STRING | 0x0A | +| uint16_t [] | WSTRING | UNICODE_STRING | 0x0B | +| uint8_t [] (1) | BITSTRING (2) | TIME_OF_DAY | 0x0C | +| uint8_t [] (1) | BITSTRING (2) | TIME_DIFFERENCE | 0x0D | +| not used | BITSTRING (2) | DOMAIN | 0x0F | +(1) Data is stored in little-endian format. + +(2) CANopen specific type is stored as <BITSTRING/> in <parameter> and additional CANopen "dataType" attribute is stored in <CANopenObject> or <CANopenSubObject>. #### <parameterGroupList> This is optional element and is not required by standard, nor by CANopenNode. This can be very useful for documentation, which can be organised into multiple chapters with multiple levels. CANopen objects can then be organised in any way, not only by index. diff --git a/example/OD.c b/example/OD.c index 206e3051..83df9db5 100644 --- a/example/OD.c +++ b/example/OD.c @@ -3,7 +3,7 @@ #include "OD.h" static const OD_entry_t OD_list[] = { - {0x1000, 0, 0, 0, NULL} + {0x1000, 0, 0, NULL} }; const OD_t OD = { diff --git a/example/OD.h b/example/OD.h index b78928cb..dc6b69de 100644 --- a/example/OD.h +++ b/example/OD.h @@ -2,23 +2,23 @@ extern const OD_t OD; -#define CO_CNT_NMT 1 -#define CO_CNT_HB_PROD 1 -#define CO_CNT_EM 1 -#define CO_CNT_EM_PROD 1 -#define CO_CNT_SDO_SRV 1 -#define CO_CNT_SDO_CLI 1 +#define OD_CNT_NMT 1 +#define OD_CNT_HB_PROD 1 +#define OD_CNT_EM 1 +#define OD_CNT_EM_PROD 1 +#define OD_CNT_SDO_SRV 1 +#define OD_CNT_SDO_CLI 1 #if 0 -#define CO_CNT_HB_CONS 1 -#define CO_CNT_TIME 1 -#define CO_CNT_SYNC 1 -#define CO_CNT_SYNC_PROD 1 -#define CO_CNT_RPDO 4 -#define CO_CNT_TPDO 4 -#define CO_CNT_GFC 0 -#define CO_CNT_SRDO 0 -#define CO_CNT_TRACE 0 +#define OD_CNT_HB_CONS 1 +#define OD_CNT_TIME 1 +#define OD_CNT_SYNC 1 +#define OD_CNT_SYNC_PROD 1 +#define OD_CNT_RPDO 4 +#define OD_CNT_TPDO 4 +#define OD_CNT_GFC 0 +#define OD_CNT_SRDO 0 +#define OD_CNT_TRACE 0 #endif #define OD_ENTRY_H1017 &OD.list[0] From 0e317dddf31f6b142278060f9d37d86940306952 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 23 Oct 2020 10:49:01 +0200 Subject: [PATCH 131/520] Add CO_errinfo() into CO_driver.h and driver_targets. Add additional error info for 'CO_ERROR_OD_PARAMETERS'. --- 301/CO_Emergency.c | 4 ++++ 301/CO_NMT_Heartbeat.c | 1 + 301/CO_SDOclient.c | 2 ++ 301/CO_SDOserver.c | 17 +++++++++++------ 301/CO_driver.h | 19 +++++++++++++++++++ example/CO_driver_target.h | 5 +++++ socketCAN/CO_driver_target.h | 4 ++++ socketCAN/CO_error_msgs.h | 1 + socketCAN/CO_main_basic.c | 8 +++++++- 9 files changed, 54 insertions(+), 7 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 55091753..b7210a1d 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -392,6 +392,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* get and verify "Error register" from Object Dictionary */ if (OD_getPtr_u8(OD_1001_errReg, 0, &em->errorRegister) != ODR_OK) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1001_errReg)); return CO_ERROR_OD_PARAMETERS; } *em->errorRegister = 0; @@ -401,6 +402,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint32_t COB_IDEmergency32; ODR_t odRet0 = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); if (odRet0 != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; } @@ -412,6 +414,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, (void *) em, OD_read_1014, OD_write_1014)) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; } /* following two variables are used inside OD_read_1014 and OD_write_1014 */ @@ -428,6 +431,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, (void *) em, OD_read_1014_default, OD_writeOriginal)) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; } #endif diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index eeb7ab6b..ca02750c 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -126,6 +126,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, /* get and verify required "Producer heartbeat time" from Object Dict. */ uint16_t HBprodTime_ms; if (OD_get_u16(OD_1017_ProducerHbTime, 0, &HBprodTime_ms, true) != ODR_OK) { + CO_errinfo(NMT_CANdevRx, OD_getIndex(OD_1017_ProducerHbTime)); return CO_ERROR_OD_PARAMETERS; } NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000; diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 879077dc..c9c96951 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -284,6 +284,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, if (odRet0 != ODR_OK || maxSubIndex != 3 || odRet1 != ODR_OK || odRet2 != ODR_OK || odRet3 != ODR_OK ) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1280_SDOcliPar)); return CO_ERROR_OD_PARAMETERS; } @@ -292,6 +293,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, (void *)SDO_C, OD_readOriginal, OD_write_1280)) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1280_SDOcliPar)); return CO_ERROR_OD_PARAMETERS; } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 266ddad7..5231a533 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -388,9 +388,11 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (!OD_extensionIO_init(OD_1200_SDOsrvPar, (void *) SDO, OD_read_1200_default, - NULL)) { - return CO_ERROR_OD_PARAMETERS; - } + NULL) + ) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1200_SDOsrvPar)); + return CO_ERROR_OD_PARAMETERS; + } } else if (OD_getIndex(OD_1200_SDOsrvPar) > OD_H1200_SDO_SERVER_1_PARAM && OD_getIndex(OD_1200_SDOsrvPar) <= (OD_H1200_SDO_SERVER_1_PARAM+0x7F) @@ -409,6 +411,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (odRet0 != ODR_OK || (maxSubIndex != 2 && maxSubIndex != 3) || odRet1 != ODR_OK || odRet2 != ODR_OK ) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1200_SDOsrvPar)); return CO_ERROR_OD_PARAMETERS; } @@ -422,9 +425,11 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (!OD_extensionIO_init(OD_1200_SDOsrvPar, (void *) SDO, OD_readOriginal, - OD_write_1201_additional)) { - return CO_ERROR_OD_PARAMETERS; - } + OD_write_1201_additional) + ) { + CO_errinfo(CANdevTx, OD_getIndex(OD_1200_SDOsrvPar)); + return CO_ERROR_OD_PARAMETERS; + } #endif } else { diff --git a/301/CO_driver.h b/301/CO_driver.h index 1d87ab2c..08ebf226 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -324,6 +324,7 @@ typedef struct { volatile uint16_t CANtxCount; /**< Number of messages in transmit buffer, which are waiting to be copied to the CAN module */ uint32_t errOld; /**< Previous state of CAN errors */ + int32_t errinfo; /**< For use with @ref CO_errinfo() */ } CO_CANmodule_t; @@ -393,6 +394,24 @@ typedef struct { #endif /* CO_DOXYGEN */ +/** Macro for passing additional information about error. + * + * This macro is called from several CANopen init functions, which returns + * @ref CO_ReturnError_t. + * + * CO_driver_target.h may implement this macro. Usually macro only sets + * CANmodule->errinfo to err. Application may then use CANmodule->errinfo to + * determine the reason of failure. errinfo must be type of int32_t. By default + * macro does not record anything. + * + * CO_errinfo is called in following @ref CO_ReturnError_t reasons: + * - 'CO_ERROR_OD_PARAMETERS' - Index of erroneous OD parameter. + */ +#ifndef CO_errinfo +#define CO_errinfo(CANmodule, err) +#endif + + /** * Default CANopen identifiers. * diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index b0eed35c..735ff530 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -182,6 +182,10 @@ extern "C" { #endif +/* Macro for passing additional information about error, see CO_driver.h. */ +#define CO_errinfo(CANmodule, err) CANmodule->errinfo = err + + /* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ #define CO_LITTLE_ENDIAN #define CO_SWAP_16(x) x @@ -234,6 +238,7 @@ typedef struct { volatile bool_t firstCANtxMessage; volatile uint16_t CANtxCount; uint32_t errOld; + int32_t errinfo; } CO_CANmodule_t; diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index de97cd03..c6ac2568 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -194,6 +194,9 @@ extern "C" { * Linux socketCAN specific @ref CO_driver definitions for CANopenNode. */ +/* Macro for passing additional information about error, see CO_driver.h. */ +#define CO_errinfo(CANmodule, err) CANmodule->errinfo = err + /** * Multi interface support * @@ -347,6 +350,7 @@ typedef struct { CO_CANtx_t *txArray; uint16_t txSize; uint16_t CANerrorStatus; + int32_t errinfo; volatile bool_t CANnormal; int epoll_fd; /* File descriptor for epoll, which waits for CAN receive event */ diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index fc799f20..7ad1182a 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -77,6 +77,7 @@ extern "C" { #define DBG_WRONG_PRIORITY "(%s) Wrong RT priority \"%d\"", __func__ #define DBG_NO_CAN_DEVICE "(%s) Can't find CAN device \"%s\"", __func__ #define DBG_OBJECT_DICTIONARY "(%s) Error in Object Dictionary \"%s\"", __func__ +#define DBG_OD_ENTRY "(%s) Error in Object Dictionary entry: 0x%X", __func__ #define DBG_CAN_OPEN "(%s) CANopen error in %s, err=%d", __func__ #define DBG_CAN_OPEN_INFO "CANopen device, Node ID = 0x%02X, %s" diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 52281a59..bf45ea20 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -500,7 +500,13 @@ int main (int argc, char *argv[]) { SDO_TIMEOUT_TIME, /* SDOtimeoutTime_ms */ CO_activeNodeId); if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); + if (err == CO_ERROR_OD_PARAMETERS) { + log_printf(LOG_CRIT, DBG_OD_ENTRY, + (uint16_t)CO->CANmodule->errinfo); + } + else { + log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); + } exit(EXIT_FAILURE); } From 82eeec2d2351fd0261210506dfdbd25904e222fc Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 26 Oct 2020 18:08:34 +0100 Subject: [PATCH 132/520] Fix gateway socket hangup handling. Speed-up gateway processing. Same as 65464f8f --- socketCAN/CO_epoll_interface.c | 11 +++++++---- socketCAN/CO_main_basic.c | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c index de2f7c72..8406f811 100644 --- a/socketCAN/CO_epoll_interface.c +++ b/socketCAN/CO_epoll_interface.c @@ -537,10 +537,6 @@ void CO_epoll_processGtw(CO_epoll_gtw_t *epGtw, && (ep->ev.data.fd == epGtw->gtwa_fdSocket || ep->ev.data.fd == epGtw->gtwa_fd) ) { - if ((ep->ev.events & (EPOLLERR | EPOLLHUP)) != 0) { - log_printf(LOG_DEBUG, DBG_GENERAL, - "socket error or hangup, event=", ep->ev.events); - } if ((ep->ev.events & EPOLLIN) != 0 && ep->ev.data.fd == epGtw->gtwa_fdSocket ) { @@ -630,6 +626,13 @@ void CO_epoll_processGtw(CO_epoll_gtw_t *epGtw, ep->epoll_new = false; } + else if ((ep->ev.events & (EPOLLERR | EPOLLHUP)) != 0) { + log_printf(LOG_DEBUG, DBG_GENERAL, + "socket error or hangup, event=", ep->ev.events); + if (close(epGtw->gtwa_fd) < 0) { + log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd, hangup)"); + } + } } /* if (ep->epoll_new) */ /* if socket connection is established, verify timeout */ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index bf45ea20..d38c1d1f 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -594,10 +594,10 @@ int main (int argc, char *argv[]) { #ifdef CO_SINGLE_THREAD CO_epoll_processRT(&epMain, CO, false); #endif - CO_epoll_processMain(&epMain, CO, GATEWAY_ENABLE, &reset); #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_processGtw(&epGtw, CO, &epMain); #endif + CO_epoll_processMain(&epMain, CO, GATEWAY_ENABLE, &reset); CO_epoll_processLast(&epMain); #ifdef CO_USE_APPLICATION From ace840fa6c6c390768a15ccba9b47d95b4e199b6 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 26 Oct 2020 18:16:00 +0100 Subject: [PATCH 133/520] Fix ODinterface, basic tests passed. --- 301/CO_NMT_Heartbeat.c | 12 ++++++++---- 301/CO_ODinterface.c | 2 +- CANopen.c | 16 ++++++++-------- doc/objectDictionary.md | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index ca02750c..06644172 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -130,10 +130,14 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, return CO_ERROR_OD_PARAMETERS; } NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000; - OD_extensionIO_init(OD_1017_ProducerHbTime, - (void *) NMT, - OD_readOriginal, - OD_write_1017); + if (!OD_extensionIO_init(OD_1017_ProducerHbTime, + (void *) NMT, + OD_readOriginal, + OD_write_1017) + ) { + CO_errinfo(HB_CANdevTx, OD_getIndex(OD_1017_ProducerHbTime)); + return CO_ERROR_OD_PARAMETERS; + } if (NMT->HBproducerTimer > NMT->HBproducerTime_us) { NMT->HBproducerTimer = NMT->HBproducerTime_us; } diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 886b76cf..e2d329ec 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -255,7 +255,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, else if (odBasicType == ODT_REC) { const OD_obj_record_t *odoArr = (const OD_obj_record_t *)odObjectOrig; const OD_obj_record_t *odo = NULL; - for (int i; i< entry->subEntriesCount; i++) { + for (int i = 0; i< entry->subEntriesCount; i++) { if (odoArr[i].subIndex == subIndex) { odo = &odoArr[i]; break; diff --git a/CANopen.c b/CANopen.c index dafe2124..ecc19a7d 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1320,6 +1320,14 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, bool_t NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL || NMTstate == CO_NMT_OPERATIONAL); + /* SDOserver */ + for (uint8_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { + CO_SDOserver_process(co->SDOserver, + NMTisPreOrOperational, + timeDifference_us, + timerNext_us); + } + #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE if (CO_GET_CNT(HB_CONS) == 1) { CO_HBconsumer_process(co->HBcons, @@ -1337,14 +1345,6 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, timerNext_us); } - /* SDOserver */ - for (uint8_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { - CO_SDOserver_process(co->SDOserver, - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); - } - #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE if (CO_GET_CNT(TIME) == 1) { CO_TIME_process(co->TIME, timeDifference_us); diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 3a1e76bb..6a6545b3 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -504,7 +504,7 @@ Other elements listed in the above XML example are required by the standard and | 1014 | COB-ID EMCY | EM_PRODUCER, req | required | EM_PROD | | 1015 | Inhibit time EMCY | EM_PROD_INHIBIT, opt | optional | | | 1016 | Consumer heartbeat time | HB_CONS, req | optional | HB_CONS | -| 1017 | Producer heartbeat time | CANopen, NMT, req | optional | HB_PROD | +| 1017 | Producer heartbeat time | CANopen, NMT, req | required | HB_PROD | | 1018 | Identity object | CANopen, LSS_SL, req | no | | | 1019 | Synch. counter overflow value | SYNC, opt | no | | | 1020 | Verify configuration | | | | From 5a7520d36d589f0b28693a34a932f18c746959a8 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 26 Oct 2020 18:18:11 +0100 Subject: [PATCH 134/520] Reduce scope of local variables to avoid warning about shadowing, #241 --- 305/CO_LSSslave.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 6e2f7e2c..72c7c2ea 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -73,24 +73,27 @@ static void CO_LSSslave_receive(void *object, void *msg) } } else if(LSSslave->lssState == CO_LSS_STATE_WAITING) { - uint32_t valSw; switch (cs) { case CO_LSS_SWITCH_STATE_SEL_VENDOR: { + uint32_t valSw; memcpy(&valSw, &data[1], sizeof(valSw)); LSSslave->lssSelect.identity.vendorID = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_PRODUCT: { + uint32_t valSw; memcpy(&valSw, &data[1], sizeof(valSw)); LSSslave->lssSelect.identity.productCode = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_REV: { + uint32_t valSw; memcpy(&valSw, &data[1], sizeof(valSw)); LSSslave->lssSelect.identity.revisionNumber = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_SERIAL: { + uint32_t valSw; memcpy(&valSw, &data[1], sizeof(valSw)); LSSslave->lssSelect.identity.serialNumber = CO_SWAP_32(valSw); From ee1d8d0c81f270d286bcfb2256dc5ba51e54640c Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 26 Oct 2020 19:05:26 +0100 Subject: [PATCH 135/520] Restore CO_CONFIG_HB_CONS_CALLBACK_CHANGE option, same as #241 --- 301/CO_HBconsumer.c | 57 ++++++++++++++++++++++++++++++-------- 301/CO_HBconsumer.h | 25 +++++++++++++---- 301/CO_config.h | 7 +++-- example/CO_driver_target.h | 1 - socketCAN/CO_error_msgs.h | 2 +- socketCAN/CO_main_basic.c | 4 +-- 6 files changed, 73 insertions(+), 23 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index a8515985..e2b09f62 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -31,6 +31,12 @@ #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +/* Verify HB consumer configuration *******************************************/ +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ + && (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#error CO_CONFIG_HB_CONS_CALLBACK_CHANGE and CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously! +#endif + /* * Read received message from CAN module. * @@ -137,6 +143,7 @@ CO_ReturnError_t CO_HBconsumer_init( HBcons->monitoredNodes[i].pFunctSignalPre = NULL; #endif #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI + HBcons->monitoredNodes[i].pFunctSignalNmtChanged = NULL; HBcons->monitoredNodes[i].pFunctSignalHbStarted = NULL; HBcons->monitoredNodes[i].pFunctSignalTimeout = NULL; HBcons->monitoredNodes[i].pFunctSignalRemoteReset = NULL; @@ -185,7 +192,8 @@ CO_ReturnError_t CO_HBconsumer_initEntry( monitoredNode->nodeId = nodeId; monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; monitoredNode->NMTstate = CO_NMT_UNKNOWN; -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ + || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -239,7 +247,7 @@ void CO_HBconsumer_initCallbackPre( void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, void *object, - void (*pFunctSignal)(uint8_t nodeId, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t NMTstate, void *object)) { @@ -254,6 +262,25 @@ void CO_HBconsumer_initCallbackNmtChanged( #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +/******************************************************************************/ +void CO_HBconsumer_initCallbackNmtChanged( + CO_HBconsumer_t *HBcons, + uint8_t idx, + void *object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, + CO_NMT_internalState_t NMTstate, + void *object)) +{ + if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { + return; + } + + CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[idx]; + monitoredNode->pFunctSignalNmtChanged = pFunctSignal; + monitoredNode->pFunctSignalObjectNmtChanged = object; +} + + /******************************************************************************/ void CO_HBconsumer_initCallbackHeartbeatStarted( CO_HBconsumer_t *HBcons, @@ -321,18 +348,16 @@ void CO_HBconsumer_process( { (void)timerNext_us; /* may be unused */ - uint8_t i; bool_t allMonitoredActiveCurrent = true; uint8_t allMonitoredOperationalCurrent = CO_NMT_OPERATIONAL; - CO_HBconsNode_t *monitoredNode = &HBcons->monitoredNodes[0]; if (NMTisPreOrOperational && HBcons->NMTisPreOrOperationalPrev) { - for (i=0; inumberOfMonitoredNodes; i++) { + for (uint8_t i=0; inumberOfMonitoredNodes; i++) { uint32_t timeDifference_us_copy = timeDifference_us; + CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[i]; if (monitoredNode->HBstate == CO_HBconsumer_UNCONFIGURED) { /* continue, if node is not monitored */ - monitoredNode++; continue; } /* Verify if received message is heartbeat or bootup */ @@ -409,32 +434,40 @@ void CO_HBconsumer_process( if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { allMonitoredOperationalCurrent = CO_NMT_UNKNOWN; } -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ + || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI /* Verify, if NMT state of monitored node changed */ if(monitoredNode->NMTstate != monitoredNode->NMTstatePrev) { +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE if (HBcons->pFunctSignalNmtChanged != NULL) { HBcons->pFunctSignalNmtChanged( - monitoredNode->nodeId, monitoredNode->NMTstate, + monitoredNode->nodeId, i, monitoredNode->NMTstate, HBcons->pFunctSignalObjectNmtChanged); +#else + if (monitoredNode->pFunctSignalNmtChanged != NULL) { + monitoredNode->pFunctSignalNmtChanged( + monitoredNode->nodeId, i, monitoredNode->NMTstate, + monitoredNode->pFunctSignalObjectNmtChanged); +#endif } monitoredNode->NMTstatePrev = monitoredNode->NMTstate; } #endif - monitoredNode++; } } else if (NMTisPreOrOperational || HBcons->NMTisPreOrOperationalPrev) { /* (pre)operational state changed, clear variables */ - for(i=0; inumberOfMonitoredNodes; i++) { + for(uint8_t i=0; inumberOfMonitoredNodes; i++) { + CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[i]; monitoredNode->NMTstate = CO_NMT_UNKNOWN; -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ + || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; } - monitoredNode++; } allMonitoredActiveCurrent = false; allMonitoredOperationalCurrent = CO_NMT_UNKNOWN; diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 2a317599..421032ff 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -91,11 +91,20 @@ typedef struct { /** From CO_HBconsumer_initCallbackPre() or NULL */ void *functSignalObjectPre; #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) \ + || ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) \ + || defined CO_DOXYGEN /** Previous value of the remote node (Heartbeat payload) */ CO_NMT_internalState_t NMTstatePrev; #endif #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) || defined CO_DOXYGEN + /** Callback for remote NMT changed event. + * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ + void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, + CO_NMT_internalState_t state, + void *object); + /** Pointer to object */ + void *pFunctSignalObjectNmtChanged; /** Callback for heartbeat state change to active event. * From CO_HBconsumer_initCallbackHeartbeatStarted() or NULL. */ void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void *object); @@ -138,7 +147,7 @@ typedef struct{ #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) || defined CO_DOXYGEN /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ - void (*pFunctSignalNmtChanged)(uint8_t nodeId, + void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t state, void *object); /** Pointer to object */ @@ -214,7 +223,9 @@ void CO_HBconsumer_initCallbackPre( void (*pFunctSignal)(void *object)); #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) || defined CO_DOXYGEN +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) \ + || ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) \ + || defined CO_DOXYGEN /** * Initialize Heartbeat consumer NMT changed callback function. * @@ -222,14 +233,19 @@ void CO_HBconsumer_initCallbackPre( * state from the remote node changes. * * @param HBcons This object. + * @param idx index of the node in HBcons object (only when + * CO_CONFIG_HB_CONS_CALLBACK_MULTI is enabled) * @param object Pointer to object, which will be passed to pFunctSignal(). * Can be NULL. * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) || defined CO_DOXYGEN + uint8_t idx, +#endif void *object, - void (*pFunctSignal)(uint8_t nodeId, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t state, void *object)); #endif @@ -253,7 +269,6 @@ void CO_HBconsumer_initCallbackHeartbeatStarted( void *object, void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); - /** * Initialize Heartbeat consumer timeout callback function. * diff --git a/301/CO_config.h b/301/CO_config.h index d455b99e..58872e64 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -135,16 +135,19 @@ extern "C" { * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_HBconsumer_process(). * - CO_CONFIG_HB_CONS_ENABLE - Enable heartbeat consumer. - * - CO_CONFIG_HB_CONS_CALLBACK_CHANGE - Enable custom callback after NMT + * - CO_CONFIG_HB_CONS_CALLBACK_CHANGE - Enable custom common callback after NMT * state of the monitored node changes. Callback is configured by * CO_HBconsumer_initCallbackNmtChanged(). * - CO_CONFIG_HB_CONS_CALLBACK_MULTI - Enable multiple custom callbacks, which - * can be configured for each monitored node. Callback are configured by + * can be configured individually for each monitored node. Callbacks are + * configured by CO_HBconsumer_initCallbackNmtChanged(), * CO_HBconsumer_initCallbackHeartbeatStarted(), * CO_HBconsumer_initCallbackTimeout() and * CO_HBconsumer_initCallbackRemoteReset() functions. * - CO_CONFIG_HB_CONS_QUERY_FUNCT - Enable functions for query HB state or * NMT state of the specific monitored node. + * Note that CO_CONFIG_HB_CONS_CALLBACK_CHANGE and + * CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously. */ #ifdef CO_DOXYGEN #define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE) diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 735ff530..f2dd4957 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -53,7 +53,6 @@ extern "C" { #ifndef CO_CONFIG_HB_CONS #define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ - CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ CO_CONFIG_HB_CONS_CALLBACK_MULTI | \ CO_CONFIG_HB_CONS_QUERY_FUNCT | \ CO_CONFIG_FLAG_CALLBACK_PRE | \ diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index 7ad1182a..ae76d566 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -70,7 +70,7 @@ extern "C" { /* mainline */ #define DBG_EMERGENCY_RX "CANopen Emergency message from node 0x%02X: errorCode=0x%04X, errorRegister=0x%02X, errorBit=0x%02X, infoCode=0x%08X" #define DBG_NMT_CHANGE "CANopen NMT state changed to: \"%s\" (%d)" -#define DBG_HB_CONS_NMT_CHANGE "CANopen Remote node ID = 0x%02X: NMT state changed to: \"%s\" (%d)" +#define DBG_HB_CONS_NMT_CHANGE "CANopen Remote node ID = 0x%02X (index = %d): NMT state changed to: \"%s\" (%d)" #define DBG_ARGUMENT_UNKNOWN "(%s) Unknown %s argument: \"%s\"", __func__ #define DBG_NOT_TCP_PORT "(%s) -c argument \"%s\" is not a valid tcp port", __func__ #define DBG_WRONG_NODE_ID "(%s) Wrong node ID \"%d\"", __func__ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index d38c1d1f..59494a9c 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -186,13 +186,13 @@ static void NmtChangedCallback(CO_NMT_internalState_t state) #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE /* callback for monitoring Heartbeat remote NMT state change */ -static void HeartbeatNmtChangedCallback(uint8_t nodeId, +static void HeartbeatNmtChangedCallback(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t state, void *object) { (void)object; log_printf(LOG_NOTICE, DBG_HB_CONS_NMT_CHANGE, - nodeId, NmtState2Str(state), state); + nodeId, idx, NmtState2Str(state), state); } #endif From 8e2de726a51b1110acf84bea29eba2d8911c771e Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 27 Oct 2020 13:13:13 +0100 Subject: [PATCH 136/520] works also with globals --- CANopen.c | 4 ++-- Makefile | 10 +++++----- doc/gettingStarted.md | 15 ++++++++------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/CANopen.c b/CANopen.c index ecc19a7d..d2b1a4d0 100644 --- a/CANopen.c +++ b/CANopen.c @@ -721,8 +721,8 @@ void CO_delete(CO_t *co) { #endif static CO_t COO; static CO_CANmodule_t COO_CANmodule; - static CO_CANrx_t COO_CANmodule_rxArray[OD_CNT_ALL_RX_MSGS]; - static CO_CANtx_t COO_CANmodule_txArray[OD_CNT_ALL_TX_MSGS]; + static CO_CANrx_t COO_CANmodule_rxArray[CO_CNT_ALL_RX_MSGS]; + static CO_CANtx_t COO_CANmodule_txArray[CO_CNT_ALL_TX_MSGS]; static CO_NMT_t COO_NMT; #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE static CO_HBconsumer_t COO_HBcons; diff --git a/Makefile b/Makefile index dad8ffe6..385bddae 100644 --- a/Makefile +++ b/Makefile @@ -47,11 +47,11 @@ SOURCES = \ OBJS = $(SOURCES:%.c=%.o) CC ?= gcc -OPT = -g -pedantic -#OPT = -g -pedantic -fanalyzer -#OPT = -g -pedantic -DCO_USE_GLOBALS -#OPT = -g -pedantic -DCO_MULTIPLE_OD -#OPT = -g -pedantic -DCO_SINGLE_THREAD +OPT = -g +#OPT = -g -pedantic -Wshadow -fanalyzer +#OPT = -g -DCO_USE_GLOBALS +#OPT = -g -DCO_MULTIPLE_OD +#OPT = -g -DCO_SINGLE_THREAD CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = -pthread #LDFLAGS = diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index 4739e603..b8245d74 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -158,21 +158,22 @@ Please be careful when exposing your CANopen network to the outside world, it is ### Next steps -Now you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware). - -You can also build your own CANopen device with your favourite microcontroller, see *deviceSupport.md*. There is also a bare-metal demo for [PIC microcontrollers](https://github.com/CANopenNode/CANopenPIC), most complete example is for PIC32. - Assigning Node-ID or CAN bitrate, which support LSS configuration, is described in *LSSusage.md*. Some further CANopenNode related Linux tools are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket). +Custom CANopen device can be created based on own Object Dictionary. Use *EDSEditor.exe* from https://github.com/robincornelius/libedssharp to generate one. It runs in Linux or Windows. For principles see *objectDictionary.md*. There are also many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download, for example CiA401. + +For own CANopen device with own microcontroller, see *deviceSupport.md*. There is a bare-metal demo for [PIC microcontrollers](https://github.com/CANopenNode/CANopenPIC), most complete example is for PIC32. + +Another interesting tool is [CANopen for Python](https://github.com/christiansandberg/canopen). + Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native in Linux kernel are: - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with: `sudo slcand -f -o -c -s8 /dev/ttyACM0 can0; sudo ip link set up can0` - [EMS CPC-USB](https://www.ems-wuensche.com/?post_type=product&p=746) or [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Start with: `sudo ip link set up can0 type can bitrate 250000` - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can) (Kconfig files). - Raspberry PI or similar has CAN capes available. -With [CANopenNode](https://github.com/CANopenNode/CANopenNode) you can also design your own device. There are many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download. +Now you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware). -Here we played with virtual CAN interface and result shows as pixels on screen. If you connect real CAN interface to your computer, things may -become dangerous. Keep control and safety on your machines! +Here we played with virtual CAN interface and result shown as pixels on screen. If you connect a real CAN interface to your computer, things may become dangerous. Keep control and safety on your machines! From da850252bd2df86748ab98b4fab1b09c13d35abc Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 29 Oct 2020 09:38:21 +0100 Subject: [PATCH 137/520] Set CANopenNode version V3.0 Added macros CO_VERSION_MAJOR and CO_VERSION_MINOR into driver.h --- 301/CO_driver.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/301/CO_driver.h b/301/CO_driver.h index 08ebf226..02e50190 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -89,6 +89,11 @@ extern "C" { * (or interrupts), CAN module, etc.). */ +/** Major version number of CANopenNode */ +#define CO_VERSION_MAJOR 3 +/** Minor version number of CANopenNode */ +#define CO_VERSION_MINOR 0 + /* Macros and declarations in following part are only used for documentation. */ #ifdef CO_DOXYGEN From 5a14e91834ae2d71a838bbb2850ebcad3076f654 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 29 Oct 2020 09:56:40 +0100 Subject: [PATCH 138/520] Set CANopenNode version V4.0 Skip V3.0, because there exists some old version numbering from SouceForge. V3.00 exists also in old CO_OD.c. Use 4.0 to avoid confusion. --- 301/CO_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_driver.h b/301/CO_driver.h index 02e50190..ce2eb4bf 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -90,7 +90,7 @@ extern "C" { */ /** Major version number of CANopenNode */ -#define CO_VERSION_MAJOR 3 +#define CO_VERSION_MAJOR 4 /** Minor version number of CANopenNode */ #define CO_VERSION_MINOR 0 From a6ce313387ca066e6b96249bd7a62eb6ad0969e4 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 28 Nov 2020 12:17:48 +0100 Subject: [PATCH 139/520] New Object Dictionary project file, etc. Remove old OD. Update doc. --- 301/CO_NMT_Heartbeat.h | 2 +- 301/CO_TIME.h | 16 +- Doxyfile | 1 + README.md | 51 +- doc/gettingStarted.md | 34 +- doc/index.html | 1 - doc/objectDictionary.md | 134 +- example/CO_OD.c | 348 -- example/CO_OD.h | 460 --- example/CO_OD_with_trace/CO_OD.c | 385 -- example/CO_OD_with_trace/CO_OD.h | 451 -- example/DS301_profile.eds | 1688 ++++++++ example/DS301_profile.md | 738 ++++ example/DS301_profile.xpd | 2631 ++++++++++++ example/IO.eds | 2800 ------------- example/IO.html | 6627 ------------------------------ example/OD.c | 1369 +++++- example/OD.h | 349 +- example/_project.html | 311 -- example/_project.xml | 960 ----- 20 files changed, 6862 insertions(+), 12494 deletions(-) delete mode 120000 doc/index.html delete mode 100644 example/CO_OD.c delete mode 100644 example/CO_OD.h delete mode 100644 example/CO_OD_with_trace/CO_OD.c delete mode 100644 example/CO_OD_with_trace/CO_OD.h create mode 100644 example/DS301_profile.eds create mode 100644 example/DS301_profile.md create mode 100644 example/DS301_profile.xpd delete mode 100644 example/IO.eds delete mode 100644 example/IO.html delete mode 100644 example/_project.html delete mode 100644 example/_project.xml diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index cd657cb0..51d87e31 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -125,7 +125,7 @@ typedef enum { /** * NMT control bitfield for NMT internal state. * - * Variable of this type is passed to @ref CO_NMT_process() function. It + * Variable of this type is passed to @ref CO_NMT_init() function. It * controls behavior of the @ref CO_NMT_internalState_t of the device according * to CANopen error register. * diff --git a/301/CO_TIME.h b/301/CO_TIME.h index f7dcefa7..44cdf3cb 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -27,7 +27,6 @@ #define CO_TIME_H #include "301/CO_driver.h" -#include "CO_OD.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_TIME @@ -79,6 +78,21 @@ extern "C" { #define TIME_MSG_LENGTH 6U +#ifndef timeOfDay_t +typedef union { + unsigned long long ullValue; + struct { + unsigned long ms:28; + unsigned reserved:4; + unsigned days:16; + unsigned reserved2:16; + }; +} timeOfDay_t; +#endif + +typedef timeOfDay_t TIME_OF_DAY; +typedef timeOfDay_t TIME_DIFFERENCE; + /** * TIME producer and consumer object. */ diff --git a/Doxyfile b/Doxyfile index fa8eb200..064509f9 100644 --- a/Doxyfile +++ b/Doxyfile @@ -821,6 +821,7 @@ WARN_LOGFILE = INPUT = README.md \ doc \ + example/DS301_profile.md \ CANopen.h \ 301 \ 303 \ diff --git a/README.md b/README.md index 7741a452..ea217202 100644 --- a/README.md +++ b/README.md @@ -165,15 +165,15 @@ File structure - **example/** - Directory with basic example, should compile on any system. - **CO_driver_target.h** - Example hardware definitions for CANopenNode. - **CO_driver_blank.c** - Example blank interface for CANopenNode. - - **CO_OD.h/.c** - CANopen Object dictionary. Automatically generated files. - **main_blank.c** - Mainline and other threads - example template. - **Makefile** - Makefile for example. - - **IO.eds** - Standard CANopen EDS file, which may be used from CANopen - configuration tool. Automatically generated file. - - _ **project.xml** - XML file contains all data for CANopen Object dictionary. - It is used by *Object dictionary editor* application, which generates other - files. - - _ **project.html** - *Object dictionary editor* launcher. + - **DS301_profile.xpd** - CANopen device description file for DS301. It + includes also CANopenNode specific properties. This file is also available + in Profiles in Object dictionary editor. + - **DS301_profile.eds**, **DS301_profile.md** - Standard CANopen EDS file and + markdown documentation file, automatically generated from DS301_profile.xpd. + - **OD.h/.c** - CANopen Object dictionary source files, automatically + generated from DS301_profile.xpd. - **socketCAN/** - Directory for Linux socketCAN interface. - **CO_driver_target.h** - Linux socketCAN specific definitions for CANopenNode. - **CO_driver.c** - Interface between Linux socketCAN and CANopenNode. @@ -187,7 +187,6 @@ File structure - **deviceSupport.md** - Information about supported devices. - **gettingStarted.md, LSSusage.md, traceUsage.md** - Getting started and usage. - **objectDictionary.md** - Description of CANopen object dictionary interface. - - **index.html** - Soft link to html/md_README.html. - **html** - Directory with documentation - must be generated by Doxygen. - **CANopen.h/.c** - Initialization and processing of CANopen objects. - **codingStyle** - Example of the coding style. @@ -201,17 +200,35 @@ File structure Object dictionary editor ------------------------ -Object Dictionary is one of the most important parts of CANopen. Its -implementation in CANopenNode is quite outdated and there are efforts to -rewrite it. Anyway, currently it is fully operational and works well. +Object Dictionary is one of the most essential parts of CANopen. To customize the Object Dictionary it is necessary to use external application: -[libedssharp](https://github.com/robincornelius/libedssharp). It can be used in -Windows or Linux with Mono. - -Please note: since rearrangement in directory structure it is necessary to -manually update CO_OD.c file - it must include: `301/CO_driver.h`, `CO_OD.h` and -`301/CO_SDOserver.h`. +[libedssharp](https://github.com/robincornelius/libedssharp). Latest pre-compiled +[binaries](https://github.com/robincornelius/libedssharp/raw/gh-pages/build/OpenEDSEditor-latest.zip) +are also available. Just extract the zip file and run the `EDSEditor.exe`. +In Linux it runs with mono, which is available by default on Ubuntu. Just set +file permissions to "executable" and then execute the program. + +In program, in preferences, set exporter to "CANopenNode_V4". Then start new +project or open the existing project file. + +Many project file types are supported, EDS, XDD v1.0, XDD v1.1, old custom XML +format. Generated project file can then be saved in XDD v1.1 file format +(xmlns="http://www.canopen.org/xml/1.1"). Project file can also be exported to +other formats, it can be used to generate documentation and CANopenNode source +files for Object Dictionary. + +If new project was started, then `DS301_profile.xpd` may be inserted. +If existing (old) project is edited, then existing `Communication Specific Parameters` +may be Deleted and then new `DS301_profile.xpd` may be inserted. Alternative is +editing existing communication parameters with observation to Object Dictionary +Requirements By CANopenNode in [objectDictionary.md](doc/objectDictionary.md). + +To clone, add or delete, select object(s) and use right click. Some knowledge +of CANopen is required to correctly set-up the custom Object Dictionary. + +CANopenNode includes some custom properties inside standard project file. See +[objectDictionary.md](doc/objectDictionary.md) for more information. Device support diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index b8245d74..f314d94c 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -30,6 +30,7 @@ Then clone [CANopenNode](https://github.com/CANopenNode/CANopenNode) from Github sudo apt-get install can-utils git clone https://github.com/CANopenNode/CANopenNode.git cd CANopenNode + # For update just use 'git pull' here make Now prepare CAN virtual device and run _candump_, which will show all CAN traffic. Use a second terminal: @@ -51,14 +52,12 @@ You are now running a fully functional CANopen device on virtual CAN network. It On the second terminal you can see some CAN traffic. After _canopend_ startup, first messages are: - vcan0 704 [1] 00 # Bootup message. + vcan0 704 [1] 00 # Boot-up message. vcan0 084 [8] 00 50 01 2F F3 FF FF FF # Emergency message. - vcan0 704 [1] 7F # Heartbeat messages each second - vcan0 704 [1] 7F -Bootup and Heartbeat messages of node 4 have CAN-ID equal to 0x704. CAN-ID is 11-bit standard CAN identifier. 0x7F in heartbeat message means, that node is in NMT pre-operational state. +Boot-up message of node 4 have CAN-ID equal to 0x704. CAN-ID is 11-bit standard CAN identifier. -Also, both, first and second terminal shows, that there is an Emergency message after the bootup. Also Heartbeat messages shows NMT pre-operational state. +Also, both, first and second terminal shows, that there is an Emergency message after the boot-up. Also Heartbeat messages shows NMT pre-operational state. The easiest way to find the reason of the emergency message is to check the byte 4 (errorBit). It has value of 0x2F. Go to CANopenNode source code and open the file "301/CO_Emergency.h", section "Error status bits". 0x2F means "CO_EM_NON_VOLATILE_MEMORY", which is generic, critical error with access to non volatile device memory. @@ -70,11 +69,9 @@ You can follow the reason of the problem inside the source code. However, there echo "-" > od4_storage_auto ./canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto -Second terminal now shows operational state (0x05) and one pre-defined PDO message with CAN-ID 0x184 and two bytes of data. To learn more about PDOs, how to configure communication and mapping parameters and how to use them see other sources of CANopen documentation. For example, you can read the article of PDO re-mapping procedure in [CAN newsletter magazine, June 2016](http://can-newsletter.org/engineering/engineering-miscellaneous/160601_can-newsletter-magazine-june-2016). +Second terminal now shows new boot-up message without emergency. vcan0 704 [1] 00 - vcan0 184 [2] 00 00 # PDO message - vcan0 704 [1] 05 ### Second CANopen device @@ -84,7 +81,7 @@ Open the third terminal and cd to the same directory as is in the first terminal echo "-" > od_storage_auto ./canopend vcan0 -i1 -c "stdio" -Now you should see in second terminal (_candump_) two CANopen devices sending heartbeats in one second interval each. One with node-ID = 4 and one with node-ID = 1. Both should be operational. +Now you should see in second terminal (_candump_) boot-up message of new CANopen device. ### CANopen command interface @@ -98,16 +95,18 @@ For example read Heartbeat producer parameter on CANopen device with ID=4. Param [1] 4 read 0x1017 0 u16 -You should see the response, which says that Heartbeats are transmitted in 1000 ms intervals: +You should see the response, which says that Heartbeats are disabled: - [1] 1000 + [1] 0 In CAN dump you can see some SDO communication. SDO communication can be quite complicated, if observing on _candump_, especially if larger data is split between multiple segments. However, there is no need to know the details, everything should work correctly in the background. Details about SDO communication can be found in CiA301 standard and partly also in 301/CO_SDOserver.h file, description of CO_SDO_state_t enumerator. [2] 4 write 0x1017 0 u16 5000 [2] OK #response -In _candump_ you will notice, that heartbeats from node 4 are coming in 5 second interval now. You can do the same also for node 1, but you won't see anything on _candump_, because data are written into itself directly. In "stdio" you can omit sequence number, to make typing easier. +In _candump_ you will notice, that heartbeats from node 4 are coming in 5 second interval now. Heartbeat message is similar to boot-up message. 0x7F in heartbeat message means, that node is in NMT pre-operational state. 0x05 means operational and 0x04 means stopped. + +You can do the same also for node 1, but you won't see SDO messages on _candump_, because data are written into itself directly. In "stdio" you can omit sequence number, to make typing easier. 1 w 0x1017 0 u16 2500 [0] OK @@ -117,7 +116,7 @@ Now store Object dictionary on node-ID 4, so it will preserve variables on next 4 w 0x1010 1 u32 0x65766173 [0] OK -More details about Object dictionary variables can be found in CiA301 standard or in example/IO.html file. +More details about Object dictionary variables can be found in CiA301 standard or in example/DS301_profile.md file. #### NMT master @@ -126,10 +125,10 @@ If node is operational (started), it can exchange all objects, including PDO, SD set node 4 [0] OK - preop + start [0] OK - start + preop [0] OK stop @@ -141,6 +140,9 @@ If node is operational (started), it can exchange all objects, including PDO, SD reset communication [0] OK + 0 start + [0] OK + reset node [0] OK @@ -162,7 +164,7 @@ Assigning Node-ID or CAN bitrate, which support LSS configuration, is described Some further CANopenNode related Linux tools are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket). -Custom CANopen device can be created based on own Object Dictionary. Use *EDSEditor.exe* from https://github.com/robincornelius/libedssharp to generate one. It runs in Linux or Windows. For principles see *objectDictionary.md*. There are also many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download, for example CiA401. +Custom CANopen device can be created based on own Object Dictionary, see README.md. There are also many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download, for example CiA401. For own CANopen device with own microcontroller, see *deviceSupport.md*. There is a bare-metal demo for [PIC microcontrollers](https://github.com/CANopenNode/CANopenPIC), most complete example is for PIC32. diff --git a/doc/index.html b/doc/index.html deleted file mode 120000 index 5bc11288..00000000 --- a/doc/index.html +++ /dev/null @@ -1 +0,0 @@ -html/index.html \ No newline at end of file diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 6a6545b3..69941a96 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -1,8 +1,8 @@ Object Dictionary ================= -Definitions from CiA 301 ------------------------- +Definitions from CiA 301 {#definitions-from-cia-301} +---------------------------------------------------- The **Object Dictionary** is a collection of all the data items which have an influence on the behavior of the application objects, the communication objects and the state machine used on this device. It serves as an interface between the communication and the application. The object dictionary is essentially a grouping of objects accessible via the network in an ordered pre-defined fashion. Each object within the object dictionary is addressed using a 16-bit index and a 8-bit sub-index. @@ -11,13 +11,12 @@ A **SDO** (Service Data Object) is providing direct access to object entries of A **PDO** (Process Data Object) is providing real-time data transfer of object entries of a CANopen device's object dictionary. The transfer of PDO is performed with no protocol overhead. The PDO correspond to objects in the object dictionary and provide the interface to the application objects. Data type and mapping of application objects into a PDO is determined by a corresponding PDO mapping structure within the object dictionary. -Operation ---------- +Operation {#operation} +---------------------- ### Terms The term **OD object** means object from object dictionary located at specific 16-bit index. There are different types of OD objects in CANopen: variables, arrays and records (structures). Each OD object contains pointer to actual data, data length(s) and attribute(s). See @ref OD_objectTypes_t. -The term **OD variable** is basic variable of specified type. For example: int8_t, uint32_t, float64_t, ... or just sequence of binary data with known -or unknown data length. Each OD variable resides in Object dictionary at specified 16-bit index and 8-bit sub-index. +The term **OD variable** is basic variable of specified type. For example: int8_t, uint32_t, float64_t, ... or just sequence of binary data with known or unknown data length. Each OD variable resides in Object dictionary at specified 16-bit index and 8-bit sub-index. The term **OD entry** means structure element, which contains some basic properties of the OD object, indication of type of OD object and pointer to all necessary data for the OD object. An array of OD entries together with information about total number of OD entries represents object dictionary as defined inside CANopenNode. See @ref OD_entry_t and @ref OD_t. @@ -82,8 +81,8 @@ void myFuncGlob(void) { ``` -Object dictionary example -------------------------- +Object Dictionary Example {#object-dictionary-example} +------------------------------------------------------ Actual Object dictionary for one CANopen device is defined by pair of OD_xyz.h and ODxyz.h files. Suffix "xyz" is unique name of the object dictionary. If single default object dictionary is used, suffix is omitted. Such way configuration with multiple object dictionaries is possible. @@ -247,15 +246,15 @@ const OD_t ODxyz = { ``` -XML device description ----------------------- +XML Device Description {#xml-device-description} +------------------------------------------------ CANopen device description - XML schema definition - is specified by CiA 311 standard. CiA 311 complies with standard ISO 15745-1:2005/Amd1 (Industrial automation systems and integration - Open systems application integration framework). CANopen device description is basically a XML file with all the information about CANopen device. The larges part of the file is a list of all object dictionary variables with all necessary properties and documentation. This file can be edited with OD editor application and can be used as data source, from which Object dictionary for CANopenNode is generated. Furthermore, this file can be used with CANopen configuration tool, which interacts with CANopen devices on running CANopen network. -XML schema definitions are available at: http://www.canopen.org/xml/1.1 One of the tools for viewing XML schemas is "xsddiagram" (https://github.com/dgis/xsddiagram). +XML schema definitions are available at: http://www.canopen.org/xml/1.1 One of the tools for viewing XML schemas and validating XDD project files is "xsddiagram" (https://github.com/dgis/xsddiagram). Command line alternative to XDD file validation against schema is: `xmlstarlet val --err --xsd 311/CANopen.xsd project_file.xdd` CANopen specifies also another type of files for CANopen device description. These are EDS files, which are in INI format. It is possible to convert between those two formats. But CANopenNode uses XML format. @@ -263,10 +262,12 @@ The device description file has "XDD" file extension. The name of this file shal CANopenNode includes multiple profile definition files, one for each CANopen object. Those files have "XPD" extension. They are in the same XML format as XDD files. The XML editor tool can use XPD files to insert prepared data into device description file (XDD), which is being edited. +There are also device configuration files with "XDC" extension. They are describing a configured CANopen device and include additional elements, such as default value, denominator and device commissioning elements. Similar as "dcf" files in INI format. + ### XDD, XPD file example ```xml - + ... @@ -333,19 +334,6 @@ CANopenNode includes multiple profile definition files, one for each CANopen obj - - - - ... - - - ... - - - - - - @@ -376,16 +364,16 @@ Above XML file example shows necessary data for OD interface used by CANopenNode XML file is divided into two parts: 1. "ProfileBody_Device_CANopen" - more standardized information - 2. "ProfileBody_CommunicationNetwork_CANopen" - communication related info + 2. "ProfileBody_CommunicationNetwork_CANopen" - CANopen specific information -Most important part of the XML file is definition of each OD object. All OD objects are listed in "CANopenObjectList", which resides in the second part of the XML file. Each "CANopenObject" and "CANopenSubObject" of the list contains a link to parameter ("uniqueIDRef"), which resides in the first part of the XML file. So data for each OD object is split between two parts of the XML file. +Largest part of the XML file is definition of each OD object. All OD objects are listed in "CANopenObjectList", which resides in the second part of the XML file. Each "CANopenObject" and "CANopenSubObject" of the list contains a link to parameter ("uniqueIDRef"), which resides in the first part of the XML file. So data for each OD object is split between two parts of the XML file. #### <CANopenObject> * "index" (required) - Object dictionary index * "name" (required) - Name of the parameter * "objectType" (required) - "7"=VAR, "8"=ARRAY, "9"=RECORD * "subNumber" (required if "objectType" is "8" or "9") - * "PDOmapping" (optional if "objectType" is "7", default is "no"): + * "PDOmapping" (optional if "objectType" is "7"): * "no" - mapping not allowed * "default" - not used, same as "optional" * "optional" - mapping allowed to TPDO or RPDO @@ -397,21 +385,20 @@ Most important part of the XML file is definition of each OD object. All OD obje * "subIndex" (required) - Object dictionary sub-index * "name" (required) - Name of the parameter * "objectType" (required, always "7") - * "PDOmapping" (optional, same as above, default is "no") + * "PDOmapping" (optional, same as above) * "uniqueIDRef" (required or see below) - Reference to <parameter> #### uniqueIDRef -This is required attribute from "CANopenObject" and "CANopenSubObject". It contains reference to <parameter> in "ProfileBody_Device_CANopen" section of the XML file. There are additional necessary properties. +This is required attribute from "CANopenObject" and "CANopenSubObject". It contains reference to <parameter> in "ProfileBody_Device_CANopen" section of the XML file. If "uniqueIDRef" attribute is not specified and "objectType" is 7(VAR), then "CANopenObject" or "CANopenSubObject" must contain additional attributes: * "dataType" (required for VAR) - CANopen basic data type, see below * "accessType" (required for VAR) - "ro", "wo", "rw" or "const" * "defaultValue" (optional) - Default value for the variable. - * "denotation" (optional) - Not used by CANopenNode. #### <parameter> - * "uniqueID" (required) - * "access" (required for VAR) - can be one of: + * "**uniqueID**" (required) + * "**access**" (required for VAR) - can be one of: * "const" - same as "read" * "read" - only read access with SDO or PDO * "write" - only write access with SDO or PDO @@ -419,22 +406,23 @@ If "uniqueIDRef" attribute is not specified and "objectType" is 7(VAR), then "CA * "readWriteInput" - same as "readWrite" * "readWriteOutput" - same as "readWrite" * "noAccess" - object will be in object dictionary, but no access. - * <label lang="en"> (required) - * <description lang="en"> (required) - * <INT and similar/> (required) - Basic or complex data type. Basic data type (for VAR) is specified in IEC 61131-3 (see below). If data type is complex (ARRAY or RECORD), then <dataTypeIDRef> must be specified and entry must be added in the <dataTypeList>. Such definition of complex data types is required by the standard, but it is not required by CANopenNode. - * <defaultValue> (optional for VAR) - Default value for the variable. If it is empty, then data is not stored inside object dictionary. Application should provide own data via IO extension. - -Additional, optional, CANopenNode specific properties, which can be used inside parameters describing <CANopenObject>: - * <property name="CO_storageGroup" value="..."> - group name (string) into which the C variable will belong. Variables from specific storage group may then be stored into non-volatile memory, automatically or by SDO command. - * <property name="CO_extensionIO" value="..."> - Valid value is "false" (default) or "true", if IO extension is enabled. - * <property name="CO_flagsPDO" value="..."> - Valid value is "false" (default) or "true", if PDO flags are enabled. - * <property name="CO_countLabel" value="..."> - Valid value is any string without spaces. OD exporter will generate a macro for each different string. For example, if four OD objects have "CO_countLabel" set to "TPDO", then macro "#define ODxyz_CNT_TPDO 4" will be generated by OD exporter. - -Additional, optional, CANopenNode specific property, which can be used inside parameters describing "VAR": - * <property name="CO_accessSRDO" value="..."> - Valid values are: "tx", "rx", "trx", "no"(default). - * <property name="CO_stringLength" value="..."> - Minimum length of the string. Used with "VISIBLE_STRING", "OCTET_STRING" and "UNICODE_STRING". If CO_stringLength smaller than length of string in <defaultValue>, then it is ignored. Byte length of unicode string is 2 * CO_stringLength. If <defaultValue> is empty and CO_stringLength is 0, then data is not stored inside object dictionary. - -#### CANopen basic data types + * <**label** lang="en">, <**description** lang="en"> (required) - several elements in multiple languages possible + * <**INT and similar**/> (required) - Basic or complex data type. Basic data type (for VAR) is specified in IEC 61131-3 (see below). If data type is complex (ARRAY or RECORD), then **<dataTypeIDRef>** must be specified and entry must be added in the **<dataTypeList>**. Such definition of complex data types is required by the standard, but it is not required by CANopenNode. + * <**defaultValue**> (optional for VAR) - Default value for the variable. If it is empty string, then data is not stored inside object dictionary. Application should provide own data via IO extension. + * <**property** name="..." value="..."> (optional) - Multiple elements may contain additional custom properties. CANopenNode uses custom properties with following names: + * "**CO_disabled**" (used for base OD entry) - Valid value is "false" (default) or "true". if OD entry is disabled, then it will not be present in generated Object Dictionary .h and .c files. + * "**CO_countLabel**" (used for base OD entry) - Valid value is any string without spaces. OD exporter will generate a macro for each different string. For example, if four OD objects have "CO_countLabel" set to "TPDO", then macro "#define ODxyz_CNT_TPDO 4" will be generated by OD exporter. "CO_countLabel" is not required for configuration with multiple object dictionaries (CO_MULTIPLE_OD), although may be useful. Default is "". + * "**CO_storageGroup**" (used for base OD entry) - group name (string) into which the C variable will belong. Variables from specific storage group may then be stored into non-volatile memory, automatically or by SDO command. Default is "RAM". Please note: if <defaultValue> is empty string at specific subindex, then no storage group will be used for that variable. + * "**CO_extensionIO**" (used for base OD entry) - Valid value is "false" (default) or "true", if IO extension is enabled. + * "**CO_flagsPDO**" (used for base OD entry) - Valid value is "false" (default) or "true", if PDO flags are enabled. + * "**CO_accessSRDO**" (used for each "VAR") - Valid values are: "tx", "rx", "trx", "no"(default). + * "**CO_stringLengthMin**" (used for each "VAR") - Minimum length of the string. Used with "VISIBLE_STRING" and "UNICODE_STRING". If CO_stringLengthMin is smaller than length of the string in <defaultValue>, then it is ignored. Byte length of unicode string is 2 * CO_stringLengthMin. If <defaultValue> is empty and CO_stringLengthMin is 0, then data is not stored inside object dictionary. Default is 0. + +#### Other elements +Other elements listed in the above XML example are required by the standard. There are also many other elements, not listed above. All those does not influence the CANopenNode object dictionary exporter. + + +### CANopen basic data types | CANopenNode | IEC 61131-3 | CANopen | dataType | | -------------- | -------------- | --------------- | -------- | | bool_t | BOOL | BOOLEAN | 0x01 | @@ -448,32 +436,28 @@ Additional, optional, CANopenNode specific property, which can be used inside pa | uint64_t | ULINT, (LWORD) | UNSIGNED64 | 0x1B | | float32_t | REAL | REAL32 | 0x08 | | float64_t | LREAL | REAL64 | 0x11 | -| uint8_t [] (1) | BITSTRING (2) | INTEGER24 | 0x10 | -| uint8_t [] (1) | BITSTRING (2) | INTEGER40 | 0x12 | -| uint8_t [] (1) | BITSTRING (2) | INTEGER48 | 0x13 | -| uint8_t [] (1) | BITSTRING (2) | INTEGER56 | 0x14 | -| uint8_t [] (1) | BITSTRING (2) | UNSIGNED24 | 0x16 | -| uint8_t [] (1) | BITSTRING (2) | UNSIGNED40 | 0x18 | -| uint8_t [] (1) | BITSTRING (2) | UNSIGNED48 | 0x19 | -| uint8_t [] (1) | BITSTRING (2) | UNSIGNED56 | 0x1A | -| char [] | STRING | VISIBLE_STRING | 0x09 | -| uint8_t [] | BITSTRING (2) | OCTET_STRING | 0x0A | -| uint16_t [] | WSTRING | UNICODE_STRING | 0x0B | -| uint8_t [] (1) | BITSTRING (2) | TIME_OF_DAY | 0x0C | -| uint8_t [] (1) | BITSTRING (2) | TIME_DIFFERENCE | 0x0D | -| not used | BITSTRING (2) | DOMAIN | 0x0F | -(1) Data is stored in little-endian format. - -(2) CANopen specific type is stored as <BITSTRING/> in <parameter> and additional CANopen "dataType" attribute is stored in <CANopenObject> or <CANopenSubObject>. - -#### <parameterGroupList> -This is optional element and is not required by standard, nor by CANopenNode. This can be very useful for documentation, which can be organised into multiple chapters with multiple levels. CANopen objects can then be organised in any way, not only by index. - -#### Other elements -Other elements listed in the above XML example are required by the standard and does not influence the CANopenNode object dictionary generator. - - -### Object dictionary requirements by CANopenNode +| - | (1) | INTEGER24 | 0x10 | +| - | (1) | INTEGER40 | 0x12 | +| - | (1) | INTEGER48 | 0x13 | +| - | (1) | INTEGER56 | 0x14 | +| - | (1) | UNSIGNED24 | 0x16 | +| - | (1) | UNSIGNED40 | 0x18 | +| - | (1) | UNSIGNED48 | 0x19 | +| - | (1) | UNSIGNED56 | 0x1A | +| char [] | STRING (2) | VISIBLE_STRING | 0x09 | +| uint8_t [] | BITSTRING (3) | OCTET_STRING | 0x0A | +| uint16_t [] | WSTRING (2) | UNICODE_STRING | 0x0B | +| - | (1) | TIME_OF_DAY | 0x0C | +| - | (1) | TIME_DIFFERENCE | 0x0D | +| app. specific | BITSTRING (4) | DOMAIN | 0x0F | +(1) Data is translated into OCTET_STRING.
+(2) Additional property "CO_stringLengthMin" indicates the minimum length of the string in CANopenNode.
+(3) Default value for BITSTRING (OCTET_STRING) is written as space separated, two hex digit bytes in little-endian format.
+(4) Default value for DOMAIN is stored as empty string. + + +Object Dictionary Requirements By CANopenNode {#object-dictionary-requirements-by-canopennode} +---------------------------------------------------------------------------------------------- * **Used by** column indicates CANopenNode object or its part, which uses the OD object. It also indicates, if OD object is required or optional for actual configuration. For the configuration of the CANopenNode objects see [Stack configuration](301/CO_config.h). If CANopenNode object or its part is disabled in stack configuration, then OD object is not used. Note that OD objects: 1000, 1001 and 1017 and 1018 are mandatory for CANopen. * **CO_extensionIO** column indicates, if OD object must have property "CO_extensionIO" set to true: * "no" - no IO extension used diff --git a/example/CO_OD.c b/example/CO_OD.c deleted file mode 100644 index 9b22f840..00000000 --- a/example/CO_OD.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * CANopen Object Dictionary. - * - * This file was automatically generated with CANopenNode Object - * Dictionary Editor. DON'T EDIT THIS FILE MANUALLY !!!! - * Object Dictionary Editor is currently an older, but functional web - * application. For more info see See 'Object_Dictionary_Editor/about.html' in - * - * For more information on CANopen Object Dictionary see . - * - * @file CO_OD.c - * @author Janez Paternoster - * @copyright 2010 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "301/CO_driver.h" -#include "CO_OD.h" -#include "301/CO_SDOserver.h" - - -/******************************************************************************* - DEFINITION AND INITIALIZATION OF OBJECT DICTIONARY VARIABLES -*******************************************************************************/ - -/***** Definition for RAM variables *******************************************/ -struct sCO_OD_RAM CO_OD_RAM = { - CO_OD_FIRST_LAST_WORD, - -/*1001*/ 0x0, -/*1002*/ 0x0L, -/*1003*/ {0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1010*/ {0x3L}, -/*1011*/ {0x1L}, -/*1280*/{{0x3, 0x0L, 0x0L, 0x0}}, -/*2100*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -/*2103*/ 0x0, -/*2104*/ 0x0, -/*2107*/ {0x3E8, 0x0, 0x0, 0x0, 0x0}, -/*2108*/ {0}, -/*2109*/ {0}, -/*2110*/ {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, -/*2120*/ {0x5, 0x1234567890ABCDEFLL, 0x234567890ABCDEF1LL, 12.345, 456.789, 0}, -/*2130*/ {0x3, {'-', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, 0, 0x0L}, -/*6000*/ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, -/*6200*/ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, -/*6401*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -/*6411*/ {0, 0, 0, 0, 0, 0, 0, 0}, - - CO_OD_FIRST_LAST_WORD, -}; - - -/***** Definition for EEPROM variables ****************************************/ -struct sCO_OD_EEPROM CO_OD_EEPROM = { - CO_OD_FIRST_LAST_WORD, - -/*2106*/ 0x0L, -/*2112*/ {1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, - - CO_OD_FIRST_LAST_WORD, -}; - - -/***** Definition for ROM variables *******************************************/ - struct sCO_OD_ROM CO_OD_ROM = { //constant variables, stored in flash - CO_OD_FIRST_LAST_WORD, - -/*1000*/ 0x0L, -/*1005*/ 0x80L, -/*1006*/ 0x0L, -/*1007*/ 0x0L, -/*1008*/ {'C', 'A', 'N', 'o', 'p', 'e', 'n', 'N', 'o', 'd', 'e'}, -/*1009*/ {'3', '.', '0', '0'}, -/*100A*/ {'3', '.', '0', '0'}, -/*1012*/ 0x80000100L, -/*1014*/ 0x80L, -/*1015*/ 0x64, -/*1016*/ {0x0L, 0x0L, 0x0L, 0x0L}, -/*1017*/ 0x3E8, -/*1018*/ {0x4, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1019*/ 0x0, -/*1029*/ {0x0, 0x0, 0x1, 0x0, 0x0, 0x0}, -/*1200*/{{0x2, 0x600L, 0x580L}}, -/*1400*/{{0x2, 0x200L, 0xFF}, -/*1401*/ {0x2, 0x300L, 0xFE}, -/*1402*/ {0x2, 0x400L, 0xFE}, -/*1403*/ {0x2, 0x500L, 0xFE}}, -/*1600*/{{0x2, 0x62000108L, 0x62000208L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1601*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1602*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1603*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}}, -/*1800*/{{0x6, 0x180L, 0xFF, 0x64, 0x0, 0x0, 0x0}, -/*1801*/ {0x6, 0x280L, 0xFE, 0x0, 0x0, 0x0, 0x0}, -/*1802*/ {0x6, 0x380L, 0xFE, 0x0, 0x0, 0x0, 0x0}, -/*1803*/ {0x6, 0x480L, 0xFE, 0x0, 0x0, 0x0, 0x0}}, -/*1A00*/{{0x2, 0x60000108L, 0x60000208L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1A01*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1A02*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1A03*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}}, -/*1F80*/ 0x00000008L, -/*2101*/ 0x30, -/*2102*/ 0xFA, -/*2111*/ {1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, - - CO_OD_FIRST_LAST_WORD -}; - - -/******************************************************************************* - STRUCTURES FOR RECORD TYPE OBJECTS -*******************************************************************************/ -/*0x1018*/ const CO_OD_entryRecord_t OD_record1018[5] = { - {(void*)&CO_OD_ROM.identity.maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.identity.vendorID, 0x85, 4}, - {(void*)&CO_OD_ROM.identity.productCode, 0x85, 4}, - {(void*)&CO_OD_ROM.identity.revisionNumber, 0x85, 4}, - {(void*)&CO_OD_ROM.identity.serialNumber, 0x85, 4}}; -/*0x1200*/ const CO_OD_entryRecord_t OD_record1200[3] = { - {(void*)&CO_OD_ROM.SDOServerParameter[0].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.SDOServerParameter[0].COB_IDClientToServer, 0x85, 4}, - {(void*)&CO_OD_ROM.SDOServerParameter[0].COB_IDServerToClient, 0x85, 4}}; -/*0x1280*/ const CO_OD_entryRecord_t OD_record1280[4] = { - {(void*)&CO_OD_RAM.SDOClientParameter[0].maxSubIndex, 0x06, 1}, - {(void*)&CO_OD_RAM.SDOClientParameter[0].COB_IDClientToServer, 0xBE, 4}, - {(void*)&CO_OD_RAM.SDOClientParameter[0].COB_IDServerToClient, 0xBE, 4}, - {(void*)&CO_OD_RAM.SDOClientParameter[0].nodeIDOfTheSDOServer, 0x0E, 1}}; -/*0x1400*/ const CO_OD_entryRecord_t OD_record1400[3] = { - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].COB_IDUsedByRPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].transmissionType, 0x0D, 1}}; -/*0x1401*/ const CO_OD_entryRecord_t OD_record1401[3] = { - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].COB_IDUsedByRPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].transmissionType, 0x0D, 1}}; -/*0x1402*/ const CO_OD_entryRecord_t OD_record1402[3] = { - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].COB_IDUsedByRPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].transmissionType, 0x0D, 1}}; -/*0x1403*/ const CO_OD_entryRecord_t OD_record1403[3] = { - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].COB_IDUsedByRPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].transmissionType, 0x0D, 1}}; -/*0x1600*/ const CO_OD_entryRecord_t OD_record1600[9] = { - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject8, 0x8D, 4}}; -/*0x1601*/ const CO_OD_entryRecord_t OD_record1601[9] = { - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject8, 0x8D, 4}}; -/*0x1602*/ const CO_OD_entryRecord_t OD_record1602[9] = { - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject8, 0x8D, 4}}; -/*0x1603*/ const CO_OD_entryRecord_t OD_record1603[9] = { - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject8, 0x8D, 4}}; -/*0x1800*/ const CO_OD_entryRecord_t OD_record1800[7] = { - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].COB_IDUsedByTPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].transmissionType, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].inhibitTime, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].compatibilityEntry, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].eventTimer, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].SYNCStartValue, 0x0D, 1}}; -/*0x1801*/ const CO_OD_entryRecord_t OD_record1801[7] = { - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].COB_IDUsedByTPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].transmissionType, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].inhibitTime, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].compatibilityEntry, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].eventTimer, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].SYNCStartValue, 0x0D, 1}}; -/*0x1802*/ const CO_OD_entryRecord_t OD_record1802[7] = { - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].COB_IDUsedByTPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].transmissionType, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].inhibitTime, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].compatibilityEntry, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].eventTimer, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].SYNCStartValue, 0x0D, 1}}; -/*0x1803*/ const CO_OD_entryRecord_t OD_record1803[7] = { - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].COB_IDUsedByTPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].transmissionType, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].inhibitTime, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].compatibilityEntry, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].eventTimer, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].SYNCStartValue, 0x0D, 1}}; -/*0x1A00*/ const CO_OD_entryRecord_t OD_record1A00[9] = { - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject8, 0x8D, 4}}; -/*0x1A01*/ const CO_OD_entryRecord_t OD_record1A01[9] = { - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject8, 0x8D, 4}}; -/*0x1A02*/ const CO_OD_entryRecord_t OD_record1A02[9] = { - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject8, 0x8D, 4}}; -/*0x1A03*/ const CO_OD_entryRecord_t OD_record1A03[9] = { - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject8, 0x8D, 4}}; -/*0x2120*/ const CO_OD_entryRecord_t OD_record2120[6] = { - {(void*)&CO_OD_RAM.testVar.maxSubIndex, 0x06, 1}, - {(void*)&CO_OD_RAM.testVar.I64, 0xBE, 8}, - {(void*)&CO_OD_RAM.testVar.U64, 0xBE, 8}, - {(void*)&CO_OD_RAM.testVar.R32, 0xBE, 4}, - {(void*)&CO_OD_RAM.testVar.R64, 0xBE, 8}, - {0, 0x0E, 0}}; -/*0x2130*/ const CO_OD_entryRecord_t OD_record2130[4] = { - {(void*)&CO_OD_RAM.time.maxSubIndex, 0x06, 1}, - {(void*)&CO_OD_RAM.time.string[0], 0x06, 30}, - {(void*)&CO_OD_RAM.time.epochTimeBaseMs, 0x8E, 8}, - {(void*)&CO_OD_RAM.time.epochTimeOffsetMs, 0xBE, 4}}; - - -/******************************************************************************* - OBJECT DICTIONARY -*******************************************************************************/ -const CO_OD_entry_t CO_OD[CO_OD_NoOfElements] = { -{0x1000, 0x00, 0x85, 4, (void*)&CO_OD_ROM.deviceType}, -{0x1001, 0x00, 0x36, 1, (void*)&CO_OD_RAM.errorRegister}, -{0x1002, 0x00, 0xB6, 4, (void*)&CO_OD_RAM.manufacturerStatusRegister}, -{0x1003, 0x08, 0x8E, 4, (void*)&CO_OD_RAM.preDefinedErrorField[0]}, -{0x1005, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.COB_ID_SYNCMessage}, -{0x1006, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.communicationCyclePeriod}, -{0x1007, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.synchronousWindowLength}, -{0x1008, 0x00, 0x05, 11, (void*)&CO_OD_ROM.manufacturerDeviceName[0]}, -{0x1009, 0x00, 0x05, 4, (void*)&CO_OD_ROM.manufacturerHardwareVersion[0]}, -{0x100A, 0x00, 0x05, 4, (void*)&CO_OD_ROM.manufacturerSoftwareVersion[0]}, -{0x1010, 0x01, 0x8E, 4, (void*)&CO_OD_RAM.storeParameters[0]}, -{0x1011, 0x01, 0x8E, 4, (void*)&CO_OD_RAM.restoreDefaultParameters[0]}, -{0x1012, 0x00, 0x85, 4, (void*)&CO_OD_ROM.COB_ID_TIME}, -{0x1014, 0x00, 0x85, 4, (void*)&CO_OD_ROM.COB_ID_EMCY}, -{0x1015, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.inhibitTimeEMCY}, -{0x1016, 0x04, 0x8D, 4, (void*)&CO_OD_ROM.consumerHeartbeatTime[0]}, -{0x1017, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.producerHeartbeatTime}, -{0x1018, 0x04, 0x00, 0, (void*)&OD_record1018}, -{0x1019, 0x00, 0x0D, 1, (void*)&CO_OD_ROM.synchronousCounterOverflowValue}, -{0x1029, 0x06, 0x0D, 1, (void*)&CO_OD_ROM.errorBehavior[0]}, -{0x1200, 0x02, 0x00, 0, (void*)&OD_record1200}, -{0x1280, 0x03, 0x00, 0, (void*)&OD_record1280}, -{0x1400, 0x02, 0x00, 0, (void*)&OD_record1400}, -{0x1401, 0x02, 0x00, 0, (void*)&OD_record1401}, -{0x1402, 0x02, 0x00, 0, (void*)&OD_record1402}, -{0x1403, 0x02, 0x00, 0, (void*)&OD_record1403}, -{0x1600, 0x08, 0x00, 0, (void*)&OD_record1600}, -{0x1601, 0x08, 0x00, 0, (void*)&OD_record1601}, -{0x1602, 0x08, 0x00, 0, (void*)&OD_record1602}, -{0x1603, 0x08, 0x00, 0, (void*)&OD_record1603}, -{0x1800, 0x06, 0x00, 0, (void*)&OD_record1800}, -{0x1801, 0x06, 0x00, 0, (void*)&OD_record1801}, -{0x1802, 0x06, 0x00, 0, (void*)&OD_record1802}, -{0x1803, 0x06, 0x00, 0, (void*)&OD_record1803}, -{0x1A00, 0x08, 0x00, 0, (void*)&OD_record1A00}, -{0x1A01, 0x08, 0x00, 0, (void*)&OD_record1A01}, -{0x1A02, 0x08, 0x00, 0, (void*)&OD_record1A02}, -{0x1A03, 0x08, 0x00, 0, (void*)&OD_record1A03}, -{0x1F80, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.NMTStartup}, -{0x2100, 0x00, 0x36, 10, (void*)&CO_OD_RAM.errorStatusBits[0]}, -{0x2101, 0x00, 0x0D, 1, (void*)&CO_OD_ROM.CANNodeID}, -{0x2102, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.CANBitRate}, -{0x2103, 0x00, 0x8E, 2, (void*)&CO_OD_RAM.SYNCCounter}, -{0x2104, 0x00, 0x86, 2, (void*)&CO_OD_RAM.SYNCTime}, -{0x2106, 0x00, 0x87, 4, (void*)&CO_OD_EEPROM.powerOnCounter}, -{0x2107, 0x05, 0xBE, 2, (void*)&CO_OD_RAM.performance[0]}, -{0x2108, 0x01, 0xB6, 2, (void*)&CO_OD_RAM.temperature[0]}, -{0x2109, 0x01, 0xB6, 2, (void*)&CO_OD_RAM.voltage[0]}, -{0x2110, 0x10, 0xFE, 4, (void*)&CO_OD_RAM.variableInt32[0]}, -{0x2111, 0x10, 0xFD, 4, (void*)&CO_OD_ROM.variableROMInt32[0]}, -{0x2112, 0x10, 0xFF, 4, (void*)&CO_OD_EEPROM.variableNVInt32[0]}, -{0x2120, 0x05, 0x00, 0, (void*)&OD_record2120}, -{0x2130, 0x03, 0x00, 0, (void*)&OD_record2130}, -{0x6000, 0x08, 0x76, 1, (void*)&CO_OD_RAM.readInput8Bit[0]}, -{0x6200, 0x08, 0x3E, 1, (void*)&CO_OD_RAM.writeOutput8Bit[0]}, -{0x6401, 0x0C, 0xB6, 2, (void*)&CO_OD_RAM.readAnalogueInput16Bit[0]}, -{0x6411, 0x08, 0xBE, 2, (void*)&CO_OD_RAM.writeAnalogueOutput16Bit[0]}, -}; - diff --git a/example/CO_OD.h b/example/CO_OD.h deleted file mode 100644 index 4e2f31e2..00000000 --- a/example/CO_OD.h +++ /dev/null @@ -1,460 +0,0 @@ -/* - * CANopen Object Dictionary. - * - * This file was automatically generated with CANopenNode Object - * Dictionary Editor. DON'T EDIT THIS FILE MANUALLY !!!! - * Object Dictionary Editor is currently an older, but functional web - * application. For more info see See 'Object_Dictionary_Editor/about.html' in - * - * For more information on CANopen Object Dictionary see . - * - * @file CO_OD.h - * @author Janez Paternoster - * @copyright 2010 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_OD_H -#define CO_OD_H - - -/******************************************************************************* - CANopen DATA DYPES -*******************************************************************************/ - typedef uint8_t UNSIGNED8; - typedef uint16_t UNSIGNED16; - typedef uint32_t UNSIGNED32; - typedef uint64_t UNSIGNED64; - typedef int8_t INTEGER8; - typedef int16_t INTEGER16; - typedef int32_t INTEGER32; - typedef int64_t INTEGER64; - typedef float32_t REAL32; - typedef float64_t REAL64; - typedef char_t VISIBLE_STRING; - typedef oChar_t OCTET_STRING; - typedef domain_t DOMAIN; - - #ifndef timeOfDay_t - typedef union { - unsigned long long ullValue; - struct { - unsigned long ms:28; - unsigned reserved:4; - unsigned days:16; - unsigned reserved2:16; - }; - }timeOfDay_t; -#endif - - typedef timeOfDay_t TIME_OF_DAY; - typedef timeOfDay_t TIME_DIFFERENCE; - - -/******************************************************************************* - FILE INFO: - FileName: IO Example - FileVersion: - - CreationTime: 18:04:29 - CreationDate: 2016-03-25 - CreatedBy: JP -*******************************************************************************/ - - -/******************************************************************************* - DEVICE INFO: - VendorName: CANopenNode - VendorNumber: 0 - ProductName: CANopenNode - ProductNumber: 0 -*******************************************************************************/ - - -/******************************************************************************* - FEATURES -*******************************************************************************/ - #define CO_NO_SYNC 1 //Associated objects: 1005, 1006, 1007, 2103, 2104 - #define CO_NO_TIME 1 //Associated objects: 1012-1013 - #define CO_NO_EMERGENCY 1 //Associated objects: 1014, 1015 - #define CO_NO_SDO_SERVER 1 //Associated objects: 1200 - #define CO_NO_SDO_CLIENT 1 //Associated objects: 1280 - #define CO_NO_GFC 0 //Associated objects: 1300 - #define CO_NO_SRDO 0 //Associated objects: 1301-13FF - #define CO_NO_RPDO 4 //Associated objects: 1400, 1401, 1402, 1403, 1600, 1601, 1602, 1603 - #define CO_NO_TPDO 4 //Associated objects: 1800, 1801, 1802, 1803, 1A00, 1A01, 1A02, 1A03 - #define CO_NO_TRACE 0 - -/******************************************************************************* - OBJECT DICTIONARY -*******************************************************************************/ - #define CO_OD_NoOfElements 57 - - -/******************************************************************************* - TYPE DEFINITIONS FOR RECORDS -*******************************************************************************/ -/*1018 */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 vendorID; - UNSIGNED32 productCode; - UNSIGNED32 revisionNumber; - UNSIGNED32 serialNumber; - } OD_identity_t; - -/*1200[1] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 COB_IDClientToServer; - UNSIGNED32 COB_IDServerToClient; - } OD_SDOServerParameter_t; - -/*1280[1] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 COB_IDClientToServer; - UNSIGNED32 COB_IDServerToClient; - UNSIGNED8 nodeIDOfTheSDOServer; - } OD_SDOClientParameter_t; -/*1301 */ typedef struct { - UNSIGNED8 maxSubIndex; - UNSIGNED8 informationDirection; - UNSIGNED16 safetyCycleTime; - UNSIGNED8 safetyRelatedValidationTime; - UNSIGNED8 transmissionType; - UNSIGNED32 COB_ID1_normal; - UNSIGNED32 COB_ID2_inverted; - } OD_SRDOCommunicationParameter_t; -/*1381 */ typedef struct { - UNSIGNED8 numberOfMappedObjects; - UNSIGNED32 mappedObject[16]; - } OD_SRDOMappingParameter_t; -/*1400[4] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 COB_IDUsedByRPDO; - UNSIGNED8 transmissionType; - } OD_RPDOCommunicationParameter_t; - -/*1600[4] */ typedef struct{ - UNSIGNED8 numberOfMappedObjects; - UNSIGNED32 mappedObject1; - UNSIGNED32 mappedObject2; - UNSIGNED32 mappedObject3; - UNSIGNED32 mappedObject4; - UNSIGNED32 mappedObject5; - UNSIGNED32 mappedObject6; - UNSIGNED32 mappedObject7; - UNSIGNED32 mappedObject8; - } OD_RPDOMappingParameter_t; - -/*1800[4] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 COB_IDUsedByTPDO; - UNSIGNED8 transmissionType; - UNSIGNED16 inhibitTime; - UNSIGNED8 compatibilityEntry; - UNSIGNED16 eventTimer; - UNSIGNED8 SYNCStartValue; - } OD_TPDOCommunicationParameter_t; - -/*1A00[4] */ typedef struct{ - UNSIGNED8 numberOfMappedObjects; - UNSIGNED32 mappedObject1; - UNSIGNED32 mappedObject2; - UNSIGNED32 mappedObject3; - UNSIGNED32 mappedObject4; - UNSIGNED32 mappedObject5; - UNSIGNED32 mappedObject6; - UNSIGNED32 mappedObject7; - UNSIGNED32 mappedObject8; - } OD_TPDOMappingParameter_t; - -/*2120 */ typedef struct{ - UNSIGNED8 maxSubIndex; - INTEGER64 I64; - UNSIGNED64 U64; - REAL32 R32; - REAL64 R64; - DOMAIN domain; - } OD_testVar_t; - -/*2130 */ typedef struct{ - UNSIGNED8 maxSubIndex; - VISIBLE_STRING string[30]; - UNSIGNED64 epochTimeBaseMs; - UNSIGNED32 epochTimeOffsetMs; - } OD_time_t; - - -/******************************************************************************* - STRUCTURES FOR VARIABLES IN DIFFERENT MEMORY LOCATIONS -*******************************************************************************/ -#define CO_OD_FIRST_LAST_WORD 0x55 //Any value from 0x01 to 0xFE. If changed, EEPROM will be reinitialized. - -/***** Structure for RAM variables ********************************************/ -struct sCO_OD_RAM{ - UNSIGNED32 FirstWord; - -/*1001 */ UNSIGNED8 errorRegister; -/*1002 */ UNSIGNED32 manufacturerStatusRegister; -/*1003 */ UNSIGNED32 preDefinedErrorField[8]; -/*1010 */ UNSIGNED32 storeParameters[1]; -/*1011 */ UNSIGNED32 restoreDefaultParameters[1]; -/*1280[1] */ OD_SDOClientParameter_t SDOClientParameter[1]; -/*2100 */ OCTET_STRING errorStatusBits[10]; -/*2103 */ UNSIGNED16 SYNCCounter; -/*2104 */ UNSIGNED16 SYNCTime; -/*2107 */ UNSIGNED16 performance[5]; -/*2108 */ INTEGER16 temperature[1]; -/*2109 */ INTEGER16 voltage[1]; -/*2110 */ INTEGER32 variableInt32[16]; -/*2120 */ OD_testVar_t testVar; -/*2130 */ OD_time_t time; -/*6000 */ UNSIGNED8 readInput8Bit[8]; -/*6200 */ UNSIGNED8 writeOutput8Bit[8]; -/*6401 */ INTEGER16 readAnalogueInput16Bit[12]; -/*6411 */ INTEGER16 writeAnalogueOutput16Bit[8]; - - UNSIGNED32 LastWord; -}; - -/***** Structure for EEPROM variables *****************************************/ -struct sCO_OD_EEPROM{ - UNSIGNED32 FirstWord; - -/*2106 */ UNSIGNED32 powerOnCounter; -/*2112 */ INTEGER32 variableNVInt32[16]; - - UNSIGNED32 LastWord; -}; - - -/***** Structure for ROM variables ********************************************/ -struct sCO_OD_ROM{ - UNSIGNED32 FirstWord; - -/*1000 */ UNSIGNED32 deviceType; -/*1005 */ UNSIGNED32 COB_ID_SYNCMessage; -/*1006 */ UNSIGNED32 communicationCyclePeriod; -/*1007 */ UNSIGNED32 synchronousWindowLength; -/*1008 */ VISIBLE_STRING manufacturerDeviceName[11]; -/*1009 */ VISIBLE_STRING manufacturerHardwareVersion[4]; -/*100A */ VISIBLE_STRING manufacturerSoftwareVersion[4]; -/*1012 */ UNSIGNED32 COB_ID_TIME; -/*1014 */ UNSIGNED32 COB_ID_EMCY; -/*1015 */ UNSIGNED16 inhibitTimeEMCY; -/*1016 */ UNSIGNED32 consumerHeartbeatTime[4]; -/*1017 */ UNSIGNED16 producerHeartbeatTime; -/*1018 */ OD_identity_t identity; -/*1019 */ UNSIGNED8 synchronousCounterOverflowValue; -/*1029 */ UNSIGNED8 errorBehavior[6]; -/*1200[1] */ OD_SDOServerParameter_t SDOServerParameter[1]; -/*1400[4] */ OD_RPDOCommunicationParameter_t RPDOCommunicationParameter[4]; -/*1600[4] */ OD_RPDOMappingParameter_t RPDOMappingParameter[4]; -/*1800[4] */ OD_TPDOCommunicationParameter_t TPDOCommunicationParameter[4]; -/*1A00[4] */ OD_TPDOMappingParameter_t TPDOMappingParameter[4]; -/*1F80 */ UNSIGNED32 NMTStartup; -/*2101 */ UNSIGNED8 CANNodeID; -/*2102 */ UNSIGNED16 CANBitRate; -/*2111 */ INTEGER32 variableROMInt32[16]; - - UNSIGNED32 LastWord; -}; - - -/***** Declaration of Object Dictionary variables *****************************/ -extern struct sCO_OD_RAM CO_OD_RAM; - -extern struct sCO_OD_EEPROM CO_OD_EEPROM; - -extern struct sCO_OD_ROM CO_OD_ROM; - - -/******************************************************************************* - ALIASES FOR OBJECT DICTIONARY VARIABLES -*******************************************************************************/ -/*1000, Data Type: UNSIGNED32 */ - #define OD_deviceType CO_OD_ROM.deviceType - -/*1001, Data Type: UNSIGNED8 */ - #define OD_errorRegister CO_OD_RAM.errorRegister - -/*1002, Data Type: UNSIGNED32 */ - #define OD_manufacturerStatusRegister CO_OD_RAM.manufacturerStatusRegister - -/*1003, Data Type: UNSIGNED32, Array[8] */ - #define OD_preDefinedErrorField CO_OD_RAM.preDefinedErrorField - #define ODL_preDefinedErrorField_arrayLength 8 - -/*1005, Data Type: UNSIGNED32 */ - #define OD_COB_ID_SYNCMessage CO_OD_ROM.COB_ID_SYNCMessage - -/*1006, Data Type: UNSIGNED32 */ - #define OD_communicationCyclePeriod CO_OD_ROM.communicationCyclePeriod - -/*1007, Data Type: UNSIGNED32 */ - #define OD_synchronousWindowLength CO_OD_ROM.synchronousWindowLength - -/*1008, Data Type: VISIBLE_STRING, Array[11] */ - #define OD_manufacturerDeviceName CO_OD_ROM.manufacturerDeviceName - #define ODL_manufacturerDeviceName_stringLength 11 - -/*1009, Data Type: VISIBLE_STRING, Array[4] */ - #define OD_manufacturerHardwareVersion CO_OD_ROM.manufacturerHardwareVersion - #define ODL_manufacturerHardwareVersion_stringLength 4 - -/*100A, Data Type: VISIBLE_STRING, Array[4] */ - #define OD_manufacturerSoftwareVersion CO_OD_ROM.manufacturerSoftwareVersion - #define ODL_manufacturerSoftwareVersion_stringLength 4 - -/*1010, Data Type: UNSIGNED32, Array[1] */ - #define OD_storeParameters CO_OD_RAM.storeParameters - #define ODL_storeParameters_arrayLength 1 - #define ODA_storeParameters_saveAllParameters 0 - -/*1011, Data Type: UNSIGNED32, Array[1] */ - #define OD_restoreDefaultParameters CO_OD_RAM.restoreDefaultParameters - #define ODL_restoreDefaultParameters_arrayLength 1 - #define ODA_restoreDefaultParameters_restoreAllDefaultParameters 0 - -/*1012, Data Type: UNSIGNED32 */ - #define OD_COB_ID_TIME CO_OD_ROM.COB_ID_TIME - -/*1014, Data Type: UNSIGNED32 */ - #define OD_COB_ID_EMCY CO_OD_ROM.COB_ID_EMCY - -/*1015, Data Type: UNSIGNED16 */ - #define OD_inhibitTimeEMCY CO_OD_ROM.inhibitTimeEMCY - -/*1016, Data Type: UNSIGNED32, Array[4] */ - #define OD_consumerHeartbeatTime CO_OD_ROM.consumerHeartbeatTime - #define ODL_consumerHeartbeatTime_arrayLength 4 - -/*1017, Data Type: UNSIGNED16 */ - #define OD_producerHeartbeatTime CO_OD_ROM.producerHeartbeatTime - -/*1018, Data Type: OD_identity_t */ - #define OD_identity CO_OD_ROM.identity - -/*1019, Data Type: UNSIGNED8 */ - #define OD_synchronousCounterOverflowValue CO_OD_ROM.synchronousCounterOverflowValue - -/*1029, Data Type: UNSIGNED8, Array[6] */ - #define OD_errorBehavior CO_OD_ROM.errorBehavior - #define ODL_errorBehavior_arrayLength 6 - #define ODA_errorBehavior_communication 0 - #define ODA_errorBehavior_communicationOther 1 - #define ODA_errorBehavior_communicationPassive 2 - #define ODA_errorBehavior_generic 3 - #define ODA_errorBehavior_deviceProfile 4 - #define ODA_errorBehavior_manufacturerSpecific 5 - -/*1200[1], Data Type: OD_SDOServerParameter_t, Array[1] */ - #define OD_SDOServerParameter CO_OD_ROM.SDOServerParameter - -/*1280[1], Data Type: OD_SDOClientParameter_t, Array[1] */ - #define OD_SDOClientParameter CO_OD_RAM.SDOClientParameter - -/*1400[4], Data Type: OD_RPDOCommunicationParameter_t, Array[4] */ - #define OD_RPDOCommunicationParameter CO_OD_ROM.RPDOCommunicationParameter - -/*1600[4], Data Type: OD_RPDOMappingParameter_t, Array[4] */ - #define OD_RPDOMappingParameter CO_OD_ROM.RPDOMappingParameter - -/*1800[4], Data Type: OD_TPDOCommunicationParameter_t, Array[4] */ - #define OD_TPDOCommunicationParameter CO_OD_ROM.TPDOCommunicationParameter - -/*1A00[4], Data Type: OD_TPDOMappingParameter_t, Array[4] */ - #define OD_TPDOMappingParameter CO_OD_ROM.TPDOMappingParameter - -/*1F80, Data Type: UNSIGNED32 */ - #define OD_NMTStartup CO_OD_ROM.NMTStartup - -/*2100, Data Type: OCTET_STRING, Array[10] */ - #define OD_errorStatusBits CO_OD_RAM.errorStatusBits - #define ODL_errorStatusBits_stringLength 10 - -/*2101, Data Type: UNSIGNED8 */ - #define OD_CANNodeID CO_OD_ROM.CANNodeID - -/*2102, Data Type: UNSIGNED16 */ - #define OD_CANBitRate CO_OD_ROM.CANBitRate - -/*2103, Data Type: UNSIGNED16 */ - #define OD_SYNCCounter CO_OD_RAM.SYNCCounter - -/*2104, Data Type: UNSIGNED16 */ - #define OD_SYNCTime CO_OD_RAM.SYNCTime - -/*2106, Data Type: UNSIGNED32 */ - #define OD_powerOnCounter CO_OD_EEPROM.powerOnCounter - -/*2107, Data Type: UNSIGNED16, Array[5] */ - #define OD_performance CO_OD_RAM.performance - #define ODL_performance_arrayLength 5 - #define ODA_performance_cyclesPerSecond 0 - #define ODA_performance_timerCycleTime 1 - #define ODA_performance_timerCycleMaxTime 2 - #define ODA_performance_mainCycleTime 3 - #define ODA_performance_mainCycleMaxTime 4 - -/*2108, Data Type: INTEGER16, Array[1] */ - #define OD_temperature CO_OD_RAM.temperature - #define ODL_temperature_arrayLength 1 - #define ODA_temperature_mainPCB 0 - -/*2109, Data Type: INTEGER16, Array[1] */ - #define OD_voltage CO_OD_RAM.voltage - #define ODL_voltage_arrayLength 1 - #define ODA_voltage_mainPCBSupply 0 - -/*2110, Data Type: INTEGER32, Array[16] */ - #define OD_variableInt32 CO_OD_RAM.variableInt32 - #define ODL_variableInt32_arrayLength 16 - -/*2111, Data Type: INTEGER32, Array[16] */ - #define OD_variableROMInt32 CO_OD_ROM.variableROMInt32 - #define ODL_variableROMInt32_arrayLength 16 - -/*2112, Data Type: INTEGER32, Array[16] */ - #define OD_variableNVInt32 CO_OD_EEPROM.variableNVInt32 - #define ODL_variableNVInt32_arrayLength 16 - -/*2120, Data Type: OD_testVar_t */ - #define OD_testVar CO_OD_RAM.testVar - -/*2130, Data Type: OD_time_t */ - #define OD_time CO_OD_RAM.time - -/*6000, Data Type: UNSIGNED8, Array[8] */ - #define OD_readInput8Bit CO_OD_RAM.readInput8Bit - #define ODL_readInput8Bit_arrayLength 8 - -/*6200, Data Type: UNSIGNED8, Array[8] */ - #define OD_writeOutput8Bit CO_OD_RAM.writeOutput8Bit - #define ODL_writeOutput8Bit_arrayLength 8 - -/*6401, Data Type: INTEGER16, Array[12] */ - #define OD_readAnalogueInput16Bit CO_OD_RAM.readAnalogueInput16Bit - #define ODL_readAnalogueInput16Bit_arrayLength 12 - -/*6411, Data Type: INTEGER16, Array[8] */ - #define OD_writeAnalogueOutput16Bit CO_OD_RAM.writeAnalogueOutput16Bit - #define ODL_writeAnalogueOutput16Bit_arrayLength 8 - - -#endif - diff --git a/example/CO_OD_with_trace/CO_OD.c b/example/CO_OD_with_trace/CO_OD.c deleted file mode 100644 index 2c50709d..00000000 --- a/example/CO_OD_with_trace/CO_OD.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * CANopen Object Dictionary. - * - * This file was automatically generated with CANopenNode Object - * Dictionary Editor. DON'T EDIT THIS FILE MANUALLY !!!! - * Object Dictionary Editor is currently an older, but functional web - * application. For more info see See 'Object_Dictionary_Editor/about.html' in - * - * For more information on CANopen Object Dictionary see . - * - * @file CO_OD.c - * @author Janez Paternoster - * @copyright 2010 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "CO_driver.h" -#include "CO_OD.h" -#include "CO_SDOserver.h" - - -/******************************************************************************* - DEFINITION AND INITIALIZATION OF OBJECT DICTIONARY VARIABLES -*******************************************************************************/ - -/***** Definition for RAM variables *******************************************/ -struct sCO_OD_RAM CO_OD_RAM = { - CO_OD_FIRST_LAST_WORD, - -/*1001*/ 0x0, -/*1002*/ 0x0L, -/*1003*/ {0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1010*/ {0x3L}, -/*1011*/ {0x1L}, -/*2100*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -/*2103*/ 0x0, -/*2104*/ 0x0, -/*2107*/ {0x3E8, 0x0, 0x0, 0x0, 0x0}, -/*2108*/ {0}, -/*2109*/ {0}, -/*2110*/ {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, -/*2120*/ {0x5, 0x1234567890ABCDEFLL, 0x234567890ABCDEF1LL, 12.345, 456.789, 0}, -/*2130*/ {0x3, {'-', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, 0, 0x0L}, -/*2400*/ 0x0, -/*2401*/{{0x6, 0x0L, 0L, 0L, 0L, 0, 0x0L}, -/*2402*/ {0x6, 0x0L, 0L, 0L, 0L, 0, 0x0L}}, -/*6000*/ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, -/*6200*/ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, -/*6401*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -/*6411*/ {0, 0, 0, 0, 0, 0, 0, 0}, - - CO_OD_FIRST_LAST_WORD, -}; - - -/***** Definition for EEPROM variables ****************************************/ -struct sCO_OD_EEPROM CO_OD_EEPROM = { - CO_OD_FIRST_LAST_WORD, - -/*2106*/ 0x0L, -/*2112*/ {1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, - - CO_OD_FIRST_LAST_WORD, -}; - - -/***** Definition for ROM variables *******************************************/ - struct sCO_OD_ROM CO_OD_ROM = { //constant variables, stored in flash - CO_OD_FIRST_LAST_WORD, - -/*1000*/ 0x0L, -/*1005*/ 0x80L, -/*1006*/ 0x0L, -/*1007*/ 0x0L, -/*1008*/ {'C', 'A', 'N', 'o', 'p', 'e', 'n', 'N', 'o', 'd', 'e'}, -/*1009*/ {'3', '.', '0', '0'}, -/*100A*/ {'3', '.', '0', '0'}, -/*1014*/ 0x80L, -/*1015*/ 0x64, -/*1016*/ {0x0L, 0x0L, 0x0L, 0x0L}, -/*1017*/ 0x3E8, -/*1018*/ {0x4, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1019*/ 0x0, -/*1029*/ {0x0, 0x0, 0x1, 0x0, 0x0, 0x0}, -/*1200*/{{0x2, 0x600L, 0x580L}}, -/*1400*/{{0x2, 0x200L, 0xFF}, -/*1401*/ {0x2, 0x300L, 0xFE}, -/*1402*/ {0x2, 0x400L, 0xFE}, -/*1403*/ {0x2, 0x500L, 0xFE}}, -/*1600*/{{0x2, 0x62000108L, 0x62000208L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1601*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1602*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1603*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}}, -/*1800*/{{0x6, 0x180L, 0xFF, 0x64, 0x0, 0x0, 0x0}, -/*1801*/ {0x6, 0x280L, 0xFE, 0x0, 0x0, 0x0, 0x0}, -/*1802*/ {0x6, 0x380L, 0xFE, 0x0, 0x0, 0x0, 0x0}, -/*1803*/ {0x6, 0x480L, 0xFE, 0x0, 0x0, 0x0, 0x0}}, -/*1A00*/{{0x2, 0x60000108L, 0x60000208L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1A01*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1A02*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, -/*1A03*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}}, -/*1F80*/ 0x0L, -/*2101*/ 0x30, -/*2102*/ 0xFA, -/*2111*/ {1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, -/*2301*/{{0x8, 0x64L, 0x1, {'T', 'r', 'a', 'c', 'e', '1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, {'r', 'e', 'd', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, 0x60000108L, 0x1, 0x0, 0L}, -/*2302*/ {0x8, 0x0L, 0x0, {'T', 'r', 'a', 'c', 'e', '2', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, {'g', 'r', 'e', 'e', 'n', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, 0x0L, 0x0, 0x0, 0L}}, - - CO_OD_FIRST_LAST_WORD -}; - - -/******************************************************************************* - STRUCTURES FOR RECORD TYPE OBJECTS -*******************************************************************************/ -/*0x1018*/ const CO_OD_entryRecord_t OD_record1018[5] = { - {(void*)&CO_OD_ROM.identity.maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.identity.vendorID, 0x85, 4}, - {(void*)&CO_OD_ROM.identity.productCode, 0x85, 4}, - {(void*)&CO_OD_ROM.identity.revisionNumber, 0x85, 4}, - {(void*)&CO_OD_ROM.identity.serialNumber, 0x85, 4}}; -/*0x1200*/ const CO_OD_entryRecord_t OD_record1200[3] = { - {(void*)&CO_OD_ROM.SDOServerParameter[0].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.SDOServerParameter[0].COB_IDClientToServer, 0x85, 4}, - {(void*)&CO_OD_ROM.SDOServerParameter[0].COB_IDServerToClient, 0x85, 4}}; -/*0x1400*/ const CO_OD_entryRecord_t OD_record1400[3] = { - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].COB_IDUsedByRPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].transmissionType, 0x0D, 1}}; -/*0x1401*/ const CO_OD_entryRecord_t OD_record1401[3] = { - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].COB_IDUsedByRPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].transmissionType, 0x0D, 1}}; -/*0x1402*/ const CO_OD_entryRecord_t OD_record1402[3] = { - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].COB_IDUsedByRPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].transmissionType, 0x0D, 1}}; -/*0x1403*/ const CO_OD_entryRecord_t OD_record1403[3] = { - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].COB_IDUsedByRPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].transmissionType, 0x0D, 1}}; -/*0x1600*/ const CO_OD_entryRecord_t OD_record1600[9] = { - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject8, 0x8D, 4}}; -/*0x1601*/ const CO_OD_entryRecord_t OD_record1601[9] = { - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject8, 0x8D, 4}}; -/*0x1602*/ const CO_OD_entryRecord_t OD_record1602[9] = { - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject8, 0x8D, 4}}; -/*0x1603*/ const CO_OD_entryRecord_t OD_record1603[9] = { - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject8, 0x8D, 4}}; -/*0x1800*/ const CO_OD_entryRecord_t OD_record1800[7] = { - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].COB_IDUsedByTPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].transmissionType, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].inhibitTime, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].compatibilityEntry, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].eventTimer, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].SYNCStartValue, 0x0D, 1}}; -/*0x1801*/ const CO_OD_entryRecord_t OD_record1801[7] = { - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].COB_IDUsedByTPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].transmissionType, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].inhibitTime, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].compatibilityEntry, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].eventTimer, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].SYNCStartValue, 0x0D, 1}}; -/*0x1802*/ const CO_OD_entryRecord_t OD_record1802[7] = { - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].COB_IDUsedByTPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].transmissionType, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].inhibitTime, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].compatibilityEntry, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].eventTimer, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].SYNCStartValue, 0x0D, 1}}; -/*0x1803*/ const CO_OD_entryRecord_t OD_record1803[7] = { - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].COB_IDUsedByTPDO, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].transmissionType, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].inhibitTime, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].compatibilityEntry, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].eventTimer, 0x8D, 2}, - {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].SYNCStartValue, 0x0D, 1}}; -/*0x1A00*/ const CO_OD_entryRecord_t OD_record1A00[9] = { - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject8, 0x8D, 4}}; -/*0x1A01*/ const CO_OD_entryRecord_t OD_record1A01[9] = { - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject8, 0x8D, 4}}; -/*0x1A02*/ const CO_OD_entryRecord_t OD_record1A02[9] = { - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject8, 0x8D, 4}}; -/*0x1A03*/ const CO_OD_entryRecord_t OD_record1A03[9] = { - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].numberOfMappedObjects, 0x0D, 1}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject1, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject2, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject3, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject4, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject5, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject6, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject7, 0x8D, 4}, - {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject8, 0x8D, 4}}; -/*0x2120*/ const CO_OD_entryRecord_t OD_record2120[6] = { - {(void*)&CO_OD_RAM.testVar.maxSubIndex, 0x06, 1}, - {(void*)&CO_OD_RAM.testVar.I64, 0xBE, 8}, - {(void*)&CO_OD_RAM.testVar.U64, 0xBE, 8}, - {(void*)&CO_OD_RAM.testVar.R32, 0xBE, 4}, - {(void*)&CO_OD_RAM.testVar.R64, 0xBE, 8}, - {0, 0x0E, 0}}; -/*0x2130*/ const CO_OD_entryRecord_t OD_record2130[4] = { - {(void*)&CO_OD_RAM.time.maxSubIndex, 0x06, 1}, - {(void*)&CO_OD_RAM.time.string[0], 0x06, 30}, - {(void*)&CO_OD_RAM.time.epochTimeBaseMs, 0x8E, 8}, - {(void*)&CO_OD_RAM.time.epochTimeOffsetMs, 0xBE, 4}}; -/*0x2301*/ const CO_OD_entryRecord_t OD_record2301[9] = { - {(void*)&CO_OD_ROM.traceConfig[0].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.traceConfig[0].size, 0x8D, 4}, - {(void*)&CO_OD_ROM.traceConfig[0].axisNo, 0x0D, 1}, - {(void*)&CO_OD_ROM.traceConfig[0].name[0], 0x0D, 30}, - {(void*)&CO_OD_ROM.traceConfig[0].color[0], 0x0D, 20}, - {(void*)&CO_OD_ROM.traceConfig[0].map, 0x8D, 4}, - {(void*)&CO_OD_ROM.traceConfig[0].format, 0x0D, 1}, - {(void*)&CO_OD_ROM.traceConfig[0].trigger, 0x0D, 1}, - {(void*)&CO_OD_ROM.traceConfig[0].threshold, 0x8D, 4}}; -/*0x2302*/ const CO_OD_entryRecord_t OD_record2302[9] = { - {(void*)&CO_OD_ROM.traceConfig[1].maxSubIndex, 0x05, 1}, - {(void*)&CO_OD_ROM.traceConfig[1].size, 0x8D, 4}, - {(void*)&CO_OD_ROM.traceConfig[1].axisNo, 0x0D, 1}, - {(void*)&CO_OD_ROM.traceConfig[1].name[0], 0x0D, 30}, - {(void*)&CO_OD_ROM.traceConfig[1].color[0], 0x0D, 20}, - {(void*)&CO_OD_ROM.traceConfig[1].map, 0x8D, 4}, - {(void*)&CO_OD_ROM.traceConfig[1].format, 0x0D, 1}, - {(void*)&CO_OD_ROM.traceConfig[1].trigger, 0x0D, 1}, - {(void*)&CO_OD_ROM.traceConfig[1].threshold, 0x8D, 4}}; -/*0x2401*/ const CO_OD_entryRecord_t OD_record2401[7] = { - {(void*)&CO_OD_RAM.trace[0].maxSubIndex, 0x06, 1}, - {(void*)&CO_OD_RAM.trace[0].size, 0xBE, 4}, - {(void*)&CO_OD_RAM.trace[0].value, 0xA6, 4}, - {(void*)&CO_OD_RAM.trace[0].min, 0xBE, 4}, - {(void*)&CO_OD_RAM.trace[0].max, 0xBE, 4}, - {0, 0x06, 0}, - {(void*)&CO_OD_RAM.trace[0].triggerTime, 0xBE, 4}}; -/*0x2402*/ const CO_OD_entryRecord_t OD_record2402[7] = { - {(void*)&CO_OD_RAM.trace[1].maxSubIndex, 0x06, 1}, - {(void*)&CO_OD_RAM.trace[1].size, 0xBE, 4}, - {(void*)&CO_OD_RAM.trace[1].value, 0xA6, 4}, - {(void*)&CO_OD_RAM.trace[1].min, 0xBE, 4}, - {(void*)&CO_OD_RAM.trace[1].max, 0xBE, 4}, - {0, 0x06, 0}, - {(void*)&CO_OD_RAM.trace[1].triggerTime, 0xBE, 4}}; - - -/******************************************************************************* - OBJECT DICTIONARY -*******************************************************************************/ -const CO_OD_entry_t CO_OD[CO_OD_NoOfElements] = { -{0x1000, 0x00, 0x85, 4, (void*)&CO_OD_ROM.deviceType}, -{0x1001, 0x00, 0x36, 1, (void*)&CO_OD_RAM.errorRegister}, -{0x1002, 0x00, 0xB6, 4, (void*)&CO_OD_RAM.manufacturerStatusRegister}, -{0x1003, 0x08, 0x8E, 4, (void*)&CO_OD_RAM.preDefinedErrorField[0]}, -{0x1005, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.COB_ID_SYNCMessage}, -{0x1006, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.communicationCyclePeriod}, -{0x1007, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.synchronousWindowLength}, -{0x1008, 0x00, 0x05, 11, (void*)&CO_OD_ROM.manufacturerDeviceName[0]}, -{0x1009, 0x00, 0x05, 4, (void*)&CO_OD_ROM.manufacturerHardwareVersion[0]}, -{0x100A, 0x00, 0x05, 4, (void*)&CO_OD_ROM.manufacturerSoftwareVersion[0]}, -{0x1010, 0x01, 0x8E, 4, (void*)&CO_OD_RAM.storeParameters[0]}, -{0x1011, 0x01, 0x8E, 4, (void*)&CO_OD_RAM.restoreDefaultParameters[0]}, -{0x1014, 0x00, 0x85, 4, (void*)&CO_OD_ROM.COB_ID_EMCY}, -{0x1015, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.inhibitTimeEMCY}, -{0x1016, 0x04, 0x8D, 4, (void*)&CO_OD_ROM.consumerHeartbeatTime[0]}, -{0x1017, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.producerHeartbeatTime}, -{0x1018, 0x04, 0x00, 0, (void*)&OD_record1018}, -{0x1019, 0x00, 0x0D, 1, (void*)&CO_OD_ROM.synchronousCounterOverflowValue}, -{0x1029, 0x06, 0x0D, 1, (void*)&CO_OD_ROM.errorBehavior[0]}, -{0x1200, 0x02, 0x00, 0, (void*)&OD_record1200}, -{0x1400, 0x02, 0x00, 0, (void*)&OD_record1400}, -{0x1401, 0x02, 0x00, 0, (void*)&OD_record1401}, -{0x1402, 0x02, 0x00, 0, (void*)&OD_record1402}, -{0x1403, 0x02, 0x00, 0, (void*)&OD_record1403}, -{0x1600, 0x08, 0x00, 0, (void*)&OD_record1600}, -{0x1601, 0x08, 0x00, 0, (void*)&OD_record1601}, -{0x1602, 0x08, 0x00, 0, (void*)&OD_record1602}, -{0x1603, 0x08, 0x00, 0, (void*)&OD_record1603}, -{0x1800, 0x06, 0x00, 0, (void*)&OD_record1800}, -{0x1801, 0x06, 0x00, 0, (void*)&OD_record1801}, -{0x1802, 0x06, 0x00, 0, (void*)&OD_record1802}, -{0x1803, 0x06, 0x00, 0, (void*)&OD_record1803}, -{0x1A00, 0x08, 0x00, 0, (void*)&OD_record1A00}, -{0x1A01, 0x08, 0x00, 0, (void*)&OD_record1A01}, -{0x1A02, 0x08, 0x00, 0, (void*)&OD_record1A02}, -{0x1A03, 0x08, 0x00, 0, (void*)&OD_record1A03}, -{0x1F80, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.NMTStartup}, -{0x2100, 0x00, 0x36, 10, (void*)&CO_OD_RAM.errorStatusBits[0]}, -{0x2101, 0x00, 0x0D, 1, (void*)&CO_OD_ROM.CANNodeID}, -{0x2102, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.CANBitRate}, -{0x2103, 0x00, 0x8E, 2, (void*)&CO_OD_RAM.SYNCCounter}, -{0x2104, 0x00, 0x86, 2, (void*)&CO_OD_RAM.SYNCTime}, -{0x2106, 0x00, 0x87, 4, (void*)&CO_OD_EEPROM.powerOnCounter}, -{0x2107, 0x05, 0xBE, 2, (void*)&CO_OD_RAM.performance[0]}, -{0x2108, 0x01, 0xB6, 2, (void*)&CO_OD_RAM.temperature[0]}, -{0x2109, 0x01, 0xB6, 2, (void*)&CO_OD_RAM.voltage[0]}, -{0x2110, 0x10, 0xFE, 4, (void*)&CO_OD_RAM.variableInt32[0]}, -{0x2111, 0x10, 0xFD, 4, (void*)&CO_OD_ROM.variableROMInt32[0]}, -{0x2112, 0x10, 0xFF, 4, (void*)&CO_OD_EEPROM.variableNVInt32[0]}, -{0x2120, 0x05, 0x00, 0, (void*)&OD_record2120}, -{0x2130, 0x03, 0x00, 0, (void*)&OD_record2130}, -{0x2301, 0x08, 0x00, 0, (void*)&OD_record2301}, -{0x2302, 0x08, 0x00, 0, (void*)&OD_record2302}, -{0x2400, 0x00, 0x3E, 1, (void*)&CO_OD_RAM.traceEnable}, -{0x2401, 0x06, 0x00, 0, (void*)&OD_record2401}, -{0x2402, 0x06, 0x00, 0, (void*)&OD_record2402}, -{0x6000, 0x08, 0x76, 1, (void*)&CO_OD_RAM.readInput8Bit[0]}, -{0x6200, 0x08, 0x3E, 1, (void*)&CO_OD_RAM.writeOutput8Bit[0]}, -{0x6401, 0x0C, 0xB6, 2, (void*)&CO_OD_RAM.readAnalogueInput16Bit[0]}, -{0x6411, 0x08, 0xBE, 2, (void*)&CO_OD_RAM.writeAnalogueOutput16Bit[0]}, -}; - diff --git a/example/CO_OD_with_trace/CO_OD.h b/example/CO_OD_with_trace/CO_OD.h deleted file mode 100644 index 717b749b..00000000 --- a/example/CO_OD_with_trace/CO_OD.h +++ /dev/null @@ -1,451 +0,0 @@ -/* - * CANopen Object Dictionary. - * - * This file was automatically generated with CANopenNode Object - * Dictionary Editor. DON'T EDIT THIS FILE MANUALLY !!!! - * Object Dictionary Editor is currently an older, but functional web - * application. For more info see See 'Object_Dictionary_Editor/about.html' in - * - * For more information on CANopen Object Dictionary see . - * - * @file CO_OD.h - * @author Janez Paternoster - * @copyright 2010 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_OD_H -#define CO_OD_H - - -/******************************************************************************* - CANopen DATA DYPES -*******************************************************************************/ - typedef uint8_t UNSIGNED8; - typedef uint16_t UNSIGNED16; - typedef uint32_t UNSIGNED32; - typedef uint64_t UNSIGNED64; - typedef int8_t INTEGER8; - typedef int16_t INTEGER16; - typedef int32_t INTEGER32; - typedef int64_t INTEGER64; - typedef float32_t REAL32; - typedef float64_t REAL64; - typedef char_t VISIBLE_STRING; - typedef oChar_t OCTET_STRING; - typedef domain_t DOMAIN; - - -/******************************************************************************* - FILE INFO: - FileName: IO Example - FileVersion: - - CreationTime: 17:24:43 - CreationDate: 2016-03-25 - CreatedBy: JP -*******************************************************************************/ - - -/******************************************************************************* - DEVICE INFO: - VendorName: CANopenNode - VendorNumber: 0 - ProductName: CANopenNode - ProductNumber: 0 -*******************************************************************************/ - - -/******************************************************************************* - FEATURES -*******************************************************************************/ - #define CO_NO_SYNC 1 //Associated objects: 1005, 1006, 1007, 2103, 2104 - #define CO_NO_EMERGENCY 1 //Associated objects: 1014, 1015 - #define CO_NO_SDO_SERVER 1 //Associated objects: 1200 - #define CO_NO_SDO_CLIENT 0 - #define CO_NO_RPDO 4 //Associated objects: 1400, 1401, 1402, 1403, 1600, 1601, 1602, 1603 - #define CO_NO_TPDO 4 //Associated objects: 1800, 1801, 1802, 1803, 1A00, 1A01, 1A02, 1A03 - #define CO_NO_NMT_MASTER 0 - #define CO_NO_TRACE 2 //Associated objects: 2301, 2302, 2400, 2401, 2402 - - -/******************************************************************************* - OBJECT DICTIONARY -*******************************************************************************/ - #define CO_OD_NoOfElements 60 - - -/******************************************************************************* - TYPE DEFINITIONS FOR RECORDS -*******************************************************************************/ -/*1018 */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 vendorID; - UNSIGNED32 productCode; - UNSIGNED32 revisionNumber; - UNSIGNED32 serialNumber; - } OD_identity_t; - -/*1200[1] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 COB_IDClientToServer; - UNSIGNED32 COB_IDServerToClient; - } OD_SDOServerParameter_t; - -/*1400[4] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 COB_IDUsedByRPDO; - UNSIGNED8 transmissionType; - } OD_RPDOCommunicationParameter_t; - -/*1600[4] */ typedef struct{ - UNSIGNED8 numberOfMappedObjects; - UNSIGNED32 mappedObject1; - UNSIGNED32 mappedObject2; - UNSIGNED32 mappedObject3; - UNSIGNED32 mappedObject4; - UNSIGNED32 mappedObject5; - UNSIGNED32 mappedObject6; - UNSIGNED32 mappedObject7; - UNSIGNED32 mappedObject8; - } OD_RPDOMappingParameter_t; - -/*1800[4] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 COB_IDUsedByTPDO; - UNSIGNED8 transmissionType; - UNSIGNED16 inhibitTime; - UNSIGNED8 compatibilityEntry; - UNSIGNED16 eventTimer; - UNSIGNED8 SYNCStartValue; - } OD_TPDOCommunicationParameter_t; - -/*1A00[4] */ typedef struct{ - UNSIGNED8 numberOfMappedObjects; - UNSIGNED32 mappedObject1; - UNSIGNED32 mappedObject2; - UNSIGNED32 mappedObject3; - UNSIGNED32 mappedObject4; - UNSIGNED32 mappedObject5; - UNSIGNED32 mappedObject6; - UNSIGNED32 mappedObject7; - UNSIGNED32 mappedObject8; - } OD_TPDOMappingParameter_t; - -/*2120 */ typedef struct{ - UNSIGNED8 maxSubIndex; - INTEGER64 I64; - UNSIGNED64 U64; - REAL32 R32; - REAL64 R64; - DOMAIN domain; - } OD_testVar_t; - -/*2130 */ typedef struct{ - UNSIGNED8 maxSubIndex; - VISIBLE_STRING string[30]; - UNSIGNED64 epochTimeBaseMs; - UNSIGNED32 epochTimeOffsetMs; - } OD_time_t; - -/*2301[2] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 size; - UNSIGNED8 axisNo; - VISIBLE_STRING name[30]; - VISIBLE_STRING color[20]; - UNSIGNED32 map; - UNSIGNED8 format; - UNSIGNED8 trigger; - INTEGER32 threshold; - } OD_traceConfig_t; - -/*2401[2] */ typedef struct{ - UNSIGNED8 maxSubIndex; - UNSIGNED32 size; - INTEGER32 value; - INTEGER32 min; - INTEGER32 max; - DOMAIN plot; - UNSIGNED32 triggerTime; - } OD_trace_t; - - -/******************************************************************************* - STRUCTURES FOR VARIABLES IN DIFFERENT MEMORY LOCATIONS -*******************************************************************************/ -#define CO_OD_FIRST_LAST_WORD 0x55 //Any value from 0x01 to 0xFE. If changed, EEPROM will be reinitialized. - -/***** Structure for RAM variables ********************************************/ -struct sCO_OD_RAM{ - UNSIGNED32 FirstWord; - -/*1001 */ UNSIGNED8 errorRegister; -/*1002 */ UNSIGNED32 manufacturerStatusRegister; -/*1003 */ UNSIGNED32 preDefinedErrorField[8]; -/*1010 */ UNSIGNED32 storeParameters[1]; -/*1011 */ UNSIGNED32 restoreDefaultParameters[1]; -/*2100 */ OCTET_STRING errorStatusBits[10]; -/*2103 */ UNSIGNED16 SYNCCounter; -/*2104 */ UNSIGNED16 SYNCTime; -/*2107 */ UNSIGNED16 performance[5]; -/*2108 */ INTEGER16 temperature[1]; -/*2109 */ INTEGER16 voltage[1]; -/*2110 */ INTEGER32 variableInt32[16]; -/*2120 */ OD_testVar_t testVar; -/*2130 */ OD_time_t time; -/*2400 */ UNSIGNED8 traceEnable; -/*2401[2] */ OD_trace_t trace[2]; -/*6000 */ UNSIGNED8 readInput8Bit[8]; -/*6200 */ UNSIGNED8 writeOutput8Bit[8]; -/*6401 */ INTEGER16 readAnalogueInput16Bit[12]; -/*6411 */ INTEGER16 writeAnalogueOutput16Bit[8]; - - UNSIGNED32 LastWord; -}; - -/***** Structure for EEPROM variables *****************************************/ -struct sCO_OD_EEPROM{ - UNSIGNED32 FirstWord; - -/*2106 */ UNSIGNED32 powerOnCounter; -/*2112 */ INTEGER32 variableNVInt32[16]; - - UNSIGNED32 LastWord; -}; - - -/***** Structure for ROM variables ********************************************/ -struct sCO_OD_ROM{ - UNSIGNED32 FirstWord; - -/*1000 */ UNSIGNED32 deviceType; -/*1005 */ UNSIGNED32 COB_ID_SYNCMessage; -/*1006 */ UNSIGNED32 communicationCyclePeriod; -/*1007 */ UNSIGNED32 synchronousWindowLength; -/*1008 */ VISIBLE_STRING manufacturerDeviceName[11]; -/*1009 */ VISIBLE_STRING manufacturerHardwareVersion[4]; -/*100A */ VISIBLE_STRING manufacturerSoftwareVersion[4]; -/*1014 */ UNSIGNED32 COB_ID_EMCY; -/*1015 */ UNSIGNED16 inhibitTimeEMCY; -/*1016 */ UNSIGNED32 consumerHeartbeatTime[4]; -/*1017 */ UNSIGNED16 producerHeartbeatTime; -/*1018 */ OD_identity_t identity; -/*1019 */ UNSIGNED8 synchronousCounterOverflowValue; -/*1029 */ UNSIGNED8 errorBehavior[6]; -/*1200[1] */ OD_SDOServerParameter_t SDOServerParameter[1]; -/*1400[4] */ OD_RPDOCommunicationParameter_t RPDOCommunicationParameter[4]; -/*1600[4] */ OD_RPDOMappingParameter_t RPDOMappingParameter[4]; -/*1800[4] */ OD_TPDOCommunicationParameter_t TPDOCommunicationParameter[4]; -/*1A00[4] */ OD_TPDOMappingParameter_t TPDOMappingParameter[4]; -/*1F80 */ UNSIGNED32 NMTStartup; -/*2101 */ UNSIGNED8 CANNodeID; -/*2102 */ UNSIGNED16 CANBitRate; -/*2111 */ INTEGER32 variableROMInt32[16]; -/*2301[2] */ OD_traceConfig_t traceConfig[2]; - - UNSIGNED32 LastWord; -}; - - -/***** Declaration of Object Dictionary variables *****************************/ -extern struct sCO_OD_RAM CO_OD_RAM; - -extern struct sCO_OD_EEPROM CO_OD_EEPROM; - -extern struct sCO_OD_ROM CO_OD_ROM; - - -/******************************************************************************* - ALIASES FOR OBJECT DICTIONARY VARIABLES -*******************************************************************************/ -/*1000, Data Type: UNSIGNED32 */ - #define OD_deviceType CO_OD_ROM.deviceType - -/*1001, Data Type: UNSIGNED8 */ - #define OD_errorRegister CO_OD_RAM.errorRegister - -/*1002, Data Type: UNSIGNED32 */ - #define OD_manufacturerStatusRegister CO_OD_RAM.manufacturerStatusRegister - -/*1003, Data Type: UNSIGNED32, Array[8] */ - #define OD_preDefinedErrorField CO_OD_RAM.preDefinedErrorField - #define ODL_preDefinedErrorField_arrayLength 8 - -/*1005, Data Type: UNSIGNED32 */ - #define OD_COB_ID_SYNCMessage CO_OD_ROM.COB_ID_SYNCMessage - -/*1006, Data Type: UNSIGNED32 */ - #define OD_communicationCyclePeriod CO_OD_ROM.communicationCyclePeriod - -/*1007, Data Type: UNSIGNED32 */ - #define OD_synchronousWindowLength CO_OD_ROM.synchronousWindowLength - -/*1008, Data Type: VISIBLE_STRING, Array[11] */ - #define OD_manufacturerDeviceName CO_OD_ROM.manufacturerDeviceName - #define ODL_manufacturerDeviceName_stringLength 11 - -/*1009, Data Type: VISIBLE_STRING, Array[4] */ - #define OD_manufacturerHardwareVersion CO_OD_ROM.manufacturerHardwareVersion - #define ODL_manufacturerHardwareVersion_stringLength 4 - -/*100A, Data Type: VISIBLE_STRING, Array[4] */ - #define OD_manufacturerSoftwareVersion CO_OD_ROM.manufacturerSoftwareVersion - #define ODL_manufacturerSoftwareVersion_stringLength 4 - -/*1010, Data Type: UNSIGNED32, Array[1] */ - #define OD_storeParameters CO_OD_RAM.storeParameters - #define ODL_storeParameters_arrayLength 1 - #define ODA_storeParameters_saveAllParameters 0 - -/*1011, Data Type: UNSIGNED32, Array[1] */ - #define OD_restoreDefaultParameters CO_OD_RAM.restoreDefaultParameters - #define ODL_restoreDefaultParameters_arrayLength 1 - #define ODA_restoreDefaultParameters_restoreAllDefaultParameters 0 - -/*1014, Data Type: UNSIGNED32 */ - #define OD_COB_ID_EMCY CO_OD_ROM.COB_ID_EMCY - -/*1015, Data Type: UNSIGNED16 */ - #define OD_inhibitTimeEMCY CO_OD_ROM.inhibitTimeEMCY - -/*1016, Data Type: UNSIGNED32, Array[4] */ - #define OD_consumerHeartbeatTime CO_OD_ROM.consumerHeartbeatTime - #define ODL_consumerHeartbeatTime_arrayLength 4 - -/*1017, Data Type: UNSIGNED16 */ - #define OD_producerHeartbeatTime CO_OD_ROM.producerHeartbeatTime - -/*1018, Data Type: OD_identity_t */ - #define OD_identity CO_OD_ROM.identity - -/*1019, Data Type: UNSIGNED8 */ - #define OD_synchronousCounterOverflowValue CO_OD_ROM.synchronousCounterOverflowValue - -/*1029, Data Type: UNSIGNED8, Array[6] */ - #define OD_errorBehavior CO_OD_ROM.errorBehavior - #define ODL_errorBehavior_arrayLength 6 - #define ODA_errorBehavior_communication 0 - #define ODA_errorBehavior_communicationOther 1 - #define ODA_errorBehavior_communicationPassive 2 - #define ODA_errorBehavior_generic 3 - #define ODA_errorBehavior_deviceProfile 4 - #define ODA_errorBehavior_manufacturerSpecific 5 - -/*1200[1], Data Type: OD_SDOServerParameter_t, Array[1] */ - #define OD_SDOServerParameter CO_OD_ROM.SDOServerParameter - -/*1400[4], Data Type: OD_RPDOCommunicationParameter_t, Array[4] */ - #define OD_RPDOCommunicationParameter CO_OD_ROM.RPDOCommunicationParameter - -/*1600[4], Data Type: OD_RPDOMappingParameter_t, Array[4] */ - #define OD_RPDOMappingParameter CO_OD_ROM.RPDOMappingParameter - -/*1800[4], Data Type: OD_TPDOCommunicationParameter_t, Array[4] */ - #define OD_TPDOCommunicationParameter CO_OD_ROM.TPDOCommunicationParameter - -/*1A00[4], Data Type: OD_TPDOMappingParameter_t, Array[4] */ - #define OD_TPDOMappingParameter CO_OD_ROM.TPDOMappingParameter - -/*1F80, Data Type: UNSIGNED32 */ - #define OD_NMTStartup CO_OD_ROM.NMTStartup - -/*2100, Data Type: OCTET_STRING, Array[10] */ - #define OD_errorStatusBits CO_OD_RAM.errorStatusBits - #define ODL_errorStatusBits_stringLength 10 - -/*2101, Data Type: UNSIGNED8 */ - #define OD_CANNodeID CO_OD_ROM.CANNodeID - -/*2102, Data Type: UNSIGNED16 */ - #define OD_CANBitRate CO_OD_ROM.CANBitRate - -/*2103, Data Type: UNSIGNED16 */ - #define OD_SYNCCounter CO_OD_RAM.SYNCCounter - -/*2104, Data Type: UNSIGNED16 */ - #define OD_SYNCTime CO_OD_RAM.SYNCTime - -/*2106, Data Type: UNSIGNED32 */ - #define OD_powerOnCounter CO_OD_EEPROM.powerOnCounter - -/*2107, Data Type: UNSIGNED16, Array[5] */ - #define OD_performance CO_OD_RAM.performance - #define ODL_performance_arrayLength 5 - #define ODA_performance_cyclesPerSecond 0 - #define ODA_performance_timerCycleTime 1 - #define ODA_performance_timerCycleMaxTime 2 - #define ODA_performance_mainCycleTime 3 - #define ODA_performance_mainCycleMaxTime 4 - -/*2108, Data Type: INTEGER16, Array[1] */ - #define OD_temperature CO_OD_RAM.temperature - #define ODL_temperature_arrayLength 1 - #define ODA_temperature_mainPCB 0 - -/*2109, Data Type: INTEGER16, Array[1] */ - #define OD_voltage CO_OD_RAM.voltage - #define ODL_voltage_arrayLength 1 - #define ODA_voltage_mainPCBSupply 0 - -/*2110, Data Type: INTEGER32, Array[16] */ - #define OD_variableInt32 CO_OD_RAM.variableInt32 - #define ODL_variableInt32_arrayLength 16 - -/*2111, Data Type: INTEGER32, Array[16] */ - #define OD_variableROMInt32 CO_OD_ROM.variableROMInt32 - #define ODL_variableROMInt32_arrayLength 16 - -/*2112, Data Type: INTEGER32, Array[16] */ - #define OD_variableNVInt32 CO_OD_EEPROM.variableNVInt32 - #define ODL_variableNVInt32_arrayLength 16 - -/*2120, Data Type: OD_testVar_t */ - #define OD_testVar CO_OD_RAM.testVar - -/*2130, Data Type: OD_time_t */ - #define OD_time CO_OD_RAM.time - -/*2301[2], Data Type: OD_traceConfig_t, Array[2] */ - #define OD_traceConfig CO_OD_ROM.traceConfig - -/*2400, Data Type: UNSIGNED8 */ - #define OD_traceEnable CO_OD_RAM.traceEnable - -/*2401[2], Data Type: OD_trace_t, Array[2] */ - #define OD_trace CO_OD_RAM.trace - -/*6000, Data Type: UNSIGNED8, Array[8] */ - #define OD_readInput8Bit CO_OD_RAM.readInput8Bit - #define ODL_readInput8Bit_arrayLength 8 - -/*6200, Data Type: UNSIGNED8, Array[8] */ - #define OD_writeOutput8Bit CO_OD_RAM.writeOutput8Bit - #define ODL_writeOutput8Bit_arrayLength 8 - -/*6401, Data Type: INTEGER16, Array[12] */ - #define OD_readAnalogueInput16Bit CO_OD_RAM.readAnalogueInput16Bit - #define ODL_readAnalogueInput16Bit_arrayLength 12 - -/*6411, Data Type: INTEGER16, Array[8] */ - #define OD_writeAnalogueOutput16Bit CO_OD_RAM.writeAnalogueOutput16Bit - #define ODL_writeAnalogueOutput16Bit_arrayLength 8 - - -#endif - diff --git a/example/DS301_profile.eds b/example/DS301_profile.eds new file mode 100644 index 00000000..c3a2f5b5 --- /dev/null +++ b/example/DS301_profile.eds @@ -0,0 +1,1688 @@ +[FileInfo] +FileName=DS301_profile.eds +FileVersion=1 +FileRevision=1 +LastEDS= +EDSVersion=4.0 +Description= +CreationTime=12:00PM +CreationDate=11-23-2020 +CreatedBy= +ModificationTime=1:31PM +ModificationDate=11-24-2020 +ModifiedBy= + +[DeviceInfo] +VendorName= +VendorNumber= +ProductName=New Product +ProductNumber= +RevisionNumber=0 +BaudRate_10=1 +BaudRate_20=1 +BaudRate_50=1 +BaudRate_125=1 +BaudRate_250=1 +BaudRate_500=1 +BaudRate_800=1 +BaudRate_1000=1 +SimpleBootUpMaster=0 +SimpleBootUpSlave=0 +Granularity=8 +DynamicChannelsSupported=0 +CompactPDO=0 +GroupMessaging=0 +NrOfRXPDO=4 +NrOfTXPDO=4 +LSS_Supported=1 + +[DummyUsage] +Dummy0001=0 +Dummy0002=1 +Dummy0003=1 +Dummy0004=1 +Dummy0005=1 +Dummy0006=1 +Dummy0007=1 + +[Comments] +Lines=0 + +[MandatoryObjects] +SupportedObjects=3 +1=0x1000 +2=0x1001 +3=0x1018 + +[1000] +ParameterName=Device type +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1001] +ParameterName=Error register +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x00 +PDOMapping=1 + +[1018] +ParameterName=Identity +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x5 + +[1018sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x04 +PDOMapping=0 + +[1018sub1] +ParameterName=Vendor-ID +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1018sub2] +ParameterName=Product code +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1018sub3] +ParameterName=Revision number +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1018sub4] +ParameterName=Serial number +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[OptionalObjects] +SupportedObjects=30 +1=0x1003 +2=0x1005 +3=0x1006 +4=0x1007 +5=0x1010 +6=0x1011 +7=0x1012 +8=0x1014 +9=0x1015 +10=0x1016 +11=0x1017 +12=0x1019 +13=0x1200 +14=0x1280 +15=0x1400 +16=0x1401 +17=0x1402 +18=0x1403 +19=0x1600 +20=0x1601 +21=0x1602 +22=0x1603 +23=0x1800 +24=0x1801 +25=0x1802 +26=0x1803 +27=0x1A00 +28=0x1A01 +29=0x1A02 +30=0x1A03 + +[1003] +ParameterName=Pre-defined error field +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x9 + +[1003sub0] +ParameterName=Number of errors +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1003sub1] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1003sub2] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1003sub3] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1003sub4] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1003sub5] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1003sub6] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1003sub7] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1003sub8] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1005] +ParameterName=COB-ID SYNC message +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000080 +PDOMapping=0 + +[1006] +ParameterName=Communication cycle period +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1007] +ParameterName=Synchronous window length +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1010] +ParameterName=Store parameters +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x5 + +[1010sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x04 +PDOMapping=0 + +[1010sub1] +ParameterName=Save all parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1010sub2] +ParameterName=Save communication parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1010sub3] +ParameterName=Save application parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1010sub4] +ParameterName=Save manufacturer defined parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1011] +ParameterName=Restore default parameters +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x5 + +[1011sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x04 +PDOMapping=0 + +[1011sub1] +ParameterName=Restore all default parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1011sub2] +ParameterName=Restore communication default parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1011sub3] +ParameterName=Restore application default parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1011sub4] +ParameterName=Restore manufacturer defined default parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1012] +ParameterName=COB-ID time stamp object +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000100 +PDOMapping=0 + +[1014] +ParameterName=COB-ID EMCY +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0007 +AccessType=rw +DefaultValue=0x80+$NODEID +PDOMapping=0 + +[1015] +ParameterName=Inhibit time EMCY +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1016] +ParameterName=Consumer heartbeat time +ObjectType=0x8 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1016sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x08 +PDOMapping=0 + +[1016sub1] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub2] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub3] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub4] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub5] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub6] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub7] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub8] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1017] +ParameterName=Producer heartbeat time +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1019] +ParameterName=Synchronous counter overflow value +ObjectType=0x7 +;StorageLocation=PERSIST_COMM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1200] +ParameterName=SDO server parameter +ObjectType=0x9 +;StorageLocation=RAM +SubNumber=0x3 + +[1200sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1200sub1] +ParameterName=COB-ID client to server (rx) +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x600+$NODEID +PDOMapping=1 + +[1200sub2] +ParameterName=COB-ID server to client (tx) +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0x580+$NODEID +PDOMapping=1 + +[1280] +ParameterName=SDO client parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x4 + +[1280sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x03 +PDOMapping=0 + +[1280sub1] +ParameterName=COB-ID client to server (tx) +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x80000000 +PDOMapping=1 + +[1280sub2] +ParameterName=COB-ID server to client (rx) +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x80000000 +PDOMapping=1 + +[1280sub3] +ParameterName=Node-ID of the SDO server +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0x01 +PDOMapping=0 + +[1400] +ParameterName=RPDO communication parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x4 + +[1400sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x05 +PDOMapping=0 + +[1400sub1] +ParameterName=COB-ID used by RPDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x80000200+$NODEID +PDOMapping=0 + +[1400sub2] +ParameterName=Transmission type +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1400sub5] +ParameterName=Event timer +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1401] +ParameterName=RPDO communication parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x4 + +[1401sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x05 +PDOMapping=0 + +[1401sub1] +ParameterName=COB-ID used by RPDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x80000300+$NODEID +PDOMapping=0 + +[1401sub2] +ParameterName=Transmission type +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1401sub5] +ParameterName=Event timer +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1402] +ParameterName=RPDO communication parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x4 + +[1402sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x05 +PDOMapping=0 + +[1402sub1] +ParameterName=COB-ID used by RPDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x80000400+$NODEID +PDOMapping=0 + +[1402sub2] +ParameterName=Transmission type +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1402sub5] +ParameterName=Event timer +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1403] +ParameterName=RPDO communication parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x4 + +[1403sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x05 +PDOMapping=0 + +[1403sub1] +ParameterName=COB-ID used by RPDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x80000500+$NODEID +PDOMapping=0 + +[1403sub2] +ParameterName=Transmission type +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1403sub5] +ParameterName=Event timer +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1600] +ParameterName=RPDO mapping parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1600sub0] +ParameterName=Number of mapped application objects in PDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1600sub1] +ParameterName=Application object 1 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub2] +ParameterName=Application object 2 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub3] +ParameterName=Application object 3 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub4] +ParameterName=Application object 4 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub5] +ParameterName=Application object 5 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub6] +ParameterName=Application object 6 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub7] +ParameterName=Application object 7 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub8] +ParameterName=Application object 8 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601] +ParameterName=RPDO mapping parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1601sub0] +ParameterName=Number of mapped application objects in PDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1601sub1] +ParameterName=Application object 1 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub2] +ParameterName=Application object 2 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub3] +ParameterName=Application object 3 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub4] +ParameterName=Application object 4 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub5] +ParameterName=Application object 5 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub6] +ParameterName=Application object 6 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub7] +ParameterName=Application object 7 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub8] +ParameterName=Application object 8 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602] +ParameterName=RPDO mapping parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1602sub0] +ParameterName=Number of mapped application objects in PDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1602sub1] +ParameterName=Application object 1 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub2] +ParameterName=Application object 2 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub3] +ParameterName=Application object 3 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub4] +ParameterName=Application object 4 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub5] +ParameterName=Application object 5 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub6] +ParameterName=Application object 6 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub7] +ParameterName=Application object 7 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub8] +ParameterName=Application object 8 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603] +ParameterName=RPDO mapping parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1603sub0] +ParameterName=Number of mapped application objects in PDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1603sub1] +ParameterName=Application object 1 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub2] +ParameterName=Application object 2 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub3] +ParameterName=Application object 3 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub4] +ParameterName=Application object 4 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub5] +ParameterName=Application object 5 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub6] +ParameterName=Application object 6 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub7] +ParameterName=Application object 7 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub8] +ParameterName=Application object 8 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1800] +ParameterName=TPDO communication parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x6 + +[1800sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x06 +PDOMapping=0 + +[1800sub1] +ParameterName=COB-ID used by TPDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0xC0000180+$NODEID +PDOMapping=0 + +[1800sub2] +ParameterName=Transmission type +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1800sub3] +ParameterName=Inhibit time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1800sub5] +ParameterName=Event timer +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1800sub6] +ParameterName=SYNC start value +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1801] +ParameterName=TPDO communication parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x6 + +[1801sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x06 +PDOMapping=0 + +[1801sub1] +ParameterName=COB-ID used by TPDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0xC0000280+$NODEID +PDOMapping=0 + +[1801sub2] +ParameterName=Transmission type +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1801sub3] +ParameterName=Inhibit time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1801sub5] +ParameterName=Event timer +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1801sub6] +ParameterName=SYNC start value +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1802] +ParameterName=TPDO communication parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x6 + +[1802sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x06 +PDOMapping=0 + +[1802sub1] +ParameterName=COB-ID used by TPDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0xC0000380+$NODEID +PDOMapping=0 + +[1802sub2] +ParameterName=Transmission type +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1802sub3] +ParameterName=Inhibit time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1802sub5] +ParameterName=Event timer +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1802sub6] +ParameterName=SYNC start value +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1803] +ParameterName=TPDO communication parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x6 + +[1803sub0] +ParameterName=Highest sub-index supported +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0x06 +PDOMapping=0 + +[1803sub1] +ParameterName=COB-ID used by TPDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0xC0000480+$NODEID +PDOMapping=0 + +[1803sub2] +ParameterName=Transmission type +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1803sub3] +ParameterName=Inhibit time +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1803sub5] +ParameterName=Event timer +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1803sub6] +ParameterName=SYNC start value +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A00] +ParameterName=TPDO mapping parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1A00sub0] +ParameterName=Number of mapped application objects in PDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A00sub1] +ParameterName=Application object 1 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub2] +ParameterName=Application object 2 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub3] +ParameterName=Application object 3 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub4] +ParameterName=Application object 4 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub5] +ParameterName=Application object 5 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub6] +ParameterName=Application object 6 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub7] +ParameterName=Application object 7 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub8] +ParameterName=Application object 8 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01] +ParameterName=TPDO mapping parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1A01sub0] +ParameterName=Number of mapped application objects in PDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A01sub1] +ParameterName=Application object 1 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub2] +ParameterName=Application object 2 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub3] +ParameterName=Application object 3 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub4] +ParameterName=Application object 4 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub5] +ParameterName=Application object 5 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub6] +ParameterName=Application object 6 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub7] +ParameterName=Application object 7 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub8] +ParameterName=Application object 8 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02] +ParameterName=TPDO mapping parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1A02sub0] +ParameterName=Number of mapped application objects in PDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A02sub1] +ParameterName=Application object 1 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub2] +ParameterName=Application object 2 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub3] +ParameterName=Application object 3 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub4] +ParameterName=Application object 4 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub5] +ParameterName=Application object 5 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub6] +ParameterName=Application object 6 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub7] +ParameterName=Application object 7 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub8] +ParameterName=Application object 8 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03] +ParameterName=TPDO mapping parameter +ObjectType=0x9 +;StorageLocation=PERSIST_COMM +SubNumber=0x9 + +[1A03sub0] +ParameterName=Number of mapped application objects in PDO +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A03sub1] +ParameterName=Application object 1 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub2] +ParameterName=Application object 2 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub3] +ParameterName=Application object 3 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub4] +ParameterName=Application object 4 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub5] +ParameterName=Application object 5 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub6] +ParameterName=Application object 6 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub7] +ParameterName=Application object 7 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub8] +ParameterName=Application object 8 +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[ManufacturerObjects] +SupportedObjects=0 + diff --git a/example/DS301_profile.md b/example/DS301_profile.md new file mode 100644 index 00000000..8dbd4404 --- /dev/null +++ b/example/DS301_profile.md @@ -0,0 +1,738 @@ +CANopen documentation +===================== +**New Product** + + + +| | | +| ------------ | ------------------------------ | +| Project File | DS301_profile.xpd | +| File Version | 1 | +| Created | 23. 11. 2020 12:00:00 | +| Created By | | +| Modified | 24. 11. 2020 13:31:53 | +| Modified By | | + +This file was automatically generated with [libedssharp](https://github.com/robincornelius/libedssharp) Object Dictionary Editor v0.8-99-g0425f94 + +* [Device Information](#device-information) * [PDO Mapping](#pdo-mapping) * [Communication Specific Parameters](#communication-specific-parameters) * [Manufacturer Specific Parameters](#manufacturer-specific-parameters) * [Device Profile Specific Parameters](#device-profile-specific-parameters) + +Device Information {#device-information} +---------------------------------------- +| | | +| ------------ | ------------------------------ | +| Vendor Name | | +| Vendor ID | | +| Product Name | New Product | +| Product ID | | +| Granularity | 8 | +| RPDO count | 4 | +| TPDO count | 4 | +| LSS Slave | True | +| LSS Master | False | + +#### Supported Baud rates +* [x] 10 kBit/s +* [x] 20 kBit/s +* [x] 50 kBit/s +* [x] 125 kBit/s +* [x] 250 kBit/s +* [x] 500 kBit/s +* [x] 800 kBit/s +* [x] 1000 kBit/s +* [ ] auto + + +PDO Mapping {#pdo-mapping} +-------------------------- + +Communication Specific Parameters {#communication-specific-parameters} +---------------------------------------------------------------------- + +### 0x1000 - Device type +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | NMT | PERSIST_COMM | False | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED32 | ro | no | no | 0x00000000 | + +* bit 16-31: Additional information +* bit 0-15: Device profile number + +### 0x1001 - Error register +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | EM | RAM | False | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED8 | ro | tr | no | 0x00 | + +* bit 7: manufacturer specific +* bit 6: Reserved (always 0) +* bit 5: device profile specific +* bit 4: communication error (overrun, error state) +* bit 3: temperature +* bit 2: voltage +* bit 1: current +* bit 0: generic error + +### 0x1003 - Pre-defined error field +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| ARRAY | | RAM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of errors | UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x02 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x03 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x04 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x05 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x06 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x07 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x08 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | + +* Sub Index 0: Contains number of actual errors. 0 can be written to clear error history. +* sub-index 1 and above: + * bit 16-31: Manufacturer specific additional information + * bit 0-15: Error code as transmited in the Emergency object + +### 0x1005 - COB-ID SYNC message +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | SYNC | PERSIST_COMM | True | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED32 | rw | no | no | 0x00000080 | + +* bit 31: set to 0 +* bit 30: If set, CANopen device generates SYNC object +* bit 11-29: set to 0 +* bit 0-10: 11-bit CAN-ID + +### 0x1006 - Communication cycle period +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | SYNC_PROD | PERSIST_COMM | True | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED32 | rw | no | no | 0 | + +Period of SYNC transmission in µs (0 = transmission disabled). + +### 0x1007 - Synchronous window length +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | | PERSIST_COMM | True | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED32 | rw | no | no | 0 | + +Synchronous window leghth in µs (0 = not used). All synchronous PDOs must be transmitted within this time window. + +### 0x1010 - Store parameters +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| ARRAY | | RAM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x04 | +| 0x01 | Save all parameters | UNSIGNED32 | rw | no | no | 0x00000001 | +| 0x02 | Save communication parameters| UNSIGNED32 | rw | no | no | 0x00000001 | +| 0x03 | Save application parameters| UNSIGNED32 | rw | no | no | 0x00000001 | +| 0x04 | Save manufacturer defined parameters| UNSIGNED32 | rw | no | no | 0x00000001 | + +Sub-indexes 1 and above: +* Reading provides information about its storage functionality: + * bit 1: If set, CANopen device saves parameters autonomously + * bit 0: If set, CANopen device saves parameters on command +* Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores corresponding data. + +### 0x1011 - Restore default parameters +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| ARRAY | | RAM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x04 | +| 0x01 | Restore all default parameters| UNSIGNED32 | rw | no | no | 0x00000001 | +| 0x02 | Restore communication default parameters| UNSIGNED32 | rw | no | no | 0x00000001 | +| 0x03 | Restore application default parameters| UNSIGNED32 | rw | no | no | 0x00000001 | +| 0x04 | Restore manufacturer defined default parameters| UNSIGNED32 | rw | no | no | 0x00000001 | + +Sub-indexes 1 and above: +* Reading provides information about its restoring capability: + * bit 0: If set, CANopen device restores parameters +* Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) restores corresponding data. + +### 0x1012 - COB-ID time stamp object +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | TIME | PERSIST_COMM | True | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED32 | rw | no | no | 0x00000100 | + +* bit 31: If set, CANopen device consumes TIME message +* bit 30: If set, CANopen device produces TIME message +* bit 11-29: set to 0 +* bit 0-10: 11-bit CAN-ID + +### 0x1014 - COB-ID EMCY +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | EM_PROD | PERSIST_COMM | True | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED32 | rw | no | no | 0x80+$NODEID | + +* bit 31: If set, EMCY does NOT exist / is NOT valid +* bit 11-30: set to 0 +* bit 0-10: 11-bit CAN-ID + +### 0x1015 - Inhibit time EMCY +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | | PERSIST_COMM | True | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED16 | rw | no | no | 0 | + +Inhibit time of emergency message in multiples of 100µs. The value 0 disables the inhibit time. + +### 0x1016 - Consumer heartbeat time +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| ARRAY | HB_CONS | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x08 | +| 0x01 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | + +Consumer Heartbeat Time: + * bit 24-31: set to 0 + * bit 16-23: Node ID of the monitored node. If 0 or greater than 127, sub-entry is not used. + * bit 0-15: Heartbeat time in ms (if 0, sub-intry is not used). Value should be higher than the corresponding producer heartbeat time. + +### 0x1017 - Producer heartbeat time +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | HB_PROD | PERSIST_COMM | True | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED16 | rw | no | no | 0 | + +Heartbeat producer time in ms (0 = disable transmission). + +### 0x1018 - Identity +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | False | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x04 | +| 0x01 | Vendor-ID | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x02 | Product code | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x03 | Revision number | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x04 | Serial number | UNSIGNED32 | ro | no | no | 0x00000000 | + +* Vendor-ID, assigned by CiA +* Product code, manufacturer specific +* Revision number: + * bit 16-31: Major revision number (CANopen behavior has changed) + * bit 0-15: Minor revision num. (CANopen behavior has not changed) +* Serial number, manufacturer specific + +### 0x1019 - Synchronous counter overflow value +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| VAR | | PERSIST_COMM | False | False | + +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | +| UNSIGNED8 | rw | no | no | 0 | + +* Value 0: SYNC message is transmitted with data length 0. +* Value 1: reserved. +* Value 2-240: SYNC message has one data byte, which contains the counter. +* Value 241-255: reserved. + +### 0x1200 - SDO server parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | SDO_SRV | RAM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 2 | +| 0x01 | COB-ID client to server (rx)| UNSIGNED32 | ro | t | no | 0x600+$NODEID | +| 0x02 | COB-ID server to client (tx)| UNSIGNED32 | ro | t | no | 0x580+$NODEID | + +Sub-indexes 1 and 2: +* bit 11-31: set to 0 +* bit 0-10: 11-bit CAN-ID + +### 0x1280 - SDO client parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | SDO_CLI | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x03 | +| 0x01 | COB-ID client to server (tx)| UNSIGNED32 | rw | tr | no | 0x80000000 | +| 0x02 | COB-ID server to client (rx)| UNSIGNED32 | rw | tr | no | 0x80000000 | +| 0x03 | Node-ID of the SDO server| UNSIGNED8 | rw | no | no | 0x01 | + +* Sub-indexes 1 and 2: + * bit 31: If set, SDO does NOT exist / is NOT valid + * bit 30: If set, value is assigned dynamically + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Node-ID of the SDO server, 0x01 to 0x7F + +### 0x1400 - RPDO communication parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | RPDO | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | +| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000200+$NODEID| +| 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | +| 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | + +* COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + +### 0x1401 - RPDO communication parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | RPDO | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | +| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000300+$NODEID| +| 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | +| 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | + +* COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + +### 0x1402 - RPDO communication parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | RPDO | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | +| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000400+$NODEID| +| 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | +| 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | + +* COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + +### 0x1403 - RPDO communication parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | RPDO | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | +| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000500+$NODEID| +| 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | +| 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | + +* COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + +### 0x1600 - RPDO mapping parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Application object 2 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Application object 3 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Application object 4 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Application object 5 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Application object 6 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Application object 7 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Application object 8 | UNSIGNED32 | rw | no | no | 0x00000000 | + +* Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + +### 0x1601 - RPDO mapping parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Application object 2 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Application object 3 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Application object 4 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Application object 5 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Application object 6 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Application object 7 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Application object 8 | UNSIGNED32 | rw | no | no | 0x00000000 | + +* Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + +### 0x1602 - RPDO mapping parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Application object 2 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Application object 3 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Application object 4 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Application object 5 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Application object 6 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Application object 7 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Application object 8 | UNSIGNED32 | rw | no | no | 0x00000000 | + +* Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + +### 0x1603 - RPDO mapping parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Application object 2 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Application object 3 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Application object 4 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Application object 5 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Application object 6 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Application object 7 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Application object 8 | UNSIGNED32 | rw | no | no | 0x00000000 | + +* Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + +### 0x1800 - TPDO communication parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | TPDO | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | +| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000180+$NODEID| +| 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | +| 0x03 | Inhibit time | UNSIGNED16 | rw | no | no | 0 | +| 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | +| 0x06 | SYNC start value | UNSIGNED8 | rw | no | no | 0 | + +* COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + +### 0x1801 - TPDO communication parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | TPDO | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | +| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000280+$NODEID| +| 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | +| 0x03 | Inhibit time | UNSIGNED16 | rw | no | no | 0 | +| 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | +| 0x06 | SYNC start value | UNSIGNED8 | rw | no | no | 0 | + +* COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + +### 0x1802 - TPDO communication parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | TPDO | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | +| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000380+$NODEID| +| 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | +| 0x03 | Inhibit time | UNSIGNED16 | rw | no | no | 0 | +| 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | +| 0x06 | SYNC start value | UNSIGNED8 | rw | no | no | 0 | + +* COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + +### 0x1803 - TPDO communication parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | TPDO | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | +| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000480+$NODEID| +| 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | +| 0x03 | Inhibit time | UNSIGNED16 | rw | no | no | 0 | +| 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | +| 0x06 | SYNC start value | UNSIGNED8 | rw | no | no | 0 | + +* COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + +### 0x1A00 - TPDO mapping parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Application object 2 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Application object 3 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Application object 4 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Application object 5 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Application object 6 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Application object 7 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Application object 8 | UNSIGNED32 | rw | no | no | 0x00000000 | + +* Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + +### 0x1A01 - TPDO mapping parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Application object 2 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Application object 3 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Application object 4 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Application object 5 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Application object 6 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Application object 7 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Application object 8 | UNSIGNED32 | rw | no | no | 0x00000000 | + +* Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + +### 0x1A02 - TPDO mapping parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Application object 2 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Application object 3 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Application object 4 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Application object 5 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Application object 6 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Application object 7 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Application object 8 | UNSIGNED32 | rw | no | no | 0x00000000 | + +* Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + +### 0x1A03 - TPDO mapping parameter +| Object Type | Count Label | Storage Group | IO extension | PDO flags | +| ----------- | -------------- | -------------- | ------------- | ------------ | +| RECORD | | PERSIST_COMM | True | False | + +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | +| 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | +| 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x02 | Application object 2 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x03 | Application object 3 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x04 | Application object 4 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x05 | Application object 5 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x06 | Application object 6 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x07 | Application object 7 | UNSIGNED32 | rw | no | no | 0x00000000 | +| 0x08 | Application object 8 | UNSIGNED32 | rw | no | no | 0x00000000 | + +* Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits diff --git a/example/DS301_profile.xpd b/example/DS301_profile.xpd new file mode 100644 index 00000000..99822ff0 --- /dev/null +++ b/example/DS301_profile.xpd @@ -0,0 +1,2631 @@ + + + + + + + CANopen device profile + 1.1 + + + Device + + 1 + 1 + CANopen + + + + + + + New Product + + 0 + 0 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * bit 16-31: Additional information +* bit 0-15: Device profile number + + + + + + + * bit 7: manufacturer specific +* bit 6: Reserved (always 0) +* bit 5: device profile specific +* bit 4: communication error (overrun, error state) +* bit 3: temperature +* bit 2: voltage +* bit 1: current +* bit 0: generic error + + + + + + + + + + + + * Sub Index 0: Contains number of actual errors. 0 can be written to clear error history. +* sub-index 1 and above: + * bit 16-31: Manufacturer specific additional information + * bit 0-15: Error code as transmited in the Emergency object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * bit 31: set to 0 +* bit 30: If set, CANopen device generates SYNC object +* bit 11-29: set to 0 +* bit 0-10: 11-bit CAN-ID + + + + + + + + Period of SYNC transmission in µs (0 = transmission disabled). + + + + + + + + Synchronous window leghth in µs (0 = not used). All synchronous PDOs must be transmitted within this time window. + + + + + + + + + + + + + + + + + + + + + + + + + Sub-indexes 1 and above: +* Reading provides information about its storage functionality: + * bit 1: If set, CANopen device saves parameters autonomously + * bit 0: If set, CANopen device saves parameters on command +* Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores corresponding data. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sub-indexes 1 and above: +* Reading provides information about its restoring capability: + * bit 0: If set, CANopen device restores parameters +* Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) restores corresponding data. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * bit 31: If set, CANopen device consumes TIME message +* bit 30: If set, CANopen device produces TIME message +* bit 11-29: set to 0 +* bit 0-10: 11-bit CAN-ID + + + + + + + + + + + + + + + * bit 31: If set, EMCY does NOT exist / is NOT valid +* bit 11-30: set to 0 +* bit 0-10: 11-bit CAN-ID + + + + + + + + Inhibit time of emergency message in multiples of 100µs. The value 0 disables the inhibit time. + + + + + + + Consumer Heartbeat Time: + * bit 24-31: set to 0 + * bit 16-23: Node ID of the monitored node. If 0 or greater than 127, sub-entry is not used. + * bit 0-15: Heartbeat time in ms (if 0, sub-intry is not used). Value should be higher than the corresponding producer heartbeat time. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Heartbeat producer time in ms (0 = disable transmission). + + + + + + + + * Vendor-ID, assigned by CiA +* Product code, manufacturer specific +* Revision number: + * bit 16-31: Major revision number (CANopen behavior has changed) + * bit 0-15: Minor revision num. (CANopen behavior has not changed) +* Serial number, manufacturer specific + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Value 0: SYNC message is transmitted with data length 0. +* Value 1: reserved. +* Value 2-240: SYNC message has one data byte, which contains the counter. +* Value 241-255: reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Emergency consumer 1 to 127: +* bit 31: If set, EMCY consumer does NOT exist / is NOT valid +* bit 11-30: set to 0 +* bit 0-10: 11-bit CAN-ID + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sub-indexes 1 and above: +* Value 0x00: on error change to NMT state Pre-operational (only if currently in NMT state Operational) +* Value 0x01: on error do nothing +* Value 0x02: on error change to NMT state Stopped + + + + + + + + + + + + + + + + + + + + + Sub-indexes 1 and 2: +* bit 11-31: set to 0 +* bit 0-10: 11-bit CAN-ID + + + + + + + + + + + + + + + + + + + + + * Sub-indexes 1 and 2: + * bit 31: If set, SDO does NOT exist / is NOT valid + * bit 30: If set, value is assigned dynamically + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Node-ID of the SDO client, 0x01 to 0x7F + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Sub-indexes 1 and 2: + * bit 31: If set, SDO does NOT exist / is NOT valid + * bit 30: If set, value is assigned dynamically + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Node-ID of the SDO server, 0x01 to 0x7F + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 11-30: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0-240: synchronous, processed after next reception of SYNC object + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Event timer in ms (0 = disabled) for deadline monitoring. + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * COB-ID used by RPDO: + * bit 31: If set, PDO does not exist / is not valid + * bit 30: If set, NO RTR is allowed on this PDO + * bit 11-29: set to 0 + * bit 0-10: 11-bit CAN-ID +* Transmission type: + * Value 0: synchronous (acyclic) + * Value 1-240: synchronous (cyclic every (1-240)-th sync) + * Value 241-253: not used + * Value 254: event-driven (manufacturer-specific) + * Value 255: event-driven (device profile and application profile specific) +* Inhibit time in multiple of 100µs, if the transmission type is set to 254 or 255 (0 = disabled). +* Event timer interval in ms, if the transmission type is set to 254 or 255 (0 = disabled). +* SYNC start value + * Value 0: Counter of the SYNC message shall not be processed. + * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Number of mapped application objects in PDO: + * Value 0: mapping is disabled. + * Value 1: sub-index 0x01 is valid. + * Value 2-8: sub-indexes 0x01 to (0x02 to 0x08) are valid. +* Application object 1-8: + * bit 16-31: index + * bit 8-15: sub-index + * bit 0-7: data length in bits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CANopen communication network profile + 1.1 + + + CommunicationNetwork + + 1 + 1 + CANopen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/IO.eds b/example/IO.eds deleted file mode 100644 index fd82270a..00000000 --- a/example/IO.eds +++ /dev/null @@ -1,2800 +0,0 @@ - -; CANopen Electronic Data Sheet -; File was automatically generated by CANopenNode Object Dictionary Editor -; See http://canopennode.sourceforge.net/ - - -[FileInfo] -FileName=IO Example -FileVersion=- -FileRevision=0 -EDSVersion=4.0 -Description=Open Source CANopen implementation -CreationTime=17:24:43 -CreationDate=2016-03-25 -CreatedBy=JP - - -[DeviceInfo] -VendorName=CANopenNode -VendorNumber=0 -ProductName=CANopenNode -ProductNumber=0 -RevisionNumber=0 -OrderCode=0 -BaudRate_10=1 -BaudRate_20=1 -BaudRate_50=1 -BaudRate_125=1 -BaudRate_250=1 -BaudRate_500=1 -BaudRate_800=1 -BaudRate_1000=1 -SimpleBootUpMaster=0 -SimpleBootUpSlave=1 -Granularity=8 -DynamicChannelsSupported=0 -GroupMessaging=0 -NrOfRXPDO=4 -NrOfTXPDO=4 -LSS_Supported=0 - - -[Comments] -Lines=5 -Line1=EDS File for CANopen device -Line2=Open Source CANopen implementation -Line3=Stack Version: V3.00 -Line4=Generated by CANopenNode Object Dictionary Editor -line5=http://canopennode.sourceforge.net/ - - -[DummyUsage] -Dummy0001=0 -Dummy0002=1 -Dummy0003=1 -Dummy0004=1 -Dummy0005=1 -Dummy0006=1 -Dummy0007=1 - - -[MandatoryObjects] -SupportedObjects=3 -1=0x1000 -2=0x1001 -3=0x1018 - - -[OptionalObjects] -SupportedObjects=38 -1=0x1002 -2=0x1003 -3=0x1005 -4=0x1006 -5=0x1007 -6=0x1008 -7=0x1009 -8=0x100A -9=0x1010 -10=0x1011 -11=0x1014 -12=0x1015 -13=0x1016 -14=0x1017 -15=0x1019 -16=0x1029 -17=0x1200 -18=0x1400 -19=0x1401 -20=0x1402 -21=0x1403 -22=0x1600 -23=0x1601 -24=0x1602 -25=0x1603 -26=0x1800 -27=0x1801 -28=0x1802 -29=0x1803 -30=0x1A00 -31=0x1A01 -32=0x1A02 -33=0x1A03 -34=0x1F80 -35=0x6000 -36=0x6200 -37=0x6401 -38=0x6411 - - -[ManufacturerObjects] -SupportedObjects=19 -1=0x2100 -2=0x2101 -3=0x2102 -4=0x2103 -5=0x2104 -6=0x2106 -7=0x2107 -8=0x2108 -9=0x2109 -10=0x2110 -11=0x2111 -12=0x2112 -13=0x2120 -14=0x2130 -15=0x2301 -16=0x2302 -17=0x2400 -18=0x2401 -19=0x2402 - -[1000] -ParameterName=Device type -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0x00000000 - -[1001] -ParameterName=Error register -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[1002] -ParameterName=Manufacturer status register -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[1003] -ParameterName=Pre-defined error field -ObjectType=8 -SubNumber=9 - -[1003sub0] -ParameterName=Number of errors -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1003sub1] -ParameterName=Standard error field -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[1003sub2] -ParameterName=Standard error field -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[1003sub3] -ParameterName=Standard error field -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[1003sub4] -ParameterName=Standard error field -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[1003sub5] -ParameterName=Standard error field -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[1003sub6] -ParameterName=Standard error field -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[1003sub7] -ParameterName=Standard error field -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[1003sub8] -ParameterName=Standard error field -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[1005] -ParameterName=COB-ID SYNC message -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000080 - -[1006] -ParameterName=Communication cycle period -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1007] -ParameterName=Synchronous window length -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1008] -ParameterName=Manufacturer device name -ObjectType=7 -DataType=0x0009 -AccessType=const -PDOMapping=0 -DefaultValue=CANopenNode - -[1009] -ParameterName=Manufacturer hardware version -ObjectType=7 -DataType=0x0009 -AccessType=const -PDOMapping=0 -DefaultValue=3.00 - -[100A] -ParameterName=Manufacturer software version -ObjectType=7 -DataType=0x0009 -AccessType=const -PDOMapping=0 -DefaultValue=3.00 - -[1010] -ParameterName=Store parameters -ObjectType=8 -SubNumber=2 - -[1010sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=1 - -[1010sub1] -ParameterName=save all parameters -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000003 - -[1011] -ParameterName=Restore default parameters -ObjectType=8 -SubNumber=2 - -[1011sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=1 - -[1011sub1] -ParameterName=restore all default parameters -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000001 - -[1014] -ParameterName=COB-ID EMCY -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=$NODEID+0x80 - -[1015] -ParameterName=inhibit time EMCY -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=100 - -[1016] -ParameterName=Consumer heartbeat time -ObjectType=8 -SubNumber=5 - -[1016sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=4 - -[1016sub1] -ParameterName=Consumer heartbeat time -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1016sub2] -ParameterName=Consumer heartbeat time -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1016sub3] -ParameterName=Consumer heartbeat time -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1016sub4] -ParameterName=Consumer heartbeat time -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1017] -ParameterName=Producer heartbeat time -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=1000 - -[1018] -ParameterName=Identity -ObjectType=9 -SubNumber=5 - -[1018sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=4 - -[1018sub1] -ParameterName=Vendor-ID -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0x00000000 - -[1018sub2] -ParameterName=Product code -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0x00000000 - -[1018sub3] -ParameterName=Revision number -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0x00000000 - -[1018sub4] -ParameterName=Serial number -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0x00000000 - -[1019] -ParameterName=Synchronous counter overflow value -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1029] -ParameterName=Error behavior -ObjectType=8 -SubNumber=7 - -[1029sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=6 - -[1029sub1] -ParameterName=Communication -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00 - -[1029sub2] -ParameterName=Communication other -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00 - -[1029sub3] -ParameterName=Communication passive -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0x01 - -[1029sub4] -ParameterName=Generic -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00 - -[1029sub5] -ParameterName=Device profile -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00 - -[1029sub6] -ParameterName=Manufacturer specific -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00 - -[1200] -ParameterName=SDO server parameter -ObjectType=9 -SubNumber=3 - -[1200sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=2 - -[1200sub1] -ParameterName=COB-ID client to server -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=$NODEID+0x600 - -[1200sub2] -ParameterName=COB-ID server to client -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=$NODEID+0x580 - -[1400] -ParameterName=RPDO communication parameter -ObjectType=9 -SubNumber=3 - -[1400sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=2 - -[1400sub1] -ParameterName=COB-ID used by RPDO -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=$NODEID+0x200 - -[1400sub2] -ParameterName=transmission type -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=255 - -[1401] -ParameterName=RPDO communication parameter -ObjectType=9 -SubNumber=3 - -[1401sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=2 - -[1401sub1] -ParameterName=COB-ID used by RPDO -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=$NODEID+0x300 - -[1401sub2] -ParameterName=transmission type -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=254 - -[1402] -ParameterName=RPDO communication parameter -ObjectType=9 -SubNumber=3 - -[1402sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=2 - -[1402sub1] -ParameterName=COB-ID used by RPDO -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=$NODEID+0x400 - -[1402sub2] -ParameterName=transmission type -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=254 - -[1403] -ParameterName=RPDO communication parameter -ObjectType=9 -SubNumber=3 - -[1403sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=2 - -[1403sub1] -ParameterName=COB-ID used by RPDO -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=$NODEID+0x500 - -[1403sub2] -ParameterName=transmission type -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=254 - -[1600] -ParameterName=RPDO mapping parameter -ObjectType=9 -SubNumber=9 - -[1600sub0] -ParameterName=Number of mapped objects -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=2 - -[1600sub1] -ParameterName=mapped object 1 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x62000108 - -[1600sub2] -ParameterName=mapped object 2 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x62000208 - -[1600sub3] -ParameterName=mapped object 3 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1600sub4] -ParameterName=mapped object 4 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1600sub5] -ParameterName=mapped object 5 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1600sub6] -ParameterName=mapped object 6 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1600sub7] -ParameterName=mapped object 7 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1600sub8] -ParameterName=mapped object 8 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1601] -ParameterName=RPDO mapping parameter -ObjectType=9 -SubNumber=9 - -[1601sub0] -ParameterName=Number of mapped objects -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1601sub1] -ParameterName=mapped object 1 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1601sub2] -ParameterName=mapped object 2 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1601sub3] -ParameterName=mapped object 3 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1601sub4] -ParameterName=mapped object 4 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1601sub5] -ParameterName=mapped object 5 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1601sub6] -ParameterName=mapped object 6 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1601sub7] -ParameterName=mapped object 7 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1601sub8] -ParameterName=mapped object 8 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1602] -ParameterName=RPDO mapping parameter -ObjectType=9 -SubNumber=9 - -[1602sub0] -ParameterName=Number of mapped objects -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1602sub1] -ParameterName=mapped object 1 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1602sub2] -ParameterName=mapped object 2 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1602sub3] -ParameterName=mapped object 3 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1602sub4] -ParameterName=mapped object 4 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1602sub5] -ParameterName=mapped object 5 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1602sub6] -ParameterName=mapped object 6 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1602sub7] -ParameterName=mapped object 7 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1602sub8] -ParameterName=mapped object 8 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1603] -ParameterName=RPDO mapping parameter -ObjectType=9 -SubNumber=9 - -[1603sub0] -ParameterName=Number of mapped objects -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1603sub1] -ParameterName=mapped object 1 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1603sub2] -ParameterName=mapped object 2 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1603sub3] -ParameterName=mapped object 3 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1603sub4] -ParameterName=mapped object 4 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1603sub5] -ParameterName=mapped object 5 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1603sub6] -ParameterName=mapped object 6 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1603sub7] -ParameterName=mapped object 7 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1603sub8] -ParameterName=mapped object 8 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1800] -ParameterName=TPDO communication parameter -ObjectType=9 -SubNumber=7 - -[1800sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=6 - -[1800sub1] -ParameterName=COB-ID used by TPDO -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=$NODEID+0x180 - -[1800sub2] -ParameterName=transmission type -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=255 - -[1800sub3] -ParameterName=inhibit time -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=100 - -[1800sub4] -ParameterName=compatibility entry -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1800sub5] -ParameterName=event timer -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1800sub6] -ParameterName=SYNC start value -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1801] -ParameterName=TPDO communication parameter -ObjectType=9 -SubNumber=7 - -[1801sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=6 - -[1801sub1] -ParameterName=COB-ID used by TPDO -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=$NODEID+0x280 - -[1801sub2] -ParameterName=transmission type -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=254 - -[1801sub3] -ParameterName=inhibit time -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1801sub4] -ParameterName=compatibility entry -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1801sub5] -ParameterName=event timer -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1801sub6] -ParameterName=SYNC start value -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1802] -ParameterName=TPDO communication parameter -ObjectType=9 -SubNumber=7 - -[1802sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=6 - -[1802sub1] -ParameterName=COB-ID used by TPDO -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=$NODEID+0x380 - -[1802sub2] -ParameterName=transmission type -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=254 - -[1802sub3] -ParameterName=inhibit time -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1802sub4] -ParameterName=compatibility entry -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1802sub5] -ParameterName=event timer -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1802sub6] -ParameterName=SYNC start value -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1803] -ParameterName=TPDO communication parameter -ObjectType=9 -SubNumber=7 - -[1803sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=6 - -[1803sub1] -ParameterName=COB-ID used by TPDO -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=$NODEID+0x480 - -[1803sub2] -ParameterName=transmission type -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=254 - -[1803sub3] -ParameterName=inhibit time -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1803sub4] -ParameterName=compatibility entry -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1803sub5] -ParameterName=event timer -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1803sub6] -ParameterName=SYNC start value -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1A00] -ParameterName=TPDO mapping parameter -ObjectType=9 -SubNumber=9 - -[1A00sub0] -ParameterName=Number of mapped objects -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=2 - -[1A00sub1] -ParameterName=mapped object 1 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x60000108 - -[1A00sub2] -ParameterName=mapped object 2 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x60000208 - -[1A00sub3] -ParameterName=mapped object 3 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A00sub4] -ParameterName=mapped object 4 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A00sub5] -ParameterName=mapped object 5 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A00sub6] -ParameterName=mapped object 6 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A00sub7] -ParameterName=mapped object 7 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A00sub8] -ParameterName=mapped object 8 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A01] -ParameterName=TPDO mapping parameter -ObjectType=9 -SubNumber=9 - -[1A01sub0] -ParameterName=Number of mapped objects -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1A01sub1] -ParameterName=mapped object 1 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A01sub2] -ParameterName=mapped object 2 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A01sub3] -ParameterName=mapped object 3 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A01sub4] -ParameterName=mapped object 4 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A01sub5] -ParameterName=mapped object 5 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A01sub6] -ParameterName=mapped object 6 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A01sub7] -ParameterName=mapped object 7 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A01sub8] -ParameterName=mapped object 8 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A02] -ParameterName=TPDO mapping parameter -ObjectType=9 -SubNumber=9 - -[1A02sub0] -ParameterName=Number of mapped objects -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1A02sub1] -ParameterName=mapped object 1 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A02sub2] -ParameterName=mapped object 2 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A02sub3] -ParameterName=mapped object 3 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A02sub4] -ParameterName=mapped object 4 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A02sub5] -ParameterName=mapped object 5 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A02sub6] -ParameterName=mapped object 6 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A02sub7] -ParameterName=mapped object 7 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A02sub8] -ParameterName=mapped object 8 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A03] -ParameterName=TPDO mapping parameter -ObjectType=9 -SubNumber=9 - -[1A03sub0] -ParameterName=Number of mapped objects -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[1A03sub1] -ParameterName=mapped object 1 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A03sub2] -ParameterName=mapped object 2 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A03sub3] -ParameterName=mapped object 3 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A03sub4] -ParameterName=mapped object 4 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A03sub5] -ParameterName=mapped object 5 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A03sub6] -ParameterName=mapped object 6 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A03sub7] -ParameterName=mapped object 7 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1A03sub8] -ParameterName=mapped object 8 -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[1F80] -ParameterName=NMT startup -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[2100] -ParameterName=Error status bits -ObjectType=7 -DataType=0x000A -AccessType=ro -PDOMapping=1 -DefaultValue=00000000000000000000 - -[2101] -ParameterName=CAN node ID -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0x30 - -[2102] -ParameterName=CAN bit rate -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=250 - -[2103] -ParameterName=SYNC counter -ObjectType=7 -DataType=0x0006 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2104] -ParameterName=SYNC time -ObjectType=7 -DataType=0x0006 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[2106] -ParameterName=Power-on counter -ObjectType=7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[2107] -ParameterName=Performance -ObjectType=8 -SubNumber=6 - -[2107sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=5 - -[2107sub1] -ParameterName=cycles per second -ObjectType=7 -DataType=0x0006 -AccessType=rww -PDOMapping=1 -DefaultValue=1000 - -[2107sub2] -ParameterName=timer cycle time -ObjectType=7 -DataType=0x0006 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2107sub3] -ParameterName=timer cycle max time -ObjectType=7 -DataType=0x0006 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2107sub4] -ParameterName=main cycle time -ObjectType=7 -DataType=0x0006 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2107sub5] -ParameterName=main cycle max time -ObjectType=7 -DataType=0x0006 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2108] -ParameterName=Temperature -ObjectType=8 -SubNumber=2 - -[2108sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=1 - -[2108sub1] -ParameterName=main PCB -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[2109] -ParameterName=Voltage -ObjectType=8 -SubNumber=2 - -[2109sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=1 - -[2109sub1] -ParameterName=main PCB supply -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[2110] -ParameterName=Variable Int32 -ObjectType=8 -SubNumber=17 - -[2110sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=16 - -[2110sub1] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub2] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub3] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub4] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub5] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub6] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub7] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub8] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub9] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110subA] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110subB] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110subC] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110subD] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110subE] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110subF] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2110sub10] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111] -ParameterName=Variable ROM Int32 -ObjectType=8 -SubNumber=17 - -[2111sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=16 - -[2111sub1] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=1 - -[2111sub2] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111sub3] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111sub4] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111sub5] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111sub6] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111sub7] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111sub8] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111sub9] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111subA] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111subB] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111subC] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111subD] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111subE] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111subF] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2111sub10] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112] -ParameterName=Variable NV Int32 -ObjectType=8 -SubNumber=17 - -[2112sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=16 - -[2112sub1] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=1 - -[2112sub2] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112sub3] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112sub4] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112sub5] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112sub6] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112sub7] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112sub8] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112sub9] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112subA] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112subB] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112subC] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112subD] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112subE] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112subF] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2112sub10] -ParameterName=int32 -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2120] -ParameterName=test var -ObjectType=9 -SubNumber=6 - -[2120sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=5 - -[2120sub1] -ParameterName=I64 -ObjectType=7 -DataType=0x0015 -AccessType=rww -PDOMapping=1 -DefaultValue=0x1234567890ABCDEFLL - -[2120sub2] -ParameterName=U64 -ObjectType=7 -DataType=0x001B -AccessType=rww -PDOMapping=1 -DefaultValue=0x234567890ABCDEF1LL - -[2120sub3] -ParameterName=R32 -ObjectType=7 -DataType=0x0008 -AccessType=rww -PDOMapping=1 -DefaultValue=12.345 - -[2120sub4] -ParameterName=R64 -ObjectType=7 -DataType=0x0011 -AccessType=rww -PDOMapping=1 -DefaultValue=456.789 - -[2120sub5] -ParameterName=domain -ObjectType=7 -DataType=0x000F -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2130] -ParameterName=Time -ObjectType=9 -SubNumber=4 - -[2130sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=3 - -[2130sub1] -ParameterName=String -ObjectType=7 -DataType=0x0009 -AccessType=ro -PDOMapping=0 -DefaultValue=- - -[2130sub2] -ParameterName=Epoch time base ms -ObjectType=7 -DataType=0x001B -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2130sub3] -ParameterName=Epoch time offset ms -ObjectType=7 -DataType=0x0007 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2301] -ParameterName=Trace config -ObjectType=9 -SubNumber=9 - -[2301sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=8 - -[2301sub1] -ParameterName=Size -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=100 - -[2301sub2] -ParameterName=Axis no -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=1 - -[2301sub3] -ParameterName=Name -ObjectType=7 -DataType=0x0009 -AccessType=rw -PDOMapping=0 -DefaultValue=Trace1 - -[2301sub4] -ParameterName=Color -ObjectType=7 -DataType=0x0009 -AccessType=rw -PDOMapping=0 -DefaultValue=red - -[2301sub5] -ParameterName=Map -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x60000108 - -[2301sub6] -ParameterName=Format -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=1 - -[2301sub7] -ParameterName=Trigger -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2301sub8] -ParameterName=Threshold -ObjectType=7 -DataType=0x0004 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2302] -ParameterName=Trace config -ObjectType=9 -SubNumber=9 - -[2302sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=8 - -[2302sub1] -ParameterName=Size -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2302sub2] -ParameterName=Axis no -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2302sub3] -ParameterName=Name -ObjectType=7 -DataType=0x0009 -AccessType=rw -PDOMapping=0 -DefaultValue=Trace2 - -[2302sub4] -ParameterName=Color -ObjectType=7 -DataType=0x0009 -AccessType=rw -PDOMapping=0 -DefaultValue=green - -[2302sub5] -ParameterName=Map -ObjectType=7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 -DefaultValue=0x00000000 - -[2302sub6] -ParameterName=Format -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2302sub7] -ParameterName=Trigger -ObjectType=7 -DataType=0x0005 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2302sub8] -ParameterName=Threshold -ObjectType=7 -DataType=0x0004 -AccessType=rw -PDOMapping=0 -DefaultValue=0 - -[2400] -ParameterName=Trace enable -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2401] -ParameterName=Trace -ObjectType=9 -SubNumber=7 - -[2401sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=6 - -[2401sub1] -ParameterName=Size -ObjectType=7 -DataType=0x0007 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2401sub2] -ParameterName=Value -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2401sub3] -ParameterName=Min -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2401sub4] -ParameterName=Max -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2401sub5] -ParameterName=Plot -ObjectType=7 -DataType=0x000F -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[2401sub6] -ParameterName=Trigger time -ObjectType=7 -DataType=0x0007 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2402] -ParameterName=Trace -ObjectType=9 -SubNumber=7 - -[2402sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=6 - -[2402sub1] -ParameterName=Size -ObjectType=7 -DataType=0x0007 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2402sub2] -ParameterName=Value -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2402sub3] -ParameterName=Min -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2402sub4] -ParameterName=Max -ObjectType=7 -DataType=0x0004 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[2402sub5] -ParameterName=Plot -ObjectType=7 -DataType=0x000F -AccessType=ro -PDOMapping=0 -DefaultValue=0 - -[2402sub6] -ParameterName=Trigger time -ObjectType=7 -DataType=0x0007 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[6000] -ParameterName=Read input 8 bit -ObjectType=8 -SubNumber=9 - -[6000sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=8 - -[6000sub1] -ParameterName=Input -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0x00 - -[6000sub2] -ParameterName=Input -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0x00 - -[6000sub3] -ParameterName=Input -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0x00 - -[6000sub4] -ParameterName=Input -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0x00 - -[6000sub5] -ParameterName=Input -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0x00 - -[6000sub6] -ParameterName=Input -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0x00 - -[6000sub7] -ParameterName=Input -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0x00 - -[6000sub8] -ParameterName=Input -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 -DefaultValue=0x00 - -[6200] -ParameterName=Write output 8 bit -ObjectType=8 -SubNumber=9 - -[6200sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=8 - -[6200sub1] -ParameterName=Output -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0x00 - -[6200sub2] -ParameterName=Output -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0x00 - -[6200sub3] -ParameterName=Output -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0x00 - -[6200sub4] -ParameterName=Output -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0x00 - -[6200sub5] -ParameterName=Output -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0x00 - -[6200sub6] -ParameterName=Output -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0x00 - -[6200sub7] -ParameterName=Output -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0x00 - -[6200sub8] -ParameterName=Output -ObjectType=7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 -DefaultValue=0x00 - -[6401] -ParameterName=Read analogue input 16 bit -ObjectType=8 -SubNumber=13 - -[6401sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=12 - -[6401sub1] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401sub2] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401sub3] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401sub4] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401sub5] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401sub6] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401sub7] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401sub8] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401sub9] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401subA] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401subB] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6401subC] -ParameterName=Input -ObjectType=7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 -DefaultValue=0 - -[6411] -ParameterName=Write analogue output 16 bit -ObjectType=8 -SubNumber=9 - -[6411sub0] -ParameterName=max sub-index -ObjectType=7 -DataType=0x0005 -AccessType=ro -PDOMapping=0 -DefaultValue=8 - -[6411sub1] -ParameterName=Output -ObjectType=7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[6411sub2] -ParameterName=Output -ObjectType=7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[6411sub3] -ParameterName=Output -ObjectType=7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[6411sub4] -ParameterName=Output -ObjectType=7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[6411sub5] -ParameterName=Output -ObjectType=7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[6411sub6] -ParameterName=Output -ObjectType=7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[6411sub7] -ParameterName=Output -ObjectType=7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - -[6411sub8] -ParameterName=Output -ObjectType=7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 -DefaultValue=0 - - diff --git a/example/IO.html b/example/IO.html deleted file mode 100644 index ec22b45b..00000000 --- a/example/IO.html +++ /dev/null @@ -1,6627 +0,0 @@ - - - - IO Example - CANopenNode - - - - - - - -

CANopen object dictionary for IO Example

-
    - - - - -
-
    -
  • -

    1000 - Device type

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED32ronono0x00000000 -
    -
    -

    en: Device type

    -
    - bit 0-15: Device profile number -
    - bit 16-31: Additional information -
    -
    -
  • -
  • -

    1001 - Error register

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarRAMUNSIGNED8rooptionalno0 -
    -
    -

    en: Error register

    -
    - bit 0: generic error -
    - bit 1: current -
    - bit 2: voltage -
    - bit 3: temperature -
    - bit 4: communication error (overrun, error state) -
    - bit 5: device profile specific -
    - bit 6: Reserved (always 0) -
    - bit 7: manufacturer specific -
    -
    -
  • -
  • -

    1002 - Manufacturer status register

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarRAMUNSIGNED32rooptionalno0 -
    -
    -

    en: Manufacturer status register

    -
    bit 0-31: Not used by stack (available for user)
    -
    -
  • -
  • -

    1003 - Pre-defined error field

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array9RAMUNSIGNED32ronono
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00Number of errors0 -
    01Standard error field0 -
    02Standard error field0 -
    03Standard error field0 -
    04Standard error field0 -
    05Standard error field0 -
    06Standard error field0 -
    07Standard error field0 -
    08Standard error field0 -
    -
    -

    en: Pre-defined error field

    -
    - Number of Errors -
    - bit 0-7: Zero can be written to erase error history -
    -
    - Standard Error Field -
    - bit 0-15: Error code as transmited in the Emergency object -
    - bit 16-31: Manufacturer specific additional information -
    -
    -
  • -
  • -

    1005 - COB-ID SYNC message

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED32rwnono0x00000080 -
    -
    -

    en: COB-ID SYNC message

    -
    - bit 0-10: COB-ID for SYNC object -
    - bit 11-29: set to 0 -
    - bit 30: 1(0) - node generates (does NOT generate) SYNC object -
    - bit 31: set to 0 -
    -
    -
  • -
  • -

    1006 - Communication cycle period

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED32rwnono0 -
    -
    -

    en: Communication cycle period

    -
    bit 0-31: period of SYNC transmission in µs (0 = no transmission, no checking)
    -
    -
  • -
  • -

    1007 - Synchronous window length

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED32rwnono0 -
    -
    -

    en: Synchronous window length

    -
    bit 0-31: window leghth after SYNC when PDOS must be transmited in µs, (0 = not used)
    -
    -
  • -
  • -

    1008 - Manufacturer device name

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMVISIBLE_STRINGconstnonoCANopenNode -
    -
    -

    en: Manufacturer device name

    -
    Name of the manufacturer as string
    -
    -
  • -
  • -

    1009 - Manufacturer hardware version

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMVISIBLE_STRINGconstnono3.00 -
    -
    -

    en: Manufacturer hardware version

    -
    Name of the hardware version as string
    -
    -
  • -
  • -

    100A - Manufacturer software version

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMVISIBLE_STRINGconstnono3.00 -
    -
    -

    en: Manufacturer software version

    -
    Name of the software version as string.
    -
    -
  • -
  • -

    1010 - Store parameters

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array2RAMUNSIGNED32rwnono
    -
    - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index1 -
    01save all parameters0x00000003 -
    -
    -

    en: Store parameters

    -
    Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) into this location stores all ROM variables into EEPROM.
    -
    -
  • -
  • -

    1011 - Restore default parameters

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array2RAMUNSIGNED32rwnono
    -
    - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index1 -
    01restore all default parameters0x00000001 -
    -
    -

    en: Restore default parameters

    -
    Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) into this location restores all ROM and EEPROM variables after reset. (After reset read form EEPROM is not performed, so default values are used.)
    -
    -
  • -
  • -

    1014 - COB-ID EMCY

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED32ronono$NODEID+0x80 -
    -
    -

    en: COB-ID emergency message

    -
    - bit 0-10: COB-ID -
    - bit 11-30: set to 0 for 11 bit COB-ID -
    - bit 31: 0(1) - node uses (does NOT use) Emergency object -
    -
    -
  • -
  • -

    1015 - inhibit time EMCY

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED16rwnono100 -
    -
    -

    en: inhibit time emergency message

    -
    bit 0-15: Inhibit time of emergency message in 100µs
    -
    -
  • -
  • -

    1016 - Consumer heartbeat time

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array5ROMUNSIGNED32rwnono
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index4 -
    01Consumer heartbeat time0x00000000 -
    02Consumer heartbeat time0x00000000 -
    03Consumer heartbeat time0x00000000 -
    04Consumer heartbeat time0x00000000 -
    -
    -

    en: Consumer heartbeat time

    -
    - max sub-index -
    -
    - Consumer Heartbeat Time -
    - bit 0-15: Heartbeat consumer time in ms (0 = node is not monitored) -
    - bit 16-23: Node ID -
    - bit 24-31: set to 0 -
    -
    -
  • -
  • -

    1017 - Producer heartbeat time

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED16rwnono1000 -
    -
    -

    en: Producer heartbeat time

    -
    bit 0-15: Heartbeat producer time in ms (0 = disable transmission)
    -
    -
  • -
  • -

    1018 - Identity

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record5ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono4 -
    01Vendor-IDUNSIGNED32ronono0x00000000 -
    02Product codeUNSIGNED32ronono0x00000000 -
    03Revision numberUNSIGNED32ronono0x00000000 -
    04Serial numberUNSIGNED32ronono0x00000000 -
    -
    -

    en: Identity

    -
    - max sub-index -
    -
    - Vendor-ID -
    - bit 0-31: Assigned by CiA -
    -
    - Product code -
    - bit 0-31: Manufacturer specific -
    -
    - Revision number -
    - bit 0-15: Minor revision num. (CANopen behavior has not changed) -
    - bit 16-31: Major revision number (CANopen behavior has changed) -
    -
    - Serial number -
    - bit 0-31: Manufacturer specific -
    -
    -
  • -
  • -

    1019 - Synchronous counter overflow value

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED8rwnono0 -
    -
    -

    en: Synchronous counter overflow value

    -
    - If value is zero, then SYNC message is transmitted with data length 0. -
    -
    - If Value is from 2 to 240, then SYNC message has one data byte, which contains the counter. -
    -
    - Other values are reserved. -
    -
    -
  • -
  • -

    1029 - Error behavior

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array7ROMUNSIGNED8rwnono
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index6 -
    01Communication0x00 -
    02Communication other0x00 -
    03Communication passive0x01 -
    04Generic0x00 -
    05Device profile0x00 -
    06Manufacturer specific0x00 -
    -
    -

    en: Error behavior

    -
    - If error is detected and operating NMT state is NMT operational, this object defines behavior of the device. -
    -
    - Value definition for all subindexes: -
    - 0x00 - if operational, switch to NMT pre-operational -
    - 0x01 - do nothing -
    - 0x02 - switch to NMT stopped -
    -
    - 01 - Communication error - bus off or Heartbeat consumer error. -
    - 02 - Communication other error (critical errors - see 'Error status bits') except CAN bus passive but including bus off or Heartbeat consumer. -
    - 03 - Communication passive - any communication error including CAN bus passive. -
    - 04 - Generic error (critical errors - see 'Error status bits'). -
    - 05 - Device profile error - bit 5 in error register is set. -
    - 06 - Manufacturer specific error - bit 7 in error register is set. -
    -
    -
  • -
  • -

    1200 - SDO server parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record3ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono2 -
    01COB-ID client to serverUNSIGNED32ronono$NODEID+0x600 -
    02COB-ID server to clientUNSIGNED32ronono$NODEID+0x580 -
    -
    -

    en: SDO server parameter

    -
    - 0x1200 SDO server parameter -
    - max sub-index -
    -
    - COB-ID client to server (Receive SDO) -
    - bit 0-31: 0x00000600 + Node ID -
    -
    - COB-ID server to client (Transmit SDO) -
    - bit 0-31: 0x00000580 + Node ID -
    -
    -
    -
    - 0x1201 - 0x127F SDO server parameter -
    - max sub-index -
    -
    - COB-ID client to server (Receive SDO) -
    - bit 0-10: COB_ID -
    - bit 11-30: Set to 0 -
    - bit 31*: 0(1) - node uses (does NOT use) SDO -
    -
    - COB-ID server to client (Transmit SDO) -
    - bit 0-31: same as previous -
    -
    - Node-ID of the SDO client -
    - bit 0-7: Node ID (optional) -
    -
    -
  • -
  • -

    1400 - RPDO communication parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record3ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono2 -
    01COB-ID used by RPDOUNSIGNED32rwnono$NODEID+0x200 -
    02transmission typeUNSIGNED8rwnono255 -
    -
    -

    en: RPDO communication parameter

    -
    - 0x1400 - 0x15FF RPDO communication parameter -
    - max sub-index -
    -
    - COB-ID -
    - bit 0-10: COB-ID for PDO, to change it bit 31 must be set -
    - bit 11-29: set to 0 for 11 bit COB-ID -
    - bit 30: 0(1) - rtr are allowed (are NOT allowed) for PDO -
    - bit 31: 0(1) - node uses (does NOT use) PDO -
    -
    - Transmission type -
    - value = 0-240: reciving is synchronous, process after next reception of SYNC object -
    - value = 241-253: not used -
    - value = 254: manufacturer specific -
    - value = 255: asynchronous -
    -
    -
  • -
  • -

    1401 - RPDO communication parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record3ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono2 -
    01COB-ID used by RPDOUNSIGNED32rwnono$NODEID+0x300 -
    02transmission typeUNSIGNED8rwnono254 -
    -
    -

    en: RPDO communication parameter

    -
    0x1400 - 0x15FF RPDO communication parameter (see description for 0x1400)
    -
    -
  • -
  • -

    1402 - RPDO communication parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record3ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono2 -
    01COB-ID used by RPDOUNSIGNED32rwnono$NODEID+0x400 -
    02transmission typeUNSIGNED8rwnono254 -
    -
    -

    en: RPDO communication parameter

    -
    0x1400 - 0x15FF RPDO communication parameter (see description for 0x1400)
    -
    -
  • -
  • -

    1403 - RPDO communication parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record3ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono2 -
    01COB-ID used by RPDOUNSIGNED32rwnono$NODEID+0x500 -
    02transmission typeUNSIGNED8rwnono254 -
    -
    -

    en: RPDO communication parameter

    -
    0x1400 - 0x15FF RPDO communication parameter (see description for 0x1400)
    -
    -
  • -
  • -

    1600 - RPDO mapping parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00Number of mapped objectsUNSIGNED8rwnono2 -
    01mapped object 1UNSIGNED32rwnono0x62000108 -
    02mapped object 2UNSIGNED32rwnono0x62000208 -
    03mapped object 3UNSIGNED32rwnono0x00000000 -
    04mapped object 4UNSIGNED32rwnono0x00000000 -
    05mapped object 5UNSIGNED32rwnono0x00000000 -
    06mapped object 6UNSIGNED32rwnono0x00000000 -
    07mapped object 7UNSIGNED32rwnono0x00000000 -
    08mapped object 8UNSIGNED32rwnono0x00000000 -
    -
    -

    en: RPDO mapping parameter

    -
    - 0x1600 - 0x17FF RPDO mapping parameter (To change mapping, 'Number of mapped objects' must be set to 0) -
    - Number of mapped objects -
    -
    - mapped object (subindex 1...8) -
    - bit 0-7: data length in bits -
    - bit 8-15: subindex from OD -
    - bit 16-31: index from OD -
    -
    -
  • -
  • -

    1601 - RPDO mapping parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00Number of mapped objectsUNSIGNED8rwnono0 -
    01mapped object 1UNSIGNED32rwnono0x00000000 -
    02mapped object 2UNSIGNED32rwnono0x00000000 -
    03mapped object 3UNSIGNED32rwnono0x00000000 -
    04mapped object 4UNSIGNED32rwnono0x00000000 -
    05mapped object 5UNSIGNED32rwnono0x00000000 -
    06mapped object 6UNSIGNED32rwnono0x00000000 -
    07mapped object 7UNSIGNED32rwnono0x00000000 -
    08mapped object 8UNSIGNED32rwnono0x00000000 -
    -
    -

    en: RPDO mapping parameter

    -
    0x1600 - 0x17FF RPDO mapping parameter (see description for 0x1600)
    -
    -
  • -
  • -

    1602 - RPDO mapping parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00Number of mapped objectsUNSIGNED8rwnono0 -
    01mapped object 1UNSIGNED32rwnono0x00000000 -
    02mapped object 2UNSIGNED32rwnono0x00000000 -
    03mapped object 3UNSIGNED32rwnono0x00000000 -
    04mapped object 4UNSIGNED32rwnono0x00000000 -
    05mapped object 5UNSIGNED32rwnono0x00000000 -
    06mapped object 6UNSIGNED32rwnono0x00000000 -
    07mapped object 7UNSIGNED32rwnono0x00000000 -
    08mapped object 8UNSIGNED32rwnono0x00000000 -
    -
    -

    en: RPDO mapping parameter

    -
    0x1600 - 0x17FF RPDO mapping parameter (see description for 0x1600)
    -
    -
  • -
  • -

    1603 - RPDO mapping parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00Number of mapped objectsUNSIGNED8rwnono0 -
    01mapped object 1UNSIGNED32rwnono0x00000000 -
    02mapped object 2UNSIGNED32rwnono0x00000000 -
    03mapped object 3UNSIGNED32rwnono0x00000000 -
    04mapped object 4UNSIGNED32rwnono0x00000000 -
    05mapped object 5UNSIGNED32rwnono0x00000000 -
    06mapped object 6UNSIGNED32rwnono0x00000000 -
    07mapped object 7UNSIGNED32rwnono0x00000000 -
    08mapped object 8UNSIGNED32rwnono0x00000000 -
    -
    -

    en: RPDO mapping parameter

    -
    0x1600 - 0x17FF RPDO mapping parameter (see description for 0x1600)
    -
    -
  • -
  • -

    1800 - TPDO communication parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record7ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono6 -
    01COB-ID used by TPDOUNSIGNED32rwnono$NODEID+0x180 -
    02transmission typeUNSIGNED8rwnono255 -
    03inhibit timeUNSIGNED16rwnono100 -
    04compatibility entryUNSIGNED8rwnono0 -
    05event timerUNSIGNED16rwnono0 -
    06SYNC start valueUNSIGNED8rwnono0 -
    -
    -

    en: TPDO communication parameter

    -
    - 0x1800 - 0x19FF TPDO communication parameter -
    - max sub-index -
    -
    - COB-ID -
    - bit 0-10: COB-ID for PDO, to change it bit 31 must be set -
    - bit 11-29: set to 0 for 11 bit COB-ID -
    - bit 30: 0(1) - rtr are allowed (are NOT allowed) for PDO -
    - bit 31: 0(1) - node uses (does NOT use) PDO -
    -
    - Transmission type -
    - value = 0: transmiting is synchronous, specification in device profile -
    - value = 1-240: transmiting is synchronous after every N-th SYNC object -
    - value = 241-251: not used -
    - value = 252-253: Transmited only on reception of Remote Transmission Request -
    - value = 254: manufacturer specific -
    - value = 255: asinchronous, specification in device profile -
    -
    - inhibit time -
    - bit 0-15: Minimum time between transmissions of the PDO in 100µs. Zero disables functionality. -
    -
    - compatibility entry -
    - bit 0-7: Not used. -
    -
    - event timer -
    - bit 0-15: Time between periodic transmissions of the PDO in ms. Zero disables functionality. -
    -
    - SYNC start value -
    - value = 0: Counter of the SYNC message shall not be processed. -
    - value = 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. -
    -
    -
  • -
  • -

    1801 - TPDO communication parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record7ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono6 -
    01COB-ID used by TPDOUNSIGNED32rwnono$NODEID+0x280 -
    02transmission typeUNSIGNED8rwnono254 -
    03inhibit timeUNSIGNED16rwnono0 -
    04compatibility entryUNSIGNED8rwnono0 -
    05event timerUNSIGNED16rwnono0 -
    06SYNC start valueUNSIGNED8rwnono0 -
    -
    -

    en: TPDO communication parameter

    -
    0x1800 - 0x19FF TPDO communication parameter (see description for 0x1800)
    -
    -
  • -
  • -

    1802 - TPDO communication parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record7ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono6 -
    01COB-ID used by TPDOUNSIGNED32rwnono$NODEID+0x380 -
    02transmission typeUNSIGNED8rwnono254 -
    03inhibit timeUNSIGNED16rwnono0 -
    04compatibility entryUNSIGNED8rwnono0 -
    05event timerUNSIGNED16rwnono0 -
    06SYNC start valueUNSIGNED8rwnono0 -
    -
    -

    en: TPDO communication parameter

    -
    0x1800 - 0x19FF TPDO communication parameter (see description for 0x1800)
    -
    -
  • -
  • -

    1803 - TPDO communication parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record7ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono6 -
    01COB-ID used by TPDOUNSIGNED32rwnono$NODEID+0x480 -
    02transmission typeUNSIGNED8rwnono254 -
    03inhibit timeUNSIGNED16rwnono0 -
    04compatibility entryUNSIGNED8rwnono0 -
    05event timerUNSIGNED16rwnono0 -
    06SYNC start valueUNSIGNED8rwnono0 -
    -
    -

    en: TPDO communication parameter

    -
    0x1800 - 0x19FF TPDO communication parameter (see description for 0x1800)
    -
    -
  • -
  • -

    1A00 - TPDO mapping parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00Number of mapped objectsUNSIGNED8rwnono2 -
    01mapped object 1UNSIGNED32rwnono0x60000108 -
    02mapped object 2UNSIGNED32rwnono0x60000208 -
    03mapped object 3UNSIGNED32rwnono0x00000000 -
    04mapped object 4UNSIGNED32rwnono0x00000000 -
    05mapped object 5UNSIGNED32rwnono0x00000000 -
    06mapped object 6UNSIGNED32rwnono0x00000000 -
    07mapped object 7UNSIGNED32rwnono0x00000000 -
    08mapped object 8UNSIGNED32rwnono0x00000000 -
    -
    -

    en: TPDO mapping parameter

    -
    - 0x1A00 - 0x1BFF TPDO mapping parameter. (To change mapping, 'Number of mapped objects' must be set to 0). -
    - Number of mapped objects -
    -
    - mapped object (subindex 1...8) -
    - bit 0-7: data length in bits -
    - bit 8-15: subindex from OD -
    - bit 16-31: index from OD -
    -
    -
  • -
  • -

    1A01 - TPDO mapping parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00Number of mapped objectsUNSIGNED8rwnono0 -
    01mapped object 1UNSIGNED32rwnono0x00000000 -
    02mapped object 2UNSIGNED32rwnono0x00000000 -
    03mapped object 3UNSIGNED32rwnono0x00000000 -
    04mapped object 4UNSIGNED32rwnono0x00000000 -
    05mapped object 5UNSIGNED32rwnono0x00000000 -
    06mapped object 6UNSIGNED32rwnono0x00000000 -
    07mapped object 7UNSIGNED32rwnono0x00000000 -
    08mapped object 8UNSIGNED32rwnono0x00000000 -
    -
    -

    en: TPDO mapping parameter

    -
    0x1A00 - 0x1BFF TPDO mapping parameter (see description for 0x1A00)
    -
    -
  • -
  • -

    1A02 - TPDO mapping parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00Number of mapped objectsUNSIGNED8rwnono0 -
    01mapped object 1UNSIGNED32rwnono0x00000000 -
    02mapped object 2UNSIGNED32rwnono0x00000000 -
    03mapped object 3UNSIGNED32rwnono0x00000000 -
    04mapped object 4UNSIGNED32rwnono0x00000000 -
    05mapped object 5UNSIGNED32rwnono0x00000000 -
    06mapped object 6UNSIGNED32rwnono0x00000000 -
    07mapped object 7UNSIGNED32rwnono0x00000000 -
    08mapped object 8UNSIGNED32rwnono0x00000000 -
    -
    -

    en: TPDO mapping parameter

    -
    0x1A00 - 0x1BFF TPDO mapping parameter (see description for 0x1A00)
    -
    -
  • -
  • -

    1A03 - TPDO mapping parameter

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00Number of mapped objectsUNSIGNED8rwnono0 -
    01mapped object 1UNSIGNED32rwnono0x00000000 -
    02mapped object 2UNSIGNED32rwnono0x00000000 -
    03mapped object 3UNSIGNED32rwnono0x00000000 -
    04mapped object 4UNSIGNED32rwnono0x00000000 -
    05mapped object 5UNSIGNED32rwnono0x00000000 -
    06mapped object 6UNSIGNED32rwnono0x00000000 -
    07mapped object 7UNSIGNED32rwnono0x00000000 -
    08mapped object 8UNSIGNED32rwnono0x00000000 -
    -
    -

    en: TPDO mapping parameter

    -
    0x1A00 - 0x1BFF TPDO mapping parameter (see description for 0x1A00)
    -
    -
  • -
  • -

    1F80 - NMT startup

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED32rwnono0x00000000 -
    -
    -

    en: NMT Startup

    -
    - Only bit 2 is implemented. -
    -
    - bit 0: 0(1) - device is not (is) NMT master -
    - bit 1: 0(1) - if bit3=0, start explicitly assigned (all) nodes -
    - bit 2: 0(1) - automaticaly enter (DO NOT automaticaly enter) the operational state on bootup -
    - bit 3: 0(1) - NMT master may (may not) start nodes automatically -
    - bit 4: 0(1) - if monitored node fails heartbeat handle that (all) node(s) -
    - bit 5: 0(1) - flying master process not (yes) supported -
    - bit 6: 0(1) - use bit 4 (ignore bit 4, stop all nodes) -
    - bit 7-31: reserved, set to 0 -
    -
    -
  • -
  • -

    2100 - Error status bits

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarRAMOCTET_STRINGrooptionalno00 00 00 00 00 00 00 00 00 00 -
    -
    -

    en: Error Status Bits

    -
    - Error Status Bits indicates error conditions inside stack or inside application. Specific bit is set by CO_errorReport() function, when error occurs in program. It can be reset by CO_errorReset() function, if error is solved. Emergency message is sent on each change of any Error Status Bit. If critical bits are set, node will not be able to stay in operational state. For more information see file CO_Emergency.h. -
    -
    - Default error status bits are: -
    -
    - Communication or protocol errors from driver (informative): -
    - 00 - ERROR_NO_ERROR - Error Reset or No Error. -
    - 01 - ERROR_CAN_BUS_WARNING - CAN bus warning. -
    - 02 - ERROR_RXMSG_WRONG_LENGTH - Wrong data length of received CAN message. -
    - 03 - ERROR_RXMSG_OVERFLOW - Previous received CAN message wasn't processed yet. -
    - 04 - ERROR_RPDO_WRONG_LENGTH - Wrong data length of received PDO. -
    - 05 - ERROR_RPDO_OVERFLOW - Previous received PDO wasn't processed yet. -
    - 06 - ERROR_CAN_RX_BUS_PASSIVE - CAN receive bus is passive. -
    - 07 - ERROR_CAN_TX_BUS_PASSIVE - CAN transmit bus is passive. -
    -
    - Communication or protocol errors from driver (critical): -
    - 08 - ERROR_08_reserved - (reserved) -
    - 09 - ERROR_09_reserved - (reserved) -
    - 0A - ERROR_CAN_TX_BUS_OFF - CAN transmit bus is off. -
    - 0B - ERROR_CAN_RXB_OVERFLOW - CAN module receive buffer has overflowed. -
    - 0C - ERROR_CAN_TX_OVERFLOW - CAN transmit buffer has overflowed. -
    - 0D - ERROR_TPDO_OUTSIDE_WINDOW - TPDO is outside SYNC window. -
    - 0E - ERROR_CAN_CONFIGURATION_FAILED - Configuration of CAN module CAN failed (Rx or Tx). -
    - 0F - ERROR_0F_reserved - (reserved) -
    -
    - Communication or protocol errors (informative): -
    - 10 - ERROR_NMT_WRONG_COMMAND - Wrong NMT command received. -
    - 11 - ERROR_SYNC_EARLY - SYNC message was too early. -
    - 12 - ERROR_12_reserved - (reserved) -
    - 13 - ERROR_13_reserved - (reserved) -
    - 14 - ERROR_14_reserved - (reserved) -
    - 15 - ERROR_15_reserved - (reserved) -
    - 16 - ERROR_16_reserved - (reserved) -
    - 17 - ERROR_17_reserved - (reserved) -
    -
    - Communication or protocol errors (critical): -
    - 18 - ERROR_SYNC_TIME_OUT - SYNC message timeout. -
    - 19 - ERROR_SYNC_LENGTH - Unexpected SYNC data length -
    - 1A - ERROR_PDO_WRONG_MAPPING - Error with PDO mapping. -
    - 1B - ERROR_HEARTBEAT_CONSUMER - Heartbeat consumer timeout. -
    - 1C - ERROR_HEARTBEAT_CONSUMER_REMOTE_RESET - Heartbeat consumer detected remote node reset. -
    - 1D - ERROR_1D_reserved - (reserved) -
    - 1E - ERROR_1E_reserved - (reserved) -
    - 1F - ERROR_1F_reserved - (reserved) -
    -
    - Generic errors (informative): -
    - 20 - ERROR_20_reserved - (reserved) -
    - 21 - ERROR_21_reserved - (reserved) -
    - 22 - ERROR_22_reserved - (reserved) -
    - 23 - ERROR_23_reserved - (reserved) -
    - 24 - ERROR_24_reserved - (reserved) -
    - 25 - ERROR_25_reserved - (reserved) -
    - 26 - ERROR_26_reserved - (reserved) -
    - 27 - ERROR_27_reserved - (reserved) -
    -
    - Generic errors (critical): -
    - 28 - ERROR_WRONG_ERROR_REPORT - Wrong parameters to <CO_errorReport()> function. -
    - 29 - ERROR_ISR_TIMER_OVERFLOW - Timer task has overflowed. -
    - 2A - ERROR_MEMORY_ALLOCATION_ERROR - Unable to allocate memory for objects. -
    - 2B - ERROR_GENERIC_ERROR - Generic error, test usage. -
    - 2C - ERROR_MAIN_TIMER_OVERFLOW - Mainline function exceeded maximum execution time. -
    - 2D - ERROR_INTERNAL_STATE_APPL - Error in application software internal state. -
    - 2E - ERROR_2E_reserved - (reserved) -
    - 2F - ERROR_2F_reserved - (reserved) -
    -
    - Manufacturer specific errors: -
    - Manufacturer may define its own constants up to index 0xFF. Of course, he must then define large enough buffer for error status bits (up to 32 bytes). -
    -
    -
  • -
  • -

    2101 - CAN node ID

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED8rwnono0x30 -
    -
    -

    en: CAN Node ID

    -
    - CAN Node ID is CANopenNode specific variable. It sets node-ID for device on CANopen network. Node-ID can be set on other ways too, for example with DIP switches. More advanced solution is use of LSS. -
    -
    - Valid values are from 1 to 127: -
    -
    -
  • -
  • -

    2102 - CAN bit rate

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarROMUNSIGNED16rwnono250 -
    -
    -

    en: CAN Bit-Rate

    -
    - CAN Bit-Rate is CANopenNode specific variable. It sets CAN Bit-Rate for device on CANopen network. -
    -
    - Valid values are in [kbps]: -
    - 10, 20, 50, 125, 250, 500, 800, 1000 -
    -
    -
  • -
  • -

    2103 - SYNC counter

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarRAMUNSIGNED16rwnono0 -
    -
    -

    en: SYNC Counter

    -
    SYNC Counter is incremented each time, SYNC message is received or transmitted.
    -
    -
  • -
  • -

    2104 - SYNC time

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarRAMUNSIGNED16ronono0 -
    -
    -

    en: SYNC Time

    -
    SYNC Time is incremented each timer period and reset to zero, each time SYNC is received or transmitted.
    -
    -
  • -
  • -

    2106 - Power-on counter

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarEEPROMUNSIGNED32ronono0 -
    -
    -

    en: Power on Counter

    -
    Power on Counter counts total microcontroller resets in it's lifetime. Variable is an example of EEPROM usage.
    -
    -
  • -
  • -

    2107 - Performance

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array6RAMUNSIGNED16rwoptionalno
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index5 -
    01cycles per second1000 -
    02timer cycle time0 -
    03timer cycle max time0 -
    04main cycle time0 -
    05main cycle max time0 -
    -
    -

    en: Performance

    -
    - Internal performance of the microcontroller. -
    -
    - cycles per second - cycle frequency of internal timer. -
    - timer cycle time - current timer cycle time in percent of timer period. -
    - timer cycle max time - maximum timer cycle time in percent of timer period. -
    - main cycle time - current mainline function cycle time in percent of timer period. -
    - main cycle max time - maximum mainline function cycle time in percent of timer period. -
    -
    -
  • -
  • -

    2108 - Temperature

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array2RAMINTEGER16rooptionalno
    -
    - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index1 -
    01main PCB0 -
    -
    -

    en: Temperature

    -
    Current temperature on device in 0,1°C.
    -
    -
  • -
  • -

    2109 - Voltage

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array2RAMINTEGER16rooptionalno
    -
    - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index1 -
    01main PCB supply0 -
    -
    -

    en: Voltage

    -
    Current voltage on device in 0,1V.
    -
    -
  • -
  • -

    2110 - Variable Int32

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array17RAMINTEGER32rwoptionalyes
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index16 -
    01int320 -
    02int320 -
    03int320 -
    04int320 -
    05int320 -
    06int320 -
    07int320 -
    08int320 -
    09int320 -
    0Aint320 -
    0Bint320 -
    0Cint320 -
    0Dint320 -
    0Eint320 -
    0Fint320 -
    10int320 -
    -
    -

    en: Variable Integer 32bit

    -
    Vartiable is free to use by application.
    -
    -
  • -
  • -

    2111 - Variable ROM Int32

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array17ROMINTEGER32rwoptionalyes
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index16 -
    01int321 -
    02int320 -
    03int320 -
    04int320 -
    05int320 -
    06int320 -
    07int320 -
    08int320 -
    09int320 -
    0Aint320 -
    0Bint320 -
    0Cint320 -
    0Dint320 -
    0Eint320 -
    0Fint320 -
    10int320 -
    -
    -

    en: Variable ROM Integer 32bit

    -
    Vartiable is free to use by application.
    -
    -
  • -
  • -

    2112 - Variable NV Int32

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array17EEPROMINTEGER32rwoptionalyes
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index16 -
    01int321 -
    02int320 -
    03int320 -
    04int320 -
    05int320 -
    06int320 -
    07int320 -
    08int320 -
    09int320 -
    0Aint320 -
    0Bint320 -
    0Cint320 -
    0Dint320 -
    0Eint320 -
    0Fint320 -
    10int320 -
    -
    -

    en: Variable nonvolatile Integer 32bit

    -
    Vartiable is free to use by application. Variable is stored to internal baterry powered SRAM.
    -
    -
  • -
  • -

    2120 - test var

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record6RAM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono5 -
    01I64INTEGER64rwoptionalno0x1234567890ABCDEFLL -
    02U64UNSIGNED64rwoptionalno0x234567890ABCDEF1LL -
    03R32REAL32rwoptionalno12.345 -
    04R64REAL64rwoptionalno456.789 -
    05domainDOMAINrwnono0 -
    -
  • -
  • -

    2130 - Time

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record4RAM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono3 -
    01StringVISIBLE_STRINGronono- -
    02Epoch time base msUNSIGNED64rwnono0 -
    03Epoch time offset msUNSIGNED32rwoptionalno0 -
    -
    -

    en: Time

    -
    - Variable displays current time. -
    -
    - String - returns current time as string. -
    -
    - Epoch time ms - Milliseconds since unix epoch (1.1.1970, 00:00:00, UTC). It is calculated as base + offset. Base is calculated on startup of program and offset increments continuously since then. 'Epoch time offset ms' overflows each 49,7 days. 'Epoch time base ms' is recalculated in case of overflow or in case of write to 'Epoch time offset ms'. It is rounded to one minute. -
    -
    -
  • -
  • -

    2301 - Trace config

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono8 -
    01SizeUNSIGNED32rwnono100 -
    02Axis noUNSIGNED8rwnono1 -
    03NameVISIBLE_STRINGrwnonoTrace1 -
    04ColorVISIBLE_STRINGrwnonored -
    05MapUNSIGNED32rwnono0x60000108 -
    06FormatUNSIGNED8rwnono1 -
    07TriggerUNSIGNED8rwnono0 -
    08ThresholdINTEGER32rwnono0 -
    -
    -

    en: Trace config

    -
    - Trace is used for recording variables. -
    -
    - See also Trace. -
    -
    - Size - Maximum number of trace records in circular buffer. By reading it returns actual buffer size (If zero, malloc may had been failed at startup). By writing it sets the size, which will be valid after next reboot. (It is necessary to store parameters before (0x1010).) -
    -
    - Axis no - If value is different than zero, trace is enabled. Value is informative and describes group of traces (Multiple traces can belong to single axis.). By reading it returns zero if trace is disabled or if it is not configured properly. When trace is enabled, internal buffer is cleared. -
    -
    - Name - name of the trace as a string (informative). -
    -
    - Color - color of the trace as a string (informative). -
    -
    - Map - Map to variable in object dictionary, similar as PDO map(two bytes of index, one byte of subindex and 1 byte of bitlength. It's value will be copied to trace.value in case index and subindex are correct. If map index and subindex is zero, RPDO may be mapped to trace.value, for example. Valid values of map.bitlength is 08, 10 or 20 or 00, which indicates 8-bit, 16bit, 32-bit or default-size variable. Trace must be disabled, if mapping is written (Axis no set to 0). -
    -
    - Format - If first bit is zero, then value is used as signed integer otherwise as unsigned integer. If format is 0 or 1, text points are generated for time and value: "123;321\n140;345\n..." If format is 2 or 3, binary data is generated: 4-byte timestamp and 4-byte value. If format is 4 or 5, SVG path is generated: "M123,321H140V345...". -
    -
    - Trigger - 0=disabled, 1=rising edge, 2=falling edge, 3=both edges. -
    -
    - Threshold - If integer value passes threshold (based on trigger setting), time is recorded into 'trigger time'. -
    -
    -
  • -
  • -

    2302 - Trace config

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record9ROM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono8 -
    01SizeUNSIGNED32rwnono0 -
    02Axis noUNSIGNED8rwnono0 -
    03NameVISIBLE_STRINGrwnonoTrace2 -
    04ColorVISIBLE_STRINGrwnonogreen -
    05MapUNSIGNED32rwnono0x00000000 -
    06FormatUNSIGNED8rwnono0 -
    07TriggerUNSIGNED8rwnono0 -
    08ThresholdINTEGER32rwnono0 -
    -
  • -
  • -

    2400 - Trace enable

    - - - - - - - - - - - - - - - - - - - - -
    Object TypeMemory TypeData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    VarRAMUNSIGNED8rwoptionalno0 -
    -
    -

    en: Trace enable

    -
    This object controls, how many trace objects (beginning from index 0x2401) are enabled. If zero, all traces are disabled.
    -
    -
  • -
  • -

    2401 - Trace

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record7RAM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono6 -
    01SizeUNSIGNED32rwoptionalno0 -
    02ValueINTEGER32rwoptionalno0 -
    03MinINTEGER32rwoptionalno0 -
    04MaxINTEGER32rwoptionalno0 -
    05PlotDOMAINronono0 -
    06Trigger timeUNSIGNED32rwoptionalno0 -
    -
    -

    en: Trace

    -
    - Trace is used for recording variables. -
    -
    - See also Trace config. -
    -
    - Size - Number of current records in buffer. -
    -
    - Value - Latest value. If traceConfig.map (index and subindex) is valid, then mapped variable will be copied here. -
    -
    - Min, Max - Minimum and maximum value. -
    -
    - Plot - SVG path generated from the values from circular buffer. For time axis is used Time->'Epoch time offset ms'. When Plot is read, internal buffer is emptied. -
    -
    - Trigger time - If integer value passes 'TraceConfig->threshold', then time is recorded into this variable. -
    -
    -
  • -
  • -

    2402 - Trace

    - - - - - - - - - - - -
    Object TypeSub NumberMemory Type
    Record7RAM
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameData TypeAccess TypePDO MappingTPDO detects COSDefault valueActual value
    00max sub-indexUNSIGNED8ronono6 -
    01SizeUNSIGNED32rwoptionalno0 -
    02ValueINTEGER32rwoptionalno0 -
    03MinINTEGER32rwoptionalno0 -
    04MaxINTEGER32rwoptionalno0 -
    05PlotDOMAINronono0 -
    06Trigger timeUNSIGNED32rwoptionalno0 -
    -
  • -
  • -

    6000 - Read input 8 bit

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array9RAMUNSIGNED8rooptionalyes
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index8 -
    01Input0x00 -
    02Input0x00 -
    03Input0x00 -
    04Input0x00 -
    05Input0x00 -
    06Input0x00 -
    07Input0x00 -
    08Input0x00 -
    -
    -

    en: Read input 8 bit

    -
    Digital inputs from hardware.
    -
    -
  • -
  • -

    6200 - Write output 8 bit

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array9RAMUNSIGNED8rwoptionalno
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index8 -
    01Output0x00 -
    02Output0x00 -
    03Output0x00 -
    04Output0x00 -
    05Output0x00 -
    06Output0x00 -
    07Output0x00 -
    08Output0x00 -
    -
    -

    en: Write output 8 bit

    -
    Digital outputs on hardware.
    -
    -
  • -
  • -

    6401 - Read analogue input 16 bit

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array13RAMINTEGER16rooptionalno
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index12 -
    01Input0 -
    02Input0 -
    03Input0 -
    04Input0 -
    05Input0 -
    06Input0 -
    07Input0 -
    08Input0 -
    09Input0 -
    0AInput0 -
    0BInput0 -
    0CInput0 -
    -
    -

    en: Read analogue input 16 bit

    -
    Analogue inputs from hardware. The integer value is left adjusted.
    -
    -
  • -
  • -

    6411 - Write analogue output 16 bit

    - - - - - - - - - - - - - - - - - - - -
    Object TypeSub NumberMemory TypeData TypeAccess TypePDO MappingTPDO detects COS
    Array9RAMINTEGER16rwoptionalno
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SubindexNameDefault valueActual value
    00max sub-index8 -
    01Output0 -
    02Output0 -
    03Output0 -
    04Output0 -
    05Output0 -
    06Output0 -
    07Output0 -
    08Output0 -
    -
    -

    en: Write analogue output 16 bit

    -
    Analogue outputs on hardware. The integer value is left adjusted.
    -
    -
  • -
- -
- - diff --git a/example/OD.c b/example/OD.c index 83df9db5..6997800d 100644 --- a/example/OD.c +++ b/example/OD.c @@ -1,12 +1,1373 @@ +/******************************************************************************* + CANopen Object Dictionary definition for CANopenNode V4 + + This file was automatically generated with + libedssharp Object Dictionary Editor v0.8-99-g0425f94 + + https://github.com/CANopenNode/CANopenNode + https://github.com/robincornelius/libedssharp + + DON'T EDIT THIS FILE MANUALLY, UNLESS YOU KNOW WHAT YOU ARE DOING !!!! +*******************************************************************************/ + #define OD_DEFINITION #include "301/CO_ODinterface.h" #include "OD.h" -static const OD_entry_t OD_list[] = { - {0x1000, 0, 0, NULL} +#if CO_VERSION_MAJOR < 4 +#error This Object dictionary is compatible with CANopenNode V4.0 and above! +#endif + +/******************************************************************************* + OD data initialization of all groups +*******************************************************************************/ +OD_PERSIST_COMM_t OD_PERSIST_COMM = { + .x1000_deviceType = 0x00000000, + .x1005_COB_ID_SYNCMessage = 0x00000080, + .x1006_communicationCyclePeriod = 0x00000000, + .x1007_synchronousWindowLength = 0x00000000, + .x1012_COB_IDTimeStampObject = 0x00000100, + .x1014_COB_ID_EMCY = 0x00000080, + .x1015_inhibitTimeEMCY = 0x0000, + .x1016_consumerHeartbeatTime_sub0 = 0x08, + .x1016_consumerHeartbeatTime = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + .x1017_producerHeartbeatTime = 0x0000, + .x1018_identity = { + .highestSub_indexSupported = 0x04, + .vendor_ID = 0x00000000, + .productCode = 0x00000000, + .revisionNumber = 0x00000000, + .serialNumber = 0x00000000 + }, + .x1019_synchronousCounterOverflowValue = 0x00, + .x1280_SDOClientParameter = { + .highestSub_indexSupported = 0x03, + .COB_IDClientToServerTx = 0x80000000, + .COB_IDServerToClientRx = 0x80000000, + .node_IDOfTheSDOServer = 0x01 + }, + .x1400_RPDOCommunicationParameter = { + .highestSub_indexSupported = 0x05, + .COB_IDUsedByRPDO = 0x80000200, + .transmissionType = 0xFE, + .eventTimer = 0x0000 + }, + .x1401_RPDOCommunicationParameter = { + .highestSub_indexSupported = 0x05, + .COB_IDUsedByRPDO = 0x80000300, + .transmissionType = 0xFE, + .eventTimer = 0x0000 + }, + .x1402_RPDOCommunicationParameter = { + .highestSub_indexSupported = 0x05, + .COB_IDUsedByRPDO = 0x80000400, + .transmissionType = 0xFE, + .eventTimer = 0x0000 + }, + .x1403_RPDOCommunicationParameter = { + .highestSub_indexSupported = 0x05, + .COB_IDUsedByRPDO = 0x80000500, + .transmissionType = 0xFE, + .eventTimer = 0x0000 + }, + .x1600_RPDOMappingParameter = { + .numberOfMappedApplicationObjectsInPDO = 0x00, + .applicationObject_1 = 0x00000000, + .applicationObject_2 = 0x00000000, + .applicationObject_3 = 0x00000000, + .applicationObject_4 = 0x00000000, + .applicationObject_5 = 0x00000000, + .applicationObject_6 = 0x00000000, + .applicationObject_7 = 0x00000000, + .applicationObject_8 = 0x00000000 + }, + .x1601_RPDOMappingParameter = { + .numberOfMappedApplicationObjectsInPDO = 0x00, + .applicationObject_1 = 0x00000000, + .applicationObject_2 = 0x00000000, + .applicationObject_3 = 0x00000000, + .applicationObject_4 = 0x00000000, + .applicationObject_5 = 0x00000000, + .applicationObject_6 = 0x00000000, + .applicationObject_7 = 0x00000000, + .applicationObject_8 = 0x00000000 + }, + .x1602_RPDOMappingParameter = { + .numberOfMappedApplicationObjectsInPDO = 0x00, + .applicationObject_1 = 0x00000000, + .applicationObject_2 = 0x00000000, + .applicationObject_3 = 0x00000000, + .applicationObject_4 = 0x00000000, + .applicationObject_5 = 0x00000000, + .applicationObject_6 = 0x00000000, + .applicationObject_7 = 0x00000000, + .applicationObject_8 = 0x00000000 + }, + .x1603_RPDOMappingParameter = { + .numberOfMappedApplicationObjectsInPDO = 0x00, + .applicationObject_1 = 0x00000000, + .applicationObject_2 = 0x00000000, + .applicationObject_3 = 0x00000000, + .applicationObject_4 = 0x00000000, + .applicationObject_5 = 0x00000000, + .applicationObject_6 = 0x00000000, + .applicationObject_7 = 0x00000000, + .applicationObject_8 = 0x00000000 + }, + .x1800_TPDOCommunicationParameter = { + .highestSub_indexSupported = 0x06, + .COB_IDUsedByTPDO = 0xC0000180, + .transmissionType = 0xFE, + .inhibitTime = 0x0000, + .eventTimer = 0x0000, + .SYNCStartValue = 0x00 + }, + .x1801_TPDOCommunicationParameter = { + .highestSub_indexSupported = 0x06, + .COB_IDUsedByTPDO = 0xC0000280, + .transmissionType = 0xFE, + .inhibitTime = 0x0000, + .eventTimer = 0x0000, + .SYNCStartValue = 0x00 + }, + .x1802_TPDOCommunicationParameter = { + .highestSub_indexSupported = 0x06, + .COB_IDUsedByTPDO = 0xC0000380, + .transmissionType = 0xFE, + .inhibitTime = 0x0000, + .eventTimer = 0x0000, + .SYNCStartValue = 0x00 + }, + .x1803_TPDOCommunicationParameter = { + .highestSub_indexSupported = 0x06, + .COB_IDUsedByTPDO = 0xC0000480, + .transmissionType = 0xFE, + .inhibitTime = 0x0000, + .eventTimer = 0x0000, + .SYNCStartValue = 0x00 + }, + .x1A00_TPDOMappingParameter = { + .numberOfMappedApplicationObjectsInPDO = 0x00, + .applicationObject_1 = 0x00000000, + .applicationObject_2 = 0x00000000, + .applicationObject_3 = 0x00000000, + .applicationObject_4 = 0x00000000, + .applicationObject_5 = 0x00000000, + .applicationObject_6 = 0x00000000, + .applicationObject_7 = 0x00000000, + .applicationObject_8 = 0x00000000 + }, + .x1A01_TPDOMappingParameter = { + .numberOfMappedApplicationObjectsInPDO = 0x00, + .applicationObject_1 = 0x00000000, + .applicationObject_2 = 0x00000000, + .applicationObject_3 = 0x00000000, + .applicationObject_4 = 0x00000000, + .applicationObject_5 = 0x00000000, + .applicationObject_6 = 0x00000000, + .applicationObject_7 = 0x00000000, + .applicationObject_8 = 0x00000000 + }, + .x1A02_TPDOMappingParameter = { + .numberOfMappedApplicationObjectsInPDO = 0x00, + .applicationObject_1 = 0x00000000, + .applicationObject_2 = 0x00000000, + .applicationObject_3 = 0x00000000, + .applicationObject_4 = 0x00000000, + .applicationObject_5 = 0x00000000, + .applicationObject_6 = 0x00000000, + .applicationObject_7 = 0x00000000, + .applicationObject_8 = 0x00000000 + }, + .x1A03_TPDOMappingParameter = { + .numberOfMappedApplicationObjectsInPDO = 0x00, + .applicationObject_1 = 0x00000000, + .applicationObject_2 = 0x00000000, + .applicationObject_3 = 0x00000000, + .applicationObject_4 = 0x00000000, + .applicationObject_5 = 0x00000000, + .applicationObject_6 = 0x00000000, + .applicationObject_7 = 0x00000000, + .applicationObject_8 = 0x00000000 + } +}; + +OD_RAM_t OD_RAM = { + .x1001_errorRegister = 0x00, + .x1003_pre_definedErrorField_sub0 = 0x00, + .x1003_pre_definedErrorField = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + .x1010_storeParameters_sub0 = 0x04, + .x1010_storeParameters = {0x00000001, 0x00000001, 0x00000001, 0x00000001}, + .x1011_restoreDefaultParameters_sub0 = 0x04, + .x1011_restoreDefaultParameters = {0x00000001, 0x00000001, 0x00000001, 0x00000001}, + .x1200_SDOServerParameter = { + .highestSub_indexSupported = 0x02, + .COB_IDClientToServerRx = 0x00000600, + .COB_IDServerToClientTx = 0x00000580 + } +}; + + +/******************************************************************************* + IO extensions and flagsPDO (configurable by application) +*******************************************************************************/ +typedef struct { + OD_extensionIO_t xio_1003_pre_definedErrorField; + OD_extensionIO_t xio_1005_COB_ID_SYNCMessage; + OD_extensionIO_t xio_1006_communicationCyclePeriod; + OD_extensionIO_t xio_1007_synchronousWindowLength; + OD_extensionIO_t xio_1010_storeParameters; + OD_extensionIO_t xio_1011_restoreDefaultParameters; + OD_extensionIO_t xio_1012_COB_IDTimeStampObject; + OD_extensionIO_t xio_1014_COB_ID_EMCY; + OD_extensionIO_t xio_1015_inhibitTimeEMCY; + OD_extensionIO_t xio_1016_consumerHeartbeatTime; + OD_extensionIO_t xio_1017_producerHeartbeatTime; + OD_extensionIO_t xio_1200_SDOServerParameter; + OD_extensionIO_t xio_1280_SDOClientParameter; + OD_extensionIO_t xio_1400_RPDOCommunicationParameter; + OD_extensionIO_t xio_1401_RPDOCommunicationParameter; + OD_extensionIO_t xio_1402_RPDOCommunicationParameter; + OD_extensionIO_t xio_1403_RPDOCommunicationParameter; + OD_extensionIO_t xio_1600_RPDOMappingParameter; + OD_extensionIO_t xio_1601_RPDOMappingParameter; + OD_extensionIO_t xio_1602_RPDOMappingParameter; + OD_extensionIO_t xio_1603_RPDOMappingParameter; + OD_extensionIO_t xio_1800_TPDOCommunicationParameter; + OD_extensionIO_t xio_1801_TPDOCommunicationParameter; + OD_extensionIO_t xio_1802_TPDOCommunicationParameter; + OD_extensionIO_t xio_1803_TPDOCommunicationParameter; + OD_extensionIO_t xio_1A00_TPDOMappingParameter; + OD_extensionIO_t xio_1A01_TPDOMappingParameter; + OD_extensionIO_t xio_1A02_TPDOMappingParameter; + OD_extensionIO_t xio_1A03_TPDOMappingParameter; +} ODExts_t; + +static ODExts_t ODExts = {0}; + + +/******************************************************************************* + All OD objects (const) +*******************************************************************************/ +typedef struct { + OD_obj_var_t o_1000_deviceType; + OD_obj_var_t o_1001_errorRegister; + OD_obj_array_t o_1003_pre_definedErrorField; + OD_obj_extended_t oE_1003_pre_definedErrorField; + OD_obj_var_t o_1005_COB_ID_SYNCMessage; + OD_obj_extended_t oE_1005_COB_ID_SYNCMessage; + OD_obj_var_t o_1006_communicationCyclePeriod; + OD_obj_extended_t oE_1006_communicationCyclePeriod; + OD_obj_var_t o_1007_synchronousWindowLength; + OD_obj_extended_t oE_1007_synchronousWindowLength; + OD_obj_array_t o_1010_storeParameters; + OD_obj_extended_t oE_1010_storeParameters; + OD_obj_array_t o_1011_restoreDefaultParameters; + OD_obj_extended_t oE_1011_restoreDefaultParameters; + OD_obj_var_t o_1012_COB_IDTimeStampObject; + OD_obj_extended_t oE_1012_COB_IDTimeStampObject; + OD_obj_var_t o_1014_COB_ID_EMCY; + OD_obj_extended_t oE_1014_COB_ID_EMCY; + OD_obj_var_t o_1015_inhibitTimeEMCY; + OD_obj_extended_t oE_1015_inhibitTimeEMCY; + OD_obj_array_t o_1016_consumerHeartbeatTime; + OD_obj_extended_t oE_1016_consumerHeartbeatTime; + OD_obj_var_t o_1017_producerHeartbeatTime; + OD_obj_extended_t oE_1017_producerHeartbeatTime; + OD_obj_record_t o_1018_identity[5]; + OD_obj_var_t o_1019_synchronousCounterOverflowValue; + OD_obj_record_t o_1200_SDOServerParameter[3]; + OD_obj_extended_t oE_1200_SDOServerParameter; + OD_obj_record_t o_1280_SDOClientParameter[4]; + OD_obj_extended_t oE_1280_SDOClientParameter; + OD_obj_record_t o_1400_RPDOCommunicationParameter[4]; + OD_obj_extended_t oE_1400_RPDOCommunicationParameter; + OD_obj_record_t o_1401_RPDOCommunicationParameter[4]; + OD_obj_extended_t oE_1401_RPDOCommunicationParameter; + OD_obj_record_t o_1402_RPDOCommunicationParameter[4]; + OD_obj_extended_t oE_1402_RPDOCommunicationParameter; + OD_obj_record_t o_1403_RPDOCommunicationParameter[4]; + OD_obj_extended_t oE_1403_RPDOCommunicationParameter; + OD_obj_record_t o_1600_RPDOMappingParameter[9]; + OD_obj_extended_t oE_1600_RPDOMappingParameter; + OD_obj_record_t o_1601_RPDOMappingParameter[9]; + OD_obj_extended_t oE_1601_RPDOMappingParameter; + OD_obj_record_t o_1602_RPDOMappingParameter[9]; + OD_obj_extended_t oE_1602_RPDOMappingParameter; + OD_obj_record_t o_1603_RPDOMappingParameter[9]; + OD_obj_extended_t oE_1603_RPDOMappingParameter; + OD_obj_record_t o_1800_TPDOCommunicationParameter[6]; + OD_obj_extended_t oE_1800_TPDOCommunicationParameter; + OD_obj_record_t o_1801_TPDOCommunicationParameter[6]; + OD_obj_extended_t oE_1801_TPDOCommunicationParameter; + OD_obj_record_t o_1802_TPDOCommunicationParameter[6]; + OD_obj_extended_t oE_1802_TPDOCommunicationParameter; + OD_obj_record_t o_1803_TPDOCommunicationParameter[6]; + OD_obj_extended_t oE_1803_TPDOCommunicationParameter; + OD_obj_record_t o_1A00_TPDOMappingParameter[9]; + OD_obj_extended_t oE_1A00_TPDOMappingParameter; + OD_obj_record_t o_1A01_TPDOMappingParameter[9]; + OD_obj_extended_t oE_1A01_TPDOMappingParameter; + OD_obj_record_t o_1A02_TPDOMappingParameter[9]; + OD_obj_extended_t oE_1A02_TPDOMappingParameter; + OD_obj_record_t o_1A03_TPDOMappingParameter[9]; + OD_obj_extended_t oE_1A03_TPDOMappingParameter; +} ODObjs_t; + +static const ODObjs_t ODObjs = { + .o_1000_deviceType = { + .data = &OD_PERSIST_COMM.x1000_deviceType, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4 + }, + .o_1001_errorRegister = { + .data = &OD_RAM.x1001_errorRegister, + .attribute = ODA_SDO_R | ODA_TRPDO, + .dataLength = 1 + }, + .o_1003_pre_definedErrorField = { + .data0 = &OD_RAM.x1003_pre_definedErrorField_sub0, + .data = &OD_RAM.x1003_pre_definedErrorField[0], + .attribute0 = ODA_SDO_RW, + .attribute = ODA_SDO_R | ODA_MB, + .dataElementLength = 4, + .dataElementSizeof = sizeof(uint32_t) + }, + .oE_1003_pre_definedErrorField = { + .extIO = &ODExts.xio_1003_pre_definedErrorField, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1003_pre_definedErrorField + }, + .o_1005_COB_ID_SYNCMessage = { + .data = &OD_PERSIST_COMM.x1005_COB_ID_SYNCMessage, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + .oE_1005_COB_ID_SYNCMessage = { + .extIO = &ODExts.xio_1005_COB_ID_SYNCMessage, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1005_COB_ID_SYNCMessage + }, + .o_1006_communicationCyclePeriod = { + .data = &OD_PERSIST_COMM.x1006_communicationCyclePeriod, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + .oE_1006_communicationCyclePeriod = { + .extIO = &ODExts.xio_1006_communicationCyclePeriod, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1006_communicationCyclePeriod + }, + .o_1007_synchronousWindowLength = { + .data = &OD_PERSIST_COMM.x1007_synchronousWindowLength, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + .oE_1007_synchronousWindowLength = { + .extIO = &ODExts.xio_1007_synchronousWindowLength, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1007_synchronousWindowLength + }, + .o_1010_storeParameters = { + .data0 = &OD_RAM.x1010_storeParameters_sub0, + .data = &OD_RAM.x1010_storeParameters[0], + .attribute0 = ODA_SDO_R, + .attribute = ODA_SDO_RW | ODA_MB, + .dataElementLength = 4, + .dataElementSizeof = sizeof(uint32_t) + }, + .oE_1010_storeParameters = { + .extIO = &ODExts.xio_1010_storeParameters, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1010_storeParameters + }, + .o_1011_restoreDefaultParameters = { + .data0 = &OD_RAM.x1011_restoreDefaultParameters_sub0, + .data = &OD_RAM.x1011_restoreDefaultParameters[0], + .attribute0 = ODA_SDO_R, + .attribute = ODA_SDO_RW | ODA_MB, + .dataElementLength = 4, + .dataElementSizeof = sizeof(uint32_t) + }, + .oE_1011_restoreDefaultParameters = { + .extIO = &ODExts.xio_1011_restoreDefaultParameters, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1011_restoreDefaultParameters + }, + .o_1012_COB_IDTimeStampObject = { + .data = &OD_PERSIST_COMM.x1012_COB_IDTimeStampObject, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + .oE_1012_COB_IDTimeStampObject = { + .extIO = &ODExts.xio_1012_COB_IDTimeStampObject, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1012_COB_IDTimeStampObject + }, + .o_1014_COB_ID_EMCY = { + .data = &OD_PERSIST_COMM.x1014_COB_ID_EMCY, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + .oE_1014_COB_ID_EMCY = { + .extIO = &ODExts.xio_1014_COB_ID_EMCY, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1014_COB_ID_EMCY + }, + .o_1015_inhibitTimeEMCY = { + .data = &OD_PERSIST_COMM.x1015_inhibitTimeEMCY, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + .oE_1015_inhibitTimeEMCY = { + .extIO = &ODExts.xio_1015_inhibitTimeEMCY, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1015_inhibitTimeEMCY + }, + .o_1016_consumerHeartbeatTime = { + .data0 = &OD_PERSIST_COMM.x1016_consumerHeartbeatTime_sub0, + .data = &OD_PERSIST_COMM.x1016_consumerHeartbeatTime[0], + .attribute0 = ODA_SDO_R, + .attribute = ODA_SDO_RW | ODA_MB, + .dataElementLength = 4, + .dataElementSizeof = sizeof(uint32_t) + }, + .oE_1016_consumerHeartbeatTime = { + .extIO = &ODExts.xio_1016_consumerHeartbeatTime, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1016_consumerHeartbeatTime + }, + .o_1017_producerHeartbeatTime = { + .data = &OD_PERSIST_COMM.x1017_producerHeartbeatTime, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + .oE_1017_producerHeartbeatTime = { + .extIO = &ODExts.xio_1017_producerHeartbeatTime, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1017_producerHeartbeatTime + }, + .o_1018_identity = { + { + .data = &OD_PERSIST_COMM.x1018_identity.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1018_identity.vendor_ID, + .subIndex = 1, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1018_identity.productCode, + .subIndex = 2, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1018_identity.revisionNumber, + .subIndex = 3, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1018_identity.serialNumber, + .subIndex = 4, + .attribute = ODA_SDO_R | ODA_MB, + .dataLength = 4 + } + }, + .o_1019_synchronousCounterOverflowValue = { + .data = &OD_PERSIST_COMM.x1019_synchronousCounterOverflowValue, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + .o_1200_SDOServerParameter = { + { + .data = &OD_RAM.x1200_SDOServerParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_RAM.x1200_SDOServerParameter.COB_IDClientToServerRx, + .subIndex = 1, + .attribute = ODA_SDO_R | ODA_TPDO | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_RAM.x1200_SDOServerParameter.COB_IDServerToClientTx, + .subIndex = 2, + .attribute = ODA_SDO_R | ODA_TPDO | ODA_MB, + .dataLength = 4 + } + }, + .oE_1200_SDOServerParameter = { + .extIO = &ODExts.xio_1200_SDOServerParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1200_SDOServerParameter + }, + .o_1280_SDOClientParameter = { + { + .data = &OD_PERSIST_COMM.x1280_SDOClientParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1280_SDOClientParameter.COB_IDClientToServerTx, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_TRPDO | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1280_SDOClientParameter.COB_IDServerToClientRx, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_TRPDO | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1280_SDOClientParameter.node_IDOfTheSDOServer, + .subIndex = 3, + .attribute = ODA_SDO_RW, + .dataLength = 1 + } + }, + .oE_1280_SDOClientParameter = { + .extIO = &ODExts.xio_1280_SDOClientParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1280_SDOClientParameter + }, + .o_1400_RPDOCommunicationParameter = { + { + .data = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.COB_IDUsedByRPDO, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.transmissionType, + .subIndex = 2, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.eventTimer, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + } + }, + .oE_1400_RPDOCommunicationParameter = { + .extIO = &ODExts.xio_1400_RPDOCommunicationParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1400_RPDOCommunicationParameter + }, + .o_1401_RPDOCommunicationParameter = { + { + .data = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.COB_IDUsedByRPDO, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.transmissionType, + .subIndex = 2, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.eventTimer, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + } + }, + .oE_1401_RPDOCommunicationParameter = { + .extIO = &ODExts.xio_1401_RPDOCommunicationParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1401_RPDOCommunicationParameter + }, + .o_1402_RPDOCommunicationParameter = { + { + .data = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.COB_IDUsedByRPDO, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.transmissionType, + .subIndex = 2, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.eventTimer, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + } + }, + .oE_1402_RPDOCommunicationParameter = { + .extIO = &ODExts.xio_1402_RPDOCommunicationParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1402_RPDOCommunicationParameter + }, + .o_1403_RPDOCommunicationParameter = { + { + .data = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.COB_IDUsedByRPDO, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.transmissionType, + .subIndex = 2, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.eventTimer, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + } + }, + .oE_1403_RPDOCommunicationParameter = { + .extIO = &ODExts.xio_1403_RPDOCommunicationParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1403_RPDOCommunicationParameter + }, + .o_1600_RPDOMappingParameter = { + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .subIndex = 0, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_1, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_2, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_3, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_4, + .subIndex = 4, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_5, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_6, + .subIndex = 6, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_7, + .subIndex = 7, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_8, + .subIndex = 8, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + } + }, + .oE_1600_RPDOMappingParameter = { + .extIO = &ODExts.xio_1600_RPDOMappingParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1600_RPDOMappingParameter + }, + .o_1601_RPDOMappingParameter = { + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .subIndex = 0, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_1, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_2, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_3, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_4, + .subIndex = 4, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_5, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_6, + .subIndex = 6, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_7, + .subIndex = 7, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_8, + .subIndex = 8, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + } + }, + .oE_1601_RPDOMappingParameter = { + .extIO = &ODExts.xio_1601_RPDOMappingParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1601_RPDOMappingParameter + }, + .o_1602_RPDOMappingParameter = { + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .subIndex = 0, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_1, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_2, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_3, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_4, + .subIndex = 4, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_5, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_6, + .subIndex = 6, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_7, + .subIndex = 7, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_8, + .subIndex = 8, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + } + }, + .oE_1602_RPDOMappingParameter = { + .extIO = &ODExts.xio_1602_RPDOMappingParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1602_RPDOMappingParameter + }, + .o_1603_RPDOMappingParameter = { + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .subIndex = 0, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_1, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_2, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_3, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_4, + .subIndex = 4, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_5, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_6, + .subIndex = 6, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_7, + .subIndex = 7, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_8, + .subIndex = 8, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + } + }, + .oE_1603_RPDOMappingParameter = { + .extIO = &ODExts.xio_1603_RPDOMappingParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1603_RPDOMappingParameter + }, + .o_1800_TPDOCommunicationParameter = { + { + .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.COB_IDUsedByTPDO, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.transmissionType, + .subIndex = 2, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.inhibitTime, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + { + .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.eventTimer, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + { + .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.SYNCStartValue, + .subIndex = 6, + .attribute = ODA_SDO_RW, + .dataLength = 1 + } + }, + .oE_1800_TPDOCommunicationParameter = { + .extIO = &ODExts.xio_1800_TPDOCommunicationParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1800_TPDOCommunicationParameter + }, + .o_1801_TPDOCommunicationParameter = { + { + .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.COB_IDUsedByTPDO, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.transmissionType, + .subIndex = 2, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.inhibitTime, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + { + .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.eventTimer, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + { + .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.SYNCStartValue, + .subIndex = 6, + .attribute = ODA_SDO_RW, + .dataLength = 1 + } + }, + .oE_1801_TPDOCommunicationParameter = { + .extIO = &ODExts.xio_1801_TPDOCommunicationParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1801_TPDOCommunicationParameter + }, + .o_1802_TPDOCommunicationParameter = { + { + .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.COB_IDUsedByTPDO, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.transmissionType, + .subIndex = 2, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.inhibitTime, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + { + .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.eventTimer, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + { + .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.SYNCStartValue, + .subIndex = 6, + .attribute = ODA_SDO_RW, + .dataLength = 1 + } + }, + .oE_1802_TPDOCommunicationParameter = { + .extIO = &ODExts.xio_1802_TPDOCommunicationParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1802_TPDOCommunicationParameter + }, + .o_1803_TPDOCommunicationParameter = { + { + .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.highestSub_indexSupported, + .subIndex = 0, + .attribute = ODA_SDO_R, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.COB_IDUsedByTPDO, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.transmissionType, + .subIndex = 2, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.inhibitTime, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + { + .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.eventTimer, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 2 + }, + { + .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.SYNCStartValue, + .subIndex = 6, + .attribute = ODA_SDO_RW, + .dataLength = 1 + } + }, + .oE_1803_TPDOCommunicationParameter = { + .extIO = &ODExts.xio_1803_TPDOCommunicationParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1803_TPDOCommunicationParameter + }, + .o_1A00_TPDOMappingParameter = { + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .subIndex = 0, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_1, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_2, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_3, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_4, + .subIndex = 4, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_5, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_6, + .subIndex = 6, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_7, + .subIndex = 7, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_8, + .subIndex = 8, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + } + }, + .oE_1A00_TPDOMappingParameter = { + .extIO = &ODExts.xio_1A00_TPDOMappingParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1A00_TPDOMappingParameter + }, + .o_1A01_TPDOMappingParameter = { + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .subIndex = 0, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_1, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_2, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_3, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_4, + .subIndex = 4, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_5, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_6, + .subIndex = 6, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_7, + .subIndex = 7, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_8, + .subIndex = 8, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + } + }, + .oE_1A01_TPDOMappingParameter = { + .extIO = &ODExts.xio_1A01_TPDOMappingParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1A01_TPDOMappingParameter + }, + .o_1A02_TPDOMappingParameter = { + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .subIndex = 0, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_1, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_2, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_3, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_4, + .subIndex = 4, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_5, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_6, + .subIndex = 6, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_7, + .subIndex = 7, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_8, + .subIndex = 8, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + } + }, + .oE_1A02_TPDOMappingParameter = { + .extIO = &ODExts.xio_1A02_TPDOMappingParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1A02_TPDOMappingParameter + }, + .o_1A03_TPDOMappingParameter = { + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .subIndex = 0, + .attribute = ODA_SDO_RW, + .dataLength = 1 + }, + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_1, + .subIndex = 1, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_2, + .subIndex = 2, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_3, + .subIndex = 3, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_4, + .subIndex = 4, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_5, + .subIndex = 5, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_6, + .subIndex = 6, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_7, + .subIndex = 7, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + }, + { + .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_8, + .subIndex = 8, + .attribute = ODA_SDO_RW | ODA_MB, + .dataLength = 4 + } + }, + .oE_1A03_TPDOMappingParameter = { + .extIO = &ODExts.xio_1A03_TPDOMappingParameter, + .flagsPDO = NULL, + .odObjectOriginal = &ODObjs.o_1A03_TPDOMappingParameter + } +}; + + +/******************************************************************************* + Object dictionary +*******************************************************************************/ +static const OD_entry_t ODList[] = { + {0x1000, 0x01, ODT_VAR, &ODObjs.o_1000_deviceType}, + {0x1001, 0x01, ODT_VAR, &ODObjs.o_1001_errorRegister}, + {0x1003, 0x09, ODT_EARR, &ODObjs.oE_1003_pre_definedErrorField}, + {0x1005, 0x01, ODT_EVAR, &ODObjs.oE_1005_COB_ID_SYNCMessage}, + {0x1006, 0x01, ODT_EVAR, &ODObjs.oE_1006_communicationCyclePeriod}, + {0x1007, 0x01, ODT_EVAR, &ODObjs.oE_1007_synchronousWindowLength}, + {0x1010, 0x05, ODT_EARR, &ODObjs.oE_1010_storeParameters}, + {0x1011, 0x05, ODT_EARR, &ODObjs.oE_1011_restoreDefaultParameters}, + {0x1012, 0x01, ODT_EVAR, &ODObjs.oE_1012_COB_IDTimeStampObject}, + {0x1014, 0x01, ODT_EVAR, &ODObjs.oE_1014_COB_ID_EMCY}, + {0x1015, 0x01, ODT_EVAR, &ODObjs.oE_1015_inhibitTimeEMCY}, + {0x1016, 0x09, ODT_EARR, &ODObjs.oE_1016_consumerHeartbeatTime}, + {0x1017, 0x01, ODT_EVAR, &ODObjs.oE_1017_producerHeartbeatTime}, + {0x1018, 0x05, ODT_REC, &ODObjs.o_1018_identity}, + {0x1019, 0x01, ODT_VAR, &ODObjs.o_1019_synchronousCounterOverflowValue}, + {0x1200, 0x03, ODT_EREC, &ODObjs.oE_1200_SDOServerParameter}, + {0x1280, 0x04, ODT_EREC, &ODObjs.oE_1280_SDOClientParameter}, + {0x1400, 0x04, ODT_EREC, &ODObjs.oE_1400_RPDOCommunicationParameter}, + {0x1401, 0x04, ODT_EREC, &ODObjs.oE_1401_RPDOCommunicationParameter}, + {0x1402, 0x04, ODT_EREC, &ODObjs.oE_1402_RPDOCommunicationParameter}, + {0x1403, 0x04, ODT_EREC, &ODObjs.oE_1403_RPDOCommunicationParameter}, + {0x1600, 0x09, ODT_EREC, &ODObjs.oE_1600_RPDOMappingParameter}, + {0x1601, 0x09, ODT_EREC, &ODObjs.oE_1601_RPDOMappingParameter}, + {0x1602, 0x09, ODT_EREC, &ODObjs.oE_1602_RPDOMappingParameter}, + {0x1603, 0x09, ODT_EREC, &ODObjs.oE_1603_RPDOMappingParameter}, + {0x1800, 0x06, ODT_EREC, &ODObjs.oE_1800_TPDOCommunicationParameter}, + {0x1801, 0x06, ODT_EREC, &ODObjs.oE_1801_TPDOCommunicationParameter}, + {0x1802, 0x06, ODT_EREC, &ODObjs.oE_1802_TPDOCommunicationParameter}, + {0x1803, 0x06, ODT_EREC, &ODObjs.oE_1803_TPDOCommunicationParameter}, + {0x1A00, 0x09, ODT_EREC, &ODObjs.oE_1A00_TPDOMappingParameter}, + {0x1A01, 0x09, ODT_EREC, &ODObjs.oE_1A01_TPDOMappingParameter}, + {0x1A02, 0x09, ODT_EREC, &ODObjs.oE_1A02_TPDOMappingParameter}, + {0x1A03, 0x09, ODT_EREC, &ODObjs.oE_1A03_TPDOMappingParameter}, + {0x0000, 0x00, 0, NULL} }; const OD_t OD = { - sizeof(OD_list) / sizeof(OD_list[0]), - &OD_list[0] + (sizeof(ODList) / sizeof(ODList[0])) - 1, + &ODList[0] }; diff --git a/example/OD.h b/example/OD.h index dc6b69de..40e31ece 100644 --- a/example/OD.h +++ b/example/OD.h @@ -1,45 +1,320 @@ -/* blank OD for pre-release */ +/******************************************************************************* + CANopen Object Dictionary definition for CANopenNode V4 -extern const OD_t OD; + This file was automatically generated with + libedssharp Object Dictionary Editor v0.8-99-g0425f94 + + https://github.com/CANopenNode/CANopenNode + https://github.com/robincornelius/libedssharp + + DON'T EDIT THIS FILE MANUALLY !!!! +******************************************************************************** + + File info: + File Names: OD.h; OD.c + Project File: DS301_profile.xpd + File Version: 1 + + Created: 23. 11. 2020 12:00:00 + Created By: + Modified: 24. 11. 2020 13:31:53 + Modified By: + Device Info: + Vendor Name: + Vendor ID: + Product Name: New Product + Product ID: + + Description: +*******************************************************************************/ + +#ifndef OD_H +#define OD_H +/******************************************************************************* + Counters of OD objects +*******************************************************************************/ #define OD_CNT_NMT 1 -#define OD_CNT_HB_PROD 1 #define OD_CNT_EM 1 +//#define OD_CNT_SYNC 1 +//#define OD_CNT_SYNC_PROD 1 +//#define OD_CNT_TIME 1 #define OD_CNT_EM_PROD 1 +//#define OD_CNT_HB_CONS 1 +#define OD_CNT_HB_PROD 1 #define OD_CNT_SDO_SRV 1 #define OD_CNT_SDO_CLI 1 +//#define OD_CNT_RPDO 4 +//#define OD_CNT_TPDO 4 + + +/******************************************************************************* + OD data declaration of all groups +*******************************************************************************/ +typedef struct { + uint32_t x1000_deviceType; + uint32_t x1005_COB_ID_SYNCMessage; + uint32_t x1006_communicationCyclePeriod; + uint32_t x1007_synchronousWindowLength; + uint32_t x1012_COB_IDTimeStampObject; + uint32_t x1014_COB_ID_EMCY; + uint16_t x1015_inhibitTimeEMCY; + uint8_t x1016_consumerHeartbeatTime_sub0; + uint32_t x1016_consumerHeartbeatTime[8]; + uint16_t x1017_producerHeartbeatTime; + struct { + uint8_t highestSub_indexSupported; + uint32_t vendor_ID; + uint32_t productCode; + uint32_t revisionNumber; + uint32_t serialNumber; + } x1018_identity; + uint8_t x1019_synchronousCounterOverflowValue; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDClientToServerTx; + uint32_t COB_IDServerToClientRx; + uint8_t node_IDOfTheSDOServer; + } x1280_SDOClientParameter; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDUsedByRPDO; + uint8_t transmissionType; + uint16_t eventTimer; + } x1400_RPDOCommunicationParameter; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDUsedByRPDO; + uint8_t transmissionType; + uint16_t eventTimer; + } x1401_RPDOCommunicationParameter; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDUsedByRPDO; + uint8_t transmissionType; + uint16_t eventTimer; + } x1402_RPDOCommunicationParameter; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDUsedByRPDO; + uint8_t transmissionType; + uint16_t eventTimer; + } x1403_RPDOCommunicationParameter; + struct { + uint8_t numberOfMappedApplicationObjectsInPDO; + uint32_t applicationObject_1; + uint32_t applicationObject_2; + uint32_t applicationObject_3; + uint32_t applicationObject_4; + uint32_t applicationObject_5; + uint32_t applicationObject_6; + uint32_t applicationObject_7; + uint32_t applicationObject_8; + } x1600_RPDOMappingParameter; + struct { + uint8_t numberOfMappedApplicationObjectsInPDO; + uint32_t applicationObject_1; + uint32_t applicationObject_2; + uint32_t applicationObject_3; + uint32_t applicationObject_4; + uint32_t applicationObject_5; + uint32_t applicationObject_6; + uint32_t applicationObject_7; + uint32_t applicationObject_8; + } x1601_RPDOMappingParameter; + struct { + uint8_t numberOfMappedApplicationObjectsInPDO; + uint32_t applicationObject_1; + uint32_t applicationObject_2; + uint32_t applicationObject_3; + uint32_t applicationObject_4; + uint32_t applicationObject_5; + uint32_t applicationObject_6; + uint32_t applicationObject_7; + uint32_t applicationObject_8; + } x1602_RPDOMappingParameter; + struct { + uint8_t numberOfMappedApplicationObjectsInPDO; + uint32_t applicationObject_1; + uint32_t applicationObject_2; + uint32_t applicationObject_3; + uint32_t applicationObject_4; + uint32_t applicationObject_5; + uint32_t applicationObject_6; + uint32_t applicationObject_7; + uint32_t applicationObject_8; + } x1603_RPDOMappingParameter; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDUsedByTPDO; + uint8_t transmissionType; + uint16_t inhibitTime; + uint16_t eventTimer; + uint8_t SYNCStartValue; + } x1800_TPDOCommunicationParameter; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDUsedByTPDO; + uint8_t transmissionType; + uint16_t inhibitTime; + uint16_t eventTimer; + uint8_t SYNCStartValue; + } x1801_TPDOCommunicationParameter; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDUsedByTPDO; + uint8_t transmissionType; + uint16_t inhibitTime; + uint16_t eventTimer; + uint8_t SYNCStartValue; + } x1802_TPDOCommunicationParameter; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDUsedByTPDO; + uint8_t transmissionType; + uint16_t inhibitTime; + uint16_t eventTimer; + uint8_t SYNCStartValue; + } x1803_TPDOCommunicationParameter; + struct { + uint8_t numberOfMappedApplicationObjectsInPDO; + uint32_t applicationObject_1; + uint32_t applicationObject_2; + uint32_t applicationObject_3; + uint32_t applicationObject_4; + uint32_t applicationObject_5; + uint32_t applicationObject_6; + uint32_t applicationObject_7; + uint32_t applicationObject_8; + } x1A00_TPDOMappingParameter; + struct { + uint8_t numberOfMappedApplicationObjectsInPDO; + uint32_t applicationObject_1; + uint32_t applicationObject_2; + uint32_t applicationObject_3; + uint32_t applicationObject_4; + uint32_t applicationObject_5; + uint32_t applicationObject_6; + uint32_t applicationObject_7; + uint32_t applicationObject_8; + } x1A01_TPDOMappingParameter; + struct { + uint8_t numberOfMappedApplicationObjectsInPDO; + uint32_t applicationObject_1; + uint32_t applicationObject_2; + uint32_t applicationObject_3; + uint32_t applicationObject_4; + uint32_t applicationObject_5; + uint32_t applicationObject_6; + uint32_t applicationObject_7; + uint32_t applicationObject_8; + } x1A02_TPDOMappingParameter; + struct { + uint8_t numberOfMappedApplicationObjectsInPDO; + uint32_t applicationObject_1; + uint32_t applicationObject_2; + uint32_t applicationObject_3; + uint32_t applicationObject_4; + uint32_t applicationObject_5; + uint32_t applicationObject_6; + uint32_t applicationObject_7; + uint32_t applicationObject_8; + } x1A03_TPDOMappingParameter; +} OD_PERSIST_COMM_t; + +typedef struct { + uint8_t x1001_errorRegister; + uint8_t x1003_pre_definedErrorField_sub0; + uint32_t x1003_pre_definedErrorField[8]; + uint8_t x1010_storeParameters_sub0; + uint32_t x1010_storeParameters[4]; + uint8_t x1011_restoreDefaultParameters_sub0; + uint32_t x1011_restoreDefaultParameters[4]; + struct { + uint8_t highestSub_indexSupported; + uint32_t COB_IDClientToServerRx; + uint32_t COB_IDServerToClientTx; + } x1200_SDOServerParameter; +} OD_RAM_t; + +extern OD_PERSIST_COMM_t OD_PERSIST_COMM; +extern OD_RAM_t OD_RAM; +extern const OD_t OD; + + +/******************************************************************************* + Object dictionary entries - shortcuts +*******************************************************************************/ +#define OD_ENTRY_H1000 &OD.list[0] +#define OD_ENTRY_H1001 &OD.list[1] +#define OD_ENTRY_H1003 &OD.list[2] +#define OD_ENTRY_H1005 &OD.list[3] +#define OD_ENTRY_H1006 &OD.list[4] +#define OD_ENTRY_H1007 &OD.list[5] +#define OD_ENTRY_H1010 &OD.list[6] +#define OD_ENTRY_H1011 &OD.list[7] +#define OD_ENTRY_H1012 &OD.list[8] +#define OD_ENTRY_H1014 &OD.list[9] +#define OD_ENTRY_H1015 &OD.list[10] +#define OD_ENTRY_H1016 &OD.list[11] +#define OD_ENTRY_H1017 &OD.list[12] +#define OD_ENTRY_H1018 &OD.list[13] +#define OD_ENTRY_H1019 &OD.list[14] +#define OD_ENTRY_H1200 &OD.list[15] +#define OD_ENTRY_H1280 &OD.list[16] +#define OD_ENTRY_H1400 &OD.list[17] +#define OD_ENTRY_H1401 &OD.list[18] +#define OD_ENTRY_H1402 &OD.list[19] +#define OD_ENTRY_H1403 &OD.list[20] +#define OD_ENTRY_H1600 &OD.list[21] +#define OD_ENTRY_H1601 &OD.list[22] +#define OD_ENTRY_H1602 &OD.list[23] +#define OD_ENTRY_H1603 &OD.list[24] +#define OD_ENTRY_H1800 &OD.list[25] +#define OD_ENTRY_H1801 &OD.list[26] +#define OD_ENTRY_H1802 &OD.list[27] +#define OD_ENTRY_H1803 &OD.list[28] +#define OD_ENTRY_H1A00 &OD.list[29] +#define OD_ENTRY_H1A01 &OD.list[30] +#define OD_ENTRY_H1A02 &OD.list[31] +#define OD_ENTRY_H1A03 &OD.list[32] + + +/******************************************************************************* + Object dictionary entries - shortcuts with names +*******************************************************************************/ +#define OD_ENTRY_H1000_deviceType &OD.list[0] +#define OD_ENTRY_H1001_errorRegister &OD.list[1] +#define OD_ENTRY_H1003_pre_definedErrorField &OD.list[2] +#define OD_ENTRY_H1005_COB_ID_SYNCMessage &OD.list[3] +#define OD_ENTRY_H1006_communicationCyclePeriod &OD.list[4] +#define OD_ENTRY_H1007_synchronousWindowLength &OD.list[5] +#define OD_ENTRY_H1010_storeParameters &OD.list[6] +#define OD_ENTRY_H1011_restoreDefaultParameters &OD.list[7] +#define OD_ENTRY_H1012_COB_IDTimeStampObject &OD.list[8] +#define OD_ENTRY_H1014_COB_ID_EMCY &OD.list[9] +#define OD_ENTRY_H1015_inhibitTimeEMCY &OD.list[10] +#define OD_ENTRY_H1016_consumerHeartbeatTime &OD.list[11] +#define OD_ENTRY_H1017_producerHeartbeatTime &OD.list[12] +#define OD_ENTRY_H1018_identity &OD.list[13] +#define OD_ENTRY_H1019_synchronousCounterOverflowValue &OD.list[14] +#define OD_ENTRY_H1200_SDOServerParameter &OD.list[15] +#define OD_ENTRY_H1280_SDOClientParameter &OD.list[16] +#define OD_ENTRY_H1400_RPDOCommunicationParameter &OD.list[17] +#define OD_ENTRY_H1401_RPDOCommunicationParameter &OD.list[18] +#define OD_ENTRY_H1402_RPDOCommunicationParameter &OD.list[19] +#define OD_ENTRY_H1403_RPDOCommunicationParameter &OD.list[20] +#define OD_ENTRY_H1600_RPDOMappingParameter &OD.list[21] +#define OD_ENTRY_H1601_RPDOMappingParameter &OD.list[22] +#define OD_ENTRY_H1602_RPDOMappingParameter &OD.list[23] +#define OD_ENTRY_H1603_RPDOMappingParameter &OD.list[24] +#define OD_ENTRY_H1800_TPDOCommunicationParameter &OD.list[25] +#define OD_ENTRY_H1801_TPDOCommunicationParameter &OD.list[26] +#define OD_ENTRY_H1802_TPDOCommunicationParameter &OD.list[27] +#define OD_ENTRY_H1803_TPDOCommunicationParameter &OD.list[28] +#define OD_ENTRY_H1A00_TPDOMappingParameter &OD.list[29] +#define OD_ENTRY_H1A01_TPDOMappingParameter &OD.list[30] +#define OD_ENTRY_H1A02_TPDOMappingParameter &OD.list[31] +#define OD_ENTRY_H1A03_TPDOMappingParameter &OD.list[32] -#if 0 -#define OD_CNT_HB_CONS 1 -#define OD_CNT_TIME 1 -#define OD_CNT_SYNC 1 -#define OD_CNT_SYNC_PROD 1 -#define OD_CNT_RPDO 4 -#define OD_CNT_TPDO 4 -#define OD_CNT_GFC 0 -#define OD_CNT_SRDO 0 -#define OD_CNT_TRACE 0 -#endif - -#define OD_ENTRY_H1017 &OD.list[0] -#define OD_ENTRY_H1016 &OD.list[0] -#define OD_ENTRY_H1001 &OD.list[0] -#define OD_ENTRY_H1014 &OD.list[0] -#define OD_ENTRY_H1015 &OD.list[0] -#define OD_ENTRY_H1003 &OD.list[0] -#define OD_ENTRY_H1200 &OD.list[0] -#define OD_ENTRY_H1280 &OD.list[0] -#define OD_ENTRY_H1012 &OD.list[0] -#define OD_ENTRY_H1005 &OD.list[0] -#define OD_ENTRY_H1006 &OD.list[0] -#define OD_ENTRY_H1007 &OD.list[0] -#define OD_ENTRY_H1019 &OD.list[0] -#define OD_ENTRY_H1400 &OD.list[0] -#define OD_ENTRY_H1600 &OD.list[0] -#define OD_ENTRY_H1800 &OD.list[0] -#define OD_ENTRY_H1A00 &OD.list[0] -#define OD_ENTRY_H1300 &OD.list[0] -#define OD_ENTRY_H1301 &OD.list[0] -#define OD_ENTRY_H1381 &OD.list[0] -#define OD_ENTRY_H13FE &OD.list[0] -#define OD_ENTRY_H13FF &OD.list[0] +#endif /* OD_H */ diff --git a/example/_project.html b/example/_project.html deleted file mode 100644 index d000a248..00000000 --- a/example/_project.html +++ /dev/null @@ -1,311 +0,0 @@ - - - - Project - CANopenNode - - - -
-
- --- - --- - - at location: - - -
- - - - - - - - - - - - -
-
- CANopenNode project file: - -
-
-
-
- Documentation HTML file: - - -
- -
-
- Source code CO_OD.h file: - -
- -
-
- Source code CO_OD.c file: - -
- -
-
- EDS specification file: - -
- -
-
- Errors and warnings: - -
- -
-CANopenNode Editor - project file. -
- - \ No newline at end of file diff --git a/example/_project.xml b/example/_project.xml deleted file mode 100644 index 26a47637..00000000 --- a/example/_project.xml +++ /dev/null @@ -1,960 +0,0 @@ - - - - - - The Sync Object is broadcast periodically by the Sync Producer. - -Permissible value for SYNC is 0 or 1. - - - - - - - - - The Emergency message is triggered by the occurrence of a device internal error situation. - -Permissible value for Emergency is 0 or 1. - - - - - - A Service Data Object (SDO) reads from entries or writes to entries of the Object Dictionary. -SDO server is implemented on all CANopen devices. - -Permissible value for SDO sever is 0 or 1. - - - - - A Service Data Object (SDO) reads from entries or writes to entries of the Object Dictionary. -SDO client is usually a master device in a CANopen network. - -Permissible value for SDO client is 0 or 1. - - - - - Process Data Objects (PDOs) are mapped to a single CAN frame using up to 8 bytes of the data field to transmit application objects. Each PDO has a unique identifier and is transmitted by only one node, but it can be received by more than one (producer/consumer communication). - -Permissible value for RPDO is 0 to 16. For larger value Max Index must be changed. - - - - - - Process Data Objects (PDOs) are mapped to a single CAN frame using up to 8 bytes of the data field to transmit application objects. Each PDO has a unique identifier and is transmitted by only one node, but it can be received by more than one (producer/consumer communication). - -Permissible value for TPDO is 0 to 16. For larger value Max Index must be changed. - - - - - - NMT master can send CANopen NMT command, which can start, stop or reset nodes. - - - - Trace is used for recording variables. - - - - - - - - - bit 0-15: Device profile number -bit 16-31: Additional information - - - - bit 0: generic error -bit 1: current -bit 2: voltage -bit 3: temperature -bit 4: communication error (overrun, error state) -bit 5: device profile specific -bit 6: Reserved (always 0) -bit 7: manufacturer specific - - - - bit 0-31: Not used by stack (available for user) - - - - Number of Errors -bit 0-7: Zero can be written to erase error history - -Standard Error Field -bit 0-15: Error code as transmited in the Emergency object -bit 16-31: Manufacturer specific additional information - - - - - - - - - - - - - bit 0-10: COB-ID for SYNC object -bit 11-29: set to 0 -bit 30: 1(0) - node generates (does NOT generate) SYNC object -bit 31: set to 0 - - - - bit 0-31: period of SYNC transmission in µs (0 = no transmission, no checking) - - - - bit 0-31: window leghth after SYNC when PDOS must be transmited in µs, (0 = not used) - - - - Name of the manufacturer as string - - - - Name of the hardware version as string - - - - Name of the software version as string. - - - - Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) into this location stores all ROM variables into EEPROM. - - - - - - Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) into this location restores all ROM and EEPROM variables after reset. (After reset read form EEPROM is not performed, so default values are used.) - - - - - - bit 0-10: COB-ID -bit 11-30: set to 0 for 11 bit COB-ID -bit 31: 0(1) - node uses (does NOT use) Emergency object - - - - bit 0-15: Inhibit time of emergency message in 100µs - - - - max sub-index - -Consumer Heartbeat Time -bit 0-15: Heartbeat consumer time in ms (0 = node is not monitored) -bit 16-23: Node ID -bit 24-31: set to 0 - - - - - - - - - bit 0-15: Heartbeat producer time in ms (0 = disable transmission) - - - - max sub-index - -Vendor-ID -bit 0-31: Assigned by CiA - -Product code -bit 0-31: Manufacturer specific - -Revision number -bit 0-15: Minor revision num. (CANopen behavior has not changed) -bit 16-31: Major revision number (CANopen behavior has changed) - -Serial number -bit 0-31: Manufacturer specific - - - - - - - - - If value is zero, then SYNC message is transmitted with data length 0. - -If Value is from 2 to 240, then SYNC message has one data byte, which contains the counter. - -Other values are reserved. - - - - If error is detected and operating NMT state is NMT operational, this object defines behavior of the device. - -Value definition for all subindexes: - 0x00 - if operational, switch to NMT pre-operational - 0x01 - do nothing - 0x02 - switch to NMT stopped - -01 - Communication error - bus off or Heartbeat consumer error. -02 - Communication other error (critical errors - see 'Error status bits') except CAN bus passive but including bus off or Heartbeat consumer. -03 - Communication passive - any communication error including CAN bus passive. -04 - Generic error (critical errors - see 'Error status bits'). -05 - Device profile error - bit 5 in error register is set. -06 - Manufacturer specific error - bit 7 in error register is set. - - - - - - - - - - - 0x1200 SDO server parameter -max sub-index - -COB-ID client to server (Receive SDO) -bit 0-31: 0x00000600 + Node ID - -COB-ID server to client (Transmit SDO) -bit 0-31: 0x00000580 + Node ID - - - -0x1201 - 0x127F SDO server parameter -max sub-index - -COB-ID client to server (Receive SDO) -bit 0-10: COB_ID -bit 11-30: Set to 0 -bit 31*: 0(1) - node uses (does NOT use) SDO - -COB-ID server to client (Transmit SDO) -bit 0-31: same as previous - -Node-ID of the SDO client -bit 0-7: Node ID (optional) - - - - - - - 0x1280 - 0x12FF SDO client parameter -max sub-index - -COB-ID client to server (Transmit SDO) -bit 0-10: COB_ID -bit 11-30: Set to 0 -bit 31: 0(1) - node uses (does NOT use) SDO - -COB-ID server to client (Receive SDO) -bit 0-31: same as previous - -Node-ID of the SDO server -0-7: Node ID - - - - - - - - - - - 0x1400 - 0x15FF RPDO communication parameter -max sub-index - -COB-ID -bit 0-10: COB-ID for PDO, to change it bit 31 must be set -bit 11-29: set to 0 for 11 bit COB-ID -bit 30: 0(1) - rtr are allowed (are NOT allowed) for PDO -bit 31: 0(1) - node uses (does NOT use) PDO - -Transmission type -value = 0-240: reciving is synchronous, process after next reception of SYNC object -value = 241-253: not used -value = 254: manufacturer specific -value = 255: asynchronous - - - - - - - 0x1400 - 0x15FF RPDO communication parameter (see description for 0x1400) - - - - - - - 0x1400 - 0x15FF RPDO communication parameter (see description for 0x1400) - - - - - - - 0x1400 - 0x15FF RPDO communication parameter (see description for 0x1400) - - - - - - - 0x1400 - 0x15FF RPDO communication parameter (see description for 0x1400) - - - - 0x1600 - 0x17FF RPDO mapping parameter (To change mapping, 'Number of mapped objects' must be set to 0) -Number of mapped objects - -mapped object (subindex 1...8) -bit 0-7: data length in bits -bit 8-15: subindex from OD -bit 16-31: index from OD - - - - - - - - - - - - - 0x1600 - 0x17FF RPDO mapping parameter (see description for 0x1600) - - - - - - - - - - - - - 0x1600 - 0x17FF RPDO mapping parameter (see description for 0x1600) - - - - - - - - - - - - - 0x1600 - 0x17FF RPDO mapping parameter (see description for 0x1600) - - - - - - - - - - - - - 0x1600 - 0x17FF RPDO mapping parameter (see description for 0x1600) - - - - - - - - - - - - - - - - - - - - 0x1800 - 0x19FF TPDO communication parameter -max sub-index - -COB-ID -bit 0-10: COB-ID for PDO, to change it bit 31 must be set -bit 11-29: set to 0 for 11 bit COB-ID -bit 30: 0(1) - rtr are allowed (are NOT allowed) for PDO -bit 31: 0(1) - node uses (does NOT use) PDO - -Transmission type -value = 0: transmiting is synchronous, specification in device profile -value = 1-240: transmiting is synchronous after every N-th SYNC object -value = 241-251: not used -value = 252-253: Transmited only on reception of Remote Transmission Request -value = 254: manufacturer specific -value = 255: asinchronous, specification in device profile - -inhibit time -bit 0-15: Minimum time between transmissions of the PDO in 100µs. Zero disables functionality. - -compatibility entry -bit 0-7: Not used. - -event timer -bit 0-15: Time between periodic transmissions of the PDO in ms. Zero disables functionality. - -SYNC start value -value = 0: Counter of the SYNC message shall not be processed. -value = 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. - - - - - - - - - - - 0x1800 - 0x19FF TPDO communication parameter (see description for 0x1800) - - - - - - - - - - - 0x1800 - 0x19FF TPDO communication parameter (see description for 0x1800) - - - - - - - - - - - 0x1800 - 0x19FF TPDO communication parameter (see description for 0x1800) - - - - - - - - - - - 0x1800 - 0x19FF TPDO communication parameter (see description for 0x1800) - - - - 0x1A00 - 0x1BFF TPDO mapping parameter. (To change mapping, 'Number of mapped objects' must be set to 0). -Number of mapped objects - -mapped object (subindex 1...8) -bit 0-7: data length in bits -bit 8-15: subindex from OD -bit 16-31: index from OD - - - - - - - - - - - - - 0x1A00 - 0x1BFF TPDO mapping parameter (see description for 0x1A00) - - - - - - - - - - - - - 0x1A00 - 0x1BFF TPDO mapping parameter (see description for 0x1A00) - - - - - - - - - - - - - 0x1A00 - 0x1BFF TPDO mapping parameter (see description for 0x1A00) - - - - - - - - - - - - - 0x1A00 - 0x1BFF TPDO mapping parameter (see description for 0x1A00) - - - - - - - - - - - - - Only bit 2 is implemented. - -bit 0: 0(1) - device is not (is) NMT master -bit 1: 0(1) - if bit3=0, start explicitly assigned (all) nodes -bit 2: 0(1) - automaticaly enter (DO NOT automaticaly enter) the operational state on bootup -bit 3: 0(1) - NMT master may (may not) start nodes automatically -bit 4: 0(1) - if monitored node fails heartbeat handle that (all) node(s) -bit 5: 0(1) - flying master process not (yes) supported -bit 6: 0(1) - use bit 4 (ignore bit 4, stop all nodes) -bit 7-31: reserved, set to 0 - - - - Error Status Bits indicates error conditions inside stack or inside application. Specific bit is set by CO_errorReport() function, when error occurs in program. It can be reset by CO_errorReset() function, if error is solved. Emergency message is sent on each change of any Error Status Bit. If critical bits are set, node will not be able to stay in operational state. For more information see file CO_Emergency.h. - -Default error status bits are: - -Communication or protocol errors from driver (informative): -00 - ERROR_NO_ERROR - Error Reset or No Error. -01 - ERROR_CAN_BUS_WARNING - CAN bus warning. -02 - ERROR_RXMSG_WRONG_LENGTH - Wrong data length of received CAN message. -03 - ERROR_RXMSG_OVERFLOW - Previous received CAN message wasn't processed yet. -04 - ERROR_RPDO_WRONG_LENGTH - Wrong data length of received PDO. -05 - ERROR_RPDO_OVERFLOW - Previous received PDO wasn't processed yet. -06 - ERROR_CAN_RX_BUS_PASSIVE - CAN receive bus is passive. -07 - ERROR_CAN_TX_BUS_PASSIVE - CAN transmit bus is passive. - -Communication or protocol errors from driver (critical): -08 - ERROR_08_reserved - (reserved) -09 - ERROR_09_reserved - (reserved) -0A - ERROR_CAN_TX_BUS_OFF - CAN transmit bus is off. -0B - ERROR_CAN_RXB_OVERFLOW - CAN module receive buffer has overflowed. -0C - ERROR_CAN_TX_OVERFLOW - CAN transmit buffer has overflowed. -0D - ERROR_TPDO_OUTSIDE_WINDOW - TPDO is outside SYNC window. -0E - ERROR_CAN_CONFIGURATION_FAILED - Configuration of CAN module CAN failed (Rx or Tx). -0F - ERROR_0F_reserved - (reserved) - -Communication or protocol errors (informative): -10 - ERROR_NMT_WRONG_COMMAND - Wrong NMT command received. -11 - ERROR_SYNC_EARLY - SYNC message was too early. -12 - ERROR_12_reserved - (reserved) -13 - ERROR_13_reserved - (reserved) -14 - ERROR_14_reserved - (reserved) -15 - ERROR_15_reserved - (reserved) -16 - ERROR_16_reserved - (reserved) -17 - ERROR_17_reserved - (reserved) - -Communication or protocol errors (critical): -18 - ERROR_SYNC_TIME_OUT - SYNC message timeout. -19 - ERROR_SYNC_LENGTH - Unexpected SYNC data length -1A - ERROR_PDO_WRONG_MAPPING - Error with PDO mapping. -1B - ERROR_HEARTBEAT_CONSUMER - Heartbeat consumer timeout. -1C - ERROR_HEARTBEAT_CONSUMER_REMOTE_RESET - Heartbeat consumer detected remote node reset. -1D - ERROR_1D_reserved - (reserved) -1E - ERROR_1E_reserved - (reserved) -1F - ERROR_1F_reserved - (reserved) - -Generic errors (informative): -20 - ERROR_20_reserved - (reserved) -21 - ERROR_21_reserved - (reserved) -22 - ERROR_22_reserved - (reserved) -23 - ERROR_23_reserved - (reserved) -24 - ERROR_24_reserved - (reserved) -25 - ERROR_25_reserved - (reserved) -26 - ERROR_26_reserved - (reserved) -27 - ERROR_27_reserved - (reserved) - -Generic errors (critical): -28 - ERROR_WRONG_ERROR_REPORT - Wrong parameters to <CO_errorReport()> function. -29 - ERROR_ISR_TIMER_OVERFLOW - Timer task has overflowed. -2A - ERROR_MEMORY_ALLOCATION_ERROR - Unable to allocate memory for objects. -2B - ERROR_GENERIC_ERROR - Generic error, test usage. -2C - ERROR_MAIN_TIMER_OVERFLOW - Mainline function exceeded maximum execution time. -2D - ERROR_INTERNAL_STATE_APPL - Error in application software internal state. -2E - ERROR_2E_reserved - (reserved) -2F - ERROR_2F_reserved - (reserved) - -Manufacturer specific errors: -Manufacturer may define its own constants up to index 0xFF. Of course, he must then define large enough buffer for error status bits (up to 32 bytes). - - - if(WRITING){ - UNSIGNED8 var = *((UNSIGNED8*)dataBuff); - if(var < 1) return 0x06090032L; //Value of parameter written too low. - if(var > 127) return 0x06090031L; //Value of parameter written too high. -} - - CAN Node ID is CANopenNode specific variable. It sets node-ID for device on CANopen network. Node-ID can be set on other ways too, for example with DIP switches. More advanced solution is use of LSS. - -Valid values are from 1 to 127: - - - if(WRITING){ - UNSIGNED16 var; - memcpySwap2((UNSIGNED8*)&var, (UNSIGNED8*)dataBuff); - if(!(var == 10 || var == 20 || var == 50 || var == 125 || var == 250 || var == 500 || var == 800 || var == 1000)) return 0x06090030L; //Invalid value for the parameter -} - - CAN Bit-Rate is CANopenNode specific variable. It sets CAN Bit-Rate for device on CANopen network. - -Valid values are in [kbps]: -10, 20, 50, 125, 250, 500, 800, 1000 - - - - SYNC Counter is incremented each time, SYNC message is received or transmitted. - - - - SYNC Time is incremented each timer period and reset to zero, each time SYNC is received or transmitted. - - - - Power on Counter counts total microcontroller resets in it's lifetime. Variable is an example of EEPROM usage. - - - if(WRITING){ - UNSIGNED16 var; - memcpySwap2((UNSIGNED8*)&var, (UNSIGNED8*)dataBuff); - if(!((subIndex == 3 || subIndex == 5) && var == 0)) - return 0x06090030; //Invalid value for parameter -} - - Internal performance of the microcontroller. - -cycles per second - cycle frequency of internal timer. -timer cycle time - current timer cycle time in percent of timer period. -timer cycle max time - maximum timer cycle time in percent of timer period. -main cycle time - current mainline function cycle time in percent of timer period. -main cycle max time - maximum mainline function cycle time in percent of timer period. - - - - - - - - - - Current temperature on device in 0,1°C. - - - - - - Current voltage on device in 0,1V. - - - - - - Vartiable is free to use by application. - - - - - - - - - - - - - - - - - - - - - Vartiable is free to use by application. - - - - - - - - - - - - - - - - - - - - - Vartiable is free to use by application. Variable is stored to internal baterry powered SRAM. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Variable displays current time. - -String - returns current time as string. - -Epoch time ms - Milliseconds since unix epoch (1.1.1970, 00:00:00, UTC). It is calculated as base + offset. Base is calculated on startup of program and offset increments continuously since then. 'Epoch time offset ms' overflows each 49,7 days. 'Epoch time base ms' is recalculated in case of overflow or in case of write to 'Epoch time offset ms'. It is rounded to one minute. - - - - - - - - Trace is used for recording variables. - -See also Trace. - -Size - Maximum number of trace records in circular buffer. By reading it returns actual buffer size (If zero, malloc may had been failed at startup). By writing it sets the size, which will be valid after next reboot. (It is necessary to store parameters before (0x1010).) - -Axis no - If value is different than zero, trace is enabled. Value is informative and describes group of traces (Multiple traces can belong to single axis.). By reading it returns zero if trace is disabled or if it is not configured properly. When trace is enabled, internal buffer is cleared. - -Name - name of the trace as a string (informative). - -Color - color of the trace as a string (informative). - -Map - Map to variable in object dictionary, similar as PDO map(two bytes of index, one byte of subindex and 1 byte of bitlength. It's value will be copied to trace.value in case index and subindex are correct. If map index and subindex is zero, RPDO may be mapped to trace.value, for example. Valid values of map.bitlength is 08, 10 or 20 or 00, which indicates 8-bit, 16bit, 32-bit or default-size variable. Trace must be disabled, if mapping is written (Axis no set to 0). - -Format - If first bit is zero, then value is used as signed integer otherwise as unsigned integer. If format is 0 or 1, text points are generated for time and value: "123;321\n140;345\n..." If format is 2 or 3, binary data is generated: 4-byte timestamp and 4-byte value. If format is 4 or 5, SVG path is generated: "M123,321H140V345...". - -Trigger - 0=disabled, 1=rising edge, 2=falling edge, 3=both edges. - -Threshold - If integer value passes threshold (based on trigger setting), time is recorded into 'trigger time'. - - - - - - - - - - - - - - - - - - - - - - - - This object controls, how many trace objects (beginning from index 0x2401) are enabled. If zero, all traces are disabled. - - - - Trace is used for recording variables. - -See also Trace config. - -Size - Number of current records in buffer. - -Value - Latest value. If traceConfig.map (index and subindex) is valid, then mapped variable will be copied here. - -Min, Max - Minimum and maximum value. - -Plot - SVG path generated from the values from circular buffer. For time axis is used Time->'Epoch time offset ms'. When Plot is read, internal buffer is emptied. - -Trigger time - If integer value passes 'TraceConfig->threshold', then time is recorded into this variable. - - - - - - - - - - - - - - - - - - - - Digital inputs from hardware. - - - - - - - - - - - - - Digital outputs on hardware. - - - - - - - - - - - - - Analogue inputs from hardware. The integer value is left adjusted. - - - - - - - - - - - - - - - - - Analogue outputs on hardware. The integer value is left adjusted. - - - - - - - - - - - - - - - CANopenNode - CANopenNode - - - CANopenNode is an open source software stack used for serial communication of multiple devices over the CAN/CANopen Network. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From d224de0ac9babb81885f445caaa00f0cc33bf459 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 28 Nov 2020 12:20:43 +0100 Subject: [PATCH 140/520] Make Linux canopend example single thread. Include files optionally in CANopen.h --- CANopen.h | 38 ++++++++++++++++++++++++++++++++++++++ Makefile | 17 +++++++---------- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/CANopen.h b/CANopen.h index 450fb11c..0a78e447 100644 --- a/CANopen.h +++ b/CANopen.h @@ -31,20 +31,58 @@ #include "301/CO_driver.h" #include "301/CO_ODinterface.h" #include "301/CO_NMT_Heartbeat.h" + +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN #include "301/CO_HBconsumer.h" +#endif + #include "301/CO_Emergency.h" #include "301/CO_SDOserver.h" + +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) || defined CO_DOXYGEN #include "301/CO_SDOclient.h" +#endif + +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN #include "301/CO_SYNC.h" +#endif + +#if ((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) || defined CO_DOXYGEN #include "301/CO_PDO.h" +#endif + +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) || defined CO_DOXYGEN #include "301/CO_TIME.h" +#endif + +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN #include "303/CO_LEDs.h" +#endif + +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || defined CO_DOXYGEN #include "304/CO_GFC.h" +#endif + +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN #include "304/CO_SRDO.h" +#endif + +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) || defined CO_DOXYGEN #include "305/CO_LSSslave.h" +#endif + +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) || defined CO_DOXYGEN #include "305/CO_LSSmaster.h" +#endif + +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN #include "309/CO_gateway_ascii.h" +#endif + +#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) || defined CO_DOXYGEN #include "extra/CO_trace.h" +#endif + #ifdef __cplusplus extern "C" { diff --git a/Makefile b/Makefile index 385bddae..2bbaf131 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,7 @@ DRV_SRC = socketCAN CANOPEN_SRC = . -OD_SRC = example -APPL_SRC = socketCAN +APPL_SRC = example LINK_TARGET = canopend @@ -13,7 +12,6 @@ LINK_TARGET = canopend INCLUDE_DIRS = \ -I$(DRV_SRC) \ -I$(CANOPEN_SRC) \ - -I$(OD_SRC) \ -I$(APPL_SRC) # $(DRV_SRC)/CO_OD_storage.c \ @@ -41,22 +39,21 @@ SOURCES = \ $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ - $(OD_SRC)/OD.c \ - $(APPL_SRC)/CO_main_basic.c + $(APPL_SRC)/OD.c \ + $(DRV_SRC)/CO_main_basic.c OBJS = $(SOURCES:%.c=%.o) CC ?= gcc -OPT = -g +OPT = -g -DCO_SINGLE_THREAD #OPT = -g -pedantic -Wshadow -fanalyzer #OPT = -g -DCO_USE_GLOBALS #OPT = -g -DCO_MULTIPLE_OD -#OPT = -g -DCO_SINGLE_THREAD CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) -LDFLAGS = -pthread -#LDFLAGS = +LDFLAGS = +#LDFLAGS = -pthread -#Options can be passed via make: 'make OPT="-g -DCO_SINGLE_THREAD" LDFLAGS=""' +#Options can be also passed via make: 'make OPT="-g" LDFLAGS="-pthread"' .PHONY: all clean From 09bf9268567b3ebe77e16776718a4d932fa71897 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 2 Dec 2020 16:44:31 +0100 Subject: [PATCH 141/520] CO_ODinterface - Change some API: - Add OD_getPtr_vs(), OD_getPtr_os() and OD_getPtr_us(). - Move read/write from OD_subEntry_t into OD_IO_t structure. - Change argument in OD_getSub(), use OD_IO_t instead OD_stream_t. - OD_getSub(), argument subEntry is optional. - Change return value of OD_extensionIO_init() to ODR_t. --- 301/CO_Emergency.c | 38 ++-- 301/CO_NMT_Heartbeat.c | 19 +- 301/CO_ODinterface.c | 489 ++++++++++++++++++++++++---------------- 301/CO_ODinterface.h | 158 +++++++------ 301/CO_SDOclient.c | 27 +-- 301/CO_SDOserver.c | 30 ++- doc/objectDictionary.md | 3 +- 7 files changed, 443 insertions(+), 321 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index b7210a1d..c992b973 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -55,9 +55,9 @@ #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE /* - * Custom functions for read/write OD variable "COB-ID EMCY" + * Custom functions for read/write OD object "COB-ID EMCY" * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_read_1014(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, @@ -128,9 +128,9 @@ static OD_size_t OD_write_1014(OD_stream_t *stream, uint8_t subIndex, } #else /* - * Custom functions for read/write OD variable "COB-ID EMCY" + * Custom functions for read/write OD object "COB-ID EMCY" * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_read_1014_default(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, @@ -154,9 +154,9 @@ static OD_size_t OD_read_1014_default(OD_stream_t *stream, uint8_t subIndex, #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT /* - * Custom function for writing OD variable "Inhibit time EMCY" + * Custom function for writing OD object "Inhibit time EMCY" * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_write_1015(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, @@ -183,9 +183,9 @@ static OD_size_t OD_write_1015(OD_stream_t *stream, uint8_t subIndex, #if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY /* - * Custom functions for read/write OD variable _OD_statusBits_, optional + * Custom functions for read/write OD object _OD_statusBits_, optional * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_read_1003(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, @@ -251,9 +251,9 @@ static OD_size_t OD_write_1003(OD_stream_t *stream, uint8_t subIndex, #if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS /* - * Custom functions for read/write OD variable _OD_statusBits_, optional + * Custom functions for read/write OD object _OD_statusBits_, optional * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_read_statusBits(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, @@ -410,10 +410,11 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0 && producerCanId != 0; - if (!OD_extensionIO_init(OD_1014_cobIdEm, - (void *) em, - OD_read_1014, - OD_write_1014)) { + ODR_t odRetE = OD_extensionIO_init(OD_1014_cobIdEm, + (void *) em, + OD_read_1014, + OD_write_1014); + if (odRetE != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; } @@ -427,10 +428,11 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #else uint16_t producerCanId = CO_CAN_ID_EMERGENCY + nodeId; em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0; - if (!OD_extensionIO_init(OD_1014_cobIdEm, - (void *) em, - OD_read_1014_default, - OD_writeOriginal)) { + ODR_t odRetE = OD_extensionIO_init(OD_1014_cobIdEm, + (void *) em, + OD_read_1014_default, + OD_writeOriginal); + if (odRetE != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; } diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 06644172..efe7527e 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -55,9 +55,9 @@ static void CO_NMT_receive(void *object, void *msg) { /* - * Custom function for writing OD variable "Producer heartbeat time" + * Custom function for writing OD object "Producer heartbeat time" * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_write_1017(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, @@ -125,19 +125,22 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, /* get and verify required "Producer heartbeat time" from Object Dict. */ uint16_t HBprodTime_ms; - if (OD_get_u16(OD_1017_ProducerHbTime, 0, &HBprodTime_ms, true) != ODR_OK) { + ODR_t odRet = OD_get_u16(OD_1017_ProducerHbTime, 0, &HBprodTime_ms, true); + if (odRet != ODR_OK) { CO_errinfo(NMT_CANdevRx, OD_getIndex(OD_1017_ProducerHbTime)); return CO_ERROR_OD_PARAMETERS; } NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000; - if (!OD_extensionIO_init(OD_1017_ProducerHbTime, - (void *) NMT, - OD_readOriginal, - OD_write_1017) - ) { + + odRet = OD_extensionIO_init(OD_1017_ProducerHbTime, + (void *) NMT, + OD_readOriginal, + OD_write_1017); + if (odRet != ODR_OK) { CO_errinfo(HB_CANdevTx, OD_getIndex(OD_1017_ProducerHbTime)); return CO_ERROR_OD_PARAMETERS; } + if (NMT->HBproducerTimer > NMT->HBproducerTime_us) { NMT->HBproducerTimer = NMT->HBproducerTime_us; } diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index e2d329ec..6eb5b81e 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -109,7 +109,7 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, odData += stream->dataOffset; if (dataLenToCopy > count) { - /* Reamining data space in OD variable is larger than current count + /* Remaining data space in OD variable is larger than current count * of data, so only current count of data will be copied */ dataLenToCopy = count; stream->dataOffset += dataLenToCopy; @@ -121,7 +121,7 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, } if (dataLenToCopy < count) { - /* OD variable is smaller than current ammount of data */ + /* OD variable is smaller than current amount of data */ *returnCode = ODR_DATA_LONG; return 0; } @@ -133,25 +133,25 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, } } -/* Read value from variable from Object Dictionary disabled, see OD_subEntry_t*/ +/* Read value from variable from Object Dictionary disabled, see OD_IO_t*/ static OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, ODR_t *returnCode) { (void) stream; (void) subIndex; (void) buf; (void) count; - if (returnCode != NULL) *returnCode = ODR_WRITEONLY; + if (returnCode != NULL) *returnCode = ODR_UNSUPP_ACCESS; return 0; } -/* Write value to variable from Object Dictionary disabled, see OD_subEntry_t */ +/* Write value to variable from Object Dictionary disabled, see OD_IO_t */ static OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode) { (void) stream; (void) subIndex; (void) buf; (void) count; - if (returnCode != NULL) *returnCode = ODR_READONLY; + if (returnCode != NULL) *returnCode = ODR_UNSUPP_ACCESS; return 0; } @@ -198,14 +198,15 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { /******************************************************************************/ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, - OD_subEntry_t *subEntry, OD_stream_t *stream, bool_t odOrig) + OD_subEntry_t *subEntry, OD_IO_t *io, bool_t odOrig) { if (entry == NULL || entry->odObject == NULL) return ODR_IDX_NOT_EXIST; - else if (subEntry == NULL || stream == NULL) return ODR_DEV_INCOMPAT; + else if (io == NULL) return ODR_DEV_INCOMPAT; const void *odObjectOrig = entry->odObject; const OD_obj_extended_t *odObjectExt = NULL; uint8_t odBasicType = entry->odObjectType & ODT_TYPE_MASK; + OD_attr_t attr = 0; /* Is object type extended? */ if ((entry->odObjectType & ODT_EXTENSION_MASK) != 0) { @@ -214,42 +215,35 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, if (odObjectOrig == NULL) return ODR_DEV_INCOMPAT; } - /* common properties */ - subEntry->index = entry->index; - subEntry->subIndex = subIndex; - subEntry->subEntriesCount = entry->subEntriesCount; - subEntry->flagsPDO = (odObjectExt != NULL ) ? odObjectExt->flagsPDO : NULL; - stream->dataOffset = 0; - /* attribute, dataObjectOriginal and dataLength, depends on object type */ if (odBasicType == ODT_VAR) { if (subIndex > 0) return ODR_SUB_NOT_EXIST; const OD_obj_var_t *odo = (const OD_obj_var_t *)odObjectOrig; - subEntry->attribute = odo->attribute; - stream->dataObjectOriginal = odo->data; - stream->dataLength = odo->dataLength; + attr = odo->attribute; + io->stream.dataObjectOriginal = odo->data; + io->stream.dataLength = odo->dataLength; } else if (odBasicType == ODT_ARR) { if (subIndex >= entry->subEntriesCount) return ODR_SUB_NOT_EXIST; const OD_obj_array_t *odo = (const OD_obj_array_t *)odObjectOrig; if (subIndex == 0) { - subEntry->attribute = odo->attribute0; - stream->dataObjectOriginal = odo->data0; - stream->dataLength = 1; + attr = odo->attribute0; + io->stream.dataObjectOriginal = odo->data0; + io->stream.dataLength = 1; } else { - subEntry->attribute = odo->attribute; + attr = odo->attribute; if (odo->data == NULL) { - stream->dataObjectOriginal = NULL; + io->stream.dataObjectOriginal = NULL; } else { char *data = (char *)odo->data; int i = subIndex - 1; - stream->dataObjectOriginal = data + odo->dataElementSizeof * i; + io->stream.dataObjectOriginal = data + odo->dataElementSizeof * i; } - stream->dataLength = odo->dataElementLength; + io->stream.dataLength = odo->dataElementLength; } } else if (odBasicType == ODT_REC) { @@ -263,9 +257,9 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, } if (odo == NULL) return ODR_SUB_NOT_EXIST; - subEntry->attribute = odo->attribute; - stream->dataObjectOriginal = odo->data; - stream->dataLength = odo->dataLength; + attr = odo->attribute; + io->stream.dataObjectOriginal = odo->data; + io->stream.dataLength = odo->dataLength; } else { return ODR_DEV_INCOMPAT; @@ -273,17 +267,28 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, /* read, write and dataObject, direct or with IO extension */ if (odObjectExt == NULL || odObjectExt->extIO == NULL || odOrig) { - subEntry->read = OD_readOriginal; - subEntry->write = OD_writeOriginal; - stream->object = NULL; + io->read = OD_readOriginal; + io->write = OD_writeOriginal; + io->stream.object = NULL; } else { - subEntry->read = odObjectExt->extIO->read != NULL ? - odObjectExt->extIO->read : OD_readDisabled; - subEntry->write = odObjectExt->extIO->write != NULL ? - odObjectExt->extIO->write : OD_writeDisabled; - stream->object = odObjectExt->extIO->object; + io->read = odObjectExt->extIO->read != NULL ? + odObjectExt->extIO->read : OD_readDisabled; + io->write = odObjectExt->extIO->write != NULL ? + odObjectExt->extIO->write : OD_writeDisabled; + io->stream.object = odObjectExt->extIO->object; + } + + /* common properties */ + if (subEntry != NULL) { + subEntry->index = entry->index; + subEntry->subIndex = subIndex; + subEntry->subEntriesCount = entry->subEntriesCount; + subEntry->attribute = attr; + subEntry->flagsPDO = odObjectExt != NULL ? + odObjectExt->flagsPDO : NULL; } + io->stream.dataOffset = 0; return ODR_OK; } @@ -324,34 +329,34 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { } /******************************************************************************/ -bool_t OD_extensionIO_init(const OD_entry_t *entry, - void *object, - OD_size_t (*read)(OD_stream_t *stream, +ODR_t OD_extensionIO_init(const OD_entry_t *entry, + void *object, + OD_size_t (*read)(OD_stream_t *stream, + uint8_t subIndex, + void *buf, + OD_size_t count, + ODR_t *returnCode), + OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, - void *buf, + const void *buf, OD_size_t count, - ODR_t *returnCode), - OD_size_t (*write)(OD_stream_t *stream, - uint8_t subIndex, - const void *buf, - OD_size_t count, - ODR_t *returnCode)) + ODR_t *returnCode)) { - if (entry == NULL || (entry->odObjectType & ODT_EXTENSION_MASK) == 0) { - return false; + if (entry == NULL) { + return ODR_IDX_NOT_EXIST; } const OD_obj_extended_t *odo = (const OD_obj_extended_t *) entry->odObject; - if (odo->extIO == NULL) { - return false; + if ((entry->odObjectType & ODT_EXTENSION_MASK) == 0 || odo->extIO == NULL) { + return ODR_PAR_INCOMPAT; } odo->extIO->object = object; odo->extIO->read = read; odo->extIO->write = write; - return true; + return ODR_OK; } @@ -359,110 +364,120 @@ bool_t OD_extensionIO_init(const OD_entry_t *entry, ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t *val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.read(&st, subIndex, val, sizeof(*val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); return ret; } @@ -470,210 +485,304 @@ ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t val, bool_t odOrig) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, odOrig); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); - if (ret == ODR_OK && st.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) subEntry.write(&st, subIndex, &val, sizeof(val), &ret); + if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) + ret = ODR_TYPE_MISMATCH; + if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } /******************************************************************************/ ODR_t OD_getPtr_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t **val) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (int8_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (int8_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t **val) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (int16_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (int16_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t **val) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (int32_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (int32_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t **val) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (int64_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (int64_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t **val) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (uint8_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (uint8_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t **val) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (uint16_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (uint16_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t **val) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (uint32_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (uint32_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t **val) { - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (uint64_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (uint64_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t **val){ - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); - - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (float32_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (float32_t *)io.stream.dataObjectOriginal; return ret; } ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val){ - OD_subEntry_t subEntry; OD_stream_t st; - ODR_t ret = OD_getSub(entry, subIndex, &subEntry, &st, true); + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL) + ret = ODR_DEV_INCOMPAT; + else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) + ret = ODR_TYPE_MISMATCH; + else if (ret == ODR_OK) + *val = (float64_t *)io.stream.dataObjectOriginal; + return ret; +} - if (ret == ODR_OK && st.dataLength != sizeof(**val))ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) *val = (float64_t *)st.dataObjectOriginal; - if (*val == NULL) ret = ODR_DEV_INCOMPAT; +ODR_t OD_getPtr_vs(const OD_entry_t *entry, uint8_t subIndex, + char **val, OD_size_t *dataLength) +{ + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL + || io.stream.dataLength == 0) + { + ret = ODR_DEV_INCOMPAT; + } + else if (ret == ODR_OK) { + *val = (char *)io.stream.dataObjectOriginal; + if (dataLength != NULL) *dataLength = io.stream.dataLength; + } + return ret; +} + +ODR_t OD_getPtr_os(const OD_entry_t *entry, uint8_t subIndex, + uint8_t **val, OD_size_t *dataLength) +{ + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL + || io.stream.dataLength == 0) + { + ret = ODR_DEV_INCOMPAT; + } + else if (ret == ODR_OK) { + *val = (uint8_t *)io.stream.dataObjectOriginal; + if (dataLength != NULL) *dataLength = io.stream.dataLength; + } + return ret; +} + +ODR_t OD_getPtr_us(const OD_entry_t *entry, uint8_t subIndex, + uint16_t **val, OD_size_t *dataLength) +{ + OD_IO_t io; + ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + + if (val == NULL || io.stream.dataObjectOriginal == NULL + || io.stream.dataLength == 0) + { + ret = ODR_DEV_INCOMPAT; + } + else if (ret == ODR_OK) { + *val = (uint16_t *)io.stream.dataObjectOriginal; + if (dataLength != NULL) *dataLength = io.stream.dataLength; + } return ret; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index b85bd10b..f94b3496 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -190,29 +190,6 @@ typedef enum { } ODR_t; -/** - * IO stream structure, used for read/write access to OD variable. - * - * Structure is initialized with @ref OD_getSub() function. - */ -typedef struct { - /** Pointer to original data object, defined by Object Dictionary. Default - * read/write functions operate on it. If memory for data object is not - * specified by Object Dictionary, then dataObjectOriginal is NULL. - */ - void *dataObjectOriginal; - /** Pointer to object, passed by @ref OD_extensionIO_init(). Can be used - * inside read / write functions from IO extension. - */ - void *object; - /** Data length in bytes or 0, if length is not specified */ - OD_size_t dataLength; - /** In case of large data, dataOffset indicates position of already - * transferred data */ - OD_size_t dataOffset; -} OD_stream_t; - - /** * Structure describing properties of a variable, located in specific index and * sub-index inside the Object Dictionary. @@ -251,6 +228,39 @@ typedef struct { * mapped. */ OD_flagsPDO_t *flagsPDO; +} OD_subEntry_t; + + +/** + * IO stream structure, used for read/write access to OD variable, part of + * @ref OD_IO_t. + */ +typedef struct { + /** Pointer to original data object, defined by Object Dictionary. Default + * read/write functions operate on it. If memory for data object is not + * specified by Object Dictionary, then dataObjectOriginal is NULL. + */ + void *dataObjectOriginal; + /** Pointer to object, passed by @ref OD_extensionIO_init(). Can be used + * inside read / write functions from IO extension. + */ + void *object; + /** Data length in bytes or 0, if length is not specified */ + OD_size_t dataLength; + /** In case of large data, dataOffset indicates position of already + * transferred data */ + OD_size_t dataOffset; +} OD_stream_t; + + +/** + * Structure for input / output on the OD variable. It is initialized with + * @ref OD_getSub() function. Access principle to OD variable is via read/write + * functions operating on stream, similar as standard read/write. + */ +typedef struct { + /** Object Dictionary stream object, passed to read or write */ + OD_stream_t stream; /** * Function pointer for reading value from specified variable from Object * Dictionary. If OD variable is larger than buf, then this function must @@ -260,21 +270,20 @@ typedef struct { * * Read can be restarted with @ref OD_rwRestart() function. * - * At the moment, when Object Dictionary is initialised, every variable has + * At the moment, when Object Dictionary is initialized, every variable has * assigned the same "read" function. This default function simply copies * data from Object Dictionary variable. Application can bind its own "read" * function for specific object. In that case application is able to * calculate data for reading from own internal state at the moment of * "read" function call. For this functionality OD object must have IO - * extension enabled. OD object must also be initialised with + * extension enabled. OD object must also be initialized with * @ref OD_extensionIO_init() function call. * * "read" function must always copy all own data to buf, except if "buf" is * not large enough. ("*returnCode" must not return 'ODR_PARTIAL', if there * is still space in "buf".) * - * @param stream Object Dictionary stream object, returned from - * @ref OD_getSub() function, see @ref OD_stream_t. + * @param stream Object Dictionary stream object. * @param subIndex Object Dictionary subIndex of the accessed element. * @param buf Pointer to external buffer, where to data will be copied. * @param count Size of the external buffer in bytes. @@ -301,8 +310,7 @@ typedef struct { * "write" function must always copy all available data from buf. If OD * variable expect more data, then "*returnCode" must return 'ODR_PARTIAL'. * - * @param stream Object Dictionary stream object, returned from - * @ref OD_getSub() function, see @ref OD_stream_t. + * @param stream Object Dictionary stream object. * @param subIndex Object Dictionary subIndex of the accessed element. * @param buf Pointer to external buffer, from where data will be copied. * @param count Size of the external buffer in bytes. @@ -313,23 +321,6 @@ typedef struct { */ OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode); -} OD_subEntry_t; - - -/** - * Helper structure for storing all objects necessary for frequent read from or - * write to specific OD variable. Structure can be used by application and can - * be filled inside and after @ref OD_getSub() function call. - */ -typedef struct { - /** Object passed to read or write */ - OD_stream_t stream; - /** Read function pointer, see @ref OD_subEntry_t */ - OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, ODR_t *returnCode); - /** Write function pointer, see @ref OD_subEntry_t */ - OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, ODR_t *returnCode); } OD_IO_t; @@ -370,8 +361,8 @@ typedef struct { * This function can be used inside read / write functions, specified by * @ref OD_extensionIO_init(). It reads data directly from memory location * specified by Object dictionary. If no IO extension is used on OD entry, then - * subEntry->read returned by @ref OD_getSub() equals to this function. See - * also @ref OD_subEntry_t. + * io->read returned by @ref OD_getSub() equals to this function. See + * also @ref OD_IO_t. */ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, ODR_t *returnCode); @@ -383,8 +374,8 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, * This function can be used inside read / write functions, specified by * @ref OD_extensionIO_init(). It writes data directly to memory location * specified by Object dictionary. If no IO extension is used on OD entry, then - * subEntry->write returned by @ref OD_getSub() equals to this function. See - * also @ref OD_subEntry_t. + * io->write returned by @ref OD_getSub() equals to this function. See + * also @ref OD_IO_t. */ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode); @@ -403,19 +394,19 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index); /** * Find sub-object with specified sub-index on OD entry returned by OD_find. - * Function populates subEntry and stream structures with sub-object data. + * Function populates subEntry and io structures with sub-object data. * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. - * @param [out] subEntry Structure will be populated on success. - * @param [out] stream Structure will be populated on success. + * @param [out] subEntry Structure will be populated on success, may be NULL. + * @param [out] io Structure will be populated on success. * @param odOrig If true, then potential IO extension on entry will be * ignored and access to data entry in the original OD location will be returned * * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, - OD_subEntry_t *subEntry, OD_stream_t *stream, bool_t odOrig); + OD_subEntry_t *subEntry, OD_IO_t *io, bool_t odOrig); /** @@ -437,8 +428,7 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { * @ref OD_getSub(). It is also not necessary to call this function, if prevous * read or write was successfully finished. * - * @param stream Object Dictionary stream object, returned from - * @ref OD_getSub() function, see @ref OD_stream_t. + * @param stream Object Dictionary stream object. */ static inline void OD_rwRestart(OD_stream_t *stream) { stream->dataOffset = 0; @@ -482,25 +472,26 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); * @param object Object, which will be passed to read or write function. * @param read Read function pointer. If NULL, then read will be disabled. * @ref OD_readOriginal can be used here to keep original read function. - * For function description see @ref OD_subEntry_t. + * For function description see @ref OD_IO_t. * @param write Write function pointer. If NULL, then write will be disabled. * @ref OD_writeOriginal can be used here to keep original write function. - * For function description see @ref OD_subEntry_t. + * For function description see @ref OD_IO_t. * - * @return true on success, false if OD object doesn't exist or is not extended. + * @return "ODR_OK" on success, "ODR_IDX_NOT_EXIST" if OD object doesn't exist, + * "ODR_PAR_INCOMPAT" if OD object is not extended. */ -bool_t OD_extensionIO_init(const OD_entry_t *entry, - void *object, - OD_size_t (*read)(OD_stream_t *stream, +ODR_t OD_extensionIO_init(const OD_entry_t *entry, + void *object, + OD_size_t (*read)(OD_stream_t *stream, + uint8_t subIndex, + void *buf, + OD_size_t count, + ODR_t *returnCode), + OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, - void *buf, + const void *buf, OD_size_t count, - ODR_t *returnCode), - OD_size_t (*write)(OD_stream_t *stream, - uint8_t subIndex, - const void *buf, - OD_size_t count, - ODR_t *returnCode)); + ODR_t *returnCode)); /** @@ -630,6 +621,31 @@ ODR_t OD_getPtr_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t **val); ODR_t OD_getPtr_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t **val); /** Get pointer to float64_t variable from OD, see @ref OD_getPtr_i8 */ ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val); +/** + * Get pointer to "visible string" variable from Object Dictionary + * + * Function always returns "dataObjectOriginal" pointer, which points to data + * in the original OD location. Take care, if IO extension is enabled on OD + * entry. + * + * @param entry OD entry returned by @ref OD_find(). + * @param subIndex Sub-index of the variable from the OD object. + * @param [out] val Pointer to variable will be written here. + * @param [out] dataLength Total variable length will be written here, may be + * NULL. + * + * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if + * variable does not exist in object dictionary or it has zero length or other + * reason. + */ +ODR_t OD_getPtr_vs(const OD_entry_t *entry, uint8_t subIndex, + char **val, OD_size_t *dataLength); +/** Get pointer to "octet string" variable from OD, see @ref OD_getPtr_vs */ +ODR_t OD_getPtr_os(const OD_entry_t *entry, uint8_t subIndex, + uint8_t **val, OD_size_t *dataLength); +/** Get pointer to "unicode string" variable from OD, see @ref OD_getPtr_vs */ +ODR_t OD_getPtr_us(const OD_entry_t *entry, uint8_t subIndex, + uint16_t **val, OD_size_t *dataLength); /** @} */ /* CO_ODgetSetters */ @@ -716,10 +732,10 @@ typedef struct { typedef struct { /** Object on which read and write will operate */ void *object; - /** Application specified function pointer, see @ref OD_subEntry_t. */ + /** Application specified function pointer, see @ref OD_IO_t. */ OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, ODR_t *returnCode); - /** Application specified function pointer, see @ref OD_subEntry_t. */ + /** Application specified function pointer, see @ref OD_IO_t. */ OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode); } OD_extensionIO_t; diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index c9c96951..6c497f35 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -158,9 +158,9 @@ static void CO_SDOclient_receive(void *object, void *msg) { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC /* - * Custom function for writing OD variable _SDO client parameter_ + * Custom function for writing OD object _SDO client parameter_ * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_write_1280(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, @@ -289,10 +289,11 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC - if (!OD_extensionIO_init(OD_1280_SDOcliPar, - (void *)SDO_C, - OD_readOriginal, - OD_write_1280)) { + ODR_t odRetE = OD_extensionIO_init(OD_1280_SDOcliPar, + (void *)SDO_C, + OD_readOriginal, + OD_write_1280); + if (odRetE != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1280_SDOcliPar)); return CO_ERROR_OD_PARAMETERS; } @@ -518,7 +519,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, OD_subEntry_t subEntry; odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, - &subEntry, &SDO_C->OD_IO.stream, false); + &subEntry, &SDO_C->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); @@ -528,13 +529,10 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, abortCode = CO_SDO_AB_READONLY; ret = CO_SDO_RT_endedWithClientAbort; } - else if (subEntry.write == NULL) { + else if (SDO_C->OD_IO.write == NULL) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; } - else { - SDO_C->OD_IO.write = subEntry.write; - } } /* write data, in several passes if necessary */ if (SDO_C->OD_IO.write != NULL) { @@ -1099,7 +1097,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, OD_subEntry_t subEntry; odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, - &subEntry, &SDO_C->OD_IO.stream, false); + &subEntry, &SDO_C->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); @@ -1109,13 +1107,10 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, abortCode = CO_SDO_AB_WRITEONLY; ret = CO_SDO_RT_endedWithClientAbort; } - else if (subEntry.read == NULL) { + else if (SDO_C->OD_IO.read == NULL) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; } - else { - SDO_C->OD_IO.read = subEntry.read; - } } size_t countFifo = CO_fifo_getSpace(&SDO_C->bufFifo); diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 5231a533..412296d9 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -154,7 +154,7 @@ static void CO_SDO_receive(void *object, void *msg) { * Custom function for reading OD variable _SDO server parameter_, default * channel * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_read_1200_default(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, @@ -254,10 +254,10 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC /* - * Custom function for writing OD variable _SDO server parameter_, additional + * Custom function for writing OD object _SDO server parameter_, additional * channels * - * For more information see file CO_ODinterface.h, OD_subEntry_t. + * For more information see file CO_ODinterface.h, OD_IO_t. */ static OD_size_t OD_write_1201_additional(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, @@ -385,11 +385,11 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; - if (!OD_extensionIO_init(OD_1200_SDOsrvPar, - (void *) SDO, - OD_read_1200_default, - NULL) - ) { + ODR_t odRetE = OD_extensionIO_init(OD_1200_SDOsrvPar, + (void *) SDO, + OD_read_1200_default, + NULL); + if (odRetE != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1200_SDOsrvPar)); return CO_ERROR_OD_PARAMETERS; } @@ -422,11 +422,11 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, ? (uint16_t)(COB_IDServerToClient32 & 0x7FF) : 0; #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC - if (!OD_extensionIO_init(OD_1200_SDOsrvPar, - (void *) SDO, - OD_readOriginal, - OD_write_1201_additional) - ) { + ODR_t odRetE = OD_extensionIO_init(OD_1200_SDOsrvPar, + (void *) SDO, + OD_readOriginal, + OD_write_1201_additional); + if (odRetE != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1200_SDOsrvPar)); return CO_ERROR_OD_PARAMETERS; } @@ -548,15 +548,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, | SDO->CANrxData[1]; SDO->subIndex = SDO->CANrxData[3]; odRet = OD_getSub(OD_find(SDO->OD, SDO->index), SDO->subIndex, - &subEntry, &SDO->OD_IO.stream, false); + &subEntry, &SDO->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); SDO->state = CO_SDO_ST_ABORT; } else { SDO->attribute = subEntry.attribute; - SDO->OD_IO.read = subEntry.read; - SDO->OD_IO.write = subEntry.write; /* verify read/write attributes */ if (upload && (SDO->attribute & ODA_SDO_R) == 0) { diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 69941a96..7b6cdd94 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -43,8 +43,7 @@ void myFunc(const OD_t *od) { /* Init IO for "Manufacturer device name" at index 0x1008, sub-index 0x00 */ entry = OD_find(od, 0x1008); - ret = OD_getSub(entry, 0x00, &subEntry, &io1008.stream, false); - io1008.read = subEntry.read; + ret = OD_getSub(entry, 0x00, &subEntry, &io1008, false); /* Read with io1008, subindex = 0x00 */ if (ret == ODR_OK) bytesRd = io1008.read(&io1008.stream, 0x00, &buf[0], sizeof(buf), &ret); From 9e9fce74a96e18468b295a14b8ef670b1bbe8f9a Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 24 Dec 2020 14:15:10 +0100 Subject: [PATCH 142/520] Updates and testing of OD interface, SDO server, SDO client, gateway, etc. - SDO server: Change behavior for string data type + fixes + test all - SDO client: fixes + test all - OD interface: Special behavior for string data type - CO_driver.h: added default debug configuration macros + fix spelling - Gateway + fifo: added base64 support + updates - CO_CANopenInit() - added arguments. - update some documentation - CO_epoll_interface fixes. - CO_main_basic.c updates --- 301/CO_ODinterface.h | 10 +- 301/CO_SDOclient.c | 246 ++++++++--- 301/CO_SDOclient.h | 11 +- 301/CO_SDOserver.c | 726 ++++++++++++++++++--------------- 301/CO_SDOserver.h | 4 +- 301/CO_config.h | 33 +- 301/CO_driver.h | 21 +- 301/CO_fifo.c | 454 ++++++++++++++++----- 301/CO_fifo.h | 40 +- 309/CO_gateway_ascii.c | 300 +++++++++----- 309/CO_gateway_ascii.h | 25 +- CANopen.c | 10 +- CANopen.h | 10 +- Makefile | 1 + README.md | 6 +- doc/gettingStarted.md | 6 +- doc/objectDictionary.md | 10 +- example/CO_driver_target.h | 12 +- socketCAN/CO_driver_target.h | 20 +- socketCAN/CO_epoll_interface.c | 32 +- socketCAN/CO_error_msgs.h | 1 + socketCAN/CO_main_basic.c | 95 +++-- 22 files changed, 1384 insertions(+), 689 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index f94b3496..9822efd7 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -118,14 +118,16 @@ typedef enum { ODA_RSRDO = 0x20, /**< Variable is mappable into receiving SRDO */ ODA_TRSRDO = 0x30, /**< Variable is mappable into tx or rx SRDO */ ODA_MB = 0x40, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */ - ODA_RESERVED = 0x80, /**< Reserved for further use */ + ODA_STR = 0x80 /**< Shorter value, than specified variable size, may be + written to the variable. SDO write will fill remaining memory with zeroes. + Attribute is used for VISIBLE_STRING and UNICODE_STRING. */ } OD_attributes_t; /** * Return codes from OD access functions. * - * @ref OD_getSDOabCode() can be used to retrive corresponding SDO abort code. + * @ref OD_getSDOabCode() can be used to retrieve corresponding SDO abort code. */ typedef enum { /* !!!! WARNING !!!! @@ -177,9 +179,9 @@ typedef enum { ODR_GENERAL = 20, /** SDO abort 0x08000020 - Data cannot be transferred or stored to app */ ODR_DATA_TRANSF = 21, - /** SDO abort 0x08000021 - Data can't be transf (local control) */ + /** SDO abort 0x08000021 - Data can't be transferred (local control) */ ODR_DATA_LOC_CTRL = 22, - /** SDO abort 0x08000022 - Data can't be transf (present device state) */ + /** SDO abort 0x08000022 - Data can't be transf. (present device state) */ ODR_DATA_DEV_STATE = 23, /** SDO abort 0x08000023 - Object dictionary not present */ ODR_OD_MISSING = 23, diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 6c497f35..1d979662 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -61,20 +61,20 @@ * description of parameters see file CO_driver.h. */ static void CO_SDOclient_receive(void *object, void *msg) { - CO_SDOclient_t *SDO_C; + CO_SDOclient_t *SDO_C = (CO_SDOclient_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); - /* change void pointer to correct object type */ - SDO_C = (CO_SDOclient_t*)object; - - /* verify idle state, message length and message overflow (previous message - * was not processed yet) */ + /* Ignore messages in idle state and messages with wrong length. Ignore + * message also if previous message was not processed yet and not abort */ if (SDO_C->state != CO_SDO_ST_IDLE && DLC == 8U - && !CO_FLAG_READ(SDO_C->CANrxNew) + && (!CO_FLAG_READ(SDO_C->CANrxNew) || data[0] == 0x80) ) { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - if (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { + if (data[0] == 0x80 /* abort from server */ + || (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ + && SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP) + ) { #endif /* copy data and set 'new message' flag */ memcpy((void *)&SDO_C->CANrxData[0], (const void *)&data[0], 8); @@ -89,21 +89,17 @@ static void CO_SDOclient_receive(void *object, void *msg) { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK } - else { + else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { /* block upload, copy data directly */ CO_SDO_state_t state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; - uint8_t seqno; - - seqno = data[0] & 0x7F; + uint8_t seqno = data[0] & 0x7F; SDO_C->timeoutTimer = 0; SDO_C->block_timeoutTimer = 0; - /* break sub-block if sequence number is too large */ - if (seqno > SDO_C->block_blksize) { - state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; - } /* verify if sequence number is correct */ - else if (seqno == (SDO_C->block_seqno + 1)) { + if (seqno <= SDO_C->block_blksize + && seqno == (SDO_C->block_seqno + 1) + ) { SDO_C->block_seqno = seqno; /* is this the last segment? */ @@ -128,18 +124,33 @@ static void CO_SDOclient_receive(void *object, void *msg) { } } } - else if (seqno == SDO_C->block_seqno || SDO_C->block_seqno == 0U) { - /* Ignore message, if it is duplicate or if sequence didn't - * start yet. */ + /* If message is duplicate or sequence didn't start yet, ignore + * it. Otherwise seqno is wrong, so break sub-block. Data after + * last good seqno will be re-transmitted. */ + else if (seqno != SDO_C->block_seqno && SDO_C->block_seqno != 0U) { + state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; +#ifdef CO_DEBUG_SDO_CLIENT + char msg[80]; + sprintf(msg, + "sub-block, rx WRONG: sequno=%02X, previous=%02X", + seqno, SDO_C->block_seqno); + CO_DEBUG_SDO_CLIENT(msg); +#endif } +#ifdef CO_DEBUG_SDO_CLIENT else { - /* seqno is totally wrong, break sub-block. Data after last good - * seqno will be re-transmitted. */ - state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; + char msg[80]; + sprintf(msg, + "sub-block, rx ignored: sequno=%02X, expected=%02X", + seqno, SDO_C->block_seqno + 1); + CO_DEBUG_SDO_CLIENT(msg); } +#endif + + /* Is exit from sub-block receive state? */ if (state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { - /* SDO_C->state has changed, processing will continue in another - * thread. Make memory barrier here with CO_FLAG_CLEAR() call.*/ + /* Processing will continue in another thread, so make memory + * barrier here with CO_FLAG_CLEAR() call. */ CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->state = state; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE @@ -329,6 +340,19 @@ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, } #endif +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) && defined CO_BIG_ENDIAN +static inline void reverseBytes(void *start, OD_size_t size) { + uint8_t *lo = (uint8_t *)start; + uint8_t *hi = (uint8_t *)start + size - 1; + uint8_t swap; + while (lo < hi) { + swap = *lo; + *lo++ = *hi; + *hi-- = swap; + } +} +#endif + /******************************************************************************/ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, @@ -505,14 +529,9 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else if (SDO_C->state == CO_SDO_ST_IDLE) { ret = CO_SDO_RT_ok_communicationEnd; } - else if (abort) { - abortCode = - (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; - SDO_C->state = CO_SDO_ST_ABORT; - } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ - else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) { + else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER && !abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.write == NULL) { ODR_t odRet; @@ -521,11 +540,17 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, &subEntry, &SDO_C->OD_IO, false); + SDO_C->attribute = subEntry.attribute; + if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithClientAbort; } - else if ((subEntry.attribute & ODA_SDO_W) == 0) { + else if ((SDO_C->attribute & ODA_SDO_RW) == 0) { + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; + ret = CO_SDO_RT_endedWithClientAbort; + } + else if ((SDO_C->attribute & ODA_SDO_W) == 0) { abortCode = CO_SDO_AB_READONLY; ret = CO_SDO_RT_endedWithClientAbort; } @@ -537,7 +562,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* write data, in several passes if necessary */ if (SDO_C->OD_IO.write != NULL) { size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo); - char buf[count]; + char buf[count + 2]; CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); SDO_C->sizeTran += count; @@ -553,9 +578,51 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, abortCode = CO_SDO_AB_DATA_LONG; ret = CO_SDO_RT_endedWithClientAbort; } - else { + /* Verify sizeTran is too small in last segment of data */ + else if (!bufferPartial + && SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + ret = CO_SDO_RT_endedWithClientAbort; + } + /* is the last segment of data? */ + else if (!bufferPartial) { +#ifdef CO_BIG_ENDIAN + /* swap int16_t .. uint64_t data if necessary */ + if ((SDO_C->attribute & ODA_MB) != 0) { + reverseBytes(buf, count); + } +#endif + OD_size_t sizeInOd = SDO_C->OD_IO.stream.dataLength; + + /* If dataType is string, then size of data downloaded may be + * shorter than size of OD data buffer. If so, add two zero + * bytes to terminate (unicode) string. Shorten also OD data + * size, (temporary, send info about EOF into OD_IO.write) */ + if ((SDO_C->attribute & ODA_STR) != 0 + && (sizeInOd == 0 || SDO_C->sizeTran < sizeInOd) + ) { + buf[count++] = 0; + SDO_C->sizeTran++; + if (sizeInOd == 0 || sizeInOd > SDO_C->sizeTran) { + buf[count++] = 0; + SDO_C->sizeTran++; + } + SDO_C->OD_IO.stream.dataLength = SDO_C->sizeTran; + } + /* Indicate OD data size, if necessary. Used for EOF check. */ + else if (sizeInOd == 0) { + SDO_C->OD_IO.stream.dataLength = SDO_C->sizeTran; + } + /* Verify if size of data downloaded matches data size in OD. */ + else if (SDO_C->sizeTran != sizeInOd) { + abortCode = (SDO_C->sizeTran > sizeInOd) ? + CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + ret = CO_SDO_RT_endedWithClientAbort; + } + } + if (abortCode == CO_SDO_AB_NONE) { ODR_t odRet; - /* write data to Object Dictionary */ SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, SDO_C->subIndex, buf, count, &odRet); @@ -565,7 +632,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithServerAbort; } - /* error if OD variable was written completelly, + /* error if OD variable was written completely, * but SDO download still has data */ else if (bufferPartial && odRet == ODR_OK) { abortCode = CO_SDO_AB_DATA_LONG; @@ -579,13 +646,6 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; } - /* Verify size transferred */ - else if (SDO_C->sizeInd > 0 - && SDO_C->sizeTran < SDO_C->sizeInd - ) { - abortCode = CO_SDO_AB_DATA_SHORT; - ret = CO_SDO_RT_endedWithClientAbort; - } /* data transfer finished successfully */ else { ret = CO_SDO_RT_ok_communicationEnd; @@ -600,8 +660,14 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (ret != CO_SDO_RT_waitingLocalTransfer) { SDO_C->state = CO_SDO_ST_IDLE; } - } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT + /* Inform OS to call this function again without delay. */ + else if (timerNext_us != NULL) { + *timerNext_us = 0; + } #endif + } +#endif /* CO_CONFIG_SDO_CLI_LOCAL */ /* CAN data received ******************************************************/ else if (CO_FLAG_READ(SDO_C->CANrxNew)) { /* is SDO abort */ @@ -612,6 +678,11 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; } + else if (abort) { + abortCode = (SDOabortCode != NULL) + ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + } else switch (SDO_C->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { if (SDO_C->CANrxData[0] == 0x60) { @@ -771,6 +842,11 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, timeDifference_us = 0; CO_FLAG_CLEAR(SDO_C->CANrxNew); } + else if (abort) { + abortCode = (SDOabortCode != NULL) + ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + } /* Timeout timers *********************************************************/ if (ret == CO_SDO_RT_waitingResponse) { @@ -918,9 +994,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { + if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) < 7 && bufferPartial) { + /* wait until data are refilled */ + break; + } SDO_C->CANtxBuff->data[0] = ++SDO_C->block_seqno; - /* fill data bytes */ + /* get up to 7 data bytes */ count = CO_fifo_altRead(&SDO_C->bufFifo, (char *)&SDO_C->CANtxBuff->data[1], 7); SDO_C->block_noData = 7 - count; @@ -935,7 +1015,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* is end of transfer? Verify also sizeTran */ - if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0 && bufferPartial) { + if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0 && !bufferPartial){ if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; @@ -1038,7 +1118,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; SDO_C->timeoutTimer = 0; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - SDO_C->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 500; + SDO_C->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700; #endif #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL @@ -1071,6 +1151,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, /******************************************************************************/ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, + bool_t abort, CO_SDO_abortCode_t *SDOabortCode, size_t *sizeIndicated, size_t *sizeTransferred, @@ -1090,7 +1171,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ - else if (SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) { + else if (SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER && !abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.read == NULL) { ODR_t odRet; @@ -1099,11 +1180,17 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, &subEntry, &SDO_C->OD_IO, false); + SDO_C->attribute = subEntry.attribute; + if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithClientAbort; } - else if ((subEntry.attribute & ODA_SDO_R) == 0) { + else if ((SDO_C->attribute & ODA_SDO_RW) == 0) { + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; + ret = CO_SDO_RT_endedWithClientAbort; + } + else if ((SDO_C->attribute & ODA_SDO_R) == 0) { abortCode = CO_SDO_AB_WRITEONLY; ret = CO_SDO_RT_endedWithClientAbort; } @@ -1126,7 +1213,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, OD_size_t countData = SDO_C->OD_IO.stream.dataLength; OD_size_t countBuf = (countData > 0 && countData <= countFifo) ? countData : countFifo; - char buf[countBuf]; + char buf[countBuf + 1]; ODR_t odRet; /* load data from OD variable into the buffer */ @@ -1139,6 +1226,20 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ret = CO_SDO_RT_endedWithServerAbort; } else { + /* if data is string, send only data up to null termination */ + if (countRd > 0 && (SDO_C->attribute & ODA_STR) != 0) { + buf[countRd] = 0; /* (buf is one byte larger) */ + OD_size_t countStr = strlen(buf); + if (countStr == 0) countStr = 1; /* ne zero length */ + if (countStr < countRd) { + /* string terminator found, finish read, shorten data */ + countRd = countStr; + odRet = ODR_OK; + SDO_C->OD_IO.stream.dataLength = + SDO_C->sizeTran + countRd; + } + } + CO_fifo_write(&SDO_C->bufFifo, buf, countRd, NULL); SDO_C->sizeTran += countRd; @@ -1170,8 +1271,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ) { SDO_C->state = CO_SDO_ST_IDLE; } - } +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT + /* Inform OS to call this function again without delay. */ + else if (timerNext_us != NULL) { + *timerNext_us = 0; + } #endif + } +#endif /* CO_CONFIG_SDO_CLI_LOCAL */ /* CAN data received ******************************************************/ else if (CO_FLAG_READ(SDO_C->CANrxNew)) { /* is SDO abort */ @@ -1182,6 +1289,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; } + else if (abort) { + abortCode = (SDOabortCode != NULL) + ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + } else switch (SDO_C->state) { case CO_SDO_ST_UPLOAD_INITIATE_RSP: { if ((SDO_C->CANrxData[0] & 0xF0) == 0x40) { @@ -1431,6 +1543,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, timeDifference_us = 0; CO_FLAG_CLEAR(SDO_C->CANrxNew); } + else if (abort) { + abortCode = (SDOabortCode != NULL) + ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + } /* Timeout timers *********************************************************/ if (ret == CO_SDO_RT_waitingResponse) { @@ -1573,6 +1690,10 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { SDO_C->CANtxBuff->data[0] = 0xA2; SDO_C->CANtxBuff->data[1] = SDO_C->block_seqno; +#ifdef CO_DEBUG_SDO_CLIENT + bool_t transferShort = SDO_C->block_seqno != SDO_C->block_blksize; + uint8_t seqnoStart = SDO_C->block_seqno; +#endif /* Is last segment? */ if (SDO_C->finished) { @@ -1591,9 +1712,18 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, if (count >= 127) { count = 127; } - else if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) > 0) { + else if (CO_fifo_getOccupied(&SDO_C->bufFifo) > 0) { /* application must empty data buffer first */ ret = CO_SDO_RT_uploadDataBufferFull; +#ifdef CO_DEBUG_SDO_CLIENT + if (transferShort) { + char msg[80]; + sprintf(msg, + "sub-block, uploadDataBufferFull: sequno=%02X", + seqnoStart); + CO_DEBUG_SDO_CLIENT(msg); + } +#endif #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT /* Inform OS to call this function again without delay. */ if (timerNext_us != NULL) { @@ -1612,10 +1742,18 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[2] = SDO_C->block_blksize; - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; + /* reset block_timeoutTimer, but not SDO_C->timeoutTimer */ SDO_C->block_timeoutTimer = 0; CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); +#ifdef CO_DEBUG_SDO_CLIENT + if (transferShort && !SDO_C->finished) { + char msg[80]; + sprintf(msg, + "sub-block restarted: sequnoPrev=%02X, blksize=%02X", + seqnoStart, SDO_C->block_blksize); + CO_DEBUG_SDO_CLIENT(msg); + } +#endif break; } diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 33b35b87..5111e5ed 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -37,7 +37,11 @@ #define CO_CONFIG_SDO_CLI (0) #endif #ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE -#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 + #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 + #else + #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 + #endif #endif #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) || defined CO_DOXYGEN @@ -68,6 +72,8 @@ typedef struct { uint8_t nodeId; /** Object dictionary interface for locally transferred object */ OD_IO_t OD_IO; + /** Attribute for locally transferred OD sub-object, see OD_attributes_t */ + OD_attr_t attribute; #endif /** From CO_SDOclient_init() */ CO_CANmodule_t *CANdevRx; @@ -371,6 +377,8 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, * @param SDO_C This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. + * @param abort If true, SDO client will send abort message from SDOabortCode + * and reception will be aborted. * @param [out] SDOabortCode In case of error in communication, SDO abort code * contains reason of error. Ignored if NULL. * @param [out] sizeIndicated If larger than 0, then SDO server has indicated @@ -385,6 +393,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, */ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, + bool_t abort, CO_SDO_abortCode_t *SDOabortCode, size_t *sizeIndicated, size_t *sizeTransferred, diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 412296d9..a57a63d5 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -30,8 +30,8 @@ /* verify configuration */ #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED - #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 8 - #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 8. + #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 20 + #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 20. #endif #endif #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK @@ -41,8 +41,8 @@ #if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) #error CO_CONFIG_CRC16_ENABLE must be enabled. #endif - #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < (127*7) - #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than (127*7). + #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 900 + #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 900. #endif #endif @@ -58,14 +58,15 @@ static void CO_SDO_receive(void *object, void *msg) { uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); - - /* verify message length and message queue overflow (if previous message - * was not processed yet) */ - if (DLC == 8 && !CO_FLAG_READ(SDO->CANrxNew)) { + /* ignore messages with wrong length */ + if (DLC == 8) { if (data[0] == 0x80) { /* abort from client, just make idle */ SDO->state = CO_SDO_ST_IDLE; } + else if (CO_FLAG_READ(SDO->CANrxNew)) { + /* ignore message if previous message was not processed yet */ + } #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK else if (SDO->state == CO_SDO_ST_UPLOAD_BLK_END_CRSP && data[0]==0xA1) { /* SDO block download successfully transferred, just make idle */ @@ -73,21 +74,17 @@ static void CO_SDO_receive(void *object, void *msg) { } else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { /* just in case, condition should always pass */ - if (SDO->bufOffsetWr <= (CO_CONFIG_SDO_SRV_BUFFER_SIZE - 7)) { + if (SDO->bufOffsetWr <= (CO_CONFIG_SDO_SRV_BUFFER_SIZE - (7+2))) { /* block download, copy data directly */ - uint8_t seqno; CO_SDO_state_t state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; - - seqno = data[0] & 0x7F; + uint8_t seqno = data[0] & 0x7F; SDO->timeoutTimer = 0; SDO->block_timeoutTimer = 0; - /* break sub-block if sequence number is too large */ - if (seqno > SDO->block_blksize) { - state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; - } /* verify if sequence number is correct */ - else if (seqno == (SDO->block_seqno + 1)) { + if (seqno <= SDO->block_blksize + && seqno == (SDO->block_seqno + 1) + ) { SDO->block_seqno = seqno; /* Copy data. There is always enough space in buffer, @@ -106,15 +103,28 @@ static void CO_SDO_receive(void *object, void *msg) { state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; } } - else if (seqno == SDO->block_seqno || SDO->block_seqno == 0U) { - /* Ignore message, if it is duplicate or if sequence didn't - * start yet. */ + /* If message is duplicate or sequence didn't start yet, ignore + * it. Otherwise seqno is wrong, so break sub-block. Data after + * last good seqno will be re-transmitted. */ + else if (seqno != SDO->block_seqno && SDO->block_seqno != 0U) { + state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; +#ifdef CO_DEBUG_SDO_SERVER + char msg[80]; + sprintf(msg, + "sub-block, rx WRONG: sequno=%02X, previous=%02X", + seqno, SDO->block_seqno); + CO_DEBUG_SDO_SERVER(msg); +#endif } +#ifdef CO_DEBUG_SDO_SERVER else { - /* seqno is totally wrong, break sub-block. Data after last - * good seqno will be re-transmitted. */ - state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; + char msg[80]; + sprintf(msg, + "sub-block, rx ignored: sequno=%02X, expected=%02X", + seqno, SDO->block_seqno + 1); + CO_DEBUG_SDO_SERVER(msg); } +#endif if (state != CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { /* SDO->state has changed, processing will continue in @@ -132,6 +142,9 @@ static void CO_SDO_receive(void *object, void *msg) { } } } + else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP) { + /* ignore subsequent server messages, if response was requested */ + } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ else { /* copy data and set 'new message' flag, data will be processed in @@ -360,6 +373,9 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, SDO->OD = OD; SDO->nodeId = nodeId; SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + SDO->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700; +#endif SDO->state = CO_SDO_ST_IDLE; #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE @@ -473,10 +489,10 @@ void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, #ifdef CO_BIG_ENDIAN -static inline void reverseBytes(void *start, int size) { - unsigned char *lo = start; - unsigned char *hi = start + size - 1; - unsigned char swap; +static inline void reverseBytes(void *start, OD_size_t size) { + uint8_t *lo = (uint8_t *)start; + uint8_t *hi = (uint8_t *)start + size - 1; + uint8_t swap; while (lo < hi) { swap = *lo; *lo++ = *hi; @@ -486,6 +502,223 @@ static inline void reverseBytes(void *start, int size) { #endif +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +/** Helper function for writing data to Object dictionary. Function swaps data + * if necessary, calcualtes (and verifies CRC) writes data to OD and verifies + * data lengths. + * + * @param SDO SDO server + * @param [out] abortCode SDO abort code in case of error + * @param crcOperation 0=none, 1=calculate, 2=calculate and compare + * @parma crcClient crc checksum to campare with + * + * Returns true on success, otherwise write also abortCode and sets state to + * CO_SDO_ST_ABORT */ +static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, + CO_SDO_abortCode_t *abortCode, + uint8_t crcOperation, + uint16_t crcClient) +{ + OD_size_t bufOffsetWrOrig = SDO->bufOffsetWr; + + if (SDO->finished) { + /* Verify if size of data downloaded matches size indicated. */ + if (SDO->sizeInd > 0 && SDO->sizeTran != SDO->sizeInd) { + *abortCode = (SDO->sizeTran > SDO->sizeInd) ? + CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + return false; + } + +#ifdef CO_BIG_ENDIAN + /* swap int16_t .. uint64_t data if necessary */ + if ((SDO->attribute & ODA_MB) != 0) { + reverseBytes(SDO->buf, SDO->bufOffsetWr); + } +#endif + + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + + /* If dataType is string, then size of data downloaded may be + * shorter than size of OD data buffer. If so, add two zero bytes + * to terminate (unicode) string. Shorten also OD data size, + * (temporary, send information about EOF into OD_IO.write) */ + if ((SDO->attribute & ODA_STR) != 0 + && (sizeInOd == 0 || SDO->sizeTran < sizeInOd) + && (SDO->bufOffsetWr + 2) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE + ) { + SDO->buf[SDO->bufOffsetWr++] = 0; + SDO->sizeTran++; + if (sizeInOd == 0 || SDO->sizeTran < sizeInOd) { + SDO->buf[SDO->bufOffsetWr++] = 0; + SDO->sizeTran++; + } + SDO->OD_IO.stream.dataLength = SDO->sizeTran; + } + /* Indicate OD data size, if not indicated. Can be used for EOF check.*/ + else if (sizeInOd == 0) { + SDO->OD_IO.stream.dataLength = SDO->sizeTran; + } + /* Verify if size of data downloaded matches data size in OD. */ + else if (SDO->sizeTran != sizeInOd) { + *abortCode = (SDO->sizeTran > sizeInOd) ? + CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + return false; + } + } + else { + /* Verify if size of data downloaded is not too large. */ + if (SDO->sizeInd > 0 && SDO->sizeTran > SDO->sizeInd) { + *abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + return false; + } + } + +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + /* calculate crc on current data */ + if (SDO->block_crcEnabled && crcOperation > 0) { + SDO->block_crc = crc16_ccitt((unsigned char *)SDO->buf, + bufOffsetWrOrig, + SDO->block_crc); + if (crcOperation == 2 && crcClient != SDO->block_crc) { + *abortCode = CO_SDO_AB_CRC; + SDO->state = CO_SDO_ST_ABORT; + return false; + } + } +#endif + /* may be unused */ + (void) crcOperation; (void) crcClient; (void) bufOffsetWrOrig; + + /* write data */ + ODR_t odRet; + SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, + SDO->buf, SDO->bufOffsetWr, &odRet); + SDO->bufOffsetWr = 0; + + /* verify write error value */ + if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + *abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + return false; + } + else if (SDO->finished && odRet == ODR_PARTIAL) { + /* OD variable was not written completely, but SDO download finished */ + *abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + return false; + } + else if (!SDO->finished && odRet == ODR_OK) { + /* OD variable was written completely, but SDO download still has data*/ + *abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + return false; + } + + return true; +} + + +/** Helper function for reading data from Object dictionary. Function also swaps + * data if necessary and calcualtes CRC. + * + * @param SDO SDO server + * @param [out] abortCode SDO abort code in case of error + * @parma countMinimum if data size in buffer is less than countMinimum, then + * buffer is refilled from OD variable + * @param calculateCrc if true, crc is calculated + * + * Returns true on success, otherwise write also abortCode and sets state to + * CO_SDO_ST_ABORT */ +static bool_t readFromOd(CO_SDOserver_t *SDO, + CO_SDO_abortCode_t *abortCode, + OD_size_t countMinimum, + bool_t calculateCrc) +{ + OD_size_t countRemain = SDO->bufOffsetWr - SDO->bufOffsetRd; + + if (!SDO->finished && countRemain < countMinimum) { + /* first move remaining data to the start of the buffer */ + memmove(SDO->buf, SDO->buf + SDO->bufOffsetRd, countRemain); + SDO->bufOffsetRd = 0; + SDO->bufOffsetWr = countRemain; + + /* Get size of free data buffer */ + OD_size_t countRdRequest = CO_CONFIG_SDO_SRV_BUFFER_SIZE - countRemain; + + /* load data from OD variable into the buffer */ + ODR_t odRet; + char *bufShifted = SDO->buf + countRemain; + OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, + bufShifted, + countRdRequest, + &odRet); + + if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + *abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + return false; + } + + /* if data is string, send only data up to null termination */ + if (countRd > 0 && (SDO->attribute & ODA_STR) != 0) { + bufShifted[countRd] = 0; /* (SDO->buf is one byte larger) */ + OD_size_t countStr = strlen(bufShifted); + if (countStr == 0) countStr = 1; /* zero length is not allowed */ + if (countStr < countRd) { + /* string terminator found, read is finished, shorten data */ + countRd = countStr; + odRet = ODR_OK; + SDO->OD_IO.stream.dataLength = SDO->sizeTran + countRd; + } + } + + /* partial or finished read */ + SDO->bufOffsetWr = countRemain + countRd; + if (SDO->bufOffsetWr == 0 || odRet == ODR_PARTIAL) { + SDO->finished = false; + if (SDO->bufOffsetWr < countMinimum) { + *abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; + return false; + } + } + else { + SDO->finished = true; + } + +#ifdef CO_BIG_ENDIAN + /* swap data if necessary */ + if ((SDO->attribute & ODA_MB) != 0) { + if (SDO->finished) { + /* int16_t .. uint64_t */ + reverseBytes(bufShifted, countRd); + } + else { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; + return false; + } + } +#endif + +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK + /* update the crc */ + if (calculateCrc && SDO->block_crcEnabled) { + SDO->block_crc = crc16_ccitt((uint8_t *)bufShifted, + countRd, + SDO->block_crc); + } +#endif + + } + return true; +} +#endif + + /******************************************************************************/ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, bool_t NMTisPreOrOperational, @@ -557,7 +790,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->attribute = subEntry.attribute; /* verify read/write attributes */ - if (upload && (SDO->attribute & ODA_SDO_R) == 0) { + if ((SDO->attribute & ODA_SDO_RW) == 0) { + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; + SDO->state = CO_SDO_ST_ABORT; + } + else if (upload && (SDO->attribute & ODA_SDO_R) == 0) { abortCode = CO_SDO_AB_WRITEONLY; SDO->state = CO_SDO_ST_ABORT; } @@ -571,53 +808,30 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED /* load data from object dictionary, if upload and no error */ if (upload && abortCode == CO_SDO_AB_NONE) { - ODR_t odRet; + SDO->bufOffsetRd = SDO->bufOffsetWr = 0; + SDO->sizeTran = 0; + SDO->finished = false; - /* load data from OD variable into the buffer */ - SDO->bufOffsetWr = SDO->OD_IO.read(&SDO->OD_IO.stream, - SDO->subIndex, - SDO->buf, - CO_CONFIG_SDO_SRV_BUFFER_SIZE, - &odRet); - SDO->bufOffsetRd = 0; + if (readFromOd(SDO, &abortCode, 7, false)) { + /* Size of variable in OD (may not be known yet) */ + if (SDO->finished) { + /* OD variable was completely read, its size is known */ - if (odRet != ODR_OK && odRet != ODR_PARTIAL) { - abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); - SDO->state = CO_SDO_ST_ABORT; - } - else if (odRet == ODR_PARTIAL && SDO->bufOffsetWr < 7) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - SDO->state = CO_SDO_ST_ABORT; - } - else { - SDO->finished = (odRet != ODR_PARTIAL); -#ifdef CO_BIG_ENDIAN - /* swap data if necessary */ - if ((SDO->attribute & ODA_MB) != 0) { - if (!SDO->finished) { + SDO->sizeInd = SDO->OD_IO.stream.dataLength; + + if (SDO->sizeInd == 0) { + SDO->sizeInd = SDO->bufOffsetWr; + } + else if (SDO->sizeInd != SDO->bufOffsetWr) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; } - else { - reverseBytes(SDO->buf, SDO->bufOffsetWr); - } } -#endif - } - } - /* get and verify OD data size, if upload and still no error */ - if (upload && abortCode == CO_SDO_AB_NONE) { - /* Size of variable in OD (may not be known yet) */ - SDO->sizeInd = SDO->OD_IO.stream.dataLength; - SDO->sizeTran = 0; - if (SDO->finished) { - /* OD variable was completely read, so its size is known */ - if (SDO->sizeInd == 0) { - SDO->sizeInd = SDO->bufOffsetWr; - } - else if (SDO->sizeInd != SDO->bufOffsetWr) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - SDO->state = CO_SDO_ST_ABORT; + else { + /* If data type is string, size is not known */ + SDO->sizeInd = (SDO->attribute & ODA_STR) == 0 + ? SDO->OD_IO.stream.dataLength + : 0; } } } @@ -629,40 +843,52 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { if (SDO->CANrxData[0] & 0x02) { /* Expedited transfer, max 4 bytes of data */ - OD_size_t sizeIndicated = 4; + + /* Size of OD variable (>0 if indicated) */ OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - ODR_t odRet; - /* is size indicated? */ - if (SDO->CANrxData[0] & 0x01) { - sizeIndicated -= (SDO->CANrxData[0] >> 2) & 0x03; - if (sizeInOd > 0 && sizeIndicated != sizeInOd) { - abortCode = (sizeIndicated < sizeInOd) ? - CO_SDO_AB_DATA_SHORT : - CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; - } - } - else { - if (sizeInOd > 4) { - abortCode = CO_SDO_AB_DATA_SHORT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - else { - sizeIndicated = sizeInOd; - } - } + /* Get SDO data size (indicated by SDO client or get from OD) */ + OD_size_t dataSizeToWrite = 4; + if (SDO->CANrxData[0] & 0x01) + dataSizeToWrite -= (SDO->CANrxData[0] >> 2) & 0x03; + else if (sizeInOd > 0 && sizeInOd < 4) + dataSizeToWrite = sizeInOd; - /* swap data if necessary, then copy data */ + /* copy data to the temp buffer, swap data if necessary */ + uint8_t buf[6] = {0}; + memcpy(buf, &SDO->CANrxData[4], dataSizeToWrite); #ifdef CO_BIG_ENDIAN if ((SDO->attribute & ODA_MB) != 0) { - reverseBytes(&SDO->CANrxData[4], sizeIndicated); + reverseBytes(buf, dataSizeToWrite); } #endif + + /* If dataType is string, then size of data downloaded may be + * shorter as size of OD data buffer. If so, add two zero bytes + * to terminate (unicode) string. Shorten also OD data size, + * (temporary, send information about EOF into OD_IO.write) */ + if ((SDO->attribute & ODA_STR) != 0 + && (sizeInOd == 0 || dataSizeToWrite < sizeInOd) + ) { + OD_size_t delta = sizeInOd - dataSizeToWrite; + dataSizeToWrite += delta == 1 ? 1 : 2; + SDO->OD_IO.stream.dataLength = dataSizeToWrite; + } + else if (sizeInOd == 0) { + SDO->OD_IO.stream.dataLength = dataSizeToWrite; + } + /* Verify if size of data downloaded matches data size in OD. */ + else if (dataSizeToWrite != sizeInOd) { + abortCode = (dataSizeToWrite > sizeInOd) ? + CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + + /* Copy data */ + ODR_t odRet; SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, - &SDO->CANrxData[4], sizeIndicated, &odRet); + buf, dataSizeToWrite, &odRet); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); SDO->state = CO_SDO_ST_ABORT; @@ -686,13 +912,21 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->sizeInd = CO_SWAP_32(size); /* Indicated size of SDO matches sizeof OD variable? */ - if (sizeInOd > 0 && SDO->sizeInd != sizeInOd) { - abortCode = (SDO->sizeInd < sizeInOd) ? - CO_SDO_AB_DATA_SHORT : - CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; - } + if (sizeInOd > 0) { + if (SDO->sizeInd > sizeInOd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } + /* strings are allowed to be shorter */ + else if (SDO->sizeInd < sizeInOd + && (SDO->attribute & ODA_STR) == 0 + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + } } else { SDO->sizeInd = 0; @@ -710,9 +944,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { if ((SDO->CANrxData[0] & 0xE0) == 0x00) { - OD_size_t count; - OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - bool_t lastSegment = (SDO->CANrxData[0] & 0x01) != 0; + SDO->finished = (SDO->CANrxData[0] & 0x01) != 0; /* verify and alternate toggle bit */ uint8_t toggle = SDO->CANrxData[0] & 0x10; @@ -721,17 +953,16 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; break; } - SDO->toggle = (toggle == 0x00) ? 0x10 : 0x00; /* get data size and write data to the buffer */ - count = 7 - ((SDO->CANrxData[0] >> 1) & 0x07); + OD_size_t count = 7 - ((SDO->CANrxData[0] >> 1) & 0x07); memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); SDO->bufOffsetWr += count; SDO->sizeTran += count; - /* verify if size of data downloaded is too large */ - if ((SDO->sizeInd > 0 && SDO->sizeTran > SDO->sizeInd) - || (sizeInOd > 0 && SDO->sizeTran > sizeInOd) + /* if data size exceeds variable size, abort */ + if (SDO->OD_IO.stream.dataLength > 0 + && SDO->sizeTran > SDO->OD_IO.stream.dataLength ) { abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; @@ -739,54 +970,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* if necessary, empty the buffer */ - if (lastSegment - || (CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr) < 7 + if (SDO->finished + || (CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7+2) ) { - ODR_t odRet; -#ifdef CO_BIG_ENDIAN - /* swap data if necessary */ - if ((SDO->attribute & ODA_MB) != 0) { - reverseBytes(SDO->buf, SDO->bufOffsetWr); - } -#endif - /* write data */ - SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, - SDO->buf, SDO->bufOffsetWr, &odRet); - SDO->bufOffsetWr = 0; - - if (odRet != ODR_OK && odRet != ODR_PARTIAL) { - abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); - SDO->state = CO_SDO_ST_ABORT; + if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) break; - } - else if (lastSegment && odRet == ODR_PARTIAL) { - /* OD variable was not written completelly, but SDO - * download finished */ - abortCode = CO_SDO_AB_DATA_SHORT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - else if (!lastSegment && odRet == ODR_OK) { - /* OD variable was written completelly, but SDO download - * still has data */ - abortCode = CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; - } } - /* If no more segments to be downloaded, finish */ - if (lastSegment) { - /* verify size of data */ - if (SDO->sizeInd > 0 && SDO->sizeTran < SDO->sizeInd) { - abortCode = CO_SDO_AB_DATA_SHORT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - else { - SDO->finished = true; - } - } SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; } else { @@ -835,12 +1025,20 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->sizeInd = CO_SWAP_32(size); /* Indicated size of SDO matches sizeof OD variable? */ - if (sizeInOd > 0 && SDO->sizeInd != sizeInOd) { - abortCode = (SDO->sizeInd < sizeInOd) ? - CO_SDO_AB_DATA_SHORT : - CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; + if (sizeInOd > 0) { + if (SDO->sizeInd > sizeInOd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } + /* strings are allowed to be shorter */ + else if (SDO->sizeInd < sizeInOd + && (SDO->attribute & ODA_STR) == 0 + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } } } else { @@ -858,8 +1056,6 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { - ODR_t odRet; - /* Get number of data bytes in last segment, that do not * contain data. Then reduce buffer. */ uint8_t noData = ((SDO->CANrxData[0] >> 2) & 0x07); @@ -872,53 +1068,14 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->sizeTran -= noData; SDO->bufOffsetWr -= noData; - /* verify length */ - if (SDO->sizeInd > 0 && SDO->sizeTran != SDO->sizeInd) { - abortCode = (SDO->sizeTran > SDO->sizeInd) ? - CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - -#ifdef CO_BIG_ENDIAN - /* swap data if necessary */ - if ((SDO->attribute & ODA_MB) != 0) { - reverseBytes(SDO->buf, SDO->bufOffsetWr); - } -#endif - - /* calculeate and verify CRC */ + uint16_t crcClient = 0; if (SDO->block_crcEnabled) { - uint16_t crcClient; - SDO->block_crc = crc16_ccitt((unsigned char *)SDO->buf, - SDO->bufOffsetWr, - SDO->block_crc); - crcClient = ((uint16_t) SDO->CANrxData[2]) << 8; crcClient |= SDO->CANrxData[1]; - if (crcClient != SDO->block_crc) { - abortCode = CO_SDO_AB_CRC; - SDO->state = CO_SDO_ST_ABORT; - break; - } } - /* write the data */ - SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, - SDO->buf, SDO->bufOffsetWr, &odRet); - SDO->bufOffsetWr = 0; - if (odRet == ODR_PARTIAL) { - /* OD variable was not written completelly, but SDO - * download finished */ - abortCode = CO_SDO_AB_DATA_SHORT; - SDO->state = CO_SDO_ST_ABORT; + if (!validateAndWriteToOD(SDO, &abortCode, 2, crcClient)) break; - } - else if (odRet != ODR_OK) { - abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); - SDO->state = CO_SDO_ST_ABORT; - break; - } SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; } @@ -980,8 +1137,6 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { if (SDO->CANrxData[0] == 0xA2) { - OD_size_t countRemain, countMinimum; - SDO->block_blksize = SDO->CANrxData[2]; if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { SDO->block_blksize = 127; @@ -1004,52 +1159,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* refill data buffer if necessary */ - countRemain = SDO->bufOffsetWr - SDO->bufOffsetRd; - countMinimum = SDO->block_blksize * 7; - if (!SDO->finished && countRemain < countMinimum) { - ODR_t odRet; - OD_size_t countRd; - - /* first move remaining data to the start of the buffer */ - memmove(SDO->buf, SDO->buf + SDO->bufOffsetRd, countRemain); - SDO->bufOffsetRd = 0; - SDO->bufOffsetWr = countRemain; - - /* load data from OD variable into the buffer */ - countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, - SDO->buf + SDO->bufOffsetWr, - CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr, - &odRet); - - countRemain += countRd; - if (odRet != ODR_OK && odRet != ODR_PARTIAL) { - abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); - SDO->state = CO_SDO_ST_ABORT; - break; - } - else if (odRet == ODR_PARTIAL) { - SDO->finished = false; - if (countRemain < countMinimum) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - } - else { - SDO->finished = true; - } + if (!readFromOd(SDO, &abortCode, SDO->block_blksize * 7, true)) + break; - /* update the crc */ - if (SDO->block_crcEnabled) { - SDO->block_crc = crc16_ccitt( - (unsigned char *)SDO->buf + SDO->bufOffsetWr, - countRd, - SDO->block_crc); - } - SDO->bufOffsetWr = countRemain; - } - if (countRemain == 0) { + if (SDO->bufOffsetWr == SDO->bufOffsetRd) { SDO->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; } else { @@ -1164,6 +1278,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { SDO->CANtxBuff->data[0] = 0x20 | SDO->toggle; + SDO->toggle = (SDO->toggle == 0x00) ? 0x10 : 0x00; /* reset timeout timer and send message */ SDO->timeoutTimer = 0; @@ -1200,6 +1315,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, memcpy(&SDO->CANtxBuff->data[4], &sizeIndSw, sizeof(sizeIndSw)); } + else { + SDO->CANtxBuff->data[0] = 0x40; + } SDO->toggle = 0x00; SDO->timeoutTimer = 0; SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; @@ -1210,6 +1328,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, OD_size_t count = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, &SDO->CANtxBuff->data[4], 4, &odRet); + + /* strings are allowed to be shorter */ + if (odRet == ODR_PARTIAL && (SDO->attribute & ODA_STR) != 0) { + odRet = ODR_OK; + } + if (odRet != ODR_OK || count == 0) { abortCode = (odRet == ODR_OK) ? CO_SDO_AB_DEVICE_INCOMPAT : (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); @@ -1220,7 +1344,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #ifdef CO_BIG_ENDIAN /* swap data if necessary */ if ((SDO->attribute & ODA_MB) != 0) { - reverseBytes(&SDO->CANtxBuff->data[4], count); + reverseBytes(buf, dataSizeToWrite); } #endif SDO->CANtxBuff->data[0] = 0x43 | ((4 - count) << 2); @@ -1239,39 +1363,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { /* refill the data buffer if necessary */ - if (!SDO->finished && (SDO->bufOffsetWr - SDO->bufOffsetRd) < 7) { - /* first move remaining data to the start of the buffer */ - SDO->bufOffsetWr -= SDO->bufOffsetRd; - memmove(SDO->buf, SDO->buf + SDO->bufOffsetRd, - SDO->bufOffsetWr); - SDO->bufOffsetRd = 0; - - /* load data from OD variable into the buffer */ - ODR_t odRet; - OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, - SDO->subIndex, - SDO->buf + SDO->bufOffsetWr, - CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr, - &odRet); - SDO->bufOffsetWr += countRd; - - if (odRet != ODR_OK && odRet != ODR_PARTIAL) { - abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); - SDO->state = CO_SDO_ST_ABORT; - break; - } - else if (odRet == ODR_PARTIAL) { - SDO->finished = false; - if (SDO->bufOffsetWr < 7) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - } - else { - SDO->finished = true; - } - } + if (!readFromOd(SDO, &abortCode, 7, false)) + break; /* SDO command specifier with toggle bit */ SDO->CANtxBuff->data[0] = SDO->toggle; @@ -1279,7 +1372,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; /* verify, if this is the last segment */ - if (count <= 7) { + if (count < 7 || (SDO->finished && count == 7)) { /* indicate last segment and nnn */ SDO->CANtxBuff->data[0] |= ((7 - count) << 1) | 0x01; SDO->state = CO_SDO_ST_IDLE; @@ -1308,6 +1401,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, && SDO->sizeTran < SDO->sizeInd ) { abortCode = CO_SDO_AB_DATA_SHORT; + ret = CO_SDO_RT_waitingResponse; SDO->state = CO_SDO_ST_ABORT; break; } @@ -1327,7 +1421,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[3] = SDO->subIndex; /* calculate number of block segments from free buffer space */ - OD_size_t count = CO_CONFIG_SDO_SRV_BUFFER_SIZE / 7; + OD_size_t count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE-2) / 7; if (count > 127) { count = 127; } @@ -1355,59 +1449,31 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { SDO->CANtxBuff->data[0] = 0xA2; SDO->CANtxBuff->data[1] = SDO->block_seqno; +#ifdef CO_DEBUG_SDO_SERVER + bool_t transferShort = SDO->block_seqno != SDO->block_blksize; + uint8_t seqnoStart = SDO->block_seqno; +#endif /* Is last segment? */ if (SDO->finished) { SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_REQ; } else { - /* verify if size of data downloaded is too large */ - if (SDO->sizeInd > 0 && SDO->sizeTran > SDO->sizeInd) { - abortCode = CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; - } - /* calculate number of block segments from free buffer space */ OD_size_t count; - count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr) / 7; + count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE-2-SDO->bufOffsetWr)/7; if (count >= 127) { count = 127; } else if (SDO->bufOffsetWr > 0) { /* it is necessary to empty the buffer */ -#ifdef CO_BIG_ENDIAN - /* swap data if necessary */ - if ((SDO->attribute & ODA_MB) != 0) { - reverseBytes(SDO->buf, SDO->bufOffsetWr); - } -#endif - /* calculate crc on current data */ - SDO->block_crc = crc16_ccitt((unsigned char *)SDO->buf, - SDO->bufOffsetWr, - SDO->block_crc); - - /* write data */ - ODR_t odRet; - SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, - SDO->buf, SDO->bufOffsetWr, &odRet); - SDO->bufOffsetWr = 0; - - if (odRet == ODR_OK) { - /* OD variable was written completelly, but SDO download - * still has data */ - abortCode = CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; - } - else if (odRet != ODR_PARTIAL) { - abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); - SDO->state = CO_SDO_ST_ABORT; + if (!validateAndWriteToOD(SDO, &abortCode, 1, 0)) break; - } - count = CO_CONFIG_SDO_SRV_BUFFER_SIZE / 7; - if (count >= 127) count = 127; + count =(CO_CONFIG_SDO_SRV_BUFFER_SIZE-2-SDO->bufOffsetWr)/7; + if (count >= 127) { + count = 127; + } } SDO->block_blksize = (uint8_t)count; @@ -1420,10 +1486,18 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[2] = SDO->block_blksize; - /* reset timeout timer and send message */ - SDO->timeoutTimer = 0; + /* reset block_timeoutTimer, but not SDO->timeoutTimer */ SDO->block_timeoutTimer = 0; CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); +#ifdef CO_DEBUG_SDO_SERVER + if (transferShort && !SDO->finished) { + char msg[80]; + sprintf(msg, + "sub-block restarted: sequnoPrev=%02X, blksize=%02X", + seqnoStart, SDO->block_blksize); + CO_DEBUG_SDO_SERVER(msg); + } +#endif break; } @@ -1461,7 +1535,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[0] = ++SDO->block_seqno; OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; /* verify, if this is the last segment */ - if (count <= 7) { + if (count < 7 || (SDO->finished && count == 7)) { SDO->CANtxBuff->data[0] |= 0x80; } else { diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 28f34b22..c28821cd 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -492,8 +492,8 @@ typedef struct { uint32_t SDOtimeoutTime_us; /** Timeout timer for SDO communication */ uint32_t timeoutTimer; - /** Interim data buffer for segmented or block transfer */ - char buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE]; + /** Interim data buffer for segmented or block transfer + byte for '\0' */ + char buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE + 1]; /** Offset of next free data byte available for write in the buffer. */ OD_size_t bufOffsetWr; /** Offset of first data available for read in the buffer */ diff --git a/301/CO_config.h b/301/CO_config.h index 58872e64..1b82de1c 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -374,13 +374,13 @@ extern "C" { /** * Size of the internal data buffer for the SDO client. * - * Circular buffer is used for SDO communication. it can be read or written + * Circular buffer is used for SDO communication. It can be read or written * between successive SDO calls. So size of the buffer can be lower than size of * the actual size of data transferred. If only segmented transfer is used, then * buffer size can be as low as 7 bytes, if data are read/written each cycle. If - * block transfer is used, buffer size should be set to at least 889 bytes, so - * maximum blksize can be used. In that case data should be read/written proper - * time between cycles. + * block transfer is used, buffer size should be set to at least 1000 bytes, so + * maximum blksize can be used (blksize is calculated from free buffer space). + * Default value for block transfer is 1000, otherwise 32. */ #ifdef CO_DOXYGEN #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 @@ -711,6 +711,31 @@ extern "C" { #define CO_CONFIG_TRACE_OWN_INTTYPES 0x02 /** @} */ /* CO_STACK_CONFIG_TRACE */ + +/** + * @defgroup CO_STACK_CONFIG_DEBUG Debug messages + * Messages from different parts of the stack. + * @{ + */ +/** + * Configuration of debug messages from different parts of the stack, which can + * be logged according to target specific function. + * + * Possible flags, can be ORed: + * - CO_CONFIG_DEBUG_COMMON - Define default CO_DEBUG_COMMON(msg) macro. This + * macro is target specific. This macro is then used as default macro in all + * other defined CO_DEBUG_XXX(msg) macros. + * - CO_CONFIG_DEBUG_SDO_CLIENT - Define default CO_DEBUG_SDO_CLIENT(msg) macro. + * - CO_CONFIG_DEBUG_SDO_SERVER - Define default CO_DEBUG_SDO_SERVER(msg) macro. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_DEBUG (0) +#endif +#define CO_CONFIG_DEBUG_COMMON 0x01 +#define CO_CONFIG_DEBUG_SDO_CLIENT 0x02 +#define CO_CONFIG_DEBUG_SDO_SERVER 0x04 +/** @} */ /* CO_STACK_CONFIG_DEBUG */ + /** @} */ /* CO_STACK_CONFIG */ #ifdef __cplusplus diff --git a/301/CO_driver.h b/301/CO_driver.h index ce2eb4bf..9330c355 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -35,6 +35,15 @@ extern "C" { #endif +#ifdef CO_DEBUG_COMMON +#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_CLIENT + #define CO_DEBUG_SDO_CLIENT(msg) CO_DEBUG_COMMON(msg) +#endif +#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_SERVER + #define CO_DEBUG_SDO_SERVER(msg) CO_DEBUG_COMMON(msg) +#endif +#endif + /** * @defgroup CO_driver Driver * @ingroup CO_CANopen_301 @@ -199,7 +208,7 @@ void CANrx_callback(void *object, void *rxMsg); * * This is target specific function and is specific for specific * microcontroller. It is best to implement it by using inline function or - * macro. `rxMsg` parameter should cast to a ponter to structure. For best + * macro. `rxMsg` parameter should cast to a pointer to structure. For best * efficiency structure may have the same alignment as CAN registers inside CAN * module. * @@ -422,7 +431,7 @@ typedef struct { * * Default CANopen identifiers for CANopen communication objects. Same as * 11-bit addresses of CAN messages. These are default identifiers and - * can be changed in CANopen. Especially PDO identifiers are confgured + * can be changed in CANopen. Especially PDO identifiers are configured * in PDO linking phase of the CANopen network configuration. */ typedef enum { @@ -491,7 +500,7 @@ typedef enum { CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, buffer full */ CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ - CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not confugured + CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not configured properly */ CO_ERROR_OD_PARAMETERS = -12, /**< Error in Object Dictionary parameters*/ CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ @@ -509,7 +518,7 @@ typedef enum { /** - * Request CAN configuration (stopped) mode and *wait* untill it is set. + * Request CAN configuration (stopped) mode and *wait* until it is set. * * @param CANptr Pointer to CAN device */ @@ -517,7 +526,7 @@ void CO_CANsetConfigurationMode(void *CANptr); /** - * Request CAN normal (opearational) mode and *wait* untill it is set. + * Request CAN normal (operational) mode and *wait* until it is set. * * @param CANmodule CO_CANmodule_t object. */ @@ -607,7 +616,7 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, * @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 This flag bit is used for synchronous TPDO messages. If it is - * set, message will not be sent, if curent time is outside synchronous window. + * set, message will not be sent, if current time is outside synchronous window. * * @return Pointer to CAN transmit message buffer. 8 bytes data array inside * buffer should be written, before CO_CANsend() function is called. diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 1e362d94..6f49c54c 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -308,27 +308,17 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { /******************************************************************************/ -bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo) { +bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { bool_t delimCommandFound = false; - if (fifo != NULL) { + if (fifo != NULL && insideComment != NULL) { while (fifo->readPtr != fifo->writePtr) { char c = fifo->buf[fifo->readPtr]; if (c == DELIM_COMMENT) { - /* comment found, clear all until next DELIM_COMMAND */ - while (fifo->readPtr != fifo->writePtr) { - if (++fifo->readPtr == fifo->bufSize) { - fifo->readPtr = 0; - } - if (c == DELIM_COMMAND) { - delimCommandFound = true; - break; - } - } - break; + *insideComment = true; } - else if (isgraph((int)c) != 0) { + else if (isgraph((int)c) != 0 && !(*insideComment)) { break; } if (++fifo->readPtr == fifo->bufSize) { @@ -336,6 +326,7 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo) { } if (c == DELIM_COMMAND) { delimCommandFound = true; + *insideComment = false; break; } } @@ -471,8 +462,26 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, #if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES /******************************************************************************/ +/* Tables for mime-base64 encoding, as specified in RFC 2045, (without CR-LF, + * but one long string). Base64 is used for encoding binary data into easy + * transferable printable characters. In general, each three bytes of binary + * data are translated into four characters, where characters are selected from + * 64 characters long table. See https://en.wikipedia.org/wiki/Base64 */ +static const char base64EncTable[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const char base64DecTable[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1,103,101, -1, -1,102, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 103, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1,100, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1}; + size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint8_t n; + uint8_t n=0; if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -484,7 +493,7 @@ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint16_t n; + uint16_t n=0; if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -496,7 +505,7 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint32_t n; + uint32_t n=0; if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -508,7 +517,7 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint64_t n; + uint64_t n=0; if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -520,7 +529,7 @@ size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint8_t n; + uint8_t n=0; if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -532,7 +541,7 @@ size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint16_t n; + uint16_t n=0; if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -544,7 +553,7 @@ size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint32_t n; + uint32_t n=0; if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -556,7 +565,7 @@ size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint64_t n; + uint64_t n=0; if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -568,7 +577,7 @@ size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - int8_t n; + int8_t n=0; if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -580,7 +589,7 @@ size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - int16_t n; + int16_t n=0; if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -592,7 +601,7 @@ size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - int32_t n; + int32_t n=0; if (fifo != NULL && count >= 13 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -604,7 +613,7 @@ size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - int64_t n; + int64_t n=0; if (fifo != NULL && count >= 23 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -616,7 +625,7 @@ size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - float32_t n; + float32_t n=0; if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -628,7 +637,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - float64_t n; + float64_t n=0; if (fifo != NULL && count >= 30 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); @@ -684,11 +693,80 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } break; } - if (c == '"') { - buf[len++] = '"'; + else if (c != 0 && c != '\r') { /* skip null and CR inside string */ + buf[len++] = c; + if (c == '"') { + buf[len++] = c; + } + } + } + } + + return len; +} + +size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { + /* mime-base64 encoding, see description above base64EncTable */ + + size_t len = 0; + + if (fifo != NULL && count >= 4) { + uint8_t step; + uint16_t word; + + if (!fifo->started) { + fifo->started = true; + step = 0; + word = 0; + } + else { + /* get memorized variables from previous function calls */ + step = (uint8_t)(fifo->aux >> 16); + word = (uint16_t)fifo->aux; + } + + while ((len + 3) <= count) { + char c; + + if(!CO_fifo_getc(fifo, &c)) { + /* buffer is empty, is also SDO communication finished? */ + if (end) { + /* add padding if necessary */ + switch (step) { + case 1: + buf[len++] = base64EncTable[(word >> 4) & 0x3F]; + buf[len++] = '='; + buf[len++] = '='; + break; + case 2: + buf[len++] = base64EncTable[(word >> 6) & 0x3F]; + buf[len++] = '='; + break; + } + } + break; + } + + word |= (uint8_t)c; + + switch (step++) { + case 0: + buf[len++] = base64EncTable[(word >> 2) & 0x3F]; + break; + case 1: + buf[len++] = base64EncTable[(word >> 4) & 0x3F]; + break; + default: + buf[len++] = base64EncTable[(word >> 6) & 0x3F]; + buf[len++] = base64EncTable[word & 0x3F]; + step = 0; + break; } - buf[len++] = c; + word <<= 8; } + + /* memorize variables for next iteration */ + fifo->aux = (uint32_t)step << 16 | word; } return len; @@ -921,6 +999,8 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t destSpace, destSpaceStart; bool_t finished = false; + uint8_t step; + char firstChar; CO_fifo_st st = 0; if (dest == NULL || src == NULL) { @@ -930,6 +1010,23 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* get free space of the dest fifo */ destSpaceStart = destSpace = CO_fifo_getSpace(dest); + /* is this the first write into dest? */ + if (!dest->started) { + bool_t insideComment = false; + if (CO_fifo_trimSpaces(src, &insideComment) || insideComment) { + /* command delimiter found without string, this is an error */ + st |= CO_fifo_st_errTok; + } + dest->started = true; + step = 0; + firstChar = 0; + } + else { + /* get memorized variables from previous function calls */ + step = (uint8_t)(dest->aux >> 8); + firstChar = (char)(dest->aux & 0xFF); + } + /* repeat until destination space available and no error and not finished * and source characters available */ while (destSpace > 0 && (st & CO_fifo_st_errMask) == 0 && !finished) { @@ -938,81 +1035,68 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { break; } - if (dest->started == false) { - /* search for first of two hex digits in token */ - if (isxdigit((int)c) != 0) { - /* first hex digit is known */ - dest->aux = c; - dest->started = true; - } - else if (c == DELIM_COMMAND) { - /* newline found, finish */ + if (step == 6) { + /* command is inside comment, waiting for command delimiter */ + bool_t insideComment = true; + if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { st |= CO_fifo_st_closed; finished = true; } - else if (c == DELIM_COMMENT) { - /* comment found, clear line and finish */ - while (CO_fifo_getc(src, &c)) { - if (c == DELIM_COMMAND) { - st |= CO_fifo_st_closed; - break; - } - } - finished = true; - } - else if (isgraph((int)c) != 0) { - /* printable character, not hex digit, error */ - st |= CO_fifo_st_errTok; - } - /* else just skip empty space */ + continue; } - else { - /* one hex digit is known, what is next */ - if (isxdigit((int)c) != 0) { - /* two hex digits are known */ + + if (isxdigit((int)c) != 0) { + /* first or second hex digit */ + if (step == 0) { + firstChar = c; + step = 1; + } + else { + /* write the byte */ char s[3]; int32_t num; - s[0] = (char) dest->aux; s[1] = c, s[2] = 0; + s[0] = firstChar; s[1] = c; s[2] = 0; num = strtol(s, NULL, 16); - /* copy the character */ CO_fifo_putc(dest, (char) num); destSpace--; + step = 0; } - else if (isgraph((int)c) != 0 && c != DELIM_COMMENT) { - /* printable character, not hex digit, error */ + } + else if (isgraph((int)c) != 0) { + /* printable character, not hex digit */ + if (c == '#') /* comment start */ + step = 6; + else /* syntax error */ st |= CO_fifo_st_errTok; - } - else { - /* this is space or comment, single hex digit is known */ + } + else { + /* this is space or delimiter */ + if (step == 1) { + /* write the byte */ char s[2]; int32_t num; - s[0] = (char) dest->aux; s[1] = 0; + s[0] = firstChar; s[1] = 0; num = strtol(s, NULL, 16); - /* copy the character */ CO_fifo_putc(dest, (char) num); destSpace--; - if (c == DELIM_COMMAND) { - /* newline found, finish */ - st |= CO_fifo_st_closed; - finished = true; - } - else if (c == DELIM_COMMENT) { - /* comment found, clear line and finish */ - while (CO_fifo_getc(src, &c)) { - if (c == DELIM_COMMAND) { - st |= CO_fifo_st_closed; - break; - } - } - finished = true; - } + step = 0; + } + bool_t insideComment = false; + if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + /* newline found, finish */ + st |= CO_fifo_st_closed; + finished = true; + } + else if (insideComment) { + step = 6; } - dest->started = false; } - } + } /* while ... */ if (!finished) { st |= CO_fifo_st_partial; + /* memorize variables for next iteration */ + dest->aux = (uint32_t)step << 8 | (uint8_t)firstChar; } if (status != NULL) *status = st; @@ -1023,6 +1107,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t destSpace, destSpaceStart; bool_t finished = false; + uint8_t step; CO_fifo_st st = 0; if (dest == NULL || src == NULL) { @@ -1034,9 +1119,17 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* is this the first write into dest? */ if (!dest->started) { - /* aux variable is used as state here */ - dest->aux = 0; + bool_t insideComment = false; + if (CO_fifo_trimSpaces(src, &insideComment) || insideComment) { + /* command delimiter found without string, this is an error */ + st |= CO_fifo_st_errTok; + } dest->started = true; + step = 0; + } + else { + /* get memorized variables from previous function calls */ + step = (uint8_t)dest->aux; } /* repeat until destination space available and no error and not finished @@ -1047,43 +1140,40 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { break; } - switch (dest->aux) { + switch (step) { case 0: /* beginning of the string, first write into dest */ - if (isgraph((int)c) == 0 || c == DELIM_COMMENT) { - if (CO_fifo_trimSpaces(src)) { - /* newline found without string, this is an error */ - st |= CO_fifo_st_errTok; - } - } - else if (c == '"') { + if (c == '"') { /* Indicated beginning of the string, skip this character. */ - dest->aux = 1; + step = 1; } else { /* this must be a single word string without '"' */ /* copy the character */ CO_fifo_putc(dest, c); destSpace--; - dest->aux = 2; + step = 2; } break; case 1: /* inside string, quoted string */ case 2: /* inside string, single word, no quotes */ if (c == '"') { - /* double qoute found, this may be end of the string or escaped + /* double quote found, this may be end of the string or escaped * double quote (with two double quotes) */ - dest->aux += 2; + step += 2; } - else if (isgraph((int)c) == 0 && dest->aux == 2) { + else if (isgraph((int)c) == 0 && step == 2) { /* end of single word string */ - if (c == DELIM_COMMAND) { + bool_t insideComment = false; + if (c == DELIM_COMMAND + || CO_fifo_trimSpaces(src, &insideComment) + ) { st |= CO_fifo_st_closed; + finished = true; } - else if (CO_fifo_trimSpaces(src)) { - st |= CO_fifo_st_closed; + else { + step = insideComment ? 6 : 5; } - finished = true; } else if (c == DELIM_COMMAND) { /* no closing quote, error */ @@ -1102,24 +1192,27 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* escaped double quote, copy the character and continue */ CO_fifo_putc(dest, c); destSpace--; - dest->aux -= 2; + step -= 2; } else { /* previous character was closing double quote */ - if (dest->aux == 4) { + if (step == 4) { /* no opening double quote, syntax error */ st |= CO_fifo_st_errTok; } else { if (isgraph((int)c) == 0) { - /* string finished */ - if (c == DELIM_COMMAND) { + /* end of quoted string */ + bool_t insideComment = false; + if (c == DELIM_COMMAND + || CO_fifo_trimSpaces(src, &insideComment) + ) { st |= CO_fifo_st_closed; + finished = true; } - else if (CO_fifo_trimSpaces(src)) { - st |= CO_fifo_st_closed; + else { + step = insideComment ? 6 : 5; } - finished = true; } else { /* space must follow closing double quote, error */ @@ -1129,6 +1222,31 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } break; + case 5: { /* String token is finished, waiting for command delimiter */ + bool_t insideComment = false; + if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + st |= CO_fifo_st_closed; + finished = true; + } + else if (insideComment) { + step = 6; + } + else if (isgraph((int)c) != 0) { + if (c == '#') /* comment start */ + step = 6; + else /* syntax error */ + st |= CO_fifo_st_errTok; + } + break; + } + case 6: { /* String token is finished, waiting for command delimiter */ + bool_t insideComment = true; + if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + st |= CO_fifo_st_closed; + finished = true; + } + break; + } default: /* internal error */ st |= CO_fifo_st_errInt; break; @@ -1137,6 +1255,120 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (!finished) { st |= CO_fifo_st_partial; + /* memorize variables for next iteration */ + dest->aux = step; + } + + if (status != NULL) *status = st; + + return destSpaceStart - destSpace; +} + +size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { + /* mime-base64 decoding, see description above base64EncTable */ + + size_t destSpace, destSpaceStart; + bool_t finished = false; + uint8_t step; + uint32_t dword; + CO_fifo_st st = 0; + + if (dest == NULL || src == NULL) { + return 0; + } + + /* get free space of the dest fifo */ + destSpaceStart = destSpace = CO_fifo_getSpace(dest); + + /* is this the first write into dest? */ + if (!dest->started) { + bool_t insideComment = false; + if (CO_fifo_trimSpaces(src, &insideComment) || insideComment) { + /* command delimiter found without string, this is an error */ + st |= CO_fifo_st_errTok; + } + dest->started = true; + step = 0; + dword = 0; + } + else { + /* get memorized variables from previous function calls */ + step = (uint8_t)(dest->aux >> 24); + dword = dest->aux & 0xFFFFFF; + } + + /* repeat until destination space available and no error and not finished + * and source characters available */ + while (destSpace >= 3 && (st & CO_fifo_st_errMask) == 0 && !finished) { + char c; + if (!CO_fifo_getc(src, &c)) { + break; + } + + if (step >= 5) { + /* String token is finished, waiting for command delimiter */ + bool_t insideComment = step > 5; + if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + st |= CO_fifo_st_closed; + finished = true; + } + else if (insideComment) { + step = 6; + } + else if (isgraph((int)c) != 0 && c != '=') { + if (c == '#') /* comment start */ + step = 6; + else /* syntax error */ + st |= CO_fifo_st_errTok; + } + continue; + } + + char code = base64DecTable[c & 0x7F]; + + if (c < 0 || code < 0) { + st |= CO_fifo_st_errTok; + } + else if (code >= 64 /* '=' (pad) or DELIM_COMMAND or space */) { + /* base64 string finished, write remaining bytes */ + switch (step) { + case 2: + CO_fifo_putc(dest, (char)(dword >> 4)); + destSpace --; + break; + case 3: + CO_fifo_putc(dest, (char)(dword >> 10)); + CO_fifo_putc(dest, (char)(dword >> 2)); + destSpace -= 2; + break; + } + + bool_t insideComment = false; + if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + st |= CO_fifo_st_closed; + finished = true; + } + else { + step = insideComment ? 6 : 5; + } + } + else { + dword = (dword << 6) | code; + if (step++ == 3) { + CO_fifo_putc(dest, (char)((dword >> 16) & 0xFF)); + CO_fifo_putc(dest, (char)((dword >> 8) & 0xFF)); + CO_fifo_putc(dest, (char)(dword & 0xFF)); + destSpace -= 3; + dword = 0; + step = 0; + } + } + } /* while ... */ + + if (!finished) { + st |= CO_fifo_st_partial; + /* memorize variables for next iteration */ + dest->aux = (uint32_t)step << 24 | (dword & 0xFFFFFF); } if (status != NULL) *status = st; diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 159ec29f..e5eecc5c 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -110,6 +110,24 @@ static inline void CO_fifo_reset(CO_fifo_t *fifo) { } +/** + * Purge all data in fifo object, keep other properties + * + * @param fifo This object + * + * @return true, if data were purged or false, if fifo were already empty + */ +static inline bool_t CO_fifo_purge(CO_fifo_t *fifo) { + if (fifo != NULL && fifo->readPtr != fifo->writePtr) { + fifo->readPtr = 0; + fifo->writePtr = 0; + return true; + } + + return false; +} + + /** * Get free buffer space in CO_fifo_t object * @@ -342,10 +360,13 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear); * is also removed). * * @param fifo This object. + * @param [in, out] insideComment if set to true as input, it skips all + * characters and searches only for delimiter. As output it is set to true, if + * fifo is empty, is inside comment and command delimiter is not found. * * @return true if command delimiter was found. */ -bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo); +bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment); /** @@ -400,7 +421,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, * @param fifo This object. * @param buf Buffer into which ascii string will be copied. * @param count Available count of bytes inside the buf. - * @param end If true, then fifo contains last bytes, which has to be read. + * @param end True indicates, that fifo contains last bytes of data. * * @return Number of ascii bytes written into buf. */ @@ -437,8 +458,14 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); /** Read data from fifo and output as visible string. A visible string is * enclosed with double quotes. If a double quote is used within the string, * the quotes are escaped by a second quotes, e.g. “Hello “”World””, CANopen - * is great”. See also CO_fifo_readU82a */ + * is great”. UTF-8 characters and also line breaks works with this function. + * Function removes all '\0' and '\r' characters from output string. + * See also CO_fifo_readU82a */ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +/** Read data from fifo and output as mime-base64 encoded string. Encoding is as + * specified in RFC 2045, without CR-LF, but one long string. See also + * CO_fifo_readU82a */ +size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); /** Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar */ @@ -493,8 +520,13 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); /** Copy visible string to data. A visible string must be enclosed with double * quotes, if it contains space. If a double quote is used within the string, - * the quotes are escaped by a second quotes. See CO_fifo_cpyTok2U8 */ + * the quotes are escaped by a second quotes. Input string can not contain + * newline characters. See CO_fifo_cpyTok2U8 */ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +/** Read ascii mime-base64 encoded string from src fifo and copy as binary data + * to dest fifo. Encoding is as specified in RFC 2045, without CR-LF, but one + * long string in single line. See also CO_fifo_readU82a */ +size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES */ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 8b7fd67a..f65a2fa7 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -51,8 +51,8 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN CO_SDOclient_t* SDO_C, - uint16_t SDOtimeoutTimeDefault, - bool_t SDOblockTransferEnableDefault, + uint16_t SDOclientTimeoutTime_ms, + bool_t SDOclientBlockTransfer, #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN CO_NMT_t *NMT, @@ -69,7 +69,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, /* verify arguments */ if (gtwa == NULL #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO - || SDO_C == NULL || SDOtimeoutTimeDefault == 0 + || SDO_C == NULL || SDOclientTimeoutTime_ms == 0 #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT || NMT == NULL @@ -90,8 +90,8 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, /* initialize variables */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO gtwa->SDO_C = SDO_C; - gtwa->SDOtimeoutTime = SDOtimeoutTimeDefault; - gtwa->SDOblockTransferEnable = SDOblockTransferEnableDefault; + gtwa->SDOtimeoutTime = SDOclientTimeoutTime_ms; + gtwa->SDOblockTransferEnable = SDOclientBlockTransfer; #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT gtwa->NMT = NMT; @@ -125,7 +125,8 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, void CO_GTWA_initRead(CO_GTWA_t* gtwa, size_t (*readCallback)(void *object, const char *buf, - size_t count), + size_t count, + uint8_t *connectionOK), void *readCallbackObject) { if (gtwa != NULL) { @@ -153,74 +154,73 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { * HELPER FUNCTIONS ******************************************************************************/ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP -/* help strings */ +/* help strings ("\n" is used between string, "\r\n" closes the response.) */ static const char CO_GTWA_helpString[] = -"\r\nCommand strings start with '\"[\"\"]\"' followed by:\r\n" \ -"[[] ] r[ead] [] # SDO upload.\r\n" \ -"[[] ] w[rite] # SDO download.\r\n" \ -"\r\n" \ -"[[] ] start # NMT Start node.\r\n" \ -"[[] ] stop # NMT Stop node.\r\n" \ -"[[] ] preop[erational] # NMT Set node to pre-operational.\r\n" \ -"[[] ] reset node # NMT Reset node.\r\n" \ -"[[] ] reset comm[unication] # NMT Reset communication.\r\n" \ -"\r\n" \ -"[] set network # Set default net.\r\n" \ -"[] set node # Set default node.\r\n" \ -"[] set sdo_timeout # Configure SDO time-out.\r\n" \ -"[] set sdo_block # Enable/disable SDO block transfer.\r\n" \ -"\r\n" \ -"help [datatype|lss] # Print this or datatype or lss help.\r\n" \ -"led # Print status LED diodes.\r\n" \ -"log # Print message log.\r\n" \ -"\r\n" \ -"Response:\r\n" \ -"\"[\"\"]\" OK | |\r\n" \ -" ERROR: | ERROR:\r\n" \ -"\r\n" \ -"* Every command must be terminated with ('\\r\\n'). characters. Same\r\n" \ -" is response. String is not null terminated, is optional in command.\r\n" \ -"* Comments started with '#' are ignored. They may be on the beginning of the\r\n" \ -" line or after the command string.\r\n" \ -"* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is\r\n" \ -" disabled by default.\r\n" \ -"* If '' or '' is not specified within commands, then value defined\r\n" \ +"\nCommand strings start with '\"[\"\"]\"' followed by:\n" \ +"[[] ] r[ead] [] # SDO upload.\n" \ +"[[] ] w[rite] # SDO download.\n" \ +"\n" \ +"[[] ] start # NMT Start node.\n" \ +"[[] ] stop # NMT Stop node.\n" \ +"[[] ] preop[erational] # NMT Set node to pre-operational.\n" \ +"[[] ] reset node # NMT Reset node.\n" \ +"[[] ] reset comm[unication] # NMT Reset communication.\n" \ +"\n" \ +"[] set network # Set default net.\n" \ +"[] set node # Set default node.\n" \ +"[] set sdo_timeout # Configure SDO client time-out in ms.\n" \ +"[] set sdo_block <0|1> # Enable/disable SDO block transfer.\n" \ +"\n" \ +"help [datatype|lss] # Print this or datatype or lss help.\n" \ +"led # Print status LEDs of this device.\n" \ +"log # Print message log.\n" \ +"\n" \ +"Response:\n" \ +"\"[\"\"]\" OK | |\n" \ +" ERROR: | ERROR:\n" \ +"\n" \ +"* Every command must be terminated with ('\\r\\n'). characters. Same\n" \ +" is response. String is not null terminated, is optional in command.\n" \ +"* Comments started with '#' are ignored. They may be on the beginning of the\n" \ +" line or after the command string.\n" \ +"* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is\n" \ +" disabled by default.\n" \ +"* If '' or '' is not specified within commands, then value defined\n" \ " by 'set network' or 'set node' command is used.\r\n"; static const char CO_GTWA_helpStringDatatypes[] = -"\r\nDatatypes:\r\n" \ -"b # Boolean.\r\n" \ -"i8, i16, i32, i64 # Signed integers.\r\n" \ -"u8, u16, u32, u64 # Unsigned integers.\r\n" \ -"x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard.\r\n" \ -"r32, r64 # Real numbers.\r\n" \ -"t, td # Time of day, time difference.\r\n" \ -"vs # Visible string (between double quotes if multi-word).\r\n" \ -"os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line).\r\n" \ -"d # domain (mime-base64 (RFC2045) based, one line).\r\n" \ +"\nDatatypes:\n" \ +"b # Boolean.\n" \ +"i8, i16, i32, i64 # Signed integers.\n" \ +"u8, u16, u32, u64 # Unsigned integers.\n" \ +"x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard.\n" \ +"r32, r64 # Real numbers.\n" \ +"vs # Visible string (between double quotes if multi-word).\n" \ +"os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line).\n" \ +"d # domain (mime-base64 (RFC2045) based, one line).\n" \ "hex # Hexagonal data, optionally space separated, non-standard.\r\n"; static const char CO_GTWA_helpStringLss[] = -"\r\nLSS commands:\r\n" \ -"lss_switch_glob <0|1> # Switch state global command.\r\n" \ -"lss_switch_sel \\\r\n" \ -" #Switch state selective.\r\n" \ -"lss_set_node # Configure node-ID.\r\n" \ -"lss_conf_bitrate \\\r\n" \ -" # Configure bit-rate.\r\n" \ -"lss_activate_bitrate # Activate new bit-rate.\r\n" \ -"lss_store # LSS store configuration.\r\n" \ -"lss_inquire_addr [] # Inquire LSS address.\r\n" \ -"lss_get_node # Inquire node-ID.\r\n" \ -"_lss_fastscan [] # Identify fastscan, non-standard.\r\n" \ -"lss_allnodes [ [ \\\r\n" \ -" [ \\\r\n" \ -" ]]]\r\n" \ -" # Node-ID configuration of all nodes.\r\n" \ -"\r\n" \ -"* All LSS commands start with '\"[\"\"]\" []'.\r\n" \ -"* : 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\r\n" \ -" 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\r\n" \ +"\nLSS commands:\n" \ +"lss_switch_glob <0|1> # Switch state global command.\n" \ +"lss_switch_sel \\\n" \ +" #Switch state selective.\n" \ +"lss_set_node # Configure node-ID.\n" \ +"lss_conf_bitrate \\\n" \ +" # Configure bit-rate.\n" \ +"lss_activate_bitrate # Activate new bit-rate.\n" \ +"lss_store # LSS store configuration.\n" \ +"lss_inquire_addr [] # Inquire LSS address.\n" \ +"lss_get_node # Inquire node-ID.\n" \ +"_lss_fastscan [] # Identify fastscan, non-standard.\n" \ +"lss_allnodes [ [ \\\n" \ +" [ \\\n" \ +" ]]]\n" \ +" # Node-ID configuration of all nodes.\n" \ +"\n" \ +"* All LSS commands start with '\"[\"\"]\" []'.\n" \ +"* : 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\n" \ +" 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\n" \ "* : 0=fastscan, 1=ignore, 2=match value in next parameter\r\n"; #endif @@ -340,12 +340,10 @@ static const CO_GTWA_dataType_t dataTypes[] = { {"x64", 8, CO_fifo_readX642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ {"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */ {"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */ -// {"t", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* TIME_OF_DAY */ -// {"td", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* TIME_DIFFERENCE */ - {"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}//, -// {"os", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* ochar_t (OCTET_STRING) (mime-base64 (RFC2045) should be used here) */ -// {"us", 0, CO_GWA_dtpHex, CO_DWA_dtsHex}, /* (UNICODE_STRING) (mime-base64 (RFC2045) should be used here) */ -// {"d", 0, CO_GWA_dtpHex, CO_DWA_dtsHex} /* domain_t (DOMAIN) (mime-base64 (RFC2045) should be used here) */ + {"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}, /* VISIBLE_STRING */ + {"os", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* OCTET_STRING base64*/ + {"us", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64},/* UNICODE_STRING base64*/ + {"d", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64} /* DOMAIN - base64 */ }; @@ -369,8 +367,11 @@ static const CO_GTWA_dataType_t *CO_GTWA_getDataType(char *token, bool_t *err) { #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ -/* transfer response buffer and verify if all bytes was read */ -static void respBufTransfer(CO_GTWA_t *gtwa) { +/* transfer response buffer and verify if all bytes was read. Return true on + * success, or false, if communication is broken. */ +static bool_t respBufTransfer(CO_GTWA_t *gtwa) { + uint8_t connectionOK = 1; + if (gtwa->readCallback == NULL) { /* no callback registered, just purge the response */ gtwa->respBufOffset = 0; @@ -382,7 +383,8 @@ static void respBufTransfer(CO_GTWA_t *gtwa) { size_t countRead = gtwa->readCallback(gtwa->readCallbackObject, (const char *)>wa->respBuf[gtwa->respBufOffset], - gtwa->respBufCount); + gtwa->respBufCount, + &connectionOK); if (countRead < gtwa->respBufCount) { gtwa->respBufOffset += countRead; @@ -395,6 +397,7 @@ static void respBufTransfer(CO_GTWA_t *gtwa) { gtwa->respHold = false; } } + return connectionOK != 0; } @@ -495,10 +498,11 @@ static void responseWithError(CO_GTWA_t *gtwa, #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO static void responseWithErrorSDO(CO_GTWA_t *gtwa, - CO_SDO_abortCode_t abortCode) + CO_SDO_abortCode_t abortCode, + bool_t postponed) { int i; - int len = sizeof(errorDescs) / sizeof(errorDescs_t); + int len = sizeof(errorDescsSDO) / sizeof(errorDescs_t); const char *desc = "-"; for (i = 0; i < len; i++) { @@ -508,9 +512,17 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, } } - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] ERROR:0x%08X #%s\r\n", - gtwa->sequence, abortCode, desc); + if (!postponed) { + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] ERROR:0x%08X #%s\r\n", + gtwa->sequence, abortCode, desc); + } + else { + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "\n...ERROR:0x%08X #%s\r\n", + abortCode, desc); + } + respBufTransfer(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ @@ -527,11 +539,20 @@ static inline void responseWithError(CO_GTWA_t *gtwa, #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, - CO_SDO_abortCode_t abortCode) + CO_SDO_abortCode_t abortCode, + bool_t postponed) { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] ERROR:0x%08X\r\n", - gtwa->sequence, abortCode); + if (!postponed) { + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%"PRId32"] ERROR:0x%08X\r\n", + gtwa->sequence, abortCode); + } + else { + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "\n...ERROR:0x%08X\r\n", + abortCode); + } + respBufTransfer(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ @@ -546,6 +567,13 @@ static inline void responseWithOK(CO_GTWA_t *gtwa) { } +static inline void responseWithEmpty(CO_GTWA_t *gtwa) { + gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "\r\n"); + respBufTransfer(gtwa); +} + + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS static void responseLSS(CO_GTWA_t *gtwa, CO_LSSmaster_return_t lss_ret) { if (lss_ret == CO_LSSmaster_OK) { @@ -649,6 +677,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* If empty line or just comment, continue with next command */ else if (n == 0 && closed != 0) { + responseWithEmpty(gtwa); continue; } if (tok[0] != '[' || tok[strlen(tok)-1] != ']') { @@ -1511,26 +1540,28 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_IDLE; } - else if (gtwa->state == CO_GTWA_ST_IDLE) { - return; + else switch (gtwa->state) { + case CO_GTWA_ST_IDLE: { + return; /* skip timerNext_us calculation */ } #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO /* SDO upload state */ - else if (gtwa->state == CO_GTWA_ST_READ) { + case CO_GTWA_ST_READ: { CO_SDO_abortCode_t abortCode; size_t sizeTransferred; CO_SDO_return_t ret; ret = CO_SDOclientUpload(gtwa->SDO_C, timeDifference_us, + false, &abortCode, NULL, &sizeTransferred, timerNext_us); if (ret < 0) { - responseWithErrorSDO(gtwa, abortCode); + responseWithErrorSDO(gtwa, abortCode, gtwa->SDOdataCopyStatus); gtwa->state = CO_GTWA_ST_IDLE; } /* Response data must be read, partially or whole */ @@ -1568,21 +1599,34 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* transfer response to the application */ - respBufTransfer(gtwa); + if (respBufTransfer(gtwa) == false) { + /* broken communication, send SDO abort and force finish. */ + abortCode = CO_SDO_AB_DATA_TRANSF; + CO_SDOclientUpload(gtwa->SDO_C, + 0, + true, + &abortCode, + NULL, + NULL, + NULL); + gtwa->state = CO_GTWA_ST_IDLE; + break; + } } while (gtwa->respHold == false && fifoRemain > 0); } + break; } /* SDO download state */ - else if (gtwa->state == CO_GTWA_ST_WRITE) { + case CO_GTWA_ST_WRITE: + case CO_GTWA_ST_WRITE_ABORTED: { CO_SDO_abortCode_t abortCode; size_t sizeTransferred; bool_t abort = false; bool_t hold = false; CO_SDO_return_t ret; - int loop = 0; - /* copy data to the SDO buffer if more data available */ + /* copy data to the SDO buffer if previous dataTypeScan was partial */ if (gtwa->SDOdataCopyStatus) { CO_fifo_st status; gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, @@ -1599,6 +1643,17 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, ) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; abort = true; /* abort SDO communication */ + /* clear the rest of the command, if necessary */ + if (closed != 1) + CO_fifo_CommSearch(>wa->commFifo, true); + } + if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) { + /* Stay in this state, until all data transferred via commFifo + * will be purged. */ + if (!CO_fifo_purge(>wa->SDO_C->bufFifo) || closed == 1) { + gtwa->state = CO_GTWA_ST_IDLE; + } + break; } } /* If not all data were transferred, make sure, there is enough data in @@ -1617,8 +1672,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, hold = true; } } - if (!hold) { + if (!hold || abort) { /* if OS has CANtx queue, speedup block transfer */ + int loop = 0; do { ret = CO_SDOclientDownload(gtwa->SDO_C, timeDifference_us, @@ -1634,19 +1690,23 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* send response in case of error or finish */ if (ret < 0) { - responseWithErrorSDO(gtwa, abortCode); - gtwa->state = CO_GTWA_ST_IDLE; + responseWithErrorSDO(gtwa, abortCode, false); + /* purge remaining data if necessary */ + gtwa->state = gtwa->SDOdataCopyStatus + ? CO_GTWA_ST_WRITE_ABORTED + : CO_GTWA_ST_IDLE; } else if (ret == CO_SDO_RT_ok_communicationEnd) { responseWithOK(gtwa); gtwa->state = CO_GTWA_ST_IDLE; } } + break; } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS - else if (gtwa->state == CO_GTWA_ST_LSS_SWITCH_GLOB) { + case CO_GTWA_ST_LSS_SWITCH_GLOB: { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster, timeDifference_us, @@ -1655,8 +1715,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, responseLSS(gtwa, ret); gtwa->state = CO_GTWA_ST_IDLE; } + break; } - else if (gtwa->state == CO_GTWA_ST_LSS_SWITCH_SEL) { + case CO_GTWA_ST_LSS_SWITCH_SEL: { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster, timeDifference_us, @@ -1665,8 +1726,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, responseLSS(gtwa, ret); gtwa->state = CO_GTWA_ST_IDLE; } + break; } - else if (gtwa->state == CO_GTWA_ST_LSS_SET_NODE) { + case CO_GTWA_ST_LSS_SET_NODE: { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster, timeDifference_us, @@ -1681,8 +1743,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } gtwa->state = CO_GTWA_ST_IDLE; } + break; } - else if (gtwa->state == CO_GTWA_ST_LSS_CONF_BITRATE) { + case CO_GTWA_ST_LSS_CONF_BITRATE: { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_configureBitTiming(gtwa->LSSmaster, timeDifference_us, @@ -1697,8 +1760,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } gtwa->state = CO_GTWA_ST_IDLE; } + break; } - else if (gtwa->state == CO_GTWA_ST_LSS_STORE) { + case CO_GTWA_ST_LSS_STORE: { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, timeDifference_us); @@ -1712,8 +1776,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } gtwa->state = CO_GTWA_ST_IDLE; } + break; } - else if (gtwa->state == CO_GTWA_ST_LSS_INQUIRE) { + case CO_GTWA_ST_LSS_INQUIRE: { CO_LSSmaster_return_t ret; uint32_t value; @@ -1739,8 +1804,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } gtwa->state = CO_GTWA_ST_IDLE; } + break; } - else if (gtwa->state == CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL) { + case CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL: { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_InquireLssAddress(gtwa->LSSmaster, timeDifference_us, @@ -1763,8 +1829,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } gtwa->state = CO_GTWA_ST_IDLE; } + break; } - else if (gtwa->state == CO_GTWA_ST__LSS_FASTSCAN) { + case CO_GTWA_ST__LSS_FASTSCAN: { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, timeDifference_us, @@ -1789,8 +1856,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_LSSmaster_DEFAULT_TIMEOUT); gtwa->state = CO_GTWA_ST_IDLE; } + break; } - else if (gtwa->state == CO_GTWA_ST_LSS_ALLNODES) { + case CO_GTWA_ST_LSS_ALLNODES: { CO_LSSmaster_return_t ret; if (gtwa->lssSubState == 0) { /* _lss_fastscan */ ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, @@ -1804,7 +1872,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* no (more) nodes found, send report sum and finish */ gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "# Found %d nodes, search finished.\r\n" \ + "# Found %d nodes, search finished.\n" \ "[%"PRId32"] OK\r\n", gtwa->lssNodeCount, gtwa->sequence); @@ -1877,7 +1945,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else { /* cycle finished successfully, send report */ uint8_t lssNidAssigned = gtwa->lssNID; - const char msg2Fmt[] = "# Not all nodes scanned!\r\n" \ + const char msg2Fmt[] = "# Not all nodes scanned!\n" \ "[%"PRId32"] OK\r\n"; char msg2[sizeof(msg2Fmt)+10] = {0}; @@ -1900,7 +1968,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "# Node-ID %d assigned to: 0x%08"PRIX32" 0x%08" \ - PRIX32" 0x%08"PRIX32" 0x%08"PRIX32"\r\n%s", + PRIX32" 0x%08"PRIX32" 0x%08"PRIX32"\n%s", lssNidAssigned, gtwa->lssFastscan.found.identity.vendorID, gtwa->lssFastscan.found.identity.productCode, @@ -1910,12 +1978,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, respBufTransfer(gtwa); } } - } /* else if (gtwa->state == CO_GTWA_ST_LSS_ALLNODES) */ + break; + } /* CO_GTWA_ST_LSS_ALLNODES */ #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG /* print message log */ - else if (gtwa->state == CO_GTWA_ST_LOG) { + case CO_GTWA_ST_LOG: { do { gtwa->respBufCount = CO_fifo_read(>wa->logFifo, gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, NULL); @@ -1926,12 +1995,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } } while (gtwa->respHold == false); + break; } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP /* Print help string (in multiple segments if necessary) */ - else if (gtwa->state == CO_GTWA_ST_HELP) { + case CO_GTWA_ST_HELP: { size_t lenBuf = CO_GTWA_RESP_BUF_SIZE; size_t lenHelp = strlen(gtwa->helpString); @@ -1952,12 +2022,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } } while (gtwa->respHold == false); + break; } #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS /* print CANopen status LED diodes */ - else if (gtwa->state == CO_GTWA_ST_LED) { + case CO_GTWA_ST_LED: { uint8_t i; if (CO_fifo_CommSearch(>wa->commFifo, false)) { @@ -1977,15 +2048,18 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, respBufTransfer(gtwa); gtwa->ledStringPreviousIndex = i; } + break; } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */ /* illegal state */ - else { + default: { respErrorCode = CO_GTWA_respErrorInternalState; responseWithError(gtwa, respErrorCode); gtwa->state = CO_GTWA_ST_IDLE; + break; } + } /* switch (gtwa->state) */ /* execute next CANopen processing immediately, if idle and more commands * available */ diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 095a8327..19e63d2a 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -154,7 +154,7 @@ lss_allnodes [ [ \\ /** Timeout time in microseconds for some internal states. */ #ifndef CO_GTWA_STATE_TIMEOUT_TIME_US -#define CO_GTWA_STATE_TIMEOUT_TIME_US 1000000 +#define CO_GTWA_STATE_TIMEOUT_TIME_US 1200000 #endif @@ -233,6 +233,8 @@ typedef enum { CO_GTWA_ST_READ = 0x10U, /** SDO 'write' (download) */ CO_GTWA_ST_WRITE = 0x11U, + /** SDO 'write' (download) - aborted, purging remaining data */ + CO_GTWA_ST_WRITE_ABORTED = 0x12U, /** LSS 'lss_switch_glob' */ CO_GTWA_ST_LSS_SWITCH_GLOB = 0x20U, /** LSS 'lss_switch_sel' */ @@ -298,10 +300,14 @@ typedef struct { * @param object Void pointer to custom object * @param buf Buffer from which data can be read * @param count Count of bytes available inside buffer + * @param [out] connectionOK different than 0 indicates connection is OK. * * @return Count of bytes actually transferred. */ - size_t (*readCallback)(void *object, const char *buf, size_t count); + size_t (*readCallback)(void *object, + const char *buf, + size_t count, + uint8_t *connectionOK); /** Pointer to object, which will be used inside readCallback, from * CO_GTWA_init() */ void *readCallbackObject; @@ -343,7 +349,9 @@ typedef struct { uint16_t SDOtimeoutTime; /** SDO block transfer enabled? */ bool_t SDOblockTransferEnable; - /** Indicate status of data copy from / to SDO buffer */ + /** Indicate status of data copy from / to SDO buffer. If reading, true + * indicates, that response has started. If writing, true indicates, that + * SDO buffer contains only part of data and more data will follow. */ bool_t SDOdataCopyStatus; /** Data type of variable in current SDO communication */ const CO_GTWA_dataType_t *SDOdataType; @@ -398,8 +406,8 @@ typedef struct { * * @param gtwa This object will be initialized * @param SDO_C SDO client object - * @param SDOtimeoutTimeDefault in milliseconds, 500 typically - * @param SDOblockTransferEnableDefault true or false + * @param SDOclientTimeoutTime_ms Default timeout in milliseconds, 500 typically + * @param SDOclientBlockTransfer If true, block transfer will be set by default * @param NMT NMT object * @param LSSmaster LSS master object * @param LEDs LEDs object @@ -410,8 +418,8 @@ typedef struct { CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN CO_SDOclient_t* SDO_C, - uint16_t SDOtimeoutTimeDefault, - bool_t SDOblockTransferEnableDefault, + uint16_t SDOclientTimeoutTime_ms, + bool_t SDOclientBlockTransfer, #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN CO_NMT_t *NMT, @@ -442,7 +450,8 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, void CO_GTWA_initRead(CO_GTWA_t* gtwa, size_t (*readCallback)(void *object, const char *buf, - size_t count), + size_t count, + uint8_t *connectionOK), void *readCallbackObject); diff --git a/CANopen.c b/CANopen.c index d2b1a4d0..43a9bcb1 100644 --- a/CANopen.c +++ b/CANopen.c @@ -910,7 +910,9 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, const OD_entry_t *OD_statusBits, CO_NMT_control_t NMTcontrol, uint16_t firstHBTime_ms, - uint16_t SDOtimeoutTime_ms, + uint16_t SDOserverTimeoutTime_ms, + uint16_t SDOclientTimeoutTime_ms, + bool_t SDOclientBlockTransfer, uint8_t nodeId) { CO_ReturnError_t err; @@ -1024,7 +1026,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, od, SDOsrvPar++, nodeId, - SDOtimeoutTime_ms, + SDOserverTimeoutTime_ms, co->CANmodule, CO_GET_CO(RX_IDX_SDO_SRV) + i, co->CANmodule, @@ -1206,8 +1208,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, err = CO_GTWA_init(co->gtwa, #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO &co->SDOclient[0], - 500, - false, + SDOclientTimeoutTime_ms, + SDOclientBlockTransfer, #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT co->NMT, diff --git a/CANopen.h b/CANopen.h index 0a78e447..c3ceed9d 100644 --- a/CANopen.h +++ b/CANopen.h @@ -519,7 +519,11 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, * @param OD_statusBits Argument passed to @ref CO_EM_init(). May be NULL. * @param NMTcontrol Argument passed to @ref CO_NMT_init(). * @param firstHBTime_ms Argument passed to @ref CO_NMT_init(). - * @param SDOtimeoutTime_ms Argument passed to @ref CO_SDOserver_init(). + * @param SDOserverTimeoutTime_ms Argument passed to @ref CO_SDOserver_init(). + * @param SDOclientTimeoutTime_ms Default timeout in milliseconds for SDO + * client, 500 typically. SDO client is configured from CO_GTWA_init(). + * @param SDOclientBlockTransfer If true, block transfer will be set in SDO + * client by default. SDO client is configured from by CO_GTWA_init(). * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). In the * CANopen initialization it is the same as pendingBitRate from CO_LSSinit(). * If it is unconfigured, then some CANopen objects will not be initialized nor @@ -534,7 +538,9 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, const OD_entry_t *OD_statusBits, CO_NMT_control_t NMTcontrol, uint16_t firstHBTime_ms, - uint16_t SDOtimeoutTime_ms, + uint16_t SDOserverTimeoutTime_ms, + uint16_t SDOclientTimeoutTime_ms, + bool_t SDOclientBlockTransfer, uint8_t nodeId); diff --git a/Makefile b/Makefile index 2bbaf131..497adfaa 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,7 @@ SOURCES = \ OBJS = $(SOURCES:%.c=%.o) CC ?= gcc OPT = -g -DCO_SINGLE_THREAD +#OPT = -g -DCO_SINGLE_THREAD -DCO_CONFIG_DEBUG=0xFFFF #OPT = -g -pedantic -Wshadow -fanalyzer #OPT = -g -DCO_USE_GLOBALS #OPT = -g -DCO_MULTIPLE_OD diff --git a/README.md b/README.md index ea217202..2e7ee608 100644 --- a/README.md +++ b/README.md @@ -63,11 +63,13 @@ Code is documented in header files. Running [doxygen](http://www.doxygen.nl/) in project base directory will produce complete html documentation. Just open CANopenNode/doc/html/index.html in the browser. Alternatively browse documentation [online](https://canopennode.github.io/CANopenSocket/). +Further documented examples are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket) project. Report issues on https://github.com/CANopenNode/CANopenNode/issues -Older and still active discussion group is on Sourceforge -http://sourceforge.net/p/canopennode/discussion/387151/ +Join discussion on Slack: https://canopennode.slack.com/ + +Older discussion group is on Sourceforge: http://sourceforge.net/p/canopennode/discussion/387151/ Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Some basic formatting diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index f314d94c..5f95d03f 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -162,7 +162,7 @@ Please be careful when exposing your CANopen network to the outside world, it is ### Next steps Assigning Node-ID or CAN bitrate, which support LSS configuration, is described in *LSSusage.md*. -Some further CANopenNode related Linux tools are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket). +Further CANopenNode related tools and examples are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket). Especially interesting is [basicDevice](https://github.com/CANopenNode/CANopenSocket/examples/basicDevice) Custom CANopen device can be created based on own Object Dictionary, see README.md. There are also many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download, for example CiA401. @@ -170,12 +170,16 @@ For own CANopen device with own microcontroller, see *deviceSupport.md*. There i Another interesting tool is [CANopen for Python](https://github.com/christiansandberg/canopen). +Examples here worked in virtual CAN interface, for simplicity. Virtual CAN runs inside Linux kernel only, it does not have much practical usability. If one has real CAN network configuration, then above examples are suitable also for this network, if Linux machine is connected to it and CAN interface is properly configured. When connecting your devices to real CAN network, make sure, you have at least two devices communicating, connected with ground and pair of wires, terminated with two 120ohm resistors, correct baudrate, etc. + Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native in Linux kernel are: - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with: `sudo slcand -f -o -c -s8 /dev/ttyACM0 can0; sudo ip link set up can0` - [EMS CPC-USB](https://www.ems-wuensche.com/?post_type=product&p=746) or [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Start with: `sudo ip link set up can0 type can bitrate 250000` - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can) (Kconfig files). - Raspberry PI or similar has CAN capes available. +Examples here run in Linux, for simplicity. However, real usability of CANopen network is, when simple, microcontroller based devices are connected together with or without more advanced commander device. CANopenNode is basically written for simple microcontrollers and also has more advanced commander features, like above used CANopen gateway with ascii command interface. + Now you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware). Here we played with virtual CAN interface and result shown as pixels on screen. If you connect a real CAN interface to your computer, things may become dangerous. Keep control and safety on your machines! diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 7b6cdd94..2d58adf8 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -449,9 +449,13 @@ Other elements listed in the above XML example are required by the standard. The | - | (1) | TIME_OF_DAY | 0x0C | | - | (1) | TIME_DIFFERENCE | 0x0D | | app. specific | BITSTRING (4) | DOMAIN | 0x0F | -(1) Data is translated into OCTET_STRING.
-(2) Additional property "CO_stringLengthMin" indicates the minimum length of the string in CANopenNode.
-(3) Default value for BITSTRING (OCTET_STRING) is written as space separated, two hex digit bytes in little-endian format.
+ +(1) Data is translated into OCTET_STRING. + +(2) Additional property "CO_stringLengthMin" indicates the minimum length of the string in CANopenNode. Property is ignored, if strlen(defaultValue) is larger. Otherwise remaining data locations are filled with zeroes. Strings always have additional element on the end of the array with value=0, which is never written (string is always null terminated). All strings have additional attribute "ODA_STR" in object dictionary. Attribute enables SDO to transfer data of length, which corresponds to actual string length. (Actual size of data read or written by SDO may be smaller than data size of the OD variable.) VISIBLE_STRING may contain control characters and UTF-8 characters, which should work on most target systems (like printf("%s", ...)). So VISIBLE_STRING may be more usable for printing complete set of unicode characters than UNICODE_STRING. + +(3) Default value for BITSTRING (OCTET_STRING) is written as space separated, two hex digit bytes in little-endian format. + (4) Default value for DOMAIN is stored as empty string. diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index f2dd4957..49d1bdc9 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -23,8 +23,8 @@ */ -#ifndef CO_DRIVER_TARGET -#define CO_DRIVER_TARGET +#ifndef CO_DRIVER_TARGET_H +#define CO_DRIVER_TARGET_H /* This file contains device and application specific definitions. * It is included from CO_driver.h, which contains documentation @@ -79,7 +79,7 @@ extern "C" { #endif #ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE -#define CO_CONFIG_SDO_SRV_BUFFER_SIZE (127*7) +#define CO_CONFIG_SDO_SRV_BUFFER_SIZE 900 #endif #ifndef CO_CONFIG_SDO_CLI @@ -92,10 +92,6 @@ extern "C" { CO_CONFIG_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE -#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 -#endif - #ifndef CO_CONFIG_TIME #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ CO_CONFIG_TIME_PRODUCER | \ @@ -264,4 +260,4 @@ typedef struct { } #endif /* __cplusplus */ -#endif /* CO_DRIVER_TARGET */ +#endif /* CO_DRIVER_TARGET_H */ diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index c6ac2568..b561d119 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -26,8 +26,8 @@ */ -#ifndef CO_DRIVER_TARGET -#define CO_DRIVER_TARGET +#ifndef CO_DRIVER_TARGET_H +#define CO_DRIVER_TARGET_H /* This file contains device and application specific definitions. * It is included from CO_driver.h, which contains documentation @@ -103,7 +103,7 @@ extern "C" { #endif #ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE -#define CO_CONFIG_SDO_SRV_BUFFER_SIZE (127*7) +#define CO_CONFIG_SDO_SRV_BUFFER_SIZE 900 #endif #ifndef CO_CONFIG_SDO_CLI @@ -116,10 +116,6 @@ extern "C" { CO_CONFIG_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE -#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 -#endif - #ifndef CO_CONFIG_TIME #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ CO_CONFIG_TIME_PRODUCER | \ @@ -186,6 +182,14 @@ extern "C" { #endif +/* Print debug info from some internal parts of the stack */ +#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_COMMON +#include +#include +#define CO_DEBUG_COMMON(msg) log_printf(LOG_DEBUG, DBG_CO_DEBUG, msg); +#endif + + /** * @defgroup CO_socketCAN_driver_target CO_driver_target.h * @ingroup CO_socketCAN @@ -495,4 +499,4 @@ bool_t CO_CANrxFromEpoll(CO_CANmodule_t *CANmodule, } #endif /* __cplusplus */ -#endif /* CO_DRIVER_TARGET */ +#endif /* CO_DRIVER_TARGET_H */ diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c index 8406f811..8674b87b 100644 --- a/socketCAN/CO_epoll_interface.c +++ b/socketCAN/CO_epoll_interface.c @@ -43,6 +43,7 @@ #include #include #include +#include #ifndef LISTEN_BACKLOG #define LISTEN_BACKLOG 50 @@ -342,7 +343,11 @@ void CO_epoll_processRT(CO_epoll_t *ep, /* GATEWAY ********************************************************************/ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII /* write response string from gateway-ascii object */ -static size_t gtwa_write_response(void *object, const char *buf, size_t count) { +static size_t gtwa_write_response(void *object, + const char *buf, + size_t count, + uint8_t *connectionOK) +{ int* fd = (int *)object; /* nWritten = count -> in case of error (non-existing fd) data are purged */ size_t nWritten = count; @@ -353,9 +358,14 @@ static size_t gtwa_write_response(void *object, const char *buf, size_t count) { nWritten = (size_t)n; } else { + /* probably EAGAIN - "Resource temporarily unavailable". Retry. */ log_printf(LOG_DEBUG, DBG_ERRNO, "write(gtwa_response)"); + nWritten = 0; } } + else { + *connectionOK = 0; + } return nWritten; } @@ -424,6 +434,14 @@ CO_ReturnError_t CO_epoll_createGtw(CO_epoll_gtw_t *epGtw, return CO_ERROR_SYSCALL; } + /* Ignore the SIGPIPE signal, which may happen, if remote client broke + * the connection. Signal may be triggered by write call inside + * gtwa_write_response() function */ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + log_printf(LOG_CRIT, DBG_ERRNO, "signal"); + return CO_ERROR_SYSCALL; + } + log_printf(LOG_INFO, DBG_COMMAND_LOCAL_INFO, localSocketPath); } else if (commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN && @@ -460,6 +478,14 @@ CO_ReturnError_t CO_epoll_createGtw(CO_epoll_gtw_t *epGtw, return CO_ERROR_SYSCALL; } + /* Ignore the SIGPIPE signal, which may happen, if remote client broke + * the connection. Signal may be triggered by write call inside + * gtwa_write_response() function */ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + log_printf(LOG_CRIT, DBG_ERRNO, "signal"); + return CO_ERROR_SYSCALL; + } + log_printf(LOG_INFO, DBG_COMMAND_TCP_INFO, commandInterface); } else { @@ -579,8 +605,8 @@ void CO_epoll_processGtw(CO_epoll_gtw_t *epGtw, ssize_t s = read(epGtw->gtwa_fd, buf, space); - if (co->nodeIdUnconfigured) { - /* purge data */ + if (space == 0 || co->nodeIdUnconfigured) { + /* continue or purge data */ } else if (s < 0 && errno != EAGAIN) { log_printf(LOG_DEBUG, DBG_ERRNO, "read(gtwa_fd)"); diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index ae76d566..b038fdee 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -59,6 +59,7 @@ extern "C" { */ #define DBG_GENERAL "(%s) Error: %s%d", __func__ #define DBG_ERRNO "(%s) OS error \"%s\" in %s", __func__, strerror(errno) +#define DBG_CO_DEBUG "(%s) CO_DEBUG: %s", __func__ #define DBG_CAN_TX_FAILED "(%s) Transmitting CAN msg OID 0x%08x failed(%s)", __func__ #define DBG_CAN_RX_PARAM_FAILED "(%s) Setting CAN rx buffer failed (%s)", __func__ #define DBG_CAN_RX_FAILED "(%s) Receiving CAN msg failed (%s)", __func__ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 59494a9c..191c25ef 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -1,14 +1,13 @@ /* - * CANopen main program file for Linux SocketCAN. + * CANopen main program file for CANopenNode on Linux. * - * @file main.c + * @file CO_main_basic.c * @author Janez Paternoster - * @copyright 2015 - 2020 Janez Paternoster + * @copyright 2020 Janez Paternoster * - * This file is part of CANopenSocket, a Linux implementation of CANopen - * stack with master functionality. Project home page is - * . CANopenSocket is based - * on CANopenNode: . + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -51,9 +51,8 @@ #endif /* Call external application functions. */ -#if __has_include("CO_application.h") +#ifdef CO_USE_APPLICATION #include "CO_application.h" -#define CO_USE_APPLICATION #endif /* Add trace functionality for recording variables over time */ @@ -86,12 +85,21 @@ #ifndef FIRST_HB_TIME #define FIRST_HB_TIME 500 #endif -#ifndef SDO_TIMEOUT_TIME -#define SDO_TIMEOUT_TIME 1000 +#ifndef SDO_SRV_TIMEOUT_TIME +#define SDO_SRV_TIMEOUT_TIME 1000 +#endif +#ifndef SDO_CLI_TIMEOUT_TIME +#define SDO_CLI_TIMEOUT_TIME 500 +#endif +#ifndef SDO_CLI_BLOCK +#define SDO_CLI_BLOCK false #endif #ifndef GATEWAY_ENABLE #define GATEWAY_ENABLE true #endif +#ifndef OD_STATUS_BITS +#define OD_STATUS_BITS NULL +#endif /* Other variables and objects */ #ifndef CO_SINGLE_THREAD @@ -153,6 +161,7 @@ void log_printf(int priority, const char *format, ...) { #endif } +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER /* callback for emergency messages */ static void EmergencyRxCallback(const uint16_t ident, const uint16_t errorCode, @@ -165,7 +174,10 @@ static void EmergencyRxCallback(const uint16_t ident, log_printf(LOG_NOTICE, DBG_EMERGENCY_RX, nodeIdRx, errorCode, errorRegister, errorBit, infoCode); } +#endif +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) \ + || ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) /* return string description of NMT state. */ static char *NmtState2Str(CO_NMT_internalState_t state) { @@ -177,12 +189,15 @@ static char *NmtState2Str(CO_NMT_internalState_t state) default: return "unknown"; } } +#endif +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE /* callback for NMT change messages */ static void NmtChangedCallback(CO_NMT_internalState_t state) { log_printf(LOG_NOTICE, DBG_NMT_CHANGE, NmtState2Str(state), state); } +#endif #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE /* callback for monitoring Heartbeat remote NMT state change */ @@ -252,6 +267,7 @@ printf( * Mainline thread ******************************************************************************/ int main (int argc, char *argv[]) { + int programExit = EXIT_SUCCESS; CO_epoll_t epMain; #ifndef CO_SINGLE_THREAD pthread_t rt_thread_id; @@ -290,9 +306,6 @@ int main (int argc, char *argv[]) { exit(EXIT_SUCCESS); } while((opt = getopt(argc, argv, "i:p:rc:T:s:a:")) != -1) { - const char comm_stdio[] = "stdio"; - const char comm_local[] = "local-"; - const char comm_tcp[] = "tcp-"; switch (opt) { case 'i': CO_pendingNodeId = (uint8_t)strtol(optarg, NULL, 0); @@ -305,7 +318,10 @@ int main (int argc, char *argv[]) { case 'r': rebootEnable = true; break; #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - case 'c': + case 'c': { + const char *comm_stdio = "stdio"; + const char *comm_local = "local-"; + const char *comm_tcp = "tcp-"; if (strcmp(optarg, comm_stdio) == 0) { commandInterface = CO_COMMAND_IF_STDIO; } @@ -328,6 +344,7 @@ int main (int argc, char *argv[]) { exit(EXIT_FAILURE); } break; + } case 'T': socketTimeout_ms = strtoul(optarg, NULL, 0); break; @@ -472,7 +489,9 @@ int main (int argc, char *argv[]) { err = CO_CANinit(CO, (void *)&CANptr, 0 /* bit rate not used */); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANinit()", err); - exit(EXIT_FAILURE); + programExit = EXIT_FAILURE; + CO_endProgram = 1; + continue; } CO_LSS_address_t lssAddress = {.identity = { @@ -485,7 +504,9 @@ int main (int argc, char *argv[]) { &CO_pendingNodeId, &CO_pendingBitRate); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_LSSinit()", err); - exit(EXIT_FAILURE); + programExit = EXIT_FAILURE; + CO_endProgram = 1; + continue; } CO_activeNodeId = CO_pendingNodeId; @@ -494,10 +515,12 @@ int main (int argc, char *argv[]) { NULL, /* alternate NMT */ NULL, /* alternate em */ &OD, /* Object dictionary */ - NULL, /* Optional OD_statusBits */ + OD_STATUS_BITS, /* Optional OD_statusBits */ NMT_CONTROL, /* CO_NMT_control_t */ FIRST_HB_TIME, /* firstHBTime_ms */ - SDO_TIMEOUT_TIME, /* SDOtimeoutTime_ms */ + SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */ + SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */ + SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ CO_activeNodeId); if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { if (err == CO_ERROR_OD_PARAMETERS) { @@ -507,7 +530,9 @@ int main (int argc, char *argv[]) { else { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); } - exit(EXIT_FAILURE); + programExit = EXIT_FAILURE; + CO_endProgram = 1; + continue; } /* initialize part of threadMain and callbacks */ @@ -520,8 +545,12 @@ int main (int argc, char *argv[]) { LSScfgStoreCallback); #endif if(!CO->nodeIdUnconfigured) { +#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); +#endif +#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); +#endif #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, HeartbeatNmtChangedCallback); @@ -555,7 +584,9 @@ int main (int argc, char *argv[]) { /* Create rt_thread and set priority */ if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) { log_printf(LOG_CRIT, DBG_ERRNO, "pthread_create(rt_thread)"); - exit(EXIT_FAILURE); + programExit = EXIT_FAILURE; + CO_endProgram = 1; + continue; } if(rtPriority > 0) { struct sched_param param; @@ -563,13 +594,27 @@ int main (int argc, char *argv[]) { param.sched_priority = rtPriority; if (pthread_setschedparam(rt_thread_id, SCHED_FIFO, ¶m) != 0) { log_printf(LOG_CRIT, DBG_ERRNO, "pthread_setschedparam()"); - exit(EXIT_FAILURE); + programExit = EXIT_FAILURE; + CO_endProgram = 1; + continue; } } #endif #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_programStart(!CO->nodeIdUnconfigured); + uint16_t errinfo = 0; + err = app_programStart(!CO->nodeIdUnconfigured, &errinfo); + if(err != CO_ERROR_NO) { + if (err == CO_ERROR_OD_PARAMETERS) { + log_printf(LOG_CRIT, DBG_OD_ENTRY, errinfo); + } + else { + log_printf(LOG_CRIT, DBG_CAN_OPEN, "app_programStart()", err); + } + programExit = EXIT_FAILURE; + CO_endProgram = 1; + continue; + } #endif } /* if(firstRun) */ @@ -654,7 +699,7 @@ int main (int argc, char *argv[]) { } } - exit(EXIT_SUCCESS); + exit(programExit); } #ifndef CO_SINGLE_THREAD @@ -680,7 +725,7 @@ static void* rt_thread(void* arg) { #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_program1ms(!CO->nodeIdUnconfigured); + app_program1ms(!CO->nodeIdUnconfigured, epRT.timeDifference_us); #endif } From d62de8dc6479cda2afa4f20303783312bc17e878 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 28 Dec 2020 13:23:57 +0100 Subject: [PATCH 143/520] Minor updates --- 301/CO_driver.h | 2 +- 301/CO_fifo.h | 2 +- README.md | 5 +++-- doc/gettingStarted.md | 4 ++-- example/CO_driver_target.h | 4 ---- socketCAN/CO_driver_target.h | 3 --- socketCAN/CO_main_basic.c | 8 ++++---- 7 files changed, 11 insertions(+), 17 deletions(-) diff --git a/301/CO_driver.h b/301/CO_driver.h index 9330c355..ae85f68a 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -422,7 +422,7 @@ typedef struct { * - 'CO_ERROR_OD_PARAMETERS' - Index of erroneous OD parameter. */ #ifndef CO_errinfo -#define CO_errinfo(CANmodule, err) +#define CO_errinfo(CANmodule, err) CANmodule->errinfo = err #endif diff --git a/301/CO_fifo.h b/301/CO_fifo.h index e5eecc5c..968e39d1 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -459,7 +459,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); * enclosed with double quotes. If a double quote is used within the string, * the quotes are escaped by a second quotes, e.g. “Hello “”World””, CANopen * is great”. UTF-8 characters and also line breaks works with this function. - * Function removes all '\0' and '\r' characters from output string. + * Function removes all NULL and CR characters from output string. * See also CO_fifo_readU82a */ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); /** Read data from fifo and output as mime-base64 encoded string. Encoding is as diff --git a/README.md b/README.md index 2e7ee608..30579ec4 100644 --- a/README.md +++ b/README.md @@ -222,12 +222,13 @@ files for Object Dictionary. If new project was started, then `DS301_profile.xpd` may be inserted. If existing (old) project is edited, then existing `Communication Specific Parameters` -may be Deleted and then new `DS301_profile.xpd` may be inserted. Alternative is +may be deleted and then new `DS301_profile.xpd` may be inserted. Alternative is editing existing communication parameters with observation to Object Dictionary Requirements By CANopenNode in [objectDictionary.md](doc/objectDictionary.md). To clone, add or delete, select object(s) and use right click. Some knowledge -of CANopen is required to correctly set-up the custom Object Dictionary. +of CANopen is required to correctly set-up the custom Object Dictionary. Separate +objects can also be inserted from another project. CANopenNode includes some custom properties inside standard project file. See [objectDictionary.md](doc/objectDictionary.md) for more information. diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index 5f95d03f..fa523a04 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -46,7 +46,7 @@ Go to the first terminal, where we have recently build executable, named _canope First print help, then run the program with some options. ./canopend --help - ./canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto + ./canopend vcan0 -i 4 #-s od4_storage -a od4_storage_auto You are now running a fully functional CANopen device on virtual CAN network. It is running in background until you terminate the process (with CTRL+C for example) or it receives a reset message from CAN network. By default process also shows some info messages on terminal, for example changes of NMT state or emergency messages, own and remote. @@ -67,7 +67,7 @@ You can follow the reason of the problem inside the source code. However, there echo "-" > od4_storage echo "-" > od4_storage_auto - ./canopend vcan0 -i 4 -s od4_storage -a od4_storage_auto + ./canopend vcan0 -i 4 #-s od4_storage -a od4_storage_auto Second terminal now shows new boot-up message without emergency. diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 49d1bdc9..df8cfbb6 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -177,10 +177,6 @@ extern "C" { #endif -/* Macro for passing additional information about error, see CO_driver.h. */ -#define CO_errinfo(CANmodule, err) CANmodule->errinfo = err - - /* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ #define CO_LITTLE_ENDIAN #define CO_SWAP_16(x) x diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index b561d119..37267db6 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -198,9 +198,6 @@ extern "C" { * Linux socketCAN specific @ref CO_driver definitions for CANopenNode. */ -/* Macro for passing additional information about error, see CO_driver.h. */ -#define CO_errinfo(CANmodule, err) CANmodule->errinfo = err - /** * Multi interface support * diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 191c25ef..709b13df 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -495,10 +495,10 @@ int main (int argc, char *argv[]) { } CO_LSS_address_t lssAddress = {.identity = { - .vendorID = 1, - .productCode = 2, - .revisionNumber = 3, - .serialNumber = 4 + .vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, + .productCode = OD_PERSIST_COMM.x1018_identity.productCode, + .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, + .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber }}; err = CO_LSSinit(CO, &lssAddress, &CO_pendingNodeId, &CO_pendingBitRate); From 267a2dafb29124b814215c5046922075ea03b48f Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 5 Jan 2021 09:22:19 +0100 Subject: [PATCH 144/520] Replace type char with uint8_t or int8_t, where appropriate 305/CO_LSS.h now passing -Wextra warnings --- 301/CO_SDOclient.c | 20 ++-- 301/CO_SDOclient.h | 6 +- 301/CO_fifo.c | 223 +++++++++++++++++++++-------------------- 301/CO_fifo.h | 18 ++-- 305/CO_LSS.h | 12 ++- 309/CO_gateway_ascii.c | 7 +- 309/CO_gateway_ascii.h | 6 +- socketCAN/CO_error.c | 2 +- 8 files changed, 152 insertions(+), 142 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 1d979662..edbe1228 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -115,7 +115,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { /* Copy data. There is always enough space in fifo buffer, * because block_blksize was calculated before */ CO_fifo_write(&SDO_C->bufFifo, - (const char *)&data[1], + &data[1], 7, &SDO_C->block_crc); SDO_C->sizeTran += 7; /* all segments in sub-block has been transferred */ @@ -497,7 +497,7 @@ void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, /******************************************************************************/ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, - const char *buf, + const uint8_t *buf, size_t count) { size_t ret = 0; @@ -907,7 +907,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* copy data */ CO_fifo_read(&SDO_C->bufFifo, - (char *)&SDO_C->CANtxBuff->data[4], count, NULL); + &SDO_C->CANtxBuff->data[4], count, NULL); SDO_C->sizeTran = count; SDO_C->finished = true; } @@ -938,7 +938,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { /* fill data bytes */ count = CO_fifo_read(&SDO_C->bufFifo, - (char *)&SDO_C->CANtxBuff->data[1], + &SDO_C->CANtxBuff->data[1], 7, NULL); /* verify if sizeTran is too large */ @@ -1002,7 +1002,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* get up to 7 data bytes */ count = CO_fifo_altRead(&SDO_C->bufFifo, - (char *)&SDO_C->CANtxBuff->data[1], 7); + &SDO_C->CANtxBuff->data[1], 7); SDO_C->block_noData = 7 - count; /* verify if sizeTran is too large */ @@ -1318,7 +1318,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* copy data, indicate size and finish */ CO_fifo_write(&SDO_C->bufFifo, - (const char *)&SDO_C->CANrxData[4], + &SDO_C->CANrxData[4], count, NULL); SDO_C->sizeTran = count; SDO_C->state = CO_SDO_ST_IDLE; @@ -1364,7 +1364,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* get data size and write data to the buffer */ count = 7 - ((SDO_C->CANrxData[0] >> 1) & 0x07); countWr = CO_fifo_write(&SDO_C->bufFifo, - (const char *)&SDO_C->CANrxData[1], + &SDO_C->CANrxData[1], count, NULL); SDO_C->sizeTran += countWr; @@ -1462,7 +1462,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* copy data, indicate size and finish */ CO_fifo_write(&SDO_C->bufFifo, - (const char *)&SDO_C->CANrxData[4], + &SDO_C->CANrxData[4], count, NULL); SDO_C->sizeTran = count; SDO_C->state = CO_SDO_ST_IDLE; @@ -1497,7 +1497,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, * contain data. Then copy remaining data into fifo */ uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07); CO_fifo_write(&SDO_C->bufFifo, - (const char *)&SDO_C->block_dataUploadLast[0], + &SDO_C->block_dataUploadLast[0], 7 - noData, &SDO_C->block_crc); SDO_C->sizeTran += 7 - noData; @@ -1810,7 +1810,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /******************************************************************************/ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, - char *buf, + uint8_t *buf, size_t count) { size_t ret = 0; diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 5111e5ed..6127ab30 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -119,7 +119,7 @@ typedef struct { CO_fifo_t bufFifo; /** Data buffer of usable size @ref CO_CONFIG_SDO_CLI_BUFFER_SIZE, used * inside bufFifo. Must be one byte larger for fifo usage. */ - char buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; + uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; /** Indicates, if new SDO message received from CAN bus. It is not cleared, * until received message is completely processed. */ volatile void *CANrxNew; @@ -298,7 +298,7 @@ void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, * @return number of bytes actually written. */ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, - const char *buf, + const uint8_t *buf, size_t count); @@ -421,7 +421,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, * @return number of bytes actually read. */ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, - char *buf, + uint8_t *buf, size_t count); diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 6f49c54c..b0042383 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -37,9 +37,11 @@ #include /* Non-graphical character for command delimiter */ -#define DELIM_COMMAND '\n' +#define DELIM_COMMAND ((uint8_t)'\n') /* Graphical character for comment delimiter */ -#define DELIM_COMMENT '#' +#define DELIM_COMMENT ((uint8_t)'#') +/* Graphical character for double quotes */ +#define DELIM_DQUOTE ((uint8_t)'"') #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ /* verify configuration */ @@ -50,7 +52,7 @@ #endif /******************************************************************************/ -void CO_fifo_init(CO_fifo_t *fifo, char *buf, size_t bufSize) { +void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize) { if (fifo == NULL || buf == NULL || bufSize < 2) { return; @@ -79,12 +81,12 @@ void CO_fifo_init(CO_fifo_t *fifo, char *buf, size_t bufSize) { * buffer in buff in buff full * ******************************************************************************/ size_t CO_fifo_write(CO_fifo_t *fifo, - const char *buf, + const uint8_t *buf, size_t count, uint16_t *crc) { size_t i; - char *bufDest; + uint8_t *bufDest; if (fifo == NULL || fifo->buf == NULL || buf == NULL) { return 0; @@ -104,7 +106,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, #if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT if (crc != NULL) { - crc16_ccitt_single(crc, (unsigned char)*buf); + crc16_ccitt_single(crc, *buf); } #endif @@ -125,9 +127,9 @@ size_t CO_fifo_write(CO_fifo_t *fifo, /******************************************************************************/ -size_t CO_fifo_read(CO_fifo_t *fifo, char *buf, size_t count, bool_t *eof) { +size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { size_t i; - const char *bufSrc; + const uint8_t *bufSrc; if (eof != NULL) { *eof = false; @@ -138,7 +140,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, char *buf, size_t count, bool_t *eof) { bufSrc = &fifo->buf[fifo->readPtr]; for (i = count; i > 0; ) { - const char c = *bufSrc; + const uint8_t c = *bufSrc; /* is circular buffer empty */ if (fifo->readPtr == fifo->writePtr) { @@ -205,10 +207,10 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { fifo->readPtr = fifo->altReadPtr; } else { - const char *bufSrc = &fifo->buf[fifo->readPtr]; + const uint8_t *bufSrc = &fifo->buf[fifo->readPtr]; while (fifo->readPtr != fifo->altReadPtr) { #if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT - crc16_ccitt_single(crc, (unsigned char)*bufSrc); + crc16_ccitt_single(crc, *bufSrc); #endif /* increment variable */ if (++fifo->readPtr == fifo->bufSize) { @@ -222,13 +224,13 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { } } -size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count) { +size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count) { size_t i; - const char *bufSrc; + const uint8_t *bufSrc; bufSrc = &fifo->buf[fifo->altReadPtr]; for (i = count; i > 0; i--) { - const char c = *bufSrc; + const uint8_t c = *bufSrc; /* is there no more data */ if (fifo->altReadPtr == fifo->writePtr) { @@ -257,7 +259,7 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count) { bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { bool_t newCommand = false; size_t count; - char *commandEnd; + uint8_t *commandEnd; if (fifo == NULL || fifo->readPtr == fifo->writePtr) { return 0; @@ -269,17 +271,17 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { } else { count = fifo->bufSize - fifo->readPtr; } - commandEnd = (char *)memchr((const void *)&fifo->buf[fifo->readPtr], - DELIM_COMMAND, - count); + commandEnd = (uint8_t *)memchr((const void *)&fifo->buf[fifo->readPtr], + (int)DELIM_COMMAND, + count); if (commandEnd != NULL) { newCommand = true; } else if (fifo->readPtr > fifo->writePtr) { /* not found, search in the beginning of the circular buffer */ - commandEnd = (char *)memchr((const void *)&fifo->buf[0], - DELIM_COMMAND, - fifo->writePtr); + commandEnd = (uint8_t *)memchr((const void *)&fifo->buf[0], + (int)DELIM_COMMAND, + fifo->writePtr); if (commandEnd != NULL || fifo->readPtr == (fifo->writePtr + 1)) { /* command delimiter found or buffer full */ newCommand = true; @@ -293,7 +295,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { /* Clear buffer if set so */ if (clear) { if (commandEnd != NULL) { - fifo->readPtr = (int)(commandEnd - fifo->buf) + 1; + fifo->readPtr = (size_t)(commandEnd - fifo->buf) + 1; if (fifo->readPtr == fifo->bufSize) { fifo->readPtr = 0; } @@ -313,7 +315,7 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { if (fifo != NULL && insideComment != NULL) { while (fifo->readPtr != fifo->writePtr) { - char c = fifo->buf[fifo->readPtr]; + uint8_t c = fifo->buf[fifo->readPtr]; if (c == DELIM_COMMENT) { *insideComment = true; @@ -339,7 +341,7 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { size_t CO_fifo_readToken(CO_fifo_t *fifo, char *buf, size_t count, - char *closed, + int8_t *closed, bool_t *err) { bool_t delimCommandFound = false; @@ -350,9 +352,9 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, && fifo->readPtr != fifo->writePtr ) { bool_t finished = false; - char step = 0; + uint8_t step = 0; size_t ptr = fifo->readPtr; /* current pointer (integer, 0 based) */ - char *c = &fifo->buf[ptr]; /* current char */ + uint8_t *c = &fifo->buf[ptr]; /* current character */ do { switch (step) { case 0: /* skip leading empty characters, stop on delimiter */ @@ -360,7 +362,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, if (*c == DELIM_COMMENT) { delimCommentFound = true; } else { - buf[tokenSize++] = *c; + buf[tokenSize++] = (char)*c; step++; } } @@ -373,7 +375,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, if (*c == DELIM_COMMENT) { delimCommentFound = true; } else if (tokenSize < count) { - buf[tokenSize++] = *c; + buf[tokenSize++] = (char)*c; } } else { @@ -446,7 +448,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, *closed = delimCommandFound ? 1 : 0; } - /* token was larger then size of the buffer, all was cleaned, return '' */ + /* token was larger then size of the buffer, all was cleaned, return empty*/ if (tokenSize == count) { tokenSize = 0; } @@ -470,21 +472,21 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, static const char base64EncTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char base64DecTable[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1,103,101, -1, -1,102, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 103, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1,100, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1}; +static const uint8_t base64DecTable[] = { + 255,255,255,255,255,255,255,255,255,103,101,255,255,102,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 103,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,100,255,255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255}; size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, &n, sizeof(n), NULL); return sprintf(buf, "%"PRIu8, n); } else { @@ -496,7 +498,7 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); } else { @@ -508,7 +510,7 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); } else { @@ -520,7 +522,7 @@ size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); } else { @@ -532,7 +534,7 @@ size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%02"PRIX8, n); } else { @@ -544,7 +546,7 @@ size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); } else { @@ -556,7 +558,7 @@ size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); } else { @@ -568,7 +570,7 @@ size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); } else { @@ -580,7 +582,7 @@ size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int8_t n=0; if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId8, n); } else { @@ -592,7 +594,7 @@ size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int16_t n=0; if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId16, CO_SWAP_16(n)); } else { @@ -604,7 +606,7 @@ size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int32_t n=0; if (fifo != NULL && count >= 13 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId32, CO_SWAP_32(n)); } else { @@ -616,7 +618,7 @@ size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int64_t n=0; if (fifo != NULL && count >= 23 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId64, CO_SWAP_64(n)); } else { @@ -628,7 +630,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float32_t n=0; if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", CO_SWAP_32(n)); } else { @@ -640,7 +642,7 @@ size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float64_t n=0; if (fifo != NULL && count >= 30 && CO_fifo_getOccupied(fifo) == sizeof(n)) { - CO_fifo_read(fifo, (char *)&n, sizeof(n), NULL); + CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", CO_SWAP_64(n)); } else { @@ -656,19 +658,19 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if (fifo != NULL && count > 3) { /* Very first write is without leading space */ if (!fifo->started) { - char c; + uint8_t c; if(CO_fifo_getc(fifo, &c)) { - len = sprintf(&buf[0], "%02"PRIX8, (uint8_t)c); + len = sprintf(&buf[0], "%02"PRIX8, c); fifo->started = true; } } while ((len + 3) < count) { - char c; + uint8_t c; if(!CO_fifo_getc(fifo, &c)) { break; } - len += sprintf(&buf[len], " %02"PRIX8, (uint8_t)c); + len += sprintf(&buf[len], " %02"PRIX8, c); } } @@ -686,17 +688,18 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } while ((len + 2) < count) { - char c; + uint8_t c; if(!CO_fifo_getc(fifo, &c)) { if (end) { buf[len++] = '"'; } break; } - else if (c != 0 && c != '\r') { /* skip null and CR inside string */ - buf[len++] = c; - if (c == '"') { - buf[len++] = c; + else if (c != 0 && c != (uint8_t)'\r') { + /* skip null and CR inside string */ + buf[len++] = (char)c; + if (c == DELIM_DQUOTE) { + buf[len++] = '"'; } } } @@ -726,7 +729,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } while ((len + 3) <= count) { - char c; + uint8_t c; if(!CO_fifo_getc(fifo, &c)) { /* buffer is empty, is also SDO communication finished? */ @@ -747,7 +750,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { break; } - word |= (uint8_t)c; + word |= c; switch (step++) { case 0: @@ -776,7 +779,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { /******************************************************************************/ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -788,7 +791,7 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (sRet != strchr(buf, '\0') || u32 > UINT8_MAX) st |= CO_fifo_st_errVal; else { uint8_t num = (uint8_t) u32; - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, &num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -798,7 +801,7 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -810,7 +813,7 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (sRet != strchr(buf, '\0') || u32 > UINT16_MAX) st |= CO_fifo_st_errVal; else { uint16_t num = CO_SWAP_16((uint16_t) u32); - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -820,7 +823,7 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -832,7 +835,7 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { uint32_t num = CO_SWAP_32(u32); - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -842,7 +845,7 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[25]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -854,7 +857,7 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { uint64_t num = CO_SWAP_64(u64); - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -864,7 +867,7 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -877,7 +880,7 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { st |= CO_fifo_st_errVal; } else { int8_t num = (int8_t) i32; - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -887,7 +890,7 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -900,7 +903,7 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { st |= CO_fifo_st_errVal; } else { int16_t num = CO_SWAP_16((int16_t) i32); - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -910,7 +913,7 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[15]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -922,7 +925,7 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { int32_t num = CO_SWAP_32(i32); - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -932,7 +935,7 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[25]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -944,7 +947,7 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { int64_t num = CO_SWAP_64(i64); - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -954,7 +957,7 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[30]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -966,7 +969,7 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { float32_t num = CO_SWAP_32(f32); - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -976,7 +979,7 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { char buf[40]; - char closed = -1; + int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -988,7 +991,7 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; else { float64_t num = CO_SWAP_64(f64); - nWr = CO_fifo_write(dest, (const char *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; } } @@ -1000,7 +1003,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t destSpace, destSpaceStart; bool_t finished = false; uint8_t step; - char firstChar; + uint8_t firstChar; CO_fifo_st st = 0; if (dest == NULL || src == NULL) { @@ -1024,13 +1027,13 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else { /* get memorized variables from previous function calls */ step = (uint8_t)(dest->aux >> 8); - firstChar = (char)(dest->aux & 0xFF); + firstChar = (uint8_t)(dest->aux & 0xFF); } /* repeat until destination space available and no error and not finished * and source characters available */ while (destSpace > 0 && (st & CO_fifo_st_errMask) == 0 && !finished) { - char c; + uint8_t c; if (!CO_fifo_getc(src, &c)) { break; } @@ -1053,18 +1056,18 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } else { /* write the byte */ - char s[3]; + uint8_t s[3]; int32_t num; s[0] = firstChar; s[1] = c; s[2] = 0; - num = strtol(s, NULL, 16); - CO_fifo_putc(dest, (char) num); + num = strtol((char *)&s[0], NULL, 16); + CO_fifo_putc(dest, (uint8_t) num); destSpace--; step = 0; } } else if (isgraph((int)c) != 0) { /* printable character, not hex digit */ - if (c == '#') /* comment start */ + if (c == DELIM_COMMENT) /* comment start */ step = 6; else /* syntax error */ st |= CO_fifo_st_errTok; @@ -1073,11 +1076,11 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* this is space or delimiter */ if (step == 1) { /* write the byte */ - char s[2]; + uint8_t s[2]; int32_t num; s[0] = firstChar; s[1] = 0; - num = strtol(s, NULL, 16); - CO_fifo_putc(dest, (char) num); + num = strtol((char *)&s[0], NULL, 16); + CO_fifo_putc(dest, (uint8_t) num); destSpace--; step = 0; } @@ -1096,7 +1099,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (!finished) { st |= CO_fifo_st_partial; /* memorize variables for next iteration */ - dest->aux = (uint32_t)step << 8 | (uint8_t)firstChar; + dest->aux = (uint32_t)step << 8 | firstChar; } if (status != NULL) *status = st; @@ -1135,14 +1138,14 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* repeat until destination space available and no error and not finished * and source characters available */ while (destSpace > 0 && (st & CO_fifo_st_errMask) == 0 && !finished) { - char c; + uint8_t c; if (!CO_fifo_getc(src, &c)) { break; } switch (step) { case 0: /* beginning of the string, first write into dest */ - if (c == '"') { + if (c == DELIM_DQUOTE) { /* Indicated beginning of the string, skip this character. */ step = 1; } @@ -1157,7 +1160,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { case 1: /* inside string, quoted string */ case 2: /* inside string, single word, no quotes */ - if (c == '"') { + if (c == DELIM_DQUOTE) { /* double quote found, this may be end of the string or escaped * double quote (with two double quotes) */ step += 2; @@ -1188,7 +1191,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { case 3: /* previous was double quote, parsing quoted string */ case 4: /* previous was double quote, parsing no quoted word */ - if (c == '"') { + if (c == DELIM_DQUOTE) { /* escaped double quote, copy the character and continue */ CO_fifo_putc(dest, c); destSpace--; @@ -1232,7 +1235,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { step = 6; } else if (isgraph((int)c) != 0) { - if (c == '#') /* comment start */ + if (c == DELIM_COMMENT) /* comment start */ step = 6; else /* syntax error */ st |= CO_fifo_st_errTok; @@ -1300,7 +1303,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* repeat until destination space available and no error and not finished * and source characters available */ while (destSpace >= 3 && (st & CO_fifo_st_errMask) == 0 && !finished) { - char c; + uint8_t c; if (!CO_fifo_getc(src, &c)) { break; } @@ -1315,8 +1318,8 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else if (insideComment) { step = 6; } - else if (isgraph((int)c) != 0 && c != '=') { - if (c == '#') /* comment start */ + else if (isgraph((int)c) != 0 && c != (uint8_t)'=') { + if (c == DELIM_COMMENT) /* comment start */ step = 6; else /* syntax error */ st |= CO_fifo_st_errTok; @@ -1324,21 +1327,21 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { continue; } - char code = base64DecTable[c & 0x7F]; + uint8_t code = base64DecTable[c & 0x7F]; - if (c < 0 || code < 0) { + if ((c & 0x80) != 0 || (code & 0x80) != 0) { st |= CO_fifo_st_errTok; } else if (code >= 64 /* '=' (pad) or DELIM_COMMAND or space */) { /* base64 string finished, write remaining bytes */ switch (step) { case 2: - CO_fifo_putc(dest, (char)(dword >> 4)); + CO_fifo_putc(dest, (uint8_t)(dword >> 4)); destSpace --; break; case 3: - CO_fifo_putc(dest, (char)(dword >> 10)); - CO_fifo_putc(dest, (char)(dword >> 2)); + CO_fifo_putc(dest, (uint8_t)(dword >> 10)); + CO_fifo_putc(dest, (uint8_t)(dword >> 2)); destSpace -= 2; break; } @@ -1355,9 +1358,9 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else { dword = (dword << 6) | code; if (step++ == 3) { - CO_fifo_putc(dest, (char)((dword >> 16) & 0xFF)); - CO_fifo_putc(dest, (char)((dword >> 8) & 0xFF)); - CO_fifo_putc(dest, (char)(dword & 0xFF)); + CO_fifo_putc(dest, (uint8_t)((dword >> 16) & 0xFF)); + CO_fifo_putc(dest, (uint8_t)((dword >> 8) & 0xFF)); + CO_fifo_putc(dest, (uint8_t)(dword & 0xFF)); destSpace -= 3; dword = 0; step = 0; diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 968e39d1..b7034140 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -59,7 +59,7 @@ extern "C" { */ typedef struct { /** Buffer of size bufSize. Initialized by CO_fifo_init() */ - char *buf; + uint8_t *buf; /** Initialized by CO_fifo_init() */ size_t bufSize; /** Location in the buffer, which will be next written. */ @@ -89,7 +89,7 @@ typedef struct { * @param bufSize Size of the above buffer. Usable size of the buffer will be * one byte less than bufSize, it is used for operation of the circular buffer. */ -void CO_fifo_init(CO_fifo_t *fifo, char *buf, size_t bufSize); +void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize); /** @@ -170,7 +170,7 @@ static inline size_t CO_fifo_getOccupied(CO_fifo_t *fifo) { * * @return true, if write was successful (enough space in fifo buffer) */ -static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const char c) { +static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const uint8_t c) { if (fifo != NULL && fifo->buf != NULL) { size_t writePtrNext = fifo->writePtr + 1; if (writePtrNext != fifo->readPtr && @@ -193,7 +193,7 @@ static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const char c) { * @param fifo This object * @param c Character to put */ -static inline void CO_fifo_putc_ov(CO_fifo_t *fifo, const char c) { +static inline void CO_fifo_putc_ov(CO_fifo_t *fifo, const uint8_t c) { if (fifo != NULL && fifo->buf != NULL) { fifo->buf[fifo->writePtr] = c; @@ -213,7 +213,7 @@ static inline void CO_fifo_putc_ov(CO_fifo_t *fifo, const char c) { * * @return true, if read was successful (non-empty fifo buffer) */ -static inline bool_t CO_fifo_getc(CO_fifo_t *fifo, char *buf) { +static inline bool_t CO_fifo_getc(CO_fifo_t *fifo, uint8_t *buf) { if (fifo != NULL && buf != NULL && fifo->readPtr != fifo->writePtr) { *buf = fifo->buf[fifo->readPtr]; if (++fifo->readPtr == fifo->bufSize) { @@ -241,7 +241,7 @@ static inline bool_t CO_fifo_getc(CO_fifo_t *fifo, char *buf) { * @return number of bytes actually written. */ size_t CO_fifo_write(CO_fifo_t *fifo, - const char *buf, + const uint8_t *buf, size_t count, uint16_t *crc); @@ -262,7 +262,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, * * @return number of bytes actually read. */ -size_t CO_fifo_read(CO_fifo_t *fifo, char *buf, size_t count, bool_t *eof); +size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof); #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) || defined CO_DOXYGEN @@ -320,7 +320,7 @@ static inline size_t CO_fifo_altGetOccupied(CO_fifo_t *fifo) { * * @return number of bytes actually read. */ -size_t CO_fifo_altRead(CO_fifo_t *fifo, char *buf, size_t count); +size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count); #endif /* #if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ */ @@ -409,7 +409,7 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment); size_t CO_fifo_readToken(CO_fifo_t *fifo, char *buf, size_t count, - char *closed, + int8_t *closed, bool_t *err); #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ diff --git a/305/CO_LSS.h b/305/CO_LSS.h index 1540bc0e..b1d62748 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -141,7 +141,8 @@ typedef enum { CO_LSS_FASTSCAN_CONFIRM = 0x80U /**< All LSS slaves waiting for scan respond and previous scan is reset */ } CO_LSS_fastscan_bitcheck; -#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit>=CO_LSS_FASTSCAN_BIT0 && bit<=CO_LSS_FASTSCAN_BIT31) || bit==CO_LSS_FASTSCAN_CONFIRM) +/* comparision is always true: bit>=CO_LSS_FASTSCAN_BIT0 */ +#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) (bit<=CO_LSS_FASTSCAN_BIT31 || bit==CO_LSS_FASTSCAN_CONFIRM) /** * Fastscan LSSsub, LSSnext @@ -153,7 +154,8 @@ typedef enum { CO_LSS_FASTSCAN_SERIAL = 3 /**< Serial number */ } CO_LSS_fastscan_lss_sub_next; -#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index>=CO_LSS_FASTSCAN_VENDOR_ID && index<=CO_LSS_FASTSCAN_SERIAL) +/* comparision is always true: index>=CO_LSS_FASTSCAN_VENDOR_ID */ +#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=CO_LSS_FASTSCAN_SERIAL) /** * The LSS address is a 128 bit number, uniquely identifying each node. It @@ -219,7 +221,11 @@ static const uint16_t CO_LSS_bitTimingTableLookup[] = { /** * Macro to check if index contains valid bit timing */ -#define CO_LSS_BIT_TIMING_VALID(index) (index != 5 && (index >= CO_LSS_BIT_TIMING_1000 && index <= CO_LSS_BIT_TIMING_AUTO)) +#if CO_LSS_BIT_TIMING_1000 != 0 +#error missing comprision index >= CO_LSS_BIT_TIMING_1000 +#endif +/* comparision is always true: index >= CO_LSS_BIT_TIMING_1000 */ +#define CO_LSS_BIT_TIMING_VALID(index) (index != 5 && index <= CO_LSS_BIT_TIMING_AUTO) /** * Invalid node ID triggers node ID assignment diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index f65a2fa7..cb5642c0 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -143,7 +143,7 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { const char *c; for (c = &message[0]; *c != 0; c++) { - CO_fifo_putc_ov(>wa->logFifo, *c); + CO_fifo_putc_ov(>wa->logFifo, (const uint8_t)*c); } } } @@ -623,7 +623,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, (void)timerNext_us; /* may be unused */ bool_t err = false; /* syntax or other error, true or false, I/O variable */ - char closed; /* indication of command delimiter, I/O variable */ + int8_t closed; /* indication of command delimiter, I/O variable */ CO_GTWA_respErrorCode_t respErrorCode = CO_GTWA_respErrorNone; if (gtwa == NULL) { @@ -1986,7 +1986,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* print message log */ case CO_GTWA_ST_LOG: { do { - gtwa->respBufCount = CO_fifo_read(>wa->logFifo, gtwa->respBuf, + gtwa->respBufCount = CO_fifo_read(>wa->logFifo, + (uint8_t *)gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, NULL); respBufTransfer(gtwa); diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 19e63d2a..b79fe42c 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -324,7 +324,7 @@ typedef struct { /** CO_fifo_t object for command (not pointer) */ CO_fifo_t commFifo; /** Command buffer of usable size @ref CO_CONFIG_GTWA_COMM_BUF_SIZE */ - char commBuf[CO_CONFIG_GTWA_COMM_BUF_SIZE + 1]; + uint8_t commBuf[CO_CONFIG_GTWA_COMM_BUF_SIZE + 1]; /** Response buffer of usable size @ref CO_GTWA_RESP_BUF_SIZE */ char respBuf[CO_GTWA_RESP_BUF_SIZE]; /** Actual size of data in respBuf */ @@ -384,7 +384,7 @@ typedef struct { #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) || defined CO_DOXYGEN /** Message log buffer of usable size @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */ - char logBuf[CO_CONFIG_GTWA_LOG_BUF_SIZE + 1]; + uint8_t logBuf[CO_CONFIG_GTWA_LOG_BUF_SIZE + 1]; /** CO_fifo_t object for message log (not pointer) */ CO_fifo_t logFifo; #endif @@ -486,7 +486,7 @@ static inline size_t CO_GTWA_write(CO_GTWA_t* gtwa, const char *buf, size_t count) { - return CO_fifo_write(>wa->commFifo, buf, count, NULL); + return CO_fifo_write(>wa->commFifo, (const uint8_t *)buf, count, NULL); } diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index 67a458b6..73d8f944 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -40,7 +40,7 @@ */ static CO_CANinterfaceState_t CO_CANerrorSetListenOnly( CO_CANinterfaceErrorhandler_t *CANerrorhandler, - unsigned char resetIf) + bool_t resetIf) { char command[100]; From 7b5de9f383089fadf4d41a56818b9d31ac0aa6a9 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 5 Jan 2021 12:27:22 +0100 Subject: [PATCH 145/520] Replace type char with uint8_t, where appropriate. Fix typos and clarify CO_ODinterface. Remove unnecessary types from CO_driver.h. --- 301/CO_ODinterface.c | 46 ++++++++++++++++++------------------ 301/CO_ODinterface.h | 10 ++++---- 301/CO_SDOclient.c | 6 ++--- 301/CO_SDOserver.c | 16 ++++--------- 301/CO_SDOserver.h | 2 +- 301/CO_driver.h | 11 ++------- example/CO_driver_target.h | 5 +--- socketCAN/CO_driver_target.h | 5 +--- 8 files changed, 41 insertions(+), 60 deletions(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 6eb5b81e..83caab04 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -39,7 +39,7 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ - const char *odData = (const char *)stream->dataObjectOriginal; + const uint8_t *odData = stream->dataObjectOriginal; if (odData == NULL) { *returnCode = ODR_SUB_NOT_EXIST; @@ -49,18 +49,18 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, *returnCode = ODR_OK; /* If previous read was partial or OD variable length is larger than - * current buffer len, then data was (will be) read in several segments */ + * current buffer size, then data was (will be) read in several segments */ if (stream->dataOffset > 0 || dataLenToCopy > count) { if (stream->dataOffset >= dataLenToCopy) { *returnCode = ODR_DEV_INCOMPAT; return 0; } - /* reduce for already copied data */ + /* Reduce for already copied data */ dataLenToCopy -= stream->dataOffset; odData += stream->dataOffset; if (dataLenToCopy > count) { - /* not enough space in destionation buffer */ + /* Not enough space in destination buffer */ dataLenToCopy = count; stream->dataOffset += dataLenToCopy; *returnCode = ODR_PARTIAL; @@ -88,7 +88,7 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ - char *odData = (char *)stream->dataObjectOriginal; + uint8_t *odData = stream->dataObjectOriginal; if (odData == NULL) { *returnCode = ODR_SUB_NOT_EXIST; @@ -98,7 +98,8 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, *returnCode = ODR_OK; /* If previous write was partial or OD variable length is larger than - * current data len, then data was (will be) written in several segments */ + * current buffer size, then data was (will be) written in several + * segments */ if (stream->dataOffset > 0 || dataLenToCopy > count) { if (stream->dataOffset >= dataLenToCopy) { *returnCode = ODR_DEV_INCOMPAT; @@ -125,12 +126,11 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, *returnCode = ODR_DATA_LONG; return 0; } - else { - CO_LOCK_OD(); - memcpy(odData, buf, dataLenToCopy); - CO_UNLOCK_OD(); - return dataLenToCopy; - } + + CO_LOCK_OD(); + memcpy(odData, buf, dataLenToCopy); + CO_UNLOCK_OD(); + return dataLenToCopy; } /* Read value from variable from Object Dictionary disabled, see OD_IO_t*/ @@ -158,17 +158,17 @@ static OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, /******************************************************************************/ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { - unsigned int cur; - unsigned int min = 0; - unsigned int max = od->size - 1; - if (od == NULL || od->size == 0) { return NULL; } + uint16_t cur; + uint16_t min = 0; + uint16_t max = od->size - 1; + /* Fast search in ordered Object Dictionary. If indexes are mixed, - * this won't work. If Object Dictionary has up to 2^N entries, then N is - * max number of loop passes. */ + * this won't work. If Object Dictionary has up to N entries, then the + * max number of loop passes is log2(N) */ while (min < max) { /* get entry between min and max */ cur = (min + max) >> 1; @@ -177,9 +177,9 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { if (index == entry->index) { return entry; } - else if (index < entry->index) { - max = cur; - if(max > 0) max--; + + if (index < entry->index) { + max = (cur > 0) ? (cur - 1) : cur; } else { min = cur + 1; @@ -239,7 +239,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, io->stream.dataObjectOriginal = NULL; } else { - char *data = (char *)odo->data; + uint8_t *data = odo->data; int i = subIndex - 1; io->stream.dataObjectOriginal = data + odo->dataElementSizeof * i; } @@ -318,7 +318,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { 0x060A0023UL, /* Resource not available: SDO connection */ 0x08000000UL, /* General error */ 0x08000020UL, /* Data cannot be transferred or stored to application */ - 0x08000021UL, /* Data cannot be transf. because of local control */ + 0x08000021UL, /* Data cannot be transferred because of local control */ 0x08000022UL, /* Data cannot be tran. because of present device state */ 0x08000023UL, /* Object dict. not present or dynamic generation fails */ 0x08000024UL /* No data available */ diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 9822efd7..827b3fb2 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -304,7 +304,7 @@ typedef struct { * * Write can be restarted with @ref OD_rwRestart() function. * - * At the moment, when Object Dictionary is initialised, every variable has + * At the moment, when Object Dictionary is initialized, every variable has * assigned the same "write" function, which simply copies data to Object * Dictionary variable. Application can bind its own "write" function, * similar as it can bind "read" function. @@ -426,9 +426,9 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { /** * Restart read or write operation on OD variable * - * It is not necessary to call this function, if stream was initialised by - * @ref OD_getSub(). It is also not necessary to call this function, if prevous - * read or write was successfully finished. + * It is not necessary to call this function, if stream was initialized by + * @ref OD_getSub(). It is also not necessary to call this function, if + * previous read or write was successfully finished. * * @param stream Object Dictionary stream object. */ @@ -448,7 +448,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); /** - * Initialise extended OD object with own read/write functions + * Initialize extended OD object with own read/write functions * * This function works on OD object, which has IO extension enabled. It gives * application very powerful tool: definition of own IO access on own OD diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index edbe1228..d76b96f2 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -562,7 +562,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* write data, in several passes if necessary */ if (SDO_C->OD_IO.write != NULL) { size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo); - char buf[count + 2]; + uint8_t buf[count + 2]; CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); SDO_C->sizeTran += count; @@ -1213,7 +1213,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, OD_size_t countData = SDO_C->OD_IO.stream.dataLength; OD_size_t countBuf = (countData > 0 && countData <= countFifo) ? countData : countFifo; - char buf[countBuf + 1]; + uint8_t buf[countBuf + 1]; ODR_t odRet; /* load data from OD variable into the buffer */ @@ -1229,7 +1229,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* if data is string, send only data up to null termination */ if (countRd > 0 && (SDO_C->attribute & ODA_STR) != 0) { buf[countRd] = 0; /* (buf is one byte larger) */ - OD_size_t countStr = strlen(buf); + OD_size_t countStr = strlen((char *)buf); if (countStr == 0) countStr = 1; /* ne zero length */ if (countStr < countRd) { /* string terminator found, finish read, shorten data */ diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index a57a63d5..6a93a2a0 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -579,9 +579,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK /* calculate crc on current data */ if (SDO->block_crcEnabled && crcOperation > 0) { - SDO->block_crc = crc16_ccitt((unsigned char *)SDO->buf, - bufOffsetWrOrig, - SDO->block_crc); + SDO->block_crc = crc16_ccitt(SDO->buf, bufOffsetWrOrig, SDO->block_crc); if (crcOperation == 2 && crcClient != SDO->block_crc) { *abortCode = CO_SDO_AB_CRC; SDO->state = CO_SDO_ST_ABORT; @@ -650,7 +648,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* load data from OD variable into the buffer */ ODR_t odRet; - char *bufShifted = SDO->buf + countRemain; + uint8_t *bufShifted = SDO->buf + countRemain; OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, bufShifted, countRdRequest, @@ -665,7 +663,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* if data is string, send only data up to null termination */ if (countRd > 0 && (SDO->attribute & ODA_STR) != 0) { bufShifted[countRd] = 0; /* (SDO->buf is one byte larger) */ - OD_size_t countStr = strlen(bufShifted); + OD_size_t countStr = strlen((char *)bufShifted); if (countStr == 0) countStr = 1; /* zero length is not allowed */ if (countStr < countRd) { /* string terminator found, read is finished, shorten data */ @@ -707,9 +705,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK /* update the crc */ if (calculateCrc && SDO->block_crcEnabled) { - SDO->block_crc = crc16_ccitt((uint8_t *)bufShifted, - countRd, - SDO->block_crc); + SDO->block_crc = crc16_ccitt(bufShifted, countRd, SDO->block_crc); } #endif @@ -1098,9 +1094,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* data were already loaded from OD variable, verify crc */ if ((SDO->CANrxData[0] & 0x04) != 0) { SDO->block_crcEnabled = true; - SDO->block_crc = crc16_ccitt((unsigned char *)SDO->buf, - SDO->bufOffsetWr, - 0); + SDO->block_crc = crc16_ccitt(SDO->buf, SDO->bufOffsetWr, 0); } else { SDO->block_crcEnabled = false; diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index c28821cd..9a49f0f4 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -493,7 +493,7 @@ typedef struct { /** Timeout timer for SDO communication */ uint32_t timeoutTimer; /** Interim data buffer for segmented or block transfer + byte for '\0' */ - char buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE + 1]; + uint8_t buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE + 1]; /** Offset of next free data byte available for write in the buffer. */ OD_size_t bufOffsetWr; /** Offset of first data available for read in the buffer */ diff --git a/301/CO_driver.h b/301/CO_driver.h index ae85f68a..12555f6e 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -110,8 +110,7 @@ extern "C" { * @defgroup CO_dataTypes Basic definitions * @{ * - * Target specific basic definitions and data types according to Misra C - * specification. + * Target specific basic definitions and data types. * * Must be defined in the **CO_driver_target.h** file. * @@ -138,7 +137,7 @@ extern "C" { /** Logical false, for general use */ #define false 0 /** Boolean data type for general use */ -typedef unsigned char bool_t; +typedef uint_fast8_t bool_t; /** INTEGER8 in CANopen (0002h), 8-bit signed integer */ typedef signed char int8_t; /** INTEGER16 in CANopen (0003h), 16-bit signed integer */ @@ -159,12 +158,6 @@ typedef unsigned long long int uint64_t; typedef float float32_t; /** REAL64 in CANopen (0011h), double precision floating point value, 64-bit */ typedef double float64_t; -/** VISIBLE_STRING in CANopen (0009h), string of signed 8-bit values */ -typedef char char_t; -/** OCTET_STRING in CANopen (000Ah), string of unsigned 8-bit values */ -typedef unsigned char oChar_t; -/** DOMAIN in CANopen (000Fh), used to transfer a large block of data */ -typedef unsigned char domain_t; /** @} */ diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index df8cfbb6..d6e22f82 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -185,12 +185,9 @@ extern "C" { /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; +typedef uint_fast8_t bool_t; typedef float float32_t; typedef double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; /* Access to received CAN message */ diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 37267db6..6ccd7ef7 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -265,12 +265,9 @@ extern "C" { /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ -typedef unsigned char bool_t; +typedef uint_fast8_t bool_t; typedef float float32_t; typedef double float64_t; -typedef char char_t; -typedef unsigned char oChar_t; -typedef unsigned char domain_t; /* CAN receive message structure as aligned in socketCAN. */ From 51d64df86054a9b58d5d82b0e72fa8688a8ddd8c Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 7 Jan 2021 08:34:53 +0100 Subject: [PATCH 146/520] OD interface simplified #162 OD_extension is now configurable by application only. --- 301/CO_Emergency.c | 56 ++-- 301/CO_Emergency.h | 36 ++- 301/CO_NMT_Heartbeat.c | 11 +- 301/CO_NMT_Heartbeat.h | 4 +- 301/CO_ODinterface.c | 277 ++++++++---------- 301/CO_ODinterface.h | 235 +++++++--------- 301/CO_SDOclient.c | 41 ++- 301/CO_SDOclient.h | 10 +- 301/CO_SDOserver.c | 115 +++----- 301/CO_SDOserver.h | 10 +- CANopen.c | 20 +- CANopen.h | 46 +-- doc/objectDictionary.md | 202 ++++++------- example/DS301_profile.eds | 4 +- example/DS301_profile.md | 315 +++++++++++---------- example/DS301_profile.xpd | 48 +--- example/OD.c | 575 ++++++++++++-------------------------- example/OD.h | 162 +++++------ socketCAN/CO_main_basic.c | 2 +- 19 files changed, 896 insertions(+), 1273 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index c992b973..9a41afca 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -349,18 +349,18 @@ static void CO_EM_receive(void *object, void *msg) { CO_ReturnError_t CO_EM_init(CO_EM_t *em, const OD_entry_t *OD_1001_errReg, #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER - const OD_entry_t *OD_1014_cobIdEm, + OD_entry_t *OD_1014_cobIdEm, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT - const OD_entry_t *OD_1015_InhTime, + OD_entry_t *OD_1015_InhTime, #endif #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY - const OD_entry_t *OD_1003_preDefErr, + OD_entry_t *OD_1003_preDefErr, #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS - const OD_entry_t *OD_statusBits, + OD_entry_t *OD_statusBits, #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER CO_CANmodule_t *CANdevRx, @@ -410,10 +410,12 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0 && producerCanId != 0; - ODR_t odRetE = OD_extensionIO_init(OD_1014_cobIdEm, - (void *) em, - OD_read_1014, - OD_write_1014); + + em->OD_1014_extension.object = em; + em->OD_1014_extension.read = OD_read_1014; + em->OD_1014_extension.write = OD_write_1014; + ODR_t odRetE = OD_extension_init(OD_1014_cobIdEm, + &em->OD_1014_extension); if (odRetE != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; @@ -428,10 +430,12 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #else uint16_t producerCanId = CO_CAN_ID_EMERGENCY + nodeId; em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0; - ODR_t odRetE = OD_extensionIO_init(OD_1014_cobIdEm, - (void *) em, - OD_read_1014_default, - OD_writeOriginal); + + em->OD_1014_extension.object = em; + em->OD_1014_extension.read = OD_read_1014_default; + em->OD_1014_extension.write = OD_writeOriginal; + ODR_t odRetE = OD_extension_init(OD_1014_cobIdEm, + &em->OD_1014_extension); if (odRetE != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; @@ -462,10 +466,12 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, ODR_t odRet1 = OD_get_u16(OD_1015_InhTime, 0, &inhibitTime_100us, true); if (odRet1 == ODR_OK) { em->inhibitEmTime_us = (uint32_t)inhibitTime_100us * 100; - OD_extensionIO_init(OD_1015_InhTime, - (void *) em, - OD_readOriginal, - OD_write_1015); + + em->OD_1015_extension.object = em; + em->OD_1015_extension.read = OD_readOriginal; + em->OD_1015_extension.write = OD_write_1015; + OD_extension_init(OD_1015_InhTime, + &em->OD_1015_extension); } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ @@ -473,19 +479,21 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY /* If OD entry available, make access to em->preDefErr */ - OD_extensionIO_init(OD_1003_preDefErr, - (void *) em, - OD_read_1003, - OD_write_1003); + em->OD_1003_extension.object = em; + em->OD_1003_extension.read = OD_read_1003; + em->OD_1003_extension.write = OD_write_1003; + OD_extension_init(OD_1003_preDefErr, + &em->OD_1003_extension); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ #if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS /* If OD entry available, make access to em->errorStatusBits */ - OD_extensionIO_init(OD_statusBits, - (void *) em, - OD_read_statusBits, - OD_write_statusBits); + em->OD_statusBits_extension.object = em; + em->OD_statusBits_extension.read = OD_read_statusBits; + em->OD_statusBits_extension.write = OD_write_statusBits; + OD_extension_init(OD_statusBits, + &em->OD_statusBits_extension); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index dfbdf6a7..8fdce32c 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -380,11 +380,11 @@ typedef struct { * messages. Messages are added by @ref CO_error() function. All messages * are later post-processed by @ref CO_EM_process() function. Fifo is also * used for error history - OD object 0x1003, "Pre-defined error field". */ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN uint32_t fifo[CO_CONFIG_EM_BUFFER_SIZE + 1][2]; -#else + #else uint32_t fifo[CO_CONFIG_EM_BUFFER_SIZE + 1][1]; -#endif + #endif /** Pointer for the fifo buffer, where next emergency message will be * written by @ref CO_error() function. */ uint8_t fifoWrPtr; @@ -407,20 +407,34 @@ typedef struct { CO_CANmodule_t *CANdevTx; /** CAN transmit buffer */ CO_CANtx_t *CANtxBuff; -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) || defined CO_DOXYGEN + /** Extension for OD object */ + OD_extension_t OD_1014_extension; + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) || defined CO_DOXYGEN /** COB ID of emergency message, from Object dictionary */ uint16_t producerCanId; /** From CO_EM_init() */ uint16_t CANdevTxIdx; -#endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) || defined CO_DOXYGEN + #endif + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) || defined CO_DOXYGEN /** Inhibit time for emergency message, from Object dictionary */ uint32_t inhibitEmTime_us; /**< Internal timer for inhibit time */ uint32_t inhibitEmTimer; -#endif + /** Extension for OD object */ + OD_extension_t OD_1015_extension; + #endif #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) || defined CO_DOXYGEN + /** Extension for OD object */ + OD_extension_t OD_1003_extension; +#endif + +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) || defined CO_DOXYGEN + /** Extension for OD object */ + OD_extension_t OD_statusBits_extension; +#endif + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN /** From CO_EM_initCallbackRx() or NULL */ void (*pFunctSignalRx)(const uint16_t ident, @@ -470,18 +484,18 @@ typedef struct { CO_ReturnError_t CO_EM_init(CO_EM_t *em, const OD_entry_t *OD_1001_errReg, #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN - const OD_entry_t *OD_1014_cobIdEm, + OD_entry_t *OD_1014_cobIdEm, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) || defined CO_DOXYGEN - const OD_entry_t *OD_1015_InhTime, + OD_entry_t *OD_1015_InhTime, #endif #endif #if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) || defined CO_DOXYGEN - const OD_entry_t *OD_1003_preDefErr, + OD_entry_t *OD_1003_preDefErr, #endif #if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) || defined CO_DOXYGEN - const OD_entry_t *OD_statusBits, + OD_entry_t *OD_statusBits, #endif #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN CO_CANmodule_t *CANdevRx, diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index efe7527e..9d69f5ca 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -83,7 +83,7 @@ static OD_size_t OD_write_1017(OD_stream_t *stream, uint8_t subIndex, /******************************************************************************/ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, - const OD_entry_t *OD_1017_ProducerHbTime, + OD_entry_t *OD_1017_ProducerHbTime, CO_EM_t *em, uint8_t nodeId, CO_NMT_control_t NMTcontrol, @@ -132,10 +132,11 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, } NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000; - odRet = OD_extensionIO_init(OD_1017_ProducerHbTime, - (void *) NMT, - OD_readOriginal, - OD_write_1017); + NMT->OD_1017_extension.object = NMT; + NMT->OD_1017_extension.read = OD_readOriginal; + NMT->OD_1017_extension.write = OD_write_1017; + odRet = OD_extension_init(OD_1017_ProducerHbTime, + &NMT->OD_1017_extension); if (odRet != ODR_OK) { CO_errinfo(HB_CANdevTx, OD_getIndex(OD_1017_ProducerHbTime)); return CO_ERROR_OD_PARAMETERS; diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 51d87e31..3414d0dd 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -175,6 +175,8 @@ typedef struct { uint32_t HBproducerTime_us; /** Internal timer for HB producer */ uint32_t HBproducerTimer; + /** Extension for OD object */ + OD_extension_t OD_1017_extension; /** From CO_NMT_init() */ CO_EM_t *em; #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN @@ -229,7 +231,7 @@ typedef struct { * @return #CO_ReturnError_t CO_ERROR_NO on success. */ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, - const OD_entry_t *OD_1017_ProducerHbTime, + OD_entry_t *OD_1017_ProducerHbTime, CO_EM_t *em, uint8_t nodeId, CO_NMT_control_t NMTcontrol, diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 83caab04..3ac5508e 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -39,9 +39,9 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ - const uint8_t *odData = stream->dataObjectOriginal; + const uint8_t *dataOrig = stream->dataOrig; - if (odData == NULL) { + if (dataOrig == NULL) { *returnCode = ODR_SUB_NOT_EXIST; return 0; } @@ -57,7 +57,7 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, } /* Reduce for already copied data */ dataLenToCopy -= stream->dataOffset; - odData += stream->dataOffset; + dataOrig += stream->dataOffset; if (dataLenToCopy > count) { /* Not enough space in destination buffer */ @@ -71,7 +71,7 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, } CO_LOCK_OD(); - memcpy(buf, odData, dataLenToCopy); + memcpy(buf, dataOrig, dataLenToCopy); CO_UNLOCK_OD(); return dataLenToCopy; } @@ -88,9 +88,9 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ - uint8_t *odData = stream->dataObjectOriginal; + uint8_t *dataOrig = stream->dataOrig; - if (odData == NULL) { + if (dataOrig == NULL) { *returnCode = ODR_SUB_NOT_EXIST; return 0; } @@ -107,7 +107,7 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, } /* reduce for already copied data */ dataLenToCopy -= stream->dataOffset; - odData += stream->dataOffset; + dataOrig += stream->dataOffset; if (dataLenToCopy > count) { /* Remaining data space in OD variable is larger than current count @@ -128,7 +128,7 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, } CO_LOCK_OD(); - memcpy(odData, buf, dataLenToCopy); + memcpy(dataOrig, buf, dataLenToCopy); CO_UNLOCK_OD(); return dataLenToCopy; } @@ -157,7 +157,7 @@ static OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, /******************************************************************************/ -const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { +OD_entry_t *OD_find(OD_t *od, uint16_t index) { if (od == NULL || od->size == 0) { return NULL; } @@ -172,7 +172,7 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { while (min < max) { /* get entry between min and max */ cur = (min + max) >> 1; - const OD_entry_t* entry = &od->list[cur]; + OD_entry_t* entry = &od->list[cur]; if (index == entry->index) { return entry; @@ -187,7 +187,7 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { } if (min == max) { - const OD_entry_t* entry = &od->list[min]; + OD_entry_t* entry = &od->list[min]; if (index == entry->index) { return entry; } @@ -198,58 +198,47 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index) { /******************************************************************************/ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, - OD_subEntry_t *subEntry, OD_IO_t *io, bool_t odOrig) + OD_IO_t *io, bool_t odOrig) { if (entry == NULL || entry->odObject == NULL) return ODR_IDX_NOT_EXIST; - else if (io == NULL) return ODR_DEV_INCOMPAT; - - const void *odObjectOrig = entry->odObject; - const OD_obj_extended_t *odObjectExt = NULL; - uint8_t odBasicType = entry->odObjectType & ODT_TYPE_MASK; - OD_attr_t attr = 0; - - /* Is object type extended? */ - if ((entry->odObjectType & ODT_EXTENSION_MASK) != 0) { - odObjectExt = (const OD_obj_extended_t *)odObjectOrig; - odObjectOrig = odObjectExt->odObjectOriginal; - if (odObjectOrig == NULL) return ODR_DEV_INCOMPAT; - } + if (io == NULL) return ODR_DEV_INCOMPAT; + + OD_stream_t *stream = &io->stream; - /* attribute, dataObjectOriginal and dataLength, depends on object type */ - if (odBasicType == ODT_VAR) { + /* attribute, dataOrig and dataLength, depends on object type */ + switch (entry->odObjectType & ODT_TYPE_MASK) { + case ODT_VAR: { if (subIndex > 0) return ODR_SUB_NOT_EXIST; - const OD_obj_var_t *odo = (const OD_obj_var_t *)odObjectOrig; + CO_PROGMEM OD_obj_var_t *odo = entry->odObject; + - attr = odo->attribute; - io->stream.dataObjectOriginal = odo->data; - io->stream.dataLength = odo->dataLength; + stream->attribute = odo->attribute; + stream->dataOrig = odo->dataOrig; + stream->dataLength = odo->dataLength; + break; } - else if (odBasicType == ODT_ARR) { + case ODT_ARR: { if (subIndex >= entry->subEntriesCount) return ODR_SUB_NOT_EXIST; - const OD_obj_array_t *odo = (const OD_obj_array_t *)odObjectOrig; + CO_PROGMEM OD_obj_array_t *odo = entry->odObject; if (subIndex == 0) { - attr = odo->attribute0; - io->stream.dataObjectOriginal = odo->data0; - io->stream.dataLength = 1; + stream->attribute = odo->attribute0; + stream->dataOrig = odo->dataOrig0; + stream->dataLength = 1; } else { - attr = odo->attribute; - if (odo->data == NULL) { - io->stream.dataObjectOriginal = NULL; - } - else { - uint8_t *data = odo->data; - int i = subIndex - 1; - io->stream.dataObjectOriginal = data + odo->dataElementSizeof * i; - } - io->stream.dataLength = odo->dataElementLength; + stream->attribute = odo->attribute; + uint8_t *ptr = odo->dataOrig; + stream->dataOrig = ptr == NULL ? ptr + : ptr + odo->dataElementSizeof * (subIndex - 1); + stream->dataLength = odo->dataElementLength; } + break; } - else if (odBasicType == ODT_REC) { - const OD_obj_record_t *odoArr = (const OD_obj_record_t *)odObjectOrig; - const OD_obj_record_t *odo = NULL; - for (int i = 0; i< entry->subEntriesCount; i++) { + case ODT_REC: { + CO_PROGMEM OD_obj_record_t *odoArr = entry->odObject; + CO_PROGMEM OD_obj_record_t *odo = NULL; + for (uint8_t i = 0; i < entry->subEntriesCount; i++) { if (odoArr[i].subIndex == subIndex) { odo = &odoArr[i]; break; @@ -257,38 +246,33 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, } if (odo == NULL) return ODR_SUB_NOT_EXIST; - attr = odo->attribute; - io->stream.dataObjectOriginal = odo->data; - io->stream.dataLength = odo->dataLength; + stream->attribute = odo->attribute; + stream->dataOrig = odo->dataOrig; + stream->dataLength = odo->dataLength; + break; } - else { + default: { return ODR_DEV_INCOMPAT; } + } - /* read, write and dataObject, direct or with IO extension */ - if (odObjectExt == NULL || odObjectExt->extIO == NULL || odOrig) { + /* Access data from the original OD location */ + if (entry->extension == NULL || odOrig) { io->read = OD_readOriginal; io->write = OD_writeOriginal; - io->stream.object = NULL; + stream->object = NULL; } + /* Access data from extension specified by application */ else { - io->read = odObjectExt->extIO->read != NULL ? - odObjectExt->extIO->read : OD_readDisabled; - io->write = odObjectExt->extIO->write != NULL ? - odObjectExt->extIO->write : OD_writeDisabled; - io->stream.object = odObjectExt->extIO->object; + io->read = entry->extension->read != NULL ? + entry->extension->read : OD_readDisabled; + io->write = entry->extension->write != NULL ? + entry->extension->write : OD_writeDisabled; + stream->object = entry->extension->object; } - /* common properties */ - if (subEntry != NULL) { - subEntry->index = entry->index; - subEntry->subIndex = subIndex; - subEntry->subEntriesCount = entry->subEntriesCount; - subEntry->attribute = attr; - subEntry->flagsPDO = odObjectExt != NULL ? - odObjectExt->flagsPDO : NULL; - } - io->stream.dataOffset = 0; + /* Reset stream data offset */ + stream->dataOffset = 0; return ODR_OK; } @@ -328,44 +312,13 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { abortCodes[ODR_DEV_INCOMPAT] : abortCodes[returnCode]; } -/******************************************************************************/ -ODR_t OD_extensionIO_init(const OD_entry_t *entry, - void *object, - OD_size_t (*read)(OD_stream_t *stream, - uint8_t subIndex, - void *buf, - OD_size_t count, - ODR_t *returnCode), - OD_size_t (*write)(OD_stream_t *stream, - uint8_t subIndex, - const void *buf, - OD_size_t count, - ODR_t *returnCode)) -{ - if (entry == NULL) { - return ODR_IDX_NOT_EXIST; - } - - const OD_obj_extended_t *odo = (const OD_obj_extended_t *) entry->odObject; - - if ((entry->odObjectType & ODT_EXTENSION_MASK) == 0 || odo->extIO == NULL) { - return ODR_PAR_INCOMPAT; - } - - odo->extIO->object = object; - odo->extIO->read = read; - odo->extIO->write = write; - - return ODR_OK; -} - /******************************************************************************/ ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -377,7 +330,7 @@ ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -389,7 +342,7 @@ ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -401,7 +354,7 @@ ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -413,7 +366,7 @@ ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -425,7 +378,7 @@ ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -437,7 +390,7 @@ ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -449,7 +402,7 @@ ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -461,7 +414,7 @@ ODR_t OD_get_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -473,7 +426,7 @@ ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t *val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) ret = ODR_TYPE_MISMATCH; @@ -486,7 +439,7 @@ ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -498,7 +451,7 @@ ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -510,7 +463,7 @@ ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -522,7 +475,7 @@ ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -534,7 +487,7 @@ ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -546,7 +499,7 @@ ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -558,7 +511,7 @@ ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -570,7 +523,7 @@ ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -582,7 +535,7 @@ ODR_t OD_set_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -594,7 +547,7 @@ ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t val, bool_t odOrig) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) ret = ODR_TYPE_MISMATCH; @@ -605,131 +558,131 @@ ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, /******************************************************************************/ ODR_t OD_getPtr_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t **val) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (int8_t *)io.stream.dataObjectOriginal; + *val = (int8_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t **val) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (int16_t *)io.stream.dataObjectOriginal; + *val = (int16_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t **val) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (int32_t *)io.stream.dataObjectOriginal; + *val = (int32_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t **val) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (int64_t *)io.stream.dataObjectOriginal; + *val = (int64_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t **val) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (uint8_t *)io.stream.dataObjectOriginal; + *val = (uint8_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t **val) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (uint16_t *)io.stream.dataObjectOriginal; + *val = (uint16_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t **val) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (uint32_t *)io.stream.dataObjectOriginal; + *val = (uint32_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t **val) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (uint64_t *)io.stream.dataObjectOriginal; + *val = (uint64_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t **val){ OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (float32_t *)io.stream.dataObjectOriginal; + *val = (float32_t *)io.stream.dataOrig; return ret; } ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val){ OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL) + if (val == NULL || io.stream.dataOrig == NULL) ret = ODR_DEV_INCOMPAT; else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) ret = ODR_TYPE_MISMATCH; else if (ret == ODR_OK) - *val = (float64_t *)io.stream.dataObjectOriginal; + *val = (float64_t *)io.stream.dataOrig; return ret; } @@ -737,15 +690,15 @@ ODR_t OD_getPtr_vs(const OD_entry_t *entry, uint8_t subIndex, char **val, OD_size_t *dataLength) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL + if (val == NULL || io.stream.dataOrig == NULL || io.stream.dataLength == 0) { ret = ODR_DEV_INCOMPAT; } else if (ret == ODR_OK) { - *val = (char *)io.stream.dataObjectOriginal; + *val = (char *)io.stream.dataOrig; if (dataLength != NULL) *dataLength = io.stream.dataLength; } return ret; @@ -755,15 +708,15 @@ ODR_t OD_getPtr_os(const OD_entry_t *entry, uint8_t subIndex, uint8_t **val, OD_size_t *dataLength) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL + if (val == NULL || io.stream.dataOrig == NULL || io.stream.dataLength == 0) { ret = ODR_DEV_INCOMPAT; } else if (ret == ODR_OK) { - *val = (uint8_t *)io.stream.dataObjectOriginal; + *val = (uint8_t *)io.stream.dataOrig; if (dataLength != NULL) *dataLength = io.stream.dataLength; } return ret; @@ -773,15 +726,15 @@ ODR_t OD_getPtr_us(const OD_entry_t *entry, uint8_t subIndex, uint16_t **val, OD_size_t *dataLength) { OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, NULL, &io, true); + ODR_t ret = OD_getSub(entry, subIndex, &io, true); - if (val == NULL || io.stream.dataObjectOriginal == NULL + if (val == NULL || io.stream.dataOrig == NULL || io.stream.dataLength == 0) { ret = ODR_DEV_INCOMPAT; } else if (ret == ODR_OK) { - *val = (uint16_t *)io.stream.dataObjectOriginal; + *val = (uint16_t *)io.stream.dataOrig; if (dataLength != NULL) *dataLength = io.stream.dataLength; } return ret; diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 827b3fb2..4b25a08f 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -39,15 +39,20 @@ extern "C" { * See @ref doc/objectDictionary.md */ -#ifndef OD_size_t +#ifndef CO_OD_OWN_TYPES /** Variable of type OD_size_t contains data length in bytes of OD variable */ -#define OD_size_t uint32_t -/** Type of flagsPDO variable from OD_subEntry_t */ -#define OD_flagsPDO_t uint32_t +typedef uint32_t OD_size_t; +/** Type (and size) of Object Dictionary attribute */ +typedef uint8_t OD_attr_t; +/** Size of of flagsPDO variable inside OD_extension_t, from 1 to 64 */ +#define OD_FLAGS_PDO_SIZE 4 #endif -/** Size of Object Dictionary attribute */ -#define OD_attr_t uint8_t +#ifndef CO_PROGMEM +/** Modifier for OD objects. This is large amount of data and is specified in + * Object Dictionary (OD.c file usually) */ +#define CO_PROGMEM const +#endif /** @@ -192,47 +197,6 @@ typedef enum { } ODR_t; -/** - * Structure describing properties of a variable, located in specific index and - * sub-index inside the Object Dictionary. - * - * Structure is initialized with @ref OD_getSub() function. - */ -typedef struct { - /** Object Dictionary index */ - uint16_t index; - /** Object Dictionary sub-index */ - uint8_t subIndex; - /** Number of sub-entries in OD object. For VAR is 1, for ARRAY is - * maxSubIndex + 1, for RECORD maxSubIndex may be larger, if there is a gap - * between sub-indexes. */ - uint8_t subEntriesCount; - /** Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */ - OD_attr_t attribute; - /** - * Pointer to PDO flags bit-field. This is optional extension of OD object. - * If OD object has enabled this extension, then each sub-element is coupled - * with own flagsPDO variable of size 8 to 64 bits (size is configurable - * by @ref OD_flagsPDO_t). Flag is useful, when variable is mapped to RPDO - * or TPDO. - * - * If sub-element is mapped to RPDO, then bit0 is set to 1 each time, when - * any RPDO writes new data into variable. Application may clear bit0. - * - * If sub-element is mapped to TPDO, then TPDO will set one bit on the time, - * it is sent. First TPDO will set bit1, second TPDO will set bit2, etc. Up - * to 63 TPDOs can use flagsPDO. - * - * Another functionality is with asynchronous TPDOs, to which variable may - * be mapped. If corresponding bit is 0, TPDO will be sent. This means, that - * if application sets variable pointed by flagsPDO to zero, it will trigger - * sending all asynchronous TPDOs (up to first 63), to which variable is - * mapped. - */ - OD_flagsPDO_t *flagsPDO; -} OD_subEntry_t; - - /** * IO stream structure, used for read/write access to OD variable, part of * @ref OD_IO_t. @@ -240,10 +204,10 @@ typedef struct { typedef struct { /** Pointer to original data object, defined by Object Dictionary. Default * read/write functions operate on it. If memory for data object is not - * specified by Object Dictionary, then dataObjectOriginal is NULL. + * specified by Object Dictionary, then dataOrig is NULL. */ - void *dataObjectOriginal; - /** Pointer to object, passed by @ref OD_extensionIO_init(). Can be used + void *dataOrig; + /** Pointer to object, passed by @ref OD_extension_init(). Can be used * inside read / write functions from IO extension. */ void *object; @@ -252,6 +216,8 @@ typedef struct { /** In case of large data, dataOffset indicates position of already * transferred data */ OD_size_t dataOffset; + /** Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */ + OD_attr_t attribute; } OD_stream_t; @@ -277,9 +243,8 @@ typedef struct { * data from Object Dictionary variable. Application can bind its own "read" * function for specific object. In that case application is able to * calculate data for reading from own internal state at the moment of - * "read" function call. For this functionality OD object must have IO - * extension enabled. OD object must also be initialized with - * @ref OD_extensionIO_init() function call. + * "read" function call. Own "read" function on OD object can be initialized + * with @ref OD_extension_init() function. * * "read" function must always copy all own data to buf, except if "buf" is * not large enough. ("*returnCode" must not return 'ODR_PARTIAL', if there @@ -326,12 +291,51 @@ typedef struct { } OD_IO_t; +/** + * Extension of OD object, which can optionally be specified by application in + * initialization phase with @ref OD_extension_init() function. + */ +typedef struct { + /** Object on which read and write will operate, part of @ref OD_stream_t */ + void *object; + /** Application specified read function pointer. If NULL, then read will be + * disabled. @ref OD_readOriginal can be used here to keep the original read + * function. For function description see @ref OD_IO_t. */ + OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, + void *buf, OD_size_t count, ODR_t *returnCode); + /** Application specified write function pointer. If NULL, then write will + * be disabled. @ref OD_writeOriginal can be used here to keep the original + * write function. For function description see @ref OD_IO_t. */ + OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, ODR_t *returnCode); + /** + * PDO flags bit-field. If available, then each sub-element is coupled + * with own flagsPDO variable of size 8 to 512 bits (size is configurable + * by @ref OD_FLAGS_PDO_SIZE). Flag is useful, when variable is mapped to + * RPDO or TPDO. + * + * If sub-element is mapped to RPDO, then bit0 is set to 1 each time, when + * any RPDO writes new data into variable. Application may clear bit0. + * + * If sub-element is mapped to TPDO, then TPDO will set one bit on the time, + * it is sent. First TPDO will set bit1, second TPDO will set bit2, etc. + * + * Another functionality is with asynchronous TPDOs, to which variable may + * be mapped. If corresponding bit is 0, TPDO will be sent. This means, that + * if application sets variable pointed by flagsPDO to zero, it will trigger + * sending all asynchronous TPDOs, to which variable is mapped. + */ + uint8_t flagsPDO[OD_FLAGS_PDO_SIZE]; +} OD_extension_t; + + /** * Object Dictionary entry for one OD object. * * OD entries are collected inside OD_t as array (list). Each OD entry contains - * basic information about OD object (index and subEntriesCount) and - * access function together with a pointer to other details of the OD object. + * basic information about OD object (index and subEntriesCount), pointer to + * odObject with additional information about var, array or record entry and + * pointer to extension, configurable by application. */ typedef struct { /** Object Dictionary index */ @@ -342,7 +346,9 @@ typedef struct { uint8_t odObjectType; /** OD object of type indicated by odObjectType, from which @ref OD_getSub() * fetches the information */ - const void *odObject; + CO_PROGMEM void *odObject; + /** Extension to OD, specified by application */ + OD_extension_t *extension; } OD_entry_t; @@ -353,7 +359,7 @@ typedef struct { /** Number of elements in the list, without last element, which is blank */ uint16_t size; /** List OD entries (table of contents), ordered by index */ - const OD_entry_t *list; + OD_entry_t *list; } OD_t; @@ -361,7 +367,7 @@ typedef struct { * Read value from original OD location * * This function can be used inside read / write functions, specified by - * @ref OD_extensionIO_init(). It reads data directly from memory location + * @ref OD_extension_init(). It reads data directly from memory location * specified by Object dictionary. If no IO extension is used on OD entry, then * io->read returned by @ref OD_getSub() equals to this function. See * also @ref OD_IO_t. @@ -374,7 +380,7 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, * Write value to original OD location * * This function can be used inside read / write functions, specified by - * @ref OD_extensionIO_init(). It writes data directly to memory location + * @ref OD_extension_init(). It writes data directly to memory location * specified by Object dictionary. If no IO extension is used on OD entry, then * io->write returned by @ref OD_getSub() equals to this function. See * also @ref OD_IO_t. @@ -391,16 +397,15 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, * * @return Pointer to OD entry or NULL if not found */ -const OD_entry_t *OD_find(const OD_t *od, uint16_t index); +OD_entry_t *OD_find(OD_t *od, uint16_t index); /** * Find sub-object with specified sub-index on OD entry returned by OD_find. - * Function populates subEntry and io structures with sub-object data. + * Function populates io structure with sub-object data. * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. - * @param [out] subEntry Structure will be populated on success, may be NULL. * @param [out] io Structure will be populated on success. * @param odOrig If true, then potential IO extension on entry will be * ignored and access to data entry in the original OD location will be returned @@ -408,7 +413,7 @@ const OD_entry_t *OD_find(const OD_t *od, uint16_t index); * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, - OD_subEntry_t *subEntry, OD_IO_t *io, bool_t odOrig); + OD_IO_t *io, bool_t odOrig); /** @@ -448,16 +453,20 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); /** - * Initialize extended OD object with own read/write functions + * Extend OD object with own read/write functions and/or flagsPDO * - * This function works on OD object, which has IO extension enabled. It gives - * application very powerful tool: definition of own IO access on own OD - * object. Structure and attributes are the same as defined in original OD - * object, but data are read directly from (or written directly to) application - * specified object via custom function calls. + * This function gives application very powerful tool: definition of own IO + * access on OD object. Structure and attributes are the same as defined in + * original OD object, but data are read directly from (or written directly to) + * application specified object via custom function calls. * - * If this function is not called yet, then normal access ("odOrig" argument is - * false) to OD entry is disabled. + * Before this function specifies extension, OD variables are accessed from + * original OD location. After this function specifies extension OD variables + * are accessed from read/write functions specified by extension. (Except when + * "odOrig" argument to @ref OD_getSub() is set to true.) + * + * This function must also be used, when flagsPDO needs to be enabled for + * specific entry. * * @warning * Object dictionary storage works only directly on OD variables. It does not @@ -471,29 +480,18 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); * @ref CO_UNLOCK_OD(). * * @param entry OD entry returned by @ref OD_find(). - * @param object Object, which will be passed to read or write function. - * @param read Read function pointer. If NULL, then read will be disabled. - * @ref OD_readOriginal can be used here to keep original read function. - * For function description see @ref OD_IO_t. - * @param write Write function pointer. If NULL, then write will be disabled. - * @ref OD_writeOriginal can be used here to keep original write function. - * For function description see @ref OD_IO_t. - * - * @return "ODR_OK" on success, "ODR_IDX_NOT_EXIST" if OD object doesn't exist, - * "ODR_PAR_INCOMPAT" if OD object is not extended. + * @param extension Extension object, which must be initialized externally. + * Extension object must exist permanently. If NULL, extension will be removed. + * + * @return "ODR_OK" on success, "ODR_IDX_NOT_EXIST" if OD object doesn't exist. */ -ODR_t OD_extensionIO_init(const OD_entry_t *entry, - void *object, - OD_size_t (*read)(OD_stream_t *stream, - uint8_t subIndex, - void *buf, - OD_size_t count, - ODR_t *returnCode), - OD_size_t (*write)(OD_stream_t *stream, - uint8_t subIndex, - const void *buf, - OD_size_t count, - ODR_t *returnCode)); +static inline ODR_t OD_extension_init(OD_entry_t *entry, + OD_extension_t *extension) +{ + if (entry == NULL) return ODR_IDX_NOT_EXIST; + entry->extension = extension; + return ODR_OK; +} /** @@ -592,7 +590,7 @@ ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, /** * Get pointer to int8_t variable from Object Dictionary * - * Function always returns "dataObjectOriginal" pointer, which points to data + * Function always returns "dataOrig" pointer, which points to data * in the original OD location. Take care, if IO extension is enabled on OD * entry. * @@ -626,7 +624,7 @@ ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val); /** * Get pointer to "visible string" variable from Object Dictionary * - * Function always returns "dataObjectOriginal" pointer, which points to data + * Function always returns "dataOrig" pointer, which points to data * in the original OD location. Take care, if IO extension is enabled on OD * entry. * @@ -680,26 +678,15 @@ typedef enum { * @ref OD_obj_var_t. Variable at sub-index 0 is of type uint8_t and usually * represents number of sub-elements in the structure. */ ODT_REC = 0x03, - - /** Same as ODT_VAR, but extended with OD_obj_extended_t type. It includes - * additional pointer to IO extension and PDO flags */ - ODT_EVAR = 0x11, - /** Same as ODT_ARR, but extended with OD_obj_extended_t type */ - ODT_EARR = 0x12, - /** Same as ODT_REC, but extended with OD_obj_extended_t type */ - ODT_EREC = 0x13, - /** Mask for basic type */ ODT_TYPE_MASK = 0x0F, - /** Mask for extension */ - ODT_EXTENSION_MASK = 0x10 } OD_objectTypes_t; /** * Object for single OD variable, used for "VAR" type OD objects */ typedef struct { - void *data; /**< Pointer to data */ + void *dataOrig; /**< Pointer to data */ OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ OD_size_t dataLength; /**< Data length in bytes */ } OD_obj_var_t; @@ -708,8 +695,8 @@ typedef struct { * Object for OD array of variables, used for "ARRAY" type OD objects */ typedef struct { - uint8_t *data0; /**< Pointer to data for sub-index 0 */ - void *data; /**< Pointer to array of data */ + uint8_t *dataOrig0; /**< Pointer to data for sub-index 0 */ + void *dataOrig; /**< Pointer to array of data */ OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see @ref OD_attributes_t */ OD_attr_t attribute; /**< Attribute bitfield for array elements */ @@ -721,40 +708,12 @@ typedef struct { * Object for OD sub-elements, used in "RECORD" type OD objects */ typedef struct { - void *data; /**< Pointer to data */ + void *dataOrig; /**< Pointer to data */ uint8_t subIndex; /**< Sub index of element. */ OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ OD_size_t dataLength; /**< Data length in bytes */ } OD_obj_record_t; -/** - * Object pointed by @ref OD_obj_extended_t contains application specified - * parameters for extended OD object - */ -typedef struct { - /** Object on which read and write will operate */ - void *object; - /** Application specified function pointer, see @ref OD_IO_t. */ - OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, ODR_t *returnCode); - /** Application specified function pointer, see @ref OD_IO_t. */ - OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, ODR_t *returnCode); -} OD_extensionIO_t; - -/** - * Object for extended type of OD variable, configurable by - * @ref OD_extensionIO_init() function - */ -typedef struct { - /** Pointer to application specified IO extension, may be NULL. */ - OD_extensionIO_t *extIO; - /** Pointer to PDO flags bit-field, see @ref OD_subEntry_t, may be NULL. */ - OD_flagsPDO_t *flagsPDO; - /** Pointer to original odObject, see @ref OD_entry_t. */ - const void *odObjectOriginal; -} OD_obj_extended_t; - /** @} */ /* CO_ODdefinition */ #endif /* defined OD_DEFINITION */ diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index d76b96f2..5376392a 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -249,8 +249,8 @@ static OD_size_t OD_write_1280(OD_stream_t *stream, uint8_t subIndex, /******************************************************************************/ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, - const OD_t *OD, - const OD_entry_t *OD_1280_SDOcliPar, + OD_t *OD, + OD_entry_t *OD_1280_SDOcliPar, uint8_t nodeId, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, @@ -300,10 +300,11 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC - ODR_t odRetE = OD_extensionIO_init(OD_1280_SDOcliPar, - (void *)SDO_C, - OD_readOriginal, - OD_write_1280); + SDO_C->OD_1280_extension.object = SDO_C; + SDO_C->OD_1280_extension.read = OD_readOriginal; + SDO_C->OD_1280_extension.write = OD_write_1280; + ODR_t odRetE = OD_extension_init(OD_1280_SDOcliPar, + &SDO_C->OD_1280_extension); if (odRetE != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1280_SDOcliPar)); return CO_ERROR_OD_PARAMETERS; @@ -535,22 +536,19 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* search object dictionary in first pass */ if (SDO_C->OD_IO.write == NULL) { ODR_t odRet; - OD_subEntry_t subEntry; odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, - &subEntry, &SDO_C->OD_IO, false); - - SDO_C->attribute = subEntry.attribute; + &SDO_C->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithClientAbort; } - else if ((SDO_C->attribute & ODA_SDO_RW) == 0) { + else if ((SDO_C->OD_IO.stream.attribute & ODA_SDO_RW) == 0) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; ret = CO_SDO_RT_endedWithClientAbort; } - else if ((SDO_C->attribute & ODA_SDO_W) == 0) { + else if ((SDO_C->OD_IO.stream.attribute & ODA_SDO_W) == 0) { abortCode = CO_SDO_AB_READONLY; ret = CO_SDO_RT_endedWithClientAbort; } @@ -589,7 +587,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else if (!bufferPartial) { #ifdef CO_BIG_ENDIAN /* swap int16_t .. uint64_t data if necessary */ - if ((SDO_C->attribute & ODA_MB) != 0) { + if ((SDO_C->OD_IO.stream.attribute & ODA_MB) != 0) { reverseBytes(buf, count); } #endif @@ -599,7 +597,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, * shorter than size of OD data buffer. If so, add two zero * bytes to terminate (unicode) string. Shorten also OD data * size, (temporary, send info about EOF into OD_IO.write) */ - if ((SDO_C->attribute & ODA_STR) != 0 + if ((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0 && (sizeInOd == 0 || SDO_C->sizeTran < sizeInOd) ) { buf[count++] = 0; @@ -1175,22 +1173,19 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* search object dictionary in first pass */ if (SDO_C->OD_IO.read == NULL) { ODR_t odRet; - OD_subEntry_t subEntry; odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, - &subEntry, &SDO_C->OD_IO, false); - - SDO_C->attribute = subEntry.attribute; + &SDO_C->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithClientAbort; } - else if ((SDO_C->attribute & ODA_SDO_RW) == 0) { + else if ((SDO_C->OD_IO.stream.attribute & ODA_SDO_RW) == 0) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; ret = CO_SDO_RT_endedWithClientAbort; } - else if ((SDO_C->attribute & ODA_SDO_R) == 0) { + else if ((SDO_C->OD_IO.stream.attribute & ODA_SDO_R) == 0) { abortCode = CO_SDO_AB_WRITEONLY; ret = CO_SDO_RT_endedWithClientAbort; } @@ -1227,10 +1222,12 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else { /* if data is string, send only data up to null termination */ - if (countRd > 0 && (SDO_C->attribute & ODA_STR) != 0) { + if (countRd > 0 + && (SDO_C->OD_IO.stream.attribute & ODA_STR) != 0 + ) { buf[countRd] = 0; /* (buf is one byte larger) */ OD_size_t countStr = strlen((char *)buf); - if (countStr == 0) countStr = 1; /* ne zero length */ + if (countStr == 0) countStr = 1; /* no zero length */ if (countStr < countRd) { /* string terminator found, finish read, shorten data */ countRd = countStr; diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 6127ab30..6beed563 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -67,13 +67,11 @@ extern "C" { typedef struct { #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) || defined CO_DOXYGEN /** From CO_SDOclient_init() */ - const OD_t *OD; + OD_t *OD; /** From CO_SDOclient_init() */ uint8_t nodeId; /** Object dictionary interface for locally transferred object */ OD_IO_t OD_IO; - /** Attribute for locally transferred OD sub-object, see OD_attributes_t */ - OD_attr_t attribute; #endif /** From CO_SDOclient_init() */ CO_CANmodule_t *CANdevRx; @@ -93,6 +91,8 @@ typedef struct { uint32_t COB_IDClientToServer; /** Copy of CANopen COB_ID Server -> Client, similar as above */ uint32_t COB_IDServerToClient; + /** Extension for OD object */ + OD_extension_t OD_1280_extension; #endif /** Node-ID of the SDO server */ uint8_t nodeIDOfTheSDOServer; @@ -177,8 +177,8 @@ typedef struct { * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, - const OD_t *OD, - const OD_entry_t *OD_1280_SDOcliPar, + OD_t *OD, + OD_entry_t *OD_1280_SDOcliPar, uint8_t nodeId, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 6a93a2a0..e674d0f1 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -163,46 +163,6 @@ static void CO_SDO_receive(void *object, void *msg) { } -/* - * Custom function for reading OD variable _SDO server parameter_, default - * channel - * - * For more information see file CO_ODinterface.h, OD_IO_t. - */ -static OD_size_t OD_read_1200_default(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) -{ - if (stream == NULL || buf == NULL || returnCode == NULL - || count < 1 || (count < 4 && subIndex > 0) - ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; - } - - CO_SDOserver_t *SDO = (CO_SDOserver_t *)stream->object; - *returnCode = ODR_OK; - - switch (subIndex) { - case 0: /* Highest sub-index supported */ - CO_setUint8(buf, 2); - return stream->dataLength = sizeof(uint8_t); - - case 1: /* COB-ID client -> server */ - CO_setUint32(buf, CO_CAN_ID_SDO_CLI + SDO->nodeId); - return stream->dataLength = sizeof(uint32_t); - - case 2: /* COB-ID server -> client */ - CO_setUint32(buf, CO_CAN_ID_SDO_SRV + SDO->nodeId); - return stream->dataLength = sizeof(uint32_t); - - default: - *returnCode = ODR_SUB_NOT_EXIST; - return 0; - } -} - - /* helper for configuring CANrx and CANtx *************************************/ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, CO_CANmodule_t *CANdevRx, @@ -355,8 +315,8 @@ static OD_size_t OD_write_1201_additional(OD_stream_t *stream, uint8_t subIndex, /******************************************************************************/ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, - const OD_t *OD, - const OD_entry_t *OD_1200_SDOsrvPar, + OD_t *OD, + OD_entry_t *OD_1200_SDOsrvPar, uint8_t nodeId, uint16_t SDOtimeoutTime_ms, CO_CANmodule_t *CANdevRx, @@ -385,6 +345,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, /* configure CAN identifiers and SDO server parameters if available */ uint16_t CanId_ClientToServer, CanId_ServerToClient; + uint16_t OD_SDOsrvParIdx = OD_getIndex(OD_1200_SDOsrvPar); if (OD_1200_SDOsrvPar == NULL) { /* configure default SDO channel */ @@ -394,24 +355,19 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; } - else if (OD_getIndex(OD_1200_SDOsrvPar) == OD_H1200_SDO_SERVER_1_PARAM) { + else if (OD_SDOsrvParIdx == OD_H1200_SDO_SERVER_1_PARAM) { /* configure default SDO channel and SDO server parameters for it */ if (nodeId < 1 || nodeId > 127) return CO_ERROR_ILLEGAL_ARGUMENT; CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; - ODR_t odRetE = OD_extensionIO_init(OD_1200_SDOsrvPar, - (void *) SDO, - OD_read_1200_default, - NULL); - if (odRetE != ODR_OK) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1200_SDOsrvPar)); - return CO_ERROR_OD_PARAMETERS; - } + + OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); + OD_set_u32(OD_1200_SDOsrvPar, 2, CanId_ServerToClient, true); } - else if (OD_getIndex(OD_1200_SDOsrvPar) > OD_H1200_SDO_SERVER_1_PARAM - && OD_getIndex(OD_1200_SDOsrvPar) <= (OD_H1200_SDO_SERVER_1_PARAM+0x7F) + else if (OD_SDOsrvParIdx > OD_H1200_SDO_SERVER_1_PARAM + && OD_SDOsrvParIdx <= (OD_H1200_SDO_SERVER_1_PARAM + 0x7F) ) { /* configure additional SDO channel and SDO server parameters for it */ uint8_t maxSubIndex; @@ -427,7 +383,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (odRet0 != ODR_OK || (maxSubIndex != 2 && maxSubIndex != 3) || odRet1 != ODR_OK || odRet2 != ODR_OK ) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1200_SDOsrvPar)); + CO_errinfo(CANdevTx, OD_SDOsrvParIdx); return CO_ERROR_OD_PARAMETERS; } @@ -438,12 +394,13 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, ? (uint16_t)(COB_IDServerToClient32 & 0x7FF) : 0; #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC - ODR_t odRetE = OD_extensionIO_init(OD_1200_SDOsrvPar, - (void *) SDO, - OD_readOriginal, - OD_write_1201_additional); + SDO->OD_1200_extension.object = SDO; + SDO->OD_1200_extension.read = OD_readOriginal; + SDO->OD_1200_extension.write = OD_write_1201_additional; + ODR_t odRetE = OD_extension_init(OD_1200_SDOsrvPar, + &SDO->OD_1200_extension); if (odRetE != ODR_OK) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1200_SDOsrvPar)); + CO_errinfo(CANdevTx, OD_SDOsrvParIdx); return CO_ERROR_OD_PARAMETERS; } #endif @@ -532,7 +489,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, #ifdef CO_BIG_ENDIAN /* swap int16_t .. uint64_t data if necessary */ - if ((SDO->attribute & ODA_MB) != 0) { + if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { reverseBytes(SDO->buf, SDO->bufOffsetWr); } #endif @@ -543,7 +500,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, * shorter than size of OD data buffer. If so, add two zero bytes * to terminate (unicode) string. Shorten also OD data size, * (temporary, send information about EOF into OD_IO.write) */ - if ((SDO->attribute & ODA_STR) != 0 + if ((SDO->OD_IO.stream.attribute & ODA_STR) != 0 && (sizeInOd == 0 || SDO->sizeTran < sizeInOd) && (SDO->bufOffsetWr + 2) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE ) { @@ -661,7 +618,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, } /* if data is string, send only data up to null termination */ - if (countRd > 0 && (SDO->attribute & ODA_STR) != 0) { + if (countRd > 0 && (SDO->OD_IO.stream.attribute & ODA_STR) != 0) { bufShifted[countRd] = 0; /* (SDO->buf is one byte larger) */ OD_size_t countStr = strlen((char *)bufShifted); if (countStr == 0) countStr = 1; /* zero length is not allowed */ @@ -689,7 +646,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, #ifdef CO_BIG_ENDIAN /* swap data if necessary */ - if ((SDO->attribute & ODA_MB) != 0) { + if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { if (SDO->finished) { /* int16_t .. uint64_t */ reverseBytes(bufShifted, countRd); @@ -771,30 +728,30 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* if no error search object dictionary for new SDO request */ if (abortCode == CO_SDO_AB_NONE) { ODR_t odRet; - OD_subEntry_t subEntry; - SDO->index = ((uint16_t)SDO->CANrxData[2]) << 8 | SDO->CANrxData[1]; SDO->subIndex = SDO->CANrxData[3]; odRet = OD_getSub(OD_find(SDO->OD, SDO->index), SDO->subIndex, - &subEntry, &SDO->OD_IO, false); + &SDO->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); SDO->state = CO_SDO_ST_ABORT; } else { - SDO->attribute = subEntry.attribute; - /* verify read/write attributes */ - if ((SDO->attribute & ODA_SDO_RW) == 0) { + if ((SDO->OD_IO.stream.attribute & ODA_SDO_RW) == 0) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; SDO->state = CO_SDO_ST_ABORT; } - else if (upload && (SDO->attribute & ODA_SDO_R) == 0) { + else if (upload + && (SDO->OD_IO.stream.attribute & ODA_SDO_R) == 0 + ) { abortCode = CO_SDO_AB_WRITEONLY; SDO->state = CO_SDO_ST_ABORT; } - else if (!upload && (SDO->attribute & ODA_SDO_W) == 0) { + else if (!upload + && (SDO->OD_IO.stream.attribute & ODA_SDO_W) == 0 + ) { abortCode = CO_SDO_AB_READONLY; SDO->state = CO_SDO_ST_ABORT; } @@ -825,7 +782,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } else { /* If data type is string, size is not known */ - SDO->sizeInd = (SDO->attribute & ODA_STR) == 0 + SDO->sizeInd = (SDO->OD_IO.stream.attribute&ODA_STR)==0 ? SDO->OD_IO.stream.dataLength : 0; } @@ -854,7 +811,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, uint8_t buf[6] = {0}; memcpy(buf, &SDO->CANrxData[4], dataSizeToWrite); #ifdef CO_BIG_ENDIAN - if ((SDO->attribute & ODA_MB) != 0) { + if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { reverseBytes(buf, dataSizeToWrite); } #endif @@ -863,7 +820,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, * shorter as size of OD data buffer. If so, add two zero bytes * to terminate (unicode) string. Shorten also OD data size, * (temporary, send information about EOF into OD_IO.write) */ - if ((SDO->attribute & ODA_STR) != 0 + if ((SDO->OD_IO.stream.attribute & ODA_STR) != 0 && (sizeInOd == 0 || dataSizeToWrite < sizeInOd) ) { OD_size_t delta = sizeInOd - dataSizeToWrite; @@ -916,7 +873,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* strings are allowed to be shorter */ else if (SDO->sizeInd < sizeInOd - && (SDO->attribute & ODA_STR) == 0 + && (SDO->OD_IO.stream.attribute & ODA_STR) == 0 ) { abortCode = CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; @@ -1029,7 +986,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* strings are allowed to be shorter */ else if (SDO->sizeInd < sizeInOd - && (SDO->attribute & ODA_STR) == 0 + && (SDO->OD_IO.stream.attribute & ODA_STR) == 0 ) { abortCode = CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; @@ -1324,7 +1281,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, &odRet); /* strings are allowed to be shorter */ - if (odRet == ODR_PARTIAL && (SDO->attribute & ODA_STR) != 0) { + if (odRet == ODR_PARTIAL + && (SDO->OD_IO.stream.attribute & ODA_STR) != 0 + ) { odRet = ODR_OK; } @@ -1337,7 +1296,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #ifdef CO_BIG_ENDIAN /* swap data if necessary */ - if ((SDO->attribute & ODA_MB) != 0) { + if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { reverseBytes(buf, dataSizeToWrite); } #endif diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 9a49f0f4..2e54a3b3 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -442,7 +442,7 @@ typedef struct { /** CAN transmit buffer inside CANdevTx for CAN tx message */ CO_CANtx_t *CANtxBuff; /** From CO_SDOserver_init() */ - const OD_t *OD; + OD_t *OD; /** From CO_SDOserver_init() */ uint8_t nodeId; /* If true, SDO channel is valid */ @@ -455,8 +455,6 @@ typedef struct { uint16_t index; /** Subindex of the current object in Object Dictionary */ uint8_t subIndex; - /** Attribute bit-field of the current OD sub-object, see OD_attributes_t */ - OD_attr_t attribute; /** Indicates, if new SDO message received from CAN bus. It is not cleared, * until received message is completely processed. */ volatile void *CANrxNew; @@ -476,6 +474,8 @@ typedef struct { uint32_t COB_IDClientToServer; /** Copy of CANopen COB_ID Server -> Client, similar as above */ uint32_t COB_IDServerToClient; + /** Extension for OD object */ + OD_extension_t OD_1200_extension; #endif #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) || defined CO_DOXYGEN /** Size of data, which will be transferred. It is optionally indicated by @@ -546,8 +546,8 @@ typedef struct { * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, - const OD_t *OD, - const OD_entry_t *OD_1200_SDOsrvPar, + OD_t *OD, + OD_entry_t *OD_1200_SDOsrvPar, uint8_t nodeId, uint16_t SDOtimeoutTime_ms, CO_CANmodule_t *CANdevRx, diff --git a/CANopen.c b/CANopen.c index 43a9bcb1..dc1f36bd 100644 --- a/CANopen.c +++ b/CANopen.c @@ -906,8 +906,8 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_NMT_t *NMT, CO_EM_t *em, - const OD_t *od, - const OD_entry_t *OD_statusBits, + OD_t *od, + OD_entry_t *OD_statusBits, CO_NMT_control_t NMTcontrol, uint16_t firstHBTime_ms, uint16_t SDOserverTimeoutTime_ms, @@ -1020,7 +1020,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, /* SDOserver */ if (CO_GET_CNT(SDO_SRV) > 0) { - const OD_entry_t *SDOsrvPar = OD_GET(H1200,OD_H1200_SDO_SERVER_1_PARAM); + OD_entry_t *SDOsrvPar = OD_GET(H1200,OD_H1200_SDO_SERVER_1_PARAM); for (int16_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { err = CO_SDOserver_init(&co->SDOserver[i], od, @@ -1037,7 +1037,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE if (CO_GET_CNT(SDO_CLI) > 0) { - const OD_entry_t *SDOcliPar = OD_GET(H1280,OD_H1280_SDO_CLIENT_1_PARAM); + OD_entry_t *SDOcliPar = OD_GET(H1280,OD_H1280_SDO_CLIENT_1_PARAM); for (int16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { err = CO_SDOclient_init(&co->SDOclient[i], od, @@ -1087,8 +1087,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE if (CO_GET_CNT(RPDO) > 0) { - const OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); - const OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); + OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); + OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { err = CO_RPDO_init(co->RPDO[i], em, @@ -1113,8 +1113,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE if (CO_GET_CNT(TPDO) > 0) { - const OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); - const OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); + OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); + OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { err = CO_TPDO_init(co->TPDO[i], em, @@ -1161,8 +1161,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, OD_H13FF_SRDO_CHECKSUM); if (err) return err; - const OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); - const OD_entry_t *SRDOmap = OD_GET(H1318, OD_H1381_SRDO_1_MAPPING); + OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); + OD_entry_t *SRDOmap = OD_GET(H1318, OD_H1381_SRDO_1_MAPPING); for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { uint16_t CANdevRxIdx = CO_GET_CO(RX_IDX_SRDO) + 2 * i; uint16_t CANdevTxIdx = CO_GET_CO(TX_IDX_SRDO) + 2 * i; diff --git a/CANopen.h b/CANopen.h index c3ceed9d..7576ce7d 100644 --- a/CANopen.h +++ b/CANopen.h @@ -230,57 +230,57 @@ typedef struct { * @ref CO_CONFIG_NMT. Start indexes inside CANrx and CANtx are always 0. * There must be one NMT object in the device. */ uint8_t CNT_NMT; - const OD_entry_t *ENTRY_H1017; /**< OD entry for @ref CO_NMT_init() */ + OD_entry_t *ENTRY_H1017; /**< OD entry for @ref CO_NMT_init() */ /** Number of Heartbeat consumer objects, 0 or 1: object uses from 1 to 127 * internal consumers (CANrx), as specified by @ref CO_CONFIG_HB_CONS_SIZE. */ uint8_t CNT_HB_CONS; - const OD_entry_t *ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init()*/ + OD_entry_t *ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init()*/ /** Number of Emergency objects, 0 or 1: optional producer (CANtx) + * optional consumer (CANrx), configurable by @ref CO_CONFIG_EM. * There must be one Emergency object in the device. */ uint8_t CNT_EM; const OD_entry_t *ENTRY_H1001; /**< OD entry for @ref CO_EM_init() */ - const OD_entry_t *ENTRY_H1014; /**< OD entry for @ref CO_EM_init() */ - const OD_entry_t *ENTRY_H1015; /**< OD entry for @ref CO_EM_init() */ - const OD_entry_t *ENTRY_H1003; /**< OD entry for @ref CO_EM_init() */ + OD_entry_t *ENTRY_H1014; /**< OD entry for @ref CO_EM_init() */ + OD_entry_t *ENTRY_H1015; /**< OD entry for @ref CO_EM_init() */ + OD_entry_t *ENTRY_H1003; /**< OD entry for @ref CO_EM_init() */ /** Number of SDO server objects, from 0 to 128 (CANrx + CANtx). There must * be at least one SDO server object in the device. */ uint8_t CNT_SDO_SRV; - const OD_entry_t *ENTRY_H1200; /**< OD entry for @ref CO_SDOserver_init()*/ + OD_entry_t *ENTRY_H1200; /**< OD entry for @ref CO_SDOserver_init()*/ /** Number of SDO client objects, from 0 to 128 (CANrx + CANtx). */ uint8_t CNT_SDO_CLI; - const OD_entry_t *ENTRY_H1280; /**< OD entry for @ref CO_SDOclient_init()*/ + OD_entry_t *ENTRY_H1280; /**< OD entry for @ref CO_SDOclient_init()*/ /** Number of TIME objects, 0 or 1: consumer (CANrx) + optional producer * (CANtx), configurable by @ref CO_CONFIG_TIME. */ uint8_t CNT_TIME; - const OD_entry_t *ENTRY_H1012; /**< OD entry for @ref CO_TIME_init() */ + OD_entry_t *ENTRY_H1012; /**< OD entry for @ref CO_TIME_init() */ /** Number of SYNC objects, 0 or 1: consumer (CANrx) + optional producer * (CANtx), configurable by @ref CO_CONFIG_SYNC. */ uint8_t CNT_SYNC; - const OD_entry_t *ENTRY_H1005; /**< OD entry for @ref CO_SYNC_init() */ - const OD_entry_t *ENTRY_H1006; /**< OD entry for @ref CO_SYNC_init() */ - const OD_entry_t *ENTRY_H1007; /**< OD entry for @ref CO_SYNC_init() */ - const OD_entry_t *ENTRY_H1019; /**< OD entry for @ref CO_SYNC_init() */ + OD_entry_t *ENTRY_H1005; /**< OD entry for @ref CO_SYNC_init() */ + OD_entry_t *ENTRY_H1006; /**< OD entry for @ref CO_SYNC_init() */ + OD_entry_t *ENTRY_H1007; /**< OD entry for @ref CO_SYNC_init() */ + OD_entry_t *ENTRY_H1019; /**< OD entry for @ref CO_SYNC_init() */ /** Number of RPDO objects, from 0 to 512 consumers (CANrx) */ uint16_t CNT_RPDO; - const OD_entry_t *ENTRY_H1400; /**< OD entry for @ref CO_RPDO_init() */ - const OD_entry_t *ENTRY_H1600; /**< OD entry for @ref CO_RPDO_init() */ + OD_entry_t *ENTRY_H1400; /**< OD entry for @ref CO_RPDO_init() */ + OD_entry_t *ENTRY_H1600; /**< OD entry for @ref CO_RPDO_init() */ /** Number of TPDO objects, from 0 to 512 producers (CANtx) */ uint16_t CNT_TPDO; - const OD_entry_t *ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */ - const OD_entry_t *ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */ + OD_entry_t *ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */ + OD_entry_t *ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */ /** Number of LEDs objects, 0 or 1. */ uint8_t CNT_LEDS; /** Number of GFC objects, 0 or 1 (CANrx + CANtx). */ uint8_t CNT_GFC; - const OD_entry_t *ENTRY_H1300; /**< OD entry for @ref CO_GFC_init() */ + OD_entry_t *ENTRY_H1300; /**< OD entry for @ref CO_GFC_init() */ /** Number of SRDO objects, from 0 to 64 (2*CANrx + 2*CANtx). */ uint8_t CNT_SRDO; - const OD_entry_t *ENTRY_H1301; /**< OD entry for @ref CO_SRDO_init() */ - const OD_entry_t *ENTRY_H1381; /**< OD entry for @ref CO_SRDO_init() */ - const OD_entry_t *ENTRY_H13FE; /**< OD entry for @ref CO_SRDOGuard_init() */ - const OD_entry_t *ENTRY_H13FF; /**< OD entry for @ref CO_SRDOGuard_init() */ + OD_entry_t *ENTRY_H1301; /**< OD entry for @ref CO_SRDO_init() */ + OD_entry_t *ENTRY_H1381; /**< OD entry for @ref CO_SRDO_init() */ + OD_entry_t *ENTRY_H13FE; /**< OD entry for @ref CO_SRDOGuard_init() */ + OD_entry_t *ENTRY_H13FF; /**< OD entry for @ref CO_SRDOGuard_init() */ /** Number of LSSslave objects, 0 or 1 (CANrx + CANtx). */ uint8_t CNT_LSS_SLV; /** Number of LSSmaster objects, 0 or 1 (CANrx + CANtx). */ @@ -534,8 +534,8 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_NMT_t *NMT, CO_EM_t *em, - const OD_t *od, - const OD_entry_t *OD_statusBits, + OD_t *od, + OD_entry_t *OD_statusBits, CO_NMT_control_t NMTcontrol, uint16_t firstHBTime_ms, uint16_t SDOserverTimeoutTime_ms, diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 2d58adf8..5870021e 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -21,21 +21,15 @@ The term **OD variable** is basic variable of specified type. For example: int8_ The term **OD entry** means structure element, which contains some basic properties of the OD object, indication of type of OD object and pointer to all necessary data for the OD object. An array of OD entries together with information about total number of OD entries represents object dictionary as defined inside CANopenNode. See @ref OD_entry_t and @ref OD_t. ### Access -Application and the stack have access to OD objects via universal @ref OD_t object and @ref OD_find() function. No direct access to custom structures, which define object dictionary, is required. Properties for specific OD variable is fetched with @ref OD_getSub() function. Access to actual variable is via **read** and **write** functions. Pointer to those two functions is fetched by @ref OD_getSub(). See @ref OD_stream_t and @ref OD_subEntry_t. See also shortcuts: @ref CO_ODgetSetters, for access to data of different type. - -### Optional extensions -There are some optional extensions to the object dictionary: - * **PDO flags** informs application, if specific OD variable was received or sent by PDO. And also gives the application ability to request a TPDO, to which variable is possibly mapped. - * **IO extension** gives the application ability to take full control over the OD object. Application can specify own **read** and **write** functions and own object, on which they operate. +Application and the stack have access to OD objects via universal @ref OD_t object and @ref OD_find() function. No direct access to custom structures, which define object dictionary, is required. Properties for specific OD variable is fetched with @ref OD_getSub() function. Access to actual variable is via **read** and **write** functions. Pointer to those two functions is fetched by @ref OD_getSub(). See @ref OD_stream_t. See also shortcuts: @ref CO_ODgetSetters, for access to data of different type. ### Example usage ```c -extern const OD_t ODxyz; +extern OD_t *ODxyz; -void myFunc(const OD_t *od) { +void myFunc(OD_t *od) { ODR_t ret; - const OD_entry_t *entry; - OD_subEntry_t subEntry; + OD_entry_t *entry; OD_IO_t io1008; char buf[50]; OD_size_t bytesRd; @@ -43,7 +37,7 @@ void myFunc(const OD_t *od) { /* Init IO for "Manufacturer device name" at index 0x1008, sub-index 0x00 */ entry = OD_find(od, 0x1008); - ret = OD_getSub(entry, 0x00, &subEntry, &io1008, false); + ret = OD_getSub(entry, 0x00, &io1008, false); /* Read with io1008, subindex = 0x00 */ if (ret == ODR_OK) bytesRd = io1008.read(&io1008.stream, 0x00, &buf[0], sizeof(buf), &ret); @@ -64,14 +58,14 @@ If access to the same variable is very frequent, it is better to use first examp Some simple user applications can also access some OD variables directly via globals. @warning -If OD object has IO extension enabled, then direct access to its OD variables must not be used. Only valid access is via read or write or helper functions. +If OD object has OD extension enabled, then direct access to its OD variables must not be used. Only valid access is via read or write or helper functions. ```c #include ODxyz.h void myFuncGlob(void) { //Direct address instead of OD_find() - const OD_entry_t *entry_errReg = ODxyz_1001_errorRegister; + OD_entry_t *entry_errReg = ODxyz_1001_errorRegister; //Direct access to OD variable uint32_t devType = ODxyz_0.x1000_deviceType; @@ -117,18 +111,18 @@ typedef struct { extern ODxyz_PERSIST_COMM_t ODxyz_PERSIST_COMM; extern ODxyz_RAM_t ODxyz_RAM; -extern const OD_t ODxyz; +extern OD_t *ODxyz; /* Object dictionary entries - shortcuts **************************************/ -#define ODxyz_ENTRY_H1000 &ODxyz.list[0] -#define ODxyz_ENTRY_H1001 &ODxyz.list[1] -#define ODxyz_ENTRY_H1003 &ODxyz.list[2] -#define ODxyz_ENTRY_H1018 &ODxyz.list[3] - -#define ODxyz_ENTRY_H1000_deviceType &ODxyz.list[0] -#define ODxyz_ENTRY_H1001_errorRegister &ODxyz.list[1] -#define ODxyz_ENTRY_H1003_preDefinedErrorField &ODxyz.list[2] -#define ODxyz_ENTRY_H1018_identity &ODxyz.list[3] +#define ODxyz_ENTRY_H1000 &ODxyz->list[0] +#define ODxyz_ENTRY_H1001 &ODxyz->list[1] +#define ODxyz_ENTRY_H1003 &ODxyz->list[2] +#define ODxyz_ENTRY_H1018 &ODxyz->list[3] + +#define ODxyz_ENTRY_H1000_deviceType &ODxyz->list[0] +#define ODxyz_ENTRY_H1001_errorRegister &ODxyz->list[1] +#define ODxyz_ENTRY_H1003_preDefinedErrorField &ODxyz->list[2] +#define ODxyz_ENTRY_H1018_identity &ODxyz->list[3] ``` ### Example ODxyz.c file @@ -139,13 +133,13 @@ extern const OD_t ODxyz; /* OD data initialization of all groups ***************************************/ ODxyz_PERSIST_COMM_t ODxyz_PERSIST_COMM = { - .x1000_deviceType = 0L, + .x1000_deviceType = 0, .x1018_identity = { .maxSubIndex = 4, - .vendorID = 0L, - .productCode = 0L, - .revisionNumber = 0L, - .serialNumber = 0L + .vendorID = 0, + .productCode = 0, + .revisionNumber = 0, + .serialNumber = 0 } }; @@ -155,46 +149,33 @@ ODxyz_RAM_t ODxyz_RAM = { .x1003_preDefinedErrorField = {0, 0, 0, 0, 0, 0, 0, 0} }; -/* IO extensions and flagsPDO (configurable by application) *******************/ -typedef struct { - OD_extensionIO_t xio_1003_preDefinedErrorField; -} ODxyzExts_t; - -static ODxyzExts_t ODxyzExts = {0}; - /* All OD objects (constant) **************************************************/ typedef struct { OD_obj_var_t o_1000_deviceType; OD_obj_var_t o_1001_errorRegister; OD_obj_array_t o_1003_preDefinedErrorField; - OD_obj_extended_t oE_1003_preDefinedErrorField; OD_obj_record_t o_1018_identity[5]; } ODxyzObjs_t; -static const ODxyzObjs_t ODxyzObjs = { +static CO_PROGMEM ODxyzObjs_t ODxyzObjs = { .o_1000_deviceType = { - .data = &ODxyz_PERSIST_COMM.x1000_deviceType, + .dataOrig = &ODxyz_PERSIST_COMM.x1000_deviceType, .attribute = ODA_SDO_R | ODA_MB, .dataLength = 4 }, .o_1001_errorRegister = { - .data = &ODxyz_RAM.x1001_errorRegister, + .dataOrig = &ODxyz_RAM.x1001_errorRegister, .attribute = ODA_SDO_R, .dataLength = 1 }, .o_1003_preDefinedErrorField = { - .data0 = &ODxyz_RAM.x1003_preDefinedErrorField_sub0, - .data = &ODxyz_RAM.x1003_preDefinedErrorField[0], + .dataOrig0 = &ODxyz_RAM.x1003_preDefinedErrorField_sub0, + .dataOrig = &ODxyz_RAM.x1003_preDefinedErrorField[0], .attribute0 = ODA_SDO_RW, .attribute = ODA_SDO_R | ODA_MB, .dataElementLength = 4, .dataElementSizeof = sizeof(uint32_t) }, - .oE_1003_preDefinedErrorField = { - .extIO = &ODxyzExts.xio_1003_preDefinedErrorField, - .flagsPDO = NULL, - .odObjectOriginal = &ODxyzObjs.o_1003_preDefinedErrorField - }, .o_1018_identity = { { .data = &ODxyz_PERSIST_COMM.x1018_identity.maxSubIndex, @@ -230,18 +211,20 @@ static const ODxyzObjs_t ODxyzObjs = { }; /* Object dictionary **********************************************************/ -static const OD_entry_t ODxyzList[] = { - {0x1000, 1, ODT_VAR, &ODxyzObjs.o_1000_deviceType}, - {0x1001, 1, ODT_VAR, &ODxyzObjs.o_1001_errorRegister}, - {0x1003, 9, ODT_EVAR, &ODxyzObjs.oE_1003_preDefinedErrorField}, - {0x1018, 5, ODT_REC, &ODxyzObjs.o_1018_identity}, - {0x0000, 0, 0, NULL} +static OD_entry_t ODxyzList[] = { + {0x1000, 0x01, ODT_VAR, &ODxyzObjs.o_1000_deviceType, NULL}, + {0x1001, 0x01, ODT_VAR, &ODxyzObjs.o_1001_errorRegister, NULL}, + {0x1003, 0x09, ODT_VAR, &ODxyzObjs.o_1003_preDefinedErrorField, NULL}, + {0x1018, 0x05, ODT_REC, &ODxyzObjs.o_1018_identity, NULL}, + {0x0000, 0x00, 0, NULL, NULL} }; -const OD_t ODxyz = { +OD_t _ODxyz = { (sizeof(ODxyzList) / sizeof(ODxyzList[0])) - 1, &ODxyzList[0] }; + +OD_t *ODxyz = &_ODxyz; ``` @@ -289,7 +272,6 @@ There are also device configuration files with "XDC" extension. They are describ - @@ -407,13 +389,11 @@ If "uniqueIDRef" attribute is not specified and "objectType" is 7(VAR), then "CA * "noAccess" - object will be in object dictionary, but no access. * <**label** lang="en">, <**description** lang="en"> (required) - several elements in multiple languages possible * <**INT and similar**/> (required) - Basic or complex data type. Basic data type (for VAR) is specified in IEC 61131-3 (see below). If data type is complex (ARRAY or RECORD), then **<dataTypeIDRef>** must be specified and entry must be added in the **<dataTypeList>**. Such definition of complex data types is required by the standard, but it is not required by CANopenNode. - * <**defaultValue**> (optional for VAR) - Default value for the variable. If it is empty string, then data is not stored inside object dictionary. Application should provide own data via IO extension. + * <**defaultValue**> (optional for VAR) - Default value for the variable. If it is empty string, then data is not stored inside object dictionary. Application should provide own data via OD extension. * <**property** name="..." value="..."> (optional) - Multiple elements may contain additional custom properties. CANopenNode uses custom properties with following names: * "**CO_disabled**" (used for base OD entry) - Valid value is "false" (default) or "true". if OD entry is disabled, then it will not be present in generated Object Dictionary .h and .c files. * "**CO_countLabel**" (used for base OD entry) - Valid value is any string without spaces. OD exporter will generate a macro for each different string. For example, if four OD objects have "CO_countLabel" set to "TPDO", then macro "#define ODxyz_CNT_TPDO 4" will be generated by OD exporter. "CO_countLabel" is not required for configuration with multiple object dictionaries (CO_MULTIPLE_OD), although may be useful. Default is "". * "**CO_storageGroup**" (used for base OD entry) - group name (string) into which the C variable will belong. Variables from specific storage group may then be stored into non-volatile memory, automatically or by SDO command. Default is "RAM". Please note: if <defaultValue> is empty string at specific subindex, then no storage group will be used for that variable. - * "**CO_extensionIO**" (used for base OD entry) - Valid value is "false" (default) or "true", if IO extension is enabled. - * "**CO_flagsPDO**" (used for base OD entry) - Valid value is "false" (default) or "true", if PDO flags are enabled. * "**CO_accessSRDO**" (used for each "VAR") - Valid values are: "tx", "rx", "trx", "no"(default). * "**CO_stringLengthMin**" (used for each "VAR") - Minimum length of the string. Used with "VISIBLE_STRING" and "UNICODE_STRING". If CO_stringLengthMin is smaller than length of the string in <defaultValue>, then it is ignored. Byte length of unicode string is 2 * CO_stringLengthMin. If <defaultValue> is empty and CO_stringLengthMin is 0, then data is not stored inside object dictionary. Default is 0. @@ -462,62 +442,56 @@ Other elements listed in the above XML example are required by the standard. The Object Dictionary Requirements By CANopenNode {#object-dictionary-requirements-by-canopennode} ---------------------------------------------------------------------------------------------- * **Used by** column indicates CANopenNode object or its part, which uses the OD object. It also indicates, if OD object is required or optional for actual configuration. For the configuration of the CANopenNode objects see [Stack configuration](301/CO_config.h). If CANopenNode object or its part is disabled in stack configuration, then OD object is not used. Note that OD objects: 1000, 1001 and 1017 and 1018 are mandatory for CANopen. -* **CO_extensionIO** column indicates, if OD object must have property "CO_extensionIO" set to true: - * "no" - no IO extension used - * "optional" - If IO extension is enabled, then writing to the OD parameter will reflect in CANopen run time, otherwise reset communication is required for changes to take effect. - * "required" - IO extension is required on OD object and init function will return error if not enabled. - * "req if DYNAMIC" - IO extension is required on OD object if CO_CONFIG_FLAG_OD_DYNAMIC is set. - * "yes, own data" - OD object don't need own data and IO extension is necessary for OD object to work. Init function will not return error, if OD object does not exist or doesn't have IO extension enabled. * **CO_countLabel** column indicates, which value must have property "CO_countLabel" inside OD object. -| index | Description | Used by | CO_extensionIO | CO_countLabel | -| ----- | ----------------------------- | ---------------------| -------------- | ------------- | -| 1000 | Device type | CANopen, req | no | NMT | -| 1001 | Error register | CANopen, EM, req | no | EM | -| 1002 | Manufacturer status register | | | | -| 1003 | Pre-defined error field | EM_HISTORY, opt | yes, own data | | -| 1005 | COB-ID SYNC message | SYNC, req | req if DYNAMIC | SYNC | -| 1006 | Communication cycle period | SYNC_PRODUCER, req | opt | SYNC_PROD | -| 1007 | Synchronous window length | SYNC, opt | opt | | -| 1008 | Manufacturer device name | | | | -| 1009 | Manufacturer hardware version | | | | -| 100A | Manufacturer software version | | | | -| 100C | Guard time | | | | -| 100D | Life time factor | | | | -| 1010 | Store parameters | | | | -| 1011 | Restore default parameters | | | | -| 1012 | COB-ID time stamp object | TIME, req | required | TIME | -| 1013 | High resolution time stamp | | | | -| 1014 | COB-ID EMCY | EM_PRODUCER, req | required | EM_PROD | -| 1015 | Inhibit time EMCY | EM_PROD_INHIBIT, opt | optional | | -| 1016 | Consumer heartbeat time | HB_CONS, req | optional | HB_CONS | -| 1017 | Producer heartbeat time | CANopen, NMT, req | required | HB_PROD | -| 1018 | Identity object | CANopen, LSS_SL, req | no | | -| 1019 | Synch. counter overflow value | SYNC, opt | no | | -| 1020 | Verify configuration | | | | -| 1021 | Store EDS | | | | -| 1022 | Store format | | | | -| 1023 | OS command | | | | -| 1024 | OS command mode | | | | -| 1025 | OS debugger interface | | | | -| 1026 | OS prompt | | | | -| 1027 | Module list | | | | -| 1028 | Emergency consumer object | | | | -| 1029 | Error behavior object | | | | -| 1200 | SDO server parameter (first) | SDO optional | required | SDO_SRV | -| 1201+ | SDO server parameter | SDO+, req | req if DYNAMIC | SDO_SRV | -| 1280+ | SDO client parameter | SDO_CLI, req | req if DYNAMIC | SDO_CLI | -| 1300 | Global fail-safe command par | GFC, req | | GFC | -| 1301+ | SRDO communication parameter | SRDO, req | | SRDO | -| 1381+ | SRDO mapping parameter | SRDO, req | | | -| 13FE | Configuration valid | SRDO, req | | | -| 13FF | Safety configuration checksum | SRDO, req | | | -| 1400+ | RPDO communication parameter | RPDO, req | req if DYNAMIC | RPDO | -| 1600+ | RPDO mapping parameter | RPDO, req | req if DYNAMIC | | -| 1800+ | TPDO communication parameter | TPDO, req | req if DYNAMIC | TPDO | -| 1A00+ | TPDO mapping parameter | TPDO, req | req if DYNAMIC | | -| 1FA0+ | Object scanner list | | | | -| 1FD0+ | Object dispatching list | | | | -| | Custom objects | | | | -| any | Error status bits | EM_STATUS_BITS, opt | yes, own data | | -| any+ | Trace | TRACE, req | yes, own data | TRACE | +| index | Description | Used by | CO_countLabel | +| ----- | ----------------------------- | ---------------------| ------------- | +| 1000 | Device type | CANopen, req | NMT | +| 1001 | Error register | CANopen, EM, req | EM | +| 1002 | Manufacturer status register | | | +| 1003 | Pre-defined error field | EM_HISTORY, opt | | +| 1005 | COB-ID SYNC message | SYNC, req | SYNC | +| 1006 | Communication cycle period | SYNC_PRODUCER, req | SYNC_PROD | +| 1007 | Synchronous window length | SYNC, opt | | +| 1008 | Manufacturer device name | | | +| 1009 | Manufacturer hardware version | | | +| 100A | Manufacturer software version | | | +| 100C | Guard time | | | +| 100D | Life time factor | | | +| 1010 | Store parameters | | | +| 1011 | Restore default parameters | | | +| 1012 | COB-ID time stamp object | TIME, req | TIME | +| 1013 | High resolution time stamp | | | +| 1014 | COB-ID EMCY | EM_PRODUCER, req | EM_PROD | +| 1015 | Inhibit time EMCY | EM_PROD_INHIBIT, opt | | +| 1016 | Consumer heartbeat time | HB_CONS, req | HB_CONS | +| 1017 | Producer heartbeat time | CANopen, NMT, req | HB_PROD | +| 1018 | Identity object | CANopen, LSS_SL, req | | +| 1019 | Synch. counter overflow value | SYNC, opt | | +| 1020 | Verify configuration | | | +| 1021 | Store EDS | | | +| 1022 | Store format | | | +| 1023 | OS command | | | +| 1024 | OS command mode | | | +| 1025 | OS debugger interface | | | +| 1026 | OS prompt | | | +| 1027 | Module list | | | +| 1028 | Emergency consumer object | | | +| 1029 | Error behavior object | | | +| 1200 | SDO server parameter (first) | SDO optional | SDO_SRV | +| 1201+ | SDO server parameter | SDO+, req | SDO_SRV | +| 1280+ | SDO client parameter | SDO_CLI, req | SDO_CLI | +| 1300 | Global fail-safe command par | GFC, req | GFC | +| 1301+ | SRDO communication parameter | SRDO, req | SRDO | +| 1381+ | SRDO mapping parameter | SRDO, req | | +| 13FE | Configuration valid | SRDO, req | | +| 13FF | Safety configuration checksum | SRDO, req | | +| 1400+ | RPDO communication parameter | RPDO, req | RPDO | +| 1600+ | RPDO mapping parameter | RPDO, req | | +| 1800+ | TPDO communication parameter | TPDO, req | TPDO | +| 1A00+ | TPDO mapping parameter | TPDO, req | | +| 1FA0+ | Object scanner list | | | +| 1FD0+ | Object dispatching list | | | +| | Custom objects | | | +| any | Error status bits | EM_STATUS_BITS, opt | | +| any+ | Trace | TRACE, req | TRACE | diff --git a/example/DS301_profile.eds b/example/DS301_profile.eds index c3a2f5b5..cae68509 100644 --- a/example/DS301_profile.eds +++ b/example/DS301_profile.eds @@ -8,8 +8,8 @@ Description= CreationTime=12:00PM CreationDate=11-23-2020 CreatedBy= -ModificationTime=1:31PM -ModificationDate=11-24-2020 +ModificationTime=4:21PM +ModificationDate=01-06-2021 ModifiedBy= [DeviceInfo] diff --git a/example/DS301_profile.md b/example/DS301_profile.md index 8dbd4404..4196b2d1 100644 --- a/example/DS301_profile.md +++ b/example/DS301_profile.md @@ -4,32 +4,37 @@ CANopen documentation -| | | -| ------------ | ------------------------------ | +| | | +| ------------ | ------------------------------ | | Project File | DS301_profile.xpd | | File Version | 1 | | Created | 23. 11. 2020 12:00:00 | | Created By | | -| Modified | 24. 11. 2020 13:31:53 | +| Modified | 6. 01. 2021 16:21:52 | | Modified By | | -This file was automatically generated with [libedssharp](https://github.com/robincornelius/libedssharp) Object Dictionary Editor v0.8-99-g0425f94 +This file was automatically generated with [libedssharp](https://github.com/robincornelius/libedssharp) Object Dictionary Editor v0.8-116-g2e8a14a + +* [Device Information](#device-information) +* [PDO Mapping](#pdo-mapping) +* [Communication Specific Parameters](#communication-specific-parameters) +* [Manufacturer Specific Parameters](#manufacturer-specific-parameters) +* [Device Profile Specific Parameters](#device-profile-specific-parameters) + -* [Device Information](#device-information) * [PDO Mapping](#pdo-mapping) * [Communication Specific Parameters](#communication-specific-parameters) * [Manufacturer Specific Parameters](#manufacturer-specific-parameters) * [Device Profile Specific Parameters](#device-profile-specific-parameters) - Device Information {#device-information} ---------------------------------------- -| | | -| ------------ | ------------------------------ | +| | | +| ------------ | ------------------------------ | | Vendor Name | | | Vendor ID | | | Product Name | New Product | | Product ID | | -| Granularity | 8 | -| RPDO count | 4 | -| TPDO count | 4 | -| LSS Slave | True | -| LSS Master | False | +| Granularity | 8 | +| RPDO count | 4 | +| TPDO count | 4 | +| LSS Slave | True | +| LSS Master | False | #### Supported Baud rates * [x] 10 kBit/s @@ -50,24 +55,24 @@ Communication Specific Parameters {#communication-specific-parameters} ---------------------------------------------------------------------- ### 0x1000 - Device type -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | NMT | PERSIST_COMM | False | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | NMT | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED32 | ro | no | no | 0x00000000 | * bit 16-31: Additional information * bit 0-15: Device profile number ### 0x1001 - Error register -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | EM | RAM | False | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | EM | RAM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED8 | ro | tr | no | 0x00 | * bit 7: manufacturer specific @@ -80,11 +85,11 @@ Communication Specific Parameters {#communication-specific-parameters} * bit 0: generic error ### 0x1003 - Pre-defined error field -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| ARRAY | | RAM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| ARRAY | | RAM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of errors | UNSIGNED8 | rw | no | no | 0 | | 0x01 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | @@ -102,12 +107,12 @@ Communication Specific Parameters {#communication-specific-parameters} * bit 0-15: Error code as transmited in the Emergency object ### 0x1005 - COB-ID SYNC message -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | SYNC | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | SYNC | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED32 | rw | no | no | 0x00000080 | * bit 31: set to 0 @@ -116,33 +121,33 @@ Communication Specific Parameters {#communication-specific-parameters} * bit 0-10: 11-bit CAN-ID ### 0x1006 - Communication cycle period -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | SYNC_PROD | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | SYNC_PROD | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED32 | rw | no | no | 0 | Period of SYNC transmission in µs (0 = transmission disabled). ### 0x1007 - Synchronous window length -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED32 | rw | no | no | 0 | Synchronous window leghth in µs (0 = not used). All synchronous PDOs must be transmitted within this time window. ### 0x1010 - Store parameters -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| ARRAY | | RAM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| ARRAY | | RAM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x04 | | 0x01 | Save all parameters | UNSIGNED32 | rw | no | no | 0x00000001 | @@ -157,11 +162,11 @@ Sub-indexes 1 and above: * Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores corresponding data. ### 0x1011 - Restore default parameters -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| ARRAY | | RAM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| ARRAY | | RAM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x04 | | 0x01 | Restore all default parameters| UNSIGNED32 | rw | no | no | 0x00000001 | @@ -175,12 +180,12 @@ Sub-indexes 1 and above: * Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) restores corresponding data. ### 0x1012 - COB-ID time stamp object -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | TIME | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | TIME | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED32 | rw | no | no | 0x00000100 | * bit 31: If set, CANopen device consumes TIME message @@ -189,12 +194,12 @@ Sub-indexes 1 and above: * bit 0-10: 11-bit CAN-ID ### 0x1014 - COB-ID EMCY -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | EM_PROD | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | EM_PROD | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED32 | rw | no | no | 0x80+$NODEID | * bit 31: If set, EMCY does NOT exist / is NOT valid @@ -202,22 +207,22 @@ Sub-indexes 1 and above: * bit 0-10: 11-bit CAN-ID ### 0x1015 - Inhibit time EMCY -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED16 | rw | no | no | 0 | Inhibit time of emergency message in multiples of 100µs. The value 0 disables the inhibit time. ### 0x1016 - Consumer heartbeat time -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| ARRAY | HB_CONS | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| ARRAY | HB_CONS | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x08 | | 0x01 | Consumer heartbeat time| UNSIGNED32 | rw | no | no | 0x00000000 | @@ -235,22 +240,22 @@ Consumer Heartbeat Time: * bit 0-15: Heartbeat time in ms (if 0, sub-intry is not used). Value should be higher than the corresponding producer heartbeat time. ### 0x1017 - Producer heartbeat time -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | HB_PROD | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | HB_PROD | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED16 | rw | no | no | 0 | Heartbeat producer time in ms (0 = disable transmission). ### 0x1018 - Identity -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | False | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x04 | | 0x01 | Vendor-ID | UNSIGNED32 | ro | no | no | 0x00000000 | @@ -266,12 +271,12 @@ Heartbeat producer time in ms (0 = disable transmission). * Serial number, manufacturer specific ### 0x1019 - Synchronous counter overflow value -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| VAR | | PERSIST_COMM | False | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| VAR | | PERSIST_COMM | -| Data Type | SDO | PDO | SRDO | Default Value | -| ----------------------- | --- | --- | ---- | ------------------------------- | +| Data Type | SDO | PDO | SRDO | Default Value | +| ----------------------- | --- | --- | ---- | ------------------------------- | | UNSIGNED8 | rw | no | no | 0 | * Value 0: SYNC message is transmitted with data length 0. @@ -280,11 +285,11 @@ Heartbeat producer time in ms (0 = disable transmission). * Value 241-255: reserved. ### 0x1200 - SDO server parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | SDO_SRV | RAM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | SDO_SRV | RAM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 2 | | 0x01 | COB-ID client to server (rx)| UNSIGNED32 | ro | t | no | 0x600+$NODEID | @@ -295,11 +300,11 @@ Sub-indexes 1 and 2: * bit 0-10: 11-bit CAN-ID ### 0x1280 - SDO client parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | SDO_CLI | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | SDO_CLI | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x03 | | 0x01 | COB-ID client to server (tx)| UNSIGNED32 | rw | tr | no | 0x80000000 | @@ -314,11 +319,11 @@ Sub-indexes 1 and 2: * Node-ID of the SDO server, 0x01 to 0x7F ### 0x1400 - RPDO communication parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | RPDO | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | RPDO | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | | 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000200+$NODEID| @@ -337,11 +342,11 @@ Sub-indexes 1 and 2: * Event timer in ms (0 = disabled) for deadline monitoring. ### 0x1401 - RPDO communication parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | RPDO | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | RPDO | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | | 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000300+$NODEID| @@ -360,11 +365,11 @@ Sub-indexes 1 and 2: * Event timer in ms (0 = disabled) for deadline monitoring. ### 0x1402 - RPDO communication parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | RPDO | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | RPDO | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | | 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000400+$NODEID| @@ -383,11 +388,11 @@ Sub-indexes 1 and 2: * Event timer in ms (0 = disabled) for deadline monitoring. ### 0x1403 - RPDO communication parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | RPDO | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | RPDO | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | | 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000500+$NODEID| @@ -406,11 +411,11 @@ Sub-indexes 1 and 2: * Event timer in ms (0 = disabled) for deadline monitoring. ### 0x1600 - RPDO mapping parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | | 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | @@ -432,11 +437,11 @@ Sub-indexes 1 and 2: * bit 0-7: data length in bits ### 0x1601 - RPDO mapping parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | | 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | @@ -458,11 +463,11 @@ Sub-indexes 1 and 2: * bit 0-7: data length in bits ### 0x1602 - RPDO mapping parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | | 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | @@ -484,11 +489,11 @@ Sub-indexes 1 and 2: * bit 0-7: data length in bits ### 0x1603 - RPDO mapping parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | | 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | @@ -510,11 +515,11 @@ Sub-indexes 1 and 2: * bit 0-7: data length in bits ### 0x1800 - TPDO communication parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | TPDO | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | TPDO | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | | 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000180+$NODEID| @@ -541,11 +546,11 @@ Sub-indexes 1 and 2: * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. ### 0x1801 - TPDO communication parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | TPDO | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | TPDO | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | | 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000280+$NODEID| @@ -572,11 +577,11 @@ Sub-indexes 1 and 2: * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. ### 0x1802 - TPDO communication parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | TPDO | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | TPDO | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | | 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000380+$NODEID| @@ -603,11 +608,11 @@ Sub-indexes 1 and 2: * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. ### 0x1803 - TPDO communication parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | TPDO | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | TPDO | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | | 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000480+$NODEID| @@ -634,11 +639,11 @@ Sub-indexes 1 and 2: * Value 1-240: The SYNC message with the counter value equal to this value shall be regarded as the first received SYNC message. ### 0x1A00 - TPDO mapping parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | | 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | @@ -660,11 +665,11 @@ Sub-indexes 1 and 2: * bit 0-7: data length in bits ### 0x1A01 - TPDO mapping parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | | 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | @@ -686,11 +691,11 @@ Sub-indexes 1 and 2: * bit 0-7: data length in bits ### 0x1A02 - TPDO mapping parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | | 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | @@ -712,11 +717,11 @@ Sub-indexes 1 and 2: * bit 0-7: data length in bits ### 0x1A03 - TPDO mapping parameter -| Object Type | Count Label | Storage Group | IO extension | PDO flags | -| ----------- | -------------- | -------------- | ------------- | ------------ | -| RECORD | | PERSIST_COMM | True | False | +| Object Type | Count Label | Storage Group | +| ----------- | -------------- | -------------- | +| RECORD | | PERSIST_COMM | -| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | +| Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Number of mapped application objects in PDO| UNSIGNED8 | rw | no | no | 0 | | 0x01 | Application object 1 | UNSIGNED32 | rw | no | no | 0x00000000 | diff --git a/example/DS301_profile.xpd b/example/DS301_profile.xpd index 99822ff0..4ecbdc54 100644 --- a/example/DS301_profile.xpd +++ b/example/DS301_profile.xpd @@ -1,5 +1,5 @@ - + @@ -15,7 +15,7 @@ CANopen - + @@ -659,7 +659,6 @@ * bit 16-31: Manufacturer specific additional information * bit 0-15: Error code as transmited in the Emergency object
- @@ -715,7 +714,6 @@ - Period of SYNC transmission in µs (0 = transmission disabled). @@ -723,14 +721,12 @@ - Synchronous window leghth in µs (0 = not used). All synchronous PDOs must be transmitted within this time window. - @@ -757,7 +753,6 @@ * bit 0: If set, CANopen device saves parameters on command * Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores corresponding data. - @@ -790,7 +785,6 @@ * bit 0: If set, CANopen device restores parameters * Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) restores corresponding data. - @@ -826,14 +820,12 @@ - - * bit 31: If set, EMCY does NOT exist / is NOT valid @@ -843,14 +835,12 @@ - Inhibit time of emergency message in multiples of 100µs. The value 0 disables the inhibit time. - Consumer Heartbeat Time: @@ -860,7 +850,6 @@ - @@ -913,7 +902,6 @@ - * Vendor-ID, assigned by CiA @@ -984,7 +972,6 @@ - @@ -997,7 +984,6 @@ - @@ -1027,7 +1013,6 @@ - @@ -1050,7 +1035,6 @@ - @@ -1093,7 +1077,6 @@ - @@ -1170,7 +1153,6 @@ * bit 0-10: 11-bit CAN-ID - @@ -1198,7 +1180,6 @@ - @@ -1230,7 +1211,6 @@ - @@ -1266,7 +1246,6 @@ - @@ -1302,7 +1281,6 @@ - @@ -1338,7 +1316,6 @@ - @@ -1374,7 +1351,6 @@ - @@ -1411,7 +1387,6 @@ - @@ -1444,7 +1419,6 @@ * bit 0-7: data length in bits - @@ -1502,7 +1476,6 @@ * bit 0-7: data length in bits - @@ -1560,7 +1533,6 @@ * bit 0-7: data length in bits - @@ -1618,7 +1590,6 @@ * bit 0-7: data length in bits - @@ -1677,7 +1648,6 @@ - @@ -1744,7 +1714,6 @@ - @@ -1796,7 +1765,6 @@ - @@ -1848,7 +1816,6 @@ - @@ -1900,7 +1867,6 @@ - @@ -1953,7 +1919,6 @@ - @@ -1996,7 +1961,6 @@ * bit 0-7: data length in bits - @@ -2054,7 +2018,6 @@ * bit 0-7: data length in bits - @@ -2112,7 +2075,6 @@ * bit 0-7: data length in bits - @@ -2170,7 +2132,6 @@ * bit 0-7: data length in bits - @@ -2229,7 +2190,6 @@ - @@ -2293,7 +2253,7 @@ CANopen - + @@ -2628,4 +2588,4 @@ - + \ No newline at end of file diff --git a/example/OD.c b/example/OD.c index 6997800d..246ef5be 100644 --- a/example/OD.c +++ b/example/OD.c @@ -2,7 +2,7 @@ CANopen Object Dictionary definition for CANopenNode V4 This file was automatically generated with - libedssharp Object Dictionary Editor v0.8-99-g0425f94 + libedssharp Object Dictionary Editor v0.8-116-g2e8a14a https://github.com/CANopenNode/CANopenNode https://github.com/robincornelius/libedssharp @@ -208,1121 +208,910 @@ OD_RAM_t OD_RAM = { }; -/******************************************************************************* - IO extensions and flagsPDO (configurable by application) -*******************************************************************************/ -typedef struct { - OD_extensionIO_t xio_1003_pre_definedErrorField; - OD_extensionIO_t xio_1005_COB_ID_SYNCMessage; - OD_extensionIO_t xio_1006_communicationCyclePeriod; - OD_extensionIO_t xio_1007_synchronousWindowLength; - OD_extensionIO_t xio_1010_storeParameters; - OD_extensionIO_t xio_1011_restoreDefaultParameters; - OD_extensionIO_t xio_1012_COB_IDTimeStampObject; - OD_extensionIO_t xio_1014_COB_ID_EMCY; - OD_extensionIO_t xio_1015_inhibitTimeEMCY; - OD_extensionIO_t xio_1016_consumerHeartbeatTime; - OD_extensionIO_t xio_1017_producerHeartbeatTime; - OD_extensionIO_t xio_1200_SDOServerParameter; - OD_extensionIO_t xio_1280_SDOClientParameter; - OD_extensionIO_t xio_1400_RPDOCommunicationParameter; - OD_extensionIO_t xio_1401_RPDOCommunicationParameter; - OD_extensionIO_t xio_1402_RPDOCommunicationParameter; - OD_extensionIO_t xio_1403_RPDOCommunicationParameter; - OD_extensionIO_t xio_1600_RPDOMappingParameter; - OD_extensionIO_t xio_1601_RPDOMappingParameter; - OD_extensionIO_t xio_1602_RPDOMappingParameter; - OD_extensionIO_t xio_1603_RPDOMappingParameter; - OD_extensionIO_t xio_1800_TPDOCommunicationParameter; - OD_extensionIO_t xio_1801_TPDOCommunicationParameter; - OD_extensionIO_t xio_1802_TPDOCommunicationParameter; - OD_extensionIO_t xio_1803_TPDOCommunicationParameter; - OD_extensionIO_t xio_1A00_TPDOMappingParameter; - OD_extensionIO_t xio_1A01_TPDOMappingParameter; - OD_extensionIO_t xio_1A02_TPDOMappingParameter; - OD_extensionIO_t xio_1A03_TPDOMappingParameter; -} ODExts_t; - -static ODExts_t ODExts = {0}; - /******************************************************************************* - All OD objects (const) + All OD objects (constant definitions) *******************************************************************************/ typedef struct { OD_obj_var_t o_1000_deviceType; OD_obj_var_t o_1001_errorRegister; OD_obj_array_t o_1003_pre_definedErrorField; - OD_obj_extended_t oE_1003_pre_definedErrorField; OD_obj_var_t o_1005_COB_ID_SYNCMessage; - OD_obj_extended_t oE_1005_COB_ID_SYNCMessage; OD_obj_var_t o_1006_communicationCyclePeriod; - OD_obj_extended_t oE_1006_communicationCyclePeriod; OD_obj_var_t o_1007_synchronousWindowLength; - OD_obj_extended_t oE_1007_synchronousWindowLength; OD_obj_array_t o_1010_storeParameters; - OD_obj_extended_t oE_1010_storeParameters; OD_obj_array_t o_1011_restoreDefaultParameters; - OD_obj_extended_t oE_1011_restoreDefaultParameters; OD_obj_var_t o_1012_COB_IDTimeStampObject; - OD_obj_extended_t oE_1012_COB_IDTimeStampObject; OD_obj_var_t o_1014_COB_ID_EMCY; - OD_obj_extended_t oE_1014_COB_ID_EMCY; OD_obj_var_t o_1015_inhibitTimeEMCY; - OD_obj_extended_t oE_1015_inhibitTimeEMCY; OD_obj_array_t o_1016_consumerHeartbeatTime; - OD_obj_extended_t oE_1016_consumerHeartbeatTime; OD_obj_var_t o_1017_producerHeartbeatTime; - OD_obj_extended_t oE_1017_producerHeartbeatTime; OD_obj_record_t o_1018_identity[5]; OD_obj_var_t o_1019_synchronousCounterOverflowValue; OD_obj_record_t o_1200_SDOServerParameter[3]; - OD_obj_extended_t oE_1200_SDOServerParameter; OD_obj_record_t o_1280_SDOClientParameter[4]; - OD_obj_extended_t oE_1280_SDOClientParameter; OD_obj_record_t o_1400_RPDOCommunicationParameter[4]; - OD_obj_extended_t oE_1400_RPDOCommunicationParameter; OD_obj_record_t o_1401_RPDOCommunicationParameter[4]; - OD_obj_extended_t oE_1401_RPDOCommunicationParameter; OD_obj_record_t o_1402_RPDOCommunicationParameter[4]; - OD_obj_extended_t oE_1402_RPDOCommunicationParameter; OD_obj_record_t o_1403_RPDOCommunicationParameter[4]; - OD_obj_extended_t oE_1403_RPDOCommunicationParameter; OD_obj_record_t o_1600_RPDOMappingParameter[9]; - OD_obj_extended_t oE_1600_RPDOMappingParameter; OD_obj_record_t o_1601_RPDOMappingParameter[9]; - OD_obj_extended_t oE_1601_RPDOMappingParameter; OD_obj_record_t o_1602_RPDOMappingParameter[9]; - OD_obj_extended_t oE_1602_RPDOMappingParameter; OD_obj_record_t o_1603_RPDOMappingParameter[9]; - OD_obj_extended_t oE_1603_RPDOMappingParameter; OD_obj_record_t o_1800_TPDOCommunicationParameter[6]; - OD_obj_extended_t oE_1800_TPDOCommunicationParameter; OD_obj_record_t o_1801_TPDOCommunicationParameter[6]; - OD_obj_extended_t oE_1801_TPDOCommunicationParameter; OD_obj_record_t o_1802_TPDOCommunicationParameter[6]; - OD_obj_extended_t oE_1802_TPDOCommunicationParameter; OD_obj_record_t o_1803_TPDOCommunicationParameter[6]; - OD_obj_extended_t oE_1803_TPDOCommunicationParameter; OD_obj_record_t o_1A00_TPDOMappingParameter[9]; - OD_obj_extended_t oE_1A00_TPDOMappingParameter; OD_obj_record_t o_1A01_TPDOMappingParameter[9]; - OD_obj_extended_t oE_1A01_TPDOMappingParameter; OD_obj_record_t o_1A02_TPDOMappingParameter[9]; - OD_obj_extended_t oE_1A02_TPDOMappingParameter; OD_obj_record_t o_1A03_TPDOMappingParameter[9]; - OD_obj_extended_t oE_1A03_TPDOMappingParameter; } ODObjs_t; -static const ODObjs_t ODObjs = { +static CO_PROGMEM ODObjs_t ODObjs = { .o_1000_deviceType = { - .data = &OD_PERSIST_COMM.x1000_deviceType, + .dataOrig = &OD_PERSIST_COMM.x1000_deviceType, .attribute = ODA_SDO_R | ODA_MB, .dataLength = 4 }, .o_1001_errorRegister = { - .data = &OD_RAM.x1001_errorRegister, + .dataOrig = &OD_RAM.x1001_errorRegister, .attribute = ODA_SDO_R | ODA_TRPDO, .dataLength = 1 }, .o_1003_pre_definedErrorField = { - .data0 = &OD_RAM.x1003_pre_definedErrorField_sub0, - .data = &OD_RAM.x1003_pre_definedErrorField[0], + .dataOrig0 = &OD_RAM.x1003_pre_definedErrorField_sub0, + .dataOrig = &OD_RAM.x1003_pre_definedErrorField[0], .attribute0 = ODA_SDO_RW, .attribute = ODA_SDO_R | ODA_MB, .dataElementLength = 4, .dataElementSizeof = sizeof(uint32_t) }, - .oE_1003_pre_definedErrorField = { - .extIO = &ODExts.xio_1003_pre_definedErrorField, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1003_pre_definedErrorField - }, .o_1005_COB_ID_SYNCMessage = { - .data = &OD_PERSIST_COMM.x1005_COB_ID_SYNCMessage, + .dataOrig = &OD_PERSIST_COMM.x1005_COB_ID_SYNCMessage, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, - .oE_1005_COB_ID_SYNCMessage = { - .extIO = &ODExts.xio_1005_COB_ID_SYNCMessage, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1005_COB_ID_SYNCMessage - }, .o_1006_communicationCyclePeriod = { - .data = &OD_PERSIST_COMM.x1006_communicationCyclePeriod, + .dataOrig = &OD_PERSIST_COMM.x1006_communicationCyclePeriod, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, - .oE_1006_communicationCyclePeriod = { - .extIO = &ODExts.xio_1006_communicationCyclePeriod, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1006_communicationCyclePeriod - }, .o_1007_synchronousWindowLength = { - .data = &OD_PERSIST_COMM.x1007_synchronousWindowLength, + .dataOrig = &OD_PERSIST_COMM.x1007_synchronousWindowLength, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, - .oE_1007_synchronousWindowLength = { - .extIO = &ODExts.xio_1007_synchronousWindowLength, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1007_synchronousWindowLength - }, .o_1010_storeParameters = { - .data0 = &OD_RAM.x1010_storeParameters_sub0, - .data = &OD_RAM.x1010_storeParameters[0], + .dataOrig0 = &OD_RAM.x1010_storeParameters_sub0, + .dataOrig = &OD_RAM.x1010_storeParameters[0], .attribute0 = ODA_SDO_R, .attribute = ODA_SDO_RW | ODA_MB, .dataElementLength = 4, .dataElementSizeof = sizeof(uint32_t) }, - .oE_1010_storeParameters = { - .extIO = &ODExts.xio_1010_storeParameters, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1010_storeParameters - }, .o_1011_restoreDefaultParameters = { - .data0 = &OD_RAM.x1011_restoreDefaultParameters_sub0, - .data = &OD_RAM.x1011_restoreDefaultParameters[0], + .dataOrig0 = &OD_RAM.x1011_restoreDefaultParameters_sub0, + .dataOrig = &OD_RAM.x1011_restoreDefaultParameters[0], .attribute0 = ODA_SDO_R, .attribute = ODA_SDO_RW | ODA_MB, .dataElementLength = 4, .dataElementSizeof = sizeof(uint32_t) }, - .oE_1011_restoreDefaultParameters = { - .extIO = &ODExts.xio_1011_restoreDefaultParameters, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1011_restoreDefaultParameters - }, .o_1012_COB_IDTimeStampObject = { - .data = &OD_PERSIST_COMM.x1012_COB_IDTimeStampObject, + .dataOrig = &OD_PERSIST_COMM.x1012_COB_IDTimeStampObject, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, - .oE_1012_COB_IDTimeStampObject = { - .extIO = &ODExts.xio_1012_COB_IDTimeStampObject, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1012_COB_IDTimeStampObject - }, .o_1014_COB_ID_EMCY = { - .data = &OD_PERSIST_COMM.x1014_COB_ID_EMCY, + .dataOrig = &OD_PERSIST_COMM.x1014_COB_ID_EMCY, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, - .oE_1014_COB_ID_EMCY = { - .extIO = &ODExts.xio_1014_COB_ID_EMCY, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1014_COB_ID_EMCY - }, .o_1015_inhibitTimeEMCY = { - .data = &OD_PERSIST_COMM.x1015_inhibitTimeEMCY, + .dataOrig = &OD_PERSIST_COMM.x1015_inhibitTimeEMCY, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, - .oE_1015_inhibitTimeEMCY = { - .extIO = &ODExts.xio_1015_inhibitTimeEMCY, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1015_inhibitTimeEMCY - }, .o_1016_consumerHeartbeatTime = { - .data0 = &OD_PERSIST_COMM.x1016_consumerHeartbeatTime_sub0, - .data = &OD_PERSIST_COMM.x1016_consumerHeartbeatTime[0], + .dataOrig0 = &OD_PERSIST_COMM.x1016_consumerHeartbeatTime_sub0, + .dataOrig = &OD_PERSIST_COMM.x1016_consumerHeartbeatTime[0], .attribute0 = ODA_SDO_R, .attribute = ODA_SDO_RW | ODA_MB, .dataElementLength = 4, .dataElementSizeof = sizeof(uint32_t) }, - .oE_1016_consumerHeartbeatTime = { - .extIO = &ODExts.xio_1016_consumerHeartbeatTime, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1016_consumerHeartbeatTime - }, .o_1017_producerHeartbeatTime = { - .data = &OD_PERSIST_COMM.x1017_producerHeartbeatTime, + .dataOrig = &OD_PERSIST_COMM.x1017_producerHeartbeatTime, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, - .oE_1017_producerHeartbeatTime = { - .extIO = &ODExts.xio_1017_producerHeartbeatTime, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1017_producerHeartbeatTime - }, .o_1018_identity = { { - .data = &OD_PERSIST_COMM.x1018_identity.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1018_identity.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1018_identity.vendor_ID, + .dataOrig = &OD_PERSIST_COMM.x1018_identity.vendor_ID, .subIndex = 1, .attribute = ODA_SDO_R | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1018_identity.productCode, + .dataOrig = &OD_PERSIST_COMM.x1018_identity.productCode, .subIndex = 2, .attribute = ODA_SDO_R | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1018_identity.revisionNumber, + .dataOrig = &OD_PERSIST_COMM.x1018_identity.revisionNumber, .subIndex = 3, .attribute = ODA_SDO_R | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1018_identity.serialNumber, + .dataOrig = &OD_PERSIST_COMM.x1018_identity.serialNumber, .subIndex = 4, .attribute = ODA_SDO_R | ODA_MB, .dataLength = 4 } }, .o_1019_synchronousCounterOverflowValue = { - .data = &OD_PERSIST_COMM.x1019_synchronousCounterOverflowValue, + .dataOrig = &OD_PERSIST_COMM.x1019_synchronousCounterOverflowValue, .attribute = ODA_SDO_RW, .dataLength = 1 }, .o_1200_SDOServerParameter = { { - .data = &OD_RAM.x1200_SDOServerParameter.highestSub_indexSupported, + .dataOrig = &OD_RAM.x1200_SDOServerParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_RAM.x1200_SDOServerParameter.COB_IDClientToServerRx, + .dataOrig = &OD_RAM.x1200_SDOServerParameter.COB_IDClientToServerRx, .subIndex = 1, .attribute = ODA_SDO_R | ODA_TPDO | ODA_MB, .dataLength = 4 }, { - .data = &OD_RAM.x1200_SDOServerParameter.COB_IDServerToClientTx, + .dataOrig = &OD_RAM.x1200_SDOServerParameter.COB_IDServerToClientTx, .subIndex = 2, .attribute = ODA_SDO_R | ODA_TPDO | ODA_MB, .dataLength = 4 } }, - .oE_1200_SDOServerParameter = { - .extIO = &ODExts.xio_1200_SDOServerParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1200_SDOServerParameter - }, .o_1280_SDOClientParameter = { { - .data = &OD_PERSIST_COMM.x1280_SDOClientParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1280_SDOClientParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1280_SDOClientParameter.COB_IDClientToServerTx, + .dataOrig = &OD_PERSIST_COMM.x1280_SDOClientParameter.COB_IDClientToServerTx, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_TRPDO | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1280_SDOClientParameter.COB_IDServerToClientRx, + .dataOrig = &OD_PERSIST_COMM.x1280_SDOClientParameter.COB_IDServerToClientRx, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_TRPDO | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1280_SDOClientParameter.node_IDOfTheSDOServer, + .dataOrig = &OD_PERSIST_COMM.x1280_SDOClientParameter.node_IDOfTheSDOServer, .subIndex = 3, .attribute = ODA_SDO_RW, .dataLength = 1 } }, - .oE_1280_SDOClientParameter = { - .extIO = &ODExts.xio_1280_SDOClientParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1280_SDOClientParameter - }, .o_1400_RPDOCommunicationParameter = { { - .data = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.COB_IDUsedByRPDO, + .dataOrig = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.COB_IDUsedByRPDO, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.transmissionType, + .dataOrig = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.transmissionType, .subIndex = 2, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.eventTimer, + .dataOrig = &OD_PERSIST_COMM.x1400_RPDOCommunicationParameter.eventTimer, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 } }, - .oE_1400_RPDOCommunicationParameter = { - .extIO = &ODExts.xio_1400_RPDOCommunicationParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1400_RPDOCommunicationParameter - }, .o_1401_RPDOCommunicationParameter = { { - .data = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.COB_IDUsedByRPDO, + .dataOrig = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.COB_IDUsedByRPDO, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.transmissionType, + .dataOrig = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.transmissionType, .subIndex = 2, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.eventTimer, + .dataOrig = &OD_PERSIST_COMM.x1401_RPDOCommunicationParameter.eventTimer, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 } }, - .oE_1401_RPDOCommunicationParameter = { - .extIO = &ODExts.xio_1401_RPDOCommunicationParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1401_RPDOCommunicationParameter - }, .o_1402_RPDOCommunicationParameter = { { - .data = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.COB_IDUsedByRPDO, + .dataOrig = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.COB_IDUsedByRPDO, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.transmissionType, + .dataOrig = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.transmissionType, .subIndex = 2, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.eventTimer, + .dataOrig = &OD_PERSIST_COMM.x1402_RPDOCommunicationParameter.eventTimer, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 } }, - .oE_1402_RPDOCommunicationParameter = { - .extIO = &ODExts.xio_1402_RPDOCommunicationParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1402_RPDOCommunicationParameter - }, .o_1403_RPDOCommunicationParameter = { { - .data = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.COB_IDUsedByRPDO, + .dataOrig = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.COB_IDUsedByRPDO, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.transmissionType, + .dataOrig = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.transmissionType, .subIndex = 2, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.eventTimer, + .dataOrig = &OD_PERSIST_COMM.x1403_RPDOCommunicationParameter.eventTimer, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 } }, - .oE_1403_RPDOCommunicationParameter = { - .extIO = &ODExts.xio_1403_RPDOCommunicationParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1403_RPDOCommunicationParameter - }, .o_1600_RPDOMappingParameter = { { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, .subIndex = 0, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 } }, - .oE_1600_RPDOMappingParameter = { - .extIO = &ODExts.xio_1600_RPDOMappingParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1600_RPDOMappingParameter - }, .o_1601_RPDOMappingParameter = { { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, .subIndex = 0, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 } }, - .oE_1601_RPDOMappingParameter = { - .extIO = &ODExts.xio_1601_RPDOMappingParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1601_RPDOMappingParameter - }, .o_1602_RPDOMappingParameter = { { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, .subIndex = 0, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 } }, - .oE_1602_RPDOMappingParameter = { - .extIO = &ODExts.xio_1602_RPDOMappingParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1602_RPDOMappingParameter - }, .o_1603_RPDOMappingParameter = { { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, .subIndex = 0, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 } }, - .oE_1603_RPDOMappingParameter = { - .extIO = &ODExts.xio_1603_RPDOMappingParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1603_RPDOMappingParameter - }, .o_1800_TPDOCommunicationParameter = { { - .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.COB_IDUsedByTPDO, + .dataOrig = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.COB_IDUsedByTPDO, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.transmissionType, + .dataOrig = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.transmissionType, .subIndex = 2, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.inhibitTime, + .dataOrig = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.inhibitTime, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, { - .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.eventTimer, + .dataOrig = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.eventTimer, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, { - .data = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.SYNCStartValue, + .dataOrig = &OD_PERSIST_COMM.x1800_TPDOCommunicationParameter.SYNCStartValue, .subIndex = 6, .attribute = ODA_SDO_RW, .dataLength = 1 } }, - .oE_1800_TPDOCommunicationParameter = { - .extIO = &ODExts.xio_1800_TPDOCommunicationParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1800_TPDOCommunicationParameter - }, .o_1801_TPDOCommunicationParameter = { { - .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.COB_IDUsedByTPDO, + .dataOrig = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.COB_IDUsedByTPDO, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.transmissionType, + .dataOrig = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.transmissionType, .subIndex = 2, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.inhibitTime, + .dataOrig = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.inhibitTime, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, { - .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.eventTimer, + .dataOrig = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.eventTimer, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, { - .data = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.SYNCStartValue, + .dataOrig = &OD_PERSIST_COMM.x1801_TPDOCommunicationParameter.SYNCStartValue, .subIndex = 6, .attribute = ODA_SDO_RW, .dataLength = 1 } }, - .oE_1801_TPDOCommunicationParameter = { - .extIO = &ODExts.xio_1801_TPDOCommunicationParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1801_TPDOCommunicationParameter - }, .o_1802_TPDOCommunicationParameter = { { - .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.COB_IDUsedByTPDO, + .dataOrig = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.COB_IDUsedByTPDO, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.transmissionType, + .dataOrig = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.transmissionType, .subIndex = 2, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.inhibitTime, + .dataOrig = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.inhibitTime, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, { - .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.eventTimer, + .dataOrig = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.eventTimer, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, { - .data = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.SYNCStartValue, + .dataOrig = &OD_PERSIST_COMM.x1802_TPDOCommunicationParameter.SYNCStartValue, .subIndex = 6, .attribute = ODA_SDO_RW, .dataLength = 1 } }, - .oE_1802_TPDOCommunicationParameter = { - .extIO = &ODExts.xio_1802_TPDOCommunicationParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1802_TPDOCommunicationParameter - }, .o_1803_TPDOCommunicationParameter = { { - .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.highestSub_indexSupported, + .dataOrig = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.highestSub_indexSupported, .subIndex = 0, .attribute = ODA_SDO_R, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.COB_IDUsedByTPDO, + .dataOrig = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.COB_IDUsedByTPDO, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.transmissionType, + .dataOrig = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.transmissionType, .subIndex = 2, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.inhibitTime, + .dataOrig = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.inhibitTime, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, { - .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.eventTimer, + .dataOrig = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.eventTimer, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 2 }, { - .data = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.SYNCStartValue, + .dataOrig = &OD_PERSIST_COMM.x1803_TPDOCommunicationParameter.SYNCStartValue, .subIndex = 6, .attribute = ODA_SDO_RW, .dataLength = 1 } }, - .oE_1803_TPDOCommunicationParameter = { - .extIO = &ODExts.xio_1803_TPDOCommunicationParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1803_TPDOCommunicationParameter - }, .o_1A00_TPDOMappingParameter = { { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, .subIndex = 0, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 } }, - .oE_1A00_TPDOMappingParameter = { - .extIO = &ODExts.xio_1A00_TPDOMappingParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1A00_TPDOMappingParameter - }, .o_1A01_TPDOMappingParameter = { { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, .subIndex = 0, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 } }, - .oE_1A01_TPDOMappingParameter = { - .extIO = &ODExts.xio_1A01_TPDOMappingParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1A01_TPDOMappingParameter - }, .o_1A02_TPDOMappingParameter = { { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, .subIndex = 0, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 } }, - .oE_1A02_TPDOMappingParameter = { - .extIO = &ODExts.xio_1A02_TPDOMappingParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1A02_TPDOMappingParameter - }, .o_1A03_TPDOMappingParameter = { { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.numberOfMappedApplicationObjectsInPDO, .subIndex = 0, .attribute = ODA_SDO_RW, .dataLength = 1 }, { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .data = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 } - }, - .oE_1A03_TPDOMappingParameter = { - .extIO = &ODExts.xio_1A03_TPDOMappingParameter, - .flagsPDO = NULL, - .odObjectOriginal = &ODObjs.o_1A03_TPDOMappingParameter } }; @@ -1330,44 +1119,46 @@ static const ODObjs_t ODObjs = { /******************************************************************************* Object dictionary *******************************************************************************/ -static const OD_entry_t ODList[] = { - {0x1000, 0x01, ODT_VAR, &ODObjs.o_1000_deviceType}, - {0x1001, 0x01, ODT_VAR, &ODObjs.o_1001_errorRegister}, - {0x1003, 0x09, ODT_EARR, &ODObjs.oE_1003_pre_definedErrorField}, - {0x1005, 0x01, ODT_EVAR, &ODObjs.oE_1005_COB_ID_SYNCMessage}, - {0x1006, 0x01, ODT_EVAR, &ODObjs.oE_1006_communicationCyclePeriod}, - {0x1007, 0x01, ODT_EVAR, &ODObjs.oE_1007_synchronousWindowLength}, - {0x1010, 0x05, ODT_EARR, &ODObjs.oE_1010_storeParameters}, - {0x1011, 0x05, ODT_EARR, &ODObjs.oE_1011_restoreDefaultParameters}, - {0x1012, 0x01, ODT_EVAR, &ODObjs.oE_1012_COB_IDTimeStampObject}, - {0x1014, 0x01, ODT_EVAR, &ODObjs.oE_1014_COB_ID_EMCY}, - {0x1015, 0x01, ODT_EVAR, &ODObjs.oE_1015_inhibitTimeEMCY}, - {0x1016, 0x09, ODT_EARR, &ODObjs.oE_1016_consumerHeartbeatTime}, - {0x1017, 0x01, ODT_EVAR, &ODObjs.oE_1017_producerHeartbeatTime}, - {0x1018, 0x05, ODT_REC, &ODObjs.o_1018_identity}, - {0x1019, 0x01, ODT_VAR, &ODObjs.o_1019_synchronousCounterOverflowValue}, - {0x1200, 0x03, ODT_EREC, &ODObjs.oE_1200_SDOServerParameter}, - {0x1280, 0x04, ODT_EREC, &ODObjs.oE_1280_SDOClientParameter}, - {0x1400, 0x04, ODT_EREC, &ODObjs.oE_1400_RPDOCommunicationParameter}, - {0x1401, 0x04, ODT_EREC, &ODObjs.oE_1401_RPDOCommunicationParameter}, - {0x1402, 0x04, ODT_EREC, &ODObjs.oE_1402_RPDOCommunicationParameter}, - {0x1403, 0x04, ODT_EREC, &ODObjs.oE_1403_RPDOCommunicationParameter}, - {0x1600, 0x09, ODT_EREC, &ODObjs.oE_1600_RPDOMappingParameter}, - {0x1601, 0x09, ODT_EREC, &ODObjs.oE_1601_RPDOMappingParameter}, - {0x1602, 0x09, ODT_EREC, &ODObjs.oE_1602_RPDOMappingParameter}, - {0x1603, 0x09, ODT_EREC, &ODObjs.oE_1603_RPDOMappingParameter}, - {0x1800, 0x06, ODT_EREC, &ODObjs.oE_1800_TPDOCommunicationParameter}, - {0x1801, 0x06, ODT_EREC, &ODObjs.oE_1801_TPDOCommunicationParameter}, - {0x1802, 0x06, ODT_EREC, &ODObjs.oE_1802_TPDOCommunicationParameter}, - {0x1803, 0x06, ODT_EREC, &ODObjs.oE_1803_TPDOCommunicationParameter}, - {0x1A00, 0x09, ODT_EREC, &ODObjs.oE_1A00_TPDOMappingParameter}, - {0x1A01, 0x09, ODT_EREC, &ODObjs.oE_1A01_TPDOMappingParameter}, - {0x1A02, 0x09, ODT_EREC, &ODObjs.oE_1A02_TPDOMappingParameter}, - {0x1A03, 0x09, ODT_EREC, &ODObjs.oE_1A03_TPDOMappingParameter}, - {0x0000, 0x00, 0, NULL} +static OD_entry_t ODList[] = { + {0x1000, 0x01, ODT_VAR, &ODObjs.o_1000_deviceType, NULL}, + {0x1001, 0x01, ODT_VAR, &ODObjs.o_1001_errorRegister, NULL}, + {0x1003, 0x09, ODT_ARR, &ODObjs.o_1003_pre_definedErrorField, NULL}, + {0x1005, 0x01, ODT_VAR, &ODObjs.o_1005_COB_ID_SYNCMessage, NULL}, + {0x1006, 0x01, ODT_VAR, &ODObjs.o_1006_communicationCyclePeriod, NULL}, + {0x1007, 0x01, ODT_VAR, &ODObjs.o_1007_synchronousWindowLength, NULL}, + {0x1010, 0x05, ODT_ARR, &ODObjs.o_1010_storeParameters, NULL}, + {0x1011, 0x05, ODT_ARR, &ODObjs.o_1011_restoreDefaultParameters, NULL}, + {0x1012, 0x01, ODT_VAR, &ODObjs.o_1012_COB_IDTimeStampObject, NULL}, + {0x1014, 0x01, ODT_VAR, &ODObjs.o_1014_COB_ID_EMCY, NULL}, + {0x1015, 0x01, ODT_VAR, &ODObjs.o_1015_inhibitTimeEMCY, NULL}, + {0x1016, 0x09, ODT_ARR, &ODObjs.o_1016_consumerHeartbeatTime, NULL}, + {0x1017, 0x01, ODT_VAR, &ODObjs.o_1017_producerHeartbeatTime, NULL}, + {0x1018, 0x05, ODT_REC, &ODObjs.o_1018_identity, NULL}, + {0x1019, 0x01, ODT_VAR, &ODObjs.o_1019_synchronousCounterOverflowValue, NULL}, + {0x1200, 0x03, ODT_REC, &ODObjs.o_1200_SDOServerParameter, NULL}, + {0x1280, 0x04, ODT_REC, &ODObjs.o_1280_SDOClientParameter, NULL}, + {0x1400, 0x04, ODT_REC, &ODObjs.o_1400_RPDOCommunicationParameter, NULL}, + {0x1401, 0x04, ODT_REC, &ODObjs.o_1401_RPDOCommunicationParameter, NULL}, + {0x1402, 0x04, ODT_REC, &ODObjs.o_1402_RPDOCommunicationParameter, NULL}, + {0x1403, 0x04, ODT_REC, &ODObjs.o_1403_RPDOCommunicationParameter, NULL}, + {0x1600, 0x09, ODT_REC, &ODObjs.o_1600_RPDOMappingParameter, NULL}, + {0x1601, 0x09, ODT_REC, &ODObjs.o_1601_RPDOMappingParameter, NULL}, + {0x1602, 0x09, ODT_REC, &ODObjs.o_1602_RPDOMappingParameter, NULL}, + {0x1603, 0x09, ODT_REC, &ODObjs.o_1603_RPDOMappingParameter, NULL}, + {0x1800, 0x06, ODT_REC, &ODObjs.o_1800_TPDOCommunicationParameter, NULL}, + {0x1801, 0x06, ODT_REC, &ODObjs.o_1801_TPDOCommunicationParameter, NULL}, + {0x1802, 0x06, ODT_REC, &ODObjs.o_1802_TPDOCommunicationParameter, NULL}, + {0x1803, 0x06, ODT_REC, &ODObjs.o_1803_TPDOCommunicationParameter, NULL}, + {0x1A00, 0x09, ODT_REC, &ODObjs.o_1A00_TPDOMappingParameter, NULL}, + {0x1A01, 0x09, ODT_REC, &ODObjs.o_1A01_TPDOMappingParameter, NULL}, + {0x1A02, 0x09, ODT_REC, &ODObjs.o_1A02_TPDOMappingParameter, NULL}, + {0x1A03, 0x09, ODT_REC, &ODObjs.o_1A03_TPDOMappingParameter, NULL}, + {0x0000, 0x00, 0, NULL, NULL} }; -const OD_t OD = { +static OD_t _OD = { (sizeof(ODList) / sizeof(ODList[0])) - 1, &ODList[0] }; + +OD_t *OD = &_OD; diff --git a/example/OD.h b/example/OD.h index 40e31ece..7bcb955f 100644 --- a/example/OD.h +++ b/example/OD.h @@ -2,7 +2,7 @@ CANopen Object Dictionary definition for CANopenNode V4 This file was automatically generated with - libedssharp Object Dictionary Editor v0.8-99-g0425f94 + libedssharp Object Dictionary Editor v0.8-116-g2e8a14a https://github.com/CANopenNode/CANopenNode https://github.com/robincornelius/libedssharp @@ -16,17 +16,17 @@ File Version: 1 Created: 23. 11. 2020 12:00:00 - Created By: - Modified: 24. 11. 2020 13:31:53 - Modified By: + Created By: + Modified: 6. 01. 2021 16:21:52 + Modified By: Device Info: - Vendor Name: - Vendor ID: + Vendor Name: + Vendor ID: Product Name: New Product - Product ID: + Product ID: - Description: + Description: *******************************************************************************/ #ifndef OD_H @@ -36,16 +36,16 @@ *******************************************************************************/ #define OD_CNT_NMT 1 #define OD_CNT_EM 1 -//#define OD_CNT_SYNC 1 -//#define OD_CNT_SYNC_PROD 1 -//#define OD_CNT_TIME 1 +#define OD_CNT_SYNC 1 +#define OD_CNT_SYNC_PROD 1 +#define OD_CNT_TIME 1 #define OD_CNT_EM_PROD 1 -//#define OD_CNT_HB_CONS 1 +#define OD_CNT_HB_CONS 1 #define OD_CNT_HB_PROD 1 #define OD_CNT_SDO_SRV 1 #define OD_CNT_SDO_CLI 1 -//#define OD_CNT_RPDO 4 -//#define OD_CNT_TPDO 4 +#define OD_CNT_RPDO 4 +#define OD_CNT_TPDO 4 /******************************************************************************* @@ -239,82 +239,82 @@ typedef struct { extern OD_PERSIST_COMM_t OD_PERSIST_COMM; extern OD_RAM_t OD_RAM; -extern const OD_t OD; +extern OD_t *OD; /******************************************************************************* Object dictionary entries - shortcuts *******************************************************************************/ -#define OD_ENTRY_H1000 &OD.list[0] -#define OD_ENTRY_H1001 &OD.list[1] -#define OD_ENTRY_H1003 &OD.list[2] -#define OD_ENTRY_H1005 &OD.list[3] -#define OD_ENTRY_H1006 &OD.list[4] -#define OD_ENTRY_H1007 &OD.list[5] -#define OD_ENTRY_H1010 &OD.list[6] -#define OD_ENTRY_H1011 &OD.list[7] -#define OD_ENTRY_H1012 &OD.list[8] -#define OD_ENTRY_H1014 &OD.list[9] -#define OD_ENTRY_H1015 &OD.list[10] -#define OD_ENTRY_H1016 &OD.list[11] -#define OD_ENTRY_H1017 &OD.list[12] -#define OD_ENTRY_H1018 &OD.list[13] -#define OD_ENTRY_H1019 &OD.list[14] -#define OD_ENTRY_H1200 &OD.list[15] -#define OD_ENTRY_H1280 &OD.list[16] -#define OD_ENTRY_H1400 &OD.list[17] -#define OD_ENTRY_H1401 &OD.list[18] -#define OD_ENTRY_H1402 &OD.list[19] -#define OD_ENTRY_H1403 &OD.list[20] -#define OD_ENTRY_H1600 &OD.list[21] -#define OD_ENTRY_H1601 &OD.list[22] -#define OD_ENTRY_H1602 &OD.list[23] -#define OD_ENTRY_H1603 &OD.list[24] -#define OD_ENTRY_H1800 &OD.list[25] -#define OD_ENTRY_H1801 &OD.list[26] -#define OD_ENTRY_H1802 &OD.list[27] -#define OD_ENTRY_H1803 &OD.list[28] -#define OD_ENTRY_H1A00 &OD.list[29] -#define OD_ENTRY_H1A01 &OD.list[30] -#define OD_ENTRY_H1A02 &OD.list[31] -#define OD_ENTRY_H1A03 &OD.list[32] +#define OD_ENTRY_H1000 &OD->list[0] +#define OD_ENTRY_H1001 &OD->list[1] +#define OD_ENTRY_H1003 &OD->list[2] +#define OD_ENTRY_H1005 &OD->list[3] +#define OD_ENTRY_H1006 &OD->list[4] +#define OD_ENTRY_H1007 &OD->list[5] +#define OD_ENTRY_H1010 &OD->list[6] +#define OD_ENTRY_H1011 &OD->list[7] +#define OD_ENTRY_H1012 &OD->list[8] +#define OD_ENTRY_H1014 &OD->list[9] +#define OD_ENTRY_H1015 &OD->list[10] +#define OD_ENTRY_H1016 &OD->list[11] +#define OD_ENTRY_H1017 &OD->list[12] +#define OD_ENTRY_H1018 &OD->list[13] +#define OD_ENTRY_H1019 &OD->list[14] +#define OD_ENTRY_H1200 &OD->list[15] +#define OD_ENTRY_H1280 &OD->list[16] +#define OD_ENTRY_H1400 &OD->list[17] +#define OD_ENTRY_H1401 &OD->list[18] +#define OD_ENTRY_H1402 &OD->list[19] +#define OD_ENTRY_H1403 &OD->list[20] +#define OD_ENTRY_H1600 &OD->list[21] +#define OD_ENTRY_H1601 &OD->list[22] +#define OD_ENTRY_H1602 &OD->list[23] +#define OD_ENTRY_H1603 &OD->list[24] +#define OD_ENTRY_H1800 &OD->list[25] +#define OD_ENTRY_H1801 &OD->list[26] +#define OD_ENTRY_H1802 &OD->list[27] +#define OD_ENTRY_H1803 &OD->list[28] +#define OD_ENTRY_H1A00 &OD->list[29] +#define OD_ENTRY_H1A01 &OD->list[30] +#define OD_ENTRY_H1A02 &OD->list[31] +#define OD_ENTRY_H1A03 &OD->list[32] /******************************************************************************* Object dictionary entries - shortcuts with names *******************************************************************************/ -#define OD_ENTRY_H1000_deviceType &OD.list[0] -#define OD_ENTRY_H1001_errorRegister &OD.list[1] -#define OD_ENTRY_H1003_pre_definedErrorField &OD.list[2] -#define OD_ENTRY_H1005_COB_ID_SYNCMessage &OD.list[3] -#define OD_ENTRY_H1006_communicationCyclePeriod &OD.list[4] -#define OD_ENTRY_H1007_synchronousWindowLength &OD.list[5] -#define OD_ENTRY_H1010_storeParameters &OD.list[6] -#define OD_ENTRY_H1011_restoreDefaultParameters &OD.list[7] -#define OD_ENTRY_H1012_COB_IDTimeStampObject &OD.list[8] -#define OD_ENTRY_H1014_COB_ID_EMCY &OD.list[9] -#define OD_ENTRY_H1015_inhibitTimeEMCY &OD.list[10] -#define OD_ENTRY_H1016_consumerHeartbeatTime &OD.list[11] -#define OD_ENTRY_H1017_producerHeartbeatTime &OD.list[12] -#define OD_ENTRY_H1018_identity &OD.list[13] -#define OD_ENTRY_H1019_synchronousCounterOverflowValue &OD.list[14] -#define OD_ENTRY_H1200_SDOServerParameter &OD.list[15] -#define OD_ENTRY_H1280_SDOClientParameter &OD.list[16] -#define OD_ENTRY_H1400_RPDOCommunicationParameter &OD.list[17] -#define OD_ENTRY_H1401_RPDOCommunicationParameter &OD.list[18] -#define OD_ENTRY_H1402_RPDOCommunicationParameter &OD.list[19] -#define OD_ENTRY_H1403_RPDOCommunicationParameter &OD.list[20] -#define OD_ENTRY_H1600_RPDOMappingParameter &OD.list[21] -#define OD_ENTRY_H1601_RPDOMappingParameter &OD.list[22] -#define OD_ENTRY_H1602_RPDOMappingParameter &OD.list[23] -#define OD_ENTRY_H1603_RPDOMappingParameter &OD.list[24] -#define OD_ENTRY_H1800_TPDOCommunicationParameter &OD.list[25] -#define OD_ENTRY_H1801_TPDOCommunicationParameter &OD.list[26] -#define OD_ENTRY_H1802_TPDOCommunicationParameter &OD.list[27] -#define OD_ENTRY_H1803_TPDOCommunicationParameter &OD.list[28] -#define OD_ENTRY_H1A00_TPDOMappingParameter &OD.list[29] -#define OD_ENTRY_H1A01_TPDOMappingParameter &OD.list[30] -#define OD_ENTRY_H1A02_TPDOMappingParameter &OD.list[31] -#define OD_ENTRY_H1A03_TPDOMappingParameter &OD.list[32] +#define OD_ENTRY_H1000_deviceType &OD->list[0] +#define OD_ENTRY_H1001_errorRegister &OD->list[1] +#define OD_ENTRY_H1003_pre_definedErrorField &OD->list[2] +#define OD_ENTRY_H1005_COB_ID_SYNCMessage &OD->list[3] +#define OD_ENTRY_H1006_communicationCyclePeriod &OD->list[4] +#define OD_ENTRY_H1007_synchronousWindowLength &OD->list[5] +#define OD_ENTRY_H1010_storeParameters &OD->list[6] +#define OD_ENTRY_H1011_restoreDefaultParameters &OD->list[7] +#define OD_ENTRY_H1012_COB_IDTimeStampObject &OD->list[8] +#define OD_ENTRY_H1014_COB_ID_EMCY &OD->list[9] +#define OD_ENTRY_H1015_inhibitTimeEMCY &OD->list[10] +#define OD_ENTRY_H1016_consumerHeartbeatTime &OD->list[11] +#define OD_ENTRY_H1017_producerHeartbeatTime &OD->list[12] +#define OD_ENTRY_H1018_identity &OD->list[13] +#define OD_ENTRY_H1019_synchronousCounterOverflowValue &OD->list[14] +#define OD_ENTRY_H1200_SDOServerParameter &OD->list[15] +#define OD_ENTRY_H1280_SDOClientParameter &OD->list[16] +#define OD_ENTRY_H1400_RPDOCommunicationParameter &OD->list[17] +#define OD_ENTRY_H1401_RPDOCommunicationParameter &OD->list[18] +#define OD_ENTRY_H1402_RPDOCommunicationParameter &OD->list[19] +#define OD_ENTRY_H1403_RPDOCommunicationParameter &OD->list[20] +#define OD_ENTRY_H1600_RPDOMappingParameter &OD->list[21] +#define OD_ENTRY_H1601_RPDOMappingParameter &OD->list[22] +#define OD_ENTRY_H1602_RPDOMappingParameter &OD->list[23] +#define OD_ENTRY_H1603_RPDOMappingParameter &OD->list[24] +#define OD_ENTRY_H1800_TPDOCommunicationParameter &OD->list[25] +#define OD_ENTRY_H1801_TPDOCommunicationParameter &OD->list[26] +#define OD_ENTRY_H1802_TPDOCommunicationParameter &OD->list[27] +#define OD_ENTRY_H1803_TPDOCommunicationParameter &OD->list[28] +#define OD_ENTRY_H1A00_TPDOMappingParameter &OD->list[29] +#define OD_ENTRY_H1A01_TPDOMappingParameter &OD->list[30] +#define OD_ENTRY_H1A02_TPDOMappingParameter &OD->list[31] +#define OD_ENTRY_H1A03_TPDOMappingParameter &OD->list[32] #endif /* OD_H */ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 709b13df..9037296b 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -514,7 +514,7 @@ int main (int argc, char *argv[]) { err = CO_CANopenInit(CO, /* CANopen object */ NULL, /* alternate NMT */ NULL, /* alternate em */ - &OD, /* Object dictionary */ + OD, /* Object dictionary */ OD_STATUS_BITS, /* Optional OD_statusBits */ NMT_CONTROL, /* CO_NMT_control_t */ FIRST_HB_TIME, /* firstHBTime_ms */ From 04ca686fd891771c7984300334e46e47a44539e5 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 7 Jan 2021 08:36:45 +0100 Subject: [PATCH 147/520] OD_interface, getter and setter helper functions simplified, #162 --- 301/CO_Emergency.c | 25 +-- 301/CO_ODinterface.c | 424 +++---------------------------------------- 301/CO_ODinterface.h | 204 ++++++++++----------- Makefile | 15 +- 4 files changed, 145 insertions(+), 523 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 9a41afca..33447e10 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -391,7 +391,12 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, memset(em, 0, sizeof(CO_EM_t)); /* get and verify "Error register" from Object Dictionary */ - if (OD_getPtr_u8(OD_1001_errReg, 0, &em->errorRegister) != ODR_OK) { + OD_size_t len; + ODR_t odRet; + + odRet = OD_getPtr(OD_1001_errReg, 0, (void **)&em->errorRegister, &len); + + if (odRet != ODR_OK || len != sizeof(uint8_t)) { CO_errinfo(CANdevTx, OD_getIndex(OD_1001_errReg)); return CO_ERROR_OD_PARAMETERS; } @@ -400,8 +405,8 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER /* get initial and verify "COB-ID EMCY" from Object Dictionary */ uint32_t COB_IDEmergency32; - ODR_t odRet0 = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); - if (odRet0 != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { + odRet = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); + if (odRet != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; } @@ -414,9 +419,8 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1014_extension.object = em; em->OD_1014_extension.read = OD_read_1014; em->OD_1014_extension.write = OD_write_1014; - ODR_t odRetE = OD_extension_init(OD_1014_cobIdEm, - &em->OD_1014_extension); - if (odRetE != ODR_OK) { + odRet = OD_extension_init(OD_1014_cobIdEm, &em->OD_1014_extension); + if (odRet != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; } @@ -434,9 +438,8 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1014_extension.object = em; em->OD_1014_extension.read = OD_read_1014_default; em->OD_1014_extension.write = OD_writeOriginal; - ODR_t odRetE = OD_extension_init(OD_1014_cobIdEm, - &em->OD_1014_extension); - if (odRetE != ODR_OK) { + odRet = OD_extension_init(OD_1014_cobIdEm, &em->OD_1014_extension); + if (odRet != ODR_OK) { CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); return CO_ERROR_OD_PARAMETERS; } @@ -463,8 +466,8 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->inhibitEmTime_us = 0; em->inhibitEmTimer = 0; uint16_t inhibitTime_100us; - ODR_t odRet1 = OD_get_u16(OD_1015_InhTime, 0, &inhibitTime_100us, true); - if (odRet1 == ODR_OK) { + odRet = OD_get_u16(OD_1015_InhTime, 0, &inhibitTime_100us, true); + if (odRet == ODR_OK) { em->inhibitEmTime_us = (uint32_t)inhibitTime_100us * 100; em->OD_1015_extension.object = em; diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 3ac5508e..982d19fb 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -314,428 +314,58 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { /******************************************************************************/ -ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, - int8_t *val, bool_t odOrig) +ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, + void *val, OD_size_t len, bool_t odOrig) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, - int16_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, - int32_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, - int64_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, - uint8_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, - uint16_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, - uint32_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, - uint64_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_r32(const OD_entry_t *entry, uint8_t subIndex, - float32_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, - float64_t *val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(*val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.read(&io.stream, subIndex, val, sizeof(*val), &ret); - return ret; -} - -/******************************************************************************/ -ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, - int8_t val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} - -ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, - int16_t val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} - -ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, - int32_t val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} - -ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, - int64_t val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} - -ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, - uint8_t val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} + if (val == NULL) return ODR_DEV_INCOMPAT; -ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, - uint16_t val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} - -ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, - uint32_t val, bool_t odOrig) -{ + ODR_t ret; OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} + OD_stream_t *stream = (OD_stream_t *)&io; -ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, - uint64_t val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); + ret = OD_getSub(entry, subIndex, &io, odOrig); - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} + if (ret != ODR_OK) return ret; + if (stream->dataLength != len) return ODR_TYPE_MISMATCH; -ODR_t OD_set_r32(const OD_entry_t *entry, uint8_t subIndex, - float32_t val, bool_t odOrig) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); + io.read(stream, subIndex, val, len, &ret); - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); return ret; } -ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, - float64_t val, bool_t odOrig) +ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, + OD_size_t len, bool_t odOrig) { + ODR_t ret; OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); + OD_stream_t *stream = &io.stream; - if (ret == ODR_OK && io.stream.dataLength != sizeof(val)) - ret = ODR_TYPE_MISMATCH; - if (ret == ODR_OK) io.write(&io.stream, subIndex, &val, sizeof(val), &ret); - return ret; -} - -/******************************************************************************/ -ODR_t OD_getPtr_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t **val) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (int8_t *)io.stream.dataOrig; - return ret; -} + ret = OD_getSub(entry, subIndex, &io, odOrig); -ODR_t OD_getPtr_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t **val) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (int16_t *)io.stream.dataOrig; - return ret; -} + if (ret != ODR_OK) return ret; + if (stream->dataLength != len) return ODR_TYPE_MISMATCH; -ODR_t OD_getPtr_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t **val) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (int32_t *)io.stream.dataOrig; - return ret; -} + io.write(stream, subIndex, val, len, &ret); -ODR_t OD_getPtr_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t **val) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (int64_t *)io.stream.dataOrig; return ret; } -ODR_t OD_getPtr_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t **val) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (uint8_t *)io.stream.dataOrig; - return ret; -} - -ODR_t OD_getPtr_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t **val) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (uint16_t *)io.stream.dataOrig; - return ret; -} - -ODR_t OD_getPtr_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t **val) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (uint32_t *)io.stream.dataOrig; - return ret; -} - -ODR_t OD_getPtr_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t **val) { - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (uint64_t *)io.stream.dataOrig; - return ret; -} - -ODR_t OD_getPtr_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t **val){ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (float32_t *)io.stream.dataOrig; - return ret; -} - -ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val){ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); - - if (val == NULL || io.stream.dataOrig == NULL) - ret = ODR_DEV_INCOMPAT; - else if (ret == ODR_OK && io.stream.dataLength != sizeof(**val)) - ret = ODR_TYPE_MISMATCH; - else if (ret == ODR_OK) - *val = (float64_t *)io.stream.dataOrig; - return ret; -} - -ODR_t OD_getPtr_vs(const OD_entry_t *entry, uint8_t subIndex, - char **val, OD_size_t *dataLength) +ODR_t OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, void **val, + OD_size_t *len) { + ODR_t ret; OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); + OD_stream_t *stream = &io.stream; - if (val == NULL || io.stream.dataOrig == NULL - || io.stream.dataLength == 0) - { - ret = ODR_DEV_INCOMPAT; - } - else if (ret == ODR_OK) { - *val = (char *)io.stream.dataOrig; - if (dataLength != NULL) *dataLength = io.stream.dataLength; - } - return ret; -} + ret = OD_getSub(entry, subIndex, &io, true); -ODR_t OD_getPtr_os(const OD_entry_t *entry, uint8_t subIndex, - uint8_t **val, OD_size_t *dataLength) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); + if (ret != ODR_OK) return ret; + if (val == NULL || stream->dataOrig == NULL || stream->dataLength == 0) + return ODR_DEV_INCOMPAT; - if (val == NULL || io.stream.dataOrig == NULL - || io.stream.dataLength == 0) - { - ret = ODR_DEV_INCOMPAT; - } - else if (ret == ODR_OK) { - *val = (uint8_t *)io.stream.dataOrig; - if (dataLength != NULL) *dataLength = io.stream.dataLength; - } - return ret; -} + *val = stream->dataOrig; -ODR_t OD_getPtr_us(const OD_entry_t *entry, uint8_t subIndex, - uint16_t **val, OD_size_t *dataLength) -{ - OD_IO_t io; - ODR_t ret = OD_getSub(entry, subIndex, &io, true); + if (len != NULL) *len = stream->dataLength; - if (val == NULL || io.stream.dataOrig == NULL - || io.stream.dataLength == 0) - { - ret = ODR_DEV_INCOMPAT; - } - else if (ret == ODR_OK) { - *val = (uint16_t *)io.stream.dataOrig; - if (dataLength != NULL) *dataLength = io.stream.dataLength; - } return ret; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 4b25a08f..6f88fdac 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -502,11 +502,12 @@ static inline ODR_t OD_extension_init(OD_entry_t *entry, * Dictionary variables. */ /** - * Get int8_t variable from Object Dictionary + * Get variable from Object Dictionary * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. * @param [out] val Value will be written here. + * @param len Size of value to retrieve from OD. * @param odOrig If true, then potential IO extension on entry will be * ignored and data in the original OD location will be returned. * @@ -514,42 +515,56 @@ static inline ODR_t OD_extension_init(OD_entry_t *entry, * variable does not exist in object dictionary or it does not have the correct * length or other reason. */ -ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, - int8_t *val, bool_t odOrig); -/** Get int16_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, - int16_t *val, bool_t odOrig); -/** Get int32_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, - int32_t *val, bool_t odOrig); -/** Get int64_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, - int64_t *val, bool_t odOrig); -/** Get uint8_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, - uint8_t *val, bool_t odOrig); -/** Get uint16_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, - uint16_t *val, bool_t odOrig); -/** Get uint32_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, - uint32_t *val, bool_t odOrig); -/** Get uint64_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, - uint64_t *val, bool_t odOrig); -/** Get float32_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_r32(const OD_entry_t *entry, uint8_t subIndex, - float32_t *val, bool_t odOrig); -/** Get float64_t variable from Object Dictionary, see @ref OD_get_i8 */ -ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, - float64_t *val, bool_t odOrig); +ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, + void *val, OD_size_t len, bool_t odOrig); + +/** Get int8_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_i8(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(int8_t), (odOrig)) + +/** Get int16_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_i16(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(int16_t), (odOrig)) + +/** Get int32_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_i32(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(int32_t), (odOrig)) + +/** Get int64_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_i64(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(int64_t), (odOrig)) + +/** Get uint8_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_u8(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(uint8_t), (odOrig)) + +/** Get uint16_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_u16(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(uint16_t), (odOrig)) + +/** Get uint32_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_u32(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(uint32_t), (odOrig)) + +/** Get uint64_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_u64(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(uint64_t), (odOrig)) + +/** Get float32_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_f32(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(float32_t), (odOrig)) + +/** Get float64_t variable from Object Dictionary, see @ref OD_get_value */ +#define OD_get_f64(entry, subIndex, val, odOrig) \ + OD_get_value((entry), (subIndex), (val), sizeof(float64_t), (odOrig)) /** - * Set int8_t variable in Object Dictionary + * Set variable in Object Dictionary * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. - * @param val Value to write. + * @param val Pointer to value to write. + * @param len Size of value to write. * @param odOrig If true, then potential IO extension on entry will be * ignored and data in the original OD location will be written. * @@ -557,95 +572,66 @@ ODR_t OD_get_r64(const OD_entry_t *entry, uint8_t subIndex, * variable does not exist in object dictionary or it does not have the correct * length or other reason. */ -ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, - int8_t val, bool_t odOrig); -/** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, - int16_t val, bool_t odOrig); -/** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, - int32_t val, bool_t odOrig); -/** Set int16_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, - int64_t val, bool_t odOrig); -/** Set uint8_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, - uint8_t val, bool_t odOrig); -/** Set uint16_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, - uint16_t val, bool_t odOrig); -/** Set uint32_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, - uint32_t val, bool_t odOrig); -/** Set uint64_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, - uint64_t val, bool_t odOrig); -/** Set float32_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_r32(const OD_entry_t *entry, uint8_t subIndex, - float32_t val, bool_t odOrig); -/** Set float64_t variable in Object Dictionary, see @ref OD_set_i8 */ -ODR_t OD_set_r64(const OD_entry_t *entry, uint8_t subIndex, - float64_t val, bool_t odOrig); +ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, + OD_size_t len, bool_t odOrig); + +/** Set int8_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_i8(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(int8_t), (odOrig)) + +/** Set int16_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_i16(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(int16_t), (odOrig)) + +/** Set int32_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_i32(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(int32_t), (odOrig)) + +/** Set int32_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_i64(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(int64_t), (odOrig)) + +/** Set uint8_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_u8(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(uint8_t), (odOrig)) + +/** Set uint16_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_u16(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(uint16_t), (odOrig)) + +/** Set uint32_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_u32(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(uint32_t), (odOrig)) + +/** Set uint64_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_u64(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(uint64_t), (odOrig)) + +/** Set float32_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_f32(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(float32_t), (odOrig)) + +/** Set float64_t variable in Object Dictionary, see @ref OD_set_value */ +#define OD_set_f64(entry, subIndex, val, odOrig) \ + OD_set_value((entry), (subIndex), &(val), sizeof(float64_t), (odOrig)) /** - * Get pointer to int8_t variable from Object Dictionary - * - * Function always returns "dataOrig" pointer, which points to data - * in the original OD location. Take care, if IO extension is enabled on OD - * entry. - * - * @param entry OD entry returned by @ref OD_find(). - * @param subIndex Sub-index of the variable from the OD object. - * @param [out] val Pointer to variable will be written here. - * - * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if - * variable does not exist in object dictionary or it does not have the correct - * length or other reason. - */ -ODR_t OD_getPtr_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t **val); -/** Get pointer to int16_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t **val); -/** Get pointer to int32_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t **val); -/** Get pointer to int64_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t **val); -/** Get pointer to uint8_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t **val); -/** Get pointer to uint16_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t **val); -/** Get pointer to uint32_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t **val); -/** Get pointer to uint64_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t **val); -/** Get pointer to float32_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_r32(const OD_entry_t *entry, uint8_t subIndex, float32_t **val); -/** Get pointer to float64_t variable from OD, see @ref OD_getPtr_i8 */ -ODR_t OD_getPtr_r64(const OD_entry_t *entry, uint8_t subIndex, float64_t **val); -/** - * Get pointer to "visible string" variable from Object Dictionary + * Get pointer to memory which holds data variable from Object Dictionary * * Function always returns "dataOrig" pointer, which points to data * in the original OD location. Take care, if IO extension is enabled on OD - * entry. + * entry. Take also care that "dataOrig" could be not aligned to data type. * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. * @param [out] val Pointer to variable will be written here. - * @param [out] dataLength Total variable length will be written here, may be - * NULL. + * @param [out] len Variable length will be written here. (allow NULL) * * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if - * variable does not exist in object dictionary or it has zero length or other - * reason. + * variable does not exist in object dictionary or other reason. */ -ODR_t OD_getPtr_vs(const OD_entry_t *entry, uint8_t subIndex, - char **val, OD_size_t *dataLength); -/** Get pointer to "octet string" variable from OD, see @ref OD_getPtr_vs */ -ODR_t OD_getPtr_os(const OD_entry_t *entry, uint8_t subIndex, - uint8_t **val, OD_size_t *dataLength); -/** Get pointer to "unicode string" variable from OD, see @ref OD_getPtr_vs */ -ODR_t OD_getPtr_us(const OD_entry_t *entry, uint8_t subIndex, - uint16_t **val, OD_size_t *dataLength); +ODR_t OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, void **val, + OD_size_t *len); /** @} */ /* CO_ODgetSetters */ diff --git a/Makefile b/Makefile index 497adfaa..0e5be8c5 100644 --- a/Makefile +++ b/Makefile @@ -45,14 +45,17 @@ SOURCES = \ OBJS = $(SOURCES:%.c=%.o) CC ?= gcc -OPT = -g -DCO_SINGLE_THREAD -#OPT = -g -DCO_SINGLE_THREAD -DCO_CONFIG_DEBUG=0xFFFF -#OPT = -g -pedantic -Wshadow -fanalyzer -#OPT = -g -DCO_USE_GLOBALS -#OPT = -g -DCO_MULTIPLE_OD +OPT = +OPT += -DCO_SINGLE_THREAD +OPT += -g +#OPT += -DCO_CONFIG_DEBUG=0xFFFF +#OPT += -Wextra -Wshadow -pedantic -fanalyzer +#OPT += -DCO_USE_GLOBALS +#OPT += -DCO_MULTIPLE_OD CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = -#LDFLAGS = -pthread +#LDFLAGS += -g +#LDFLAGS += -pthread #Options can be also passed via make: 'make OPT="-g" LDFLAGS="-pthread"' From 5538b5e1f887ee4d4cbe5d78961c07acc521920a Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 20 Jan 2021 12:49:20 +0100 Subject: [PATCH 148/520] Remove CO_errinfo() from driver and put errInfo into CO_CANopenInit() as arg --- 301/CO_Emergency.c | 11 ++++++----- 301/CO_Emergency.h | 4 +++- 301/CO_NMT_Heartbeat.c | 7 ++++--- 301/CO_NMT_Heartbeat.h | 4 +++- 301/CO_SDOclient.c | 7 ++++--- 301/CO_SDOclient.h | 4 +++- 301/CO_SDOserver.c | 7 ++++--- 301/CO_SDOserver.h | 4 +++- 301/CO_driver.h | 19 ------------------- CANopen.c | 15 ++++++++++----- CANopen.h | 4 +++- example/CO_driver_target.h | 1 - socketCAN/CO_driver_target.h | 1 - socketCAN/CO_main_basic.c | 14 ++++++++------ 14 files changed, 51 insertions(+), 51 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 33447e10..49704ab4 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -366,7 +366,8 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, #endif - const uint8_t nodeId) + const uint8_t nodeId, + uint32_t *errInfo) { (void) nodeId; /* may be unused */ CO_ReturnError_t ret = CO_ERROR_NO; @@ -397,7 +398,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, odRet = OD_getPtr(OD_1001_errReg, 0, (void **)&em->errorRegister, &len); if (odRet != ODR_OK || len != sizeof(uint8_t)) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1001_errReg)); + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1001_errReg); return CO_ERROR_OD_PARAMETERS; } *em->errorRegister = 0; @@ -407,7 +408,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint32_t COB_IDEmergency32; odRet = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); if (odRet != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1014_cobIdEm); return CO_ERROR_OD_PARAMETERS; } @@ -421,7 +422,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1014_extension.write = OD_write_1014; odRet = OD_extension_init(OD_1014_cobIdEm, &em->OD_1014_extension); if (odRet != ODR_OK) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1014_cobIdEm); return CO_ERROR_OD_PARAMETERS; } /* following two variables are used inside OD_read_1014 and OD_write_1014 */ @@ -440,7 +441,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1014_extension.write = OD_writeOriginal; odRet = OD_extension_init(OD_1014_cobIdEm, &em->OD_1014_extension); if (odRet != ODR_OK) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1014_cobIdEm)); + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1014_cobIdEm); return CO_ERROR_OD_PARAMETERS; } #endif diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 8fdce32c..aa256558 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -478,6 +478,7 @@ typedef struct { * @param CANdevRx CAN device for Emergency consumer reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param nodeId CANopen node ID of this device (for default emergency producer) + * @param [out] errInfo Additional information in case of error, may be NULL. * * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ @@ -501,7 +502,8 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, #endif - const uint8_t nodeId); + const uint8_t nodeId, + uint32_t *errInfo); #if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 9d69f5ca..86a2d113 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -98,7 +98,8 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, #endif CO_CANmodule_t *HB_CANdevTx, uint16_t HB_txIdx, - uint16_t CANidTxHB) + uint16_t CANidTxHB, + uint32_t *errInfo) { CO_ReturnError_t ret = CO_ERROR_NO; @@ -127,7 +128,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, uint16_t HBprodTime_ms; ODR_t odRet = OD_get_u16(OD_1017_ProducerHbTime, 0, &HBprodTime_ms, true); if (odRet != ODR_OK) { - CO_errinfo(NMT_CANdevRx, OD_getIndex(OD_1017_ProducerHbTime)); + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1017_ProducerHbTime); return CO_ERROR_OD_PARAMETERS; } NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000; @@ -138,7 +139,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, odRet = OD_extension_init(OD_1017_ProducerHbTime, &NMT->OD_1017_extension); if (odRet != ODR_OK) { - CO_errinfo(HB_CANdevTx, OD_getIndex(OD_1017_ProducerHbTime)); + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1017_ProducerHbTime); return CO_ERROR_OD_PARAMETERS; } diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 3414d0dd..605caa50 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -227,6 +227,7 @@ typedef struct { * @param HB_CANdevTx CAN device for HB transmission. * @param HB_txIdx Index of transmit buffer in the above CAN device. * @param CANidTxHB CAN identifier for HB message. + * @param [out] errInfo Additional information in case of error, may be NULL. * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ @@ -246,7 +247,8 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, #endif CO_CANmodule_t *HB_CANdevTx, uint16_t HB_txIdx, - uint16_t CANidTxHB); + uint16_t CANidTxHB, + uint32_t *errInfo); #if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 5376392a..291c7f37 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -255,7 +255,8 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx) + uint16_t CANdevTxIdx, + uint32_t *errInfo) { /* verify arguments */ if (SDO_C == NULL || OD_1280_SDOcliPar == NULL @@ -295,7 +296,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, if (odRet0 != ODR_OK || maxSubIndex != 3 || odRet1 != ODR_OK || odRet2 != ODR_OK || odRet3 != ODR_OK ) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1280_SDOcliPar)); + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1280_SDOcliPar); return CO_ERROR_OD_PARAMETERS; } @@ -306,7 +307,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, ODR_t odRetE = OD_extension_init(OD_1280_SDOcliPar, &SDO_C->OD_1280_extension); if (odRetE != ODR_OK) { - CO_errinfo(CANdevTx, OD_getIndex(OD_1280_SDOcliPar)); + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1280_SDOcliPar); return CO_ERROR_OD_PARAMETERS; } diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 6beed563..f84c0440 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -173,6 +173,7 @@ typedef struct { * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for SDO client transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. + * @param [out] errInfo Additional information in case of error, may be NULL. * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ @@ -183,7 +184,8 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx); + uint16_t CANdevTxIdx, + uint32_t *errInfo); #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index e674d0f1..e4bafa5c 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -322,7 +322,8 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx) + uint16_t CANdevTxIdx, + uint32_t *errInfo) { /* verify arguments */ if (SDO == NULL || OD == NULL || CANdevRx == NULL || CANdevTx == NULL) { @@ -383,7 +384,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (odRet0 != ODR_OK || (maxSubIndex != 2 && maxSubIndex != 3) || odRet1 != ODR_OK || odRet2 != ODR_OK ) { - CO_errinfo(CANdevTx, OD_SDOsrvParIdx); + if (errInfo != NULL) *errInfo = OD_SDOsrvParIdx; return CO_ERROR_OD_PARAMETERS; } @@ -400,7 +401,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, ODR_t odRetE = OD_extension_init(OD_1200_SDOsrvPar, &SDO->OD_1200_extension); if (odRetE != ODR_OK) { - CO_errinfo(CANdevTx, OD_SDOsrvParIdx); + if (errInfo != NULL) *errInfo = OD_SDOsrvParIdx; return CO_ERROR_OD_PARAMETERS; } #endif diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 2e54a3b3..76d8bcbd 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -542,6 +542,7 @@ typedef struct { * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for SDO server transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. + * @param [out] errInfo Additional information in case of error, may be NULL. * * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ @@ -553,7 +554,8 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx); + uint16_t CANdevTxIdx, + uint32_t *errInfo); #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN diff --git a/301/CO_driver.h b/301/CO_driver.h index 12555f6e..98da8d1c 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -331,7 +331,6 @@ typedef struct { volatile uint16_t CANtxCount; /**< Number of messages in transmit buffer, which are waiting to be copied to the CAN module */ uint32_t errOld; /**< Previous state of CAN errors */ - int32_t errinfo; /**< For use with @ref CO_errinfo() */ } CO_CANmodule_t; @@ -401,24 +400,6 @@ typedef struct { #endif /* CO_DOXYGEN */ -/** Macro for passing additional information about error. - * - * This macro is called from several CANopen init functions, which returns - * @ref CO_ReturnError_t. - * - * CO_driver_target.h may implement this macro. Usually macro only sets - * CANmodule->errinfo to err. Application may then use CANmodule->errinfo to - * determine the reason of failure. errinfo must be type of int32_t. By default - * macro does not record anything. - * - * CO_errinfo is called in following @ref CO_ReturnError_t reasons: - * - 'CO_ERROR_OD_PARAMETERS' - Index of erroneous OD parameter. - */ -#ifndef CO_errinfo -#define CO_errinfo(CANmodule, err) CANmodule->errinfo = err -#endif - - /** * Default CANopen identifiers. * diff --git a/CANopen.c b/CANopen.c index dc1f36bd..2c14a524 100644 --- a/CANopen.c +++ b/CANopen.c @@ -913,7 +913,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, uint16_t SDOserverTimeoutTime_ms, uint16_t SDOclientTimeoutTime_ms, bool_t SDOclientBlockTransfer, - uint8_t nodeId) + uint8_t nodeId, + uint32_t *errInfo) { CO_ReturnError_t err; @@ -978,7 +979,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(RX_IDX_EM_CONS), #endif - nodeId); + nodeId, + errInfo); if (err) return err; } @@ -1000,7 +1002,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif co->CANmodule, CO_GET_CO(TX_IDX_HB_PROD), - CO_CAN_ID_HEARTBEAT + nodeId); + CO_CAN_ID_HEARTBEAT + nodeId, + errInfo); if (err) return err; } @@ -1030,7 +1033,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(RX_IDX_SDO_SRV) + i, co->CANmodule, - CO_GET_CO(TX_IDX_SDO_SRV) + i); + CO_GET_CO(TX_IDX_SDO_SRV) + i, + errInfo); if (err) return err; } } @@ -1046,7 +1050,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(RX_IDX_SDO_CLI) + i, co->CANmodule, - CO_GET_CO(TX_IDX_SDO_CLI) + i); + CO_GET_CO(TX_IDX_SDO_CLI) + i, + errInfo); if (err) return err; } } diff --git a/CANopen.h b/CANopen.h index 7576ce7d..093628ae 100644 --- a/CANopen.h +++ b/CANopen.h @@ -528,6 +528,7 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, * CANopen initialization it is the same as pendingBitRate from CO_LSSinit(). * If it is unconfigured, then some CANopen objects will not be initialized nor * processed. + * @param [out] errInfo Additional information in case of error, may be NULL. * * @return CO_ERROR_NO in case of success. */ @@ -541,7 +542,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, uint16_t SDOserverTimeoutTime_ms, uint16_t SDOclientTimeoutTime_ms, bool_t SDOclientBlockTransfer, - uint8_t nodeId); + uint8_t nodeId, + uint32_t *errInfo); /** diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index d6e22f82..d31025f9 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -226,7 +226,6 @@ typedef struct { volatile bool_t firstCANtxMessage; volatile uint16_t CANtxCount; uint32_t errOld; - int32_t errinfo; } CO_CANmodule_t; diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 6ccd7ef7..deacd2ff 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -348,7 +348,6 @@ typedef struct { CO_CANtx_t *txArray; uint16_t txSize; uint16_t CANerrorStatus; - int32_t errinfo; volatile bool_t CANnormal; int epoll_fd; /* File descriptor for epoll, which waits for CAN receive event */ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 9037296b..5a5cbc74 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -471,6 +471,7 @@ int main (int argc, char *argv[]) { while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { + uint32_t errInfo; /* CANopen communication reset - initialize CANopen objects *******************/ /* Wait rt_thread. */ @@ -510,6 +511,7 @@ int main (int argc, char *argv[]) { } CO_activeNodeId = CO_pendingNodeId; + errInfo = 0; err = CO_CANopenInit(CO, /* CANopen object */ NULL, /* alternate NMT */ @@ -521,11 +523,11 @@ int main (int argc, char *argv[]) { SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */ SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */ SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ - CO_activeNodeId); + CO_activeNodeId, + &errInfo); if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { if (err == CO_ERROR_OD_PARAMETERS) { - log_printf(LOG_CRIT, DBG_OD_ENTRY, - (uint16_t)CO->CANmodule->errinfo); + log_printf(LOG_CRIT, DBG_OD_ENTRY, errInfo); } else { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); @@ -602,11 +604,11 @@ int main (int argc, char *argv[]) { #endif #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - uint16_t errinfo = 0; - err = app_programStart(!CO->nodeIdUnconfigured, &errinfo); + errInfo = 0; + err = app_programStart(!CO->nodeIdUnconfigured, &errInfo); if(err != CO_ERROR_NO) { if (err == CO_ERROR_OD_PARAMETERS) { - log_printf(LOG_CRIT, DBG_OD_ENTRY, errinfo); + log_printf(LOG_CRIT, DBG_OD_ENTRY, errInfo); } else { log_printf(LOG_CRIT, DBG_CAN_OPEN, "app_programStart()", err); From 9dce037ecb0fceeb2bb46aba3e5bb49edc64a6bb Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 25 Jan 2021 12:42:10 +0100 Subject: [PATCH 149/520] Add data storage, common and Linux specific functions, tested in Linux. --- .gitignore | 3 +- 301/CO_Emergency.c | 9 +- 301/CO_Emergency.h | 4 +- 301/CO_NMT_Heartbeat.c | 3 +- 301/CO_ODinterface.h | 4 +- 301/CO_config.h | 18 ++ 301/CO_storage.c | 214 ++++++++++++++++++++ 301/CO_storage.h | 175 ++++++++++++++++ CANopen.c | 46 ++++- CANopen.h | 46 +---- Doxyfile | 31 +-- Makefile | 3 +- README.md | 5 +- doc/deviceSupport.md | 1 + doc/gettingStarted.md | 22 ++- doc/objectDictionary.md | 2 +- example/DS301_profile.eds | 4 +- example/DS301_profile.md | 6 +- example/DS301_profile.xpd | 7 +- example/OD.c | 2 +- example/OD.h | 5 +- socketCAN/CO_OD_storage.c | 373 ----------------------------------- socketCAN/CO_OD_storage.h | 171 ---------------- socketCAN/CO_driver_target.h | 1 - socketCAN/CO_main_basic.c | 250 ++++++++++++++--------- socketCAN/CO_storageLinux.c | 321 ++++++++++++++++++++++++++++++ socketCAN/CO_storageLinux.h | 135 +++++++++++++ 27 files changed, 1133 insertions(+), 728 deletions(-) create mode 100644 301/CO_storage.c create mode 100644 301/CO_storage.h delete mode 100644 socketCAN/CO_OD_storage.c delete mode 100644 socketCAN/CO_OD_storage.h create mode 100644 socketCAN/CO_storageLinux.c create mode 100644 socketCAN/CO_storageLinux.h diff --git a/.gitignore b/.gitignore index 4c60d24c..96202779 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ /example/canopennode_blank /canopend *.o -/od_storage* +*.persist +*.persist.old doc/html/ diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 49704ab4..8958108f 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -474,8 +474,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1015_extension.object = em; em->OD_1015_extension.read = OD_readOriginal; em->OD_1015_extension.write = OD_write_1015; - OD_extension_init(OD_1015_InhTime, - &em->OD_1015_extension); + OD_extension_init(OD_1015_InhTime, &em->OD_1015_extension); } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ @@ -486,8 +485,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1003_extension.object = em; em->OD_1003_extension.read = OD_read_1003; em->OD_1003_extension.write = OD_write_1003; - OD_extension_init(OD_1003_preDefErr, - &em->OD_1003_extension); + OD_extension_init(OD_1003_preDefErr, &em->OD_1003_extension); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ @@ -496,8 +494,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_statusBits_extension.object = em; em->OD_statusBits_extension.read = OD_read_statusBits; em->OD_statusBits_extension.write = OD_write_statusBits; - OD_extension_init(OD_statusBits, - &em->OD_statusBits_extension); + OD_extension_init(OD_statusBits, &em->OD_statusBits_extension); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index aa256558..c59df371 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -330,8 +330,8 @@ typedef enum { CO_EM_25_unused = 0x25U, /** 0x26, generic, info, (unused) */ CO_EM_26_unused = 0x26U, - /** 0x27, generic, info, (unused) */ - CO_EM_27_unused = 0x27U, + /** 0x27, generic, info, Automatic store to non-volatile memory failed */ + CO_EM_NON_VOLATILE_AUTO_SAVE = 0x27U, /** 0x28, generic, critical, Wrong parameters to CO_errorReport() function*/ CO_EM_WRONG_ERROR_REPORT = 0x28U, diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 86a2d113..0cdbece4 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -136,8 +136,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, NMT->OD_1017_extension.object = NMT; NMT->OD_1017_extension.read = OD_readOriginal; NMT->OD_1017_extension.write = OD_write_1017; - odRet = OD_extension_init(OD_1017_ProducerHbTime, - &NMT->OD_1017_extension); + odRet = OD_extension_init(OD_1017_ProducerHbTime, &NMT->OD_1017_extension); if (odRet != ODR_OK) { if (errInfo != NULL) *errInfo = OD_getIndex(OD_1017_ProducerHbTime); return CO_ERROR_OD_PARAMETERS; diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 6f88fdac..f228aa5e 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -75,8 +75,8 @@ typedef enum { OD_H100D_LIFETIME_FACTOR = 0x100DU,/**< Life time factor */ OD_H100E_RSV = 0x100EU,/**< Reserved */ OD_H100F_RSV = 0x100FU,/**< Reserved */ - OD_H1010_STORE_PARAM_FUNC = 0x1010U,/**< Store params in persistent mem.*/ - OD_H1011_REST_PARAM_FUNC = 0x1011U,/**< Restore default parameters */ + OD_H1010_STORE_PARAMETERS = 0x1010U,/**< Store params in persistent mem.*/ + OD_H1011_RESTORE_DEFAULT = 0x1011U,/**< Restore default parameters */ OD_H1012_COBID_TIME = 0x1012U,/**< Timestamp message cob-id */ OD_H1013_HIGH_RES_TIMESTAMP = 0x1013U,/**< High resolution timestamp */ OD_H1014_COBID_EMERGENCY = 0x1014U,/**< Emergency message cob-id */ diff --git a/301/CO_config.h b/301/CO_config.h index 1b82de1c..701be253 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -460,6 +460,24 @@ extern "C" { /** @} */ /* CO_STACK_CONFIG_SYNC_PDO */ +/** + * @defgroup CO_STACK_CONFIG_STORAGE Data storage + * Data storage with CANopen OD objects 1010 and 1011 + * @{ + */ +/** + * Configuration of @ref CO_storage + * + * Possible flags, can be ORed: + * - CO_CONFIG_STORAGE_ENABLE - Enable data storage + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_STORAGE (CO_CONFIG_STORAGE_ENABLE) +#endif +#define CO_CONFIG_STORAGE_ENABLE 0x01 +/** @} */ /* CO_STACK_CONFIG_STORAGE */ + + /** * @defgroup CO_STACK_CONFIG_LEDS CANopen LED diodes * Specified in standard CiA 303-3 diff --git a/301/CO_storage.c b/301/CO_storage.c new file mode 100644 index 00000000..ca92bb61 --- /dev/null +++ b/301/CO_storage.c @@ -0,0 +1,214 @@ +/* + * CANopen data storage object + * + * @file CO_storage.c + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "301/CO_storage.h" + +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + +/* + * Custom function for writing OD object "Store parameters" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + /* verify arguments */ + if (stream == NULL || subIndex == 0 || buf == NULL || count != 4 + || returnCode == NULL + ) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + if (subIndex == 0) { + *returnCode = ODR_READONLY; + return 0; + } + + if (CO_getUint32(buf) != 0x65766173) { + *returnCode = ODR_DATA_TRANSF; + return 0; + } + + CO_storage_t *storage = stream->object; + CO_storage_entry_t *entry = storage->firstEntry; + bool_t found = false; + *returnCode = ODR_OK; + + /* call pre-configured function matching subIndex or call all functions */ + while (entry != NULL) { + if (entry->store != NULL + && (entry->subIndexOD == subIndex + || (storage->sub1_all && subIndex == 1)) + ) { + ODR_t code = entry->store(entry->object, entry->addr, entry->len); + found = true; + + if (code != ODR_OK) *returnCode = code; + if (!(storage->sub1_all && subIndex == 1)) { + break; + } + } + entry = entry->nextEntry; + } + + if (!found) *returnCode = ODR_SUB_NOT_EXIST; + + return *returnCode == ODR_OK ? 4 : 0; +} + + +/* + * Custom function for writing OD object "Restore default parameters" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + /* verify arguments */ + if (stream == NULL || subIndex == 0 || buf == NULL || count != 4 + || returnCode == NULL + ) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + if (subIndex == 0) { + *returnCode = ODR_READONLY; + return 0; + } + + if (CO_getUint32(buf) != 0x64616F6C) { + *returnCode = ODR_DATA_TRANSF; + return 0; + } + + CO_storage_t *storage = stream->object; + CO_storage_entry_t *entry = storage->firstEntry; + bool_t found = false; + *returnCode = ODR_OK; + + /* call pre-configured function matching subIndex or call all functions */ + while (entry != NULL) { + if (entry->restore != NULL + && (entry->subIndexOD == subIndex + || (storage->sub1_all && subIndex == 1)) + ) { + ODR_t code = entry->restore(entry->object, entry->addr, entry->len); + found = true; + + if (code != ODR_OK) *returnCode = code; + if (!(storage->sub1_all && subIndex == 1)) { + break; + } + } + entry = entry->nextEntry; + } + + if (!found) *returnCode = ODR_SUB_NOT_EXIST; + + return *returnCode == ODR_OK ? 4 : 0; +} + + +CO_ReturnError_t CO_storage_init(CO_storage_t *storage, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParameters, + bool_t sub1_all, + uint32_t *errInfo) +{ + ODR_t odRet; + + /* verify arguments */ + if (storage == NULL || OD_1010_StoreParameters == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* object was pre-initialised by CO_storage_pre_init() */ + + storage->sub1_all = sub1_all; + + /* configure extensions */ + storage->OD_1010_extension.object = storage; + storage->OD_1010_extension.read = OD_readOriginal; + storage->OD_1010_extension.write = OD_write_1010; + odRet = OD_extension_init(OD_1010_StoreParameters, + &storage->OD_1010_extension); + if (odRet != ODR_OK) { + if (errInfo != NULL) + *errInfo = OD_getIndex(OD_1010_StoreParameters); + return CO_ERROR_OD_PARAMETERS; + } + + if (OD_1011_RestoreDefaultParameters != NULL) { + storage->OD_1011_extension.object = storage; + storage->OD_1011_extension.read = OD_readOriginal; + storage->OD_1011_extension.write = OD_write_1011; + odRet = OD_extension_init(OD_1011_RestoreDefaultParameters, + &storage->OD_1011_extension); + if (odRet != ODR_OK) { + if (errInfo != NULL) + *errInfo = OD_getIndex(OD_1011_RestoreDefaultParameters); + return CO_ERROR_OD_PARAMETERS; + } + } + + return CO_ERROR_NO; +} + + +CO_ReturnError_t CO_storage_entry_init(CO_storage_t *storage, + CO_storage_entry_t *newEntry) { + /* verify arguments */ + if (storage == NULL || newEntry == NULL || newEntry->addr == NULL + || newEntry->len == 0 || newEntry->subIndexOD == 0 + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + CO_storage_entry_t **entry = &storage->firstEntry; + + /* Add newEntry on the end of linked list or replace existing entry */ + for ( ; ; ) { + if (*entry == NULL) { + newEntry->nextEntry = NULL; + *entry = newEntry; + break; + } + if ((*entry)->subIndexOD == newEntry->subIndexOD) { + newEntry->nextEntry = (*entry)->nextEntry; + *entry = newEntry; + break; + } + *entry = (*entry)->nextEntry; + }; + + return CO_ERROR_NO; +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/301/CO_storage.h b/301/CO_storage.h new file mode 100644 index 00000000..ac7eba85 --- /dev/null +++ b/301/CO_storage.h @@ -0,0 +1,175 @@ +/** + * CANopen data storage object + * + * @file CO_storage.h + * @ingroup CO_storage + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CO_STORAGE_H +#define CO_STORAGE_H + +#include "301/CO_driver.h" +#include "301/CO_ODinterface.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_STORAGE +#define CO_CONFIG_STORAGE (CO_CONFIG_STORAGE_ENABLE) +#endif + +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_storage Data storage + * @ingroup CO_CANopen_301 + * @{ + * + * CANopen data storage - connection to Object Dictionary + */ + + +/** + * Data storage object for one entry. + * + * Object is defined by application and registered with + * @ref CO_storage_entry_init() function. + */ +typedef struct { + /** Address of data to store */ + void *addr; + /** Length of data to store */ + OD_size_t len; + /** Object defined by application, passed to store and restore functions. */ + void *object; + /** Sub index in OD objects 1010 and 1011, from 2 to 254. Writing + * 0x65766173 to 1010,subIndexOD will store data to non-volatile memory. + * Writing 0x64616F6C to 1011,subIndexOD will restore default data. */ + uint8_t subIndexOD; + /** + * Pointer to externally defined function, which will store data from addr. + * + * @param object object from above. + * @param addr Address form above. + * @param len Length from above. + * + * @return Value from @ref ODR_t, "ODR_OK" in case of success, "ODR_HW" in + * case of error in hardware. + */ + ODR_t (*store)(void *object, void *addr, OD_size_t len); + /** + * Pointer to externally defined function, which will restore data to addr. + * + * For description of arguments see above. + */ + ODR_t (*restore)(void *object, void *addr, OD_size_t len); + /** Pointer to next entry, initialized inside @ref CO_storage_entry_init() + * function. */ + void *nextEntry; +} CO_storage_entry_t; + + +/** + * Data storage object. + * + * Object is used with CANopen OD objects at index 1010 and 1011. + */ +typedef struct { + /** Extension for OD object */ + OD_extension_t OD_1010_extension; + /** Extension for OD object */ + OD_extension_t OD_1011_extension; + /** Null on the beginning, @ref CO_storage_entry_init() adds objects here + * and creates linked list. */ + CO_storage_entry_t *firstEntry; + /** From @ref CO_storage_init(). */ + bool_t sub1_all; +} CO_storage_t; + + +/** + * Pre-initialize data storage object. + * + * This function must be called before first @ref CO_storage_entry_init() + * function call. It is used inside @ref CO_new(). + * + * @param storage This object will be pre-initialized. + */ +static inline void CO_storage_pre_init(CO_storage_t *storage) { + if (storage != NULL) storage->firstEntry = NULL; +} + + +/** + * Initialize data storage object for usage with OD objects 1010 and 1011. + * + * Function is used inside @ref CO_CANopenInit(). It does not erase + * pre-configured entries from CO_storage_entry_init() calls. + * + * @param storage This object will be initialized. + * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". + * @param OD_1011_RestoreDefaultParameters OD entry for 0x1011 -"Restore default + * parameters". Entry is optional, may be NULL. + * @param sub1_all If true, then writing to sub-index 1 of 1010 and 1011 will + * store/restore all data. This is default in CANopen. + * @param [out] errInfo Additional information in case of error, may be NULL. + * + * @return CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OD_PARAMETERS. + */ +CO_ReturnError_t CO_storage_init(CO_storage_t *storage, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParameters, + bool_t sub1_all, + uint32_t *errInfo); + + +/** + * Initialize / add one entry into data storage object + * + * This function may be called by application one or several times after + * @ref CO_storage_pre_init() and before @ref CO_CANopenInit(). If entry with + * the same CO_storage_entry_t->subIndexOD as in newEntry already exists in + * storage object, then that entry in storage object will be replaced with + * newEntry. So it is not a problem to call this function multiple times with + * the same subIndexOD in CANopen communication reset section. + * + * @param storage Data storage object. + * @param newEntry New entry for data storage object. It must be initialized + * externally. This object must exist permanently. To disable entry, set store + * and restore function pointers to NULL. + * + * @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + */ +CO_ReturnError_t CO_storage_entry_init(CO_storage_t *storage, + CO_storage_entry_t *newEntry); + + +/** @} */ /* CO_storage */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +#endif /* CO_STORAGE_H */ diff --git a/CANopen.c b/CANopen.c index 2c14a524..e44aaba1 100644 --- a/CANopen.c +++ b/CANopen.c @@ -185,6 +185,18 @@ #define CO_TX_CNT_TPDO 0 #endif +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + #if !defined OD_CNT_STORAGE + #define OD_CNT_STORAGE 0 + #define OD_ENTRY_H1010 NULL + #elif OD_CNT_STORAGE < 0 || OD_CNT_STORAGE > 1 + #error OD_CNT_STORAGE from OD.h not correct! + #endif + #ifndef OD_ENTRY_H1011 + #define OD_ENTRY_H1011 NULL + #endif +#endif + #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE #define OD_CNT_LEDS 1 #endif @@ -313,7 +325,8 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { || config->CNT_EM > 1 || config->CNT_SDO_SRV > 128 || config->CNT_SDO_CLI > 128 || config->CNT_SYNC > 1 || config->CNT_RPDO > 512 || config->CNT_TPDO > 512 - || config->CNT_TIME > 1 || config->CNT_LEDS > 1 + || config->CNT_TIME > 1 + || config->OD_CNT_STORAGE > 1 || config->CNT_LEDS > 1 || config->CNT_GFC > 1 || config->CNT_SRDO > 64 || config->CNT_LSS_SLV > 1 || config->CNT_LSS_MST > 1 || config->CNT_GTWA > 1 @@ -456,6 +469,16 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + if (CO_GET_CNT(STORAGE) == 1) { + p = calloc(1, sizeof(CO_storage_t)); + if (p == NULL) break; + else co->storage = (CO_storage_t *)p; + CO_storage_pre_init(co->storage); + mem += sizeof(CO_storage_t); + } +#endif + #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE if (CO_GET_CNT(LEDS) == 1) { p = calloc(1, sizeof(CO_LEDs_t)); @@ -671,6 +694,10 @@ void CO_delete(CO_t *co) { free(co->GFC); #endif +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + free(co->storage); +#endif + #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE free(co->LEDs); #endif @@ -744,6 +771,9 @@ void CO_delete(CO_t *co) { #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE static CO_TPDO_t COO_TPDO[OD_CNT_TPDO]; #endif +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + static CO_storage_t COO_storage; +#endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE static CO_LEDs_t COO_LEDs; #endif @@ -802,6 +832,9 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE co->TPDO = &COO_TPDO[0]; #endif +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + co->storage = &COO_storage; +#endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE co->LEDs = &COO_LEDs; #endif @@ -945,6 +978,17 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, return CO_ERROR_ILLEGAL_ARGUMENT; } +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + if (CO_GET_CNT(STORAGE) == 1) { + err = CO_storage_init(co->storage, + OD_GET(H1010, OD_H1010_STORE_PARAMETERS), + OD_GET(H1011, OD_H1011_RESTORE_DEFAULT), + true, + errInfo); + if (err) return err; + } +#endif + #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE if (CO_GET_CNT(LEDS) == 1) { err = CO_LEDs_init(co->LEDs); diff --git a/CANopen.h b/CANopen.h index 093628ae..42176526 100644 --- a/CANopen.h +++ b/CANopen.h @@ -31,57 +31,21 @@ #include "301/CO_driver.h" #include "301/CO_ODinterface.h" #include "301/CO_NMT_Heartbeat.h" - -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN #include "301/CO_HBconsumer.h" -#endif - #include "301/CO_Emergency.h" #include "301/CO_SDOserver.h" - -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) || defined CO_DOXYGEN #include "301/CO_SDOclient.h" -#endif - -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN #include "301/CO_SYNC.h" -#endif - -#if ((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) || defined CO_DOXYGEN #include "301/CO_PDO.h" -#endif - -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) || defined CO_DOXYGEN #include "301/CO_TIME.h" -#endif - -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN +#include "301/CO_storage.h" #include "303/CO_LEDs.h" -#endif - -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || defined CO_DOXYGEN #include "304/CO_GFC.h" -#endif - -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN #include "304/CO_SRDO.h" -#endif - -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) || defined CO_DOXYGEN #include "305/CO_LSSslave.h" -#endif - -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) || defined CO_DOXYGEN #include "305/CO_LSSmaster.h" -#endif - -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN #include "309/CO_gateway_ascii.h" -#endif - -#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) || defined CO_DOXYGEN #include "extra/CO_trace.h" -#endif #ifdef __cplusplus @@ -270,6 +234,10 @@ typedef struct { uint16_t CNT_TPDO; OD_entry_t *ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */ OD_entry_t *ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */ + /** Number of storage objects, 0 or 1. */ + uint8_t CNT_STORAGE; + OD_entry_t *ENTRY_H1010; /**< OD entry for @ref CO_storage_init() */ + OD_entry_t *ENTRY_H1011; /**< OD entry for @ref CO_storage_init() */ /** Number of LEDs objects, 0 or 1. */ uint8_t CNT_LEDS; /** Number of GFC objects, 0 or 1 (CANrx + CANtx). */ @@ -375,6 +343,10 @@ typedef struct { uint16_t TX_IDX_TPDO; /**< Start index in CANtx. */ #endif #endif +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN + /** Storage object, initialised by @ref CO_storage_init() */ + CO_storage_t *storage; +#endif #if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN /** LEDs object, initialised by @ref CO_LEDs_init() */ CO_LEDs_t *LEDs; diff --git a/Doxyfile b/Doxyfile index 064509f9..86c9b45c 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.17 +# Doxyfile 1.8.18 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -253,12 +253,6 @@ TAB_SIZE = 4 ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -300,13 +294,13 @@ OPTIMIZE_OUTPUT_SLICE = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, # Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is -# Fortran), use: inc=Fortran f=C. +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # @@ -853,7 +847,7 @@ INPUT_ENCODING = UTF-8 # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), # *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen -# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f, *.for, *.tcl, *.vhd, +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = @@ -1523,6 +1517,17 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png The default and svg Looks nicer but requires the +# pdf2svg tool. +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1578,7 +1583,7 @@ MATHJAX_FORMAT = HTML-CSS # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest diff --git a/Makefile b/Makefile index 0e5be8c5..4060f05e 100644 --- a/Makefile +++ b/Makefile @@ -14,12 +14,12 @@ INCLUDE_DIRS = \ -I$(CANOPEN_SRC) \ -I$(APPL_SRC) -# $(DRV_SRC)/CO_OD_storage.c \ SOURCES = \ $(DRV_SRC)/CO_driver.c \ $(DRV_SRC)/CO_error.c \ $(DRV_SRC)/CO_epoll_interface.c \ + $(DRV_SRC)/CO_storageLinux.c \ $(CANOPEN_SRC)/301/CO_ODinterface.c \ $(CANOPEN_SRC)/301/CO_NMT_Heartbeat.c \ $(CANOPEN_SRC)/301/CO_HBconsumer.c \ @@ -31,6 +31,7 @@ SOURCES = \ $(CANOPEN_SRC)/301/CO_PDO.c \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ $(CANOPEN_SRC)/301/CO_fifo.c \ + $(CANOPEN_SRC)/301/CO_storage.c \ $(CANOPEN_SRC)/303/CO_LEDs.c \ $(CANOPEN_SRC)/304/CO_GFC.c \ $(CANOPEN_SRC)/304/CO_SRDO.c \ diff --git a/README.md b/README.md index 30579ec4..6057400d 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,8 @@ Characteristics - [Suitable for 16-bit microcontrollers and above](#device-support) - [Multithreaded, real-time](#flowchart-of-a-typical-canopennode-implementation) - [Object Dictionary editor](#object-dictionary-editor) - - Non-volatile storage for Object Dictionary variables. + - Non-volatile storage for Object Dictionary or other variables. Automatic or + controlled by standard CANopen commands, configurable. - [Power saving possible](#power-saving) - [Bootloader possible](https://github.com/CANopenNode/CANopenNode/issues/111) (for firmware update) @@ -67,7 +68,7 @@ Further documented examples are available in [CANopenSocket](https://github.com/ Report issues on https://github.com/CANopenNode/CANopenNode/issues -Join discussion on Slack: https://canopennode.slack.com/ +For discussion on [Slack](https://canopennode.slack.com/) see: https://github.com/robincornelius/libedssharp Older discussion group is on Sourceforge: http://sourceforge.net/p/canopennode/discussion/387151/ diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index ab47409d..0e9d4b1d 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -96,6 +96,7 @@ S32DS (NXP S32 Design studio for Arm or Powerpc) Other ----- +* [ESP32](https://github.com/CANopenNode/CANopenNode/issues/198#issuecomment-658429391), 2020-07-14 * [FreeRTOS](https://github.com/martinwag/CANopenNode/tree/neuberger-freertos/stack/neuberger-FreeRTOS) by Neuberger, 2020-06-23, based on v1.3-master, see also [issue 198](https://github.com/CANopenNode/CANopenNode/issues/198). * [STM32CubeMX HAL](https://github.com/w1ne/CANOpenNode-CubeMX-HAL), 2019-05-03, demo project for Atollic studio, tested on Nucleo STM32L452xx board. * K64F_FreeRTOS, Kinetis SDK, 2018-02-13, [zip file](https://github.com/CANopenNode/CANopenNode/pull/28#issuecomment-365392867) diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index fa523a04..773ba1d6 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -46,14 +46,14 @@ Go to the first terminal, where we have recently build executable, named _canope First print help, then run the program with some options. ./canopend --help - ./canopend vcan0 -i 4 #-s od4_storage -a od4_storage_auto + ./canopend vcan0 -i 4 You are now running a fully functional CANopen device on virtual CAN network. It is running in background until you terminate the process (with CTRL+C for example) or it receives a reset message from CAN network. By default process also shows some info messages on terminal, for example changes of NMT state or emergency messages, own and remote. On the second terminal you can see some CAN traffic. After _canopend_ startup, first messages are: vcan0 704 [1] 00 # Boot-up message. - vcan0 084 [8] 00 50 01 2F F3 FF FF FF # Emergency message. + vcan0 084 [8] 00 50 01 2F 03 00 00 00 # Emergency message. Boot-up message of node 4 have CAN-ID equal to 0x704. CAN-ID is 11-bit standard CAN identifier. @@ -63,11 +63,13 @@ The easiest way to find the reason of the emergency message is to check the byte This byte is CANopenNode specific. You can observe also first two bytes, which shows standard error code (0x5000 - Device Hardware) or third byte, which shows error register. If error register is different than zero, then node may be prohibited to enter operational and PDOs can not be exchanged with it. -You can follow the reason of the problem inside the source code. However, there are missing non-default storage files. Go to the first terminal, terminate the application with CTRL+C, add files and run _canopend_ again. +You can follow the reason of the problem inside the source code. However, data storage was not yet initialized, files are missing. CANopen device works, but NMT operational state is not possible. Data storage files on running new device can be generated by CANopen gateway command `4 write 0x1010 1 u32 0x65766173` or `4 write 0x1011 1 u32 0x64616F6C`. Or files can be generated manually with the Linux commands below. - echo "-" > od4_storage - echo "-" > od4_storage_auto - ./canopend vcan0 -i 4 #-s od4_storage -a od4_storage_auto +Go to the first terminal, terminate the application with CTRL+C, add files and run _canopend_ again. + + echo "-" > lss.persist + echo "-" > od_comm.persist + ./canopend vcan0 -i 4 Second terminal now shows new boot-up message without emergency. @@ -75,11 +77,11 @@ Second terminal now shows new boot-up message without emergency. ### Second CANopen device -Open the third terminal and cd to the same directory as is in the first terminal. First generate default storage files. Then start second instance of _canopend_ with NodeID = 1. Use default od_storage files and enable command interface on standard IO (terminal). +Open the third terminal and cd to the same directory as is in the first terminal. First generate data storage files with prefix, so data won't mix. Then start second instance of _canopend_ with NodeID = 1 and prefix for data storage. Enable command interface on standard IO (terminal). - echo "-" > od_storage - echo "-" > od_storage_auto - ./canopend vcan0 -i1 -c "stdio" + echo "-" > node1_lss.persist + echo "-" > node1_od_comm.persist + ./canopend vcan0 -i1 -s "node1_" -c "stdio" Now you should see in second terminal (_candump_) boot-up message of new CANopen device. diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 5870021e..400fb6d0 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -458,7 +458,7 @@ Object Dictionary Requirements By CANopenNode {#object-dictionary-requirements-b | 100A | Manufacturer software version | | | | 100C | Guard time | | | | 100D | Life time factor | | | -| 1010 | Store parameters | | | +| 1010 | Store parameters | | STORAGE | | 1011 | Restore default parameters | | | | 1012 | COB-ID time stamp object | TIME, req | TIME | | 1013 | High resolution time stamp | | | diff --git a/example/DS301_profile.eds b/example/DS301_profile.eds index cae68509..2c92d406 100644 --- a/example/DS301_profile.eds +++ b/example/DS301_profile.eds @@ -8,8 +8,8 @@ Description= CreationTime=12:00PM CreationDate=11-23-2020 CreatedBy= -ModificationTime=4:21PM -ModificationDate=01-06-2021 +ModificationTime=3:01PM +ModificationDate=01-20-2021 ModifiedBy= [DeviceInfo] diff --git a/example/DS301_profile.md b/example/DS301_profile.md index 4196b2d1..dde64d2b 100644 --- a/example/DS301_profile.md +++ b/example/DS301_profile.md @@ -10,10 +10,10 @@ CANopen documentation | File Version | 1 | | Created | 23. 11. 2020 12:00:00 | | Created By | | -| Modified | 6. 01. 2021 16:21:52 | +| Modified | 20. 01. 2021 15:01:07 | | Modified By | | -This file was automatically generated with [libedssharp](https://github.com/robincornelius/libedssharp) Object Dictionary Editor v0.8-116-g2e8a14a +This file was automatically generated with [libedssharp](https://github.com/robincornelius/libedssharp) Object Dictionary Editor v0.8-114-gc3a898f * [Device Information](#device-information) * [PDO Mapping](#pdo-mapping) @@ -145,7 +145,7 @@ Synchronous window leghth in µs (0 = not used). All synchronous PDOs must be tr ### 0x1010 - Store parameters | Object Type | Count Label | Storage Group | | ----------- | -------------- | -------------- | -| ARRAY | | RAM | +| ARRAY | STORAGE | RAM | | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | diff --git a/example/DS301_profile.xpd b/example/DS301_profile.xpd index 4ecbdc54..5e402278 100644 --- a/example/DS301_profile.xpd +++ b/example/DS301_profile.xpd @@ -1,5 +1,5 @@ - + @@ -15,7 +15,7 @@ CANopen - + @@ -753,6 +753,7 @@ * bit 0: If set, CANopen device saves parameters on command * Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores corresponding data. + @@ -2253,7 +2254,7 @@ CANopen - + diff --git a/example/OD.c b/example/OD.c index 246ef5be..d8ec0d5a 100644 --- a/example/OD.c +++ b/example/OD.c @@ -2,7 +2,7 @@ CANopen Object Dictionary definition for CANopenNode V4 This file was automatically generated with - libedssharp Object Dictionary Editor v0.8-116-g2e8a14a + libedssharp Object Dictionary Editor v0.8-114-gc3a898f https://github.com/CANopenNode/CANopenNode https://github.com/robincornelius/libedssharp diff --git a/example/OD.h b/example/OD.h index 7bcb955f..b50db42e 100644 --- a/example/OD.h +++ b/example/OD.h @@ -2,7 +2,7 @@ CANopen Object Dictionary definition for CANopenNode V4 This file was automatically generated with - libedssharp Object Dictionary Editor v0.8-116-g2e8a14a + libedssharp Object Dictionary Editor v0.8-114-gc3a898f https://github.com/CANopenNode/CANopenNode https://github.com/robincornelius/libedssharp @@ -17,7 +17,7 @@ Created: 23. 11. 2020 12:00:00 Created By: - Modified: 6. 01. 2021 16:21:52 + Modified: 20. 01. 2021 15:01:07 Modified By: Device Info: @@ -38,6 +38,7 @@ #define OD_CNT_EM 1 #define OD_CNT_SYNC 1 #define OD_CNT_SYNC_PROD 1 +#define OD_CNT_STORAGE 1 #define OD_CNT_TIME 1 #define OD_CNT_EM_PROD 1 #define OD_CNT_HB_CONS 1 diff --git a/socketCAN/CO_OD_storage.c b/socketCAN/CO_OD_storage.c deleted file mode 100644 index 1a39ee8f..00000000 --- a/socketCAN/CO_OD_storage.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * CANopen Object Dictionary storage object for Linux SocketCAN. - * - * @file CO_OD_storage.c - * @author Janez Paternoster - * @copyright 2015 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" -#include "301/CO_Emergency.h" -#include "301/crc16-ccitt.h" -#include "CO_OD_storage.h" - -#include -#include /* for memcpy */ -#include /* for malloc, free */ - - -#define RETURN_SUCCESS 0 -#define RETURN_ERROR -1 - - -/******************************************************************************/ -CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg) { - CO_OD_storage_t *odStor; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - odStor = (CO_OD_storage_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - if(!ODF_arg->reading) { - /* don't change the old value */ - memcpy(ODF_arg->data, ODF_arg->ODdataStorage, 4); - - if(ODF_arg->subIndex == 1) { - /* store parameters */ - if(value == 0x65766173UL) { - if(CO_OD_storage_saveSecure(odStor->odAddress, odStor->odSize, odStor->filename) != 0) { - ret = CO_SDO_AB_HW; - } - } - else { - ret = CO_SDO_AB_DATA_TRANSF; - } - } - } - - return ret; -} - - -/******************************************************************************/ -CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg) { - CO_OD_storage_t *odStor; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - odStor = (CO_OD_storage_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - if(!ODF_arg->reading) { - /* don't change the old value */ - memcpy(ODF_arg->data, ODF_arg->ODdataStorage, 4); - - if(ODF_arg->subIndex >= 1) { - /* restore default parameters */ - if(value == 0x64616F6CUL) { - if(CO_OD_storage_restoreSecure(odStor->filename) != 0) { - ret = CO_SDO_AB_HW; - } - } - else { - ret = CO_SDO_AB_DATA_TRANSF; - } - } - } - - return ret; -} - - -/******************************************************************************/ -int CO_OD_storage_saveSecure( - uint8_t *odAddress, - uint32_t odSize, - char *filename) -{ - int ret = RETURN_SUCCESS; - - char *filename_old = NULL; - uint16_t CRC = 0; - - /* Generate new string with extension '.old' and rename current file to it. */ - filename_old = malloc(strlen(filename)+10); - if(filename_old != NULL) { - strcpy(filename_old, filename); - strcat(filename_old, ".old"); - - remove(filename_old); - if(rename(filename, filename_old) != 0) { - ret = RETURN_ERROR; - } - } else { - ret = RETURN_ERROR; - } - - /* Open a new file and write data to it, including CRC. */ - if(ret == RETURN_SUCCESS) { - FILE *fp = fopen(filename, "w"); - if(fp != NULL) { - - //CO_LOCK_OD(); - fwrite((const void *)odAddress, 1, odSize, fp); - CRC = crc16_ccitt((unsigned char*)odAddress, odSize, 0); - //CO_UNLOCK_OD(); - - fwrite((const void *)&CRC, 1, 2, fp); - fclose(fp); - } else { - ret = RETURN_ERROR; - } - } - - /* Verify data */ - if(ret == RETURN_SUCCESS) { - void *buf = NULL; - FILE *fp = NULL; - uint32_t cnt = 0; - uint16_t CRC2 = 0; - - buf = malloc(odSize + 4); - if(buf != NULL) { - fp = fopen(filename, "r"); - if(fp != NULL) { - cnt = fread(buf, 1, odSize, fp); - CRC2 = crc16_ccitt((unsigned char*)buf, odSize, 0); - /* read also two bytes of CRC */ - cnt += fread(buf, 1, 4, fp); - fclose(fp); - } - free(buf); - } - /* If size or CRC differs, report error */ - if(buf == NULL || fp == NULL || cnt != (odSize + 2) || CRC != CRC2) { - ret = RETURN_ERROR; - } - } - - /* In case of error, set back the old file. */ - if(ret != RETURN_SUCCESS && filename_old != NULL) { - remove(filename); - rename(filename_old, filename); - } - - free(filename_old); - - return ret; -} - - -/******************************************************************************/ -int CO_OD_storage_restoreSecure(char *filename) { - int ret = RETURN_SUCCESS; - FILE *fp = NULL; - - /* If filename already exists, rename it to '.old'. */ - fp = fopen(filename, "r"); - if(fp != NULL) { - char *filename_old = NULL; - - fclose(fp); - - filename_old = malloc(strlen(filename)+10); - if(filename_old != NULL) { - strcpy(filename_old, filename); - strcat(filename_old, ".old"); - - remove(filename_old); - if(rename(filename, filename_old) != 0) { - ret = RETURN_ERROR; - } - free(filename_old); - } - else { - ret = RETURN_ERROR; - } - } - - /* create an empty file and write "-\n" to it. */ - if(ret == RETURN_SUCCESS) { - fp = fopen(filename, "w"); - if(fp != NULL) { - fputs("-\n", fp); - fclose(fp); - } else { - ret = RETURN_ERROR; - } - } - - return ret; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_OD_storage_init( - CO_OD_storage_t *odStor, - uint8_t *odAddress, - uint32_t odSize, - char *filename) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - void *buf = NULL; - - /* verify arguments */ - if(odStor==NULL || odAddress==NULL) { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* configure object variables and allocate buffer */ - if(ret == CO_ERROR_NO) { - odStor->odAddress = odAddress; - odStor->odSize = odSize; - odStor->filename = filename; - odStor->fp = NULL; - odStor->lastSavedUs = 0; - - buf = malloc(odStor->odSize); - if(buf == NULL) { - ret = CO_ERROR_OUT_OF_MEMORY; - } - } - - /* read data from the file and verify CRC */ - if(ret == CO_ERROR_NO) { - FILE *fp; - uint32_t cnt = 0; - uint16_t CRC[2]; - - fp = fopen(odStor->filename, "r"); - if(fp) { - cnt = fread(buf, 1, odStor->odSize, fp); - /* read also two bytes of CRC from file */ - cnt += fread(&CRC[0], 1, 4, fp); - CRC[1] = crc16_ccitt((unsigned char*)buf, odStor->odSize, 0); - fclose(fp); - } - - if(cnt == 2 && *((char*)buf) == '-') { - /* file is empty, default values will be used, no error */ - ret = CO_ERROR_NO; - } - else if(cnt != (odStor->odSize + 2)) { - /* file length does not match */ - ret = CO_ERROR_DATA_CORRUPT; - } - else if(CRC[0] != CRC[1]) { - /* CRC does not match */ - ret = CO_ERROR_CRC; - } - else { - /* no errors, copy data into Object dictionary */ - memcpy(odStor->odAddress, buf, odStor->odSize); - } - } - - free(buf); - - return ret; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_OD_storage_autoSave( - CO_OD_storage_t *odStor, - uint32_t timer1usDiff, - uint32_t delay_us) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - /* verify arguments */ - if(odStor==NULL || odStor->odAddress==NULL) { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* don't save file more often than delay */ - odStor->lastSavedUs += timer1usDiff; - if (odStor->lastSavedUs > delay_us) { - void *buf = NULL; - bool_t saveData = false; - - /* allocate buffer and open file if necessary */ - if(ret == CO_ERROR_NO) { - buf = malloc(odStor->odSize); - if(odStor->fp == NULL) { - odStor->fp = fopen(odStor->filename, "r+"); - } - if(buf == NULL || odStor->fp == NULL) { - ret = CO_ERROR_OUT_OF_MEMORY; - } - } - - /* read data from the beginning of the file */ - if(ret == CO_ERROR_NO) { - uint32_t cnt = 0; - - rewind(odStor->fp); - cnt = fread(buf, 1, odStor->odSize, odStor->fp); - - if(cnt == 2 && *((char*)buf) == '-') { - /* file is empty, data will be saved. */ - saveData = true; - } - else if(cnt == odStor->odSize) { - /* verify, if data differs */ - if(memcmp((const void *)buf, (const void *)odStor->odAddress, odStor->odSize) != 0) { - saveData = true; - } - } - else { - /* file length does not match */ - ret = CO_ERROR_DATA_CORRUPT; - } - } - - /* Save the data to the file only if data differs. */ - if(ret == CO_ERROR_NO && saveData) { - uint16_t CRC; - - /* copy data to temporary buffer */ - memcpy(buf, odStor->odAddress, odStor->odSize); - - rewind(odStor->fp); - fwrite((const void *)buf, 1, odStor->odSize, odStor->fp); - - /* write also CRC */ - CRC = crc16_ccitt((unsigned char*)buf, odStor->odSize, 0); - fwrite((const void *)&CRC, 1, 2, odStor->fp); - - fflush(odStor->fp); - - odStor->lastSavedUs = 0; - } - - free(buf); - } - - return ret; -} - -void CO_OD_storage_autoSaveClose(CO_OD_storage_t *odStor) { - if(odStor->fp != NULL) { - fclose(odStor->fp); - } -} diff --git a/socketCAN/CO_OD_storage.h b/socketCAN/CO_OD_storage.h deleted file mode 100644 index c0212e81..00000000 --- a/socketCAN/CO_OD_storage.h +++ /dev/null @@ -1,171 +0,0 @@ -/** - * CANopen Object Dictionary storage object for Linux SocketCAN. - * - * @file CO_OD_storage.h - * @ingroup CO_socketCAN_OD_storage - * @author Janez Paternoster - * @copyright 2015 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_OD_STORAGE_H -#define CO_OD_STORAGE_H - - -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_socketCAN_OD_storage OD storage - * @ingroup CO_socketCAN - * @{ - * - * Object Dictionary storage implementation for CANopenNode on Linux - */ - - -/** - * Callback for use inside @ref CO_OD_configure() function for OD object 1010 - */ -CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg); - -/** - * Callback for use inside @ref CO_OD_configure() function for OD object 1011 - */ -CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg); - - -/** - * Save memory block to a file. - * - * Function renames current file to filename.old, copies contents from odAddress - * to filename, adds two bytes of CRC code. It then verifies the written file and - * in case of errors sets back the old file and returns error. - * - * Function is used with CANopen OD object at index 1010. - * - * @param odAddress Address of the memory block, which will be stored. - * @param odSize Size of the above memory block. - * @param filename Name of the file, where data will be stored. - * - * @return 0 on success, -1 on error. - */ -int CO_OD_storage_saveSecure( - uint8_t *odAddress, - uint32_t odSize, - char *filename); - - -/** - * Remove OD storage file. - * - * Function renames current file to filename.old, then creates empty file and - * writes two bytes "-\n" to it. When program will start next time, default values - * are used for Object Dictionary. In case of error in renaming to .old it - * keeps the original file and returns error. - * - * Writing data to file is secured with mutex CO_LOCK_OD. - * - * Function is used with CANopen OD object at index 1011. - * - * @param filename Name of the file. - * - * @return 0 on success, -1 on error. - */ -int CO_OD_storage_restoreSecure(char *filename); - - -/** - * Object Dictionary storage object. - * - * Object is used with CANopen OD objects at index 1010 and 1011. - */ -typedef struct { - uint8_t *odAddress; /**< From CO_OD_storage_init() */ - uint32_t odSize; /**< From CO_OD_storage_init() */ - char *filename; /**< From CO_OD_storage_init() */ - /** If CO_OD_storage_autoSave() is used, file stays opened and fp is stored here. */ - FILE *fp; - uint32_t lastSavedUs; /**< used with CO_OD_storage_autoSave. */ -} CO_OD_storage_t; - - -/** - * Initialize OD storage object and load data from file. - * - * Called after program startup. Load storage file and copy data to Object - * Dictionary variables. - * - * @param odStor This object will be initialized. - * @param odAddress Address of the memory block from Object dictionary, where data will be copied. - * @param odSize Size of the above memory block. - * @param filename Name of the file, where data are stored. - * - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_DATA_CORRUPT (Data in file corrupt), - * CO_ERROR_CRC (CRC from MBR does not match the CRC of OD_ROM block in file), - * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY (malloc failed). - */ -CO_ReturnError_t CO_OD_storage_init( - CO_OD_storage_t *odStor, - uint8_t *odAddress, - uint32_t odSize, - char *filename); - - -/** - * Automatically save memory block if differs from file. - * - * Should be called cyclically by program. It first verifies, if memory block - * differs from file and if it does, it saves it to file with two additional - * CRC bytes. File remains opened. - * - * @param odStor OD storage object. - * @param timer1usDiff Time difference in microseconds since last call. - * @param delay_us Delay (inhibit) time between writes to disk in microseconds - * (60000 for example). - * - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_DATA_CORRUPT (Data in file - * corrupt), CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY (malloc failed). - */ -CO_ReturnError_t CO_OD_storage_autoSave( - CO_OD_storage_t *odStor, - uint32_t timer1usDiff, - uint32_t delay_us); - - -/** - * Closes file opened by CO_OD_storage_autoSave. - * - * @param odStor OD storage object. - */ -void CO_OD_storage_autoSaveClose(CO_OD_storage_t *odStor); - -/** @} */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CO_OD_STORAGE_H */ diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index deacd2ff..9003dad3 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -261,7 +261,6 @@ extern "C" { #define CO_SWAP_64(x) bswap_64(x) #endif #endif -/* #define CO_USE_LEDS */ /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 5a5cbc74..8c2d1b62 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -22,10 +22,6 @@ * limitations under the License. */ -#ifndef CO_OD_STORAGE -#define CO_OD_STORAGE 0 -#endif - #include #include #include @@ -46,9 +42,7 @@ #include "OD.h" #include "CO_error.h" #include "CO_epoll_interface.h" -#if CO_OD_STORAGE == 1 -#include "CO_OD_storage.h" -#endif +#include "CO_storageLinux.h" /* Call external application functions. */ #ifdef CO_USE_APPLICATION @@ -60,11 +54,6 @@ #include "CO_time_trace.h" #endif -/* Use DS309-3 standard - ASCII command interface to CANopen: NMT master, - * LSS master and SDO client */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -#include "309/CO_gateway_ascii.h" -#endif /* Interval of mainline and real-time thread in microseconds */ #ifndef MAIN_THREAD_INTERVAL_US @@ -74,7 +63,7 @@ #define TMR_THREAD_INTERVAL_US 1000 #endif -/* default values */ +/* default values for CO_CANopenInit() */ #ifndef NMT_CONTROL #define NMT_CONTROL \ CO_NMT_STARTUP_TO_OPERATIONAL \ @@ -94,35 +83,82 @@ #ifndef SDO_CLI_BLOCK #define SDO_CLI_BLOCK false #endif -#ifndef GATEWAY_ENABLE -#define GATEWAY_ENABLE true -#endif #ifndef OD_STATUS_BITS #define OD_STATUS_BITS NULL #endif - -/* Other variables and objects */ -#ifndef CO_SINGLE_THREAD -CO_epoll_t epRT; /* Epoll-timer object for realtime thread */ -static int rtPriority = -1; /* Real time priority, configurable by arguments. (-1=RT disabled) */ -#endif -CO_t *CO = NULL; /* CANopen object */ -static uint8_t CO_pendingNodeId = 0xFF; /* Set by arguments or by OD_CAN_NODE_ID macro, if defined. Can be changed by LSS slave. */ -static uint8_t CO_activeNodeId = 0xFF;/* Copied from CO_pendingNodeId in the communication reset section */ -static uint16_t CO_pendingBitRate = 0; /* CAN bitrate, not used here */ -#if CO_OD_STORAGE == 1 -static CO_OD_storage_t odStor; /* Object Dictionary storage object for CO_OD_ROM */ -static CO_OD_storage_t odStorAuto; /* Object Dictionary storage object for CO_OD_EEPROM */ -static char *odStorFile_rom = "od_storage"; /* Name of the file */ -static char *odStorFile_eeprom = "od_storage_auto"; /* Name of the file */ +/* CANopen gateway enable switch for CO_epoll_processMain() */ +#ifndef GATEWAY_ENABLE +#define GATEWAY_ENABLE true #endif + +/* CANopen object */ +CO_t *CO = NULL; + +/* Configurable CAN bit-rate and CANopen node-id, store-able to non-volatile + * memory. Can be set by argument and changed by LSS slave. */ +typedef struct { uint16_t bitRate; uint8_t nodeId; } CO_pending_t; +CO_pending_t CO_pending = { .bitRate = 0, .nodeId = CO_LSS_NODE_ID_ASSIGNMENT }; +/* Active node-id, copied from CO_pending.nodeId in the communication reset */ +static uint8_t CO_activeNodeId = CO_LSS_NODE_ID_ASSIGNMENT; + +/* Data storage for Object Dictionnary and LSS */ +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE +/* Maximum file name length including path for storage */ +#ifndef CO_STORAGE_PATH_MAX +#define CO_STORAGE_PATH_MAX 255 +#endif + +/* Definitions for application specific storage objects */ +#ifndef CO_STORAGE_APPLICATION +#define CO_STORAGE_APPLICATION +#endif + +/* Interval for automatic storage in microseconds */ +#ifndef CO_STORAGE_AUTO_INTERVAL +#define CO_STORAGE_AUTO_INTERVAL 60000000 +#endif + +/* Configure objects for storage */ +typedef struct { + /* Address, length and filename of data to store */ + void *addr; + OD_size_t len; + char filename[CO_STORAGE_PATH_MAX]; + /* Subindex in OD objects 1010 and 1011 or 0 for auto storage. + * 1 is reserved for storing all parameters */ + uint8_t subIndexOD; + /* Object for storage or auto storage, usage depends on subIndexOD */ + CO_storage_entry_t entry; + CO_storageLinux_auto_t entryAuto; +} CO_storageLinux_entry_t; +CO_storageLinux_entry_t storage[] = { + { + .addr = &CO_pending, + .len = sizeof(CO_pending), + .filename = {'l', 's', 's', + '.', 'p', 'e', 'r', 's', 'i', 's', 't', '\0'}, + .subIndexOD = 0 + }, + { + .addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), + .filename = {'o', 'd', '_', 'c', 'o', 'm', 'm', + '.', 'p', 'e', 'r', 's', 'i', 's', 't', '\0'}, + .subIndexOD = 2 + }, + CO_STORAGE_APPLICATION +}; +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE static CO_time_t CO_time; /* Object for current time */ #endif + /* Helper functions ***********************************************************/ #ifndef CO_SINGLE_THREAD /* Realtime thread */ +CO_epoll_t epRT; static void* rt_thread(void* arg); #endif @@ -211,15 +247,13 @@ static void HeartbeatNmtChangedCallback(uint8_t nodeId, uint8_t idx, } #endif -#if CO_OD_STORAGE == 1 /* callback for storing node id and bitrate */ static bool_t LSScfgStoreCallback(void *object, uint8_t id, uint16_t bitRate) { (void)object; - OD_CANNodeID = id; - OD_CANBitRate = bitRate; + CO_pending.nodeId = id; + CO_pending.bitRate = bitRate; return true; } -#endif /* Print usage */ static void printUsage(char *progName) { @@ -236,11 +270,10 @@ printf( #endif printf( " -r Enable reboot on CANopen NMT reset_node command. \n"); -#if CO_OD_STORAGE == 1 +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE printf( -" -s Set Filename for OD storage ('od_storage' is default).\n" -" -a Set Filename for automatic storage variables from\n" -" Object dictionary. ('od_storage_auto' is default).\n"); +" -s Path and filename prefix for data storage files.\n" +" By default files are stored in current dictionary.\n"); #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII printf( @@ -271,11 +304,13 @@ int main (int argc, char *argv[]) { CO_epoll_t epMain; #ifndef CO_SINGLE_THREAD pthread_t rt_thread_id; + int rtPriority = -1; #endif CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_ReturnError_t err; -#if CO_OD_STORAGE == 1 - CO_ReturnError_t odStorStatus_rom, odStorStatus_eeprom; +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + uint32_t storageInitError = 0; + uint32_t storageIntervalTimer = 0; #endif CO_CANptrSocketCan_t CANptr = {0}; int opt; @@ -308,8 +343,8 @@ int main (int argc, char *argv[]) { while((opt = getopt(argc, argv, "i:p:rc:T:s:a:")) != -1) { switch (opt) { case 'i': - CO_pendingNodeId = (uint8_t)strtol(optarg, NULL, 0); nodeIdFromArgs = true; + CO_pending.nodeId = (uint8_t)strtol(optarg, NULL, 0); break; #ifndef CO_SINGLE_THREAD case 'p': rtPriority = strtol(optarg, NULL, 0); @@ -349,11 +384,21 @@ int main (int argc, char *argv[]) { socketTimeout_ms = strtoul(optarg, NULL, 0); break; #endif -#if CO_OD_STORAGE == 1 - case 's': odStorFile_rom = optarg; - break; - case 'a': odStorFile_eeprom = optarg; +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + case 's': { + /* add prefix to each storage[i].filename */ + for (int i = 0; i < sizeof(storage) / sizeof(storage[0]); i++) { + char* filePrefix = optarg; + size_t filePrefixLen = strlen(filePrefix); + char* file = storage[i].filename; + size_t fileLen = strlen(file); + if (fileLen + filePrefixLen < CO_STORAGE_PATH_MAX) { + memmove(&file[filePrefixLen], &file[0], fileLen + 1); + memcpy(&file[0], &filePrefix[0], filePrefixLen); + } + } break; + } #endif default: printUsage(argv[0]); @@ -366,18 +411,11 @@ int main (int argc, char *argv[]) { CANptr.can_ifindex = if_nametoindex(CANdevice); } - if(!nodeIdFromArgs) { -#ifdef OD_CAN_NODE_ID - /* use value from Object dictionary, if not set by program arguments */ - CO_pendingNodeId = OD_CAN_NODE_ID; -#endif - } - - if((CO_pendingNodeId < 1 || CO_pendingNodeId > 127) + if((CO_pending.nodeId < 1 || CO_pending.nodeId > 127) && CO_isLSSslaveEnabled(CO) - && CO_pendingNodeId != CO_LSS_NODE_ID_ASSIGNMENT + && CO_pending.nodeId != CO_LSS_NODE_ID_ASSIGNMENT ) { - log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_pendingNodeId); + log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_pending.nodeId); printUsage(argv[0]); exit(EXIT_FAILURE); } @@ -397,7 +435,7 @@ int main (int argc, char *argv[]) { } - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_pendingNodeId, "starting"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_pending.nodeId, "starting"); /* Allocate memory for CANopen objects */ @@ -410,25 +448,37 @@ int main (int argc, char *argv[]) { } -#if CO_OD_STORAGE == 1 - /* Verify, if OD structures have proper alignment of initial values */ - if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) { - log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, "CO_OD_RAM"); - exit(EXIT_FAILURE); - } - if(CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) { - log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, "CO_OD_EEPROM"); - exit(EXIT_FAILURE); +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + uint8_t pendingNodeIdOriginal = CO_pending.nodeId; + for (int i = 0; i < sizeof(storage) / sizeof(storage[0]); i++) { + CO_storageLinux_entry_t *st = &storage[i]; + if (st->subIndexOD == 0) { + err = CO_storageLinux_auto_init(&st->entryAuto, + st->addr, + st->len, + st->filename); + } else { + err = CO_storageLinux_entry_init(CO->storage, + &st->entry, + st->addr, + st->len, + st->filename, + st->subIndexOD); + } + if (err == CO_ERROR_DATA_CORRUPT) { + uint32_t bit = 1; + if (i < 32) bit <<= i; + storageInitError |= bit; + } + else if (err != CO_ERROR_NO) { + log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, st->filename); + exit(EXIT_FAILURE); + } } - if(CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) { - log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, "CO_OD_ROM"); - exit(EXIT_FAILURE); + /* Overwrite stored node-id, if specified by program arguments */ + if (nodeIdFromArgs) { + CO_pending.nodeId = pendingNodeIdOriginal; } - - - /* initialize Object Dictionary storage */ - odStorStatus_rom = CO_OD_storage_init(&odStor, (uint8_t*) &CO_OD_ROM, sizeof(CO_OD_ROM), odStorFile_rom); - odStorStatus_eeprom = CO_OD_storage_init(&odStorAuto, (uint8_t*) &CO_OD_EEPROM, sizeof(CO_OD_EEPROM), odStorFile_eeprom); #endif /* Catch signals SIGINT and SIGTERM */ @@ -502,7 +552,7 @@ int main (int argc, char *argv[]) { .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber }}; err = CO_LSSinit(CO, &lssAddress, - &CO_pendingNodeId, &CO_pendingBitRate); + &CO_pending.nodeId, &CO_pending.bitRate); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_LSSinit()", err); programExit = EXIT_FAILURE; @@ -510,7 +560,7 @@ int main (int argc, char *argv[]) { continue; } - CO_activeNodeId = CO_pendingNodeId; + CO_activeNodeId = CO_pending.nodeId; errInfo = 0; err = CO_CANopenInit(CO, /* CANopen object */ @@ -542,10 +592,8 @@ int main (int argc, char *argv[]) { #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_initCANopenGtw(&epGtw, CO); #endif -#if CO_OD_STORAGE == 1 CO_LSSslave_initCfgStoreCallback(CO->LSSslave, NULL, LSScfgStoreCallback); -#endif if(!CO->nodeIdUnconfigured) { #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); @@ -557,15 +605,10 @@ int main (int argc, char *argv[]) { CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, HeartbeatNmtChangedCallback); #endif -#if CO_OD_STORAGE == 1 - /* initialize OD objects 1010 and 1011 and verify errors. */ - CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U); - CO_OD_configure(CO->SDO[0], OD_H1011_REST_PARAM_FUNC, CO_ODF_1011, (void*)&odStor, 0, 0U); - if(odStorStatus_rom != CO_ERROR_NO) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_rom); - } - if(odStorStatus_eeprom != CO_ERROR_NO) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_eeprom + 1000); +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + if(storageInitError != 0) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, + CO_EMC_HARDWARE, storageInitError); } #endif @@ -651,9 +694,25 @@ int main (int argc, char *argv[]) { app_programAsync(!CO->nodeIdUnconfigured, epMain.timeDifference_us); #endif -#if CO_OD_STORAGE == 1 - CO_OD_storage_autoSave(&odStorAuto, - epMain.timeDifference_us, 60000000); +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + /* don't save more often than interval */ + if (storageIntervalTimer < CO_STORAGE_AUTO_INTERVAL) { + storageIntervalTimer += epMain.timeDifference_us; + } + else { + storageIntervalTimer = 0; + for (int i = 0; i < sizeof(storage) / sizeof(storage[0]); i++) { + CO_storageLinux_entry_t *st = &storage[i]; + if (st->subIndexOD == 0) { + bool_t storageOK = CO_storageLinux_auto_process( + &st->entryAuto, false); + if(!storageOK) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, + CO_EMC_HARDWARE, i); + } + } + } + } #endif } } /* while(reset != CO_RESET_APP */ @@ -673,10 +732,13 @@ int main (int argc, char *argv[]) { app_programEnd(); #endif -#if CO_OD_STORAGE == 1 - /* Store CO_OD_EEPROM */ - CO_OD_storage_autoSave(&odStorAuto, 0, 0); - CO_OD_storage_autoSaveClose(&odStorAuto); +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + for (int i = 0; i < sizeof(storage) / sizeof(storage[0]); i++) { + CO_storageLinux_entry_t *st = &storage[i]; + if (st->subIndexOD == 0) { + CO_storageLinux_auto_process(&st->entryAuto, true); + } + } #endif /* delete objects from memory */ diff --git a/socketCAN/CO_storageLinux.c b/socketCAN/CO_storageLinux.c new file mode 100644 index 00000000..36b67037 --- /dev/null +++ b/socketCAN/CO_storageLinux.c @@ -0,0 +1,321 @@ +/* + * CANopen Object Dictionary storage object for Linux SocketCAN. + * + * @file CO_storageLinux.c + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CO_storageLinux.h" +#include "301/crc16-ccitt.h" + +#include +#include +#include + +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + + +/* + * Function for writing data on "Store parameters" command - OD object 1010 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t storeLinux(void *object, void *addr, OD_size_t len) { + ODR_t ret = ODR_OK; + char *filename = object; + uint16_t crc_store; + + /* Create names for temporary and old file */ + size_t fn_len = strlen(filename) + 5; + char *filename_tmp = malloc(fn_len); + char *filename_old = malloc(fn_len); + if (filename_tmp == NULL || filename_old == NULL) { + ret = ODR_OUT_OF_MEM; + } + else { + strcpy(filename_tmp, filename); + strcpy(filename_old, filename); + strcat(filename_tmp, ".tmp"); + strcat(filename_old, ".old"); + } + + /* Open a temporary file and write data to it */ + if (ret == ODR_OK) { + FILE *fp = fopen(filename_tmp, "w"); + if (fp == NULL) { + ret = ODR_HW; + } + else { + CO_LOCK_OD(); + size_t cnt = fwrite(addr, 1, len, fp); + crc_store = crc16_ccitt(addr, len, 0); + CO_UNLOCK_OD(); + cnt += fwrite(&crc_store, 1, sizeof(crc_store), fp); + fclose(fp); + if (cnt != (len + sizeof(crc_store))) { + ret = ODR_HW; + } + } + } + + /* Verify data */ + if (ret == ODR_OK) { + uint8_t *buf = NULL; + FILE *fp = NULL; + size_t cnt = 0; + uint16_t crc_verify, crc_read; + + buf = malloc(len + 4); + if (buf != NULL) { + fp = fopen(filename_tmp, "r"); + if (fp != NULL) { + cnt = fread(buf, 1, len + 4, fp); + crc_verify = crc16_ccitt(buf, len, 0); + fclose(fp); + memcpy(&crc_read, &buf[len], sizeof(crc_read)); + } + free(buf); + } + /* If size or CRC differs, report error */ + if (buf == NULL || fp == NULL || cnt != (len + sizeof(crc_verify)) + || crc_store != crc_verify || crc_store != crc_read + ) { + ret = ODR_HW; + } + } + + /* rename existing file to *.old and *.tmp to existing */ + if (ret == ODR_OK) { + if (rename(filename, filename_old) != 0 + || rename(filename_tmp, filename) != 0 + ) { + ret = ODR_HW; + } + } + + free(filename_tmp); + free(filename_old); + + return ret; +} + + +/* + * Function for restoring data on "Restore default parameters" command - OD 1011 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t restoreLinux(void *object, void *addr, OD_size_t len) { + (void) addr; (void) len; + + char *filename = object; + ODR_t ret = ODR_OK; + + /* Rename existing filename to *.old. */ + char *filename_old = malloc(strlen(filename) + 5); + if (filename_old == NULL) { + ret = ODR_OUT_OF_MEM; + } + else { + strcpy(filename_old, filename); + strcat(filename_old, ".old"); + rename(filename, filename_old); + free(filename_old); + } + + /* create an empty file and write "-\n" to it. */ + if (ret == ODR_OK) { + FILE *fp = fopen(filename, "w"); + if (fp == NULL) { + ret = ODR_HW; + } + else { + fputs("-\n", fp); + fclose(fp); + } + } + + return ret; +} + + +CO_ReturnError_t CO_storageLinux_entry_init(CO_storage_t *storage, + CO_storage_entry_t *newEntry, + void *addr, + OD_size_t len, + char *filename, + uint8_t subIndexOD) +{ + /* verify arguments */ + if (storage == NULL || newEntry == NULL || addr == NULL || len == 0 + || filename == NULL || subIndexOD < 1 + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* configure newEntry and add it to the storage */ + newEntry->addr = addr; + newEntry->len = len; + newEntry->object = filename; + newEntry->subIndexOD = subIndexOD; + newEntry->store = storeLinux; + newEntry->restore = restoreLinux; + + CO_ReturnError_t ret; + FILE *fp = NULL; + uint8_t *buf = NULL; + + /* Add newEntry to storage object */ + ret = CO_storage_entry_init(storage, newEntry); + + /* Open file, check existence and create temporary buffer */ + if (ret == CO_ERROR_NO) { + fp = fopen(filename, "r"); + if (fp == NULL) { + ret = CO_ERROR_DATA_CORRUPT; + } + else { + buf = malloc(len + 4); + if (buf == NULL) { + ret = CO_ERROR_OUT_OF_MEMORY; + } + } + } + + /* Read data into temporary buffer first. Then verify and copy to addr */ + if (ret == CO_ERROR_NO) { + size_t cnt = fread(buf, 1, len + 4, fp); + + uint16_t crc1, crc2; + crc1 = crc16_ccitt(buf, len, 0); + memcpy(&crc2, &buf[len], sizeof(crc2)); + + if (cnt == 2 && buf[0] == '-') { + /* File is empty, default values will be used, no error */ + } + else if (cnt != (len + sizeof(crc2)) || crc1 != crc2) { + /* Data length does not match */ + ret = CO_ERROR_DATA_CORRUPT; + } + else { + /* no errors, copy data into Object dictionary */ + memcpy(addr, buf, len); + } + } + + if (buf != NULL) free(buf); + if (fp != NULL) fclose(fp); + + return ret; +} + + +CO_ReturnError_t CO_storageLinux_auto_init(CO_storageLinux_auto_t *storageAuto, + void *addr, + OD_size_t len, + char *filename) +{ + /* verify arguments */ + if (storageAuto == NULL || addr == NULL || len == 0 || filename == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* configure variables */ + storageAuto->addr = addr; + storageAuto->len = len; + storageAuto->crc = 0; + bool_t readOK = false; + char *writeFileAccess = "w"; + + /* Open the file, read data into temporary buffer, verify them and copy them + * into addr. If file does not exist or data is corrupt, just skip reading + * and keep the default values. */ + FILE *fp = fopen(filename, "r"); + if (fp != NULL) { + uint8_t *buf = malloc(len + 4); + if (buf != NULL) { + size_t cnt = fread(buf, 1, len + 4, fp); + + if (cnt == 2 && buf[0] == '-') { + /* File is empty, default values will be used, no error */ + readOK = true; + } + else { + uint16_t crc1, crc2; + crc1 = crc16_ccitt(buf, len, 0); + memcpy(&crc2, &buf[len], sizeof(crc2)); + + if (crc1 == crc2 && cnt == (len + sizeof(crc2))) { + memcpy(addr, buf, len); + storageAuto->crc = crc1; + readOK = true; + writeFileAccess = "r+"; + } + } + free(buf); + } + fclose(fp); + } + + storageAuto->fp = fopen(filename, writeFileAccess); + if (storageAuto->fp == NULL) return CO_ERROR_ILLEGAL_ARGUMENT; + + return readOK ? CO_ERROR_NO : CO_ERROR_DATA_CORRUPT; +} + + +bool_t CO_storageLinux_auto_process(CO_storageLinux_auto_t *storageAuto, + bool_t closeFile) +{ + bool_t ret = false; + + /* verify arguments */ + if (storageAuto == NULL || storageAuto->fp == NULL) { + return ret; + } + + /* If CRC of the current data differs, save the file */ + uint16_t crc = crc16_ccitt(storageAuto->addr, storageAuto->len, 0); + if (crc == storageAuto->crc) { + ret = true; + } + else { + size_t cnt; + rewind(storageAuto->fp); + CO_LOCK_OD(); + cnt = fwrite(storageAuto->addr, 1, storageAuto->len, storageAuto->fp); + CO_UNLOCK_OD(); + cnt += fwrite(&crc, 1, sizeof(crc), storageAuto->fp); + fflush(storageAuto->fp); + if (cnt == (storageAuto->len + sizeof(crc))) { + storageAuto->crc = crc; + ret = true; + } + } + + if (closeFile) { + fclose(storageAuto->fp); + storageAuto->fp = NULL; + } + + return ret; +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/socketCAN/CO_storageLinux.h b/socketCAN/CO_storageLinux.h new file mode 100644 index 00000000..ccee4749 --- /dev/null +++ b/socketCAN/CO_storageLinux.h @@ -0,0 +1,135 @@ +/** + * CANopen data storage object for Linux + * + * @file CO_storageLinux.h + * @ingroup CO_storageLinux + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CO_STORAGE_LINUX_H +#define CO_STORAGE_LINUX_H + +#include "301/CO_storage.h" +#include + +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_storageLinux Data storage with Linux + * @ingroup CO_socketCAN + * @{ + * + * Data initialize, store and restore functions with Linux, see @ref CO_storage + */ + + +/** + * Initialize / add one entry into data storage object (Linux specific) + * + * This function configures newEntry and calls @ref CO_storage_entry_init(). + * Then reads data from file, verifies and writes them to addr. + * + * @param storage Data storage object. + * @param newEntry Data storage object for one entry. It will be configured and + * must exist permanently. + * @param addr Address of data to store + * @param len Length of data to store + * @param filename Name of the file, where data are stored. + * @param subIndexOD Sub index in OD 1010 and 1011 ,see @ref CO_storage_entry_t + * + * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if memory can not be initialized, + * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY. + */ +CO_ReturnError_t CO_storageLinux_entry_init(CO_storage_t *storage, + CO_storage_entry_t *newEntry, + void *addr, + OD_size_t len, + char *filename, + uint8_t subIndexOD); + + +/** + * Object for automatic data storage + */ +typedef struct { + /** Address of data to store */ + void *addr; + /** Length of data to store */ + OD_size_t len; + /** CRC checksum of the data stored previously. */ + uint16_t crc; + /** Pointer to file opened by @ref CO_storageLinux_auto_init() */ + FILE *fp; +} CO_storageLinux_auto_t; + + +/** + * Initialize automatic storage with Linux + * + * Function in combination with @ref CO_storageLinux_auto_process() are + * standalone functions. They are used for automatic data storage. + * + * This function configures storageAuto, then reads data from file. If data are + * valid, then it writes them to addr. Function also open file pointer for + * writing and keeps it open. + * + * @param storageAuto This object will be initialized. + * @param addr Address of data to store + * @param len Length of data to store + * @param filename Name of the file, where data are stored. + * + * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if memory can not be initialized, + * CO_ERROR_ILLEGAL_ARGUMENT, if file can not be opened for writing. + */ +CO_ReturnError_t CO_storageLinux_auto_init(CO_storageLinux_auto_t *storageAuto, + void *addr, + OD_size_t len, + char *filename); + + +/** + * Automatically save data if differs from previous call. + * + * Should be called cyclically by program. Each interval it verifies, if crc + * checksum of data differs previous checksum. If it does, data are saved into + * file, opened by CO_storageLinux_auto_init(). + * + * @param storageAuto This object + * @param closeFile If true, then data will be stored regardless interval and + * file will be closed. Use on end of program. + * + * @return true, if data are unchanged or saved successfully. + */ +bool_t CO_storageLinux_auto_process(CO_storageLinux_auto_t *storageAuto, + bool_t closeFile); + +/** @} */ /* CO_storageLinux */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +#endif /* CO_STORAGE_LINUX_H */ From 464a856a3f13417769f0f36eba3ce2901df381f1 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 25 Jan 2021 12:52:52 +0100 Subject: [PATCH 150/520] 301/CO_time.c updated to newOD. Some principles changed. --- 301/CO_Emergency.h | 6 +- 301/CO_TIME.c | 268 +++++++++++++++++++---------------- 301/CO_TIME.h | 200 +++++++++++++------------- 301/CO_config.h | 2 + CANopen.c | 17 ++- example/CO_driver_target.h | 3 +- socketCAN/CO_driver_target.h | 4 +- socketCAN/CO_main_basic.c | 15 ++ 8 files changed, 281 insertions(+), 234 deletions(-) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index c59df371..dc67e6f0 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -198,8 +198,6 @@ typedef enum { CO_EMC_SYNC_DATA_LENGTH = 0x8240U, /** 0x8250, RPDO timeout */ CO_EMC_RPDO_TIMEOUT = 0x8250U, - /** 0x8260, Unexpected TIME data length */ - CO_EMC_TIME_DATA_LENGTH = 0x8260U, /** 0x90xx, External Error */ CO_EMC_EXTERNAL_ERROR = 0x9000U, /** 0xF0xx, Additional Functions */ @@ -267,8 +265,8 @@ typedef enum { CO_EM_NMT_WRONG_COMMAND = 0x08U, /** 0x09, communication, info, TIME message timeout */ CO_EM_TIME_TIMEOUT = 0x09U, - /** 0x0A, communication, info, Unexpected TIME data length */ - CO_EM_TIME_LENGTH = 0x0AU, + /** 0x0A, communication, info, (unused) */ + CO_EM_0A_unused = 0x0AU, /** 0x0B, communication, info, (unused) */ CO_EM_0B_unused = 0x0BU, /** 0x0C, communication, info, (unused) */ diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 403a9fb6..1dd02973 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -25,188 +25,212 @@ #include -#include "301/CO_SDOserver.h" -#include "301/CO_Emergency.h" -#include "301/CO_NMT_Heartbeat.h" #include "301/CO_TIME.h" #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE -#define DIV_ROUND_UP(_n, _d) (((_n) + (_d) - 1) / (_d)) - /* * Read received message from CAN module. * * Function will be called (by CAN receive interrupt) every time, when CAN * message with correct identifier will be received. */ -static void CO_TIME_receive(void *object, void *msg){ - CO_TIME_t *TIME; - CO_NMT_internalState_t operState; +static void CO_TIME_receive(void *object, void *msg) { + CO_TIME_t *TIME = object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); - TIME = (CO_TIME_t*)object; /* this is the correct pointer type of the first argument */ - operState = *TIME->operatingState; - - if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){ - // Process Time from msg buffer - memcpy(&TIME->Time.ullValue, data, DLC); + if (DLC == CO_TIME_MSG_LENGTH) { + memcpy(TIME->timeStamp, data, sizeof(TIME->timeStamp)); CO_FLAG_SET(TIME->CANrxNew); #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles TIME. */ - if(TIME->pFunctSignalPre != NULL) { + /* Optional signal to RTOS, which can resume task, which handles TIME.*/ + if (TIME->pFunctSignalPre != NULL) { TIME->pFunctSignalPre(TIME->functSignalObjectPre); } #endif } - else{ - TIME->receiveError = (uint16_t)DLC; - } } -/******************************************************************************/ -CO_ReturnError_t CO_TIME_init( - CO_TIME_t *TIME, - CO_EM_t *em, - CO_SDO_t *SDO, - CO_NMT_internalState_t *operatingState, - uint32_t COB_ID_TIMEMessage, - uint32_t TIMECyclePeriod, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - /* verify arguments */ - if(TIME==NULL || em==NULL || SDO==NULL || operatingState==NULL || - CANdevRx==NULL || CANdevTx==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; +#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC +/* + * Custom function for writing OD object "COB-ID time stamp" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static OD_size_t OD_write_1012(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + /* "count" is already verified in *_init() function */ + if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; } - /* Configure object variables */ - TIME->isConsumer = (COB_ID_TIMEMessage&0x80000000L) ? true : false; - TIME->isProducer = (COB_ID_TIMEMessage&0x40000000L) ? true : false; - TIME->COB_ID = COB_ID_TIMEMessage&0x7FF; // 11 bit ID + CO_TIME_t *TIME = stream->object; + *returnCode = ODR_OK; - TIME->periodTime = TIMECyclePeriod; - TIME->periodTimeoutTime = TIMECyclePeriod / 2 * 3; - /* overflow? */ - if(TIME->periodTimeoutTime < TIMECyclePeriod) - TIME->periodTimeoutTime = 0xFFFFFFFFL; + /* update object */ + uint32_t cobIdTimeStamp = CO_getUint32(buf); + TIME->isConsumer = (cobIdTimeStamp & 0x80000000L) != 0; + TIME->isProducer = (cobIdTimeStamp & 0x40000000L) != 0; - CO_FLAG_CLEAR(TIME->CANrxNew); - TIME->timer = 0; - TIME->receiveError = 0U; + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); +} +#endif - TIME->em = em; - TIME->operatingState = operatingState; -#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE - TIME->pFunctSignalPre = NULL; - TIME->functSignalObjectPre = NULL; +CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, + OD_entry_t *OD_1012_cobIdTimeStamp, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, #endif + uint32_t *errInfo) +{ + /* verify arguments */ + if (TIME == NULL || OD_1012_cobIdTimeStamp == NULL || CANdevRx == NULL +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER + || CANdevTx == NULL +#endif + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + memset(TIME, 0, sizeof(CO_TIME_t)); + + /* get parameters from object dictionary and configure extension */ + uint32_t cobIdTimeStamp; + ODR_t odRet = OD_get_u32(OD_1012_cobIdTimeStamp, 0, &cobIdTimeStamp, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1012_cobIdTimeStamp); + return CO_ERROR_OD_PARAMETERS; + } +#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC + TIME->OD_1012_extension.object = TIME; + TIME->OD_1012_extension.read = OD_readOriginal; + TIME->OD_1012_extension.write = OD_write_1012; + OD_extension_init(OD_1012_cobIdTimeStamp, &TIME->OD_1012_extension); +#endif + + /* Configure object variables */ + uint16_t cobId = cobIdTimeStamp & 0x7FF; + TIME->isConsumer = (cobIdTimeStamp & 0x80000000L) != 0; + TIME->isProducer = (cobIdTimeStamp & 0x40000000L) != 0; + CO_FLAG_CLEAR(TIME->CANrxNew); /* configure TIME consumer message reception */ - TIME->CANdevRx = CANdevRx; - TIME->CANdevRxIdx = CANdevRxIdx; if (TIME->isConsumer) { - ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - TIME->COB_ID, /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void*)TIME, /* object passed to receive function */ - CO_TIME_receive); /* this function will process received message */ + CO_ReturnError_t ret = CO_CANrxBufferInit( + CANdevRx, /* CAN device */ + CANdevRxIdx, /* rx buffer index */ + cobId, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)TIME, /* object passed to receive function */ + CO_TIME_receive);/*this function will process received message*/ + if (ret != CO_ERROR_NO) + return ret; } +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER /* configure TIME producer message transmission */ TIME->CANdevTx = CANdevTx; - TIME->CANdevTxIdx = CANdevTxIdx; - if (TIME->isProducer) { - TIME->TXbuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - TIME->COB_ID, /* CAN identifier */ - 0, /* rtr */ - TIME_MSG_LENGTH, /* number of data bytes */ - 0); /* synchronous message flag bit */ - - if (TIME->TXbuff == NULL) { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } + TIME->CANtxBuff = CO_CANtxBufferInit( + CANdevTx, /* CAN device */ + CANdevTxIdx, /* index of specific buffer inside CAN module */ + cobId, /* CAN identifier */ + 0, /* rtr */ + CO_TIME_MSG_LENGTH, /* number of data bytes */ + 0); /* synchronous message flag bit */ + + if (TIME->CANtxBuff == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; } +#endif - return ret; + return CO_ERROR_NO; } + #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE -/******************************************************************************/ -void CO_TIME_initCallbackPre( - CO_TIME_t *TIME, - void *object, - void (*pFunctSignalPre)(void *object)) +void CO_TIME_initCallbackPre(CO_TIME_t *TIME, + void *object, + void (*pFunctSignalPre)(void *object)) { - if(TIME != NULL){ + if (TIME != NULL) { TIME->functSignalObjectPre = object; TIME->pFunctSignalPre = pFunctSignalPre; } } #endif -/******************************************************************************/ -uint8_t CO_TIME_process( - CO_TIME_t *TIME, - uint32_t timeDifference_us) + +bool_t CO_TIME_process(CO_TIME_t *TIME, + bool_t NMTisPreOrOperational, + uint32_t timeDifference_us) { - uint8_t ret = 0; - uint32_t timerNew; - - if(*TIME->operatingState == CO_NMT_OPERATIONAL || *TIME->operatingState == CO_NMT_PRE_OPERATIONAL){ - /* update TIME timer, no overflow */ - uint32_t timeDifference_ms = DIV_ROUND_UP(timeDifference_us, 1000); - timerNew = TIME->timer + timeDifference_ms; - if(timerNew > TIME->timer) - TIME->timer = timerNew; - - /* was TIME just received */ - if(CO_FLAG_READ(TIME->CANrxNew)){ - TIME->timer = 0; - ret = 1; - CO_FLAG_CLEAR(TIME->CANrxNew); - } + bool_t timestampReceived = false; + + /* Was TIME stamp message just received */ + if (NMTisPreOrOperational && TIME->isConsumer) { + if(CO_FLAG_READ(TIME->CANrxNew)) { + uint32_t ms_swapped = CO_getUint32(&TIME->timeStamp[0]); + uint16_t days_swapped = CO_getUint16(&TIME->timeStamp[4]); + TIME->ms = CO_SWAP_32(ms_swapped) & 0x0FFFFFFF; + TIME->days = CO_SWAP_16(days_swapped); + TIME->residual_us = 0; + timestampReceived = true; - /* TIME producer */ - if(TIME->isProducer && TIME->periodTime){ - if(TIME->timer >= TIME->periodTime){ - TIME->timer = 0; - ret = 1; - memcpy(TIME->TXbuff->data, &TIME->Time.ullValue, TIME_MSG_LENGTH); - CO_CANsend(TIME->CANdevTx, TIME->TXbuff); - } + CO_FLAG_CLEAR(TIME->CANrxNew); } - - /* Verify TIME timeout if node is consumer */ - if(TIME->isConsumer && TIME->periodTime && TIME->timer > TIME->periodTimeoutTime - && *TIME->operatingState == CO_NMT_OPERATIONAL) - CO_errorReport(TIME->em, CO_EM_TIME_TIMEOUT, CO_EMC_COMMUNICATION, TIME->timer); } else { CO_FLAG_CLEAR(TIME->CANrxNew); } - /* verify error from receive function */ - if(TIME->receiveError != 0U){ - CO_errorReport(TIME->em, CO_EM_TIME_LENGTH, CO_EMC_TIME_DATA_LENGTH, (uint32_t)TIME->receiveError); - TIME->receiveError = 0U; + /* Update time */ + uint32_t ms = 0; + if (!timestampReceived && timeDifference_us > 0) { + uint32_t us = timeDifference_us + TIME->residual_us; + ms = us / 1000; + TIME->residual_us = us % 1000; + TIME->ms += ms; + if (TIME->ms >= (1000*60*60*24)) { + TIME->ms -= (1000*60*60*24); + TIME->days += 1; + } + } + +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER + if (NMTisPreOrOperational && TIME->isProducer + && TIME->producerInterval_ms > 0 + ) { + if (TIME->producerTimer_ms >= TIME->producerInterval_ms) { + TIME->producerTimer_ms -= TIME->producerInterval_ms; + + uint32_t ms_swapped = CO_SWAP_32(TIME->ms); + uint16_t days_swapped = CO_SWAP_16(TIME->days); + CO_setUint32(&TIME->CANtxBuff->data[0], ms_swapped); + CO_setUint16(&TIME->CANtxBuff->data[4], days_swapped); + CO_CANsend(TIME->CANdevTx, TIME->CANtxBuff); + } + else { + TIME->producerTimer_ms += ms; + } } + else { + TIME->producerTimer_ms = TIME->producerInterval_ms; + } +#endif - return ret; + return timestampReceived; } #endif /* (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE */ diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 44cdf3cb..7af36ba7 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -27,10 +27,13 @@ #define CO_TIME_H #include "301/CO_driver.h" +#include "301/CO_ODinterface.h" +#include "301/CO_NMT_Heartbeat.h" + /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (0) +#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE) #endif #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) || defined CO_DOXYGEN @@ -46,92 +49,73 @@ extern "C" { * * CANopen Time-stamp protocol. * - * For CAN identifier see #CO_Default_CAN_ID_t + * For CAN identifier see @ref CO_Default_CAN_ID_t * - * TIME message is used for time synchronization of the nodes on network. One node - * should be TIME producer, others can be TIME consumers. This is configured with - * COB_ID_TIME object 0x1012 : + * TIME message is used for time synchronization of the nodes on the network. + * One node should be TIME producer, others can be TIME consumers. This is + * configured by COB_ID_TIME object 0x1012: * * - bit 31 should be set for a consumer * - bit 30 should be set for a producer + * - bits 0..10 is CAN-ID, 0x100 by default * + * Current time can be read from @p CO_TIME_t->ms (milliseconds after midnight) + * and @p CO_TIME_t->days (number of days since January 1, 1984). Those values + * are updated on each @ref CO_TIME_process() call, either from internal timer + * or from received time stamp message. * - * ###TIME CONSUMER - * - * CO_TIME_init() configuration : - * - COB_ID_TIME : 0x80000100L -> TIME consumer with TIME_COB_ID = 0x100 - * - TIMECyclePeriod : - * - 0 -> no EMCY will be transmitted in case of TIME timeout - * - X -> an EMCY will be transmitted in case of TIME timeout (X * 1.5) ms - * - * Latest time value is stored in \p CO->TIME->Time variable. - * - * - * ###TIME PRODUCER - * - * CO_TIME_init() configuration : - * - COB_ID_TIME : 0x40000100L -> TIME producer with TIME_COB_ID = 0x100 - * - TIMECyclePeriod : Time transmit period in ms - * - * Write time value in \p CO->TIME->Time variable, this will be sent at TIMECyclePeriod. + * Current time can be set with @ref CO_TIME_set() function, which is necessary + * at least once, if time producer. If configured, time stamp message is + * send from @ref CO_TIME_process() in intervals specified by @ref CO_TIME_set() */ -#define TIME_MSG_LENGTH 6U - -#ifndef timeOfDay_t -typedef union { - unsigned long long ullValue; - struct { - unsigned long ms:28; - unsigned reserved:4; - unsigned days:16; - unsigned reserved2:16; - }; -} timeOfDay_t; -#endif -typedef timeOfDay_t TIME_OF_DAY; -typedef timeOfDay_t TIME_DIFFERENCE; +/** Length of the TIME message */ +#define CO_TIME_MSG_LENGTH 6 + /** * TIME producer and consumer object. */ -typedef struct{ - CO_EM_t *em; /**< From CO_TIME_init() */ - CO_NMT_internalState_t *operatingState; /**< From CO_TIME_init() */ +typedef struct { + /** Received timestamp data */ + uint8_t timeStamp[CO_TIME_MSG_LENGTH]; + /** Milliseconds after midnight */ + uint32_t ms; + /** Number of days since January 1, 1984 */ + uint16_t days; + /** Residual microseconds calculated inside CO_TIME_process() */ + uint16_t residual_us; /** True, if device is TIME consumer. Calculated from _COB ID TIME Message_ variable from Object dictionary (index 0x1012). */ - bool_t isConsumer; - /** True, if device is TIME producer. Calculated from _COB ID TIME Message_ + bool_t isConsumer; + /** True, if device is TIME producer. Calculated from _COB ID TIME Message_ variable from Object dictionary (index 0x1012). */ - bool_t isProducer; - uint16_t COB_ID; /**< From CO_TIME_init() */ - /** TIME period time in [milliseconds]. Set to TIME period to enable - timeout detection */ - uint32_t periodTime; - /** TIME period timeout time in [milliseconds]. - (periodTimeoutTime = periodTime * 1,5) */ - uint32_t periodTimeoutTime; + bool_t isProducer; /** Variable indicates, if new TIME message received from CAN bus */ - volatile void *CANrxNew; - /** Timer for the TIME message in [microseconds]. - Set to zero after received or transmitted TIME message */ - uint32_t timer; - /** Set to nonzero value, if TIME with wrong data length is received from CAN */ - uint16_t receiveError; + volatile void *CANrxNew; +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) || defined CO_DOXYGEN + /** Interval for time producer in milli seconds */ + uint32_t producerInterval_ms; + /** Sync producer timer */ + uint32_t producerTimer_ms; + /** From CO_TIME_init() */ + CO_CANmodule_t *CANdevTx; + /** CAN transmit buffer */ + CO_CANtx_t *CANtxBuff; +#endif #if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_TIME_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_TIME_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void *functSignalObjectPre; +#endif +#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN + /** Extension for OD object */ + OD_extension_t OD_1012_extension; #endif - CO_CANmodule_t *CANdevRx; /**< From CO_TIME_init() */ - uint16_t CANdevRxIdx; /**< From CO_TIME_init() */ - CO_CANmodule_t *CANdevTx; /**< From CO_TIME_init() */ - uint16_t CANdevTxIdx; /**< From CO_TIME_init() */ - CO_CANtx_t *TXbuff; /**< CAN transmit buffer */ - TIME_OF_DAY Time; -}CO_TIME_t; +} CO_TIME_t; + /** * Initialize TIME object. @@ -139,29 +123,26 @@ typedef struct{ * Function must be called in the communication reset section. * * @param TIME This object will be initialized. - * @param em Emergency object. - * @param SDO SDO server object. - * @param operatingState Pointer to variable indicating CANopen device NMT internal state. - * @param COB_ID_TIMEMessage Should be intialized with CO_CAN_ID_TIME_STAMP - * @param TIMECyclePeriod TIME period in ms (may also be used in consumer mode for timeout detection (1.5x period)). + * @param OD_1012_cobIdTimeStamp OD entry for 0x1012 -"COB-ID time stamp", + * entry is required. * @param CANdevRx CAN device for TIME reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for TIME transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. + * @param [out] errInfo Additional information in case of error, may be NULL. * - * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_TIME_init( - CO_TIME_t *TIME, - CO_EM_t *em, - CO_SDO_t *SDO, - CO_NMT_internalState_t *operatingState, - uint32_t COB_ID_TIMEMessage, - uint32_t TIMECyclePeriod, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx); +CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, + OD_entry_t *OD_1012_cobIdTimeStamp, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) || defined CO_DOXYGEN + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, +#endif + uint32_t *errInfo); + #if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** @@ -172,29 +153,56 @@ CO_ReturnError_t CO_TIME_init( * Callback is called after TIME message is received from the CAN bus. * * @param TIME This object. - * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignalPre(). * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_TIME_initCallbackPre( - CO_TIME_t *TIME, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_TIME_initCallbackPre(CO_TIME_t *TIME, + void *object, + void (*pFunctSignalPre)(void *object)); #endif + /** - * Process TIME communication. + * Set current time * - * Function must be called cyclically. + * @param TIME This object. + * @param ms Milliseconds after midnight + * @param days Number of days since January 1, 1984 + * @param producerInterval_ms Interval time for time producer in milliseconds + */ +static inline void CO_TIME_set(CO_TIME_t *TIME, + uint32_t ms, + uint16_t days, + uint32_t producerInterval_ms) +{ + if (TIME != NULL) { + TIME->residual_us = 0; + TIME->ms = ms; + TIME->days = days; + TIME->producerTimer_ms = TIME->producerInterval_ms =producerInterval_ms; + } +} + + +/** + * Process TIME object. + * + * Function must be called cyclically. It updates internal time from received + * time stamp message or from timeDifference_us. It also sends produces + * timestamp message, if producer and producerInterval_ms is set. * * @param TIME This object. - * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. + * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or + * NMT_OPERATIONAL state. * - * @return 0: No special meaning. - * @return 1: New TIME message recently received (consumer) / transmited (producer). + * @return True if new TIME stamp message recently received (consumer). */ -uint8_t CO_TIME_process( - CO_TIME_t *TIME, - uint32_t timeDifference_us); +bool_t CO_TIME_process(CO_TIME_t *TIME, + bool_t NMTisPreOrOperational, + uint32_t timeDifference_us); + /** @} */ /* CO_TIME */ diff --git a/301/CO_config.h b/301/CO_config.h index 701be253..4d44005c 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -401,6 +401,8 @@ extern "C" { * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received TIME CAN message. * Callback is configured by CO_TIME_initCallbackPre(). + * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration - writing to + * object 0x1012 enables / disables time producer or consumer. */ #ifdef CO_DOXYGEN #define CO_CONFIG_TIME (0) diff --git a/CANopen.c b/CANopen.c index e44aaba1..e7f1da04 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1067,7 +1067,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, /* SDOserver */ if (CO_GET_CNT(SDO_SRV) > 0) { - OD_entry_t *SDOsrvPar = OD_GET(H1200,OD_H1200_SDO_SERVER_1_PARAM); + OD_entry_t *SDOsrvPar = OD_GET(H1200, OD_H1200_SDO_SERVER_1_PARAM); for (int16_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { err = CO_SDOserver_init(&co->SDOserver[i], od, @@ -1085,7 +1085,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE if (CO_GET_CNT(SDO_CLI) > 0) { - OD_entry_t *SDOcliPar = OD_GET(H1280,OD_H1280_SDO_CLIENT_1_PARAM); + OD_entry_t *SDOcliPar = OD_GET(H1280, OD_H1280_SDO_CLIENT_1_PARAM); for (int16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { err = CO_SDOclient_init(&co->SDOclient[i], od, @@ -1104,15 +1104,14 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE if (CO_GET_CNT(TIME) == 1) { err = CO_TIME_init(co->TIME, - em, - co->SDO[0], - &co->NMT->operatingState, - OD_COB_ID_TIME, - 0, + OD_GET(H1012, OD_H1012_COBID_TIME), co->CANmodule, CO_GET_CO(RX_IDX_TIME), +#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER co->CANmodule, - CO_GET_CO(TX_IDX_TIME)); + CO_GET_CO(TX_IDX_TIME), +#endif + errInfo); if (err) return err; } #endif @@ -1398,7 +1397,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE if (CO_GET_CNT(TIME) == 1) { - CO_TIME_process(co->TIME, timeDifference_us); + CO_TIME_process(co->TIME, NMTisPreOrOperational, timeDifference_us); } #endif diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index d31025f9..4aabcb21 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -95,7 +95,8 @@ extern "C" { #ifndef CO_CONFIG_TIME #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE) + CO_CONFIG_FLAG_CALLBACK_PRE | \ + CO_CONFIG_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SYNC diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 9003dad3..b1febbce 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -55,7 +55,6 @@ extern "C" { /* TODO some parts are disabled in non-finished pre-release */ #define CO_CONFIG_HB_CONS (0) -#define CO_CONFIG_TIME (0) #define CO_CONFIG_SYNC (0) #define CO_CONFIG_PDO (0) #define CO_CONFIG_TRACE (0) @@ -119,7 +118,8 @@ extern "C" { #ifndef CO_CONFIG_TIME #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED) + CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ + CO_CONFIG_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SYNC diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 8c2d1b62..dbdd227c 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -90,6 +90,10 @@ #ifndef GATEWAY_ENABLE #define GATEWAY_ENABLE true #endif +/* Interval for time stamp message in milliseconds */ +#ifndef TIME_STAMP_INTERVAL_MS +#define TIME_STAMP_INTERVAL_MS 10000 +#endif /* CANopen object */ CO_t *CO = NULL; @@ -491,6 +495,16 @@ int main (int argc, char *argv[]) { exit(EXIT_FAILURE); } + /* get current time for CO_TIME_set(), since January 1, 1984, UTC. */ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + log_printf(LOG_CRIT, DBG_GENERAL, "clock_gettime(main)", 0); + exit(EXIT_FAILURE); + } + uint16_t time_days = (uint16_t)(ts.tv_sec / (24 * 60 * 60)); + time_days -= 5113; /* difference between Unix epoch and CANopen Epoch */ + uint32_t time_ms = (uint32_t)(ts.tv_sec % (24 * 60 * 60)) * 1000; + time_ms += ts.tv_nsec / 1000000; /* Create epoll functions */ err = CO_epoll_create(&epMain, MAIN_THREAD_INTERVAL_US); @@ -625,6 +639,7 @@ int main (int argc, char *argv[]) { /* First time only initialization. */ if(firstRun) { firstRun = false; + CO_TIME_set(CO->TIME, time_ms, time_days, TIME_STAMP_INTERVAL_MS); #ifndef CO_SINGLE_THREAD /* Create rt_thread and set priority */ if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) { From 8cff68f196de796874f320a52201dd0ffe31b21b Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 25 Jan 2021 21:24:21 +0100 Subject: [PATCH 151/520] CO_config.h: use global macros for common definitions --- 301/CO_Emergency.h | 4 ++- 301/CO_NMT_Heartbeat.h | 3 +- 301/CO_PDO.h | 5 +++- 301/CO_SDOserver.h | 5 +++- 301/CO_SYNC.h | 6 +++- 301/CO_TIME.h | 4 ++- 301/CO_config.h | 45 ++++++++++++++++++++--------- 301/CO_driver.h | 21 ++++++++++---- 303/CO_LEDs.h | 3 +- 305/CO_LSS.h | 3 +- example/CO_driver_target.h | 55 ++++++++++++++++++------------------ socketCAN/CO_driver_target.h | 49 +++++++++++++++----------------- 12 files changed, 122 insertions(+), 81 deletions(-) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index dc67e6f0..41c740fc 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -32,7 +32,9 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_EM #define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ - CO_CONFIG_EM_HISTORY) + CO_CONFIG_EM_HISTORY | \ + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_EM_ERR_STATUS_BITS_COUNT #define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 605caa50..b85a3a3a 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -32,7 +32,8 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT (0) +#define CO_CONFIG_NMT (CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifdef __cplusplus diff --git a/301/CO_PDO.h b/301/CO_PDO.h index be3f9156..9faaed60 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -36,7 +36,10 @@ #ifndef CO_CONFIG_PDO #define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ CO_CONFIG_TPDO_ENABLE | \ - CO_CONFIG_PDO_SYNC_ENABLE) + CO_CONFIG_PDO_SYNC_ENABLE | \ + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #if ((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) || defined CO_DOXYGEN diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 76d8bcbd..3daa6e8a 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -31,7 +31,10 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_SDO_SRV -#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED) +#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE #define CO_CONFIG_SDO_SRV_BUFFER_SIZE 32 diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 47828aee..4c79bc81 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -30,7 +30,11 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER) +#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ + CO_CONFIG_SYNC_PRODUCER | \ + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 7af36ba7..97176be2 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -33,7 +33,9 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE) +#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) || defined CO_DOXYGEN diff --git a/301/CO_config.h b/301/CO_config.h index 4d44005c..3e594dc3 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -98,6 +98,21 @@ extern "C" { * This flag is common to multiple configuration macros. */ #define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000 + +/** This flag may be set globally to @ref CO_CONFIG_FLAG_CALLBACK_PRE */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0) +#endif + +/** This flag may be set globally to @ref CO_CONFIG_FLAG_TIMERNEXT */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT (0) +#endif + +/** This flag may be set globally to (0) */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC CO_CONFIG_FLAG_OD_DYNAMIC +#endif /** @} */ /* CO_STACK_CONFIG_COMMON */ @@ -120,7 +135,7 @@ extern "C" { * inside CO_NMT_process(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_NMT (0) +#define CO_CONFIG_NMT (CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #define CO_CONFIG_NMT_CALLBACK_CHANGE 0x01 #define CO_CONFIG_NMT_MASTER 0x02 @@ -129,11 +144,6 @@ extern "C" { * Configuration of @ref CO_HBconsumer * * Possible flags, can be ORed: - * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing - * received heartbeat CAN message. - * Callback is configured by CO_HBconsumer_initCallbackPre(). - * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable - * inside CO_HBconsumer_process(). * - CO_CONFIG_HB_CONS_ENABLE - Enable heartbeat consumer. * - CO_CONFIG_HB_CONS_CALLBACK_CHANGE - Enable custom common callback after NMT * state of the monitored node changes. Callback is configured by @@ -146,11 +156,16 @@ extern "C" { * CO_HBconsumer_initCallbackRemoteReset() functions. * - CO_CONFIG_HB_CONS_QUERY_FUNCT - Enable functions for query HB state or * NMT state of the specific monitored node. + * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing + * received heartbeat CAN message. + * Callback is configured by CO_HBconsumer_initCallbackPre(). + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_HBconsumer_process(). * Note that CO_CONFIG_HB_CONS_CALLBACK_CHANGE and * CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE) +#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #define CO_CONFIG_HB_CONS_ENABLE 0x01 #define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x02 @@ -194,7 +209,7 @@ extern "C" { * inside CO_EM_process(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #define CO_CONFIG_EM_PRODUCER 0x01 #define CO_CONFIG_EM_PROD_CONFIGURABLE 0x02 @@ -326,7 +341,7 @@ extern "C" { * servers (Writing to object 0x1201+ re-configures the additional server). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED) +#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_SDO_SRV_SEGMENTED 0x02 #define CO_CONFIG_SDO_SRV_BLOCK 0x04 @@ -405,7 +420,7 @@ extern "C" { * object 0x1012 enables / disables time producer or consumer. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_TIME (0) +#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_TIME_ENABLE 0x01 #define CO_CONFIG_TIME_PRODUCER 0x02 @@ -427,9 +442,10 @@ extern "C" { * Callback is configured by CO_SYNC_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_SYNC_process(). + * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of SYNC. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER) +#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_SYNC_ENABLE 0x01 #define CO_CONFIG_SYNC_PRODUCER 0x02 @@ -450,9 +466,10 @@ extern "C" { * Callback is configured by CO_RPDO_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_TPDO_process(). + * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of PDO. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE) +#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_RPDO_ENABLE 0x01 #define CO_CONFIG_TPDO_ENABLE 0x02 @@ -494,7 +511,7 @@ extern "C" { * inside CO_NMT_process(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE) +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #define CO_CONFIG_LEDS_ENABLE 0x01 /** @} */ /* CO_STACK_CONFIG_LEDS */ @@ -574,7 +591,7 @@ extern "C" { * Callback is configured by CO_LSSmaster_initCallbackPre(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE) +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) #endif #define CO_CONFIG_LSS_SLAVE 0x01 #define CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND 0x02 diff --git a/301/CO_driver.h b/301/CO_driver.h index 98da8d1c..e09583fe 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -35,13 +35,24 @@ extern "C" { #endif -#ifdef CO_DEBUG_COMMON -#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_CLIENT - #define CO_DEBUG_SDO_CLIENT(msg) CO_DEBUG_COMMON(msg) +/* Stack configuration default global values. + * For more information see file CO_config.h. */ +#ifndef CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE + #define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0) +#endif +#ifndef CO_CONFIG_GLOBAL_FLAG_TIMERNEXT + #define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT (0) #endif -#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_SERVER - #define CO_DEBUG_SDO_SERVER(msg) CO_DEBUG_COMMON(msg) +#ifndef CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC + #define CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC CO_CONFIG_FLAG_OD_DYNAMIC #endif +#ifdef CO_DEBUG_COMMON + #if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_CLIENT + #define CO_DEBUG_SDO_CLIENT(msg) CO_DEBUG_COMMON(msg) + #endif + #if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_SERVER + #define CO_DEBUG_SDO_SERVER(msg) CO_DEBUG_COMMON(msg) + #endif #endif /** diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index 75364f88..d8937f91 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -31,7 +31,8 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_LEDS -#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE) +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN diff --git a/305/CO_LSS.h b/305/CO_LSS.h index b1d62748..70d6ebb3 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -31,7 +31,8 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE) +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE \ + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) #endif #if ((CO_CONFIG_LSS) & (CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER)) || defined CO_DOXYGEN diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 4aabcb21..5b50dab9 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -28,7 +28,7 @@ /* This file contains device and application specific definitions. * It is included from CO_driver.h, which contains documentation - * for definitions below. */ + * for common definitions below. */ #include #include @@ -42,21 +42,24 @@ extern "C" { #endif -/* Stack configuration override default values. +/* Stack configuration override default values (all enabled in this example). * For more information see file CO_config.h. */ +#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE CO_CONFIG_FLAG_CALLBACK_PRE +#define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT CO_CONFIG_FLAG_TIMERNEXT + #ifndef CO_CONFIG_NMT #define CO_CONFIG_NMT (CO_CONFIG_NMT_CALLBACK_CHANGE | \ CO_CONFIG_NMT_MASTER | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_HB_CONS #define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ CO_CONFIG_HB_CONS_CALLBACK_MULTI | \ CO_CONFIG_HB_CONS_QUERY_FUNCT | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_EM @@ -66,16 +69,16 @@ extern "C" { CO_CONFIG_EM_HISTORY | \ CO_CONFIG_EM_STATUS_BITS | \ CO_CONFIG_EM_CONSUMER | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SDO_SRV #define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ CO_CONFIG_SDO_SRV_BLOCK | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_FLAG_OD_DYNAMIC) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE @@ -87,23 +90,24 @@ extern "C" { CO_CONFIG_SDO_CLI_SEGMENTED | \ CO_CONFIG_SDO_CLI_BLOCK | \ CO_CONFIG_SDO_CLI_LOCAL | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_FLAG_OD_DYNAMIC) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_TIME #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_OD_DYNAMIC) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SYNC #define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ CO_CONFIG_SYNC_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_PDO @@ -112,13 +116,8 @@ extern "C" { CO_CONFIG_PDO_SYNC_ENABLE | \ CO_CONFIG_RPDO_CALLS_EXTENSION | \ CO_CONFIG_TPDO_CALLS_EXTENSION | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT) -#endif - -#ifndef CO_CONFIG_LEDS -#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_GFC @@ -132,8 +131,8 @@ extern "C" { CO_CONFIG_SRDO_CHECK_TX | \ CO_CONFIG_RSRDO_CALLS_EXTENSION | \ CO_CONFIG_TSRDO_CALLS_EXTENSION | \ - CO_CONFIG_FLAG_CALLBACK_PRE | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SRDO_MINIMUM_DELAY @@ -144,7 +143,7 @@ extern "C" { #define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ CO_CONFIG_LSS_MASTER | \ - CO_CONFIG_FLAG_CALLBACK_PRE) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) #endif #ifndef CO_CONFIG_GTW diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index b1febbce..bdd06175 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -63,23 +63,24 @@ extern "C" { /* Stack configuration override default values. * For more information see file CO_config.h. */ #ifdef CO_SINGLE_THREAD -#define CO_CONFIG_FLAG_CALLBACK_PRE_USED 0 +#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE 0 #else -#define CO_CONFIG_FLAG_CALLBACK_PRE_USED CO_CONFIG_FLAG_CALLBACK_PRE +#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE CO_CONFIG_FLAG_CALLBACK_PRE #endif +#define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT CO_CONFIG_FLAG_TIMERNEXT #ifndef CO_CONFIG_NMT #define CO_CONFIG_NMT (CO_CONFIG_NMT_CALLBACK_CHANGE | \ CO_CONFIG_NMT_MASTER | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_HB_CONS #define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_EM @@ -89,16 +90,16 @@ extern "C" { CO_CONFIG_EM_HISTORY | \ CO_CONFIG_EM_STATUS_BITS | \ CO_CONFIG_EM_CONSUMER | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_SDO_SRV #define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ CO_CONFIG_SDO_SRV_BLOCK | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_FLAG_OD_DYNAMIC) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE @@ -110,23 +111,24 @@ extern "C" { CO_CONFIG_SDO_CLI_SEGMENTED | \ CO_CONFIG_SDO_CLI_BLOCK | \ CO_CONFIG_SDO_CLI_LOCAL | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_TIMERNEXT | \ - CO_CONFIG_FLAG_OD_DYNAMIC) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_TIME #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_OD_DYNAMIC) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SYNC #define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ CO_CONFIG_SYNC_PRODUCER | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_PDO @@ -135,20 +137,15 @@ extern "C" { CO_CONFIG_PDO_SYNC_ENABLE | \ CO_CONFIG_RPDO_CALLS_EXTENSION | \ CO_CONFIG_TPDO_CALLS_EXTENSION | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED | \ - CO_CONFIG_FLAG_TIMERNEXT) -#endif - -#ifndef CO_CONFIG_LEDS -#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | \ - CO_CONFIG_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_LSS #define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ CO_CONFIG_LSS_MASTER | \ - CO_CONFIG_FLAG_CALLBACK_PRE_USED) + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) #endif #ifndef CO_CONFIG_GTW From 49f7c8011418600a1d7c46049d460c328d5819a4 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 30 Jan 2021 14:40:27 +0100 Subject: [PATCH 152/520] Heartbeat consumer updated to newOD --- 301/CO_Emergency.c | 4 +- 301/CO_HBconsumer.c | 212 +++++++++++++++++++---------------- 301/CO_HBconsumer.h | 123 ++++++++++---------- 301/CO_config.h | 11 +- 305/CO_LSS.h | 2 +- CANopen.c | 8 +- CANopen.h | 2 + example/CO_driver_target.h | 3 +- socketCAN/CO_driver_target.h | 4 +- socketCAN/CO_main_basic.c | 12 +- 10 files changed, 206 insertions(+), 175 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 8958108f..148feab9 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -409,7 +409,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, odRet = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); if (odRet != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { if (errInfo != NULL) *errInfo = OD_getIndex(OD_1014_cobIdEm); - return CO_ERROR_OD_PARAMETERS; + /* don't break a program, if only value of a parameter is wrong */ + if (odRet != ODR_OK) + return CO_ERROR_OD_PARAMETERS; } #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index e2b09f62..9df780f6 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -4,7 +4,7 @@ * @file CO_HBconsumer.c * @ingroup CO_HBconsumer * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2021 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -23,10 +23,6 @@ * limitations under the License. */ -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" -#include "301/CO_Emergency.h" -#include "301/CO_NMT_Heartbeat.h" #include "301/CO_HBconsumer.h" #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE @@ -37,6 +33,10 @@ #error CO_CONFIG_HB_CONS_CALLBACK_CHANGE and CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously! #endif +#if CO_CONFIG_HB_CONS_SIZE < 1 || CO_CONFIG_HB_CONS_SIZE > 127 +#error CO_CONFIG_HB_CONS_SIZE is not correct +#endif + /* * Read received message from CAN module. * @@ -44,125 +44,148 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_HBcons_receive(void *object, void *msg){ - CO_HBconsNode_t *HBconsNode; +static void CO_HBcons_receive(void *object, void *msg) { + CO_HBconsNode_t *HBconsNode = object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); - HBconsNode = (CO_HBconsNode_t*) object; /* this is the correct pointer type of the first argument */ - - /* verify message length */ - if(DLC == 1){ + if (DLC == 1) { /* copy data and set 'new message' flag. */ HBconsNode->NMTstate = (CO_NMT_internalState_t)data[0]; CO_FLAG_SET(HBconsNode->CANrxNew); - } - #if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles HBcons. */ - if(HBconsNode->pFunctSignalPre != NULL) { - HBconsNode->pFunctSignalPre(HBconsNode->functSignalObjectPre); - } + /* Optional signal to RTOS, which can resume task, which handles HBcons. */ + if (HBconsNode->pFunctSignalPre != NULL) { + HBconsNode->pFunctSignalPre(HBconsNode->functSignalObjectPre); + } #endif + } } /* - * OD function for accessing _Consumer Heartbeat Time_ (index 0x1016) from SDO server. + * Initialize one Heartbeat consumer entry + * + * This function is called from the @ref CO_HBconsumer_init() or when writing + * to OD entry 1016. * - * For more information see file CO_SDOserver.h. + * @param HBcons This object. + * @param idx index of the node in HBcons object + * @param nodeId see OD 0x1016 description + * @param consumerTime_ms in milliseconds. see OD 0x1016 description + * @return */ -static CO_SDO_abortCode_t CO_ODF_1016(CO_ODF_arg_t *ODF_arg) -{ - CO_HBconsumer_t *HBcons; - uint8_t NodeID; - uint16_t HBconsTime; - uint32_t value; - CO_ReturnError_t ret; - - if(ODF_arg->reading){ - return CO_SDO_AB_NONE; - } +static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, + uint8_t idx, + uint8_t nodeId, + uint16_t consumerTime_ms); - HBcons = (CO_HBconsumer_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - NodeID = (value >> 16U) & 0xFFU; - HBconsTime = value & 0xFFFFU; - if((value & 0xFF800000U) != 0){ - return CO_SDO_AB_PRAM_INCOMPAT; +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC +/* + * Custom function for writing OD object "Consumer heartbeat time" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static OD_size_t OD_write_1016(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + CO_HBconsumer_t *HBcons = stream->object; + + /* "count" is already verified in *_init() function */ + if (stream == NULL || buf == NULL || returnCode == NULL + || subIndex < 1 || subIndex > HBcons->numberOfMonitoredNodes + ) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; } - ret = CO_HBconsumer_initEntry(HBcons, ODF_arg->subIndex-1U, NodeID, HBconsTime); + uint32_t val = CO_getUint32(buf); + uint8_t nodeId = (val >> 16) & 0xFF; + uint16_t time = val & 0xFFFF; + CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, subIndex - 1, + nodeId, time); if (ret != CO_ERROR_NO) { - return CO_SDO_AB_PRAM_INCOMPAT; + *returnCode = ODR_PAR_INCOMPAT; + return 0; } - return CO_SDO_AB_NONE; + + /* write value to the original location in the Object Dictionary */ + *returnCode = ODR_OK; + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); } +#endif /******************************************************************************/ -CO_ReturnError_t CO_HBconsumer_init( - CO_HBconsumer_t *HBcons, - CO_EM_t *em, - CO_SDO_t *SDO, - const uint32_t HBconsTime[], - CO_HBconsNode_t monitoredNodes[], - uint8_t numberOfMonitoredNodes, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdxStart) +CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, + CO_EM_t *em, + OD_entry_t *OD_1016_HBcons, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdxStart, + uint32_t *errInfo) { - uint8_t i; - CO_ReturnError_t ret = CO_ERROR_NO; + ODR_t odRet; /* verify arguments */ - if(HBcons==NULL || em==NULL || SDO==NULL || HBconsTime==NULL || - monitoredNodes==NULL || CANdevRx==NULL){ + if (HBcons == NULL || em == NULL || OD_1016_HBcons == NULL + || CANdevRx == NULL + ) { return CO_ERROR_ILLEGAL_ARGUMENT; } /* Configure object variables */ + memset(HBcons, 0, sizeof(CO_HBconsumer_t)); HBcons->em = em; - HBcons->HBconsTime = HBconsTime; - HBcons->monitoredNodes = monitoredNodes; - HBcons->numberOfMonitoredNodes = numberOfMonitoredNodes; - HBcons->allMonitoredActive = false; - HBcons->allMonitoredOperational = CO_NMT_UNKNOWN; - HBcons->NMTisPreOrOperationalPrev = false; HBcons->CANdevRx = CANdevRx; HBcons->CANdevRxIdxStart = CANdevRxIdxStart; -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE - HBcons->pFunctSignalNmtChanged = NULL; -#endif - for(i=0; inumberOfMonitoredNodes; i++) { - uint8_t nodeId = (HBcons->HBconsTime[i] >> 16U) & 0xFFU; - uint16_t time = HBcons->HBconsTime[i] & 0xFFFFU; - ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE - HBcons->monitoredNodes[i].pFunctSignalPre = NULL; -#endif -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI - HBcons->monitoredNodes[i].pFunctSignalNmtChanged = NULL; - HBcons->monitoredNodes[i].pFunctSignalHbStarted = NULL; - HBcons->monitoredNodes[i].pFunctSignalTimeout = NULL; - HBcons->monitoredNodes[i].pFunctSignalRemoteReset = NULL; -#endif + /* get actual number of monitored nodes */ + HBcons->numberOfMonitoredNodes = + OD_1016_HBcons->subEntriesCount < CO_CONFIG_HB_CONS_SIZE ? + OD_1016_HBcons->subEntriesCount : CO_CONFIG_HB_CONS_SIZE; + + for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { + uint32_t val; + odRet = OD_get_u32(OD_1016_HBcons, i + 1, &val, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1016_HBcons); + return CO_ERROR_OD_PARAMETERS; + } + + uint8_t nodeId = (val >> 16) & 0xFF; + uint16_t time = val & 0xFFFF; + CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); + if (ret != CO_ERROR_NO) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1016_HBcons); + /* don't break a program, if only value of a parameter is wrong */ + if (ret != CO_ERROR_OD_PARAMETERS) + return ret; + } } - /* Configure Object dictionary entry at index 0x1016 */ - CO_OD_configure(SDO, OD_H1016_CONSUMER_HB_TIME, CO_ODF_1016, (void*)HBcons, 0, 0); + /* configure extension for OD */ +#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC + HBcons->OD_1016_extension.object = HBcons; + HBcons->OD_1016_extension.read = OD_readOriginal; + HBcons->OD_1016_extension.write = OD_write_1016; + odRet = OD_extension_init(OD_1016_HBcons, &HBcons->OD_1016_extension); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1016_HBcons); + return CO_ERROR_OD_PARAMETERS; + } +#endif - return ret; + return CO_ERROR_NO; } /******************************************************************************/ -CO_ReturnError_t CO_HBconsumer_initEntry( - CO_HBconsumer_t *HBcons, - uint8_t idx, - uint8_t nodeId, - uint16_t consumerTime_ms) +static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, + uint8_t idx, + uint8_t nodeId, + uint16_t consumerTime_ms) { CO_ReturnError_t ret = CO_ERROR_NO; @@ -171,15 +194,12 @@ CO_ReturnError_t CO_HBconsumer_initEntry( return CO_ERROR_ILLEGAL_ARGUMENT; } - if((consumerTime_ms != 0) && (nodeId != 0)){ - uint8_t i; - /* there must not be more entries with same index and time different than zero */ - for(i = 0U; inumberOfMonitoredNodes; i++){ - uint32_t objectCopy = HBcons->HBconsTime[i]; - uint8_t NodeIDObj = (objectCopy >> 16U) & 0xFFU; - uint16_t HBconsTimeObj = objectCopy & 0xFFFFU; - if((idx != i) && (HBconsTimeObj != 0) && (nodeId == NodeIDObj)){ - ret = CO_ERROR_ILLEGAL_ARGUMENT; + /* verify for duplicate entries */ + if(consumerTime_ms != 0 && nodeId != 0) { + for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { + CO_HBconsNode_t node = HBcons->monitoredNodes[i]; + if(idx != i && node.time_us != 0 && node.nodeId == nodeId) { + ret = CO_ERROR_OD_PARAMETERS; } } } @@ -199,7 +219,7 @@ CO_ReturnError_t CO_HBconsumer_initEntry( CO_FLAG_CLEAR(monitoredNode->CANrxNew); /* is channel used */ - if (monitoredNode->nodeId && monitoredNode->time_us) { + if (monitoredNode->nodeId != 0 && monitoredNode->time_us != 0) { COB_ID = monitoredNode->nodeId + CO_CAN_ID_HEARTBEAT; monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; } @@ -246,11 +266,13 @@ void CO_HBconsumer_initCallbackPre( /******************************************************************************/ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, + uint8_t idx, void *object, void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t NMTstate, void *object)) { + (void) idx; if (HBcons==NULL) { return; } @@ -349,7 +371,7 @@ void CO_HBconsumer_process( (void)timerNext_us; /* may be unused */ bool_t allMonitoredActiveCurrent = true; - uint8_t allMonitoredOperationalCurrent = CO_NMT_OPERATIONAL; + bool_t allMonitoredOperationalCurrent = true; if (NMTisPreOrOperational && HBcons->NMTisPreOrOperationalPrev) { for (uint8_t i=0; inumberOfMonitoredNodes; i++) { @@ -432,7 +454,7 @@ void CO_HBconsumer_process( allMonitoredActiveCurrent = false; } if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { - allMonitoredOperationalCurrent = CO_NMT_UNKNOWN; + allMonitoredOperationalCurrent = false; } #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI @@ -470,7 +492,7 @@ void CO_HBconsumer_process( } } allMonitoredActiveCurrent = false; - allMonitoredOperationalCurrent = CO_NMT_UNKNOWN; + allMonitoredOperationalCurrent = false; } /* Clear emergencies when all monitored nodes becomes active. diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 421032ff..73a5b096 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -4,7 +4,7 @@ * @file CO_HBconsumer.h * @ingroup CO_HBconsumer * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2021 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -27,10 +27,19 @@ #define CO_HB_CONS_H #include "301/CO_driver.h" +#include "301/CO_ODinterface.h" +#include "301/CO_NMT_Heartbeat.h" +#include "301/CO_Emergency.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE) +#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ + CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#endif +#ifndef CO_CONFIG_HB_CONS_SIZE +#define CO_CONFIG_HB_CONS_SIZE 8 #endif #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN @@ -52,10 +61,11 @@ extern "C" { * variable _allMonitoredOperational_ inside CO_HBconsumer_t is set to true. * Monitoring starts after the reception of the first HeartBeat (not bootup). * - * Heartbeat set up is done by writing to the OD registers 0x1016 or by using - * the function _CO_HBconsumer_initEntry()_ + * Heartbeat set up is done by writing to the OD registers 0x1016. + * To setup heartbeat consumer by application, use + * @code ODR_t odRet = OD_set_u32(entry, subIndex, val, false); @endcode * - * @see @ref CO_NMT_Heartbeat + * @see @ref CO_NMT_Heartbeat */ /** @@ -75,9 +85,9 @@ typedef enum { typedef struct { /** Node Id of the monitored node */ uint8_t nodeId; - /** Of the remote node (Heartbeat payload) */ + /** NMT state of the remote node (Heartbeat payload) */ CO_NMT_internalState_t NMTstate; - /** Current heartbeat state */ + /** Current heartbeat monitoring state of the remote node */ CO_HBconsumer_state_t HBstate; /** Time since last heartbeat received */ uint32_t timeoutTimer; @@ -87,9 +97,9 @@ typedef struct { volatile void *CANrxNew; #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_HBconsumer_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_HBconsumer_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void *functSignalObjectPre; #endif #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) \ || ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) \ @@ -101,7 +111,7 @@ typedef struct { /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t state, + CO_NMT_internalState_t NMTstate, void *object); /** Pointer to object */ void *pFunctSignalObjectNmtChanged; @@ -130,30 +140,40 @@ typedef struct { * Object is initilaized by CO_HBconsumer_init(). It contains an array of * CO_HBconsNode_t objects. */ -typedef struct{ - CO_EM_t *em; /**< From CO_HBconsumer_init() */ - const uint32_t *HBconsTime; /**< From CO_HBconsumer_init() */ - CO_HBconsNode_t *monitoredNodes; /**< From CO_HBconsumer_init() */ - uint8_t numberOfMonitoredNodes; /**< From CO_HBconsumer_init() */ - /** True, if all monitored nodes are active or no node is - monitored. Can be read by the application */ - bool_t allMonitoredActive; +typedef struct { + /** From CO_HBconsumer_init() */ + CO_EM_t *em; + /** Array of monitored nodes, maximum size CO_CONFIG_HB_CONS_SIZE */ + CO_HBconsNode_t monitoredNodes[CO_CONFIG_HB_CONS_SIZE]; + /** Actual number of monitored nodes, + * MIN(CO_CONFIG_HB_CONS_SIZE or number-of-array-elements-in-OD-0x1016) */ + uint8_t numberOfMonitoredNodes; + /** True, if all monitored nodes are active or no node is monitored. Can be + * read by the application */ + bool_t allMonitoredActive; /** True, if all monitored nodes are NMT operational or no node is - monitored. Can be read by the application */ - uint8_t allMonitoredOperational; - bool_t NMTisPreOrOperationalPrev; /**< previous state of var */ - CO_CANmodule_t *CANdevRx; /**< From CO_HBconsumer_init() */ - uint16_t CANdevRxIdxStart; /**< From CO_HBconsumer_init() */ + * monitored. Can be read by the application */ + bool_t allMonitoredOperational; + /** previous state of the variable */ + bool_t NMTisPreOrOperationalPrev; + /** From CO_HBconsumer_init() */ + CO_CANmodule_t *CANdevRx; + /** From CO_HBconsumer_init() */ + uint16_t CANdevRxIdxStart; +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN + /** Extension for OD object */ + OD_extension_t OD_1016_extension; +#endif #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) || defined CO_DOXYGEN /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t state, + CO_NMT_internalState_t NMTstate, void *object); /** Pointer to object */ void *pFunctSignalObjectNmtChanged; #endif -}CO_HBconsumer_t; +} CO_HBconsumer_t; /** @@ -163,47 +183,22 @@ typedef struct{ * * @param HBcons This object will be initialized. * @param em Emergency object. - * @param SDO SDO server object. - * @param HBconsTime Pointer to _Consumer Heartbeat Time_ array - * from Object Dictionary (index 0x1016). Size of array is equal to numberOfMonitoredNodes. - * @param monitoredNodes Pointer to the externaly defined array of the same size - * as numberOfMonitoredNodes. - * @param numberOfMonitoredNodes Total size of the above arrays. + * @param OD_1016_HBcons OD entry for 0x1016 - "Consumer heartbeat time", entry + * is required, IO extension will be applied. * @param CANdevRx CAN device for Heartbeat reception. - * @param CANdevRxIdxStart Starting index of receive buffer in the above CAN device. - * Number of used indexes is equal to numberOfMonitoredNodes. + * @param CANdevRxIdxStart Starting index of receive buffer in the above CAN + * device. Number of used indexes is equal to CO_CONFIG_HB_CONS_SIZE. + * @param [out] errInfo Additional information in case of error, may be NULL. * - * @return #CO_ReturnError_t CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_HBconsumer_init( - CO_HBconsumer_t *HBcons, - CO_EM_t *em, - CO_SDO_t *SDO, - const uint32_t HBconsTime[], - CO_HBconsNode_t monitoredNodes[], - uint8_t numberOfMonitoredNodes, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdxStart); +CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, + CO_EM_t *em, + OD_entry_t *OD_1016_HBcons, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdxStart, + uint32_t *errInfo); -/** - * Initialize one Heartbeat consumer entry - * - * Calling this function has the same affect as writing to the corresponding - * entries in the Object Dictionary (index 0x1016) - * @remark The values in the Object Dictionary must be set manually by the - * calling function so that heartbeat consumer behaviour matches the OD value. - * - * @param HBcons This object. - * @param idx index of the node in HBcons object - * @param nodeId see OD 0x1016 description - * @param consumerTime_ms in milliseconds. see OD 0x1016 description - * @return - */ -CO_ReturnError_t CO_HBconsumer_initEntry( - CO_HBconsumer_t *HBcons, - uint8_t idx, - uint8_t nodeId, - uint16_t consumerTime_ms); #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** @@ -241,12 +236,10 @@ void CO_HBconsumer_initCallbackPre( */ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) || defined CO_DOXYGEN uint8_t idx, -#endif void *object, void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t state, + CO_NMT_internalState_t NMTstate, void *object)); #endif diff --git a/301/CO_config.h b/301/CO_config.h index 3e594dc3..954cda47 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -161,11 +161,14 @@ extern "C" { * Callback is configured by CO_HBconsumer_initCallbackPre(). * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_HBconsumer_process(). - * Note that CO_CONFIG_HB_CONS_CALLBACK_CHANGE and + * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of monitored + * nodes (Writing to object 0x1016 re-configures the monitored nodes). + * + * @warning CO_CONFIG_HB_CONS_CALLBACK_CHANGE and * CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) +#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_HB_CONS_ENABLE 0x01 #define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x02 @@ -174,7 +177,9 @@ extern "C" { /** * Number of heartbeat consumer objects, where each object corresponds to one - * sub-index in OD object 0x1016, "Consumer heartbeat time". + * sub-index in OD object 0x1016, "Consumer heartbeat time". Each heartbeat + * consumer uses own CANrx object. Actual number of heartbeat consumer objects + * may be lower, if OD variable 1016 has lower number of sub entries. * * If heartbeat consumer is enabled, then valid values are 1 to 127. */ diff --git a/305/CO_LSS.h b/305/CO_LSS.h index 70d6ebb3..dae96257 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -31,7 +31,7 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE \ +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) #endif diff --git a/CANopen.c b/CANopen.c index e7f1da04..c4266cef 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1055,12 +1055,10 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, if (CO_GET_CNT(HB_CONS) == 1) { err = CO_HBconsumer_init(co->HBcons, em, - co->SDO[0], - &OD_consumerHeartbeatTime[0], - CO_HBcons_monitoredNodes, - CO_GET_CNT(HB_CONS), + OD_GET(H1016, OD_H1016_CONSUMER_HB_TIME), co->CANmodule, - CO_GET_CO(RX_IDX_HB_CONS)); + CO_GET_CO(RX_IDX_HB_CONS), + errInfo); if (err) return err; } #endif diff --git a/CANopen.h b/CANopen.h index 42176526..41d74a0c 100644 --- a/CANopen.h +++ b/CANopen.h @@ -501,6 +501,8 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, * If it is unconfigured, then some CANopen objects will not be initialized nor * processed. * @param [out] errInfo Additional information in case of error, may be NULL. + * errInfo can also be set in noncritical errors, where function returns + * CO_ERROR_NO. For example, if OD parameter contains wrong value. * * @return CO_ERROR_NO in case of success. */ diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 5b50dab9..aa4b20d5 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -59,7 +59,8 @@ extern "C" { CO_CONFIG_HB_CONS_CALLBACK_MULTI | \ CO_CONFIG_HB_CONS_QUERY_FUNCT | \ CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_EM diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index bdd06175..96eee1e7 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -54,7 +54,6 @@ extern "C" { #endif /* TODO some parts are disabled in non-finished pre-release */ -#define CO_CONFIG_HB_CONS (0) #define CO_CONFIG_SYNC (0) #define CO_CONFIG_PDO (0) #define CO_CONFIG_TRACE (0) @@ -80,7 +79,8 @@ extern "C" { #define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) + CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ + CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_EM diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index dbdd227c..6132c13b 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -609,6 +609,10 @@ int main (int argc, char *argv[]) { CO_LSSslave_initCfgStoreCallback(CO->LSSslave, NULL, LSScfgStoreCallback); if(!CO->nodeIdUnconfigured) { + if(errInfo != 0) { + CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, + CO_EMC_DATA_SET, errInfo); + } #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); #endif @@ -616,7 +620,7 @@ int main (int argc, char *argv[]) { CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); #endif #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE - CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, NULL, + CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, 0, NULL, HeartbeatNmtChangedCallback); #endif #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE @@ -670,6 +674,10 @@ int main (int argc, char *argv[]) { } else { log_printf(LOG_CRIT, DBG_CAN_OPEN, "app_programStart()", err); + if(errInfo != 0 && !CO->nodeIdUnconfigured) { + CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, + CO_EMC_DATA_SET, errInfo); + } } programExit = EXIT_FAILURE; CO_endProgram = 1; @@ -721,7 +729,7 @@ int main (int argc, char *argv[]) { if (st->subIndexOD == 0) { bool_t storageOK = CO_storageLinux_auto_process( &st->entryAuto, false); - if(!storageOK) { + if(!storageOK && !CO->nodeIdUnconfigured) { CO_errorReport(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, CO_EMC_HARDWARE, i); } From 3ee872503671a8bcab7c18f9a92652994e7b1993 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 1 Feb 2021 15:24:37 +0100 Subject: [PATCH 153/520] Simplify Data Storage - remove CO_storage from CANopen.h/c (revert) - add target specific CO_storage_entry_t into CO_driver(_target).h --- 301/CO_driver.h | 23 +++ 301/CO_storage.c | 137 ++++++----------- 301/CO_storage.h | 171 ++++++++++----------- CANopen.c | 46 +----- CANopen.h | 9 -- doc/gettingStarted.md | 5 + example/CO_driver_target.h | 10 ++ socketCAN/CO_driver_target.h | 22 +++ socketCAN/CO_main_basic.c | 161 ++++++++------------ socketCAN/CO_storageLinux.c | 281 +++++++++++++++++------------------ socketCAN/CO_storageLinux.h | 104 +++++-------- 11 files changed, 427 insertions(+), 542 deletions(-) diff --git a/301/CO_driver.h b/301/CO_driver.h index e09583fe..09c7865c 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -345,6 +345,29 @@ typedef struct { } CO_CANmodule_t; +/** + * Data storage object for one entry. + * + * Must be defined in the **CO_driver_target.h** file. + * + * For more information on Data storage see @ref CO_storage or **CO_storage.h** + * file. Structure members documented here are required. Target system shall add + * own additional, hardware specific variables. + */ +typedef struct { + /** Address of data to store */ + void *addr; + /** Length of data to store */ + size_t len; + /** Sub index in OD objects 1010 and 1011, from 2 to 127. Writing + * 0x65766173 to 1010,subIndexOD will store data to non-volatile memory. + * Writing 0x64616F6C to 1011,subIndexOD will restore default data. */ + uint8_t subIndexOD; + /** Attribute from @ref CO_storage_attributes_t */ + uint8_t attr; +} CO_storage_entry_t; + + /** * @defgroup CO_critical_sections Critical sections * @{ diff --git a/301/CO_storage.c b/301/CO_storage.c index ca92bb61..0f3c6057 100644 --- a/301/CO_storage.c +++ b/301/CO_storage.c @@ -43,7 +43,9 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex, return 0; } - if (subIndex == 0) { + CO_storage_t *storage = stream->object; + + if (subIndex == 0 || storage->store == NULL) { *returnCode = ODR_READONLY; return 0; } @@ -53,29 +55,24 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex, return 0; } - CO_storage_t *storage = stream->object; - CO_storage_entry_t *entry = storage->firstEntry; - bool_t found = false; + /* loop through entries and store relevant */ + uint8_t found = 0; *returnCode = ODR_OK; - /* call pre-configured function matching subIndex or call all functions */ - while (entry != NULL) { - if (entry->store != NULL - && (entry->subIndexOD == subIndex - || (storage->sub1_all && subIndex == 1)) - ) { - ODR_t code = entry->store(entry->object, entry->addr, entry->len); - found = true; - - if (code != ODR_OK) *returnCode = code; - if (!(storage->sub1_all && subIndex == 1)) { - break; + for (uint8_t i = 0; i < storage->entriesCount; i++) { + CO_storage_entry_t *entry = &storage->entries[i]; + + if (subIndex == 1 || entry->subIndexOD == subIndex) { + if (found == 0) found = 1; + if ((entry->attr & CO_storage_cmd) != 0) { + ODR_t code = storage->store(entry); + if (code != ODR_OK) *returnCode = code; + found = 2; } } - entry = entry->nextEntry; } - if (!found) *returnCode = ODR_SUB_NOT_EXIST; + if (found != 2) *returnCode = found == 0 ? ODR_SUB_NOT_EXIST : ODR_READONLY; return *returnCode == ODR_OK ? 4 : 0; } @@ -98,7 +95,9 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, return 0; } - if (subIndex == 0) { + CO_storage_t *storage = stream->object; + + if (subIndex == 0 || storage->restore == NULL) { *returnCode = ODR_READONLY; return 0; } @@ -108,29 +107,24 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, return 0; } - CO_storage_t *storage = stream->object; - CO_storage_entry_t *entry = storage->firstEntry; - bool_t found = false; + /* loop through entries and store relevant */ + uint8_t found = 0; *returnCode = ODR_OK; - /* call pre-configured function matching subIndex or call all functions */ - while (entry != NULL) { - if (entry->restore != NULL - && (entry->subIndexOD == subIndex - || (storage->sub1_all && subIndex == 1)) - ) { - ODR_t code = entry->restore(entry->object, entry->addr, entry->len); - found = true; - - if (code != ODR_OK) *returnCode = code; - if (!(storage->sub1_all && subIndex == 1)) { - break; + for (uint8_t i = 0; i < storage->entriesCount; i++) { + CO_storage_entry_t *entry = &storage->entries[i]; + + if (subIndex == 1 || entry->subIndexOD == subIndex) { + if (found == 0) found = 1; + if ((entry->attr & CO_storage_restore) != 0) { + ODR_t code = storage->restore(entry); + if (code != ODR_OK) *returnCode = code; + found = 2; } } - entry = entry->nextEntry; } - if (!found) *returnCode = ODR_SUB_NOT_EXIST; + if (found != 2) *returnCode = found == 0 ? ODR_SUB_NOT_EXIST : ODR_READONLY; return *returnCode == ODR_OK ? 4 : 0; } @@ -139,75 +133,38 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, CO_ReturnError_t CO_storage_init(CO_storage_t *storage, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParameters, - bool_t sub1_all, - uint32_t *errInfo) + ODR_t (*store)(CO_storage_entry_t *entry), + ODR_t (*restore)(CO_storage_entry_t *entry), + CO_storage_entry_t *entries, + uint8_t entriesCount) { - ODR_t odRet; - /* verify arguments */ - if (storage == NULL || OD_1010_StoreParameters == NULL) { + if (storage == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } - /* object was pre-initialised by CO_storage_pre_init() */ - - storage->sub1_all = sub1_all; + /* Configure object variables */ + storage->store = store; + storage->restore = restore; + storage->entries = entries; + storage->entriesCount = entriesCount; /* configure extensions */ - storage->OD_1010_extension.object = storage; - storage->OD_1010_extension.read = OD_readOriginal; - storage->OD_1010_extension.write = OD_write_1010; - odRet = OD_extension_init(OD_1010_StoreParameters, - &storage->OD_1010_extension); - if (odRet != ODR_OK) { - if (errInfo != NULL) - *errInfo = OD_getIndex(OD_1010_StoreParameters); - return CO_ERROR_OD_PARAMETERS; + if (OD_1010_StoreParameters != NULL) { + storage->OD_1010_extension.object = storage; + storage->OD_1010_extension.read = OD_readOriginal; + storage->OD_1010_extension.write = OD_write_1010; + OD_extension_init(OD_1010_StoreParameters, &storage->OD_1010_extension); } if (OD_1011_RestoreDefaultParameters != NULL) { storage->OD_1011_extension.object = storage; storage->OD_1011_extension.read = OD_readOriginal; storage->OD_1011_extension.write = OD_write_1011; - odRet = OD_extension_init(OD_1011_RestoreDefaultParameters, - &storage->OD_1011_extension); - if (odRet != ODR_OK) { - if (errInfo != NULL) - *errInfo = OD_getIndex(OD_1011_RestoreDefaultParameters); - return CO_ERROR_OD_PARAMETERS; - } - } - - return CO_ERROR_NO; -} - - -CO_ReturnError_t CO_storage_entry_init(CO_storage_t *storage, - CO_storage_entry_t *newEntry) { - /* verify arguments */ - if (storage == NULL || newEntry == NULL || newEntry->addr == NULL - || newEntry->len == 0 || newEntry->subIndexOD == 0 - ) { - return CO_ERROR_ILLEGAL_ARGUMENT; + OD_extension_init(OD_1011_RestoreDefaultParameters, + &storage->OD_1011_extension); } - CO_storage_entry_t **entry = &storage->firstEntry; - - /* Add newEntry on the end of linked list or replace existing entry */ - for ( ; ; ) { - if (*entry == NULL) { - newEntry->nextEntry = NULL; - *entry = newEntry; - break; - } - if ((*entry)->subIndexOD == newEntry->subIndexOD) { - newEntry->nextEntry = (*entry)->nextEntry; - *entry = newEntry; - break; - } - *entry = (*entry)->nextEntry; - }; - return CO_ERROR_NO; } diff --git a/301/CO_storage.h b/301/CO_storage.h index ac7eba85..fa15b8c8 100644 --- a/301/CO_storage.h +++ b/301/CO_storage.h @@ -45,48 +45,55 @@ extern "C" { * @ingroup CO_CANopen_301 * @{ * - * CANopen data storage - connection to Object Dictionary + * CANopen provides OD objects 0x1010 and 0x1011 for control of storing and + * restoring data. Data source is usually a group of variables inside object + * dictionary, but it is not limited to OD. + * + * When object dictionary is generated (OD.h and OD.c files), OD variables are + * grouped into structures according to 'Storage group' parameter. + * + * Autonomous data storing must be implemented target specific, if in use. + * + * ### OD object 0x1010 - Store parameters: + * - Sub index 0: Highest sub-index supported + * - Sub index 1: Save all parameters, UNSIGNED32 + * - Sub index 2: Save communication parameters, UNSIGNED32 + * - Sub index 3: Save application parameters, UNSIGNED32 + * - Sub index 4 - 127: Manufacturer specific, UNSIGNED32 + * + * Sub-indexes 1 and above: + * - Reading provides information about its storage functionality: + * - bit 0: If set, CANopen device saves parameters on command + * - bit 1: If set, CANopen device saves parameters autonomously + * - Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores + * corresponding data. + * + * ### OD object 0x1011 - Restore default parameters + * - Sub index 0: Highest sub-index supported + * - Sub index 1: Restore all default parameters, UNSIGNED32 + * - Sub index 2: Restore communication default parameters, UNSIGNED32 + * - Sub index 3: Restore application default parameters, UNSIGNED32 + * - Sub index 4 - 127: Manufacturer specific, UNSIGNED32 + * + * Sub-indexes 1 and above: + * - Reading provides information about its restoring capability: + * - bit 0: If set, CANopen device restores parameters + * - Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) restores + * corresponding data. */ /** - * Data storage object for one entry. - * - * Object is defined by application and registered with - * @ref CO_storage_entry_init() function. + * Attributes (bit masks) for Data storage object. */ -typedef struct { - /** Address of data to store */ - void *addr; - /** Length of data to store */ - OD_size_t len; - /** Object defined by application, passed to store and restore functions. */ - void *object; - /** Sub index in OD objects 1010 and 1011, from 2 to 254. Writing - * 0x65766173 to 1010,subIndexOD will store data to non-volatile memory. - * Writing 0x64616F6C to 1011,subIndexOD will restore default data. */ - uint8_t subIndexOD; - /** - * Pointer to externally defined function, which will store data from addr. - * - * @param object object from above. - * @param addr Address form above. - * @param len Length from above. - * - * @return Value from @ref ODR_t, "ODR_OK" in case of success, "ODR_HW" in - * case of error in hardware. - */ - ODR_t (*store)(void *object, void *addr, OD_size_t len); - /** - * Pointer to externally defined function, which will restore data to addr. - * - * For description of arguments see above. - */ - ODR_t (*restore)(void *object, void *addr, OD_size_t len); - /** Pointer to next entry, initialized inside @ref CO_storage_entry_init() - * function. */ - void *nextEntry; -} CO_storage_entry_t; +typedef enum { + /** CANopen device saves parameters on OD 1010 command */ + CO_storage_cmd = 0x01, + /** CANopen device saves parameters autonomously */ + CO_storage_auto = 0x02, + /** CANopen device restores parameters on OD 1011 command */ + CO_storage_restore = 0x04 +} CO_storage_attributes_t; /** @@ -95,74 +102,56 @@ typedef struct { * Object is used with CANopen OD objects at index 1010 and 1011. */ typedef struct { - /** Extension for OD object */ - OD_extension_t OD_1010_extension; - /** Extension for OD object */ - OD_extension_t OD_1011_extension; - /** Null on the beginning, @ref CO_storage_entry_init() adds objects here - * and creates linked list. */ - CO_storage_entry_t *firstEntry; - /** From @ref CO_storage_init(). */ - bool_t sub1_all; + OD_extension_t OD_1010_extension; /**< Extension for OD object */ + OD_extension_t OD_1011_extension; /**< Extension for OD object */ + ODR_t (*store)(CO_storage_entry_t *entry); /**< From CO_storage_init() */ + ODR_t (*restore)(CO_storage_entry_t *entry); /**< From CO_storage_init() */ + CO_storage_entry_t *entries; /**< From CO_storage_init() */ + uint8_t entriesCount; /**< From CO_storage_init() */ } CO_storage_t; /** - * Pre-initialize data storage object. - * - * This function must be called before first @ref CO_storage_entry_init() - * function call. It is used inside @ref CO_new(). - * - * @param storage This object will be pre-initialized. - */ -static inline void CO_storage_pre_init(CO_storage_t *storage) { - if (storage != NULL) storage->firstEntry = NULL; -} - - -/** - * Initialize data storage object for usage with OD objects 1010 and 1011. + * Initialize data storage object * - * Function is used inside @ref CO_CANopenInit(). It does not erase - * pre-configured entries from CO_storage_entry_init() calls. + * This function should be called by application after the program startup, + * before @ref CO_CANopenInit(). This function initializes storage object and + * OD extensions on objects 1010 and 1011. Function does not load stored data + * on startup, because loading data is target specific. * - * @param storage This object will be initialized. + * @param storage This object will be initialized. It must be defined by + * application and must exist permanently. * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". + * Entry is optional, may be NULL. * @param OD_1011_RestoreDefaultParameters OD entry for 0x1011 -"Restore default * parameters". Entry is optional, may be NULL. - * @param sub1_all If true, then writing to sub-index 1 of 1010 and 1011 will - * store/restore all data. This is default in CANopen. - * @param [out] errInfo Additional information in case of error, may be NULL. + * @param store Pointer to externally defined function, which will store data + * specified by @ref CO_storage_entry_t. Function will be called when + * OD variable 0x1010 will be written. Argument to function is entry, where + * 'entry->subIndexOD' equals accessed subIndex. Function returns value from + * @ref ODR_t : "ODR_OK" in case of success, "ODR_HW" in case of hardware error. + * @param restore Same as 'store', but for restoring default data. + * @param entries Pointer to array of storage entries. Array must be defined and + * initialized by application and must exist permanently. Each array element + * contains: + * - Pointer and length of data, which will be stored or restored, + * - subIndexOD, which binds entry to specific subindex in 1010 and 1011 OD + * objects. Multiple entries with the same subIndexOD are possible. + * - Attribute, which specifies, if data is stored on command or automatically + * and also specifies if data is able to restore. @ref CO_storage_attributes_t + * - Additional target specific parameters. See @ref CO_storage_entry_t in + * CO_driver_target.h file. + * @param entriesCount Count of storage entries * - * @return CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OD_PARAMETERS. + * @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_storage_init(CO_storage_t *storage, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParameters, - bool_t sub1_all, - uint32_t *errInfo); - - -/** - * Initialize / add one entry into data storage object - * - * This function may be called by application one or several times after - * @ref CO_storage_pre_init() and before @ref CO_CANopenInit(). If entry with - * the same CO_storage_entry_t->subIndexOD as in newEntry already exists in - * storage object, then that entry in storage object will be replaced with - * newEntry. So it is not a problem to call this function multiple times with - * the same subIndexOD in CANopen communication reset section. - * - * @param storage Data storage object. - * @param newEntry New entry for data storage object. It must be initialized - * externally. This object must exist permanently. To disable entry, set store - * and restore function pointers to NULL. - * - * @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. - */ -CO_ReturnError_t CO_storage_entry_init(CO_storage_t *storage, - CO_storage_entry_t *newEntry); - + ODR_t (*store)(CO_storage_entry_t *entry), + ODR_t (*restore)(CO_storage_entry_t *entry), + CO_storage_entry_t *entries, + uint8_t entriesCount); /** @} */ /* CO_storage */ diff --git a/CANopen.c b/CANopen.c index c4266cef..a8078a48 100644 --- a/CANopen.c +++ b/CANopen.c @@ -185,18 +185,6 @@ #define CO_TX_CNT_TPDO 0 #endif -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - #if !defined OD_CNT_STORAGE - #define OD_CNT_STORAGE 0 - #define OD_ENTRY_H1010 NULL - #elif OD_CNT_STORAGE < 0 || OD_CNT_STORAGE > 1 - #error OD_CNT_STORAGE from OD.h not correct! - #endif - #ifndef OD_ENTRY_H1011 - #define OD_ENTRY_H1011 NULL - #endif -#endif - #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE #define OD_CNT_LEDS 1 #endif @@ -325,8 +313,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { || config->CNT_EM > 1 || config->CNT_SDO_SRV > 128 || config->CNT_SDO_CLI > 128 || config->CNT_SYNC > 1 || config->CNT_RPDO > 512 || config->CNT_TPDO > 512 - || config->CNT_TIME > 1 - || config->OD_CNT_STORAGE > 1 || config->CNT_LEDS > 1 + || config->CNT_TIME > 1 || config->CNT_LEDS > 1 || config->CNT_GFC > 1 || config->CNT_SRDO > 64 || config->CNT_LSS_SLV > 1 || config->CNT_LSS_MST > 1 || config->CNT_GTWA > 1 @@ -469,16 +456,6 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - if (CO_GET_CNT(STORAGE) == 1) { - p = calloc(1, sizeof(CO_storage_t)); - if (p == NULL) break; - else co->storage = (CO_storage_t *)p; - CO_storage_pre_init(co->storage); - mem += sizeof(CO_storage_t); - } -#endif - #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE if (CO_GET_CNT(LEDS) == 1) { p = calloc(1, sizeof(CO_LEDs_t)); @@ -694,10 +671,6 @@ void CO_delete(CO_t *co) { free(co->GFC); #endif -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - free(co->storage); -#endif - #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE free(co->LEDs); #endif @@ -771,9 +744,6 @@ void CO_delete(CO_t *co) { #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE static CO_TPDO_t COO_TPDO[OD_CNT_TPDO]; #endif -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - static CO_storage_t COO_storage; -#endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE static CO_LEDs_t COO_LEDs; #endif @@ -832,9 +802,6 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE co->TPDO = &COO_TPDO[0]; #endif -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - co->storage = &COO_storage; -#endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE co->LEDs = &COO_LEDs; #endif @@ -978,17 +945,6 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, return CO_ERROR_ILLEGAL_ARGUMENT; } -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - if (CO_GET_CNT(STORAGE) == 1) { - err = CO_storage_init(co->storage, - OD_GET(H1010, OD_H1010_STORE_PARAMETERS), - OD_GET(H1011, OD_H1011_RESTORE_DEFAULT), - true, - errInfo); - if (err) return err; - } -#endif - #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE if (CO_GET_CNT(LEDS) == 1) { err = CO_LEDs_init(co->LEDs); diff --git a/CANopen.h b/CANopen.h index 41d74a0c..23361b07 100644 --- a/CANopen.h +++ b/CANopen.h @@ -38,7 +38,6 @@ #include "301/CO_SYNC.h" #include "301/CO_PDO.h" #include "301/CO_TIME.h" -#include "301/CO_storage.h" #include "303/CO_LEDs.h" #include "304/CO_GFC.h" #include "304/CO_SRDO.h" @@ -234,10 +233,6 @@ typedef struct { uint16_t CNT_TPDO; OD_entry_t *ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */ OD_entry_t *ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */ - /** Number of storage objects, 0 or 1. */ - uint8_t CNT_STORAGE; - OD_entry_t *ENTRY_H1010; /**< OD entry for @ref CO_storage_init() */ - OD_entry_t *ENTRY_H1011; /**< OD entry for @ref CO_storage_init() */ /** Number of LEDs objects, 0 or 1. */ uint8_t CNT_LEDS; /** Number of GFC objects, 0 or 1 (CANrx + CANtx). */ @@ -343,10 +338,6 @@ typedef struct { uint16_t TX_IDX_TPDO; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN - /** Storage object, initialised by @ref CO_storage_init() */ - CO_storage_t *storage; -#endif #if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN /** LEDs object, initialised by @ref CO_LEDs_init() */ CO_LEDs_t *LEDs; diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index 773ba1d6..e1acec1b 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -118,6 +118,11 @@ Now store Object dictionary on node-ID 4, so it will preserve variables on next 4 w 0x1010 1 u32 0x65766173 [0] OK +0x65766173 are ascii characters for 's', 'a', 'v', 'e', so it is easier to simply write visible string instead of unsigned 32. This is equivalent to the above command: + + 4 w 0x1010 1 vs save + [0] OK + More details about Object dictionary variables can be found in CiA301 standard or in example/DS301_profile.md file. diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index aa4b20d5..b94124dd 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -230,6 +230,16 @@ typedef struct { } CO_CANmodule_t; +/* Data storage object for one entry */ +typedef struct { + void *addr; + size_t len; + uint8_t subIndexOD; + uint8_t attr; + /* Additional variables */ +} CO_storage_entry_t; + + /* (un)lock critical section in CO_CANsend() */ #define CO_LOCK_CAN_SEND() #define CO_UNLOCK_CAN_SEND() diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 96eee1e7..b5671d21 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #ifndef CO_SINGLE_THREAD #include @@ -355,6 +356,27 @@ typedef struct { #endif } CO_CANmodule_t; + +/* Data storage: Maximum file name length including path */ +#ifndef CO_STORAGE_PATH_MAX +#define CO_STORAGE_PATH_MAX 255 +#endif + +/* Data storage object for one entry */ +typedef struct { + void *addr; + size_t len; + uint8_t subIndexOD; + uint8_t attr; + /* Name of the file, where data block is stored */ + char filename[CO_STORAGE_PATH_MAX]; + /* CRC checksum of the data stored previously, for auto storage */ + uint16_t crc; + /* Pointer to opened file, for auto storage */ + FILE *fp; +} CO_storage_entry_t; + + #ifdef CO_SINGLE_THREAD #define CO_LOCK_CAN_SEND() #define CO_UNLOCK_CAN_SEND() diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 6132c13b..f636045d 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -95,6 +95,15 @@ #define TIME_STAMP_INTERVAL_MS 10000 #endif +/* Definitions for application specific data storage objects */ +#ifndef CO_STORAGE_APPLICATION +#define CO_STORAGE_APPLICATION +#endif +/* Interval for automatic data storage in microseconds */ +#ifndef CO_STORAGE_AUTO_INTERVAL +#define CO_STORAGE_AUTO_INTERVAL 60000000 +#endif + /* CANopen object */ CO_t *CO = NULL; @@ -105,55 +114,6 @@ CO_pending_t CO_pending = { .bitRate = 0, .nodeId = CO_LSS_NODE_ID_ASSIGNMENT }; /* Active node-id, copied from CO_pending.nodeId in the communication reset */ static uint8_t CO_activeNodeId = CO_LSS_NODE_ID_ASSIGNMENT; -/* Data storage for Object Dictionnary and LSS */ -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE -/* Maximum file name length including path for storage */ -#ifndef CO_STORAGE_PATH_MAX -#define CO_STORAGE_PATH_MAX 255 -#endif - -/* Definitions for application specific storage objects */ -#ifndef CO_STORAGE_APPLICATION -#define CO_STORAGE_APPLICATION -#endif - -/* Interval for automatic storage in microseconds */ -#ifndef CO_STORAGE_AUTO_INTERVAL -#define CO_STORAGE_AUTO_INTERVAL 60000000 -#endif - -/* Configure objects for storage */ -typedef struct { - /* Address, length and filename of data to store */ - void *addr; - OD_size_t len; - char filename[CO_STORAGE_PATH_MAX]; - /* Subindex in OD objects 1010 and 1011 or 0 for auto storage. - * 1 is reserved for storing all parameters */ - uint8_t subIndexOD; - /* Object for storage or auto storage, usage depends on subIndexOD */ - CO_storage_entry_t entry; - CO_storageLinux_auto_t entryAuto; -} CO_storageLinux_entry_t; -CO_storageLinux_entry_t storage[] = { - { - .addr = &CO_pending, - .len = sizeof(CO_pending), - .filename = {'l', 's', 's', - '.', 'p', 'e', 'r', 's', 'i', 's', 't', '\0'}, - .subIndexOD = 0 - }, - { - .addr = &OD_PERSIST_COMM, - .len = sizeof(OD_PERSIST_COMM), - .filename = {'o', 'd', '_', 'c', 'o', 'm', 'm', - '.', 'p', 'e', 'r', 's', 'i', 's', 't', '\0'}, - .subIndexOD = 2 - }, - CO_STORAGE_APPLICATION -}; -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ - #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE static CO_time_t CO_time; /* Object for current time */ #endif @@ -312,10 +272,6 @@ int main (int argc, char *argv[]) { #endif CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_ReturnError_t err; -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - uint32_t storageInitError = 0; - uint32_t storageIntervalTimer = 0; -#endif CO_CANptrSocketCan_t CANptr = {0}; int opt; bool_t firstRun = true; @@ -323,6 +279,33 @@ int main (int argc, char *argv[]) { char* CANdevice = NULL; /* CAN device, configurable by arguments. */ bool_t nodeIdFromArgs = false; /* True, if program arguments are used for CANopen Node Id */ bool_t rebootEnable = false; /* Configurable by arguments */ + +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + CO_storage_t storage; + CO_storage_entry_t storageEntries[] = { + { + .addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), + .subIndexOD = 2, + .attr = CO_storage_cmd | CO_storage_restore, + .filename = {'o','d','_','c','o','m','m', + '.','p','e','r','s','i','s','t','\0'} + }, + { + .addr = &CO_pending, + .len = sizeof(CO_pending), + .subIndexOD = 4, + .attr = CO_storage_cmd | CO_storage_auto | CO_storage_restore, + .filename = {'l','s','s','.','p','e','r','s','i','s','t','\0'} + }, + CO_STORAGE_APPLICATION + }; + uint8_t storageEntriesCount = sizeof(storageEntries) / sizeof(storageEntries[0]); + uint32_t storageInitError = 0; + uint32_t storageErrorPrev = 0; + uint32_t storageIntervalTimer = 0; +#endif + #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_gtw_t epGtw; /* values from CO_commandInterface_t */ @@ -344,7 +327,7 @@ int main (int argc, char *argv[]) { printUsage(argv[0]); exit(EXIT_SUCCESS); } - while((opt = getopt(argc, argv, "i:p:rc:T:s:a:")) != -1) { + while((opt = getopt(argc, argv, "i:p:rc:T:s:")) != -1) { switch (opt) { case 'i': nodeIdFromArgs = true; @@ -390,11 +373,11 @@ int main (int argc, char *argv[]) { #endif #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE case 's': { - /* add prefix to each storage[i].filename */ - for (int i = 0; i < sizeof(storage) / sizeof(storage[0]); i++) { + /* add prefix to each storageEntries[i].filename */ + for (uint8_t i = 0; i < storageEntriesCount; i++) { char* filePrefix = optarg; size_t filePrefixLen = strlen(filePrefix); - char* file = storage[i].filename; + char* file = storageEntries[i].filename; size_t fileLen = strlen(file); if (fileLen + filePrefixLen < CO_STORAGE_PATH_MAX) { memmove(&file[filePrefixLen], &file[0], fileLen + 1); @@ -454,31 +437,20 @@ int main (int argc, char *argv[]) { #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE uint8_t pendingNodeIdOriginal = CO_pending.nodeId; - for (int i = 0; i < sizeof(storage) / sizeof(storage[0]); i++) { - CO_storageLinux_entry_t *st = &storage[i]; - if (st->subIndexOD == 0) { - err = CO_storageLinux_auto_init(&st->entryAuto, - st->addr, - st->len, - st->filename); - } else { - err = CO_storageLinux_entry_init(CO->storage, - &st->entry, - st->addr, - st->len, - st->filename, - st->subIndexOD); - } - if (err == CO_ERROR_DATA_CORRUPT) { - uint32_t bit = 1; - if (i < 32) bit <<= i; - storageInitError |= bit; - } - else if (err != CO_ERROR_NO) { - log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, st->filename); - exit(EXIT_FAILURE); - } + err = CO_storageLinux_init(&storage, + OD_ENTRY_H1010_storeParameters, + OD_ENTRY_H1011_restoreDefaultParameters, + storageEntries, + storageEntriesCount, + &storageInitError); + + if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) { + char *filename = storageInitError < storageEntriesCount + ? storageEntries[storageInitError].filename : "???"; + log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, filename); + exit(EXIT_FAILURE); } + /* Overwrite stored node-id, if specified by program arguments */ if (nodeIdFromArgs) { CO_pending.nodeId = pendingNodeIdOriginal; @@ -723,18 +695,18 @@ int main (int argc, char *argv[]) { storageIntervalTimer += epMain.timeDifference_us; } else { - storageIntervalTimer = 0; - for (int i = 0; i < sizeof(storage) / sizeof(storage[0]); i++) { - CO_storageLinux_entry_t *st = &storage[i]; - if (st->subIndexOD == 0) { - bool_t storageOK = CO_storageLinux_auto_process( - &st->entryAuto, false); - if(!storageOK && !CO->nodeIdUnconfigured) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, - CO_EMC_HARDWARE, i); - } + uint32_t err = CO_storageLinux_auto_process(&storage, false); + if(err != storageErrorPrev && !CO->nodeIdUnconfigured) { + if(err != 0) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, + CO_EMC_HARDWARE, err); + } + else { + CO_errorReset(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, 0); } } + storageErrorPrev = err; + storageIntervalTimer = 0; } #endif } @@ -756,12 +728,7 @@ int main (int argc, char *argv[]) { #endif #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - for (int i = 0; i < sizeof(storage) / sizeof(storage[0]); i++) { - CO_storageLinux_entry_t *st = &storage[i]; - if (st->subIndexOD == 0) { - CO_storageLinux_auto_process(&st->entryAuto, true); - } - } + CO_storageLinux_auto_process(&storage, true); #endif /* delete objects from memory */ diff --git a/socketCAN/CO_storageLinux.c b/socketCAN/CO_storageLinux.c index 36b67037..014cb2f2 100644 --- a/socketCAN/CO_storageLinux.c +++ b/socketCAN/CO_storageLinux.c @@ -37,21 +37,22 @@ * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t storeLinux(void *object, void *addr, OD_size_t len) { +static ODR_t storeLinux(CO_storage_entry_t *entry) { ODR_t ret = ODR_OK; - char *filename = object; uint16_t crc_store; /* Create names for temporary and old file */ - size_t fn_len = strlen(filename) + 5; + size_t fn_len = strlen(entry->filename) + 5; char *filename_tmp = malloc(fn_len); char *filename_old = malloc(fn_len); if (filename_tmp == NULL || filename_old == NULL) { + if (filename_tmp != NULL) free(filename_tmp); + if (filename_old != NULL) free(filename_old); ret = ODR_OUT_OF_MEM; } else { - strcpy(filename_tmp, filename); - strcpy(filename_old, filename); + strcpy(filename_tmp, entry->filename); + strcpy(filename_old, entry->filename); strcat(filename_tmp, ".tmp"); strcat(filename_old, ".old"); } @@ -64,12 +65,12 @@ static ODR_t storeLinux(void *object, void *addr, OD_size_t len) { } else { CO_LOCK_OD(); - size_t cnt = fwrite(addr, 1, len, fp); - crc_store = crc16_ccitt(addr, len, 0); + size_t cnt = fwrite(entry->addr, 1, entry->len, fp); + crc_store = crc16_ccitt(entry->addr, entry->len, 0); CO_UNLOCK_OD(); cnt += fwrite(&crc_store, 1, sizeof(crc_store), fp); fclose(fp); - if (cnt != (len + sizeof(crc_store))) { + if (cnt != (entry->len + sizeof(crc_store))) { ret = ODR_HW; } } @@ -82,19 +83,19 @@ static ODR_t storeLinux(void *object, void *addr, OD_size_t len) { size_t cnt = 0; uint16_t crc_verify, crc_read; - buf = malloc(len + 4); + buf = malloc(entry->len + 4); if (buf != NULL) { fp = fopen(filename_tmp, "r"); if (fp != NULL) { - cnt = fread(buf, 1, len + 4, fp); - crc_verify = crc16_ccitt(buf, len, 0); + cnt = fread(buf, 1, entry->len + 4, fp); + crc_verify = crc16_ccitt(buf, entry->len, 0); fclose(fp); - memcpy(&crc_read, &buf[len], sizeof(crc_read)); + memcpy(&crc_read, &buf[entry->len], sizeof(crc_read)); } free(buf); } /* If size or CRC differs, report error */ - if (buf == NULL || fp == NULL || cnt != (len + sizeof(crc_verify)) + if (buf == NULL || fp == NULL || cnt != (entry->len+sizeof(crc_verify)) || crc_store != crc_verify || crc_store != crc_read ) { ret = ODR_HW; @@ -103,8 +104,8 @@ static ODR_t storeLinux(void *object, void *addr, OD_size_t len) { /* rename existing file to *.old and *.tmp to existing */ if (ret == ODR_OK) { - if (rename(filename, filename_old) != 0 - || rename(filename_tmp, filename) != 0 + if (rename(entry->filename, filename_old) != 0 + || rename(filename_tmp, entry->filename) != 0 ) { ret = ODR_HW; } @@ -122,27 +123,30 @@ static ODR_t storeLinux(void *object, void *addr, OD_size_t len) { * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t restoreLinux(void *object, void *addr, OD_size_t len) { - (void) addr; (void) len; - - char *filename = object; +static ODR_t restoreLinux(CO_storage_entry_t *entry) { ODR_t ret = ODR_OK; + /* close the file first, if auto storage */ + if ((entry->attr & CO_storage_auto) != 0 && entry->fp != NULL) { + fclose(entry->fp); + entry->fp = NULL; + } + /* Rename existing filename to *.old. */ - char *filename_old = malloc(strlen(filename) + 5); + char *filename_old = malloc(strlen(entry->filename) + 5); if (filename_old == NULL) { ret = ODR_OUT_OF_MEM; } else { - strcpy(filename_old, filename); + strcpy(filename_old, entry->filename); strcat(filename_old, ".old"); - rename(filename, filename_old); + rename(entry->filename, filename_old); free(filename_old); } /* create an empty file and write "-\n" to it. */ if (ret == ODR_OK) { - FILE *fp = fopen(filename, "w"); + FILE *fp = fopen(entry->filename, "w"); if (fp == NULL) { ret = ODR_HW; } @@ -156,166 +160,157 @@ static ODR_t restoreLinux(void *object, void *addr, OD_size_t len) { } -CO_ReturnError_t CO_storageLinux_entry_init(CO_storage_t *storage, - CO_storage_entry_t *newEntry, - void *addr, - OD_size_t len, - char *filename, - uint8_t subIndexOD) +CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, + uint8_t entriesCount, + uint32_t *storageInitError) { + CO_ReturnError_t ret; + *storageInitError = 0; + /* verify arguments */ - if (storage == NULL || newEntry == NULL || addr == NULL || len == 0 - || filename == NULL || subIndexOD < 1 + if (storage == NULL || entries == NULL || entriesCount == 0 + || storageInitError == NULL ) { return CO_ERROR_ILLEGAL_ARGUMENT; } - /* configure newEntry and add it to the storage */ - newEntry->addr = addr; - newEntry->len = len; - newEntry->object = filename; - newEntry->subIndexOD = subIndexOD; - newEntry->store = storeLinux; - newEntry->restore = restoreLinux; + /* initialize storage and OD extensions */ + ret = CO_storage_init(storage, + OD_1010_StoreParameters, + OD_1011_RestoreDefaultParam, + storeLinux, + restoreLinux, + entries, + entriesCount); + if (ret != CO_ERROR_NO) { + return ret; + } - CO_ReturnError_t ret; - FILE *fp = NULL; - uint8_t *buf = NULL; + /* initialize entries */ + for (uint8_t i = 0; i < entriesCount; i++) { + CO_storage_entry_t *entry = &entries[i]; + bool_t dataCorrupt = false; + char *writeFileAccess = "w"; - /* Add newEntry to storage object */ - ret = CO_storage_entry_init(storage, newEntry); + /* verify arguments */ + if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2 + || strlen(entry->filename) == 0 + ) { + *storageInitError = i; + return CO_ERROR_ILLEGAL_ARGUMENT; + } - /* Open file, check existence and create temporary buffer */ - if (ret == CO_ERROR_NO) { - fp = fopen(filename, "r"); + /* Open file, check existence and create temporary buffer */ + uint8_t *buf = NULL; + FILE * fp = fopen(entry->filename, "r"); if (fp == NULL) { + dataCorrupt = true; ret = CO_ERROR_DATA_CORRUPT; } else { - buf = malloc(len + 4); + buf = malloc(entry->len + 4); if (buf == NULL) { - ret = CO_ERROR_OUT_OF_MEMORY; + fclose(fp); + *storageInitError = i; + return CO_ERROR_OUT_OF_MEMORY; } } - } - /* Read data into temporary buffer first. Then verify and copy to addr */ - if (ret == CO_ERROR_NO) { - size_t cnt = fread(buf, 1, len + 4, fp); + /* Read data into temporary buffer first. Then verify and copy to addr*/ + if (!dataCorrupt) { + size_t cnt = fread(buf, 1, entry->len + 4, fp); + + /* If file is empty, just skip loading, default values will be used, + * no error. Otherwise verify length and crc and copy data. */ + if (!(cnt == 2 && buf[0] == '-')) { + uint16_t crc1, crc2; + crc1 = crc16_ccitt(buf, entry->len, 0); + memcpy(&crc2, &buf[entry->len], sizeof(crc2)); - uint16_t crc1, crc2; - crc1 = crc16_ccitt(buf, len, 0); - memcpy(&crc2, &buf[len], sizeof(crc2)); + if (crc1 == crc2 && cnt == (entry->len + sizeof(crc2))) { + memcpy(entry->addr, buf, entry->len); + entry->crc = crc1; + writeFileAccess = "r+"; + } + else { + dataCorrupt = true; + ret = CO_ERROR_DATA_CORRUPT; + } + } - if (cnt == 2 && buf[0] == '-') { - /* File is empty, default values will be used, no error */ - } - else if (cnt != (len + sizeof(crc2)) || crc1 != crc2) { - /* Data length does not match */ - ret = CO_ERROR_DATA_CORRUPT; + free(buf); + fclose(fp); } - else { - /* no errors, copy data into Object dictionary */ - memcpy(addr, buf, len); + + /* additional info in case of error */ + if (dataCorrupt) { + uint32_t errorBit = entry->subIndexOD; + if (errorBit > 31) errorBit = 31; + *storageInitError |= ((uint32_t) 1) << errorBit; } - } - if (buf != NULL) free(buf); - if (fp != NULL) fclose(fp); + /* open file for auto storage, if set so */ + if ((entry->attr & CO_storage_auto) != 0) { + entry->fp = fopen(entry->filename, writeFileAccess); + if (entry->fp == NULL) { + *storageInitError = i; + return CO_ERROR_ILLEGAL_ARGUMENT; + } + } + } /* for (entries) */ return ret; } -CO_ReturnError_t CO_storageLinux_auto_init(CO_storageLinux_auto_t *storageAuto, - void *addr, - OD_size_t len, - char *filename) +uint32_t CO_storageLinux_auto_process(CO_storage_t *storage, + bool_t closeFiles) { + uint32_t storageError = 0; + /* verify arguments */ - if (storageAuto == NULL || addr == NULL || len == 0 || filename == NULL) { - return CO_ERROR_ILLEGAL_ARGUMENT; + if (storage == NULL) { + return false; } - /* configure variables */ - storageAuto->addr = addr; - storageAuto->len = len; - storageAuto->crc = 0; - bool_t readOK = false; - char *writeFileAccess = "w"; - - /* Open the file, read data into temporary buffer, verify them and copy them - * into addr. If file does not exist or data is corrupt, just skip reading - * and keep the default values. */ - FILE *fp = fopen(filename, "r"); - if (fp != NULL) { - uint8_t *buf = malloc(len + 4); - if (buf != NULL) { - size_t cnt = fread(buf, 1, len + 4, fp); + /* loop through entries */ + for (uint8_t i = 0; i < storage->entriesCount; i++) { + CO_storage_entry_t *entry = &storage->entries[i]; + + if ((entry->attr & CO_storage_auto) == 0 || entry->fp == NULL) + continue; - if (cnt == 2 && buf[0] == '-') { - /* File is empty, default values will be used, no error */ - readOK = true; + /* If CRC of the current data differs, save the file */ + uint16_t crc = crc16_ccitt(entry->addr, entry->len, 0); + if (crc != entry->crc) { + size_t cnt; + rewind(entry->fp); + CO_LOCK_OD(); + cnt = fwrite(entry->addr, 1, entry->len, entry->fp); + CO_UNLOCK_OD(); + cnt += fwrite(&crc, 1, sizeof(crc), entry->fp); + fflush(entry->fp); + if (cnt == (entry->len + sizeof(crc))) { + entry->crc = crc; } else { - uint16_t crc1, crc2; - crc1 = crc16_ccitt(buf, len, 0); - memcpy(&crc2, &buf[len], sizeof(crc2)); - - if (crc1 == crc2 && cnt == (len + sizeof(crc2))) { - memcpy(addr, buf, len); - storageAuto->crc = crc1; - readOK = true; - writeFileAccess = "r+"; - } + /* error with save */ + uint32_t errorBit = entry->subIndexOD; + if (errorBit > 31) errorBit = 31; + storageError |= ((uint32_t) 1) << errorBit; } - free(buf); } - fclose(fp); - } - - storageAuto->fp = fopen(filename, writeFileAccess); - if (storageAuto->fp == NULL) return CO_ERROR_ILLEGAL_ARGUMENT; - return readOK ? CO_ERROR_NO : CO_ERROR_DATA_CORRUPT; -} - - -bool_t CO_storageLinux_auto_process(CO_storageLinux_auto_t *storageAuto, - bool_t closeFile) -{ - bool_t ret = false; - - /* verify arguments */ - if (storageAuto == NULL || storageAuto->fp == NULL) { - return ret; - } - - /* If CRC of the current data differs, save the file */ - uint16_t crc = crc16_ccitt(storageAuto->addr, storageAuto->len, 0); - if (crc == storageAuto->crc) { - ret = true; - } - else { - size_t cnt; - rewind(storageAuto->fp); - CO_LOCK_OD(); - cnt = fwrite(storageAuto->addr, 1, storageAuto->len, storageAuto->fp); - CO_UNLOCK_OD(); - cnt += fwrite(&crc, 1, sizeof(crc), storageAuto->fp); - fflush(storageAuto->fp); - if (cnt == (storageAuto->len + sizeof(crc))) { - storageAuto->crc = crc; - ret = true; + if (closeFiles) { + fclose(entry->fp); + entry->fp = NULL; } } - if (closeFile) { - fclose(storageAuto->fp); - storageAuto->fp = NULL; - } - - return ret; + return storageError; } #endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/socketCAN/CO_storageLinux.h b/socketCAN/CO_storageLinux.h index ccee4749..64bde660 100644 --- a/socketCAN/CO_storageLinux.h +++ b/socketCAN/CO_storageLinux.h @@ -45,84 +45,54 @@ extern "C" { /** - * Initialize / add one entry into data storage object (Linux specific) - * - * This function configures newEntry and calls @ref CO_storage_entry_init(). - * Then reads data from file, verifies and writes them to addr. - * - * @param storage Data storage object. - * @param newEntry Data storage object for one entry. It will be configured and - * must exist permanently. - * @param addr Address of data to store - * @param len Length of data to store - * @param filename Name of the file, where data are stored. - * @param subIndexOD Sub index in OD 1010 and 1011 ,see @ref CO_storage_entry_t - * - * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if memory can not be initialized, + * Initialize data storage object (Linux specific) + * + * This function should be called by application after the program startup, + * before @ref CO_CANopenInit(). This function initializes storage object, + * OD extensions on objects 1010 and 1011, reads data from file, verifies them + * and writes data to addresses specified inside entries. This function + * internally calls @ref CO_storage_init(). + * + * @param storage This object will be initialized. It must be defined by + * application and must exist permanently. + * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". + * Entry is optional, may be NULL. + * @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default + * parameters". Entry is optional, may be NULL. + * @param entries Pointer to array of storage entries, see @ref CO_storage_init. + * @param entriesCount Count of storage entries + * @param [out] storageInitError If function returns CO_ERROR_DATA_CORRUPT, + * then this variable contains a bit mask from subIndexOD values, where data + * was not properly initialized. If other error, then this variable contains + * index or erroneous entry. + * + * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if data can not be initialized, * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY. */ -CO_ReturnError_t CO_storageLinux_entry_init(CO_storage_t *storage, - CO_storage_entry_t *newEntry, - void *addr, - OD_size_t len, - char *filename, - uint8_t subIndexOD); - - -/** - * Object for automatic data storage - */ -typedef struct { - /** Address of data to store */ - void *addr; - /** Length of data to store */ - OD_size_t len; - /** CRC checksum of the data stored previously. */ - uint16_t crc; - /** Pointer to file opened by @ref CO_storageLinux_auto_init() */ - FILE *fp; -} CO_storageLinux_auto_t; - - -/** - * Initialize automatic storage with Linux - * - * Function in combination with @ref CO_storageLinux_auto_process() are - * standalone functions. They are used for automatic data storage. - * - * This function configures storageAuto, then reads data from file. If data are - * valid, then it writes them to addr. Function also open file pointer for - * writing and keeps it open. - * - * @param storageAuto This object will be initialized. - * @param addr Address of data to store - * @param len Length of data to store - * @param filename Name of the file, where data are stored. - * - * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if memory can not be initialized, - * CO_ERROR_ILLEGAL_ARGUMENT, if file can not be opened for writing. - */ -CO_ReturnError_t CO_storageLinux_auto_init(CO_storageLinux_auto_t *storageAuto, - void *addr, - OD_size_t len, - char *filename); +CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, + uint8_t entriesCount, + uint32_t *storageInitError); /** * Automatically save data if differs from previous call. * * Should be called cyclically by program. Each interval it verifies, if crc - * checksum of data differs previous checksum. If it does, data are saved into - * file, opened by CO_storageLinux_auto_init(). + * checksum of data differs from previous checksum. If it does, data are saved + * into pre-opened file. * - * @param storageAuto This object - * @param closeFile If true, then data will be stored regardless interval and - * file will be closed. Use on end of program. + * @param storage This object + * @param closeFiles If true, then all files will be closed. Use on end of the + * program. * - * @return true, if data are unchanged or saved successfully. + * @return 0 on success or bit mask from subIndexOD values, where data was not + * able to be saved. */ -bool_t CO_storageLinux_auto_process(CO_storageLinux_auto_t *storageAuto, - bool_t closeFile); +uint32_t CO_storageLinux_auto_process(CO_storage_t *storage, + bool_t closeFiles); /** @} */ /* CO_storageLinux */ From 88558203a017863ee94880aebeb54b5412b2a88a Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 8 Feb 2021 17:01:55 +0100 Subject: [PATCH 154/520] Linux socketCAN driver, fix CANsend(). There was a problem with block transfer, when transmitting sequence of data. If CANsend() failed (socket buffer full), message was dropped. Now dropped message is marked with bufferFull flag and then it is re-transmitted later by the driver, as is in the original behaviour of CANopenNode. Same as commit acd719e27 in v2.0. --- 301/CO_SDOclient.c | 4 +- 301/CO_SDOserver.c | 2 +- CANopen.c | 2 +- Makefile | 5 +- README.md | 3 ++ doc/gettingStarted.md | 2 +- socketCAN/CO_driver.c | 98 ++++++++++++++++++++++++++++++++-- socketCAN/CO_driver_target.h | 3 +- socketCAN/CO_epoll_interface.c | 10 ++++ socketCAN/CO_error_msgs.h | 4 +- 10 files changed, 118 insertions(+), 15 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 291c7f37..65d7988e 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -847,7 +847,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_ABORT; } - /* Timeout timers *********************************************************/ + /* Timeout timers and transmit bufferFull flag ****************************/ if (ret == CO_SDO_RT_waitingResponse) { if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { SDO_C->timeoutTimer += timeDifference_us; @@ -1547,7 +1547,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_ABORT; } - /* Timeout timers *********************************************************/ + /* Timeout timers and transmit bufferFull flag ****************************/ if (ret == CO_SDO_RT_waitingResponse) { if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { SDO_C->timeoutTimer += timeDifference_us; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index e4bafa5c..3409d627 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1142,7 +1142,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, CO_FLAG_CLEAR(SDO->CANrxNew); } /* if (isNew) */ - /* Timeout timers *********************************************************/ + /* Timeout timers and transmit bufferFull flag ****************************/ #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED if (ret == CO_SDO_RT_waitingResponse) { if (SDO->timeoutTimer < SDO->SDOtimeoutTime_us) { diff --git a/CANopen.c b/CANopen.c index a8078a48..fcdf91fe 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1261,7 +1261,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { - (void) enableGateway; (void) timerNext_us; /* may be unused */ + (void) enableGateway; /* may be unused */ CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_NMT_internalState_t NMTstate = CO_NMT_getInternalState(co->NMT); diff --git a/Makefile b/Makefile index 4060f05e..195008a8 100644 --- a/Makefile +++ b/Makefile @@ -47,15 +47,16 @@ SOURCES = \ OBJS = $(SOURCES:%.c=%.o) CC ?= gcc OPT = -OPT += -DCO_SINGLE_THREAD OPT += -g +#OPT += -O2 +OPT += -DCO_SINGLE_THREAD #OPT += -DCO_CONFIG_DEBUG=0xFFFF #OPT += -Wextra -Wshadow -pedantic -fanalyzer #OPT += -DCO_USE_GLOBALS #OPT += -DCO_MULTIPLE_OD CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = -#LDFLAGS += -g +LDFLAGS += -g #LDFLAGS += -pthread #Options can be also passed via make: 'make OPT="-g" LDFLAGS="-pthread"' diff --git a/README.md b/README.md index 6057400d..bc4c1e37 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ Dictionary and are accessible from both: C code and from CANopen network. CANopenNode homepage is https://github.com/CANopenNode/CANopenNode +This is renewed version of CANopenNode with new Object Dictionary implementation. +For older versions see branches `v1.3-master` or `v2.0-master`. + Characteristics --------------- diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md index e1acec1b..5a4cdbf5 100644 --- a/doc/gettingStarted.md +++ b/doc/gettingStarted.md @@ -180,7 +180,7 @@ Another interesting tool is [CANopen for Python](https://github.com/christiansan Examples here worked in virtual CAN interface, for simplicity. Virtual CAN runs inside Linux kernel only, it does not have much practical usability. If one has real CAN network configuration, then above examples are suitable also for this network, if Linux machine is connected to it and CAN interface is properly configured. When connecting your devices to real CAN network, make sure, you have at least two devices communicating, connected with ground and pair of wires, terminated with two 120ohm resistors, correct baudrate, etc. Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native in Linux kernel are: - - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with: `sudo slcand -f -o -c -s8 /dev/ttyACM0 can0; sudo ip link set up can0` + - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with (-s5=250kbps): `sudo slcand -f -o -c -s5 /dev/ttyACM0 can0; sudo ip link set up can0` - [EMS CPC-USB](https://www.ems-wuensche.com/?post_type=product&p=746) or [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Start with: `sudo ip link set up can0 type can bitrate 250000` - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can) (Kconfig files). - Raspberry PI or similar has CAN capes available. diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 8f22aae8..5a083d79 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -225,6 +225,8 @@ CO_ReturnError_t CO_CANmodule_init( CANmodule->txSize = txSize; CANmodule->CANerrorStatus = 0; CANmodule->CANnormal = false; + CANmodule->CANtxCount = 0; + #if CO_DRIVER_MULTI_INTERFACE > 0 for (i = 0; i < CO_CAN_MSG_SFF_MAX_COB_ID; i++) { CANmodule->rxIdentToIndex[i] = CO_INVALID_COB_ID; @@ -572,6 +574,7 @@ CO_ReturnError_t CO_CANtxBuffer_setInterface( } #endif /* CO_DRIVER_MULTI_INTERFACE */ +#if CO_DRIVER_MULTI_INTERFACE > 0 /* send CAN message ***********************************************************/ static CO_ReturnError_t CO_CANCheckSendInterface( @@ -702,6 +705,68 @@ CO_ReturnError_t CO_CANCheckSend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) return err; } +#warning CO_CANsend() is outdated for CO_DRIVER_MULTI_INTERFACE > 0 + +#endif /* CO_DRIVER_MULTI_INTERFACE > 0 */ + + +#if CO_DRIVER_MULTI_INTERFACE == 0 + +/* Change handling of tx buffer full in CO_CANsend(). Use CO_CANtx_t->bufferFull + * flag. Re-transmit undelivered message inside CO_CANmodule_process(). */ +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) +{ + CO_ReturnError_t err = CO_ERROR_NO; + + if (CANmodule==NULL || buffer==NULL || CANmodule->CANinterfaceCount==0) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + CO_CANinterface_t *interface = &CANmodule->CANinterfaces[0]; + if (interface == NULL || interface->fd < 0) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* Verify overflow */ + if(buffer->bufferFull){ +#if CO_DRIVER_ERROR_REPORTING > 0 + interface->errorhandler.CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; +#endif + log_printf(LOG_ERR, DBG_CAN_TX_FAILED, buffer->ident, interface->ifName); + err = CO_ERROR_TX_OVERFLOW; + } + + errno = 0; + ssize_t n = send(interface->fd, buffer, CAN_MTU, MSG_DONTWAIT); + if (errno == 0 && n == CAN_MTU) { + /* success */ + if (buffer->bufferFull) { + buffer->bufferFull = false; + CANmodule->CANtxCount--; + } + } + else if (errno == EINTR || errno == EAGAIN || errno == ENOBUFS) { + /* Send failed, message will be re-sent by CO_CANmodule_process() */ + if (!buffer->bufferFull) { + buffer->bufferFull = true; + CANmodule->CANtxCount++; + } + err = CO_ERROR_TX_BUSY; + } + else { + /* Unknown error */ + log_printf(LOG_DEBUG, DBG_ERRNO, "send()"); +#if CO_DRIVER_ERROR_REPORTING > 0 + interface->errorhandler.CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; +#endif + err = CO_ERROR_SYSCALL; + } + + return err; +} + +#endif /* CO_DRIVER_MULTI_INTERFACE == 0 */ + /******************************************************************************/ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) @@ -714,18 +779,41 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) /******************************************************************************/ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { + if (CANmodule == NULL || CANmodule->CANinterfaceCount == 0) return; + +#if CO_DRIVER_ERROR_REPORTING > 0 /* socketCAN doesn't support microcontroller-like error counters. If an * error has occured, a special can message is created by the driver and * received by the application like a regular message. * Therefore, error counter evaluation is included in rx function. * Here we just copy evaluated CANerrorStatus from the first CAN interface. */ -#if CO_DRIVER_ERROR_REPORTING > 0 - if (CANmodule->CANinterfaceCount > 0) { - CANmodule->CANerrorStatus = - CANmodule->CANinterfaces[0].errorhandler.CANerrorStatus; - } + CANmodule->CANerrorStatus = + CANmodule->CANinterfaces[0].errorhandler.CANerrorStatus; #endif + +#if CO_DRIVER_MULTI_INTERFACE == 0 + /* recall CO_CANsend(), if message was unsent before */ + if (CANmodule->CANtxCount > 0) { + bool_t found = false; + + for (uint16_t i = 0; i < CANmodule->txSize; i++) { + CO_CANtx_t *buffer = &CANmodule->txArray[i]; + + if (buffer->bufferFull) { + buffer->bufferFull = false; + CANmodule->CANtxCount--; + CO_CANsend(CANmodule, buffer); + found = true; + break; + } + } + + if (!found) { + CANmodule->CANtxCount = 0; + } + } +#endif /* CO_DRIVER_MULTI_INTERFACE == 0 */ } diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index b5671d21..63946b29 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -306,7 +306,7 @@ typedef struct { uint8_t DLC; uint8_t padding[3]; /* ensure alignment */ uint8_t data[8]; - volatile bool_t bufferFull; /* not used */ + volatile bool_t bufferFull; volatile bool_t syncFlag; /* info about transmit message */ int can_ifindex; /* CAN Interface index to use */ } CO_CANtx_t; @@ -346,6 +346,7 @@ typedef struct { uint16_t txSize; uint16_t CANerrorStatus; volatile bool_t CANnormal; + volatile uint16_t CANtxCount; int epoll_fd; /* File descriptor for epoll, which waits for CAN receive event */ #if CO_DRIVER_MULTI_INTERFACE > 0 || defined CO_DOXYGEN diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c index 8674b87b..aaed28a9 100644 --- a/socketCAN/CO_epoll_interface.c +++ b/socketCAN/CO_epoll_interface.c @@ -50,6 +50,11 @@ #endif #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ +/* delay for recall CANsend(), if CAN TX buffer is full */ +#ifndef CANSEND_DELAY_US +#define CANSEND_DELAY_US 100 +#endif + /* EPOLL **********************************************************************/ /* Helper function - get monotonic clock time in microseconds */ @@ -297,6 +302,11 @@ void CO_epoll_processMain(CO_epoll_t *ep, enableGateway, ep->timeDifference_us, &ep->timerNext_us); + + /* If there are unsent CAN messages, call CO_CANmodule_process() earlier */ + if (co->CANmodule->CANtxCount > 0 && ep->timerNext_us > CANSEND_DELAY_US) { + ep->timerNext_us = CANSEND_DELAY_US; + } } diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index b038fdee..1ce9f822 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -41,7 +41,7 @@ extern "C" { #define CAN_ERROR_FILTER_FAILED "(%s) Setting CAN Interface \"%s\" error filter failed", __func__ #define CAN_FILTER_FAILED "(%s) Setting CAN Interface \"%s\" message filter failed", __func__ #define CAN_NAMETOINDEX "CAN Interface \"%s\" -> Index %d" -#define CAN_SOCKET_BUF_SIZE "CAN Interface \"%s\" Buffer set to %d messages (%d Bytes)" +#define CAN_SOCKET_BUF_SIZE "CAN Interface \"%s\" RX buffer set to %d messages (%d Bytes)" #define CAN_RX_SOCKET_QUEUE_OVERFLOW "CAN Interface \"%s\" has lost %d messages" #define CAN_BUSOFF "CAN Interface \"%s\" changed to \"Bus Off\". Switching to Listen Only mode..." #define CAN_NOACK "CAN Interface \"%s\" no \"ACK\" received. Switching to Listen Only mode..." @@ -60,7 +60,7 @@ extern "C" { #define DBG_GENERAL "(%s) Error: %s%d", __func__ #define DBG_ERRNO "(%s) OS error \"%s\" in %s", __func__, strerror(errno) #define DBG_CO_DEBUG "(%s) CO_DEBUG: %s", __func__ -#define DBG_CAN_TX_FAILED "(%s) Transmitting CAN msg OID 0x%08x failed(%s)", __func__ +#define DBG_CAN_TX_FAILED "(%s) Transmitting CAN msg OID 0x%03x failed(%s)", __func__ #define DBG_CAN_RX_PARAM_FAILED "(%s) Setting CAN rx buffer failed (%s)", __func__ #define DBG_CAN_RX_FAILED "(%s) Receiving CAN msg failed (%s)", __func__ #define DBG_CAN_ERROR_GENERAL "(%s) Socket error msg ID: 0x%08x, Data[0..7]: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x (%s)", __func__ From 9f8819176786869907d0a47e3ecc1c15a53c1a9f Mon Sep 17 00:00:00 2001 From: Koen Dergent Date: Mon, 15 Feb 2021 14:24:38 +0100 Subject: [PATCH 155/520] only use SDO segmented fields when enabled --- 301/CO_SDOserver.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 3409d627..ec353df9 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -333,7 +333,9 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, /* Configure object variables */ SDO->OD = OD; SDO->nodeId = nodeId; +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; +#endif #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK SDO->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700; #endif @@ -1137,7 +1139,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; } } /* switch (SDO->state) */ +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED SDO->timeoutTimer = 0; +#endif timeDifference_us = 0; CO_FLAG_CLEAR(SDO->CANrxNew); } /* if (isNew) */ @@ -1206,7 +1210,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[3] = SDO->subIndex; /* reset timeout timer and send message */ +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED SDO->timeoutTimer = 0; +#endif CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED if (SDO->finished) { From d00ddf5a597e3b9a8408660df635cdc0221f36a1 Mon Sep 17 00:00:00 2001 From: Koen Dergent Date: Mon, 15 Feb 2021 14:31:53 +0100 Subject: [PATCH 156/520] only use optional emergency fields when enabled --- 301/CO_Emergency.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 148feab9..1badfabe 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -554,6 +554,7 @@ void CO_EM_process(CO_EM_t *em, (void)timerNext_us; /* may be unused */ /* verify errors from driver */ +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) uint16_t CANerrSt = em->CANdevTx->CANerrorStatus; if (CANerrSt != em->CANerrorStatusOld) { uint16_t CANerrStChanged = CANerrSt ^ em->CANerrorStatusOld; @@ -588,6 +589,7 @@ void CO_EM_process(CO_EM_t *em, CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0, CO_EM_CAN_RXB_OVERFLOW, CO_EM_CAN_RXB_OVERFLOW, 0); } +#endif /* calculate Error register */ uint8_t errorRegister = 0U; From a3606672d15bc16667efa0058761d07b28c46741 Mon Sep 17 00:00:00 2001 From: Koen Dergent Date: Tue, 16 Feb 2021 10:01:16 +0100 Subject: [PATCH 157/520] only use time producer fields when enabled --- 301/CO_TIME.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 97176be2..a68c032e 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -181,7 +181,9 @@ static inline void CO_TIME_set(CO_TIME_t *TIME, TIME->residual_us = 0; TIME->ms = ms; TIME->days = days; +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) TIME->producerTimer_ms = TIME->producerInterval_ms =producerInterval_ms; +#endif } } From c3ec5dfb682a618e5dffa3a37ca16df90e77002c Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 25 Feb 2021 07:37:16 +0100 Subject: [PATCH 158/520] Replace CO_NMT_setInternalState() with CO_NMT_sendInternalCommand(). --- 301/CO_NMT_Heartbeat.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index b85a3a3a..8b9d7c32 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -320,18 +320,17 @@ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { /** - * Set internal NMT state + * Send NMT command to self, without sending NMT message * - * Functions sets state directly, without any checking. @ref CO_NMT_process() - * may also switch between states automatically, see @ref CO_NMT_control_t. + * Internal NMT state will be verified and switched inside @ref CO_NMT_process() * * @param NMT This object. - * @param state New state. + * @param command NMT command */ -static inline void CO_NMT_setInternalState(CO_NMT_t *NMT, - CO_NMT_internalState_t state) +static inline void CO_NMT_sendInternalCommand(CO_NMT_t *NMT, + CO_NMT_command_t command) { - if (NMT != NULL) NMT->operatingState = state; + if (NMT != NULL) NMT->internalCommand = command; } From db7940ffc46187ee793f066ec91465edf536f0dd Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 25 Feb 2021 08:12:10 +0100 Subject: [PATCH 159/520] OD_interface: simplify OD_getPtr() function and add additional check. --- 301/CO_Emergency.c | 29 +++++++++++++++-------------- 301/CO_HBconsumer.c | 4 ++-- 301/CO_NMT_Heartbeat.c | 5 +++-- 301/CO_ODinterface.c | 25 ++++++++++++++----------- 301/CO_ODinterface.h | 11 +++++------ 301/CO_TIME.c | 8 +++++--- 301/CO_TIME.h | 2 +- 7 files changed, 45 insertions(+), 39 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 148feab9..49324b17 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -63,8 +63,9 @@ static OD_size_t OD_read_1014(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, ODR_t *returnCode) { - (void)count; /* "count" is already verified in *_init() function */ - if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (stream == NULL || subIndex != 0 || buf == NULL + || count != sizeof(uint32_t) || returnCode == NULL + ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } @@ -84,8 +85,9 @@ static OD_size_t OD_write_1014(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode) { - /* "count" is already verified in *_init() function */ - if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (stream == NULL || subIndex != 0 || buf == NULL + || count != sizeof(uint32_t) || returnCode == NULL + ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } @@ -136,8 +138,9 @@ static OD_size_t OD_read_1014_default(OD_stream_t *stream, uint8_t subIndex, void *buf, OD_size_t count, ODR_t *returnCode) { - (void)count; /* "count" is already verified in *_init() function */ - if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (stream == NULL || subIndex != 0 || buf == NULL + || count != sizeof(uint32_t) || returnCode == NULL + ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } @@ -162,8 +165,9 @@ static OD_size_t OD_write_1015(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode) { - /* "count" is already verified in *_init() function */ - if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (stream == NULL || subIndex != 0 || buf == NULL + || count != sizeof(uint16_t) || returnCode == NULL + ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } @@ -371,6 +375,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, { (void) nodeId; /* may be unused */ CO_ReturnError_t ret = CO_ERROR_NO; + ODR_t odRet; /* verify arguments */ if (em == NULL || OD_1001_errReg == NULL @@ -392,12 +397,8 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, memset(em, 0, sizeof(CO_EM_t)); /* get and verify "Error register" from Object Dictionary */ - OD_size_t len; - ODR_t odRet; - - odRet = OD_getPtr(OD_1001_errReg, 0, (void **)&em->errorRegister, &len); - - if (odRet != ODR_OK || len != sizeof(uint8_t)) { + em->errorRegister = OD_getPtr(OD_1001_errReg, 0, sizeof(uint8_t), NULL); + if (em->errorRegister == NULL) { if (errInfo != NULL) *errInfo = OD_getIndex(OD_1001_errReg); return CO_ERROR_OD_PARAMETERS; } diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 9df780f6..71e938c0 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -93,9 +93,9 @@ static OD_size_t OD_write_1016(OD_stream_t *stream, uint8_t subIndex, { CO_HBconsumer_t *HBcons = stream->object; - /* "count" is already verified in *_init() function */ - if (stream == NULL || buf == NULL || returnCode == NULL + if (stream == NULL || buf == NULL || subIndex < 1 || subIndex > HBcons->numberOfMonitoredNodes + || count != sizeof(uint32_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 0cdbece4..87773f2b 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -63,8 +63,9 @@ static OD_size_t OD_write_1017(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode) { - /* "count" is already verified in *_init() function */ - if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (stream == NULL || subIndex != 0 || buf == NULL + || count != sizeof(uint16_t) || returnCode == NULL + ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 982d19fb..ba737214 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -350,22 +350,25 @@ ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, return ret; } -ODR_t OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, void **val, - OD_size_t *len) +void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, + ODR_t *err) { - ODR_t ret; + ODR_t errCopy; OD_IO_t io; OD_stream_t *stream = &io.stream; - ret = OD_getSub(entry, subIndex, &io, true); - - if (ret != ODR_OK) return ret; - if (val == NULL || stream->dataOrig == NULL || stream->dataLength == 0) - return ODR_DEV_INCOMPAT; + errCopy = OD_getSub(entry, subIndex, &io, true); - *val = stream->dataOrig; + if (errCopy == ODR_OK) { + if (stream->dataOrig == NULL || stream->dataLength == 0) { + errCopy = ODR_DEV_INCOMPAT; + } + else if (len != stream->dataLength) { + errCopy = ODR_TYPE_MISMATCH; + } + } - if (len != NULL) *len = stream->dataLength; + if (err != NULL) *err = errCopy; - return ret; + return errCopy == ODR_OK ? stream->dataOrig : NULL; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index f228aa5e..47c1af5f 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -624,14 +624,13 @@ ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. - * @param [out] val Pointer to variable will be written here. - * @param [out] len Variable length will be written here. (allow NULL) + * @param len Required length of the variable. + * @param [out] err Error reason is written here in case of error (allow NULL). * - * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if - * variable does not exist in object dictionary or other reason. + * @return Pointer to variable in Object Dictionary or NULL in case of error. */ -ODR_t OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, void **val, - OD_size_t *len); +void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, + ODR_t *err); /** @} */ /* CO_ODgetSetters */ diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 1dd02973..0128c336 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -33,7 +33,8 @@ * Read received message from CAN module. * * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. + * message with correct identifier will be received. For more information and + * description of parameters see file CO_driver.h. */ static void CO_TIME_receive(void *object, void *msg) { CO_TIME_t *TIME = object; @@ -64,8 +65,9 @@ static OD_size_t OD_write_1012(OD_stream_t *stream, uint8_t subIndex, const void *buf, OD_size_t count, ODR_t *returnCode) { - /* "count" is already verified in *_init() function */ - if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (stream == NULL || subIndex != 0 || buf == NULL + || count != sizeof(uint32_t) || returnCode == NULL + ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 97176be2..d8dbe49a 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -125,7 +125,7 @@ typedef struct { * Function must be called in the communication reset section. * * @param TIME This object will be initialized. - * @param OD_1012_cobIdTimeStamp OD entry for 0x1012 -"COB-ID time stamp", + * @param OD_1012_cobIdTimeStamp OD entry for 0x1012 - "COB-ID time stamp", * entry is required. * @param CANdevRx CAN device for TIME reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. From bc54b697f45809f69020f0b42e44cd821db1e80d Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 25 Feb 2021 08:35:55 +0100 Subject: [PATCH 160/520] CO_Emergency fix: CANdevTx is not optional field. CO_EM_init() arguments changed. --- 301/CO_Emergency.c | 8 ++++---- 301/CO_Emergency.h | 8 ++++---- CANopen.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 0d013a49..b4967da8 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -351,10 +351,10 @@ static void CO_EM_receive(void *object, void *msg) { /******************************************************************************/ CO_ReturnError_t CO_EM_init(CO_EM_t *em, + CO_CANmodule_t *CANdevTx, const OD_entry_t *OD_1001_errReg, #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER OD_entry_t *OD_1014_cobIdEm, - CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT OD_entry_t *OD_1015_InhTime, @@ -396,6 +396,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* clear the object */ memset(em, 0, sizeof(CO_EM_t)); + /* set object variables */ + em->CANdevTx = CANdevTx; + /* get and verify "Error register" from Object Dictionary */ em->errorRegister = OD_getPtr(OD_1001_errReg, 0, sizeof(uint8_t), NULL); if (em->errorRegister == NULL) { @@ -451,7 +454,6 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* configure parameters and emergency message CAN transmission */ em->nodeId = nodeId; - em->CANdevTx = CANdevTx; em->CANtxBuff = CO_CANtxBufferInit( CANdevTx, /* CAN device */ @@ -555,7 +557,6 @@ void CO_EM_process(CO_EM_t *em, (void)timerNext_us; /* may be unused */ /* verify errors from driver */ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) uint16_t CANerrSt = em->CANdevTx->CANerrorStatus; if (CANerrSt != em->CANerrorStatusOld) { uint16_t CANerrStChanged = CANerrSt ^ em->CANerrorStatusOld; @@ -590,7 +591,6 @@ void CO_EM_process(CO_EM_t *em, CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0, CO_EM_CAN_RXB_OVERFLOW, CO_EM_CAN_RXB_OVERFLOW, 0); } -#endif /* calculate Error register */ uint8_t errorRegister = 0U; diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 41c740fc..7b8ea455 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -373,6 +373,8 @@ typedef struct { uint8_t *errorRegister; /** Old CAN error status bitfield */ uint16_t CANerrorStatusOld; + /** From CO_EM_init() */ + CO_CANmodule_t *CANdevTx; #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ || defined CO_DOXYGEN @@ -403,8 +405,6 @@ typedef struct { bool_t producerEnabled; /** Copy of CANopen node ID, from CO_EM_init() */ uint8_t nodeId; - /** From CO_EM_init() */ - CO_CANmodule_t *CANdevTx; /** CAN transmit buffer */ CO_CANtx_t *CANtxBuff; /** Extension for OD object */ @@ -459,11 +459,11 @@ typedef struct { * Function must be called in the communication reset section. * * @param em This object will be initialized. + * @param CANdevTx CAN device for Emergency transmission. * @param OD_1001_errReg OD entry for 0x1001 - "Error register", entry is * required, without IO extension. * @param OD_1014_cobIdEm OD entry for 0x1014 - "COB-ID EMCY", entry is * required, IO extension is required. - * @param CANdevTx CAN device for Emergency transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. * @param OD_1015_InhTime OD entry for 0x1015 - "Inhibit time EMCY", entry is * optional (can be NULL), IO extension is optional for runtime configuration. @@ -483,10 +483,10 @@ typedef struct { * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ CO_ReturnError_t CO_EM_init(CO_EM_t *em, + CO_CANmodule_t *CANdevTx, const OD_entry_t *OD_1001_errReg, #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN OD_entry_t *OD_1014_cobIdEm, - CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) || defined CO_DOXYGEN OD_entry_t *OD_1015_InhTime, diff --git a/CANopen.c b/CANopen.c index fcdf91fe..be524f3e 100644 --- a/CANopen.c +++ b/CANopen.c @@ -960,10 +960,10 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, /* Emergency */ if (CO_GET_CNT(EM) == 1) { err = CO_EM_init(co->em, + co->CANmodule, OD_GET(H1001, OD_H1001_ERR_REG), #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER OD_GET(H1014, OD_H1014_COBID_EMERGENCY), - co->CANmodule, CO_GET_CO(TX_IDX_EM_PROD), #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT OD_GET(H1015, OD_H1015_INHIBIT_TIME_EMCY), From 9b3f329d525a2e8c946a0c70dd6f274a5fb3844a Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 1 Mar 2021 11:06:09 +0100 Subject: [PATCH 161/520] 301/CO_SYNC.h/c updated to newOD. --- 301/CO_NMT_Heartbeat.h | 2 +- 301/CO_ODinterface.c | 2 +- 301/CO_ODinterface.h | 3 +- 301/CO_PDO.h | 2 +- 301/CO_SYNC.c | 631 ++++++++++++++++++----------------- 301/CO_SYNC.h | 185 +++++----- CANopen.c | 31 +- example/CO_driver_target.h | 8 - socketCAN/CO_driver_target.h | 9 - 9 files changed, 461 insertions(+), 412 deletions(-) diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 8b9d7c32..b60b98fd 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -131,7 +131,7 @@ typedef enum { * to CANopen error register. * * Internal NMT state is controlled also with external NMT command, - * @ref CO_NMT_setInternalState() or @ref CO_NMT_sendCommand() functions. + * @ref CO_NMT_sendInternalCommand() or @ref CO_NMT_sendCommand() functions. */ typedef enum { /** First 8 bits can be used to specify bitmask for the diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index ba737214..53e5fa7c 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -363,7 +363,7 @@ void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, if (stream->dataOrig == NULL || stream->dataLength == 0) { errCopy = ODR_DEV_INCOMPAT; } - else if (len != stream->dataLength) { + else if (len != 0 && len != stream->dataLength) { errCopy = ODR_TYPE_MISMATCH; } } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 47c1af5f..e6a78bfb 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -624,7 +624,8 @@ ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. - * @param len Required length of the variable. + * @param len Required length of the variable. If len is different than zero, + * then actual length of the variable must match len or error is returned. * @param [out] err Error reason is written here in case of error (allow NULL). * * @return Pointer to variable in Object Dictionary or NULL in case of error. diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 9faaed60..d3f551f9 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -427,7 +427,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas); * @param TPDO This object. * @param syncWas True, if CANopen SYNC message was just received or transmitted. * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param [out] timerNext_us info to OS - see CO_process_SYNC_PDO(). + * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_TPDO_process( CO_TPDO_t *TPDO, diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 6669e1c3..6c15fec3 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -4,7 +4,7 @@ * @file CO_SYNC.c * @ingroup CO_SYNC * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2021 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -23,10 +23,6 @@ * limitations under the License. */ - -#include "301/CO_SDOserver.h" -#include "301/CO_Emergency.h" -#include "301/CO_NMT_Heartbeat.h" #include "301/CO_SYNC.h" #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE @@ -39,296 +35,318 @@ * description of parameters see file CO_driver.h. */ static void CO_SYNC_receive(void *object, void *msg) { - CO_SYNC_t *SYNC; - CO_NMT_internalState_t operState; - - SYNC = (CO_SYNC_t*)object; /* this is the correct pointer type of the first argument */ - operState = *SYNC->operatingState; + CO_SYNC_t *SYNC = object; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + bool_t syncReceived = false; - if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){ - uint8_t DLC = CO_CANrxMsg_readDLC(msg); - - if(SYNC->counterOverflowValue == 0){ - if(DLC == 0U){ - CO_FLAG_SET(SYNC->CANrxNew); - } - else{ - SYNC->receiveError = (uint16_t)DLC | 0x0100U; - } + if (SYNC->counterOverflowValue == 0) { + if (DLC == 0) { + syncReceived = true; } - else{ - if(DLC == 1U){ - uint8_t *data = CO_CANrxMsg_readData(msg); - SYNC->counter = data[0]; - CO_FLAG_SET(SYNC->CANrxNew); - } - else{ - SYNC->receiveError = (uint16_t)DLC | 0x0200U; - } - } - if(CO_FLAG_READ(SYNC->CANrxNew)) { - SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; - -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles SYNC. */ - if(SYNC->pFunctSignalPre != NULL) { - SYNC->pFunctSignalPre(SYNC->functSignalObjectPre); - } -#endif + else { + SYNC->receiveError = DLC | 0x40; } } -} - - -/* - * Function for accessing _COB ID SYNC Message_ (index 0x1005) from SDO server. - * - * For more information see file CO_SDOserver.h. - */ -static CO_SDO_abortCode_t CO_ODF_1005(CO_ODF_arg_t *ODF_arg){ - CO_SYNC_t *SYNC; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - SYNC = (CO_SYNC_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - if(!ODF_arg->reading){ - uint8_t configureSyncProducer = 0; - - /* only 11-bit CAN identifier is supported */ - if(value & 0x20000000UL){ - ret = CO_SDO_AB_INVALID_VALUE; + else { + if (DLC == 1) { + uint8_t *data = CO_CANrxMsg_readData(msg); + SYNC->counter = data[0]; + syncReceived = true; } - else{ - /* is 'generate Sync messge' bit set? */ - if(value & 0x40000000UL){ - /* if bit was set before, value can not be changed */ - if(SYNC->isProducer){ - ret = CO_SDO_AB_DATA_DEV_STATE; - } - else{ - configureSyncProducer = 1; - } - } + else { + SYNC->receiveError = DLC | 0x80; } + } - /* configure sync producer */ - if(ret == CO_SDO_AB_NONE){ - SYNC->COB_ID = (uint16_t)(value & 0x7FFU); + if (syncReceived) { + /* toggle PDO receive buffer */ + SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; - if(configureSyncProducer){ - uint8_t len = 0U; - if(SYNC->counterOverflowValue != 0U){ - len = 1U; - SYNC->counter = 0U; - SYNC->timer = 0U; - } - SYNC->CANtxBuff = CO_CANtxBufferInit( - SYNC->CANdevTx, /* CAN device */ - SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ - SYNC->COB_ID, /* CAN identifier */ - 0, /* rtr */ - len, /* number of data bytes */ - 0); /* synchronous message flag bit */ - - if (SYNC->CANtxBuff == NULL) { - ret = CO_SDO_AB_DATA_DEV_STATE; - SYNC->isProducer = false; - } else { - SYNC->isProducer = true; - } - } - else{ - SYNC->isProducer = false; - } - } + CO_FLAG_SET(SYNC->CANrxNew); - /* configure sync consumer */ - if (ret == CO_SDO_AB_NONE) { - CO_ReturnError_t CANret = CO_CANrxBufferInit( - SYNC->CANdevRx, /* CAN device */ - SYNC->CANdevRxIdx, /* rx buffer index */ - SYNC->COB_ID, /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void*)SYNC, /* object passed to receive function */ - CO_SYNC_receive); /* this function will process received message */ - - if (CANret != CO_ERROR_NO) { - ret = CO_SDO_AB_DATA_DEV_STATE; - } +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles SYNC.*/ + if (SYNC->pFunctSignalPre != NULL) { + SYNC->pFunctSignalPre(SYNC->functSignalObjectPre); } +#endif } - - return ret; } +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC /* - * Function for accessing _Communication cycle period_ (index 0x1006) from SDO server. + * Custom function for writing OD object "COB-ID sync message" * - * For more information see file CO_SDOserver.h. + * For more information see file CO_ODinterface.h, OD_IO_t. */ -static CO_SDO_abortCode_t CO_ODF_1006(CO_ODF_arg_t *ODF_arg){ - CO_SYNC_t *SYNC; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - SYNC = (CO_SYNC_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - if(!ODF_arg->reading){ - /* period transition from 0 to something */ - if((SYNC->periodTime == 0) && (value != 0)){ - SYNC->counter = 0; +static OD_size_t OD_write_1005(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + if (stream == NULL || subIndex != 0 || buf == NULL + || count != sizeof(uint32_t) || returnCode == NULL + ) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } + + CO_SYNC_t *SYNC = stream->object; + *returnCode = ODR_OK; + uint32_t cobIdSync = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(cobIdSync & 0x7FF); + + /* verify written value */ +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + bool_t isProducer = (cobIdSync & 0x40000000) != 0; + if ((cobIdSync & 0xBFFF8000) != 0 + || (SYNC->isProducer && isProducer && CAN_ID != SYNC->CAN_ID) + ) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } +#else + if ((cobIdSync & 0xFFFF8000) != 0) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } +#endif + + /* Configure CAN receive and transmit buffers */ + if (CAN_ID != SYNC->CAN_ID) { + CO_ReturnError_t CANret = CO_CANrxBufferInit( + SYNC->CANdevRx, /* CAN device */ + SYNC->CANdevRxIdx, /* rx buffer index */ + CAN_ID, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)SYNC, /* object passed to receive function */ + CO_SYNC_receive); /* this function will process received message*/ + + if (CANret != CO_ERROR_NO) { + *returnCode = ODR_DEV_INCOMPAT; + return 0; } - SYNC->periodTime = value; - SYNC->periodTimeoutTime = (value / 2U) * 3U; - /* overflow? */ - if(SYNC->periodTimeoutTime < value){ - SYNC->periodTimeoutTime = 0xFFFFFFFFUL; +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + SYNC->CANtxBuff = CO_CANtxBufferInit( + SYNC->CANdevTx, /* CAN device */ + SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ + CAN_ID, /* CAN identifier */ + 0, /* rtr */ + SYNC->counterOverflowValue != 0 ? 1 : 0, /* number of data bytes */ + 0); /* synchronous message flag bit */ + + if (SYNC->CANtxBuff == NULL) { + SYNC->isProducer = false; + *returnCode = ODR_DEV_INCOMPAT; + return 0; } +#endif + + SYNC->CAN_ID = CAN_ID; + } +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + SYNC->isProducer = isProducer; + if (isProducer) { + SYNC->counter = 0; SYNC->timer = 0; } +#endif /* CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ - return ret; + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); } - -/** - * Function for accessing _Synchronous counter overflow value_ (index 0x1019) from SDO server. +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +/* + * Custom function for writing OD object "Synchronous counter overflow value" * - * For more information see file CO_SDOserver.h. + * For more information see file CO_ODinterface.h, OD_IO_t. */ -static CO_SDO_abortCode_t CO_ODF_1019(CO_ODF_arg_t *ODF_arg){ - CO_SYNC_t *SYNC; - uint8_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - SYNC = (CO_SYNC_t*) ODF_arg->object; - value = ODF_arg->data[0]; +static OD_size_t OD_write_1019(OD_stream_t *stream, uint8_t subIndex, + const void *buf, OD_size_t count, + ODR_t *returnCode) +{ + if (stream == NULL || subIndex != 0 || buf == NULL + || count != sizeof(uint8_t) || returnCode == NULL + ) { + if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; + return 0; + } - if(!ODF_arg->reading){ - uint8_t len = 0U; + CO_SYNC_t *SYNC = stream->object; + *returnCode = ODR_OK; + uint8_t syncCounterOvf = CO_getUint8(buf); - if(SYNC->periodTime){ - ret = CO_SDO_AB_DATA_DEV_STATE; - } - else if((value == 1) || (value > 240)){ - ret = CO_SDO_AB_INVALID_VALUE; - } - else{ - SYNC->counterOverflowValue = value; - if(value != 0){ - len = 1U; - } + /* verify written value */ + if (syncCounterOvf == 1 || syncCounterOvf > 240) { + *returnCode = ODR_INVALID_VALUE; + return 0; + } + if (*SYNC->OD_1006_period != 0 && SYNC->isProducer) { + *returnCode = ODR_DATA_DEV_STATE; + return 0; + } - SYNC->CANtxBuff = CO_CANtxBufferInit( - SYNC->CANdevTx, /* CAN device */ - SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ - SYNC->COB_ID, /* CAN identifier */ - 0, /* rtr */ - len, /* number of data bytes */ - 0); /* synchronous message flag bit */ + /* Configure CAN transmit buffer */ + SYNC->CANtxBuff = CO_CANtxBufferInit( + SYNC->CANdevTx, /* CAN device */ + SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ + SYNC->CAN_ID, /* CAN identifier */ + 0, /* rtr */ + syncCounterOvf != 0 ? 1 : 0, /* number of data bytes */ + 0); /* synchronous message flag bit */ - if (SYNC->CANtxBuff == NULL) { - ret = CO_SDO_AB_DATA_DEV_STATE; - } - } + if (SYNC->CANtxBuff == NULL) { + SYNC->isProducer = false; + *returnCode = ODR_DEV_INCOMPAT; + return 0; } - return ret; + SYNC->counterOverflowValue = syncCounterOvf; + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, subIndex, buf, count, returnCode); } +#endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ +#endif /* (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC */ /******************************************************************************/ -CO_ReturnError_t CO_SYNC_init( - CO_SYNC_t *SYNC, - CO_EM_t *em, - CO_SDO_t *SDO, - CO_NMT_internalState_t *operatingState, - uint32_t COB_ID_SYNCMessage, - uint32_t communicationCyclePeriod, - uint8_t synchronousCounterOverflowValue, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx) +CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, + CO_EM_t *em, + OD_entry_t *OD_1005_cobIdSync, + OD_entry_t *OD_1006_commCyclePeriod, + OD_entry_t *OD_1007_syncWindowLen, + OD_entry_t *OD_1019_syncCounterOvf, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, +#endif + uint32_t *errInfo) { - uint8_t len = 0; - CO_ReturnError_t ret = CO_ERROR_NO; + ODR_t odRet; /* verify arguments */ - if(SYNC==NULL || em==NULL || SDO==NULL || operatingState==NULL || - CANdevRx==NULL || CANdevTx==NULL){ + if (SYNC == NULL || em == NULL || OD_1005_cobIdSync == NULL +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + || OD_1006_commCyclePeriod == NULL || CANdevTx == NULL +#endif + || CANdevRx == NULL + ) { return CO_ERROR_ILLEGAL_ARGUMENT; } - /* Configure object variables */ - SYNC->isProducer = (COB_ID_SYNCMessage&0x40000000L) ? true : false; - SYNC->COB_ID = COB_ID_SYNCMessage&0x7FF; - - SYNC->periodTime = communicationCyclePeriod; - SYNC->periodTimeoutTime = communicationCyclePeriod / 2 * 3; - /* overflow? */ - if(SYNC->periodTimeoutTime < communicationCyclePeriod) SYNC->periodTimeoutTime = 0xFFFFFFFFL; + /* clear object */ + memset(SYNC, 0, sizeof(CO_SYNC_t)); - SYNC->counterOverflowValue = synchronousCounterOverflowValue; - if(synchronousCounterOverflowValue) len = 1; + /* get and verify "COB-ID SYNC message" from OD and configure extension */ + uint32_t cobIdSync = 0x00000080; - SYNC->curentSyncTimeIsInsideWindow = true; + odRet = OD_get_u32(OD_1005_cobIdSync, 0, &cobIdSync, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1005_cobIdSync); + return CO_ERROR_OD_PARAMETERS; + } +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC + SYNC->OD_1005_extension.object = SYNC; + SYNC->OD_1005_extension.read = OD_readOriginal; + SYNC->OD_1005_extension.write = OD_write_1005; + OD_extension_init(OD_1005_cobIdSync, &SYNC->OD_1005_extension); +#endif - CO_FLAG_CLEAR(SYNC->CANrxNew); - SYNC->CANrxToggle = false; - SYNC->timer = 0; - SYNC->counter = 0; - SYNC->receiveError = 0U; + /* get and verify "Communication cycle period" from OD */ + SYNC->OD_1006_period = OD_getPtr(OD_1006_commCyclePeriod, 0, + sizeof(uint32_t), NULL); +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + if (SYNC->OD_1006_period == NULL) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1006_commCyclePeriod); + return CO_ERROR_OD_PARAMETERS; + } +#else + if (OD_1006_commCyclePeriod != NULL && SYNC->OD_1006_period == NULL) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1006_commCyclePeriod); + return CO_ERROR_OD_PARAMETERS; + } +#endif - SYNC->em = em; - SYNC->operatingState = operatingState; + /* get "Synchronous window length" from OD (optional parameter) */ + SYNC->OD_1007_window = OD_getPtr(OD_1007_syncWindowLen, 0, + sizeof(uint32_t), NULL); + if (OD_1007_syncWindowLen != NULL && SYNC->OD_1007_window == NULL) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1007_syncWindowLen); + return CO_ERROR_OD_PARAMETERS; + } - SYNC->CANdevRx = CANdevRx; - SYNC->CANdevRxIdx = CANdevRxIdx; + /* get and verify optional "Synchronous counter overflow value" from OD and + * configure extension */ + uint8_t syncCounterOvf = 0; -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE - SYNC->pFunctSignalPre = NULL; - SYNC->functSignalObjectPre = NULL; + if (OD_1019_syncCounterOvf != NULL) { + odRet = OD_get_u8(OD_1019_syncCounterOvf, 0, &syncCounterOvf, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_1019_syncCounterOvf); + return CO_ERROR_OD_PARAMETERS; + } + if (syncCounterOvf == 1) syncCounterOvf = 2; + else if (syncCounterOvf > 240) syncCounterOvf = 240; + +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + SYNC->OD_1019_extension.object = SYNC; + SYNC->OD_1019_extension.read = OD_readOriginal; + SYNC->OD_1019_extension.write = OD_write_1019; + OD_extension_init(OD_1019_syncCounterOvf, &SYNC->OD_1019_extension); #endif +#endif + } + SYNC->counterOverflowValue = syncCounterOvf; - /* Configure Object dictionary entry at index 0x1005, 0x1006 and 0x1019 */ - CO_OD_configure(SDO, OD_H1005_COBID_SYNC, CO_ODF_1005, (void*)SYNC, 0, 0); - CO_OD_configure(SDO, OD_H1006_COMM_CYCL_PERIOD, CO_ODF_1006, (void*)SYNC, 0, 0); - CO_OD_configure(SDO, OD_H1019_SYNC_CNT_OVERFLOW, CO_ODF_1019, (void*)SYNC, 0, 0); - - /* configure SYNC CAN reception */ - ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - SYNC->COB_ID, /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void*)SYNC, /* object passed to receive function */ - CO_SYNC_receive); /* this function will process received message */ - - /* configure SYNC CAN transmission */ + /* Configure object variables */ + SYNC->em = em; +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + SYNC->isProducer = (cobIdSync & 0x40000000) != 0; +#endif +#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC + SYNC->CAN_ID = cobIdSync & 0x7FF; + SYNC->CANdevRx = CANdevRx; + SYNC->CANdevRxIdx = CANdevRxIdx; + #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER SYNC->CANdevTx = CANdevTx; SYNC->CANdevTxIdx = CANdevTxIdx; - SYNC->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - SYNC->COB_ID, /* CAN identifier */ - 0, /* rtr */ - len, /* number of data bytes */ - 0); /* synchronous message flag bit */ + #endif +#endif - if (SYNC->CANtxBuff == NULL) { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } + /* configure SYNC CAN reception and transmission */ + CO_ReturnError_t ret = CO_CANrxBufferInit( + CANdevRx, /* CAN device */ + CANdevRxIdx, /* rx buffer index */ + cobIdSync & 0x7FF, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)SYNC, /* object passed to receive function */ + CO_SYNC_receive); /* this function will process received message*/ + if (ret != CO_ERROR_NO) + return ret; + +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + SYNC->CANtxBuff = CO_CANtxBufferInit( + CANdevTx, /* CAN device */ + CANdevTxIdx, /* index of specific buffer inside CAN module */ + cobIdSync & 0x7FF, /* CAN identifier */ + 0, /* rtr */ + syncCounterOvf != 0 ? 1 : 0, /* number of data bytes */ + 0); /* synchronous message flag bit */ + + if (SYNC->CANtxBuff == NULL) + return CO_ERROR_ILLEGAL_ARGUMENT; +#endif - return ret; + return CO_ERROR_NO; } @@ -339,105 +357,112 @@ void CO_SYNC_initCallbackPre( void *object, void (*pFunctSignalPre)(void *object)) { - if(SYNC != NULL){ + if (SYNC != NULL) { SYNC->functSignalObjectPre = object; SYNC->pFunctSignalPre = pFunctSignalPre; } } #endif -/******************************************************************************/ -CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC){ - if(++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1; - SYNC->timer = 0; - SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; - SYNC->CANtxBuff->data[0] = SYNC->counter; - return CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff); -} /******************************************************************************/ -CO_SYNC_status_t CO_SYNC_process( - CO_SYNC_t *SYNC, - uint32_t timeDifference_us, - uint32_t ObjDict_synchronousWindowLength, - uint32_t *timerNext_us) +CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, + bool_t NMTisPreOrOperational, + uint32_t timeDifference_us, + uint32_t *timerNext_us) { (void)timerNext_us; /* may be unused */ CO_SYNC_status_t ret = CO_SYNC_NONE; - uint32_t timerNew; - if(*SYNC->operatingState == CO_NMT_OPERATIONAL || *SYNC->operatingState == CO_NMT_PRE_OPERATIONAL){ + if (NMTisPreOrOperational) { /* update sync timer, no overflow */ - timerNew = SYNC->timer + timeDifference_us; - if(timerNew > SYNC->timer) SYNC->timer = timerNew; + uint32_t timerNew = SYNC->timer + timeDifference_us; + if (timerNew > SYNC->timer) SYNC->timer = timerNew; /* was SYNC just received */ - if(CO_FLAG_READ(SYNC->CANrxNew)){ + if (CO_FLAG_READ(SYNC->CANrxNew)) { SYNC->timer = 0; - ret = CO_SYNC_RECEIVED; + ret = CO_SYNC_RX_TX; CO_FLAG_CLEAR(SYNC->CANrxNew); } - /* SYNC producer */ - if(SYNC->isProducer && SYNC->periodTime){ - if(SYNC->timer >= SYNC->periodTime){ - ret = CO_SYNC_RECEIVED; - CO_SYNCsend(SYNC); + uint32_t OD_1006_period = SYNC->OD_1006_period != NULL + ? *SYNC->OD_1006_period : 0; + + if (OD_1006_period > 0) { +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + if (SYNC->isProducer) { + if (SYNC->timer >= OD_1006_period) { + ret = CO_SYNC_RX_TX; + CO_SYNCsend(SYNC); + } + #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT + /* Calculate when next SYNC needs to be sent */ + if (timerNext_us != NULL) { + uint32_t diff = OD_1006_period - SYNC->timer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } + #endif } + else +#endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ + + /* Verify timeout of SYNC */ + { + /* periodTimeout is 1,5 * OD_1006_period, no overflow */ + uint32_t periodTimeout = OD_1006_period + (OD_1006_period >> 1); + if (periodTimeout < OD_1006_period) periodTimeout = 0xFFFFFFFF; + + if (SYNC->timer > periodTimeout) { + CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, + CO_EMC_COMMUNICATION, SYNC->timer); + SYNC->timeoutError = true; + } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT - /* Calculate when next SYNC needs to be sent */ - if(timerNext_us != NULL){ - uint32_t diff = SYNC->periodTime - SYNC->timer; - if(*timerNext_us > diff){ - *timerNext_us = diff; + else if (timerNext_us != NULL) { + uint32_t diff = periodTimeout - SYNC->timer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } } - } #endif - } + } + } /* if (OD_1006_period > 0) */ /* Synchronous PDOs are allowed only inside time window */ - if(ObjDict_synchronousWindowLength){ - if(SYNC->timer > ObjDict_synchronousWindowLength){ - if(SYNC->curentSyncTimeIsInsideWindow){ - ret = CO_SYNC_OUTSIDE_WINDOW; - } - SYNC->curentSyncTimeIsInsideWindow = false; - } - else{ - SYNC->curentSyncTimeIsInsideWindow = true; + uint32_t OD_1007_window = SYNC->OD_1007_window != NULL + ? *SYNC->OD_1007_window : 0; + + if (OD_1007_window > 0 && SYNC->timer > OD_1007_window) { + if (!SYNC->syncIsOutsideWindow) { + ret = CO_SYNC_PASSED_WINDOW; } + SYNC->syncIsOutsideWindow = true; } - else{ - SYNC->curentSyncTimeIsInsideWindow = true; + else { + SYNC->syncIsOutsideWindow = false; } - /* Verify timeout of SYNC */ - if(SYNC->periodTime && (*SYNC->operatingState == CO_NMT_OPERATIONAL || *SYNC->operatingState == CO_NMT_PRE_OPERATIONAL)){ - if(SYNC->timer > SYNC->periodTimeoutTime) { - CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); - } - else { - CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION); -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT - if(timerNext_us != NULL) { - uint32_t diff = SYNC->periodTimeoutTime - SYNC->timer; - if(*timerNext_us > diff){ - *timerNext_us = diff; - } - } -#endif - } + /* verify error from receive function */ + if (SYNC->receiveError != 0) { + CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, + CO_EMC_SYNC_DATA_LENGTH, SYNC->receiveError); + SYNC->receiveError = 0; } - } + } /* if (NMTisPreOrOperational) */ else { CO_FLAG_CLEAR(SYNC->CANrxNew); + SYNC->receiveError = 0; + SYNC->counter = 0; + SYNC->timer = 0; } - /* verify error from receive function */ - if(SYNC->receiveError != 0U){ - CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, CO_EMC_SYNC_DATA_LENGTH, (uint32_t)SYNC->receiveError); - SYNC->receiveError = 0U; + if (SYNC->timeoutError && SYNC->timer == 0) { + CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, 0); + SYNC->timeoutError = false; } return ret; diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 4c79bc81..488fbc63 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -27,6 +27,9 @@ #define CO_SYNC_H #include "301/CO_driver.h" +#include "301/CO_ODinterface.h" +#include "301/CO_Emergency.h" + /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_SYNC @@ -76,57 +79,78 @@ extern "C" { /** * SYNC producer and consumer object. */ -typedef struct{ - CO_EM_t *em; /**< From CO_SYNC_init() */ - CO_NMT_internalState_t *operatingState; /**< From CO_SYNC_init() */ - /** True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ - variable from Object dictionary (index 0x1005). */ - bool_t isProducer; - /** COB_ID of SYNC message. Calculated from _COB ID SYNC Message_ - variable from Object dictionary (index 0x1005). */ - uint16_t COB_ID; - /** Sync period time in [microseconds]. Calculated from _Communication cycle period_ - variable from Object dictionary (index 0x1006). */ - uint32_t periodTime; - /** Sync period timeout time in [microseconds]. - (periodTimeoutTime = periodTime * 1,5) */ - uint32_t periodTimeoutTime; - /** Value from _Synchronous counter overflow value_ variable from Object - dictionary (index 0x1019) */ - uint8_t counterOverflowValue; - /** True, if current time is inside synchronous window. - In this case synchronous PDO may be sent. */ - bool_t curentSyncTimeIsInsideWindow; +typedef struct { + /** From CO_SYNC_init() */ + CO_EM_t *em; /** Indicates, if new SYNC message received from CAN bus */ - volatile void *CANrxNew; + volatile void *CANrxNew; + /** Set to nonzero value, if SYNC with wrong data length is received */ + uint8_t receiveError; /** Variable toggles, if new SYNC message received from CAN bus */ - bool_t CANrxToggle; - /** Counter of the SYNC message if counterOverflowValue is different than zero */ - uint8_t counter; + bool_t CANrxToggle; + /** True in sync timeout error state */ + bool_t timeoutError; + /** Value from _Synchronous counter overflow value_ variable from Object + dictionary (index 0x1019) */ + uint8_t counterOverflowValue; + /** Counter of the SYNC message if counterOverflowValue is different than + * zero */ + uint8_t counter; + /** True, if current time is outside "synchronous window" (OD 1007) */ + bool_t syncIsOutsideWindow; /** Timer for the SYNC message in [microseconds]. Set to zero after received or transmitted SYNC message */ - uint32_t timer; - /** Set to nonzero value, if SYNC with wrong data length is received from CAN */ - uint16_t receiveError; + uint32_t timer; + /**Pointer to variable in OD, "Communication cycle period" in microseconds*/ + uint32_t *OD_1006_period; + /** Pointer to variable in OD, "Synchronous window length" in microseconds*/ + uint32_t *OD_1007_window; + +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) || defined CO_DOXYGEN + /** True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ + variable from Object dictionary (index 0x1005). */ + bool_t isProducer; + /** CAN transmit buffer inside CANdevTx */ + CO_CANtx_t *CANtxBuff; +#endif + +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN + /** From CO_SYNC_init() */ + CO_CANmodule_t *CANdevRx; + /** From CO_SYNC_init() */ + uint16_t CANdevRxIdx; + /** Extension for OD object */ + OD_extension_t OD_1005_extension; + /** CAN ID of the SYNC message. Calculated from _COB ID SYNC Message_ + variable from Object dictionary (index 0x1005). */ + uint16_t CAN_ID; + #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) || defined CO_DOXYGEN + /** From CO_SYNC_init() */ + CO_CANmodule_t *CANdevTx; + /** From CO_SYNC_init() */ + uint16_t CANdevTxIdx; + /** Extension for OD object */ + OD_extension_t OD_1019_extension; + #endif +#endif + #if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_SYNC_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_SYNC_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void *functSignalObjectPre; #endif - CO_CANmodule_t *CANdevRx; /**< From CO_SYNC_init() */ - uint16_t CANdevRxIdx; /**< From CO_SYNC_init() */ - CO_CANmodule_t *CANdevTx; /**< From CO_SYNC_init() */ - CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ - uint16_t CANdevTxIdx; /**< From CO_SYNC_init() */ -}CO_SYNC_t; +} CO_SYNC_t; -/** Return value for #CO_SYNC_process */ +/** Return value for @ref CO_SYNC_process */ typedef enum { - CO_SYNC_NONE = 0, /**< SYNC not received */ - CO_SYNC_RECEIVED = 1, /**< SYNC received */ - CO_SYNC_OUTSIDE_WINDOW = 2 /**< SYNC received outside SYNC window */ + /** No SYNC event in last cycle */ + CO_SYNC_NONE = 0, + /** SYNC message was received or transmitted in last cycle */ + CO_SYNC_RX_TX = 1, + /** Time has just passed SYNC window (OD_1007) in last cycle */ + CO_SYNC_PASSED_WINDOW = 2 } CO_SYNC_status_t; @@ -137,30 +161,35 @@ typedef enum { * * @param SYNC This object will be initialized. * @param em Emergency object. - * @param SDO SDO server object. - * @param operatingState Pointer to variable indicating CANopen device NMT internal state. - * @param COB_ID_SYNCMessage From Object dictionary (index 0x1005). - * @param communicationCyclePeriod From Object dictionary (index 0x1006). - * @param synchronousCounterOverflowValue From Object dictionary (index 0x1019). + * @param OD_1005_cobIdSync OD entry for 0x1005 - "COB-ID SYNC message", + * entry is required. + * @param OD_1006_commCyclePeriod OD entry for 0x1006 - "Communication cycle + * period", entry is required if device is sync producer. + * @param OD_1007_syncWindowLen OD entry for 0x1007 - "Synchronous window + * length", entry is optional, may be NULL. + * @param OD_1019_syncCounterOvf OD entry for 0x1019 - "Synchronous counter + * overflow value", entry is optional, may be NULL. * @param CANdevRx CAN device for SYNC reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for SYNC transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. + * @param [out] errInfo Additional information in case of error, may be NULL. * - * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_SYNC_init( - CO_SYNC_t *SYNC, - CO_EM_t *em, - CO_SDO_t *SDO, - CO_NMT_internalState_t *operatingState, - uint32_t COB_ID_SYNCMessage, - uint32_t communicationCyclePeriod, - uint8_t synchronousCounterOverflowValue, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx); +CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, + CO_EM_t *em, + OD_entry_t *OD_1005_cobIdSync, + OD_entry_t *OD_1006_commCyclePeriod, + OD_entry_t *OD_1007_syncWindowLen, + OD_entry_t *OD_1019_syncCounterOvf, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) || defined CO_DOXYGEN + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, +#endif + uint32_t *errInfo); #if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN @@ -172,16 +201,16 @@ CO_ReturnError_t CO_SYNC_init( * Callback is called after SYNC message is received from the CAN bus. * * @param SYNC This object. - * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignalPre(). * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_SYNC_initCallbackPre( - CO_SYNC_t *SYNC, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_SYNC_initCallbackPre(CO_SYNC_t *SYNC, + void *object, + void (*pFunctSignalPre)(void *object)); #endif +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) || defined CO_DOXYGEN /** * Send SYNC message. * @@ -189,12 +218,18 @@ void CO_SYNC_initCallbackPre( * call this if direct control of SYNC transmission is needed, otherwise use * CO_SYNC_process(). * - * * @param SYNC SYNC object. * * @return Same as CO_CANsend(). */ -CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC); +static inline CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC) { + if (++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1; + SYNC->timer = 0; + SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; + SYNC->CANtxBuff->data[0] = SYNC->counter; + return CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff); +} +#endif /** @@ -203,18 +238,18 @@ CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC); * Function must be called cyclically. * * @param SYNC This object. - * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param ObjDict_synchronousWindowLength _Synchronous window length_ variable from - * Object dictionary (index 0x1007). - * @param [out] timerNext_us info to OS - see CO_process_SYNC_PDO(). + * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or + * NMT_OPERATIONAL state. + * @param timeDifference_us Time difference from previous function call in + * [microseconds]. + * @param [out] timerNext_us info to OS - see CO_process(). * - * @return #CO_SYNC_status_t: CO_SYNC_NONE, CO_SYNC_RECEIVED or CO_SYNC_OUTSIDE_WINDOW. + * @return @ref CO_SYNC_status_t */ -CO_SYNC_status_t CO_SYNC_process( - CO_SYNC_t *SYNC, - uint32_t timeDifference_us, - uint32_t ObjDict_synchronousWindowLength, - uint32_t *timerNext_us); +CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, + bool_t NMTisPreOrOperational, + uint32_t timeDifference_us, + uint32_t *timerNext_us); /** @} */ /* CO_SYNC */ diff --git a/CANopen.c b/CANopen.c index be524f3e..53edd91e 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1074,15 +1074,17 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, if (CO_GET_CNT(SYNC) == 1) { err = CO_SYNC_init(co->SYNC, em, - co->SDO[0], - &co->NMT->operatingState, - OD_COB_ID_SYNCMessage, - OD_communicationCyclePeriod, - OD_synchronousCounterOverflowValue, + OD_GET(H1005, OD_H1005_COBID_SYNC), + OD_GET(H1006, OD_H1006_COMM_CYCL_PERIOD), + OD_GET(H1007, OD_H1007_SYNC_WINDOW_LEN), + OD_GET(H1019, OD_H1019_SYNC_CNT_OVERFLOW), co->CANmodule, CO_GET_CO(RX_IDX_SYNC), +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER co->CANmodule, - CO_GET_CO(TX_IDX_SYNC)); + CO_GET_CO(TX_IDX_SYNC), +#endif + errInfo); if (err) return err; } #endif @@ -1377,19 +1379,22 @@ bool_t CO_process_SYNC(CO_t *co, bool_t syncWas = false; if (!co->nodeIdUnconfigured && CO_GET_CNT(SYNC) == 1) { - const CO_SYNC_status_t sync_process = - CO_SYNC_process(co->SYNC, - timeDifference_us, - OD_synchronousWindowLength, - timerNext_us); + CO_NMT_internalState_t NMTstate = CO_NMT_getInternalState(co->NMT); + bool_t NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL + || NMTstate == CO_NMT_OPERATIONAL); + + CO_SYNC_status_t sync_process = CO_SYNC_process(co->SYNC, + NMTisPreOrOperational, + timeDifference_us, + timerNext_us); switch (sync_process) { case CO_SYNC_NONE: break; - case CO_SYNC_RECEIVED: + case CO_SYNC_RX_TX: syncWas = true; break; - case CO_SYNC_OUTSIDE_WINDOW: + case CO_SYNC_PASSED_WINDOW: CO_CANclearPendingSyncPDOs(co->CANmodule); break; } diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index b94124dd..0346838f 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -103,14 +103,6 @@ extern "C" { CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ - CO_CONFIG_SYNC_PRODUCER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - #ifndef CO_CONFIG_PDO #define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ CO_CONFIG_TPDO_ENABLE | \ diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 63946b29..70a16a35 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -55,7 +55,6 @@ extern "C" { #endif /* TODO some parts are disabled in non-finished pre-release */ -#define CO_CONFIG_SYNC (0) #define CO_CONFIG_PDO (0) #define CO_CONFIG_TRACE (0) @@ -124,14 +123,6 @@ extern "C" { CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ - CO_CONFIG_SYNC_PRODUCER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - #ifndef CO_CONFIG_PDO #define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ CO_CONFIG_TPDO_ENABLE | \ From fc817770974e31656eea89998f4f2c612432528a Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 2 Mar 2021 21:28:22 +0100 Subject: [PATCH 162/520] Pass CO_CANmodule_t argument to all the CO_LOCK_...() and CO_UNLOCK_...() macros. https://github.com/CANopenNode/CANopenNode/issues/162#issuecomment-777438875 --- 301/CO_Emergency.c | 4 +-- 301/CO_ODinterface.c | 4 --- 301/CO_ODinterface.h | 22 +++++++++++++++-- 301/CO_SDOclient.c | 7 ++++++ 301/CO_SDOserver.c | 18 ++++++++++++++ 301/CO_driver.h | 45 +++++++++++++++++++++------------- 301/CO_storage.c | 12 ++++++--- 301/CO_storage.h | 15 +++++++++--- CANopen.c | 1 + doc/objectDictionary.md | 2 ++ example/CO_driver_blank.c | 8 +++--- example/CO_driver_target.h | 12 ++++----- socketCAN/CO_driver_target.h | 28 ++++++++++++--------- socketCAN/CO_epoll_interface.c | 4 +-- socketCAN/CO_main_basic.c | 15 ++++++------ socketCAN/CO_storageLinux.c | 18 ++++++++------ socketCAN/CO_storageLinux.h | 2 ++ 17 files changed, 146 insertions(+), 71 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index b4967da8..82a915de 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -739,7 +739,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, #endif /* safely write data, and increment pointers */ - CO_LOCK_EMCY(); + CO_LOCK_EMCY(em->CANdevTx); if (setError) *errorStatusBits |= bitmask; else *errorStatusBits &= ~bitmask; @@ -763,7 +763,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, } #endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ - CO_UNLOCK_EMCY(); + CO_UNLOCK_EMCY(em->CANdevTx); #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 53e5fa7c..dbc66a73 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -70,9 +70,7 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, } } - CO_LOCK_OD(); memcpy(buf, dataOrig, dataLenToCopy); - CO_UNLOCK_OD(); return dataLenToCopy; } @@ -127,9 +125,7 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, return 0; } - CO_LOCK_OD(); memcpy(dataOrig, buf, dataLenToCopy); - CO_UNLOCK_OD(); return dataLenToCopy; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index e6a78bfb..ce96d671 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -404,6 +404,10 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index); * Find sub-object with specified sub-index on OD entry returned by OD_find. * Function populates io structure with sub-object data. * + * @warning + * Read and write functions may be called from different threads, so critical + * sections in custom functions must be observed, see @ref CO_critical_sections. + * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. * @param [out] io Structure will be populated on success. @@ -428,6 +432,21 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { } +/** + * Check, if OD variable is mappable to PDO or SRDO. + * + * If OD variable is mappable, then it may be necessary to protect read/write + * access from mainline function. See @ref CO_critical_sections. + * + * @param stream Object Dictionary stream object. + * + * @return true, if OD variable is mappable. + */ +static inline bool_t OD_mappable(OD_stream_t *stream) { + return (stream->attribute & (ODA_TRPDO | ODA_TRSRDO)) != 0; +} + + /** * Restart read or write operation on OD variable * @@ -476,8 +495,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); * * @warning * Read and write functions may be called from different threads, so critical - * sections in custom functions must be protected with @ref CO_LOCK_OD() and - * @ref CO_UNLOCK_OD(). + * sections in custom functions must be observed, see @ref CO_critical_sections. * * @param entry OD entry returned by @ref OD_find(). * @param extension Extension object, which must be initialized externally. diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 65d7988e..ff08e58a 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -622,9 +622,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } if (abortCode == CO_SDO_AB_NONE) { ODR_t odRet; + bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); + /* write data to Object Dictionary */ + if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, SDO_C->subIndex, buf, count, &odRet); + if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } /* verify for errors in write */ if (odRet != ODR_OK && odRet != ODR_PARTIAL) { @@ -1211,11 +1215,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ? countData : countFifo; uint8_t buf[countBuf + 1]; ODR_t odRet; + bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); /* load data from OD variable into the buffer */ + if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } OD_size_t countRd = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, SDO_C->subIndex, buf, countBuf, &odRet); + if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } if (odRet != ODR_OK && odRet != ODR_PARTIAL) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index ec353df9..684cd8d6 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -552,8 +552,13 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, /* write data */ ODR_t odRet; + bool_t lock = OD_mappable(&SDO->OD_IO.stream); + + if (lock) { CO_LOCK_OD(SDO->CANdevTx); } SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, SDO->buf, SDO->bufOffsetWr, &odRet); + if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } + SDO->bufOffsetWr = 0; /* verify write error value */ @@ -609,10 +614,14 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* load data from OD variable into the buffer */ ODR_t odRet; uint8_t *bufShifted = SDO->buf + countRemain; + bool_t lock = OD_mappable(&SDO->OD_IO.stream); + + if (lock) { CO_LOCK_OD(SDO->CANdevTx); } OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, bufShifted, countRdRequest, &odRet); + if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } if (odRet != ODR_OK && odRet != ODR_PARTIAL) { *abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); @@ -843,8 +852,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Copy data */ ODR_t odRet; + bool_t lock = OD_mappable(&SDO->OD_IO.stream); + + if (lock) { CO_LOCK_OD(SDO->CANdevTx); } SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, buf, dataSizeToWrite, &odRet); + if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } + if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); SDO->state = CO_SDO_ST_ABORT; @@ -1283,9 +1297,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #else /* Expedited transfer only */ /* load data from OD variable */ ODR_t odRet; + bool_t lock = OD_mappable(&SDO->OD_IO.stream); + + if (lock) { CO_LOCK_OD(SDO->CANdevTx); } OD_size_t count = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, &SDO->CANtxBuff->data[4], 4, &odRet); + if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } /* strings are allowed to be shorter */ if (odRet == ODR_PARTIAL diff --git a/301/CO_driver.h b/301/CO_driver.h index 09c7865c..066f1fd6 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -380,19 +380,30 @@ typedef struct { * Otherwise mutexes or semaphores can be used. * * #### Reentrant functions - * Functions CO_CANsend() from C_driver.h, CO_errorReport() from CO_Emergency.h - * and CO_errorReset() from CO_Emergency.h may be called from different threads. - * Critical sections must be protected. Either by disabling scheduler or - * interrupts or by mutexes or semaphores. + * Functions CO_CANsend() from C_driver.h, and CO_error() from CO_Emergency.h + * may be called from different threads. Critical sections must be protected. + * Either by disabling scheduler or interrupts or by mutexes or semaphores. + * Lock/unlock macro is called with pointer to CAN module, which may be used + * inside. * * #### Object Dictionary variables - * In general, there are two threads, which accesses OD variables: mainline and - * timer. CANopenNode initialization and SDO server runs in mainline. PDOs runs - * in faster timer thread. Processing of PDOs must not be interrupted by - * mainline. Mainline thread must protect sections, which accesses the same OD - * variables as timer thread. This care must also take the application. Note - * that not all variables are allowed to be mapped to PDOs, so they may not need - * to be protected. SDO server protects sections with access to OD variables. + * In general, there are two threads, which accesses OD variables: mainline + * (initialization, storage, SDO access) and timer (PDO access). CANopenNode + * uses locking mechanism, where SDO server (or other mainline code) prevents + * execution of the real-time thread at the moment it reads or writes OD + * variable. CO_LOCK_OD(CAN_MODULE) and CO_UNLOCK_OD(CAN_MODULE) macros + * are used to protect: + * - Whole real-time thread, + * - SDO server protects read/write access to OD variable, if specific OD + * variable has ODA_TRPDO or ODA_TRSRDO from @ref OD_attributes_t set. If + * those attributes are not set, OD variable is not locked by SDO server. + * Locking of long OD variables, not accessible from real-time thread, may + * block RT thread. + * - Any mainline code, which accesses PDO-mappable OD variable, must protect + * read/write with locking macros. Use @ref OD_mappable() for check. + * - Other cases, where non-PDO-mappable OD variable is used inside real-time + * thread by some other part of the user application must be considered with + * special care. * * #### Synchronization functions for CAN receive * After CAN message is received, it is pre-processed in CANrx_callback(), which @@ -411,17 +422,17 @@ typedef struct { */ /** Lock critical section in CO_CANsend() */ -#define CO_LOCK_CAN_SEND() +#define CO_LOCK_CAN_SEND(CAN_MODULE) /** Unlock critical section in CO_CANsend() */ -#define CO_UNLOCK_CAN_SEND() +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) /** Lock critical section in CO_errorReport() or CO_errorReset() */ -#define CO_LOCK_EMCY() +#define CO_LOCK_EMCY(CAN_MODULE) /** Unlock critical section in CO_errorReport() or CO_errorReset() */ -#define CO_UNLOCK_EMCY() +#define CO_UNLOCK_EMCY(CAN_MODULE) /** Lock critical section when accessing Object Dictionary */ -#define CO_LOCK_OD() +#define CO_LOCK_OD(CAN_MODULE) /** Unock critical section when accessing Object Dictionary */ -#define CO_UNLOCK_OD() +#define CO_UNLOCK_OD(CAN_MODULE) /** Check if new message has arrived */ #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) diff --git a/301/CO_storage.c b/301/CO_storage.c index 0f3c6057..9505d0d7 100644 --- a/301/CO_storage.c +++ b/301/CO_storage.c @@ -65,7 +65,7 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex, if (subIndex == 1 || entry->subIndexOD == subIndex) { if (found == 0) found = 1; if ((entry->attr & CO_storage_cmd) != 0) { - ODR_t code = storage->store(entry); + ODR_t code = storage->store(entry, storage->CANmodule); if (code != ODR_OK) *returnCode = code; found = 2; } @@ -117,7 +117,7 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, if (subIndex == 1 || entry->subIndexOD == subIndex) { if (found == 0) found = 1; if ((entry->attr & CO_storage_restore) != 0) { - ODR_t code = storage->restore(entry); + ODR_t code = storage->restore(entry, storage->CANmodule); if (code != ODR_OK) *returnCode = code; found = 2; } @@ -131,10 +131,13 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, CO_ReturnError_t CO_storage_init(CO_storage_t *storage, + CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParameters, - ODR_t (*store)(CO_storage_entry_t *entry), - ODR_t (*restore)(CO_storage_entry_t *entry), + ODR_t (*store)(CO_storage_entry_t *entry, + CO_CANmodule_t *CANmodule), + ODR_t (*restore)(CO_storage_entry_t *entry, + CO_CANmodule_t *CANmodule), CO_storage_entry_t *entries, uint8_t entriesCount) { @@ -144,6 +147,7 @@ CO_ReturnError_t CO_storage_init(CO_storage_t *storage, } /* Configure object variables */ + storage->CANmodule = CANmodule; storage->store = store; storage->restore = restore; storage->entries = entries; diff --git a/301/CO_storage.h b/301/CO_storage.h index fa15b8c8..d977c5a8 100644 --- a/301/CO_storage.h +++ b/301/CO_storage.h @@ -104,8 +104,11 @@ typedef enum { typedef struct { OD_extension_t OD_1010_extension; /**< Extension for OD object */ OD_extension_t OD_1011_extension; /**< Extension for OD object */ - ODR_t (*store)(CO_storage_entry_t *entry); /**< From CO_storage_init() */ - ODR_t (*restore)(CO_storage_entry_t *entry); /**< From CO_storage_init() */ + CO_CANmodule_t *CANmodule; /**< From CO_storage_init() */ + ODR_t (*store)(CO_storage_entry_t *entry, + CO_CANmodule_t *CANmodule); /**< From CO_storage_init() */ + ODR_t (*restore)(CO_storage_entry_t *entry, + CO_CANmodule_t *CANmodule); /**< From CO_storage_init() */ CO_storage_entry_t *entries; /**< From CO_storage_init() */ uint8_t entriesCount; /**< From CO_storage_init() */ } CO_storage_t; @@ -121,6 +124,7 @@ typedef struct { * * @param storage This object will be initialized. It must be defined by * application and must exist permanently. + * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". * Entry is optional, may be NULL. * @param OD_1011_RestoreDefaultParameters OD entry for 0x1011 -"Restore default @@ -146,10 +150,13 @@ typedef struct { * @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_storage_init(CO_storage_t *storage, + CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParameters, - ODR_t (*store)(CO_storage_entry_t *entry), - ODR_t (*restore)(CO_storage_entry_t *entry), + ODR_t (*store)(CO_storage_entry_t *entry, + CO_CANmodule_t *CANmodule), + ODR_t (*restore)(CO_storage_entry_t *entry, + CO_CANmodule_t *CANmodule), CO_storage_entry_t *entries, uint8_t entriesCount); diff --git a/CANopen.c b/CANopen.c index 53edd91e..769be237 100644 --- a/CANopen.c +++ b/CANopen.c @@ -916,6 +916,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, uint8_t nodeId, uint32_t *errInfo) { + (void)SDOclientTimeoutTime_ms; (void)SDOclientBlockTransfer; CO_ReturnError_t err; if (co == NULL diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 400fb6d0..bfc93bba 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -23,6 +23,8 @@ The term **OD entry** means structure element, which contains some basic propert ### Access Application and the stack have access to OD objects via universal @ref OD_t object and @ref OD_find() function. No direct access to custom structures, which define object dictionary, is required. Properties for specific OD variable is fetched with @ref OD_getSub() function. Access to actual variable is via **read** and **write** functions. Pointer to those two functions is fetched by @ref OD_getSub(). See @ref OD_stream_t. See also shortcuts: @ref CO_ODgetSetters, for access to data of different type. +Note that OD variables can be accessed from different threads. CANopenNode basically runs in two threads: fast real-time (PDO processing, etc.) and time non-critical mainline (SDO etc.). Both threads have access to OD variables, so care must be taken into account. CANopenNode uses locking mechanism, where SDO server prevents execution of the real-time thread at the moment it reads or writes OD variable. The same protection of the OD variables is necessary in @ref CO_storage. For more information see @ref CO_critical_sections in CO_driver.h. + ### Example usage ```c extern OD_t *ODxyz; diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index 66380be6..1cd404a7 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -200,7 +200,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ err = CO_ERROR_TX_OVERFLOW; } - CO_LOCK_CAN_SEND(); + CO_LOCK_CAN_SEND(CANmodule); /* if CAN TX buffer is free, copy message to it */ if(1 && CANmodule->CANtxCount == 0){ CANmodule->bufferInhibitFlag = buffer->syncFlag; @@ -211,7 +211,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ buffer->bufferFull = true; CANmodule->CANtxCount++; } - CO_UNLOCK_CAN_SEND(); + CO_UNLOCK_CAN_SEND(CANmodule); return err; } @@ -221,7 +221,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ uint32_t tpdoDeleted = 0U; - CO_LOCK_CAN_SEND(); + CO_LOCK_CAN_SEND(CANmodule); /* Abort message from CAN module, if there is synchronous TPDO. * Take special care with this functionality. */ if(/*messageIsOnCanBuffer && */CANmodule->bufferInhibitFlag){ @@ -244,7 +244,7 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ buffer++; } } - CO_UNLOCK_CAN_SEND(); + CO_UNLOCK_CAN_SEND(CANmodule); if(tpdoDeleted != 0U){ diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 0346838f..61a8d86e 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -233,16 +233,16 @@ typedef struct { /* (un)lock critical section in CO_CANsend() */ -#define CO_LOCK_CAN_SEND() -#define CO_UNLOCK_CAN_SEND() +#define CO_LOCK_CAN_SEND(CAN_MODULE) +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ -#define CO_LOCK_EMCY() -#define CO_UNLOCK_EMCY() +#define CO_LOCK_EMCY(CAN_MODULE) +#define CO_UNLOCK_EMCY(CAN_MODULE) /* (un)lock critical section when accessing Object Dictionary */ -#define CO_LOCK_OD() -#define CO_UNLOCK_OD() +#define CO_LOCK_OD(CAN_MODULE) +#define CO_UNLOCK_OD(CAN_MODULE) /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 70a16a35..2d88eae6 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -370,34 +370,38 @@ typedef struct { #ifdef CO_SINGLE_THREAD -#define CO_LOCK_CAN_SEND() -#define CO_UNLOCK_CAN_SEND() -#define CO_LOCK_EMCY() -#define CO_UNLOCK_EMCY() -#define CO_LOCK_OD() -#define CO_UNLOCK_OD() +#define CO_LOCK_CAN_SEND(CAN_MODULE) +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) +#define CO_LOCK_EMCY(CAN_MODULE) +#define CO_UNLOCK_EMCY(CAN_MODULE) +#define CO_LOCK_OD(CAN_MODULE) +#define CO_UNLOCK_OD(CAN_MODULE) #define CO_MemoryBarrier() #else /* (un)lock critical section in CO_CANsend() - unused */ -#define CO_LOCK_CAN_SEND() -#define CO_UNLOCK_CAN_SEND() +#define CO_LOCK_CAN_SEND(CAN_MODULE) +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ extern pthread_mutex_t CO_EMCY_mutex; -static inline int CO_LOCK_EMCY() { +static inline int CO_LOCK_EMCY(CO_CANmodule_t *CANmodule) { + (void)CANmodule; return pthread_mutex_lock(&CO_EMCY_mutex); } -static inline void CO_UNLOCK_EMCY() { +static inline void CO_UNLOCK_EMCY(CO_CANmodule_t *CANmodule) { + (void)CANmodule; (void)pthread_mutex_unlock(&CO_EMCY_mutex); } /* (un)lock critical section when accessing Object Dictionary */ extern pthread_mutex_t CO_OD_mutex; -static inline int CO_LOCK_OD() { +static inline int CO_LOCK_OD(CO_CANmodule_t *CANmodule) { + (void)CANmodule; return pthread_mutex_lock(&CO_OD_mutex); } -static inline void CO_UNLOCK_OD() { +static inline void CO_UNLOCK_OD(CO_CANmodule_t *CANmodule) { + (void)CANmodule; (void)pthread_mutex_unlock(&CO_OD_mutex); } diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c index aaed28a9..0be29218 100644 --- a/socketCAN/CO_epoll_interface.c +++ b/socketCAN/CO_epoll_interface.c @@ -329,7 +329,7 @@ void CO_epoll_processRT(CO_epoll_t *ep, if (!realtime || ep->timerEvent) { uint32_t *pTimerNext_us = realtime ? NULL : &ep->timerNext_us; - CO_LOCK_OD(); + CO_LOCK_OD(co->CANmodule); if (!co->nodeIdUnconfigured && co->CANmodule->CANnormal) { bool_t syncWas = false; @@ -346,7 +346,7 @@ void CO_epoll_processRT(CO_epoll_t *ep, #endif (void) syncWas; (void) pTimerNext_us; } - CO_UNLOCK_OD(); + CO_UNLOCK_OD(co->CANmodule); } } diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index f636045d..5c1f6c45 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -438,6 +438,7 @@ int main (int argc, char *argv[]) { #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE uint8_t pendingNodeIdOriginal = CO_pending.nodeId; err = CO_storageLinux_init(&storage, + CO->CANmodule, OD_ENTRY_H1010_storeParameters, OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, @@ -512,9 +513,9 @@ int main (int argc, char *argv[]) { /* Wait rt_thread. */ if(!firstRun) { - CO_LOCK_OD(); + CO_LOCK_OD(CO->CANmodule); CO->CANmodule->CANnormal = false; - CO_UNLOCK_OD(); + CO_UNLOCK_OD(CO->CANmodule); } /* Enter CAN configuration. */ @@ -695,17 +696,17 @@ int main (int argc, char *argv[]) { storageIntervalTimer += epMain.timeDifference_us; } else { - uint32_t err = CO_storageLinux_auto_process(&storage, false); - if(err != storageErrorPrev && !CO->nodeIdUnconfigured) { - if(err != 0) { + uint32_t mask = CO_storageLinux_auto_process(&storage, false); + if(mask != storageErrorPrev && !CO->nodeIdUnconfigured) { + if(mask != 0) { CO_errorReport(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, - CO_EMC_HARDWARE, err); + CO_EMC_HARDWARE, mask); } else { CO_errorReset(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, 0); } } - storageErrorPrev = err; + storageErrorPrev = mask; storageIntervalTimer = 0; } #endif diff --git a/socketCAN/CO_storageLinux.c b/socketCAN/CO_storageLinux.c index 014cb2f2..e2235727 100644 --- a/socketCAN/CO_storageLinux.c +++ b/socketCAN/CO_storageLinux.c @@ -37,7 +37,8 @@ * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t storeLinux(CO_storage_entry_t *entry) { +static ODR_t storeLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { + (void) CANmodule; ODR_t ret = ODR_OK; uint16_t crc_store; @@ -64,10 +65,10 @@ static ODR_t storeLinux(CO_storage_entry_t *entry) { ret = ODR_HW; } else { - CO_LOCK_OD(); + CO_LOCK_OD(CANmodule); size_t cnt = fwrite(entry->addr, 1, entry->len, fp); crc_store = crc16_ccitt(entry->addr, entry->len, 0); - CO_UNLOCK_OD(); + CO_UNLOCK_OD(CANmodule); cnt += fwrite(&crc_store, 1, sizeof(crc_store), fp); fclose(fp); if (cnt != (entry->len + sizeof(crc_store))) { @@ -123,7 +124,8 @@ static ODR_t storeLinux(CO_storage_entry_t *entry) { * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t restoreLinux(CO_storage_entry_t *entry) { +static ODR_t restoreLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule){ + (void) CANmodule; ODR_t ret = ODR_OK; /* close the file first, if auto storage */ @@ -161,6 +163,7 @@ static ODR_t restoreLinux(CO_storage_entry_t *entry) { CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, + CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParam, CO_storage_entry_t *entries, @@ -168,7 +171,6 @@ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, uint32_t *storageInitError) { CO_ReturnError_t ret; - *storageInitError = 0; /* verify arguments */ if (storage == NULL || entries == NULL || entriesCount == 0 @@ -179,6 +181,7 @@ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, /* initialize storage and OD extensions */ ret = CO_storage_init(storage, + CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeLinux, @@ -190,6 +193,7 @@ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, } /* initialize entries */ + *storageInitError = 0; for (uint8_t i = 0; i < entriesCount; i++) { CO_storage_entry_t *entry = &entries[i]; bool_t dataCorrupt = false; @@ -288,9 +292,9 @@ uint32_t CO_storageLinux_auto_process(CO_storage_t *storage, if (crc != entry->crc) { size_t cnt; rewind(entry->fp); - CO_LOCK_OD(); + CO_LOCK_OD(storage->CANmodule); cnt = fwrite(entry->addr, 1, entry->len, entry->fp); - CO_UNLOCK_OD(); + CO_UNLOCK_OD(storage->CANmodule); cnt += fwrite(&crc, 1, sizeof(crc), entry->fp); fflush(entry->fp); if (cnt == (entry->len + sizeof(crc))) { diff --git a/socketCAN/CO_storageLinux.h b/socketCAN/CO_storageLinux.h index 64bde660..04658997 100644 --- a/socketCAN/CO_storageLinux.h +++ b/socketCAN/CO_storageLinux.h @@ -55,6 +55,7 @@ extern "C" { * * @param storage This object will be initialized. It must be defined by * application and must exist permanently. + * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". * Entry is optional, may be NULL. * @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default @@ -70,6 +71,7 @@ extern "C" { * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY. */ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, + CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParam, CO_storage_entry_t *entries, From 5b8be4ef7eb8d59421664fd69130bd7e655cbcde Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 10 Mar 2021 15:22:03 +0100 Subject: [PATCH 163/520] CO_ODinterface: simplified API to read/write functions. subIndex moved to OD_stream_t. --- 301/CO_Emergency.c | 68 ++++++++++++++++++++---------------------- 301/CO_HBconsumer.c | 12 ++++---- 301/CO_NMT_Heartbeat.c | 9 +++--- 301/CO_ODinterface.c | 31 ++++++++----------- 301/CO_ODinterface.h | 28 ++++++++--------- 301/CO_SDOclient.c | 13 ++++---- 301/CO_SDOserver.c | 24 +++++++-------- 301/CO_SYNC.c | 18 +++++------ 301/CO_TIME.c | 9 +++--- 301/CO_storage.c | 22 +++++++------- 10 files changed, 106 insertions(+), 128 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 82a915de..d3929c8a 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -59,11 +59,10 @@ * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_read_1014(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_read_1014(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != sizeof(uint32_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -81,11 +80,10 @@ static OD_size_t OD_read_1014(OD_stream_t *stream, uint8_t subIndex, return sizeof(uint32_t); } -static OD_size_t OD_write_1014(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1014(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != sizeof(uint32_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -126,7 +124,7 @@ static OD_size_t OD_write_1014(OD_stream_t *stream, uint8_t subIndex, } /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } #else /* @@ -134,11 +132,10 @@ static OD_size_t OD_write_1014(OD_stream_t *stream, uint8_t subIndex, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_read_1014_default(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_read_1014_default(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != sizeof(uint32_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -161,11 +158,10 @@ static OD_size_t OD_read_1014_default(OD_stream_t *stream, uint8_t subIndex, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1015(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1015(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != sizeof(uint16_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -180,7 +176,7 @@ static OD_size_t OD_write_1015(OD_stream_t *stream, uint8_t subIndex, em->inhibitEmTimer = 0; /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ @@ -191,9 +187,8 @@ static OD_size_t OD_write_1015(OD_stream_t *stream, uint8_t subIndex, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_read_1003(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_read_1003(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode) { if (stream == NULL || buf == NULL || count < 4 || returnCode == NULL) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -203,14 +198,14 @@ static OD_size_t OD_read_1003(OD_stream_t *stream, uint8_t subIndex, CO_EM_t *em = (CO_EM_t *)stream->object; *returnCode = ODR_OK; - if (subIndex == 0) { + if (stream->subIndex == 0) { CO_setUint8(buf, em->fifoCount); return 1; } - else if (subIndex <= em->fifoCount) { + else if (stream->subIndex <= em->fifoCount) { /* newest error is reported on subIndex 1 and is stored just behind * fifoWrPtr. Get correct index in FIFO buffer. */ - int16_t index = (int16_t)em->fifoWrPtr - subIndex; + int16_t index = (int16_t)em->fifoWrPtr - stream->subIndex; if (index < 0) { index += CO_CONFIG_EM_BUFFER_SIZE + 1; } @@ -227,11 +222,10 @@ static OD_size_t OD_read_1003(OD_stream_t *stream, uint8_t subIndex, } } -static OD_size_t OD_write_1003(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1003(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL || count != 1 + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != 1 || returnCode == NULL) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -259,11 +253,12 @@ static OD_size_t OD_write_1003(OD_stream_t *stream, uint8_t subIndex, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_read_statusBits(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_read_statusBits(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (stream == NULL || stream->subIndex != 0 + || buf == NULL || returnCode == NULL) + { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } @@ -287,11 +282,12 @@ static OD_size_t OD_read_statusBits(OD_stream_t *stream, uint8_t subIndex, return countRead; } -static OD_size_t OD_write_statusBits(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_statusBits(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL || returnCode == NULL) { + if (stream == NULL || stream->subIndex != 0 + || buf == NULL || returnCode == NULL + ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; } diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 71e938c0..1b873247 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -87,14 +87,14 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1016(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1016(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { CO_HBconsumer_t *HBcons = stream->object; if (stream == NULL || buf == NULL - || subIndex < 1 || subIndex > HBcons->numberOfMonitoredNodes + || stream->subIndex < 1 + || stream->subIndex > HBcons->numberOfMonitoredNodes || count != sizeof(uint32_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -104,7 +104,7 @@ static OD_size_t OD_write_1016(OD_stream_t *stream, uint8_t subIndex, uint32_t val = CO_getUint32(buf); uint8_t nodeId = (val >> 16) & 0xFF; uint16_t time = val & 0xFFFF; - CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, subIndex - 1, + CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, stream->subIndex - 1, nodeId, time); if (ret != CO_ERROR_NO) { *returnCode = ODR_PAR_INCOMPAT; @@ -113,7 +113,7 @@ static OD_size_t OD_write_1016(OD_stream_t *stream, uint8_t subIndex, /* write value to the original location in the Object Dictionary */ *returnCode = ODR_OK; - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } #endif diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 87773f2b..37b51ae2 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -59,11 +59,10 @@ static void CO_NMT_receive(void *object, void *msg) { * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1017(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1017(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != sizeof(uint16_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -78,7 +77,7 @@ static OD_size_t OD_write_1017(OD_stream_t *stream, uint8_t subIndex, NMT->HBproducerTimer = 0; /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index dbc66a73..5728f6eb 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -28,11 +28,9 @@ /******************************************************************************/ -OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, ODR_t *returnCode) +OD_size_t OD_readOriginal(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode) { - (void) subIndex; - if (stream == NULL || buf == NULL || returnCode == NULL) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; @@ -75,11 +73,9 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, } /******************************************************************************/ -OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, ODR_t *returnCode) +OD_size_t OD_writeOriginal(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - (void) subIndex; - if (stream == NULL || buf == NULL || returnCode == NULL) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; return 0; @@ -130,22 +126,20 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, } /* Read value from variable from Object Dictionary disabled, see OD_IO_t*/ -static OD_size_t OD_readDisabled(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_readDisabled(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode) { - (void) stream; (void) subIndex; (void) buf; (void) count; + (void) stream; (void) buf; (void) count; if (returnCode != NULL) *returnCode = ODR_UNSUPP_ACCESS; return 0; } /* Write value to variable from Object Dictionary disabled, see OD_IO_t */ -static OD_size_t OD_writeDisabled(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_writeDisabled(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - (void) stream; (void) subIndex; (void) buf; (void) count; + (void) stream; (void) buf; (void) count; if (returnCode != NULL) *returnCode = ODR_UNSUPP_ACCESS; return 0; @@ -269,6 +263,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, /* Reset stream data offset */ stream->dataOffset = 0; + stream->subIndex = subIndex; return ODR_OK; } @@ -324,7 +319,7 @@ ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, if (ret != ODR_OK) return ret; if (stream->dataLength != len) return ODR_TYPE_MISMATCH; - io.read(stream, subIndex, val, len, &ret); + io.read(stream, val, len, &ret); return ret; } @@ -341,7 +336,7 @@ ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, if (ret != ODR_OK) return ret; if (stream->dataLength != len) return ODR_TYPE_MISMATCH; - io.write(stream, subIndex, val, len, &ret); + io.write(stream, val, len, &ret); return ret; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index ce96d671..07dff7f2 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -218,6 +218,8 @@ typedef struct { OD_size_t dataOffset; /** Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */ OD_attr_t attribute; + /** Sub index of the OD sub-object, informative */ + uint8_t subIndex; } OD_stream_t; @@ -251,15 +253,14 @@ typedef struct { * is still space in "buf".) * * @param stream Object Dictionary stream object. - * @param subIndex Object Dictionary subIndex of the accessed element. * @param buf Pointer to external buffer, where to data will be copied. * @param count Size of the external buffer in bytes. * @param [out] returnCode Return value from @ref ODR_t. * * @return Number of bytes successfully read. */ - OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, ODR_t *returnCode); + OD_size_t (*read)(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode); /** * Function pointer for writing value into specified variable inside Object * Dictionary. If OD variable is larger than buf, then this function must @@ -278,7 +279,6 @@ typedef struct { * variable expect more data, then "*returnCode" must return 'ODR_PARTIAL'. * * @param stream Object Dictionary stream object. - * @param subIndex Object Dictionary subIndex of the accessed element. * @param buf Pointer to external buffer, from where data will be copied. * @param count Size of the external buffer in bytes. * @param [out] returnCode Return value from ODR_t. @@ -286,8 +286,8 @@ typedef struct { * @return Number of bytes successfully written, must be equal to count on * success or zero on error. */ - OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, ODR_t *returnCode); + OD_size_t (*write)(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode); } OD_IO_t; @@ -301,13 +301,13 @@ typedef struct { /** Application specified read function pointer. If NULL, then read will be * disabled. @ref OD_readOriginal can be used here to keep the original read * function. For function description see @ref OD_IO_t. */ - OD_size_t (*read)(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, ODR_t *returnCode); + OD_size_t (*read)(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode); /** Application specified write function pointer. If NULL, then write will * be disabled. @ref OD_writeOriginal can be used here to keep the original * write function. For function description see @ref OD_IO_t. */ - OD_size_t (*write)(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, ODR_t *returnCode); + OD_size_t (*write)(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode); /** * PDO flags bit-field. If available, then each sub-element is coupled * with own flagsPDO variable of size 8 to 512 bits (size is configurable @@ -372,8 +372,8 @@ typedef struct { * io->read returned by @ref OD_getSub() equals to this function. See * also @ref OD_IO_t. */ -OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, - void *buf, OD_size_t count, ODR_t *returnCode); +OD_size_t OD_readOriginal(OD_stream_t *stream, void *buf, + OD_size_t count, ODR_t *returnCode); /** @@ -385,8 +385,8 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, uint8_t subIndex, * io->write returned by @ref OD_getSub() equals to this function. See * also @ref OD_IO_t. */ -OD_size_t OD_writeOriginal(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, ODR_t *returnCode); +OD_size_t OD_writeOriginal(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode); /** diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index ff08e58a..444e5329 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -173,9 +173,8 @@ static void CO_SDOclient_receive(void *object, void *msg) { * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1280(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1280(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { /* "count" is already verified in *_init() function */ if (stream == NULL || buf == NULL || returnCode == NULL) { @@ -188,7 +187,7 @@ static OD_size_t OD_write_1280(OD_stream_t *stream, uint8_t subIndex, uint32_t COB_ID; uint8_t nodeId; - switch (subIndex) { + switch (stream->subIndex) { case 0: /* Highest sub-index supported */ *returnCode = ODR_READONLY; return 0; @@ -242,7 +241,7 @@ static OD_size_t OD_write_1280(OD_stream_t *stream, uint8_t subIndex, } /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC */ @@ -626,8 +625,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* write data to Object Dictionary */ if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } - SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, SDO_C->subIndex, - buf, count, &odRet); + SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, count, &odRet); if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } /* verify for errors in write */ @@ -1220,7 +1218,6 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* load data from OD variable into the buffer */ if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } OD_size_t countRd = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, - SDO_C->subIndex, buf, countBuf, &odRet); if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 684cd8d6..4ea81e29 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -232,9 +232,8 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1201_additional(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { /* "count" is already verified in *_init() function */ if (stream == NULL || buf == NULL || returnCode == NULL) { @@ -247,7 +246,7 @@ static OD_size_t OD_write_1201_additional(OD_stream_t *stream, uint8_t subIndex, uint32_t COB_ID; uint8_t nodeId; - switch (subIndex) { + switch (stream->subIndex) { case 0: /* Highest sub-index supported */ *returnCode = ODR_READONLY; return 0; @@ -308,7 +307,7 @@ static OD_size_t OD_write_1201_additional(OD_stream_t *stream, uint8_t subIndex, } /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC */ @@ -555,8 +554,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, bool_t lock = OD_mappable(&SDO->OD_IO.stream); if (lock) { CO_LOCK_OD(SDO->CANdevTx); } - SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, - SDO->buf, SDO->bufOffsetWr, &odRet); + SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, SDO->bufOffsetWr, &odRet); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } SDO->bufOffsetWr = 0; @@ -617,10 +615,8 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, bool_t lock = OD_mappable(&SDO->OD_IO.stream); if (lock) { CO_LOCK_OD(SDO->CANdevTx); } - OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, - bufShifted, - countRdRequest, - &odRet); + OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, bufShifted, + countRdRequest, &odRet); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } if (odRet != ODR_OK && odRet != ODR_PARTIAL) { @@ -855,8 +851,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, bool_t lock = OD_mappable(&SDO->OD_IO.stream); if (lock) { CO_LOCK_OD(SDO->CANdevTx); } - SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->subIndex, - buf, dataSizeToWrite, &odRet); + SDO->OD_IO.write(&SDO->OD_IO.stream, buf, + dataSizeToWrite, &odRet); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } if (odRet != ODR_OK) { @@ -1300,7 +1296,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, bool_t lock = OD_mappable(&SDO->OD_IO.stream); if (lock) { CO_LOCK_OD(SDO->CANdevTx); } - OD_size_t count = SDO->OD_IO.read(&SDO->OD_IO.stream, SDO->subIndex, + OD_size_t count = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->CANtxBuff->data[4], 4, &odRet); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 6c15fec3..412edc6c 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -80,11 +80,10 @@ static void CO_SYNC_receive(void *object, void *msg) { * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1005(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1005(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != sizeof(uint32_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -156,7 +155,7 @@ static OD_size_t OD_write_1005(OD_stream_t *stream, uint8_t subIndex, #endif /* CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER @@ -165,11 +164,10 @@ static OD_size_t OD_write_1005(OD_stream_t *stream, uint8_t subIndex, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1019(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1019(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != sizeof(uint8_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -208,7 +206,7 @@ static OD_size_t OD_write_1019(OD_stream_t *stream, uint8_t subIndex, SYNC->counterOverflowValue = syncCounterOvf; /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC */ diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 0128c336..96e689f8 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -61,11 +61,10 @@ static void CO_TIME_receive(void *object, void *msg) { * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1012(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1012(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { - if (stream == NULL || subIndex != 0 || buf == NULL + if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != sizeof(uint32_t) || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -81,7 +80,7 @@ static OD_size_t OD_write_1012(OD_stream_t *stream, uint8_t subIndex, TIME->isProducer = (cobIdTimeStamp & 0x40000000L) != 0; /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, subIndex, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, returnCode); } #endif diff --git a/301/CO_storage.c b/301/CO_storage.c index 9505d0d7..c5dbb580 100644 --- a/301/CO_storage.c +++ b/301/CO_storage.c @@ -31,12 +31,11 @@ * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1010(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { /* verify arguments */ - if (stream == NULL || subIndex == 0 || buf == NULL || count != 4 + if (stream == NULL || stream->subIndex == 0 || buf == NULL || count != 4 || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -45,7 +44,7 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex, CO_storage_t *storage = stream->object; - if (subIndex == 0 || storage->store == NULL) { + if (stream->subIndex == 0 || storage->store == NULL) { *returnCode = ODR_READONLY; return 0; } @@ -62,7 +61,7 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex, for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; - if (subIndex == 1 || entry->subIndexOD == subIndex) { + if (stream->subIndex == 1 || entry->subIndexOD == stream->subIndex) { if (found == 0) found = 1; if ((entry->attr & CO_storage_cmd) != 0) { ODR_t code = storage->store(entry, storage->CANmodule); @@ -83,12 +82,11 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, uint8_t subIndex, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, - const void *buf, OD_size_t count, - ODR_t *returnCode) +static OD_size_t OD_write_1011(OD_stream_t *stream, const void *buf, + OD_size_t count, ODR_t *returnCode) { /* verify arguments */ - if (stream == NULL || subIndex == 0 || buf == NULL || count != 4 + if (stream == NULL || stream->subIndex == 0 || buf == NULL || count != 4 || returnCode == NULL ) { if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; @@ -97,7 +95,7 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, CO_storage_t *storage = stream->object; - if (subIndex == 0 || storage->restore == NULL) { + if (stream->subIndex == 0 || storage->restore == NULL) { *returnCode = ODR_READONLY; return 0; } @@ -114,7 +112,7 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, uint8_t subIndex, for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; - if (subIndex == 1 || entry->subIndexOD == subIndex) { + if (stream->subIndex == 1 || entry->subIndexOD == stream->subIndex) { if (found == 0) found = 1; if ((entry->attr & CO_storage_restore) != 0) { ODR_t code = storage->restore(entry, storage->CANmodule); From f8eb4bc0a1d2768f7fa5414a35c3e98c547949c0 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 12 Mar 2021 11:42:34 +0100 Subject: [PATCH 164/520] CO_ODinterface: simplified API to read/write functions. Return variables changed. --- 301/CO_Emergency.c | 138 ++++++++++++++++++++--------------------- 301/CO_HBconsumer.c | 15 ++--- 301/CO_NMT_Heartbeat.c | 12 ++-- 301/CO_ODinterface.c | 85 +++++++++++-------------- 301/CO_ODinterface.h | 35 ++++++----- 301/CO_SDOclient.c | 38 +++++------- 301/CO_SDOserver.c | 54 +++++++--------- 301/CO_SYNC.c | 45 +++++--------- 301/CO_TIME.c | 12 ++-- 301/CO_storage.c | 50 +++++++-------- 10 files changed, 217 insertions(+), 267 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index d3929c8a..6d6b3db9 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -59,39 +59,38 @@ * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_read_1014(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || returnCode == NULL + || count != sizeof(uint32_t) || countRead == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - *returnCode = ODR_OK; uint16_t canId = em->producerCanId == CO_CAN_ID_EMERGENCY ? CO_CAN_ID_EMERGENCY + em->nodeId : em->producerCanId; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; COB_IDEmergency32 |= canId; CO_setUint32(buf, COB_IDEmergency32); - return sizeof(uint32_t); + + + *countRead = sizeof(uint32_t); + return ODR_OK; } -static OD_size_t OD_write_1014(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || returnCode == NULL + || count != sizeof(uint32_t) || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - *returnCode = ODR_OK; /* Verify written value. COB ID must not change, if emergency is enabled */ uint32_t COB_IDEmergency32 = CO_getUint32(buf); @@ -102,8 +101,7 @@ static OD_size_t OD_write_1014(OD_stream_t *stream, const void *buf, if ((COB_IDEmergency32 & 0x7FFFF800) != 0 || (em->producerEnabled && newEnabled && newCanId != curCanId) ) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } /* store values. If default CAN-ID is used, then store only value of @@ -124,7 +122,7 @@ static OD_size_t OD_write_1014(OD_stream_t *stream, const void *buf, } /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } #else /* @@ -132,23 +130,23 @@ static OD_size_t OD_write_1014(OD_stream_t *stream, const void *buf, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_read_1014_default(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || returnCode == NULL + || count != sizeof(uint32_t) || countRead == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - *returnCode = ODR_OK; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + em->nodeId; CO_setUint32(buf, COB_IDEmergency32); - return sizeof(uint32_t); + + *countRead = sizeof(uint32_t); + return ODR_OK; } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE */ @@ -158,25 +156,23 @@ static OD_size_t OD_read_1014_default(OD_stream_t *stream, void *buf, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1015(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint16_t) || returnCode == NULL + || count != sizeof(uint16_t) || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - *returnCode = ODR_OK; /* update object */ em->inhibitEmTime_us = (uint32_t)CO_getUint16(buf) * 100; em->inhibitEmTimer = 0; /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ @@ -187,20 +183,20 @@ static OD_size_t OD_write_1015(OD_stream_t *stream, const void *buf, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_read_1003(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) { - if (stream == NULL || buf == NULL || count < 4 || returnCode == NULL) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + if (stream == NULL || buf == NULL || count < 4 || countRead == NULL) { + return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - *returnCode = ODR_OK; if (stream->subIndex == 0) { CO_setUint8(buf, em->fifoCount); - return 1; + + *countRead = sizeof(uint8_t); + return ODR_OK; } else if (stream->subIndex <= em->fifoCount) { /* newest error is reported on subIndex 1 and is stored just behind @@ -210,40 +206,38 @@ static OD_size_t OD_read_1003(OD_stream_t *stream, void *buf, index += CO_CONFIG_EM_BUFFER_SIZE + 1; } else if (index >= (CO_CONFIG_EM_BUFFER_SIZE + 1)) { - *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_setUint32(buf, em->fifo[index][0]); - return 4; + + *countRead = sizeof(uint32_t); + return ODR_OK; } else { - *returnCode = ODR_NO_DATA; - return 0; + return ODR_NO_DATA; } } -static OD_size_t OD_write_1003(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != 1 - || returnCode == NULL) + || countWritten == NULL) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } if (CO_getUint8(buf) != 0) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } CO_EM_t *em = (CO_EM_t *)stream->object; - *returnCode = ODR_OK; /* clear error history */ em->fifoCount = 0; - return sizeof(uint8_t); + *countWritten = sizeof(uint8_t); + return ODR_OK; } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ @@ -253,47 +247,45 @@ static OD_size_t OD_write_1003(OD_stream_t *stream, const void *buf, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_read_statusBits(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) { if (stream == NULL || stream->subIndex != 0 - || buf == NULL || returnCode == NULL) + || buf == NULL || countRead == NULL) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - *returnCode = ODR_OK; /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ - size_t countRead = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; - if (countRead > count) { - countRead = count; + size_t countReadLocal = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; + if (countReadLocal > count) { + countReadLocal = count; } - if (stream->dataLength != 0 && countRead > stream->dataLength) { - countRead = stream->dataLength; + if (stream->dataLength != 0 && countReadLocal > stream->dataLength) { + countReadLocal = stream->dataLength; } else { - stream->dataLength = countRead; + stream->dataLength = countReadLocal; } - memcpy (buf, &em->errorStatusBits[0], countRead); - return countRead; + memcpy (buf, &em->errorStatusBits[0], countReadLocal); + + *countRead = countReadLocal; + return ODR_OK; } -static OD_size_t OD_write_statusBits(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { if (stream == NULL || stream->subIndex != 0 - || buf == NULL || returnCode == NULL + || buf == NULL || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - *returnCode = ODR_OK; /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ size_t countWrite = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; @@ -308,7 +300,9 @@ static OD_size_t OD_write_statusBits(OD_stream_t *stream, const void *buf, } memcpy (&em->errorStatusBits[0], buf, countWrite); - return countWrite; + + *countWritten = countWrite; + return ODR_OK; } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 1b873247..43590404 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -87,18 +87,17 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1016(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { CO_HBconsumer_t *HBcons = stream->object; if (stream == NULL || buf == NULL || stream->subIndex < 1 || stream->subIndex > HBcons->numberOfMonitoredNodes - || count != sizeof(uint32_t) || returnCode == NULL + || count != sizeof(uint32_t) || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } uint32_t val = CO_getUint32(buf); @@ -107,13 +106,11 @@ static OD_size_t OD_write_1016(OD_stream_t *stream, const void *buf, CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, stream->subIndex - 1, nodeId, time); if (ret != CO_ERROR_NO) { - *returnCode = ODR_PAR_INCOMPAT; - return 0; + return ODR_PAR_INCOMPAT; } /* write value to the original location in the Object Dictionary */ - *returnCode = ODR_OK; - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } #endif diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 37b51ae2..dfe05965 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -59,25 +59,23 @@ static void CO_NMT_receive(void *object, void *msg) { * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1017(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1017(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint16_t) || returnCode == NULL + || count != sizeof(uint16_t) || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_NMT_t *NMT = (CO_NMT_t *)stream->object; - *returnCode = ODR_OK; /* update object, send Heartbeat immediately */ NMT->HBproducerTime_us = (uint32_t)CO_getUint16(buf) * 1000; NMT->HBproducerTimer = 0; /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 5728f6eb..9a170a37 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -28,30 +28,27 @@ /******************************************************************************/ -OD_size_t OD_readOriginal(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode) +ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) { - if (stream == NULL || buf == NULL || returnCode == NULL) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + if (stream == NULL || buf == NULL || countRead == NULL) { + return ODR_DEV_INCOMPAT; } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ const uint8_t *dataOrig = stream->dataOrig; if (dataOrig == NULL) { - *returnCode = ODR_SUB_NOT_EXIST; - return 0; + return ODR_SUB_NOT_EXIST; } - *returnCode = ODR_OK; + ODR_t returnCode = ODR_OK; /* If previous read was partial or OD variable length is larger than * current buffer size, then data was (will be) read in several segments */ if (stream->dataOffset > 0 || dataLenToCopy > count) { if (stream->dataOffset >= dataLenToCopy) { - *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } /* Reduce for already copied data */ dataLenToCopy -= stream->dataOffset; @@ -61,7 +58,7 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, void *buf, /* Not enough space in destination buffer */ dataLenToCopy = count; stream->dataOffset += dataLenToCopy; - *returnCode = ODR_PARTIAL; + returnCode = ODR_PARTIAL; } else { stream->dataOffset = 0; /* copy finished, reset offset */ @@ -69,35 +66,34 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, void *buf, } memcpy(buf, dataOrig, dataLenToCopy); - return dataLenToCopy; + + *countRead = dataLenToCopy; + return returnCode; } /******************************************************************************/ -OD_size_t OD_writeOriginal(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || buf == NULL || returnCode == NULL) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + if (stream == NULL || buf == NULL || countWritten == NULL) { + return ODR_DEV_INCOMPAT; } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ uint8_t *dataOrig = stream->dataOrig; if (dataOrig == NULL) { - *returnCode = ODR_SUB_NOT_EXIST; - return 0; + return ODR_SUB_NOT_EXIST; } - *returnCode = ODR_OK; + ODR_t returnCode = ODR_OK; /* If previous write was partial or OD variable length is larger than * current buffer size, then data was (will be) written in several * segments */ if (stream->dataOffset > 0 || dataLenToCopy > count) { if (stream->dataOffset >= dataLenToCopy) { - *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } /* reduce for already copied data */ dataLenToCopy -= stream->dataOffset; @@ -108,7 +104,7 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, const void *buf, * of data, so only current count of data will be copied */ dataLenToCopy = count; stream->dataOffset += dataLenToCopy; - *returnCode = ODR_PARTIAL; + returnCode = ODR_PARTIAL; } else { stream->dataOffset = 0; /* copy finished, reset offset */ @@ -117,32 +113,29 @@ OD_size_t OD_writeOriginal(OD_stream_t *stream, const void *buf, if (dataLenToCopy < count) { /* OD variable is smaller than current amount of data */ - *returnCode = ODR_DATA_LONG; - return 0; + return ODR_DATA_LONG; } memcpy(dataOrig, buf, dataLenToCopy); - return dataLenToCopy; + + *countWritten = dataLenToCopy; + return returnCode; } /* Read value from variable from Object Dictionary disabled, see OD_IO_t*/ -static OD_size_t OD_readDisabled(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_readDisabled(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) { - (void) stream; (void) buf; (void) count; - - if (returnCode != NULL) *returnCode = ODR_UNSUPP_ACCESS; - return 0; + (void) stream; (void) buf; (void) count; (void) countRead; + return ODR_UNSUPP_ACCESS; } /* Write value to variable from Object Dictionary disabled, see OD_IO_t */ -static OD_size_t OD_writeDisabled(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_writeDisabled(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { - (void) stream; (void) buf; (void) count; - - if (returnCode != NULL) *returnCode = ODR_UNSUPP_ACCESS; - return 0; + (void) stream; (void) buf; (void) count; (void) countWritten; + return ODR_UNSUPP_ACCESS; } @@ -310,35 +303,31 @@ ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, { if (val == NULL) return ODR_DEV_INCOMPAT; - ODR_t ret; OD_IO_t io; OD_stream_t *stream = (OD_stream_t *)&io; + OD_size_t countRd = 0; - ret = OD_getSub(entry, subIndex, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret != ODR_OK) return ret; if (stream->dataLength != len) return ODR_TYPE_MISMATCH; - io.read(stream, val, len, &ret); - - return ret; + return io.read(stream, val, len, &countRd); } ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, OD_size_t len, bool_t odOrig) { - ODR_t ret; OD_IO_t io; OD_stream_t *stream = &io.stream; + OD_size_t countWritten = 0; - ret = OD_getSub(entry, subIndex, &io, odOrig); + ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); if (ret != ODR_OK) return ret; if (stream->dataLength != len) return ODR_TYPE_MISMATCH; - io.write(stream, val, len, &ret); - - return ret; + return io.write(stream, val, len, &countWritten); } void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 07dff7f2..9b070f8f 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -255,12 +255,13 @@ typedef struct { * @param stream Object Dictionary stream object. * @param buf Pointer to external buffer, where to data will be copied. * @param count Size of the external buffer in bytes. - * @param [out] returnCode Return value from @ref ODR_t. + * @param [out] countRead If return value is "ODR_OK" or "ODR_PARTIAL", + * then number of bytes successfully read must be returned here. * - * @return Number of bytes successfully read. + * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ - OD_size_t (*read)(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode); + ODR_t (*read)(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead); /** * Function pointer for writing value into specified variable inside Object * Dictionary. If OD variable is larger than buf, then this function must @@ -281,13 +282,13 @@ typedef struct { * @param stream Object Dictionary stream object. * @param buf Pointer to external buffer, from where data will be copied. * @param count Size of the external buffer in bytes. - * @param [out] returnCode Return value from ODR_t. + * @param [out] countWritten If return value is "ODR_OK" or "ODR_PARTIAL", + * then number of bytes successfully written must be returned here. * - * @return Number of bytes successfully written, must be equal to count on - * success or zero on error. + * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ - OD_size_t (*write)(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode); + ODR_t (*write)(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten); } OD_IO_t; @@ -301,13 +302,13 @@ typedef struct { /** Application specified read function pointer. If NULL, then read will be * disabled. @ref OD_readOriginal can be used here to keep the original read * function. For function description see @ref OD_IO_t. */ - OD_size_t (*read)(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode); + ODR_t (*read)(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead); /** Application specified write function pointer. If NULL, then write will * be disabled. @ref OD_writeOriginal can be used here to keep the original * write function. For function description see @ref OD_IO_t. */ - OD_size_t (*write)(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode); + ODR_t (*write)(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten); /** * PDO flags bit-field. If available, then each sub-element is coupled * with own flagsPDO variable of size 8 to 512 bits (size is configurable @@ -372,8 +373,8 @@ typedef struct { * io->read returned by @ref OD_getSub() equals to this function. See * also @ref OD_IO_t. */ -OD_size_t OD_readOriginal(OD_stream_t *stream, void *buf, - OD_size_t count, ODR_t *returnCode); +ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead); /** @@ -385,8 +386,8 @@ OD_size_t OD_readOriginal(OD_stream_t *stream, void *buf, * io->write returned by @ref OD_getSub() equals to this function. See * also @ref OD_IO_t. */ -OD_size_t OD_writeOriginal(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode); +ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten); /** diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 444e5329..74c0a544 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -173,24 +173,21 @@ static void CO_SDOclient_receive(void *object, void *msg) { * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1280(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { /* "count" is already verified in *_init() function */ - if (stream == NULL || buf == NULL || returnCode == NULL) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + if (stream == NULL || buf == NULL || countWritten == NULL) { + return ODR_DEV_INCOMPAT; } CO_SDOclient_t *SDO_C = (CO_SDOclient_t *)stream->object; - *returnCode = ODR_OK; uint32_t COB_ID; uint8_t nodeId; switch (stream->subIndex) { case 0: /* Highest sub-index supported */ - *returnCode = ODR_READONLY; - return 0; + return ODR_READONLY; case 1: /* COB-ID client -> server */ COB_ID = CO_getUint32(buf); @@ -200,8 +197,7 @@ static OD_size_t OD_write_1280(OD_stream_t *stream, const void *buf, || ((uint16_t)COB_ID != (uint16_t)SDO_C->COB_IDClientToServer && SDO_C->valid && (COB_ID & 0x80000000) == 0) ) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } CO_SDOclient_setup(SDO_C, COB_ID, @@ -217,8 +213,7 @@ static OD_size_t OD_write_1280(OD_stream_t *stream, const void *buf, || ((uint16_t)COB_ID != (uint16_t)SDO_C->COB_IDServerToClient && SDO_C->valid && (COB_ID & 0x80000000) == 0) ) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } CO_SDOclient_setup(SDO_C, SDO_C->COB_IDClientToServer, @@ -229,19 +224,17 @@ static OD_size_t OD_write_1280(OD_stream_t *stream, const void *buf, case 3: /* Node-ID of the SDO server */ nodeId = CO_getUint8(buf); if (nodeId > 127) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } SDO_C->nodeIDOfTheSDOServer = nodeId; break; default: - *returnCode = ODR_SUB_NOT_EXIST; - return 0; + return ODR_SUB_NOT_EXIST; } /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC */ @@ -620,12 +613,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } } if (abortCode == CO_SDO_AB_NONE) { - ODR_t odRet; + OD_size_t countWritten = 0; bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); /* write data to Object Dictionary */ if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } - SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, count, &odRet); + ODR_t odRet = SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, + count, &countWritten); if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } /* verify for errors in write */ @@ -1211,14 +1205,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, OD_size_t countData = SDO_C->OD_IO.stream.dataLength; OD_size_t countBuf = (countData > 0 && countData <= countFifo) ? countData : countFifo; + OD_size_t countRd = 0; uint8_t buf[countBuf + 1]; - ODR_t odRet; bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); /* load data from OD variable into the buffer */ if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } - OD_size_t countRd = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, - buf, countBuf, &odRet); + ODR_t odRet = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, + buf, countBuf, &countRd); if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } if (odRet != ODR_OK && odRet != ODR_PARTIAL) { diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 4ea81e29..67fb1cfe 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -232,24 +232,21 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { /* "count" is already verified in *_init() function */ - if (stream == NULL || buf == NULL || returnCode == NULL) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + if (stream == NULL || buf == NULL || countWritten == NULL) { + return ODR_DEV_INCOMPAT; } CO_SDOserver_t *SDO = (CO_SDOserver_t *)stream->object; - *returnCode = ODR_OK; uint32_t COB_ID; uint8_t nodeId; switch (stream->subIndex) { case 0: /* Highest sub-index supported */ - *returnCode = ODR_READONLY; - return 0; + return ODR_READONLY; case 1: /* COB-ID client -> server */ COB_ID = CO_getUint32(buf); @@ -259,8 +256,7 @@ static OD_size_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, || ((uint16_t)COB_ID != (uint16_t)SDO->COB_IDClientToServer && SDO->valid && (COB_ID & 0x80000000)) ) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } CO_SDOserver_init_canRxTx(SDO, SDO->CANdevRx, @@ -278,8 +274,7 @@ static OD_size_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, || ((uint16_t)COB_ID != (uint16_t)SDO->COB_IDServerToClient && SDO->valid && (COB_ID & 0x80000000)) ) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } CO_SDOserver_init_canRxTx(SDO, SDO->CANdevRx, @@ -291,23 +286,20 @@ static OD_size_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, case 3: /* Node-ID of the SDO server */ if (count != 1) { - *returnCode = ODR_TYPE_MISMATCH; - return 0; + return ODR_TYPE_MISMATCH; } nodeId = CO_getUint8(buf); if (nodeId < 1 || nodeId > 127) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } break; default: - *returnCode = ODR_SUB_NOT_EXIST; - return 0; + return ODR_SUB_NOT_EXIST; } /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC */ @@ -550,11 +542,12 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, (void) crcOperation; (void) crcClient; (void) bufOffsetWrOrig; /* write data */ - ODR_t odRet; + OD_size_t countWritten = 0; bool_t lock = OD_mappable(&SDO->OD_IO.stream); if (lock) { CO_LOCK_OD(SDO->CANdevTx); } - SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, SDO->bufOffsetWr, &odRet); + ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, + SDO->bufOffsetWr, &countWritten); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } SDO->bufOffsetWr = 0; @@ -610,13 +603,13 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, OD_size_t countRdRequest = CO_CONFIG_SDO_SRV_BUFFER_SIZE - countRemain; /* load data from OD variable into the buffer */ - ODR_t odRet; + OD_size_t countRd = 0; uint8_t *bufShifted = SDO->buf + countRemain; bool_t lock = OD_mappable(&SDO->OD_IO.stream); if (lock) { CO_LOCK_OD(SDO->CANdevTx); } - OD_size_t countRd = SDO->OD_IO.read(&SDO->OD_IO.stream, bufShifted, - countRdRequest, &odRet); + ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, bufShifted, + countRdRequest, &countRd); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } if (odRet != ODR_OK && odRet != ODR_PARTIAL) { @@ -847,12 +840,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* Copy data */ - ODR_t odRet; + OD_size_t countWritten = 0; bool_t lock = OD_mappable(&SDO->OD_IO.stream); if (lock) { CO_LOCK_OD(SDO->CANdevTx); } - SDO->OD_IO.write(&SDO->OD_IO.stream, buf, - dataSizeToWrite, &odRet); + ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, + dataSizeToWrite, &countWritten); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } if (odRet != ODR_OK) { @@ -1292,13 +1285,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } #else /* Expedited transfer only */ /* load data from OD variable */ - ODR_t odRet; + OD_size_t count = 0; bool_t lock = OD_mappable(&SDO->OD_IO.stream); if (lock) { CO_LOCK_OD(SDO->CANdevTx); } - OD_size_t count = SDO->OD_IO.read(&SDO->OD_IO.stream, - &SDO->CANtxBuff->data[4], 4, - &odRet); + ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, + &SDO->CANtxBuff->data[4], 4, &count); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } /* strings are allowed to be shorter */ diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 412edc6c..971dc9c8 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -80,18 +80,16 @@ static void CO_SYNC_receive(void *object, void *msg) { * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1005(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || returnCode == NULL + || count != sizeof(uint32_t) || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_SYNC_t *SYNC = stream->object; - *returnCode = ODR_OK; uint32_t cobIdSync = CO_getUint32(buf); uint16_t CAN_ID = (uint16_t)(cobIdSync & 0x7FF); @@ -101,13 +99,11 @@ static OD_size_t OD_write_1005(OD_stream_t *stream, const void *buf, if ((cobIdSync & 0xBFFF8000) != 0 || (SYNC->isProducer && isProducer && CAN_ID != SYNC->CAN_ID) ) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } #else if ((cobIdSync & 0xFFFF8000) != 0) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } #endif @@ -123,8 +119,7 @@ static OD_size_t OD_write_1005(OD_stream_t *stream, const void *buf, CO_SYNC_receive); /* this function will process received message*/ if (CANret != CO_ERROR_NO) { - *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER @@ -138,8 +133,7 @@ static OD_size_t OD_write_1005(OD_stream_t *stream, const void *buf, if (SYNC->CANtxBuff == NULL) { SYNC->isProducer = false; - *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } #endif @@ -155,7 +149,7 @@ static OD_size_t OD_write_1005(OD_stream_t *stream, const void *buf, #endif /* CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER @@ -164,28 +158,24 @@ static OD_size_t OD_write_1005(OD_stream_t *stream, const void *buf, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1019(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint8_t) || returnCode == NULL + || count != sizeof(uint8_t) || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_SYNC_t *SYNC = stream->object; - *returnCode = ODR_OK; uint8_t syncCounterOvf = CO_getUint8(buf); /* verify written value */ if (syncCounterOvf == 1 || syncCounterOvf > 240) { - *returnCode = ODR_INVALID_VALUE; - return 0; + return ODR_INVALID_VALUE; } if (*SYNC->OD_1006_period != 0 && SYNC->isProducer) { - *returnCode = ODR_DATA_DEV_STATE; - return 0; + return ODR_DATA_DEV_STATE; } /* Configure CAN transmit buffer */ @@ -199,14 +189,13 @@ static OD_size_t OD_write_1019(OD_stream_t *stream, const void *buf, if (SYNC->CANtxBuff == NULL) { SYNC->isProducer = false; - *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } SYNC->counterOverflowValue = syncCounterOvf; /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC */ diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 96e689f8..2f6aa064 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -61,18 +61,16 @@ static void CO_TIME_receive(void *object, void *msg) { * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1012(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || returnCode == NULL + || count != sizeof(uint32_t) || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_TIME_t *TIME = stream->object; - *returnCode = ODR_OK; /* update object */ uint32_t cobIdTimeStamp = CO_getUint32(buf); @@ -80,7 +78,7 @@ static OD_size_t OD_write_1012(OD_stream_t *stream, const void *buf, TIME->isProducer = (cobIdTimeStamp & 0x40000000L) != 0; /* write value to the original location in the Object Dictionary */ - return OD_writeOriginal(stream, buf, count, returnCode); + return OD_writeOriginal(stream, buf, count, countWritten); } #endif diff --git a/301/CO_storage.c b/301/CO_storage.c index c5dbb580..57d553f6 100644 --- a/301/CO_storage.c +++ b/301/CO_storage.c @@ -31,32 +31,29 @@ * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1010(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { /* verify arguments */ if (stream == NULL || stream->subIndex == 0 || buf == NULL || count != 4 - || returnCode == NULL + || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_storage_t *storage = stream->object; if (stream->subIndex == 0 || storage->store == NULL) { - *returnCode = ODR_READONLY; - return 0; + return ODR_READONLY; } if (CO_getUint32(buf) != 0x65766173) { - *returnCode = ODR_DATA_TRANSF; - return 0; + return ODR_DATA_TRANSF; } /* loop through entries and store relevant */ uint8_t found = 0; - *returnCode = ODR_OK; + ODR_t returnCode = ODR_OK; for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; @@ -65,15 +62,17 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, const void *buf, if (found == 0) found = 1; if ((entry->attr & CO_storage_cmd) != 0) { ODR_t code = storage->store(entry, storage->CANmodule); - if (code != ODR_OK) *returnCode = code; + if (code != ODR_OK) returnCode = code; found = 2; } } } - if (found != 2) *returnCode = found == 0 ? ODR_SUB_NOT_EXIST : ODR_READONLY; + if (found != 2) + returnCode = found == 0 ? ODR_SUB_NOT_EXIST : ODR_READONLY; - return *returnCode == ODR_OK ? 4 : 0; + if (returnCode == ODR_OK) *countWritten = sizeof(uint32_t); + return returnCode; } @@ -82,32 +81,29 @@ static OD_size_t OD_write_1010(OD_stream_t *stream, const void *buf, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static OD_size_t OD_write_1011(OD_stream_t *stream, const void *buf, - OD_size_t count, ODR_t *returnCode) +static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { /* verify arguments */ if (stream == NULL || stream->subIndex == 0 || buf == NULL || count != 4 - || returnCode == NULL + || countWritten == NULL ) { - if (returnCode != NULL) *returnCode = ODR_DEV_INCOMPAT; - return 0; + return ODR_DEV_INCOMPAT; } CO_storage_t *storage = stream->object; if (stream->subIndex == 0 || storage->restore == NULL) { - *returnCode = ODR_READONLY; - return 0; + return ODR_READONLY; } if (CO_getUint32(buf) != 0x64616F6C) { - *returnCode = ODR_DATA_TRANSF; - return 0; + return ODR_DATA_TRANSF; } /* loop through entries and store relevant */ uint8_t found = 0; - *returnCode = ODR_OK; + ODR_t returnCode = ODR_OK; for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; @@ -116,15 +112,17 @@ static OD_size_t OD_write_1011(OD_stream_t *stream, const void *buf, if (found == 0) found = 1; if ((entry->attr & CO_storage_restore) != 0) { ODR_t code = storage->restore(entry, storage->CANmodule); - if (code != ODR_OK) *returnCode = code; + if (code != ODR_OK) returnCode = code; found = 2; } } } - if (found != 2) *returnCode = found == 0 ? ODR_SUB_NOT_EXIST : ODR_READONLY; + if (found != 2) + returnCode = found == 0 ? ODR_SUB_NOT_EXIST : ODR_READONLY; - return *returnCode == ODR_OK ? 4 : 0; + if (returnCode == ODR_OK) *countWritten = sizeof(uint32_t); + return returnCode; } From 86d467a192790bd8cebb1224b336905df89a6b80 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 12 Mar 2021 13:18:14 +0100 Subject: [PATCH 165/520] Change OD getters/setters from macros to static inline functions, issue #273 --- 301/CO_ODinterface.h | 140 ++++++++++++++++++++++++++++++------------- 1 file changed, 100 insertions(+), 40 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 9b070f8f..cd961b42 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -538,44 +538,74 @@ ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, void *val, OD_size_t len, bool_t odOrig); /** Get int8_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_i8(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(int8_t), (odOrig)) +static inline ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, + int8_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get int16_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_i16(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(int16_t), (odOrig)) +static inline ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, + int16_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get int32_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_i32(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(int32_t), (odOrig)) +static inline ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, + int32_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get int64_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_i64(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(int64_t), (odOrig)) +static inline ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, + int64_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get uint8_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_u8(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(uint8_t), (odOrig)) +static inline ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, + uint8_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get uint16_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_u16(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(uint16_t), (odOrig)) +static inline ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, + uint16_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get uint32_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_u32(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(uint32_t), (odOrig)) +static inline ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, + uint32_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get uint64_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_u64(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(uint64_t), (odOrig)) +static inline ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, + uint64_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get float32_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_f32(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(float32_t), (odOrig)) +static inline ODR_t OD_get_f32(const OD_entry_t *entry, uint8_t subIndex, + float32_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** Get float64_t variable from Object Dictionary, see @ref OD_get_value */ -#define OD_get_f64(entry, subIndex, val, odOrig) \ - OD_get_value((entry), (subIndex), (val), sizeof(float64_t), (odOrig)) +static inline ODR_t OD_get_f64(const OD_entry_t *entry, uint8_t subIndex, + float64_t *val, bool_t odOrig) +{ + return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); +} /** * Set variable in Object Dictionary @@ -595,44 +625,74 @@ ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, OD_size_t len, bool_t odOrig); /** Set int8_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_i8(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(int8_t), (odOrig)) +static inline ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, + int8_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set int16_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_i16(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(int16_t), (odOrig)) +static inline ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, + int16_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set int32_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_i32(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(int32_t), (odOrig)) +static inline ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, + int32_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set int32_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_i64(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(int64_t), (odOrig)) +static inline ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, + int64_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set uint8_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_u8(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(uint8_t), (odOrig)) +static inline ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, + uint8_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set uint16_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_u16(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(uint16_t), (odOrig)) +static inline ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, + uint16_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set uint32_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_u32(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(uint32_t), (odOrig)) +static inline ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, + uint32_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set uint64_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_u64(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(uint64_t), (odOrig)) +static inline ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, + uint64_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set float32_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_f32(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(float32_t), (odOrig)) +static inline ODR_t OD_set_f32(const OD_entry_t *entry, uint8_t subIndex, + float32_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** Set float64_t variable in Object Dictionary, see @ref OD_set_value */ -#define OD_set_f64(entry, subIndex, val, odOrig) \ - OD_set_value((entry), (subIndex), &(val), sizeof(float64_t), (odOrig)) +static inline ODR_t OD_set_f64(const OD_entry_t *entry, uint8_t subIndex, + float64_t val, bool_t odOrig) +{ + return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); +} /** * Get pointer to memory which holds data variable from Object Dictionary From f6d33cdf29438070933d587991713336acee0d5b Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 12 Mar 2021 21:01:44 +0100 Subject: [PATCH 166/520] OD getters/setters fix previous commit, issue #273 --- 301/CO_ODinterface.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index cd961b42..3c6455d7 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -541,70 +541,70 @@ ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, static inline ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, int8_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get int16_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, int16_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get int32_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, int32_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get int64_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, int64_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get uint8_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, uint8_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get uint16_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, uint16_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get uint32_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, uint32_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get uint64_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, uint64_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get float32_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_f32(const OD_entry_t *entry, uint8_t subIndex, float32_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get float64_t variable from Object Dictionary, see @ref OD_get_value */ static inline ODR_t OD_get_f64(const OD_entry_t *entry, uint8_t subIndex, float64_t *val, bool_t odOrig) { - return OD_get_value(entry, subIndex, val, sizeof(val), odOrig); + return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** From 926b59f3fdee6ca974d6000a6d53ee00190edc2a Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 15 Mar 2021 11:58:20 +0100 Subject: [PATCH 167/520] Fix missing CO_CONFIG_EM_PROD_INHIBIT switches --- 301/CO_Emergency.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 6d6b3db9..4032f8f9 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -610,18 +610,20 @@ void CO_EM_process(CO_EM_t *em, /* post-process Emergency message in fifo buffer. */ #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER - /* inhibit time */ + uint8_t fifoPpPtr = em->fifoPpPtr; + + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT if (em->inhibitEmTimer < em->inhibitEmTime_us) { em->inhibitEmTimer += timeDifference_us; } - uint8_t fifoPpPtr = em->fifoPpPtr; - if (fifoPpPtr != em->fifoWrPtr + if (fifoPpPtr != em->fifoWrPtr && !em->CANtxBuff->bufferFull && em->inhibitEmTimer >= em->inhibitEmTime_us - && !em->CANtxBuff->bufferFull ) { em->inhibitEmTimer = 0; - + #else + if (fifoPpPtr != em->fifoWrPtr && !em->CANtxBuff->bufferFull) { + #endif /* add error register to emergency message */ em->fifo[fifoPpPtr][0] |= (uint32_t) errorRegister << 16; @@ -660,7 +662,8 @@ void CO_EM_process(CO_EM_t *em, CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); } } - #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT else if (timerNext_us != NULL && em->inhibitEmTimer < em->inhibitEmTime_us){ /* check again after inhibit time elapsed */ uint32_t diff = em->inhibitEmTime_us - em->inhibitEmTimer; @@ -668,6 +671,7 @@ void CO_EM_process(CO_EM_t *em, *timerNext_us = diff; } } + #endif #endif #elif (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY uint8_t fifoPpPtr = em->fifoPpPtr; From 66d0e14ef4ac631894c5b4adc0441ef4406c2eb9 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 18 Mar 2021 15:13:06 +0100 Subject: [PATCH 168/520] 301/CO_PDO.h/c updated to newOD. --- 301/CO_Emergency.c | 4 +- 301/CO_Emergency.h | 4 +- 301/CO_ODinterface.h | 112 +- 301/CO_PDO.c | 2020 +++++++++++++++++++------------- 301/CO_PDO.h | 601 +++++----- 301/CO_SYNC.c | 29 +- 301/CO_SYNC.h | 7 +- 301/CO_config.h | 33 +- 301/CO_driver.h | 3 + CANopen.c | 150 ++- CANopen.h | 34 +- README.md | 95 +- doc/CHANGELOG.md | 12 +- doc/objectDictionary.md | 23 +- example/CO_driver_target.h | 10 - socketCAN/CO_driver_target.h | 18 - socketCAN/CO_epoll_interface.c | 3 +- socketCAN/CO_main_basic.c | 24 +- 18 files changed, 1853 insertions(+), 1329 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 4032f8f9..4e817f43 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -63,7 +63,7 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || countRead == NULL + || count < sizeof(uint32_t) || countRead == NULL ) { return ODR_DEV_INCOMPAT; } @@ -134,7 +134,7 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || countRead == NULL + || count < sizeof(uint32_t) || countRead == NULL ) { return ODR_DEV_INCOMPAT; } diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 7b8ea455..e4d71b5f 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -295,8 +295,8 @@ typedef enum { CO_EM_TPDO_OUTSIDE_WINDOW = 0x15U, /** 0x16, communication, critical, (unused) */ CO_EM_16_unused = 0x16U, - /** 0x17, communication, critical, (unused) */ - CO_EM_17_unused = 0x17U, + /** 0x17, communication, critical, RPDO message timeout */ + CO_EM_RPDO_TIME_OUT = 0x17U, /** 0x18, communication, critical, SYNC message timeout */ CO_EM_SYNC_TIME_OUT = 0x18U, /** 0x19, communication, critical, Unexpected SYNC data length */ diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 3c6455d7..2c5cf937 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -44,7 +44,10 @@ extern "C" { typedef uint32_t OD_size_t; /** Type (and size) of Object Dictionary attribute */ typedef uint8_t OD_attr_t; -/** Size of of flagsPDO variable inside OD_extension_t, from 1 to 64 */ +#endif + +#ifndef OD_FLAGS_PDO_SIZE +/** Size of of flagsPDO variable inside @ref OD_extension_t, from 0 to 32. */ #define OD_FLAGS_PDO_SIZE 4 #endif @@ -252,6 +255,10 @@ typedef struct { * not large enough. ("*returnCode" must not return 'ODR_PARTIAL', if there * is still space in "buf".) * + * @warning When accessing OD variables by calling the read() function, it + * may be necessary to use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros. + * See @ref CO_critical_sections for more information. + * * @param stream Object Dictionary stream object. * @param buf Pointer to external buffer, where to data will be copied. * @param count Size of the external buffer in bytes. @@ -279,6 +286,10 @@ typedef struct { * "write" function must always copy all available data from buf. If OD * variable expect more data, then "*returnCode" must return 'ODR_PARTIAL'. * + * @warning When accessing OD variables by calling the read() function, it + * may be necessary to use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros. + * See @ref CO_critical_sections for more information. + * * @param stream Object Dictionary stream object. * @param buf Pointer to external buffer, from where data will be copied. * @param count Size of the external buffer in bytes. @@ -309,24 +320,19 @@ typedef struct { * write function. For function description see @ref OD_IO_t. */ ODR_t (*write)(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten); - /** - * PDO flags bit-field. If available, then each sub-element is coupled - * with own flagsPDO variable of size 8 to 512 bits (size is configurable - * by @ref OD_FLAGS_PDO_SIZE). Flag is useful, when variable is mapped to - * RPDO or TPDO. +#if OD_FLAGS_PDO_SIZE > 0 + /**PDO flags bit-field provides one bit for each OD variable, which exist + * inside OD object at specific sub index. If application clears that bit, + * and OD variable is mapped to an event driven TPDO, then TPDO will be + * sent. * - * If sub-element is mapped to RPDO, then bit0 is set to 1 each time, when - * any RPDO writes new data into variable. Application may clear bit0. - * - * If sub-element is mapped to TPDO, then TPDO will set one bit on the time, - * it is sent. First TPDO will set bit1, second TPDO will set bit2, etc. - * - * Another functionality is with asynchronous TPDOs, to which variable may - * be mapped. If corresponding bit is 0, TPDO will be sent. This means, that - * if application sets variable pointed by flagsPDO to zero, it will trigger - * sending all asynchronous TPDOs, to which variable is mapped. - */ + * @ref OD_FLAGS_PDO_SIZE can have a value from 0 to 32 bytes, which + * corresponds to 0 to 256 available bits. If, for example, + * @ref OD_FLAGS_PDO_SIZE has value 4, then OD variables with sub index up + * to 31 will have the TPDO requesting functionality. + * See also @ref OD_requestTPDO and @ref OD_TPDOtransmitted. */ uint8_t flagsPDO[OD_FLAGS_PDO_SIZE]; +#endif } OD_extension_t; @@ -462,6 +468,78 @@ static inline void OD_rwRestart(OD_stream_t *stream) { } +/** + * Get TPDO request flags for OD entry. + * + * flagsPDO can be used for @ref OD_requestTPDO() or @ref OD_TPDOtransmitted(). + * + * @param entry OD entry returned by @ref OD_find(). + * + * @return pointer to flagsPDO + */ +static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) { +#if OD_FLAGS_PDO_SIZE > 0 + if (entry != NULL && entry->extension != NULL) { + return &entry->extension->flagsPDO[0]; + } +#endif + return 0; +} + + +/** + * Request TPDO, to which OD variable is mapped + * + * Function clears the flagPDO bit, which corresponds to OD variable at specific + * OD index and subindex. For this functionality to work, @ref OD_extension_t + * must be enabled on OD variable. If OD variable is mapped to any TPDO with + * event driven transmission, then TPDO will be transmitted after this function + * call. If OD variable is mapped to more than one TPDO with event driven + * transmission, only the first matched TPDO will be transmitted. + * + * TPDO event driven transmission is enabled, if TPDO communication parameter, + * transmission type is set to 0, 254 or 255. For other transmission types + * (synchronous) flagPDO bit is ignored. + * + * @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO. + * @param subIndex subIndex of the OD variable. + */ +static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) { +#if OD_FLAGS_PDO_SIZE > 0 + if (flagsPDO != NULL && subIndex < (OD_FLAGS_PDO_SIZE * 8)) { + /* clear subIndex-th bit */ + uint8_t mask = ~(1 << (subIndex & 0x07)); + flagsPDO[subIndex >> 3] &= mask; + } +#endif +} + + +/** + * Check if requested TPDO was transmitted + * + * @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO. + * @param subIndex subIndex of the OD variable. + * + * @return Return true if event driven TPDO with mapping to OD variable, + * indicated by flagsPDO and subIndex, was transmitted since last + * @ref OD_requestTPDO call. If there was no @ref OD_requestTPDO call yet and + * TPDO was transmitted by other event, function also returns true. + */ +static inline bool_t OD_TPDOtransmitted(uint8_t *flagsPDO, uint8_t subIndex) { +#if OD_FLAGS_PDO_SIZE > 0 + if (flagsPDO != NULL && subIndex < (OD_FLAGS_PDO_SIZE * 8)) { + /* return true, if subIndex-th bit is set */ + uint8_t mask = 1 << (subIndex & 0x07); + if ((flagsPDO[subIndex >> 3] & mask) != 0) { + return true; + } + } +#endif + return false; +} + + /** * Get SDO abort code from returnCode * diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 420a7845..564a64ad 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -1,10 +1,10 @@ /* - * CANopen Process Data Object. + * CANopen Receive Process Data Object protocol. * * @file CO_PDO.c * @ingroup CO_PDO * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2021 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -23,1076 +23,1422 @@ * limitations under the License. */ - #include #include "301/CO_PDO.h" #if (CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE) +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC + #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 + #error Dynamic PDO mapping is not possible without CO_CONFIG_PDO_OD_IO_ACCESS + #endif +#endif + +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS /* - * Read received message from CAN module. + * Custom function for write dummy OD object. Will be used only from RPDO. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. - * If new message arrives and previous message wasn't processed yet, then - * previous message will be lost and overwritten by new message. That's OK with PDOs. + * For more information see file CO_ODinterface.h, OD_IO_t. */ -static void CO_PDO_receive(void *object, void *msg){ - CO_RPDO_t *RPDO; - uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); +static ODR_t OD_write_dummy(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + (void) stream; (void) buf; + if (countWritten != NULL) *countWritten = count; + return ODR_OK; +} - RPDO = (CO_RPDO_t*)object; /* this is the correct pointer type of the first argument */ +/* + * Custom function for read dummy OD object. Will be used only from TPDO. + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static ODR_t OD_read_dummy(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) +{ + if (buf == NULL || stream == NULL || countRead == NULL) { + return ODR_DEV_INCOMPAT; + } - if( (RPDO->valid) && - (*RPDO->operatingState == CO_NMT_OPERATIONAL) && - (DLC >= RPDO->dataLength)) - { -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - const size_t index = RPDO->SYNC && RPDO->synchronous && RPDO->SYNC->CANrxToggle; -#else - const size_t index = 0; -#endif + if (count > stream->dataLength) { + count = stream->dataLength; + } - /* copy data into appropriate buffer and set 'new message' flag */ - memcpy(RPDO->CANrxData[index], data, sizeof(RPDO->CANrxData[index])); - CO_FLAG_SET(RPDO->CANrxNew[index]); + memset(buf, 0, count); -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE - /* Optional signal to RTOS, which can resume task, which handles RPDO. */ - if(RPDO->pFunctSignalPre != NULL) { - RPDO->pFunctSignalPre(RPDO->functSignalObjectPre); - } -#endif - } + *countRead = count; + return ODR_OK; } /* - * Configure RPDO Communication parameter. - * - * Function is called from commuincation reset or when parameter changes. + * Find mapped variable in Object Dictionary and configure entry in RPDO or TPDO * - * Function configures following variable from CO_RPDO_t: _valid_. It also - * configures CAN rx buffer. If configuration fails, emergency message is send - * and device is not able to enter NMT operational. + * @param PDO This object will be configured. If map is erroneous, then it will + * stay unchanged. + * @param map PDO mapping parameter. + * @param mapIndex from 0 to CO_PDO_MAX_MAPPED_ENTRIES + * @param isRPDO True for RPDO and false for TPDO. + * @param OD Object Dictionary. * - * @param RPDO RPDO object. - * @param COB_IDUsedByRPDO _RPDO communication parameter_, _COB-ID for PDO_ variable - * from Object dictionary (index 0x1400+, subindex 1). + * @return ODR_OK on success, otherwise error reason. */ -static void CO_RPDOconfigCom(CO_RPDO_t* RPDO, uint32_t COB_IDUsedByRPDO){ - uint16_t ID; - CO_ReturnError_t r; +static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, + uint32_t map, + uint8_t mapIndex, + bool_t isRPDO, + OD_t *OD) +{ + uint16_t index = (uint16_t) (map >> 16); + uint8_t subIndex = (uint8_t) (map >> 8); + uint8_t mappedLengthBits = (uint8_t) map; + uint8_t mappedLength = mappedLengthBits >> 3; + OD_IO_t *OD_IO = &PDO->OD_IO[mapIndex]; + + /* total PDO length can not be more than CO_PDO_MAX_SIZE bytes */ + if (mappedLength > CO_PDO_MAX_SIZE) { + return ODR_MAP_LEN; /* PDO length exceeded */ + } - ID = (uint16_t)COB_IDUsedByRPDO; + /* is there a reference to the dummy entry */ + if (index < 0x20 && subIndex == 0) { + OD_stream_t *stream = &OD_IO->stream; + memset(stream, 0, sizeof(OD_stream_t)); + stream->dataLength = stream->dataOffset = mappedLength; + OD_IO->read = OD_read_dummy; + OD_IO->write = OD_write_dummy; + return ODR_OK; + } - /* is RPDO used? */ - if((COB_IDUsedByRPDO & 0xBFFFF800L) == 0 && RPDO->dataLength && ID){ - /* is used default COB-ID? */ - if(ID == RPDO->defaultCOB_ID) ID += RPDO->nodeId; - RPDO->valid = true; -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - RPDO->synchronous = (RPDO->RPDOCommPar->transmissionType <= 240) ? true : false; -#endif + /* find entry in the Object Dictionary */ + OD_IO_t OD_IOcopy; + OD_entry_t *entry = OD_find(OD, index); + ODR_t odRet = OD_getSub(entry, subIndex, &OD_IOcopy, false); + if (odRet != ODR_OK) { + return odRet; } - else{ - ID = 0; - RPDO->valid = false; - CO_FLAG_CLEAR(RPDO->CANrxNew[0]); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - CO_FLAG_CLEAR(RPDO->CANrxNew[1]); -#endif + + /* verify access attributes, byte alignment and length */ + OD_attr_t testAttribute = isRPDO ? ODA_RPDO : ODA_TPDO; + if ((OD_IOcopy.stream.attribute & testAttribute) == 0 + || (mappedLengthBits & 0x07) != 0 + || OD_IOcopy.stream.dataLength < mappedLength + ) { + return ODR_NO_MAP; /* Object cannot be mapped to the PDO. */ } - r = CO_CANrxBufferInit( - RPDO->CANdevRx, /* CAN device */ - RPDO->CANdevRxIdx, /* rx buffer index */ - ID, /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void*)RPDO, /* object passed to receive function */ - CO_PDO_receive); /* this function will process received message */ - if(r != CO_ERROR_NO){ - RPDO->valid = false; - CO_FLAG_CLEAR(RPDO->CANrxNew[0]); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - CO_FLAG_CLEAR(RPDO->CANrxNew[1]); -#endif + + /* Copy values and store mappedLength temporary. */ + *OD_IO = OD_IOcopy; + OD_IO->stream.dataOffset = mappedLength; + + /* get TPDO request flag byte from extension */ +#if OD_FLAGS_PDO_SIZE > 0 + if (!isRPDO) { + if (subIndex < (OD_FLAGS_PDO_SIZE * 8) && entry->extension != NULL) { + PDO->flagPDObyte[mapIndex] = + &entry->extension->flagsPDO[subIndex >> 3]; + PDO->flagPDObitmask[mapIndex] = 1 << (subIndex & 0x07); + } + else { + PDO->flagPDObyte[mapIndex] = NULL; + } } -} +#endif + return ODR_OK; +} /* - * Configure TPDO Communication parameter. + * Initialize PDO mapping parameters * - * Function is called from commuincation reset or when parameter changes. + * @param PDO This object. + * @param OD Object Dictionary. + * @param OD_PDOMapPar OD entry for "PDO mapping parameter". + * @param isRPDO True for RPDO and false for TPDO. + * @param [out] errInfo Additional information in case of error, may be NULL. + * @param [out] erroneousMap Additional information about erroneous map. * - * Function configures following variable from CO_TPDO_t: _valid_. It also - * configures CAN tx buffer. If configuration fails, emergency message is send - * and device is not able to enter NMT operational. - * - * @param TPDO TPDO object. - * @param COB_IDUsedByTPDO _TPDO communication parameter_, _COB-ID for PDO_ variable - * from Object dictionary (index 0x1400+, subindex 1). - * @param syncFlag Indicate, if TPDO is synchronous. + * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -static void CO_TPDOconfigCom(CO_TPDO_t* TPDO, uint32_t COB_IDUsedByTPDO, uint8_t syncFlag){ - uint16_t ID; +static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, + OD_t *OD, + OD_entry_t *OD_PDOMapPar, + bool_t isRPDO, + uint32_t *errInfo, + uint32_t *erroneousMap) +{ + ODR_t odRet; + size_t pdoDataLength = 0; + uint8_t mappedObjectsCount = 0; + + /* number of mapped application objects in PDO */ + odRet = OD_get_u8(OD_PDOMapPar, 0, &mappedObjectsCount, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = ((uint32_t)OD_getIndex(OD_PDOMapPar)) << 8; + } + return CO_ERROR_OD_PARAMETERS; + } + + for (uint8_t i = 0; i < CO_PDO_MAX_MAPPED_ENTRIES; i++) { + OD_IO_t *OD_IO = &PDO->OD_IO[i]; + uint32_t map = 0; + + odRet = OD_get_u32(OD_PDOMapPar, i + 1, &map, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_PDOMapPar))<<8) | i; + } + return CO_ERROR_OD_PARAMETERS; + } - ID = (uint16_t)COB_IDUsedByTPDO; + odRet = PDOconfigMap(PDO, map, i, isRPDO, OD); + if (odRet != ODR_OK) { + /* indicate erroneous mapping in initialization phase */ + OD_IO->stream.dataLength = 0; + OD_IO->stream.dataOffset = 0xFF; + if (*erroneousMap == 0) *erroneousMap = map; + } - /* is TPDO used? */ - if((COB_IDUsedByTPDO & 0xBFFFF800L) == 0 && TPDO->dataLength && ID){ - /* is used default COB-ID? */ - if(ID == TPDO->defaultCOB_ID) ID += TPDO->nodeId; - TPDO->valid = true; + if (i < mappedObjectsCount) { + pdoDataLength += OD_IO->stream.dataOffset; + } } - else{ - ID = 0; - TPDO->valid = false; + if (pdoDataLength > CO_PDO_MAX_SIZE + || (pdoDataLength == 0 && mappedObjectsCount > 0) + ) { + if (*erroneousMap == 0) *erroneousMap = 1; } - TPDO->CANtxBuff = CO_CANtxBufferInit( - TPDO->CANdevTx, /* CAN device */ - TPDO->CANdevTxIdx, /* index of specific buffer inside CAN module */ - ID, /* CAN identifier */ - 0, /* rtr */ - TPDO->dataLength, /* number of data bytes */ - syncFlag); /* synchronous message flag bit */ - - if(TPDO->CANtxBuff == 0){ - TPDO->valid = false; + if (*erroneousMap == 0) { + PDO->dataLength = (CO_PDO_size_t)pdoDataLength; + PDO->mappedObjectsCount = mappedObjectsCount; } -} + return CO_ERROR_NO; +} +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC /* - * Find mapped variable in Object Dictionary. + * Custom function for writing OD object "PDO mapping parameter" * - * Function is called from CO_R(T)PDOconfigMap or when mapping parameter changes. - * - * @param SDO SDO object. - * @param map PDO mapping parameter. - * @param R_T 0 for RPDO map, 1 for TPDO map. - * @param ppData Pointer to returning parameter: pointer to data of mapped variable. - * @param pLength Pointer to returning parameter: *add* length of mapped variable. - * @param pSendIfCOSFlags Pointer to returning parameter: sendIfCOSFlags variable. - * @param pIsMultibyteVar Pointer to returning parameter: true for multibyte variable. - * - * @return 0 on success, otherwise SDO abort code. + * For more information see file CO_ODinterface.h, OD_IO_t. */ -static uint32_t CO_PDOfindMap( - CO_SDO_t *SDO, - uint32_t map, - uint8_t R_T, - uint8_t **ppData, - uint8_t *pLength, - uint8_t *pSendIfCOSFlags, - uint8_t *pIsMultibyteVar) +static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) { - uint16_t entryNo; - uint16_t index; - uint8_t subIndex; - uint8_t dataLen; - uint8_t objectLen; - uint8_t attr; - - index = (uint16_t)(map>>16); - subIndex = (uint8_t)(map>>8); - dataLen = (uint8_t) map; /* data length in bits */ + /* "count" is already verified in *_init() function */ + if (stream == NULL || buf == NULL || countWritten == NULL + || stream->subIndex > CO_PDO_MAX_MAPPED_ENTRIES + ) { + return ODR_DEV_INCOMPAT; + } - /* data length must be byte aligned */ - if(dataLen&0x07) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ + /* Only common part of the CO_RPDO_t or CO_TPDO_t will be used */ + CO_PDO_common_t *PDO = stream->object; - dataLen >>= 3; /* new data length is in bytes */ - *pLength += dataLen; + /* PDO must be disabled before mapping configuration */ + if (PDO->valid || (PDO->mappedObjectsCount != 0 && stream->subIndex > 0)) { + return ODR_INVALID_VALUE; + } - /* total PDO length can not be more than 8 bytes */ - if(*pLength > 8) return CO_SDO_AB_MAP_LEN; /* The number and length of the objects to be mapped would exceed PDO length. */ + if (stream->subIndex == 0) { + uint8_t mappedObjectsCount = CO_getUint8(buf); + size_t pdoDataLength = 0; - /* is there a reference to dummy entries */ - if(index <=7 && subIndex == 0){ - static uint32_t dummyTX = 0; - static uint32_t dummyRX; - uint8_t dummySize = 4; + if (mappedObjectsCount > CO_PDO_MAX_MAPPED_ENTRIES) { + return ODR_INVALID_VALUE; + } - if(index<2) dummySize = 0; - else if(index==2 || index==5) dummySize = 1; - else if(index==3 || index==6) dummySize = 2; + /* validate enabled mapping parameters */ + for (uint8_t i = 0; i < mappedObjectsCount; i++) { + OD_IO_t *OD_IO = &PDO->OD_IO[i]; + size_t dataLength = (size_t) OD_IO->stream.dataLength; + size_t mappedLength = (size_t) OD_IO->stream.dataOffset; - /* is size of variable big enough for map */ - if(dummySize < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ + if (mappedLength > dataLength) { + /* erroneous map since device initial values */ + return ODR_NO_MAP; + } + pdoDataLength += mappedLength; + } - /* Data and ODE pointer */ - if(R_T == 0) *ppData = (uint8_t*) &dummyRX; - else *ppData = (uint8_t*) &dummyTX; + if (pdoDataLength > CO_PDO_MAX_SIZE) { + return ODR_MAP_LEN; + } + if (pdoDataLength == 0 && mappedObjectsCount > 0) { + return ODR_INVALID_VALUE; + } - return 0; + /* success, update PDO */ + PDO->dataLength = (CO_PDO_size_t)pdoDataLength; + PDO->mappedObjectsCount = mappedObjectsCount; + } + else { + ODR_t odRet = PDOconfigMap(PDO, CO_getUint32(buf), stream->subIndex-1, + PDO->isRPDO, PDO->OD); + if (odRet != ODR_OK) { + return odRet; + } } - /* find object in Object Dictionary */ - entryNo = CO_OD_find(SDO, index); - - /* Does object exist in OD? */ - if(entryNo == 0xFFFF || subIndex > SDO->OD[entryNo].maxSubIndex) - return CO_SDO_AB_NOT_EXIST; /* Object does not exist in the object dictionary. */ - - attr = CO_OD_getAttribute(SDO, entryNo, subIndex); - /* Is object Mappable for RPDO? */ - if(R_T==0 && !((attr&CO_ODA_RPDO_MAPABLE) && (attr&CO_ODA_WRITEABLE))) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ - /* Is object Mappable for TPDO? */ - if(R_T!=0 && !((attr&CO_ODA_TPDO_MAPABLE) && (attr&CO_ODA_READABLE))) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ - - /* is size of variable big enough for map */ - objectLen = CO_OD_getLength(SDO, entryNo, subIndex); - if(objectLen < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ - - /* mark multibyte variable */ - *pIsMultibyteVar = (attr&CO_ODA_MB_VALUE) ? 1 : 0; + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, buf, count, countWritten); +} +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ - /* pointer to data */ - *ppData = (uint8_t*) CO_OD_getDataPointer(SDO, entryNo, subIndex); -#ifdef CO_BIG_ENDIAN - /* skip unused MSB bytes */ - if(*pIsMultibyteVar){ - *ppData += objectLen - dataLen; - } -#endif - /* setup change of state flags */ - if(attr&CO_ODA_TPDO_DETECT_COS){ - int16_t i; - for(i=*pLength-dataLen; i<*pLength; i++){ - *pSendIfCOSFlags |= 1< CO_PDO_MAX_SIZE) { + *erroneousMap = 1; + return CO_ERROR_NO; } - return 0; -} + /* iterate mapped OD variables */ + for (uint8_t i = 0; i < mappedObjectsCount; i++) { + uint32_t map = 0; + odRet = OD_get_u32(OD_PDOMapPar, i + 1, &map, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_PDOMapPar)) << 8) | i; + } + return CO_ERROR_OD_PARAMETERS; + } + uint16_t index = (uint16_t) (map >> 16); + uint8_t subIndex = (uint8_t) (map >> 8); + uint8_t mappedLengthBits = (uint8_t) map; + uint8_t mappedLength = mappedLengthBits >> 3; + uint8_t pdoDataStart = pdoDataLength; + pdoDataLength += mappedLength; + + if ((mappedLengthBits & 0x07) != 0 || pdoDataLength > CO_PDO_MAX_SIZE) { + *erroneousMap = map; + return CO_ERROR_NO; + } -/* - * Configure RPDO Mapping parameter. - * - * Function is called from communication reset or when parameter changes. - * - * Function configures following variables from CO_RPDO_t: _dataLength_ and - * _mapPointer_. - * - * @param RPDO RPDO object. - * @param noOfMappedObjects Number of mapped object (from OD). - * - * @return 0 on success, otherwise SDO abort code. - */ -static uint32_t CO_RPDOconfigMap(CO_RPDO_t* RPDO, uint8_t noOfMappedObjects){ - int16_t i; - uint8_t length = 0; - uint32_t ret = 0; - const uint32_t* pMap = &RPDO->RPDOMapPar->mappedObject1; - - for(i=noOfMappedObjects; i>0; i--){ - int16_t j; - uint8_t* pData; - uint8_t dummy = 0; - uint8_t prevLength = length; - uint8_t MBvar; - uint32_t map = *(pMap++); - - /* function do much checking of errors in map */ - ret = CO_PDOfindMap( - RPDO->SDO, - map, - 0, - &pData, - &length, - &dummy, - &MBvar); - if(ret){ - length = 0; - CO_errorReport(RPDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, map); - break; + /* is there a reference to the dummy entry */ + if (index < 0x20 && subIndex == 0) { + for (uint8_t j = pdoDataStart; j < pdoDataLength; j++) { + static uint8_t dummyTX = 0; + static uint8_t dummyRX; + PDO->mapPointer[j] = isRPDO ? &dummyRX : &dummyTX; + } + continue; + } + + /* find entry in the Object Dictionary, original location */ + OD_IO_t OD_IO; + OD_entry_t *entry = OD_find(OD, index); + OD_attr_t testAttribute = isRPDO ? ODA_RPDO : ODA_TPDO; + + ODR_t odRet = OD_getSub(entry, subIndex, &OD_IO, true); + if (odRet != ODR_OK + || (OD_IO.stream.attribute & testAttribute) == 0 + || OD_IO.stream.dataLength < mappedLength + || OD_IO.stream.dataOrig == NULL + ) { + *erroneousMap = map; + return CO_ERROR_NO; } - /* write PDO data pointers */ + /* write locations to OD variable data bytes into PDO map pointers */ #ifdef CO_BIG_ENDIAN - if(MBvar){ - for(j=length-1; j>=prevLength; j--) - RPDO->mapPointer[j] = pData++; + if((OD_IO.stream.attribute & ODA_MB) != 0) { + uint8_t *odDataPointer = OD_IO.stream.dataOrig + + OD_IO.stream.dataLength - 1; + for (uint8_t j = pdoDataStart; j < pdoDataLength; j++) { + PDO->mapPointer[j] = odDataPointer--; + } } - else{ - for(j=prevLength; jmapPointer[j] = pData++; + else +#endif + { + uint8_t *odDataPointer = OD_IO.stream.dataOrig; + for (uint8_t j = pdoDataStart; j < pdoDataLength; j++) { + PDO->mapPointer[j] = odDataPointer++; + } } -#else - for(j=prevLength; jmapPointer[j] = pData++; + + /* get TPDO request flag byte from extension */ +#if OD_FLAGS_PDO_SIZE > 0 + if (!isRPDO && subIndex < (OD_FLAGS_PDO_SIZE * 8) + && entry->extension != NULL + ) { + PDO->flagPDObyte[pdoDataStart] = + &entry->extension->flagsPDO[subIndex >> 3]; + PDO->flagPDObitmask[pdoDataStart] = 1 << (subIndex & 0x07); } #endif - } - RPDO->dataLength = length; - - return ret; + PDO->dataLength = PDO->mappedObjectsCount = pdoDataLength; + return CO_ERROR_NO; } +#endif /* ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 */ + +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC /* - * Configure TPDO Mapping parameter. - * - * Function is called from communication reset or when parameter changes. - * - * Function configures following variables from CO_TPDO_t: _dataLength_, - * _mapPointer_ and _sendIfCOSFlags_. + * Custom function for reading OD object "PDO communication parameter" * - * @param TPDO TPDO object. - * @param noOfMappedObjects Number of mapped object (from OD). - * - * @return 0 on success, otherwise SDO abort code. + * For more information see file CO_ODinterface.h, OD_IO_t. */ -static uint32_t CO_TPDOconfigMap(CO_TPDO_t* TPDO, uint8_t noOfMappedObjects){ - int16_t i; - uint8_t length = 0; - uint32_t ret = 0; - const uint32_t* pMap = &TPDO->TPDOMapPar->mappedObject1; - - TPDO->sendIfCOSFlags = 0; - - for(i=noOfMappedObjects; i>0; i--){ - int16_t j; - uint8_t* pData; - uint8_t prevLength = length; - uint8_t MBvar; - uint32_t map = *(pMap++); - - /* function do much checking of errors in map */ - ret = CO_PDOfindMap( - TPDO->SDO, - map, - 1, - &pData, - &length, - &TPDO->sendIfCOSFlags, - &MBvar); - if(ret){ - length = 0; - CO_errorReport(TPDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, map); - break; +static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) +{ + ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); + + /* When reading COB_ID, add Node-Id to the read value, if necessary */ + if (returnCode == ODR_OK && stream->subIndex == 1 && *countRead == 4) { + /* Only common part of the CO_RPDO_t or CO_TPDO_t will be used */ + CO_PDO_common_t *PDO = stream->object; + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + + /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ + if (CAN_ID != 0 && CAN_ID == (PDO->preDefinedCanId & 0xFF80)) { + COB_ID = (COB_ID & 0xFFFF0000) | PDO->preDefinedCanId; } - /* write PDO data pointers */ -#ifdef CO_BIG_ENDIAN - if(MBvar){ - for(j=length-1; j>=prevLength; j--) - TPDO->mapPointer[j] = pData++; - } - else{ - for(j=prevLength; jmapPointer[j] = pData++; - } -#else - for(j=prevLength; jmapPointer[j] = pData++; - } -#endif + /* If PDO is not valid, set bit 31 */ + if (!PDO->valid) COB_ID |= 0x80000000; + CO_setUint32(buf, COB_ID); } - TPDO->dataLength = length; - - return ret; + return returnCode; } +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ +/******************************************************************************* + * R P D O + ******************************************************************************/ +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE /* - * Function for accessing _RPDO communication parameter_ (index 0x1400+) from SDO server. - * - * For more information see file CO_SDOserver.h. + * States for RPDO->receiveError indicates received RPDOs with wrong length. */ -static CO_SDO_abortCode_t CO_ODF_RPDOcom(CO_ODF_arg_t *ODF_arg){ - CO_RPDO_t *RPDO; +typedef enum { + CO_RPDO_RX_ACK_NO_ERROR = 0, /* No error */ + CO_RPDO_RX_ACK_ERROR = 1, /* Error is acknowledged */ + CO_RPDO_RX_ACK = 10, /* Auxiliary value */ + CO_RPDO_RX_OK = 11, /* Correct RPDO received, not acknowledged */ + CO_RPDO_RX_SHORT = 12, /* Too short RPDO received, not acknowledged */ + CO_RPDO_RX_LONG = 13 /* Too long RPDO received, not acknowledged */ +} CO_PDO_receiveErrors_t; - RPDO = (CO_RPDO_t*) ODF_arg->object; +/* + * Read received message from CAN module. + * + * Function will be called (by CAN receive interrupt) every time, when CAN + * message with correct identifier will be received. For more information and + * description of parameters see file CO_driver.h. + * If new message arrives and previous message wasn't processed yet, then + * previous message will be lost and overwritten by the new message. + */ +static void CO_PDO_receive(void *object, void *msg) { + CO_RPDO_t *RPDO = object; + CO_PDO_common_t *PDO = &RPDO->PDO_common; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); + uint8_t err = RPDO->receiveError; - /* Reading Object Dictionary variable */ - if(ODF_arg->reading){ - if(ODF_arg->subIndex == 1){ - uint32_t value = CO_getUint32(ODF_arg->data); + if (PDO->valid) { + if (DLC >= PDO->dataLength) { + /* indicate errors in PDO length */ + if (DLC == PDO->dataLength) { + if (err == CO_RPDO_RX_ACK_ERROR) err = CO_RPDO_RX_OK; + } + else { + if (err == CO_RPDO_RX_ACK_NO_ERROR) err = CO_RPDO_RX_LONG; + } - /* if default COB ID is used, write default value here */ - if(((value)&0xFFFF) == RPDO->defaultCOB_ID && RPDO->defaultCOB_ID) - value += RPDO->nodeId; + /* Determine, to which of the two rx buffers copy the message. */ + uint8_t bufNo = 0; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + if (RPDO->synchronous && RPDO->SYNC != NULL + && RPDO->SYNC->CANrxToggle + ) { + bufNo = 1; + } +#endif - /* If PDO is not valid, set bit 31 */ - if(!RPDO->valid) value |= 0x80000000L; + /* copy data into appropriate buffer and set 'new message' flag */ + memcpy(RPDO->CANrxData[bufNo], data,sizeof(RPDO->CANrxData[bufNo])); + CO_FLAG_SET(RPDO->CANrxNew[bufNo]); - CO_setUint32(ODF_arg->data, value); +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE + /* Optional signal to RTOS, which can resume task, which handles + * the RPDO. */ + if (RPDO->pFunctSignalPre != NULL) { + RPDO->pFunctSignalPre(RPDO->functSignalObjectPre); + } +#endif + } + else if (err == CO_RPDO_RX_ACK_NO_ERROR) { + err = CO_RPDO_RX_SHORT; } - return CO_SDO_AB_NONE; } - /* Writing Object Dictionary variable */ - if(RPDO->restrictionFlags & 0x04) - return CO_SDO_AB_READONLY; /* Attempt to write a read only object. */ - if(*RPDO->operatingState == CO_NMT_OPERATIONAL && (RPDO->restrictionFlags & 0x01)) - return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + RPDO->receiveError = err; +} - if(ODF_arg->subIndex == 1){ /* COB_ID */ - uint32_t value = CO_getUint32(ODF_arg->data); - /* bits 11...29 must be zero */ - if(value & 0x3FFF8000L) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC +/* + * Custom function for writing OD object "RPDO communication parameter" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + /* "count" is also verified in *_init() function */ + if (stream == NULL || buf == NULL || countWritten == NULL || count > 4) { + return ODR_DEV_INCOMPAT; + } - /* if default COB-ID is being written, write defaultCOB_ID without nodeId */ - if(((value)&0xFFFF) == (RPDO->defaultCOB_ID + RPDO->nodeId)){ - value &= 0xC0000000L; - value += RPDO->defaultCOB_ID; - CO_setUint32(ODF_arg->data, value); + CO_RPDO_t *RPDO = stream->object; + CO_PDO_common_t *PDO = &RPDO->PDO_common; + uint8_t bufCopy[4]; + memcpy(bufCopy, buf, count); + + switch (stream->subIndex) { + case 1: { /* COB-ID used by PDO */ + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + bool_t valid = (COB_ID & 0x80000000) == 0; + + /* bits 11...29 must be zero, PDO must be disabled on change, + * CAN_ID == 0 is not allowed, mapping must be configured before + * enabling the PDO */ + if ((COB_ID & 0x3FFFF800) != 0 + || (valid && PDO->valid && CAN_ID != PDO->configuredCanId) + || (valid && CAN_ID == 0) + || (valid && PDO->mappedObjectsCount == 0) + ) { + return ODR_INVALID_VALUE; } - /* if PDO is valid, bits 0..29 can not be changed */ - if(RPDO->valid && ((value ^ RPDO->RPDOCommPar->COB_IDUsedByRPDO) & 0x3FFFFFFFL)) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + /* parameter changed? */ + if (valid != PDO->valid || CAN_ID != PDO->configuredCanId) { + /* if default CAN-ID is written, store to OD without Node-ID */ + if (CAN_ID == PDO->preDefinedCanId) { + CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); + } + if (!valid) { + CAN_ID = 0; + } - /* configure RPDO */ - CO_RPDOconfigCom(RPDO, value); - } - else if(ODF_arg->subIndex == 2){ /* Transmission_type */ - uint8_t *value = (uint8_t*) ODF_arg->data; + CO_ReturnError_t ret = CO_CANrxBufferInit( + PDO->CANdev, /* CAN device */ + PDO->CANdevIdx, /* rx buffer index */ + CAN_ID, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)RPDO, /* object passed to receive function */ + CO_PDO_receive); /* this function will process rx msg */ + + if (valid && ret == CO_ERROR_NO) { + PDO->valid = true; + PDO->configuredCanId = CAN_ID; + } + else { + PDO->valid = false; + CO_FLAG_CLEAR(RPDO->CANrxNew[0]); #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - bool_t synchronousPrev = RPDO->synchronous; - - /* values from 241...253 are not valid */ - if(*value >= 241 && *value <= 253) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); +#endif + if (ret != CO_ERROR_NO) { + return ODR_DEV_INCOMPAT; + } + } + } + break; + } - RPDO->synchronous = (*value <= 240) ? true : false; + case 2: { /* transmission type */ + uint8_t transmissionType = CO_getUint8(buf); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + if (transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240 + && transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO + ) { + return ODR_INVALID_VALUE; + } - /* Remove old message from second buffer. */ - if(RPDO->synchronous != synchronousPrev) { + bool_t synchronous = transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240; + /* Remove old message from the second buffer. */ + if (RPDO->synchronous != synchronous) { CO_FLAG_CLEAR(RPDO->CANrxNew[1]); } + + RPDO->synchronous = synchronous; #else - /* values from 0...253 are not valid */ - if(*value <= 253) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { + return ODR_INVALID_VALUE; + } #endif + break; } - return CO_SDO_AB_NONE; -} +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + case 5: { /* event-timer */ + uint32_t eventTime = CO_getUint16(buf); + RPDO->timeoutTime_us = eventTime * 1000; + RPDO->timeoutTimer = 0; + break; + } +#endif + } + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, bufCopy, count, countWritten); +} +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ -/* - * Function for accessing _TPDO communication parameter_ (index 0x1800+) from SDO server. - * - * For more information see file CO_SDOserver.h. - */ -static CO_SDO_abortCode_t CO_ODF_TPDOcom(CO_ODF_arg_t *ODF_arg){ - CO_TPDO_t *TPDO; - TPDO = (CO_TPDO_t*) ODF_arg->object; +/******************************************************************************/ +CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, + OD_t *OD, + CO_EM_t *em, +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + CO_SYNC_t *SYNC, +#endif + uint16_t preDefinedCanId, + OD_entry_t *OD_14xx_RPDOCommPar, + OD_entry_t *OD_16xx_RPDOMapPar, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + uint32_t *errInfo) +{ + CO_PDO_common_t *PDO = &RPDO->PDO_common; + CO_ReturnError_t ret; + ODR_t odRet; - if(ODF_arg->subIndex == 4) return CO_SDO_AB_SUB_UNKNOWN; /* Sub-index does not exist. */ + /* verify arguments */ + if (RPDO == NULL || OD == NULL || em == NULL || OD_14xx_RPDOCommPar == NULL + || OD_16xx_RPDOMapPar == NULL || CANdevRx == NULL + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } - /* Reading Object Dictionary variable */ - if(ODF_arg->reading){ - if(ODF_arg->subIndex == 1){ /* COB_ID */ - uint32_t value = CO_getUint32(ODF_arg->data); + /* clear object */ + memset(RPDO, 0, sizeof(CO_RPDO_t)); - /* if default COB ID is used, write default value here */ - if(((value)&0xFFFF) == TPDO->defaultCOB_ID && TPDO->defaultCOB_ID) - value += TPDO->nodeId; + /* Configure object variables */ + PDO->em = em; + PDO->CANdev = CANdevRx; + + /* Configure mapping parameters */ + uint32_t erroneousMap = 0; + ret = PDO_initMapping(PDO, + OD, + OD_16xx_RPDOMapPar, + true, + errInfo, + &erroneousMap); + if (ret != CO_ERROR_NO) { + return ret; + } - /* If PDO is not valid, set bit 31 */ - if(!TPDO->valid) value |= 0x80000000L; - CO_setUint32(ODF_arg->data, value); + /* Configure communication parameter - COB-ID */ + uint32_t COB_ID = 0; + odRet = OD_get_u32(OD_14xx_RPDOCommPar, 1, &COB_ID, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_14xx_RPDOCommPar)) << 8) | 1; } - return CO_SDO_AB_NONE; + return CO_ERROR_OD_PARAMETERS; } - /* Writing Object Dictionary variable */ - if(TPDO->restrictionFlags & 0x04) - return CO_SDO_AB_READONLY; /* Attempt to write a read only object. */ - if(*TPDO->operatingState == CO_NMT_OPERATIONAL && (TPDO->restrictionFlags & 0x01)) - return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + bool_t valid = (COB_ID & 0x80000000) == 0; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + if (valid && (PDO->mappedObjectsCount == 0 || CAN_ID == 0)) { + valid = false; + if (erroneousMap == 0) erroneousMap = 1; + } - if(ODF_arg->subIndex == 1){ /* COB_ID */ - uint32_t value = CO_getUint32(ODF_arg->data); + if (erroneousMap != 0) { + CO_errorReport(PDO->em, + CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, + erroneousMap != 1 ? erroneousMap : COB_ID); + } + if (!valid) { + CAN_ID = 0; + } - /* bits 11...29 must be zero */ - if(value & 0x3FFF8000L) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ + if (CAN_ID != 0 && CAN_ID == (preDefinedCanId & 0xFF80)) { + CAN_ID = preDefinedCanId; + } - /* if default COB-ID is being written, write defaultCOB_ID without nodeId */ - if(((value)&0xFFFF) == (TPDO->defaultCOB_ID + TPDO->nodeId)){ - value &= 0xC0000000L; - value += TPDO->defaultCOB_ID; + ret = CO_CANrxBufferInit( + CANdevRx, /* CAN device */ + CANdevRxIdx, /* rx buffer index */ + CAN_ID, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)RPDO, /* object passed to receive function */ + CO_PDO_receive); /* this function will process received message*/ + if (ret != CO_ERROR_NO) { + return ret; + } - CO_setUint32(ODF_arg->data, value); - } + PDO->valid = valid; - /* if PDO is valid, bits 0..29 can not be changed */ - if(TPDO->valid && ((value ^ TPDO->TPDOCommPar->COB_IDUsedByTPDO) & 0x3FFFFFFFL)) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ - /* configure TPDO */ - CO_TPDOconfigCom(TPDO, value, TPDO->CANtxBuff->syncFlag); + /* Configure communication parameter - transmission type */ #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - TPDO->syncCounter = 255; -#endif + uint8_t transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; + odRet = OD_get_u8(OD_14xx_RPDOCommPar, 2, &transmissionType, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_14xx_RPDOCommPar)) << 8) | 2; + } + return CO_ERROR_OD_PARAMETERS; } - else if(ODF_arg->subIndex == 2){ /* Transmission_type */ - uint8_t *value = (uint8_t*) ODF_arg->data; -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - /* values from 241...253 are not valid */ - if(*value >= 241 && *value <= 253) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ - TPDO->CANtxBuff->syncFlag = (*value <= 240) ? 1 : 0; - TPDO->syncCounter = 255; -#else - /* values from 0...253 are not valid */ - if(*value <= 253) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + RPDO->SYNC = SYNC; + RPDO->synchronous = transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240; #endif - } - else if(ODF_arg->subIndex == 3){ /* Inhibit_Time */ - /* if PDO is valid, value can not be changed */ - if(TPDO->valid) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ - TPDO->inhibitTimer = 0; - } - else if(ODF_arg->subIndex == 5){ /* Event_Timer */ - uint16_t value = CO_getUint16(ODF_arg->data); - TPDO->eventTimer = ((uint32_t) value) * 1000; - } - else if(ODF_arg->subIndex == 6){ /* SYNC start value */ - uint8_t *value = (uint8_t*) ODF_arg->data; + /* Configure communication parameter - event-timer (optional) */ +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + uint16_t eventTime = 0; + odRet = OD_get_u16(OD_14xx_RPDOCommPar, 5, &eventTime, true); + RPDO->timeoutTime_us = (uint32_t)eventTime * 1000; +#endif - /* if PDO is valid, value can not be changed */ - if(TPDO->valid) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ - /* values from 240...255 are not valid */ - if(*value > 240) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ - } + /* Configure OD extensions */ +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC + PDO->isRPDO = true; + PDO->OD = OD; + PDO->CANdevIdx = CANdevRxIdx; + PDO->preDefinedCanId = preDefinedCanId; + PDO->configuredCanId = CAN_ID; + PDO->OD_communicationParam_ext.object = RPDO; + PDO->OD_communicationParam_ext.read = OD_read_PDO_commParam; + PDO->OD_communicationParam_ext.write = OD_write_14xx; + PDO->OD_mappingParam_extension.object = RPDO; + PDO->OD_mappingParam_extension.read = OD_readOriginal; + PDO->OD_mappingParam_extension.write = OD_write_PDO_mapping; + OD_extension_init(OD_14xx_RPDOCommPar, &PDO->OD_communicationParam_ext); + OD_extension_init(OD_16xx_RPDOMapPar, &PDO->OD_mappingParam_extension); +#endif - return CO_SDO_AB_NONE; + return CO_ERROR_NO; } -/* - * Function for accessing _RPDO mapping parameter_ (index 0x1600+) from SDO server. - * - * For more information see file CO_SDOserver.h. - */ -static CO_SDO_abortCode_t CO_ODF_RPDOmap(CO_ODF_arg_t *ODF_arg){ - CO_RPDO_t *RPDO; +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE +void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, + void *object, + void (*pFunctSignalPre)(void *object)) +{ + if (RPDO != NULL) { + RPDO->functSignalObjectPre = object; + RPDO->pFunctSignalPre = pFunctSignalPre; + } +} +#endif - RPDO = (CO_RPDO_t*) ODF_arg->object; - /* Reading Object Dictionary variable */ - if(ODF_arg->reading){ - uint8_t *value = (uint8_t*) ODF_arg->data; +/******************************************************************************/ +void CO_RPDO_process(CO_RPDO_t *RPDO, +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + uint32_t timeDifference_us, + uint32_t *timerNext_us, +#endif + bool_t NMTisOperational, + bool_t syncWas) +{ + (void) syncWas; + CO_PDO_common_t *PDO = &RPDO->PDO_common; - if(ODF_arg->subIndex == 0){ - /* If there is error in mapping, dataLength is 0, so numberOfMappedObjects is 0. */ - if(!RPDO->dataLength) *value = 0; + if (PDO->valid && NMTisOperational +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + && (syncWas || !RPDO->synchronous) +#endif + ) { + /* Verify errors in length of received RPDO CAN message */ + if (RPDO->receiveError > CO_RPDO_RX_ACK) { + bool_t setError = RPDO->receiveError != CO_RPDO_RX_OK; + uint16_t code = RPDO->receiveError == CO_RPDO_RX_SHORT + ? CO_EMC_PDO_LENGTH : CO_EMC_PDO_LENGTH_EXC; + CO_error(PDO->em, setError, CO_EM_RPDO_WRONG_LENGTH, + code, PDO->dataLength); + RPDO->receiveError = setError + ? CO_RPDO_RX_ACK_ERROR : CO_RPDO_RX_ACK_NO_ERROR; } - return CO_SDO_AB_NONE; - } - /* Writing Object Dictionary variable */ - if(RPDO->restrictionFlags & 0x08) - return CO_SDO_AB_READONLY; /* Attempt to write a read only object. */ - if(*RPDO->operatingState == CO_NMT_OPERATIONAL && (RPDO->restrictionFlags & 0x02)) - return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ - if(RPDO->valid) - return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */ + /* Determine, which of the two rx buffers contains relevant message. */ + uint8_t bufNo = 0; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + if (RPDO->synchronous && RPDO->SYNC != NULL && !RPDO->SYNC->CANrxToggle) + bufNo = 1; +#endif + + /* copy RPDO into OD variables according to mappings */ + bool_t rpdoReceived = false; + while (CO_FLAG_READ(RPDO->CANrxNew[bufNo])) { + rpdoReceived = true; + uint8_t *dataRPDO = &RPDO->CANrxData[0][bufNo]; - /* numberOfMappedObjects */ - if(ODF_arg->subIndex == 0){ - uint8_t *value = (uint8_t*) ODF_arg->data; + /* Clear the flag. If between the copy operation CANrxNew is set + * by receive thread, then copy the latest data again. */ + CO_FLAG_CLEAR(RPDO->CANrxNew[bufNo]); - if(*value > 8) - return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds PDO length. */ +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS + for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { + OD_IO_t *OD_IO = &PDO->OD_IO[i]; + + /* get mappedLength from temporary storage */ + OD_size_t *dataOffset = &OD_IO->stream.dataOffset; + uint8_t mappedLength = (uint8_t) (*dataOffset); + + /* length of OD variable may be larger than mappedLength */ + OD_size_t ODdataLength = OD_IO->stream.dataLength; + if (ODdataLength > CO_PDO_MAX_SIZE) + ODdataLength = CO_PDO_MAX_SIZE; + + /* Prepare data for writing into OD variable. If mappedLength + * is smaller than ODdataLength, then use auxiliary buffer */ + uint8_t buf[CO_PDO_MAX_SIZE]; + uint8_t *dataOD; + if (ODdataLength > mappedLength) { + memset(buf, 0, sizeof(buf)); + memcpy(buf, dataOD, mappedLength); + dataOD = buf; + } + else { + dataOD = dataRPDO; + } - /* configure mapping */ - return (CO_SDO_abortCode_t) CO_RPDOconfigMap(RPDO, *value); - } + /* swap multibyte data if big-endian */ + #ifdef CO_BIG_ENDIAN + if ((OD_IO->stream.attribute & ODA_MB) != 0) { + uint8_t *lo = dataOD; + uint8_t *hi = dataOD + ODdataLength - 1; + while (lo < hi) { + uint8_t swap = *lo; + *lo++ = *hi; + *hi-- = swap; + } + } + #endif - /* mappedObject */ - else{ - uint32_t value = CO_getUint32(ODF_arg->data); - uint8_t* pData; - uint8_t length = 0; - uint8_t dummy = 0; - uint8_t MBvar; - - if(RPDO->dataLength) - return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */ - - /* verify if mapping is correct */ - return (CO_SDO_abortCode_t) CO_PDOfindMap( - RPDO->SDO, - value, - 0, - &pData, - &length, - &dummy, - &MBvar); - } + /* Set stream.dataOffset to zero, perform OD_IO.write() + * and store mappedLength back to stream.dataOffset */ + *dataOffset = 0; + OD_size_t countWritten; + OD_IO->write(&OD_IO->stream, dataOD, + ODdataLength, &countWritten); + *dataOffset = mappedLength; - return CO_SDO_AB_NONE; + dataRPDO += mappedLength; + } + +#else + for (uint8_t i = 0; i < PDO->dataLength; i++) { + *PDO->mapPointer[i] = dataRPDO[i]; + } +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ + + } /* while (CO_FLAG_READ(RPDO->CANrxNew[bufNo])) */ + + /* verify RPDO timeout */ + (void) rpdoReceived; +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + if (RPDO->timeoutTime_us > 0) { + if (rpdoReceived) { + if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { + CO_errorReset(PDO->em, CO_EM_RPDO_TIME_OUT, + RPDO->timeoutTimer); + } + /* enable monitoring */ + RPDO->timeoutTimer = 1; + } + else if (RPDO->timeoutTimer > 0 + && RPDO->timeoutTimer < RPDO->timeoutTime_us + ) { + RPDO->timeoutTimer += timeDifference_us; + + if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { + CO_errorReport(PDO->em, CO_EM_RPDO_TIME_OUT, + CO_EMC_RPDO_TIMEOUT, RPDO->timeoutTimer); + } + } + #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT + if (timerNext_us != NULL + && RPDO->timeoutTimer < RPDO->timeoutTime_us + ) { + uint32_t diff = RPDO->timeoutTime_us - RPDO->timeoutTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } + #endif + } +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE */ + } /* if (PDO->valid && NMTisOperational) */ + else { + /* not valid and operational, clear CAN receive flags and timeoutTimer*/ +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + if (!PDO->valid || !NMTisOperational) { + CO_FLAG_CLEAR(RPDO->CANrxNew[0]); + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); + #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + RPDO->timeoutTimer = 0; + #endif + } +#else + CO_FLAG_CLEAR(RPDO->CANrxNew[0]); + #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + RPDO->timeoutTimer = 0; + #endif +#endif + } } +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE */ +/******************************************************************************* + * T P D O + ******************************************************************************/ +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC /* - * Function for accessing _TPDO mapping parameter_ (index 0x1A00+) from SDO server. + * Custom function for writing OD object "TPDO communication parameter" * - * For more information see file CO_SDOserver.h. + * For more information see file CO_ODinterface.h, OD_IO_t. */ -static CO_SDO_abortCode_t CO_ODF_TPDOmap(CO_ODF_arg_t *ODF_arg){ - CO_TPDO_t *TPDO; +static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + /* "count" is also verified in *_init() function */ + if (stream == NULL || buf == NULL || countWritten == NULL || count > 4) { + return ODR_DEV_INCOMPAT; + } + + CO_TPDO_t *TPDO = stream->object; + CO_PDO_common_t *PDO = &TPDO->PDO_common; + uint8_t bufCopy[4]; + memcpy(bufCopy, buf, count); + + switch (stream->subIndex) { + case 1: { /* COB-ID used by PDO */ + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + bool_t valid = (COB_ID & 0x80000000) == 0; + + /* bits 11...29 must be zero, PDO must be disabled on change, + * CAN_ID == 0 is not allowed, mapping must be configured before + * enabling the PDO */ + if ((COB_ID & 0x3FFFF800) != 0 + || (valid && PDO->valid && CAN_ID != PDO->configuredCanId) + || (valid && CAN_ID == 0) + || (valid && PDO->mappedObjectsCount == 0) + ) { + return ODR_INVALID_VALUE; + } - TPDO = (CO_TPDO_t*) ODF_arg->object; + /* parameter changed? */ + if (valid != PDO->valid || CAN_ID != PDO->configuredCanId) { + /* if default CAN-ID is written, store to OD without Node-ID */ + if (CAN_ID == PDO->preDefinedCanId) { + CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); + } + if (!valid) { + CAN_ID = 0; + } - /* Reading Object Dictionary variable */ - if(ODF_arg->reading){ - uint8_t *value = (uint8_t*) ODF_arg->data; + CO_CANtx_t *CANtxBuff = CO_CANtxBufferInit( + PDO->CANdev, /* CAN device */ + PDO->CANdevIdx, /* index of specific buffer inside CAN mod. */ + CAN_ID, /* CAN identifier */ + 0, /* rtr */ + PDO->dataLength, /* number of data bytes */ + TPDO->transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240); + /* synchronous message flag */ + + if (CANtxBuff == NULL) { + return ODR_DEV_INCOMPAT; + } - if(ODF_arg->subIndex == 0){ - /* If there is error in mapping, dataLength is 0, so numberOfMappedObjects is 0. */ - if(!TPDO->dataLength) *value = 0; + TPDO->CANtxBuff = CANtxBuff; + PDO->valid = valid; + PDO->configuredCanId = CAN_ID; } - return CO_SDO_AB_NONE; + break; } - /* Writing Object Dictionary variable */ - if(TPDO->restrictionFlags & 0x08) - return CO_SDO_AB_READONLY; /* Attempt to write a read only object. */ - if(*TPDO->operatingState == CO_NMT_OPERATIONAL && (TPDO->restrictionFlags & 0x02)) - return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ - if(TPDO->valid) - return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */ - - /* numberOfMappedObjects */ - if(ODF_arg->subIndex == 0){ - uint8_t *value = (uint8_t*) ODF_arg->data; + case 2: { /* transmission type */ + uint8_t transmissionType = CO_getUint8(buf); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + if (transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240 + && transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO + ) { + return ODR_INVALID_VALUE; + } + TPDO->CANtxBuff->syncFlag = + transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240; + TPDO->syncCounter = 255; +#else + if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { + return ODR_INVALID_VALUE; + } +#endif + TPDO->transmissionType = transmissionType; + TPDO->sendRequest = true; +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + TPDO->inhibitTimer = TPDO->eventTimer = 0; +#endif + break; + } - if(*value > 8) - return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds PDO length. */ +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + case 3: { /* inhibit time */ + if (PDO->valid) { + return ODR_INVALID_VALUE; + } + uint32_t inhibitTime = CO_getUint16(buf); + TPDO->inhibitTime_us = inhibitTime * 100; + TPDO->inhibitTimer = 0; + break; + } - /* configure mapping */ - return (CO_SDO_abortCode_t) CO_TPDOconfigMap(TPDO, *value); + case 5: { /* event-timer */ + uint32_t eventTime = CO_getUint16(buf); + TPDO->eventTime_us = eventTime * 1000; + TPDO->eventTimer = 0; + break; } +#endif - /* mappedObject */ - else{ - uint32_t value = CO_getUint32(ODF_arg->data); - uint8_t* pData; - uint8_t length = 0; - uint8_t dummy = 0; - uint8_t MBvar; - - if(TPDO->dataLength) - return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */ - - /* verify if mapping is correct */ - return (CO_SDO_abortCode_t) CO_PDOfindMap( - TPDO->SDO, - value, - 1, - &pData, - &length, - &dummy, - &MBvar); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + case 6: { /* SYNC start value */ + uint8_t syncStartValue = CO_getUint8(buf); + + if (PDO->valid || syncStartValue > 240) { + return ODR_INVALID_VALUE; + } + TPDO->syncStartValue = syncStartValue; + break; + } +#endif } - return CO_SDO_AB_NONE; + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, bufCopy, count, countWritten); } +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ /******************************************************************************/ -CO_ReturnError_t CO_RPDO_init( - CO_RPDO_t *RPDO, - CO_EM_t *em, - CO_SDO_t *SDO, +CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, + OD_t *OD, + CO_EM_t *em, #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - CO_SYNC_t *SYNC, + CO_SYNC_t *SYNC, #endif - CO_NMT_internalState_t *operatingState, - uint8_t nodeId, - uint16_t defaultCOB_ID, - uint8_t restrictionFlags, - const CO_RPDOCommPar_t *RPDOCommPar, - const CO_RPDOMapPar_t *RPDOMapPar, - uint16_t idx_RPDOCommPar, - uint16_t idx_RPDOMapPar, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx) + uint16_t preDefinedCanId, + OD_entry_t *OD_18xx_TPDOCommPar, + OD_entry_t *OD_1Axx_TPDOMapPar, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, + uint32_t *errInfo) { + CO_PDO_common_t *PDO = &TPDO->PDO_common; + ODR_t odRet; + /* verify arguments */ - if(RPDO==NULL || em==NULL || SDO==NULL || operatingState==NULL || - RPDOCommPar==NULL || RPDOMapPar==NULL || CANdevRx==NULL){ + if (TPDO == NULL || OD == NULL || em == NULL || OD_18xx_TPDOCommPar == NULL + || OD_1Axx_TPDOMapPar == NULL || CANdevTx == NULL + ) { return CO_ERROR_ILLEGAL_ARGUMENT; } + /* clear object */ + memset(TPDO, 0, sizeof(CO_TPDO_t)); + /* Configure object variables */ - RPDO->em = em; - RPDO->SDO = SDO; -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - RPDO->SYNC = SYNC; -#endif - RPDO->RPDOCommPar = RPDOCommPar; - RPDO->RPDOMapPar = RPDOMapPar; - RPDO->operatingState = operatingState; - RPDO->nodeId = nodeId; - RPDO->defaultCOB_ID = defaultCOB_ID; - RPDO->restrictionFlags = restrictionFlags; -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE - RPDO->pFunctSignalPre = NULL; - RPDO->functSignalObjectPre = NULL; -#endif + PDO->em = em; + PDO->CANdev = CANdevTx; + + /* Configure mapping parameters */ + uint32_t erroneousMap = 0; + CO_ReturnError_t ret = PDO_initMapping(PDO, + OD, + OD_1Axx_TPDOMapPar, + false, + errInfo, + &erroneousMap); + if (ret != CO_ERROR_NO) { + return ret; + } - /* Configure Object dictionary entry at index 0x1400+ and 0x1600+ */ - CO_OD_configure(SDO, idx_RPDOCommPar, CO_ODF_RPDOcom, (void*)RPDO, 0, 0); - CO_OD_configure(SDO, idx_RPDOMapPar, CO_ODF_RPDOmap, (void*)RPDO, 0, 0); - /* configure communication and mapping */ - CO_FLAG_CLEAR(RPDO->CANrxNew[0]); + /* Configure communication parameter - transmission type */ + uint8_t transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; + odRet = OD_get_u8(OD_18xx_TPDOCommPar, 2, &transmissionType, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 2; + } + return CO_ERROR_OD_PARAMETERS; + } + if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - CO_FLAG_CLEAR(RPDO->CANrxNew[1]); + && transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240 #endif - RPDO->CANdevRx = CANdevRx; - RPDO->CANdevRxIdx = CANdevRxIdx; + ) { + transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; + } + TPDO->transmissionType = transmissionType; + TPDO->sendRequest = true; + + /* Configure communication parameter - COB-ID */ + uint32_t COB_ID = 0; + odRet = OD_get_u32(OD_18xx_TPDOCommPar, 1, &COB_ID, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 1; + } + return CO_ERROR_OD_PARAMETERS; + } - CO_RPDOconfigMap(RPDO, RPDOMapPar->numberOfMappedObjects); - CO_RPDOconfigCom(RPDO, RPDOCommPar->COB_IDUsedByRPDO); + bool_t valid = (COB_ID & 0x80000000) == 0; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + if (valid && (PDO->mappedObjectsCount == 0 || CAN_ID == 0)) { + valid = false; + if (erroneousMap == 0) erroneousMap = 1; + } - return CO_ERROR_NO; -} + if (erroneousMap != 0) { + CO_errorReport(PDO->em, + CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, + erroneousMap != 1 ? erroneousMap : COB_ID); + } + if (!valid) { + CAN_ID = 0; + } + /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ + if (CAN_ID != 0 && CAN_ID == (preDefinedCanId & 0xFF80)) { + CAN_ID = preDefinedCanId; + } -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE -/******************************************************************************/ -void CO_RPDO_initCallbackPre( - CO_RPDO_t *RPDO, - void *object, - void (*pFunctSignalPre)(void *object)) -{ - if(RPDO != NULL){ - RPDO->functSignalObjectPre = object; - RPDO->pFunctSignalPre = pFunctSignalPre; + TPDO->CANtxBuff = CO_CANtxBufferInit( + CANdevTx, /* CAN device */ + CANdevTxIdx, /* index of specific buffer inside CAN module */ + CAN_ID, /* CAN identifier */ + 0, /* rtr */ + PDO->dataLength, /* number of data bytes */ + TPDO->transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240); + /* synchronous message flag bit */ + if (TPDO->CANtxBuff == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; } -} -#endif + PDO->valid = valid; -/******************************************************************************/ -CO_ReturnError_t CO_TPDO_init( - CO_TPDO_t *TPDO, - CO_EM_t *em, - CO_SDO_t *SDO, -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - CO_SYNC_t *SYNC, + + /* Configure communication parameter - inhibit time and event-timer (opt) */ +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + uint16_t inhibitTime = 0; + uint16_t eventTime = 0; + odRet = OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); + odRet = OD_get_u16(OD_18xx_TPDOCommPar, 5, &eventTime, true); + TPDO->inhibitTime_us = inhibitTime * 100; + TPDO->eventTime_us = eventTime * 1000; #endif - CO_NMT_internalState_t *operatingState, - uint8_t nodeId, - uint16_t defaultCOB_ID, - uint8_t restrictionFlags, - const CO_TPDOCommPar_t *TPDOCommPar, - const CO_TPDOMapPar_t *TPDOMapPar, - uint16_t idx_TPDOCommPar, - uint16_t idx_TPDOMapPar, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx) -{ - /* verify arguments */ - if(TPDO==NULL || em==NULL || SDO==NULL || operatingState==NULL || - TPDOCommPar==NULL || TPDOMapPar==NULL || CANdevTx==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - /* Configure object variables */ - TPDO->em = em; - TPDO->SDO = SDO; + + /* Configure communication parameter - SYNC start value (optional) */ #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + TPDO->syncStartValue = 0; + odRet = OD_get_u8(OD_18xx_TPDOCommPar, 6, &TPDO->syncStartValue, true); TPDO->SYNC = SYNC; -#endif - TPDO->TPDOCommPar = TPDOCommPar; - TPDO->TPDOMapPar = TPDOMapPar; - TPDO->operatingState = operatingState; - TPDO->nodeId = nodeId; - TPDO->defaultCOB_ID = defaultCOB_ID; - TPDO->restrictionFlags = restrictionFlags; - - /* Configure Object dictionary entry at index 0x1800+ and 0x1A00+ */ - CO_OD_configure(SDO, idx_TPDOCommPar, CO_ODF_TPDOcom, (void*)TPDO, 0, 0); - CO_OD_configure(SDO, idx_TPDOMapPar, CO_ODF_TPDOmap, (void*)TPDO, 0, 0); - - /* configure communication and mapping */ - TPDO->CANdevTx = CANdevTx; - TPDO->CANdevTxIdx = CANdevTxIdx; - TPDO->inhibitTimer = 0; - TPDO->eventTimer = ((uint32_t) TPDOCommPar->eventTimer) * 1000; - if(TPDOCommPar->transmissionType>=254) TPDO->sendRequest = 1; - - CO_TPDOconfigMap(TPDO, TPDOMapPar->numberOfMappedObjects); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE TPDO->syncCounter = 255; - CO_TPDOconfigCom(TPDO, TPDOCommPar->COB_IDUsedByTPDO, ((TPDOCommPar->transmissionType<=240) ? 1 : 0)); - - if((TPDOCommPar->transmissionType>240 && - TPDOCommPar->transmissionType<254) || - TPDOCommPar->SYNCStartValue>240){ - TPDO->valid = false; - } -#else - CO_TPDOconfigCom(TPDO, TPDOCommPar->COB_IDUsedByTPDO, 0); - if(TPDOCommPar->transmissionType<254) - TPDO->valid = false; #endif - return CO_ERROR_NO; -} - - -/******************************************************************************/ -uint8_t CO_TPDOisCOS(CO_TPDO_t *TPDO){ - - /* Prepare TPDO data automatically from Object Dictionary variables */ - uint8_t* pPDOdataByte; - uint8_t** ppODdataByte; - - pPDOdataByte = &TPDO->CANtxBuff->data[TPDO->dataLength]; - ppODdataByte = &TPDO->mapPointer[TPDO->dataLength]; - - switch(TPDO->dataLength){ - case 8: if(*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x80)) return 1; // fallthrough - case 7: if(*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x40)) return 1; // fallthrough - case 6: if(*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x20)) return 1; // fallthrough - case 5: if(*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x10)) return 1; // fallthrough - case 4: if(*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x08)) return 1; // fallthrough - case 3: if(*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x04)) return 1; // fallthrough - case 2: if(*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x02)) return 1; // fallthrough - case 1: if(*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x01)) return 1; // fallthrough - } - - return 0; -} -/******************************************************************************/ -CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO){ - int16_t i; - uint8_t* pPDOdataByte; - uint8_t** ppODdataByte; - -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_CALLS_EXTENSION - if(TPDO->SDO->ODExtensions){ - /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ - const uint32_t* pMap = &TPDO->TPDOMapPar->mappedObject1; - CO_SDO_t *pSDO = TPDO->SDO; - - for(i=TPDO->TPDOMapPar->numberOfMappedObjects; i>0; i--){ - uint32_t map = *(pMap++); - uint16_t index = (uint16_t)(map>>16); - uint8_t subIndex = (uint8_t)(map>>8); - uint16_t entryNo = CO_OD_find(pSDO, index); - if ( entryNo == 0xFFFF ) continue; - CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo]; - if( ext->pODFunc == NULL) continue; - CO_ODF_arg_t ODF_arg; - memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t)); - ODF_arg.reading = true; - ODF_arg.index = index; - ODF_arg.subIndex = subIndex; - ODF_arg.object = ext->object; - ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex); - ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex); - ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); //https://github.com/CANopenNode/CANopenNode/issues/100 - ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex); - ext->pODFunc(&ODF_arg); - } - } + /* Configure OD extensions */ +#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC + PDO->isRPDO = false; + PDO->OD = OD; + PDO->CANdevIdx = CANdevTxIdx; + PDO->preDefinedCanId = preDefinedCanId; + PDO->configuredCanId = CAN_ID; + PDO->OD_communicationParam_ext.object = TPDO; + PDO->OD_communicationParam_ext.read = OD_read_PDO_commParam; + PDO->OD_communicationParam_ext.write = OD_write_18xx; + PDO->OD_mappingParam_extension.object = TPDO; + PDO->OD_mappingParam_extension.read = OD_readOriginal; + PDO->OD_mappingParam_extension.write = OD_write_PDO_mapping; + OD_extension_init(OD_18xx_TPDOCommPar, &PDO->OD_communicationParam_ext); + OD_extension_init(OD_1Axx_TPDOMapPar, &PDO->OD_mappingParam_extension); #endif - i = TPDO->dataLength; - pPDOdataByte = &TPDO->CANtxBuff->data[0]; - ppODdataByte = &TPDO->mapPointer[0]; - - /* Copy data from Object dictionary. */ - for(; i>0; i--) { - *(pPDOdataByte++) = **(ppODdataByte++); - } - TPDO->sendRequest = 0; - - return CO_CANsend(TPDO->CANdevTx, TPDO->CANtxBuff); + return CO_ERROR_NO; } -/******************************************************************************/ -void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){ - bool_t process_rpdo = true; - -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if(RPDO->synchronous && !syncWas) - process_rpdo = false; -#endif - if(!RPDO->valid || !(*RPDO->operatingState == CO_NMT_OPERATIONAL)) - { - CO_FLAG_CLEAR(RPDO->CANrxNew[0]); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - CO_FLAG_CLEAR(RPDO->CANrxNew[1]); -#endif - } - else if(process_rpdo) - { -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION - bool_t update = false; +/* + * Send TPDO message. + * + * Function prepares TPDO data from Object Dictionary variables. It is called + * from CO_TPDO_process() according to TPDO communication parameters. + * + * @param TPDO TPDO object. + * + * @return Same as CO_CANsend(). + */ +static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { + CO_PDO_common_t *PDO = &TPDO->PDO_common; + uint8_t *dataTPDO = &TPDO->CANtxBuff->data[0]; +#if OD_FLAGS_PDO_SIZE > 0 + bool_t eventDriven = + (TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC + || TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO); #endif - uint8_t bufNo = 0; - -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - /* Determine, which of the two rx buffers, contains relevant message. */ - if(RPDO->SYNC && RPDO->synchronous && !RPDO->SYNC->CANrxToggle) { - bufNo = 1; +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS + for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { + OD_IO_t *OD_IO = &PDO->OD_IO[i]; + OD_stream_t *stream = &OD_IO->stream; + + /* get mappedLength from temporary storage */ + uint8_t mappedLength = (uint8_t) stream->dataOffset; + + /* length of OD variable may be larger than mappedLength */ + OD_size_t ODdataLength = stream->dataLength; + if (ODdataLength > CO_PDO_MAX_SIZE) + ODdataLength = CO_PDO_MAX_SIZE; + + /* If mappedLength is smaller than ODdataLength, use auxiliary buffer */ + uint8_t buf[CO_PDO_MAX_SIZE]; + uint8_t *dataTPDOCopy; + if (ODdataLength > mappedLength) { + memset(buf, 0, sizeof(buf)); + dataTPDOCopy = buf; + } + else { + dataTPDOCopy = dataTPDO; } -#endif - while(CO_FLAG_READ(RPDO->CANrxNew[bufNo])){ - int16_t i; - uint8_t* pPDOdataByte; - uint8_t** ppODdataByte; + /* Set stream.dataOffset to zero, perform OD_IO.read() + * and store mappedLength back to stream.dataOffset */ + stream->dataOffset= 0; + OD_size_t countRd; + OD_IO->read(stream, dataTPDOCopy, ODdataLength, &countRd); + stream->dataOffset = mappedLength; + + /* swap multibyte data if big-endian */ + #ifdef CO_BIG_ENDIAN + if ((stream->attribute & ODA_MB) != 0) { + uint8_t *lo = dataOD; + uint8_t *hi = dataOD + ODdataLength - 1; + while (lo < hi) { + uint8_t swap = *lo; + *lo++ = *hi; + *hi-- = swap; + } + } + #endif - i = RPDO->dataLength; - pPDOdataByte = &RPDO->CANrxData[bufNo][0]; - ppODdataByte = &RPDO->mapPointer[0]; + /* If auxiliary buffer, copy it to the TPDO */ + if (ODdataLength > mappedLength) { + memcpy(dataTPDO, buf, mappedLength); + } - /* Copy data to Object dictionary. If between the copy operation CANrxNew - * is set to true by receive thread, then copy the latest data again. */ - CO_FLAG_CLEAR(RPDO->CANrxNew[bufNo]); - for(; i>0; i--) { - **(ppODdataByte++) = *(pPDOdataByte++); - } -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION - update = true; -#endif + /* In event driven TPDO indicate transmission of OD variable */ + #if OD_FLAGS_PDO_SIZE > 0 + uint8_t *flagPDObyte = PDO->flagPDObyte[i]; + if (flagPDObyte != NULL && eventDriven) { + *flagPDObyte |= PDO->flagPDObitmask[i]; } -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION - if(update && RPDO->SDO->ODExtensions){ - int16_t i; - /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ - const uint32_t* pMap = &RPDO->RPDOMapPar->mappedObject1; - CO_SDO_t *pSDO = RPDO->SDO; - - for(i=RPDO->RPDOMapPar->numberOfMappedObjects; i>0; i--){ - uint32_t map = *(pMap++); - uint16_t index = (uint16_t)(map>>16); - uint8_t subIndex = (uint8_t)(map>>8); - uint16_t entryNo = CO_OD_find(pSDO, index); - if ( entryNo == 0xFFFF ) continue; - CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo]; - if( ext->pODFunc == NULL) continue; - CO_ODF_arg_t ODF_arg; - memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t)); - ODF_arg.reading = false; - ODF_arg.index = index; - ODF_arg.subIndex = subIndex; - ODF_arg.object = ext->object; - ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex); - ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex); - ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); //https://github.com/CANopenNode/CANopenNode/issues/100 - ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex); - ext->pODFunc(&ODF_arg); - } + #endif + + dataTPDO += mappedLength; + } +#else + for (uint8_t i = 0; i < PDO->dataLength; i++) { + dataTPDO[i] = *PDO->mapPointer[i]; + + /* In event driven TPDO indicate transmission of OD variable */ + #if OD_FLAGS_PDO_SIZE > 0 + uint8_t *flagPDObyte = PDO->flagPDObyte[i]; + if (flagPDObyte != NULL && eventDriven) { + *flagPDObyte |= PDO->flagPDObitmask[i]; } -#endif + #endif } +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ + + TPDO->sendRequest = false; +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + TPDO->eventTimer = TPDO->eventTime_us; + TPDO->inhibitTimer = TPDO->inhibitTime_us; +#endif + return CO_CANsend(PDO->CANdev, TPDO->CANtxBuff); } /******************************************************************************/ -void CO_TPDO_process( - CO_TPDO_t *TPDO, - bool_t syncWas, - uint32_t timeDifference_us, - uint32_t *timerNext_us) +void CO_TPDO_process(CO_TPDO_t *TPDO, +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || defined CO_DOXYGEN + uint32_t timeDifference_us, + uint32_t *timerNext_us, +#endif + bool_t NMTisOperational, + bool_t syncWas) { - (void)timerNext_us; /* may be unused */ - - /* update timers */ - TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) : 0; - TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) ? (TPDO->eventTimer - timeDifference_us) : 0; + (void) syncWas; (void) timerNext_us; + CO_PDO_common_t *PDO = &TPDO->PDO_common; + + if (PDO->valid && NMTisOperational) { + + /* check for event timer or application event */ +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || (OD_FLAGS_PDO_SIZE > 0) + if (TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC + || TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO + ) { + /* event timer */ + #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + if (TPDO->eventTime_us != 0) { + TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) + ? (TPDO->eventTimer - timeDifference_us) : 0; + if (TPDO->eventTimer == 0) { + TPDO->sendRequest = true; + } + #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT + if (timerNext_us != NULL && *timerNext_us > TPDO->eventTimer) { + /* Schedule for next event time */ + *timerNext_us = TPDO->eventTimer; + } + #endif + } + #endif + /* check for any OD_requestTPDO() */ + #if OD_FLAGS_PDO_SIZE > 0 + if (!TPDO->sendRequest) { + for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { + uint8_t *flagPDObyte = PDO->flagPDObyte[i]; + if (flagPDObyte != NULL) { + if ((*flagPDObyte & PDO->flagPDObitmask[i]) == 0) { + TPDO->sendRequest = true; + break; + } + } + } + } + #endif + } +#endif /*((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE)||(OD_FLAGS_PDO_SIZE>0)*/ - if(TPDO->valid && *TPDO->operatingState == CO_NMT_OPERATIONAL){ /* Send PDO by application request or by Event timer */ - if(TPDO->TPDOCommPar->transmissionType >= 253){ - if(TPDO->inhibitTimer == 0 && (TPDO->sendRequest || (TPDO->TPDOCommPar->eventTimer && TPDO->eventTimer == 0))){ - if(CO_TPDOsend(TPDO) == CO_ERROR_NO){ - /* successfully sent */ - TPDO->inhibitTimer = ((uint32_t) TPDO->TPDOCommPar->inhibitTime) * 100; - TPDO->eventTimer = ((uint32_t) TPDO->TPDOCommPar->eventTimer) * 1000; - } + if (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) + ? (TPDO->inhibitTimer - timeDifference_us) : 0; + + /* send TPDO */ + if (TPDO->sendRequest && TPDO->inhibitTimer == 0) { + CO_TPDOsend(TPDO); } -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT - if(timerNext_us != NULL){ - if(TPDO->sendRequest && *timerNext_us > TPDO->inhibitTimer){ - *timerNext_us = TPDO->inhibitTimer; /* Schedule for just beyond inhibit window */ - }else if(TPDO->TPDOCommPar->eventTimer && *timerNext_us > TPDO->eventTimer){ - *timerNext_us = TPDO->eventTimer; /* Schedule for next maximum event time */ - } + + #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT + if (TPDO->sendRequest + && timerNext_us != NULL && *timerNext_us > TPDO->inhibitTimer + ) { + /* Schedule for just beyond inhibit window */ + *timerNext_us = TPDO->inhibitTimer; + } + #endif +#else + if (TPDO->sendRequest) { + CO_TPDOsend(TPDO); } #endif - } + } /* if (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) */ -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE /* Synchronous PDOs */ - else if(TPDO->SYNC && syncWas){ - /* send synchronous acyclic PDO */ - if(TPDO->TPDOCommPar->transmissionType == 0){ - if(TPDO->sendRequest) CO_TPDOsend(TPDO); +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + else if (TPDO->SYNC != NULL && syncWas) { + /* send synchronous acyclic TPDO */ + if (TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { + if (TPDO->sendRequest) CO_TPDOsend(TPDO); } - /* send synchronous cyclic PDO */ - else{ + /* send synchronous cyclic TPDO */ + else { /* is the start of synchronous TPDO transmission */ - if(TPDO->syncCounter == 255){ - if(TPDO->SYNC->counterOverflowValue && TPDO->TPDOCommPar->SYNCStartValue) - TPDO->syncCounter = 254; /* SYNCStartValue is in use */ - else - TPDO->syncCounter = TPDO->TPDOCommPar->transmissionType; + if (TPDO->syncCounter == 255) { + if (TPDO->SYNC->counterOverflowValue != 0 + && TPDO->syncStartValue != 0 + ) { + /* syncStartValue is in use */ + TPDO->syncCounter = 254; + } + else { + TPDO->syncCounter = TPDO->transmissionType; + } } - /* if the SYNCStartValue is in use, start first TPDO after SYNC with matched SYNCStartValue. */ - if(TPDO->syncCounter == 254){ - if(TPDO->SYNC->counter == TPDO->TPDOCommPar->SYNCStartValue){ - TPDO->syncCounter = TPDO->TPDOCommPar->transmissionType; + /* If the syncStartValue is in use, start first TPDO after SYNC + * with matched syncStartValue. */ + if (TPDO->syncCounter == 254) { + if (TPDO->SYNC->counter == TPDO->syncStartValue) { + TPDO->syncCounter = TPDO->transmissionType; CO_TPDOsend(TPDO); } } - /* Send PDO after every N-th Sync */ - else if(--TPDO->syncCounter == 0){ - TPDO->syncCounter = TPDO->TPDOCommPar->transmissionType; + /* Send TPDO after every N-th Sync */ + else if (--TPDO->syncCounter == 0) { + TPDO->syncCounter = TPDO->transmissionType; CO_TPDOsend(TPDO); } } - } + } /* else if (TPDO->SYNC && syncWas) */ #endif } - else{ - /* Not operational or valid. Force TPDO first send after operational or valid. */ - if(TPDO->TPDOCommPar->transmissionType>=254) TPDO->sendRequest = 1; - else TPDO->sendRequest = 0; + else { + /* Not operational or valid, reset triggers */ + TPDO->sendRequest = true; +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + TPDO->inhibitTimer = TPDO->eventTimer = 0; +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + TPDO->syncCounter = 255; +#endif } } +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE */ #endif /* (CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE) */ diff --git a/301/CO_PDO.h b/301/CO_PDO.h index d3f551f9..5863db9f 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -4,7 +4,7 @@ * @file CO_PDO.h * @ingroup CO_PDO * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2021 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -26,18 +26,19 @@ #ifndef CO_PDO_H #define CO_PDO_H -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" +#include "301/CO_ODinterface.h" #include "301/CO_Emergency.h" -#include "301/CO_NMT_Heartbeat.h" #include "301/CO_SYNC.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_PDO #define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ CO_CONFIG_TPDO_ENABLE | \ + CO_CONFIG_RPDO_TIMERS_ENABLE | \ + CO_CONFIG_TPDO_TIMERS_ENABLE | \ CO_CONFIG_PDO_SYNC_ENABLE | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_PDO_OD_IO_ACCESS | \ + CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | \ CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif @@ -60,249 +61,247 @@ extern "C" { * * TPDO with specific identifier is transmitted by one device and recieved by * zero or more devices as RPDO. PDO communication parameters(COB-ID, - * transmission type, etc.) are in Object Dictionary at index 0x1400+ and - * 0x1800+. PDO mapping parameters (size and contents of the PDO) are in Object - * Dictionary at index 0x1600+ and 0x1A00+. + * transmission type, etc.) are in the Object Dictionary at index 0x1400+ and + * 0x1800+. PDO mapping parameters (size and contents of the PDO) are in the + * Object Dictionary at index 0x1600+ and 0x1A00+. * - * Features of the PDO as implemented here, in CANopenNode: + * Features of the PDO as implemented in CANopenNode: * - Dynamic PDO mapping. * - Map granularity of one byte. - * - After RPDO is received from CAN bus, its data are copied to buffer. - * Function CO_RPDO_process() (called by application) copies data to - * mapped objects in Object Dictionary. Synchronous RPDOs are processed AFTER - * reception of the next SYNC message. - * - Function CO_TPDO_process() (called by application) sends TPDO if - * necessary. There are possible different transmission types, including - * automatic detection of Change of State of specific variable. + * - Data from OD variables are accessed via @ref OD_IO_t read()/write() + * functions, which gives a great usefulness to the application. + * - For systems with very low memory and processing capabilities there is a + * simplified @ref CO_CONFIG_PDO option, where instead of read()/write() + * access, PDO data are copied directly to/from memory locations of + * OD variables. + * - After RPDO is received from CAN bus, its data are copied to internal + * buffer (inside fast CAN receive interrupt). Function CO_RPDO_process() + * (called by application) copies data to the mapped objects in the Object + * Dictionary. Synchronous RPDOs are processed AFTER reception of the next + * SYNC message. + * - Function CO_TPDO_process() (called by application) sends TPDO when + * necessary. There are different transmission types possible, controlled by: + * SYNC message, event timer, @ref CO_TPDOsendRequest() by application or + * @ref OD_requestTPDO(), where application can request TPDO for OD + * variable mapped to any of them. In later case application may, for + * example, monitor change of state of the OD variable and indicate TPDO + * request on it. + * + * @anchor CO_PDO_CAN_ID + * ### CAN identifiers for PDO + + * Each PDO can be configured with any valid 11-bit CAN identifier. Lower + * numbers have higher priorities on CAN bus. As a general rule, each CAN + * message is identified with own CAN-ID, which must be unique and produced by + * single source. The same is with PDO objects: Any TPDO produced on the CANopen + * network must have unique CAN-ID and there can be zero to many RPDOs (from + * different devices) configured to match the CAN-ID of the TPDO of interest. + * + * CANopen standard provides pre-defined connection sets for four RPDOs and four + * TPDOs on each device with specific 7-bit Node-ID. These are default values + * and are usable in configuration, where CANopen network contains a master + * device, which directly communicates with many slaves. In de-centralized + * systems, where devices operate without a master, it makes sense to configure + * CAN-IDs of the RPDOs to the non-default values. + * + * Default CAN identifiers for first four TPDOs on device with specific CANopen + * Node-Id are: 0x180+NodeId, 0x280+NodeId, 0x380+NodeId and 0x480+NodeId. + * + * Default CAN identifiers for first four RPDOs on device with specific CANopen + * Node-Id are: 0x200+NodeId, 0x300+NodeId, 0x400+NodeId and 0x500+NodeId. + * + * CANopenNode handles default (pre-defined) CAN-IDs. If it is detected, that + * PDO is configured with default CAN-ID (when writing to OD variable PDO + * communication parameter, COB-ID), then COB-ID is stored without Node-Id to + * the Object Dictionary. If Node-ID is changed, then COB-ID will always contain + * correct default CAN-ID (default CAN-ID + Node-ID). If PDO is configured with + * non-default CAN-ID, then it will be stored to the Object Dictionary as is. + * + * If configuration CO_CONFIG_FLAG_OD_DYNAMIC is enabled in @ref CO_CONFIG_PDO, + * then PDOs can be configured dynamically, also in NMT operational state. + * Otherwise PDOs are configured only in reset communication section and also + * default CAN-IDs are always stored to OD as is, no default node-id is handled. + * + * Configure PDO by writing to the OD variables in the following procedure: + * - Disable the PDO by setting bit-31 to 1 in PDO communication parameter, + * COB-ID + * - Node-Id can be configured only when PDO is disabled. + * - Disable mapping by setting PDO mapping parameter, sub index 0 to 0 + * - Configure mapping + * - Enable mapping by setting PDO mapping param, sub 0 to number of mapped + * objects + * - Enable the PDO by setting bit-31 to 0 in PDO communication parameter, + * COB-ID */ +/** Maximum size of PDO message, 8 for standard CAN */ +#ifndef CO_PDO_MAX_SIZE +#define CO_PDO_MAX_SIZE 8 +#endif -/** - * RPDO communication parameter. The same as record from Object dictionary (index 0x1400+). - */ -typedef struct{ - uint8_t maxSubIndex; /**< Equal to 2 */ - /** Communication object identifier for message received. Meaning of the specific bits: - - Bit 0-10: COB-ID for PDO, to change it bit 31 must be set. - - Bit 11-29: set to 0 for 11 bit COB-ID. - - Bit 30: If true, rtr are NOT allowed for PDO. - - Bit 31: If true, node does NOT use the PDO. */ - uint32_t COB_IDUsedByRPDO; - /** Transmission type. Values: - - 0-240: Reciving is synchronous, process after next reception of the SYNC object. - - 241-253: Not used. - - 254: Manufacturer specific. - - 255: Asynchronous. */ - uint8_t transmissionType; -}CO_RPDOCommPar_t; +/** Maximum number of entries, which can be mapped to PDO, 8 for standard CAN, + * may be less to preserve RAM usage */ +#ifndef CO_PDO_MAX_MAPPED_ENTRIES +#define CO_PDO_MAX_MAPPED_ENTRIES 8 +#endif +#ifndef CO_PDO_OWN_TYPES +/** Variable of type CO_PDO_size_t contains data length in bytes of PDO */ +typedef uint8_t CO_PDO_size_t; +#endif /** - * RPDO mapping parameter. The same as record from Object dictionary (index 0x1600+). + * PDO transmission Types */ -typedef struct{ - /** Actual number of mapped objects from 0 to 8. To change mapped object, - this value must be 0. */ - uint8_t numberOfMappedObjects; - /** Location and size of the mapped object. Bit meanings `0xIIIISSLL`: - - Bit 0-7: Data Length in bits. - - Bit 8-15: Subindex from object distionary. - - Bit 16-31: Index from object distionary. */ - uint32_t mappedObject1; - uint32_t mappedObject2; /**< Same */ - uint32_t mappedObject3; /**< Same */ - uint32_t mappedObject4; /**< Same */ - uint32_t mappedObject5; /**< Same */ - uint32_t mappedObject6; /**< Same */ - uint32_t mappedObject7; /**< Same */ - uint32_t mappedObject8; /**< Same */ -}CO_RPDOMapPar_t; - +typedef enum { + CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC = 0, /**< synchronous (acyclic) */ + CO_PDO_TRANSM_TYPE_SYNC_1 = 1, /**< synchronous (cyclic every sync) */ + CO_PDO_TRANSM_TYPE_SYNC_240 = 0xF0, /**< synchronous (cyclic every 240-th + sync) */ + CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO = 0xFE, /**< event-driven, lower value + (manufacturer specific), */ + CO_PDO_TRANSM_TYPE_SYNC_EVENT_HI = 0xFF /**< event-driven, higher value + (device profile and application profile specific) */ +} CO_PDO_transmissionTypes_t; /** - * TPDO communication parameter. The same as record from Object dictionary (index 0x1800+). + * PDO object, common properties */ -typedef struct{ - uint8_t maxSubIndex; /**< Equal to 6 */ - /** Communication object identifier for transmitting message. Meaning of the specific bits: - - Bit 0-10: COB-ID for PDO, to change it bit 31 must be set. - - Bit 11-29: set to 0 for 11 bit COB-ID. - - Bit 30: If true, rtr are NOT allowed for PDO. - - Bit 31: If true, node does NOT use the PDO. */ - uint32_t COB_IDUsedByTPDO; - /** Transmission type. Values: - - 0: Transmiting is synchronous, specification in device profile. - - 1-240: Transmiting is synchronous after every N-th SYNC object. - - 241-251: Not used. - - 252-253: Transmited only on reception of Remote Transmission Request. - - 254: Manufacturer specific. - - 255: Asinchronous, specification in device profile. */ - uint8_t transmissionType; - /** Minimum time between transmissions of the PDO in 100micro seconds. - Zero disables functionality. */ - uint16_t inhibitTime; - /** Not used */ - uint8_t compatibilityEntry; - /** Time between periodic transmissions of the PDO in milliseconds. - Zero disables functionality. */ - uint16_t eventTimer; - /** Used with numbered SYNC messages. Values: - - 0: Counter of the SYNC message shall not be processed. - - 1-240: The SYNC message with the counter value equal to this value - shall be regarded as the first received SYNC message. */ - uint8_t SYNCStartValue; -}CO_TPDOCommPar_t; +typedef struct { + /** From CO_xPDO_init() */ + CO_EM_t *em; + /** From CO_xPDO_init() */ + CO_CANmodule_t *CANdev; + /** True, if PDO is enabled and valid */ + bool_t valid; + /** Data length of the received PDO message. Calculated from mapping */ + CO_PDO_size_t dataLength; + /** Number of mapped objects in PDO */ + uint8_t mappedObjectsCount; +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) || defined CO_DOXYGEN + /** Object dictionary interface for all mapped entries. OD_IO.dataOffset has + * special usage with PDO. It stores information about mappedLength of + * the variable. mappedLength can be less or equal to the OD_IO.dataLength. + * mappedLength greater than OD_IO.dataLength indicates erroneous mapping. + * OD_IO.dataOffset is set to 0 before read/write function call and after + * the call OD_IO.dataOffset is set back to mappedLength. */ + OD_IO_t OD_IO[CO_PDO_MAX_MAPPED_ENTRIES]; + #if OD_FLAGS_PDO_SIZE > 0 + /** Pointer to byte, which contains PDO flag bit from @ref OD_extension_t */ + uint8_t *flagPDObyte[CO_PDO_MAX_MAPPED_ENTRIES]; + /** Bitmask for the flagPDObyte */ + uint8_t flagPDObitmask[CO_PDO_MAX_MAPPED_ENTRIES]; + #endif +#else + /* Pointers to data objects inside OD, where PDO will be copied */ + uint8_t *mapPointer[CO_PDO_MAX_SIZE]; + #if OD_FLAGS_PDO_SIZE > 0 + uint8_t *flagPDObyte[CO_PDO_MAX_SIZE]; + uint8_t flagPDObitmask[CO_PDO_MAX_SIZE]; + #endif +#endif +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN + /** True for RPDO, false for TPDO */ + bool_t isRPDO; + /** From CO_xPDO_init() */ + OD_t *OD; + /** From CO_xPDO_init() */ + uint16_t CANdevIdx; + /** From CO_xPDO_init() */ + uint16_t preDefinedCanId; + /** Currently configured CAN identifier */ + uint16_t configuredCanId; + /** Extension for OD object */ + OD_extension_t OD_communicationParam_ext; + /** Extension for OD object */ + OD_extension_t OD_mappingParam_extension; +#endif +} CO_PDO_common_t; +/******************************************************************************* + * R P D O + ******************************************************************************/ +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) || defined CO_DOXYGEN /** - * TPDO mapping parameter. The same as record from Object dictionary (index 0x1A00+). + * Number of buffers for received CAN message for RPDO */ -typedef struct{ - /** Actual number of mapped objects from 0 to 8. To change mapped object, - this value must be 0. */ - uint8_t numberOfMappedObjects; - /** Location and size of the mapped object. Bit meanings `0xIIIISSLL`: - - Bit 0-7: Data Length in bits. - - Bit 8-15: Subindex from object distionary. - - Bit 16-31: Index from object distionary. */ - uint32_t mappedObject1; - uint32_t mappedObject2; /**< Same */ - uint32_t mappedObject3; /**< Same */ - uint32_t mappedObject4; /**< Same */ - uint32_t mappedObject5; /**< Same */ - uint32_t mappedObject6; /**< Same */ - uint32_t mappedObject7; /**< Same */ - uint32_t mappedObject8; /**< Same */ -}CO_TPDOMapPar_t; +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN +#define CO_RPDO_CAN_BUFFERS_COUNT 2 +#else +#define CO_RPDO_CAN_BUFFERS_COUNT 1 +#endif /** * RPDO object. */ -typedef struct{ - CO_EM_t *em; /**< From CO_RPDO_init() */ - CO_SDO_t *SDO; /**< From CO_RPDO_init() */ - const CO_RPDOCommPar_t *RPDOCommPar;/**< From CO_RPDO_init() */ - const CO_RPDOMapPar_t *RPDOMapPar; /**< From CO_RPDO_init() */ - CO_NMT_internalState_t *operatingState; /**< From CO_RPDO_init() */ - uint8_t nodeId; /**< From CO_RPDO_init() */ - uint16_t defaultCOB_ID; /**< From CO_RPDO_init() */ - uint8_t restrictionFlags;/**< From CO_RPDO_init() */ - /** True, if PDO is enabled and valid */ - bool_t valid; - /** Data length of the received PDO message. Calculated from mapping */ - uint8_t dataLength; - /** Pointers to 8 data objects, where PDO will be copied */ - uint8_t *mapPointer[8]; -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN - CO_SYNC_t *SYNC; /**< From CO_RPDO_init() */ - /** True, if PDO synchronous (transmissionType <= 240) */ - bool_t synchronous; +typedef struct { + /** PDO common properties, must be first element in this object */ + CO_PDO_common_t PDO_common; /** Variable indicates, if new PDO message received from CAN bus. */ - volatile void *CANrxNew[2]; - /** 8 data bytes of the received message. */ - uint8_t CANrxData[2][8]; -#else - volatile void *CANrxNew[1]; - uint8_t CANrxData[1][8]; + volatile void *CANrxNew[CO_RPDO_CAN_BUFFERS_COUNT]; + /** CO_PDO_MAX_SIZE data bytes of the received message. */ + uint8_t CANrxData[CO_RPDO_CAN_BUFFERS_COUNT][CO_PDO_MAX_SIZE]; + /** Indication of RPDO length errors, use with CO_PDO_receiveErrors_t */ + uint8_t receiveError; +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN + /** From CO_RPDO_init() */ + CO_SYNC_t *SYNC; + /** True if transmissionType <= 240 */ + bool_t synchronous; +#endif +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) || defined CO_DOXYGEN + /** Maximum timeout time between received PDOs in microseconds. Configurable + * by OD variable RPDO communication parameter, event-timer. */ + uint32_t timeoutTime_us; + /** Timeout timer variable in microseconds */ + uint32_t timeoutTimer; #endif #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_RPDO_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void *object); /** From CO_RPDO_initCallbackPre() or NULL */ - void *functSignalObjectPre; -#endif - CO_CANmodule_t *CANdevRx; /**< From CO_RPDO_init() */ - uint16_t CANdevRxIdx; /**< From CO_RPDO_init() */ -}CO_RPDO_t; - - -/** - * TPDO object. - */ -typedef struct{ - CO_EM_t *em; /**< From CO_TPDO_init() */ - CO_SDO_t *SDO; /**< From CO_TPDO_init() */ - const CO_TPDOCommPar_t *TPDOCommPar;/**< From CO_TPDO_init() */ - const CO_TPDOMapPar_t *TPDOMapPar; /**< From CO_TPDO_init() */ - CO_NMT_internalState_t *operatingState; /**< From CO_TPDO_init() */ - uint8_t nodeId; /**< From CO_TPDO_init() */ - uint16_t defaultCOB_ID; /**< From CO_TPDO_init() */ - uint8_t restrictionFlags;/**< From CO_TPDO_init() */ - bool_t valid; /**< True, if PDO is enabled and valid */ - /** Data length of the transmitting PDO message. Calculated from mapping */ - uint8_t dataLength; - /** If application set this flag, PDO will be later sent by - function CO_TPDO_process(). Depends on transmission type. */ - uint8_t sendRequest; - /** Pointers to 8 data objects, where PDO will be copied */ - uint8_t *mapPointer[8]; - /** Inhibit timer used for inhibit PDO sending translated to microseconds */ - uint32_t inhibitTimer; - /** Event timer used for PDO sending translated to microseconds */ - uint32_t eventTimer; - /** Each flag bit is connected with one mapPointer. If flag bit - is true, CO_TPDO_process() functiuon will send PDO if - Change of State is detected on value pointed by that mapPointer */ - uint8_t sendIfCOSFlags; -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN - /** SYNC counter used for PDO sending */ - uint8_t syncCounter; - CO_SYNC_t *SYNC; /**< From CO_TPDO_init() */ + void *functSignalObjectPre; #endif - CO_CANmodule_t *CANdevTx; /**< From CO_TPDO_init() */ - CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer inside CANdev */ - uint16_t CANdevTxIdx; /**< From CO_TPDO_init() */ -}CO_TPDO_t; +} CO_RPDO_t; /** * Initialize RPDO object. * - * Function must be called in the communication reset section. + * Function must be called in the end of the communication reset section, after + * all application initialization. Otherwise mapping to application OD variables + * will not be correct. * * @param RPDO This object will be initialized. + * @param OD Object Dictionary. * @param em Emergency object. - * @param SDO SDO server object. - * @param SYNC void pointer to SYNC object or NULL. - * @param operatingState Pointer to variable indicating CANopen device NMT internal state. - * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. - * @param defaultCOB_ID Default COB ID for this PDO (without NodeId). - * See #CO_Default_CAN_ID_t - * @param restrictionFlags Flag bits indicates, how PDO communication - * and mapping parameters are handled: - * - Bit1: If true, communication parameters are writeable only in pre-operational NMT state. - * - Bit2: If true, mapping parameters are writeable only in pre-operational NMT state. - * - Bit3: If true, communication parameters are read-only. - * - Bit4: If true, mapping parameters are read-only. - * @param RPDOCommPar Pointer to _RPDO communication parameter_ record from Object - * dictionary (index 0x1400+). - * @param RPDOMapPar Pointer to _RPDO mapping parameter_ record from Object - * dictionary (index 0x1600+). - * @param idx_RPDOCommPar Index in Object Dictionary. - * @param idx_RPDOMapPar Index in Object Dictionary. + * @param SYNC SYNC object, may be NULL. + * @param preDefinedCanId CAN identifier from pre-defined connection set, + * including node-id for first four PDOs, or 0 otherwise, see @ref CO_PDO_CAN_ID + * @param OD_14xx_RPDOCommPar OD entry for 0x1400+ - "RPDO communication + * parameter", entry is required. + * @param OD_16xx_RPDOMapPar OD entry for 0x1600+ - "RPDO mapping parameter", + * entry is required. * @param CANdevRx CAN device for PDO reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. + * @param [out] errInfo Additional information in case of error, may be NULL. * - * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_RPDO_init( - CO_RPDO_t *RPDO, - CO_EM_t *em, - CO_SDO_t *SDO, +CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, + OD_t *OD, + CO_EM_t *em, #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN - CO_SYNC_t *SYNC, + CO_SYNC_t *SYNC, #endif - CO_NMT_internalState_t *operatingState, - uint8_t nodeId, - uint16_t defaultCOB_ID, - uint8_t restrictionFlags, - const CO_RPDOCommPar_t *RPDOCommPar, - const CO_RPDOMapPar_t *RPDOMapPar, - uint16_t idx_RPDOCommPar, - uint16_t idx_RPDOMapPar, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx); + uint16_t preDefinedCanId, + OD_entry_t *OD_14xx_RPDOCommPar, + OD_entry_t *OD_16xx_RPDOMapPar, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + uint32_t *errInfo); #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN @@ -314,126 +313,150 @@ CO_ReturnError_t CO_RPDO_init( * Callback is called after RPDO message is received from the CAN bus. * * @param RPDO This object. - * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignalPre(). * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_RPDO_initCallbackPre( - CO_RPDO_t *RPDO, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, + void *object, + void (*pFunctSignalPre)(void *object)); #endif /** - * Initialize TPDO object. - * - * Function must be called in the communication reset section. + * Process received PDO messages. * - * @param TPDO This object will be initialized. - * @param em Emergency object. - * @param SDO SDO object. - * @param SYNC void pointer to SYNC object or NULL. - * @param operatingState Pointer to variable indicating CANopen device NMT internal state. - * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. - * @param defaultCOB_ID Default COB ID for this PDO (without NodeId). - * See #CO_Default_CAN_ID_t - * @param restrictionFlags Flag bits indicates, how PDO communication - * and mapping parameters are handled: - * - Bit1: If true, communication parameters are writeable only in pre-operational NMT state. - * - Bit2: If true, mapping parameters are writeable only in pre-operational NMT state. - * - Bit3: If true, communication parameters are read-only. - * - Bit4: If true, mapping parameters are read-only. - * @param TPDOCommPar Pointer to _TPDO communication parameter_ record from Object - * dictionary (index 0x1400+). - * @param TPDOMapPar Pointer to _TPDO mapping parameter_ record from Object - * dictionary (index 0x1600+). - * @param idx_TPDOCommPar Index in Object Dictionary. - * @param idx_TPDOMapPar Index in Object Dictionary. - * @param CANdevTx CAN device used for PDO transmission. - * @param CANdevTxIdx Index of transmit buffer in the above CAN device. + * Function must be called cyclically in any NMT state. It copies data from RPDO + * to Object Dictionary variables if: new PDO receives and PDO is valid and NMT + * operating state is operational. Synchronous RPDOs are processed after next + * SYNC message. * - * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @param RPDO This object. + * @param timeDifference_us Time difference from previous function call. + * @param [out] timerNext_us info to OS - see CO_process(). + * @param NMTisOperational True if this node is in NMT_OPERATIONAL state. + * @param syncWas True, if CANopen SYNC message was just received or + * transmitted. */ -CO_ReturnError_t CO_TPDO_init( - CO_TPDO_t *TPDO, - CO_EM_t *em, - CO_SDO_t *SDO, -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN - CO_SYNC_t *SYNC, +void CO_RPDO_process(CO_RPDO_t *RPDO, +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) || defined CO_DOXYGEN + uint32_t timeDifference_us, + uint32_t *timerNext_us, #endif - CO_NMT_internalState_t *operatingState, - uint8_t nodeId, - uint16_t defaultCOB_ID, - uint8_t restrictionFlags, - const CO_TPDOCommPar_t *TPDOCommPar, - const CO_TPDOMapPar_t *TPDOMapPar, - uint16_t idx_TPDOCommPar, - uint16_t idx_TPDOMapPar, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx); + bool_t NMTisOperational, + bool_t syncWas); +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE */ +/******************************************************************************* + * T P D O + ******************************************************************************/ +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) || defined CO_DOXYGEN /** - * Verify Change of State of the PDO. - * - * Function verifies if variable mapped to TPDO has changed its value. Verified - * are only variables, which has set attribute _CO_ODA_TPDO_DETECT_COS_ in - * #CO_SDO_OD_attributes_t. - * - * Function may be called by application just before CO_TPDO_process() function, - * for example: `TPDOx->sendRequest = CO_TPDOisCOS(TPDOx); CO_TPDO_process(TPDOx, ....` - * - * @param TPDO TPDO object. - * - * @return True if COS was detected. + * TPDO object. */ -uint8_t CO_TPDOisCOS(CO_TPDO_t *TPDO); +typedef struct { + /** PDO common properties, must be first element in this object */ + CO_PDO_common_t PDO_common; + /** CAN transmit buffer inside CANdev */ + CO_CANtx_t *CANtxBuff; + /** Copy of the variable from object dictionary */ + uint8_t transmissionType; + /** If this flag is set and TPDO is event driven (transmission type is 0, + * 254 or 255), then PDO will be sent by CO_TPDO_process(). */ + bool_t sendRequest; +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN + /** From CO_TPDO_init() */ + CO_SYNC_t *SYNC; + /** Copy of the variable from object dictionary */ + uint8_t syncStartValue; + /** SYNC counter used for PDO sending */ + uint8_t syncCounter; +#endif +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || defined CO_DOXYGEN + /** Inhibit time from object dictionary translated to microseconds */ + uint32_t inhibitTime_us; + /** Event time from object dictionary translated to microseconds */ + uint32_t eventTime_us; + /** Inhibit timer variable in microseconds */ + uint32_t inhibitTimer; + /** Event timer variable in microseconds */ + uint32_t eventTimer; +#endif +} CO_TPDO_t; /** - * Send TPDO message. - * - * Function prepares TPDO data from Object Dictionary variables. It should not - * be called by application, it is called from CO_TPDO_process(). + * Initialize TPDO object. * + * Function must be called in the end of the communication reset section, after + * all application initialization. Otherwise mapping to application OD variables + * will not be correct. * - * @param TPDO TPDO object. + * @param TPDO This object will be initialized. + * @param OD Object Dictionary. + * @param em Emergency object. + * @param SYNC SYNC object, may be NULL. + * @param preDefinedCanId CAN identifier from pre-defined connection set, + * including node-id for first four PDOs, or 0 otherwise, see @ref CO_PDO_CAN_ID + * @param OD_18xx_TPDOCommPar OD entry for 0x1800+ - "TPDO communication + * parameter", entry is required. + * @param OD_1Axx_TPDOMapPar OD entry for 0x1A00+ - "TPDO mapping parameter", + * entry is required. + * @param CANdevTx CAN device used for PDO transmission. + * @param CANdevTxIdx Index of transmit buffer in the above CAN device. + * @param [out] errInfo Additional information in case of error, may be NULL. * - * @return Same as CO_CANsend(). + * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO); +CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, + OD_t *OD, + CO_EM_t *em, +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN + CO_SYNC_t *SYNC, +#endif + uint16_t preDefinedCanId, + OD_entry_t *OD_18xx_TPDOCommPar, + OD_entry_t *OD_1Axx_TPDOMapPar, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, + uint32_t *errInfo); /** - * Process received PDO messages. + * Request transmission of TPDO message. * - * Function must be called cyclically in any NMT state. It copies data from RPDO - * to Object Dictionary variables if: new PDO receives and PDO is valid and NMT - * operating state is operational. It does not verify _transmission type_. + * If TPDO transmission type is 0, 254 or 255, then TPDO will be sent by + * @ref CO_TPDO_process() after inhibit timer expires. See also + * @ref OD_requestTPDO() and @ref OD_TPDOtransmitted(). * - * @param RPDO This object. - * @param syncWas True, if CANopen SYNC message was just received or transmitted. + * @param TPDO TPDO object. */ -void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas); +static inline void CO_TPDOsendRequest(CO_TPDO_t *TPDO) { + if (TPDO != NULL) TPDO->sendRequest = true; +} /** * Process transmitting PDO messages. * * Function must be called cyclically in any NMT state. It prepares and sends - * TPDO if necessary. If Change of State needs to be detected, function - * CO_TPDOisCOS() must be called before. + * TPDO if necessary. * * @param TPDO This object. - * @param syncWas True, if CANopen SYNC message was just received or transmitted. - * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param timeDifference_us Time difference from previous function call. * @param [out] timerNext_us info to OS - see CO_process(). + * @param NMTisOperational True if this node is in NMT_OPERATIONAL state. + * @param syncWas True, if CANopen SYNC message was just received or + * transmitted. */ -void CO_TPDO_process( - CO_TPDO_t *TPDO, - bool_t syncWas, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +void CO_TPDO_process(CO_TPDO_t *TPDO, +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || defined CO_DOXYGEN + uint32_t timeDifference_us, + uint32_t *timerNext_us, +#endif + bool_t NMTisOperational, + bool_t syncWas); +#endif /* (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE */ /** @} */ /* CO_PDO */ diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 971dc9c8..61990227 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -360,7 +360,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, { (void)timerNext_us; /* may be unused */ - CO_SYNC_status_t ret = CO_SYNC_NONE; + CO_SYNC_status_t syncStatus = CO_SYNC_NONE; if (NMTisPreOrOperational) { /* update sync timer, no overflow */ @@ -370,7 +370,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, /* was SYNC just received */ if (CO_FLAG_READ(SYNC->CANrxNew)) { SYNC->timer = 0; - ret = CO_SYNC_RX_TX; + syncStatus = CO_SYNC_RX_TX; CO_FLAG_CLEAR(SYNC->CANrxNew); } @@ -381,7 +381,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER if (SYNC->isProducer) { if (SYNC->timer >= OD_1006_period) { - ret = CO_SYNC_RX_TX; + syncStatus = CO_SYNC_RX_TX; CO_SYNCsend(SYNC); } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT @@ -398,7 +398,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ /* Verify timeout of SYNC */ - { + if (SYNC->timeoutError == 1) { /* periodTimeout is 1,5 * OD_1006_period, no overflow */ uint32_t periodTimeout = OD_1006_period + (OD_1006_period >> 1); if (periodTimeout < OD_1006_period) periodTimeout = 0xFFFFFFFF; @@ -406,7 +406,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, if (SYNC->timer > periodTimeout) { CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); - SYNC->timeoutError = true; + SYNC->timeoutError = 2; } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT else if (timerNext_us != NULL) { @@ -420,12 +420,11 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } /* if (OD_1006_period > 0) */ /* Synchronous PDOs are allowed only inside time window */ - uint32_t OD_1007_window = SYNC->OD_1007_window != NULL - ? *SYNC->OD_1007_window : 0; - - if (OD_1007_window > 0 && SYNC->timer > OD_1007_window) { + if (SYNC->OD_1007_window != NULL && *SYNC->OD_1007_window > 0 + && SYNC->timer > *SYNC->OD_1007_window + ) { if (!SYNC->syncIsOutsideWindow) { - ret = CO_SYNC_PASSED_WINDOW; + syncStatus = CO_SYNC_PASSED_WINDOW; } SYNC->syncIsOutsideWindow = true; } @@ -447,12 +446,14 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, SYNC->timer = 0; } - if (SYNC->timeoutError && SYNC->timer == 0) { - CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, 0); - SYNC->timeoutError = false; + if (syncStatus == CO_SYNC_RX_TX) { + if (SYNC->timeoutError == 2) { + CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, 0); + } + SYNC->timeoutError = 1; } - return ret; + return syncStatus; } #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE */ diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 488fbc63..8843bd9a 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -35,7 +35,7 @@ #ifndef CO_CONFIG_SYNC #define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ CO_CONFIG_SYNC_PRODUCER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ + CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | \ CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif @@ -88,8 +88,9 @@ typedef struct { uint8_t receiveError; /** Variable toggles, if new SYNC message received from CAN bus */ bool_t CANrxToggle; - /** True in sync timeout error state */ - bool_t timeoutError; + /** Sync timeout monitoring: 0 = not started; 1 = started; 2 = sync timeout + * error state */ + uint8_t timeoutError; /** Value from _Synchronous counter overflow value_ variable from Object dictionary (index 0x1019) */ uint8_t counterOverflowValue; diff --git a/301/CO_config.h b/301/CO_config.h index 954cda47..0b905f29 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -99,11 +99,18 @@ extern "C" { */ #define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000 -/** This flag may be set globally to @ref CO_CONFIG_FLAG_CALLBACK_PRE */ +/** This flag may be set globally for mainline objects to + * @ref CO_CONFIG_FLAG_CALLBACK_PRE */ #ifdef CO_DOXYGEN #define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0) #endif +/** This flag may be set globally for Real-Time objects (SYNC, PDO) to + * @ref CO_CONFIG_FLAG_CALLBACK_PRE */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE (0) +#endif + /** This flag may be set globally to @ref CO_CONFIG_FLAG_TIMERNEXT */ #ifdef CO_DOXYGEN #define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT (0) @@ -450,7 +457,7 @@ extern "C" { * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of SYNC. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_SYNC_ENABLE 0x01 #define CO_CONFIG_SYNC_PRODUCER 0x02 @@ -461,11 +468,16 @@ extern "C" { * Possible flags, can be ORed: * - CO_CONFIG_RPDO_ENABLE - Enable receive PDO objects. * - CO_CONFIG_TPDO_ENABLE - Enable transmit PDO objects. + * - CO_CONFIG_RPDO_TIMERS_ENABLE - Enable RPDO timers: RPDO timeout monitoring + * with event timer. + * - CO_CONFIG_TPDO_TIMERS_ENABLE - Enable TPDO timers: TPDO inhibit and event + * timers. * - CO_CONFIG_PDO_SYNC_ENABLE - Enable SYNC in PDO objects. - * - CO_CONFIG_RPDO_CALLS_EXTENSION - Enable calling configured extension - * callbacks when received RPDO CAN message modifies OD entries. - * - CO_CONFIG_TPDO_CALLS_EXTENSION - Enable calling configured extension - * callbacks before TPDO CAN message is sent. + * - CO_CONFIG_PDO_OD_IO_ACCESS - For OD variables mapped to PDO use read/write + * function access with @ref OD_IO_t. This option enables much more + * flexibility for application program, but consumes some additional memory + * and processor resources. If this option is not enabled, then data from OD + * variables are fetched directly from memory allocated by Object dictionary. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received RPDO CAN message. * Callback is configured by CO_RPDO_initCallbackPre(). @@ -474,13 +486,14 @@ extern "C" { * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of PDO. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_RPDO_TIMERS_ENABLE | CO_CONFIG_TPDO_TIMERS_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_PDO_OD_IO_ACCESS | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_RPDO_ENABLE 0x01 #define CO_CONFIG_TPDO_ENABLE 0x02 -#define CO_CONFIG_PDO_SYNC_ENABLE 0x04 -#define CO_CONFIG_RPDO_CALLS_EXTENSION 0x08 -#define CO_CONFIG_TPDO_CALLS_EXTENSION 0x10 +#define CO_CONFIG_RPDO_TIMERS_ENABLE 0x04 +#define CO_CONFIG_TPDO_TIMERS_ENABLE 0x08 +#define CO_CONFIG_PDO_SYNC_ENABLE 0x10 +#define CO_CONFIG_PDO_OD_IO_ACCESS 0x20 /** @} */ /* CO_STACK_CONFIG_SYNC_PDO */ diff --git a/301/CO_driver.h b/301/CO_driver.h index 066f1fd6..7929f185 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -40,6 +40,9 @@ extern "C" { #ifndef CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE #define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0) #endif +#ifndef CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE + #define CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE (0) +#endif #ifndef CO_CONFIG_GLOBAL_FLAG_TIMERNEXT #define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT (0) #endif diff --git a/CANopen.c b/CANopen.c index 769be237..1a19527a 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1090,58 +1090,6 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE - if (CO_GET_CNT(RPDO) > 0) { - OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); - OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); - for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { - err = CO_RPDO_init(co->RPDO[i], - em, - co->SDO[0], - #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - co->SYNC, - #endif - &co->NMT->operatingState, - nodeId, - ((i < 4) ? (CO_CAN_ID_RPDO_1 + i * 0x100) : 0), - 0, - RPDOcomm++, - RPDOmap++, - OD_H1400_RXPDO_1_PARAM + i, - OD_H1600_RXPDO_1_MAPPING + i, - co->CANmodule, - CO_GET_CO(RX_IDX_RPDO) + i); - if (err) return err; - } - } -#endif - -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE - if (CO_GET_CNT(TPDO) > 0) { - OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); - OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); - for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { - err = CO_TPDO_init(co->TPDO[i], - em, - co->SDO[0], - #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - co->SYNC, - #endif - &co->NMT->operatingState, - nodeId, - ((i < 4) ? (CO_CAN_ID_TPDO_1 + i * 0x100) : 0), - 0, - TPDOcomm++, - TPDOmap++, - OD_H1800_TXPDO_1_PARAM + i, - OD_H1A00_TXPDO_1_MAPPING + i, - co->CANmodule, - CO_GET_CO(TX_IDX_TPDO) + i); - if (err) return err; - } - } -#endif - #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE if (CO_GET_CNT(GFC) == 1) { err = CO_GFC_init(co->GFC, @@ -1258,6 +1206,74 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } +/******************************************************************************/ +CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, + CO_EM_t *em, + OD_t *od, + uint8_t nodeId, + uint32_t *errInfo) +{ + if (co == NULL || nodeId < 1 || nodeId > 127 || co->nodeIdUnconfigured) { + return (co != NULL || co->nodeIdUnconfigured) + ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; + } + +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + if (CO_GET_CNT(RPDO) > 0) { + OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); + OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); + for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { + CO_ReturnError_t err; + uint16_t preDefinedCanId = i < 4 + ? (CO_CAN_ID_RPDO_1 + i * 0x100) + nodeId + : 0; + err = CO_RPDO_init(&co->RPDO[i], + od, + em, + #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + co->SYNC, + #endif + preDefinedCanId, + RPDOcomm++, + RPDOmap++, + co->CANmodule, + CO_GET_CO(RX_IDX_RPDO) + i, + errInfo); + if (err) return err; + } + } +#endif + +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + if (CO_GET_CNT(TPDO) > 0) { + OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); + OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); + for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { + CO_ReturnError_t err; + uint16_t preDefinedCanId = i < 4 + ? (CO_CAN_ID_TPDO_1 + i * 0x100) + nodeId + : 0; + err = CO_TPDO_init(&co->TPDO[i], + od, + em, + #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + co->SYNC, + #endif + preDefinedCanId, + TPDOcomm++, + TPDOmap++, + co->CANmodule, + CO_GET_CO(TX_IDX_TPDO) + i, + errInfo); + if (err) return err; + } + } +#endif + + return CO_ERROR_NO; +} + + /******************************************************************************/ CO_NMT_reset_cmd_t CO_process(CO_t *co, bool_t enableGateway, @@ -1408,13 +1424,27 @@ bool_t CO_process_SYNC(CO_t *co, /******************************************************************************/ #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE -void CO_process_RPDO(CO_t *co, bool_t syncWas) { +void CO_process_RPDO(CO_t *co, + bool_t syncWas, + uint32_t timeDifference_us, + uint32_t *timerNext_us) +{ + (void) timeDifference_us; (void) timerNext_us; if (co->nodeIdUnconfigured) { return; } + bool_t NMTisOperational = + CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; + for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { - CO_RPDO_process(&co->RPDO[i], syncWas); + CO_RPDO_process(&co->RPDO[i], +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + timeDifference_us, + timerNext_us, +#endif + NMTisOperational, + syncWas); } } #endif @@ -1427,12 +1457,22 @@ void CO_process_TPDO(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { + (void) timeDifference_us; (void) timerNext_us; if (co->nodeIdUnconfigured) { return; } + bool_t NMTisOperational = + CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; + for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { - CO_TPDO_process(&co->TPDO[i], syncWas, timeDifference_us, timerNext_us); + CO_TPDO_process(&co->TPDO[i], +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + timeDifference_us, + timerNext_us, +#endif + NMTisOperational, + syncWas); } } #endif diff --git a/CANopen.h b/CANopen.h index 23361b07..ecf3ba43 100644 --- a/CANopen.h +++ b/CANopen.h @@ -467,7 +467,7 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, /** - * Initialize CANopenNode. + * Initialize CANopenNode except PDO objects. * * Function must be called in the communication reset section. * @@ -511,6 +511,30 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, uint32_t *errInfo); +/** + * Initialize CANopenNode PDO objects. + * + * Function must be called in the end of communication reset section after all + * CANopen and application initialization, otherwise some OD variables wont be + * mapped into PDO correctly. + * + * @param co CANopen object. + * @param em Emergency object, which is used inside PDO objects for error + * reporting. + * @param od CANopen Object dictionary + * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). If + * unconfigured, then PDO will not be initialized nor processed. + * @param [out] errInfo Additional information in case of error, may be NULL. + * + * @return CO_ERROR_NO in case of success. + */ +CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, + CO_EM_t *em, + OD_t *od, + uint8_t nodeId, + uint32_t *errInfo); + + /** * Process CANopen objects. * @@ -571,8 +595,14 @@ bool_t CO_process_SYNC(CO_t *co, * @param co CANopen object. * @param syncWas True, if CANopen SYNC message was just received or * transmitted. + * @param timeDifference_us Time difference from previous function call in + * microseconds. + * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_process_RPDO(CO_t *co, bool_t syncWas); +void CO_process_RPDO(CO_t *co, + bool_t syncWas, + uint32_t timeDifference_us, + uint32_t *timerNext_us); #endif diff --git a/README.md b/README.md index bc4c1e37..7fbe12d5 100644 --- a/README.md +++ b/README.md @@ -17,36 +17,42 @@ Dictionary and are accessible from both: C code and from CANopen network. CANopenNode homepage is https://github.com/CANopenNode/CANopenNode -This is renewed version of CANopenNode with new Object Dictionary implementation. -For older versions see branches `v1.3-master` or `v2.0-master`. +This is version 4 of CANopenNode with new Object Dictionary implementation. +For older versions `git checkout` branches `v1.3-master` or `v2.0-master`. Characteristics --------------- ### CANopen - [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen/device-architecture/) - offers clear and flexible organisation of any variables. + offers clear and flexible organisation of any variables. Variables can be accessed + directly or via read/write functions. - [NMT](https://www.can-cia.org/can-knowledge/canopen/network-management/) slave to start, stop, reset device. Simple NMT master. - [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/) - producer/consumer error control. - - [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) linking - and dynamic mapping for fast exchange of process variables from Object Dictionary. - - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) expedited, - segmented and block transfer for service access to all Object Dictionary variables. - - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client. + producer/consumer error control for monitoring of CANopen devices. + - [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) for + broadcasting process data with high priority and no protocol overhead. + Variables from Object Dictionary can be dynamically mapped to the TPDO, which + is then transmitted according to communication rules and received as RPDO + by another device. + - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) server + enables expedited, segmented and block transfer access to all Object + Dictionary variables inside CANopen device. + - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client can + access any Object Dictionary variable on any CANopen device inside the network. - [Emergency](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) - producer/consumer. + message producer/consumer. - [Sync](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) - producer/consumer. + producer/consumer enables network synchronized transmission of the PDO objects, etc. - [Time-stamp](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) - protocol producer/consumer. - - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) master and - slave, LSS fastscan. + producer/consumer enables date and time synchronization in millisecond resolution. + - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) CANopen node-id + and bitrate setup, master and slave, LSS fastscan. - [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. - CANopen Safety, - EN 50325-5 "PDO like" communication in safety-relevant networks + EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks ### Other - [Suitable for 16-bit microcontrollers and above](#device-support) @@ -61,8 +67,8 @@ Characteristics Documentation, support and contributions ---------------------------------------- Documentation with [Getting started](doc/gettingStarted.md), -[LSS usage](doc/LSSusage.md) and [Trace usage](doc/traceUsage.md) is in `doc` -directory. +[Objec Dictionary](doc/objectDictionary.md) and [LSS usage](doc/LSSusage.md) +is in `doc` directory. Code is documented in header files. Running [doxygen](http://www.doxygen.nl/) in project base directory will produce complete html documentation. Just open CANopenNode/doc/html/index.html in the browser. Alternatively browse @@ -99,43 +105,24 @@ Flowchart of a typical CANopenNode implementation | | | -------------------- | -------------------- | | | - ----------------------- ----------------------- ----------------------- -| CAN receive thread | | Timer interval thread | | Mainline thread | -| | | | | | -| - Fast response. | | - Realtime thread with| | - Processing of time | -| - Detect CAN ID. | | constant interval, | | consuming tasks | -| - Partially process | | typically 1ms. | | in CANopen objects: | -| messages and copy | | - Network synchronized| | - SDO server, | -| data to target | | - Copy inputs (RPDOs, | | - Emergency, | -| CANopen objects. | | HW) to Object Dict. | | - Network state, | -| | | - May call application| | - Heartbeat. | -| | | for some processing.| | - LSS slave | -| | | - Copy variables from | | - May cyclically call | -| | | Object Dictionary to| | application code. | -| | | outputs (TPDOs, HW).| | | - ----------------------- ----------------------- ----------------------- - - ----------------------- - | SDO client (optional) | - | | - | - Can be called by | - | external application| - | - Can read or write | - | any variable from | - | Object Dictionary | - | from any node in the| - | CANopen network. | - ----------------------- - - ----------------------- - | LSS Master (optional) | - | | - | - Can be called by | - | external application| - | - Can do LSS requests | - | - Can request node | - | enumeration | - ----------------------- + ---------------------- ------------------------ ----------------------- +| CAN receive thread | | Timer interval thread | | Mainline thread | +| | | | | | +| - Fast response. | | - Realtime thread with | | - Processing of time | +| - Detect CAN ID. | | constant interval, | | consuming tasks | +| - Partially process | | typically 1ms. | | in CANopen objects: | +| messages and copy | | - Network synchronized | | - SDO server, | +| data to target | | - Copy inputs (RPDOs, | | - Emergency, | +| CANopen objects. | | HW) to Object Dict. | | - Network state, | +| | | - May call application | | - Heartbeat. | +| | | for some processing. | | - LSS slave | +| | | - Copy variables from | | - Gateway (optional): | +| | | Object Dictionary to | | - NMT master | +| | | outputs (TPDOs, HW). | | - SDO client | +| | | | | - LSS master | +| | | | | - May cyclically call | +| | | | | application code. | + ---------------------- ------------------------ ----------------------- ~~~ diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index dd8515d5..d280a777 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -5,12 +5,14 @@ Change Log ------------------------- - [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/master...newOD) ### Changed -- New Object dictionary interface. It has very similar principles as before. All parts of CANopenNode objects, which works with OD entries, are rewritten. +- New Object dictionary interface. It has similar principles as before. Main access to OD variables is via fast read/write functions, but direct access to OD variables is also possible. OD entries are passed with pointers to CANopen objects. All parts of CANopenNode objects, which works with OD entries, are rewritten. +- [libedssharp](https://github.com/robincornelius/libedssharp) have new OD exporter, new project file format (standard CANopen XDD v1.1), new documentation generator, and many other improvements. - New OD.h and OD.c files, replaces CO_OD files. -- CANopen.c and CANopen.h files redesigned. Integration of "OD.h" is optional. Configuration of multiple object dictionaries is possible with one CANopen device. Interface is the same, with some changes to function arguments. -- Rewritten SDO server. Object dictionary part is removed. -- CO_Emergency is mostly rewritten. Now is much easier customization. -- CO_NMT_Heartbeat is redesigned. +- CANopen.c and CANopen.h files redesigned. `#include OD.h` is optional. Configuration of multiple object dictionaries is possible with one CANopen device. Interface is the same, with some changes to function arguments. +- New CO_storage.h/c files enables easier integration to target system for storing OD variables. +- Rewritten SDO server. Object dictionary part is moved to CO_ODinterface.h/c files. +- Rewritten PDO. PDO mapped variables are accessed via fast read/write functions. New RPDO event timer (timeout). +- CO_Emergency is mostly rewritten. Now is much easier customization. All other objects has been adjusted to newOD, inspected and some parts were redesigned. [Unreleased master] ------------------------- diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index bfc93bba..949ebcba 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -30,7 +30,7 @@ Note that OD variables can be accessed from different threads. CANopenNode basic extern OD_t *ODxyz; void myFunc(OD_t *od) { - ODR_t ret; + ODR_t odRet; OD_entry_t *entry; OD_IO_t io1008; char buf[50]; @@ -39,15 +39,24 @@ void myFunc(OD_t *od) { /* Init IO for "Manufacturer device name" at index 0x1008, sub-index 0x00 */ entry = OD_find(od, 0x1008); - ret = OD_getSub(entry, 0x00, &io1008, false); + odRet = OD_getSub(entry, 0x00, &io1008, false); /* Read with io1008, subindex = 0x00 */ - if (ret == ODR_OK) - bytesRd = io1008.read(&io1008.stream, 0x00, &buf[0], sizeof(buf), &ret); - if (ret != ODR_OK) error++; + if (odRet == ODR_OK) { + /* Locking is necessary from mainline thread, but must not be used from + * timer interval (real-time) thread. Locking is not necessary in the + * CANoopen initialization section. Locking is also not necessary, if + * OD variable is not mappable to PDO and not accessed from RT thread.*/ + CO_LOCK_OD(CANmodule); + odRet = io1008.read(&io1008.stream, &buf[0], sizeof(buf), &bytesRd); + CO_UNLOCK_OD(CANmodule); + } + if (odRet != ODR_OK) error++; /* Use helper and set "Producer heartbeat time" at index 0x1017, sub 0x00 */ - ret = OD_set_u16(OD_find(od, 0x1017), 0x00, 500, false); - if (ret != ODR_OK) error++; + CO_LOCK_OD(CANmodule); /* may not be necessary, see comment above */ + odRet = OD_set_u16(OD_find(od, 0x1017), 0x00, 500, false); + CO_UNLOCK_OD(CANmodule); + if (odRet != ODR_OK) error++; } ``` There is no need to include ODxyt.h file, it is only necessary to know, we have ODxyz defined somewhere. diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 61a8d86e..de9f11cb 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -103,16 +103,6 @@ extern "C" { CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ - CO_CONFIG_TPDO_ENABLE | \ - CO_CONFIG_PDO_SYNC_ENABLE | \ - CO_CONFIG_RPDO_CALLS_EXTENSION | \ - CO_CONFIG_TPDO_CALLS_EXTENSION | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) -#endif - #ifndef CO_CONFIG_GFC #define CO_CONFIG_GFC (CO_CONFIG_GFC_ENABLE | \ CO_CONFIG_GFC_CONSUMER | \ diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index 2d88eae6..d9622da2 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -54,10 +54,6 @@ extern "C" { #endif -/* TODO some parts are disabled in non-finished pre-release */ -#define CO_CONFIG_PDO (0) -#define CO_CONFIG_TRACE (0) - /* Stack configuration override default values. * For more information see file CO_config.h. */ @@ -123,16 +119,6 @@ extern "C" { CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ - CO_CONFIG_TPDO_ENABLE | \ - CO_CONFIG_PDO_SYNC_ENABLE | \ - CO_CONFIG_RPDO_CALLS_EXTENSION | \ - CO_CONFIG_TPDO_CALLS_EXTENSION | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) -#endif - #ifndef CO_CONFIG_LSS #define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ @@ -166,10 +152,6 @@ extern "C" { CO_CONFIG_FIFO_ASCII_DATATYPES) #endif -#ifndef CO_CONFIG_TRACE -#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE) -#endif - /* Print debug info from some internal parts of the stack */ #if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_COMMON diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c index 0be29218..016a1971 100644 --- a/socketCAN/CO_epoll_interface.c +++ b/socketCAN/CO_epoll_interface.c @@ -338,7 +338,8 @@ void CO_epoll_processRT(CO_epoll_t *ep, pTimerNext_us); #endif #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE - CO_process_RPDO(co, syncWas); + CO_process_RPDO(co, syncWas, ep->timeDifference_us, + pTimerNext_us); #endif #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE CO_process_TPDO(co, syncWas, ep->timeDifference_us, diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index 5c1f6c45..cfc9d755 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -67,9 +67,9 @@ #ifndef NMT_CONTROL #define NMT_CONTROL \ CO_NMT_STARTUP_TO_OPERATIONAL \ - || CO_NMT_ERR_ON_ERR_REG \ - || CO_ERR_REG_GENERIC_ERR \ - || CO_ERR_REG_COMMUNICATION + | CO_NMT_ERR_ON_ERR_REG \ + | CO_ERR_REG_GENERIC_ERR \ + | CO_ERR_REG_COMMUNICATION #endif #ifndef FIRST_HB_TIME #define FIRST_HB_TIME 500 @@ -665,6 +665,24 @@ int main (int argc, char *argv[]) { app_communicationReset(!CO->nodeIdUnconfigured); #endif + errInfo = 0; + err = CO_CANopenInitPDO(CO, /* CANopen object */ + CO->em, /* emergency object */ + OD, /* Object dictionary */ + CO_activeNodeId, + &errInfo); + if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + if (err == CO_ERROR_OD_PARAMETERS) { + log_printf(LOG_CRIT, DBG_OD_ENTRY, errInfo); + } + else { + log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInitPDO()", err); + } + programExit = EXIT_FAILURE; + CO_endProgram = 1; + continue; + } + /* start CAN */ CO_CANsetNormalMode(CO->CANmodule); From b6f04d65f8eb42467085a42bdb0513a92078360b Mon Sep 17 00:00:00 2001 From: Julien PEYREGNE Date: Fri, 19 Mar 2021 09:20:21 +0100 Subject: [PATCH 169/520] Fix null pointer dereference warnings --- 301/CO_SDOserver.c | 9 +++++---- CANopen.c | 7 +++++-- socketCAN/CO_driver.c | 3 +-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 67fb1cfe..b2120905 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -679,6 +679,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, uint32_t timeDifference_us, uint32_t *timerNext_us) { + if (SDO == NULL) { + return CO_SDO_RT_wrongArguments; + } + (void)timerNext_us; /* may be unused */ CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; @@ -686,10 +690,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, bool_t isNew = CO_FLAG_READ(SDO->CANrxNew); - if (SDO == NULL) { - ret = CO_SDO_RT_wrongArguments; - } - else if (SDO->valid && SDO->state == CO_SDO_ST_IDLE && !isNew) { + if (SDO->valid && SDO->state == CO_SDO_ST_IDLE && !isNew) { /* Idle and nothing new */ ret = CO_SDO_RT_ok_communicationEnd; } diff --git a/CANopen.c b/CANopen.c index 1a19527a..4280339b 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1213,8 +1213,11 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, uint8_t nodeId, uint32_t *errInfo) { - if (co == NULL || nodeId < 1 || nodeId > 127 || co->nodeIdUnconfigured) { - return (co != NULL || co->nodeIdUnconfigured) + if (co == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + if (nodeId < 1 || nodeId > 127 || co->nodeIdUnconfigured) { + return (co->nodeIdUnconfigured) ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; } diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 5a083d79..0df0f659 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -182,9 +182,8 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) { CO_ReturnError_t ret; - CANmodule->CANnormal = false; - if(CANmodule != NULL) { + CANmodule->CANnormal = false; ret = setRxFilters(CANmodule); if (ret == CO_ERROR_NO) { /* Put CAN module in normal mode */ From 9554c2c8dfb388d4145a153710d53b5ccb56b980 Mon Sep 17 00:00:00 2001 From: Julien PEYREGNE Date: Fri, 19 Mar 2021 09:30:55 +0100 Subject: [PATCH 170/520] Fix printf argument signedness --- example/main_blank.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/main_blank.c b/example/main_blank.c index b645e71c..c8c4d6c6 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -63,7 +63,7 @@ int main (void){ return 0; } else { - log_printf("Allocated %d bytes for CANopen objects\n", heapMemoryUsed); + log_printf("Allocated %u bytes for CANopen objects\n", heapMemoryUsed); } /* initialize EEPROM */ From 877edc50a81175d343d78a557a0b1dd8bd70586f Mon Sep 17 00:00:00 2001 From: Julien PEYREGNE Date: Fri, 19 Mar 2021 09:44:29 +0100 Subject: [PATCH 171/520] Reduce variable scope --- 301/CO_ODinterface.c | 3 +-- 301/CO_SDOserver.c | 3 +-- example/main_blank.c | 3 +-- socketCAN/CO_driver.c | 6 ++---- socketCAN/CO_error.c | 3 +-- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 9a170a37..ff61cec1 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -145,7 +145,6 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index) { return NULL; } - uint16_t cur; uint16_t min = 0; uint16_t max = od->size - 1; @@ -154,7 +153,7 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index) { * max number of loop passes is log2(N) */ while (min < max) { /* get entry between min and max */ - cur = (min + max) >> 1; + uint16_t cur = (min + max) >> 1; OD_entry_t* entry = &od->list[cur]; if (index == entry->index) { diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index b2120905..22e48820 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -443,9 +443,8 @@ void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, static inline void reverseBytes(void *start, OD_size_t size) { uint8_t *lo = (uint8_t *)start; uint8_t *hi = (uint8_t *)start + size - 1; - uint8_t swap; while (lo < hi) { - swap = *lo; + uint8_t swap = *lo; *lo++ = *hi; *hi-- = swap; } diff --git a/example/main_blank.c b/example/main_blank.c index c8c4d6c6..0138ee6f 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -50,7 +50,6 @@ int main (void){ uint32_t heapMemoryUsed; void *CANmoduleAddress = NULL; /* CAN module address */ uint8_t pendingNodeId = 10; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ - uint8_t activeNodeId = 10; /* Copied from CO_pendingNodeId in the communication reset section */ uint16_t pendingBitRate = 125; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ /* Configure microcontroller. */ @@ -94,7 +93,7 @@ int main (void){ log_printf("Error: LSS slave initialization failed: %d\n", err); return 0; } - activeNodeId = pendingNodeId; + uint8_t activeNodeId = pendingNodeId; err = CO_CANopenInit(activeNodeId); if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { log_printf("Error: CANopen initialization failed: %d\n", err); diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c index 0df0f659..b10402aa 100644 --- a/socketCAN/CO_driver.c +++ b/socketCAN/CO_driver.c @@ -104,14 +104,13 @@ static uint32_t CO_CANgetIndexFromIdent( /** Disable socketCAN rx ******************************************************/ static CO_ReturnError_t disableRx(CO_CANmodule_t *CANmodule) { - int ret; uint32_t i; CO_ReturnError_t retval; /* insert a filter that doesn't match any messages */ retval = CO_ERROR_NO; for (i = 0; i < CANmodule->CANinterfaceCount; i ++) { - ret = setsockopt(CANmodule->CANinterfaces[i].fd, SOL_CAN_RAW, CAN_RAW_FILTER, + int ret = setsockopt(CANmodule->CANinterfaces[i].fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); if(ret < 0){ log_printf(LOG_ERR, CAN_FILTER_FAILED, @@ -128,7 +127,6 @@ static CO_ReturnError_t disableRx(CO_CANmodule_t *CANmodule) /** Set up or update socketCAN rx filters *************************************/ static CO_ReturnError_t setRxFilters(CO_CANmodule_t *CANmodule) { - int ret; size_t i; int count; CO_ReturnError_t retval; @@ -155,7 +153,7 @@ static CO_ReturnError_t setRxFilters(CO_CANmodule_t *CANmodule) retval = CO_ERROR_NO; for (i = 0; i < CANmodule->CANinterfaceCount; i ++) { - ret = setsockopt(CANmodule->CANinterfaces[i].fd, SOL_CAN_RAW, CAN_RAW_FILTER, + int ret = setsockopt(CANmodule->CANinterfaces[i].fd, SOL_CAN_RAW, CAN_RAW_FILTER, rxFiltersCpy, sizeof(struct can_filter) * count); if(ret < 0){ log_printf(LOG_ERR, CAN_FILTER_FAILED, diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c index 73d8f944..4ceb1bc5 100644 --- a/socketCAN/CO_error.c +++ b/socketCAN/CO_error.c @@ -42,8 +42,6 @@ static CO_CANinterfaceState_t CO_CANerrorSetListenOnly( CO_CANinterfaceErrorhandler_t *CANerrorhandler, bool_t resetIf) { - char command[100]; - log_printf(LOG_DEBUG, DBG_CAN_SET_LISTEN_ONLY, CANerrorhandler->ifName); clock_gettime(CLOCK_MONOTONIC, &CANerrorhandler->timestamp); @@ -51,6 +49,7 @@ static CO_CANinterfaceState_t CO_CANerrorSetListenOnly( if (resetIf) { int ret; + char command[100]; snprintf(command, sizeof(command), "ip link set %s down && " "ip link set %s up " "&", From 7d85e12f2a964799584bf0a93471229bace11c96 Mon Sep 17 00:00:00 2001 From: Julien PEYREGNE Date: Mon, 22 Mar 2021 16:21:43 +0100 Subject: [PATCH 172/520] Fix overflow on 16 bit platform --- 301/CO_TIME.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 2f6aa064..17648d35 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -201,8 +201,8 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, ms = us / 1000; TIME->residual_us = us % 1000; TIME->ms += ms; - if (TIME->ms >= (1000*60*60*24)) { - TIME->ms -= (1000*60*60*24); + if (TIME->ms >= ((uint32_t)1000*60*60*24)) { + TIME->ms -= ((uint32_t)1000*60*60*24); TIME->days += 1; } } From b7aaaa167b2493a018fac7c477c8446c799fe92e Mon Sep 17 00:00:00 2001 From: Julien PEYREGNE Date: Mon, 22 Mar 2021 16:22:32 +0100 Subject: [PATCH 173/520] Fix snprintf float to double warning --- 301/CO_fifo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index b0042383..1ec77ac2 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -631,7 +631,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%g", CO_SWAP_32(n)); + return sprintf(buf, "%g", (double)CO_SWAP_32(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -643,7 +643,7 @@ size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if (fifo != NULL && count >= 30 && CO_fifo_getOccupied(fifo) == sizeof(n)) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%g", CO_SWAP_64(n)); + return sprintf(buf, "%g", (double)CO_SWAP_64(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); From 9824b740ca67cf6aa5b874d25e12ab34b30cedae Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 22 Mar 2021 21:13:11 +0100 Subject: [PATCH 174/520] Fixed invariant pointer in CO_Process #278 --- CANopen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CANopen.c b/CANopen.c index 1a19527a..0503dac5 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1345,7 +1345,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, /* SDOserver */ for (uint8_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { - CO_SDOserver_process(co->SDOserver, + CO_SDOserver_process(&co->SDOserver[i], NMTisPreOrOperational, timeDifference_us, timerNext_us); From 0d33cbb8bdd9e6e2c6be6b397849a0ad7f2aa527 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 22 Mar 2021 22:59:49 +0100 Subject: [PATCH 175/520] Fix in CO_RPDO_process(), #283 --- 301/CO_PDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 564a64ad..6eeb2be7 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -833,7 +833,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, uint8_t *dataOD; if (ODdataLength > mappedLength) { memset(buf, 0, sizeof(buf)); - memcpy(buf, dataOD, mappedLength); + memcpy(buf, dataRPDO, mappedLength); dataOD = buf; } else { From 72e840429718ded8bb59c0012945ca54aeaa259f Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 22 Mar 2021 23:03:37 +0100 Subject: [PATCH 176/520] Remove unnecessary #include in Linux driver https://github.com/CANopenNode/CANopenSocket/issues/26 --- socketCAN/CO_main_basic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index cfc9d755..f0c93990 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include From ba0b0bcdb5806241bf145adb251ca9d405b07938 Mon Sep 17 00:00:00 2001 From: Julien PEYREGNE Date: Wed, 24 Mar 2021 17:30:55 +0100 Subject: [PATCH 177/520] Fix HBcons entries count HB Consumer sub index 0 is Highest sub-index supported and should not be counted on number of HB consumers. Without this, CO_CANopenInit fails with error code -12 : CO_ERROR_OD_PARAMETERS --- 301/CO_HBconsumer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 43590404..17a5830f 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -140,8 +140,8 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, /* get actual number of monitored nodes */ HBcons->numberOfMonitoredNodes = - OD_1016_HBcons->subEntriesCount < CO_CONFIG_HB_CONS_SIZE ? - OD_1016_HBcons->subEntriesCount : CO_CONFIG_HB_CONS_SIZE; + OD_1016_HBcons->subEntriesCount-1 < CO_CONFIG_HB_CONS_SIZE ? + OD_1016_HBcons->subEntriesCount-1 : CO_CONFIG_HB_CONS_SIZE; for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { uint32_t val; From 90ec8819beb8d38feb0312479f331394af95da53 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 7 Apr 2021 16:19:09 +0200 Subject: [PATCH 178/520] Example update --- 301/CO_ODinterface.h | 2 +- example/CO_driver_target.h | 121 +------------------------ example/CO_storageBlank.c | 111 +++++++++++++++++++++++ example/CO_storageBlank.h | 56 ++++++++++++ example/Makefile | 28 +++--- example/eeprom.c | 176 ------------------------------------- example/eeprom.h | 108 ----------------------- example/main_blank.c | 174 ++++++++++++++++++++++++------------ socketCAN/CO_error_msgs.h | 2 +- socketCAN/CO_main_basic.c | 7 +- 10 files changed, 307 insertions(+), 478 deletions(-) create mode 100644 example/CO_storageBlank.c create mode 100644 example/CO_storageBlank.h delete mode 100644 example/eeprom.c delete mode 100644 example/eeprom.h diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 2c5cf937..aa12b796 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -347,7 +347,7 @@ typedef struct { typedef struct { /** Object Dictionary index */ uint16_t index; - /** Maximum sub-index in the OD object */ + /** Number of all sub-entries, including sub-entry at sub-index 0 */ uint8_t subEntriesCount; /** Type of the odObject, indicated by @ref OD_objectTypes_t enumerator. */ uint8_t odObjectType; diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index de9f11cb..a270beed 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -3,7 +3,7 @@ * * @file CO_driver_target.h * @author Janez Paternoster - * @copyright 2020 Janez Paternoster + * @copyright 2021 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -42,122 +42,8 @@ extern "C" { #endif -/* Stack configuration override default values (all enabled in this example). +/* Stack configuration override default values. * For more information see file CO_config.h. */ -#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE CO_CONFIG_FLAG_CALLBACK_PRE -#define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT CO_CONFIG_FLAG_TIMERNEXT - -#ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT (CO_CONFIG_NMT_CALLBACK_CHANGE | \ - CO_CONFIG_NMT_MASTER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) -#endif - -#ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ - CO_CONFIG_HB_CONS_CALLBACK_MULTI | \ - CO_CONFIG_HB_CONS_QUERY_FUNCT | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - -#ifndef CO_CONFIG_EM -#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ - CO_CONFIG_EM_PROD_CONFIGURABLE | \ - CO_CONFIG_EM_PROD_INHIBIT | \ - CO_CONFIG_EM_HISTORY | \ - CO_CONFIG_EM_STATUS_BITS | \ - CO_CONFIG_EM_CONSUMER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) -#endif - -#ifndef CO_CONFIG_SDO_SRV -#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ - CO_CONFIG_SDO_SRV_BLOCK | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - -#ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE -#define CO_CONFIG_SDO_SRV_BUFFER_SIZE 900 -#endif - -#ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI (CO_CONFIG_SDO_CLI_ENABLE | \ - CO_CONFIG_SDO_CLI_SEGMENTED | \ - CO_CONFIG_SDO_CLI_BLOCK | \ - CO_CONFIG_SDO_CLI_LOCAL | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - -#ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ - CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - -#ifndef CO_CONFIG_GFC -#define CO_CONFIG_GFC (CO_CONFIG_GFC_ENABLE | \ - CO_CONFIG_GFC_CONSUMER | \ - CO_CONFIG_GFC_PRODUCER) -#endif - -#ifndef CO_CONFIG_SRDO -#define CO_CONFIG_SRDO (CO_CONFIG_SRDO_ENABLE | \ - CO_CONFIG_SRDO_CHECK_TX | \ - CO_CONFIG_RSRDO_CALLS_EXTENSION | \ - CO_CONFIG_TSRDO_CALLS_EXTENSION | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) -#endif - -#ifndef CO_CONFIG_SRDO_MINIMUM_DELAY -#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 -#endif - -#ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ - CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ - CO_CONFIG_LSS_MASTER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) -#endif - -#ifndef CO_CONFIG_GTW -#define CO_CONFIG_GTW (CO_CONFIG_GTW_ASCII | \ - CO_CONFIG_GTW_ASCII_SDO | \ - CO_CONFIG_GTW_ASCII_NMT | \ - CO_CONFIG_GTW_ASCII_LSS | \ - CO_CONFIG_GTW_ASCII_LOG | \ - CO_CONFIG_GTW_ASCII_ERROR_DESC | \ - CO_CONFIG_GTW_ASCII_PRINT_HELP | \ - CO_CONFIG_GTW_ASCII_PRINT_LEDS) -#define CO_CONFIG_GTW_BLOCK_DL_LOOP 1 -#define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 -#define CO_CONFIG_GTWA_LOG_BUF_SIZE 2000 -#endif - -#ifndef CO_CONFIG_CRC16 -#define CO_CONFIG_CRC16 (CO_CONFIG_CRC16_ENABLE) -#endif - -#ifndef CO_CONFIG_FIFO -#define CO_CONFIG_FIFO (CO_CONFIG_FIFO_ENABLE | \ - CO_CONFIG_FIFO_ALT_READ | \ - CO_CONFIG_FIFO_CRC16_CCITT | \ - CO_CONFIG_FIFO_ASCII_COMMANDS | \ - CO_CONFIG_FIFO_ASCII_DATATYPES) -#endif - -#ifndef CO_CONFIG_TRACE -#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE) -#endif /* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ @@ -218,7 +104,8 @@ typedef struct { size_t len; uint8_t subIndexOD; uint8_t attr; - /* Additional variables */ + /* Additional variables (target specific) */ + void *addrNV; } CO_storage_entry_t; diff --git a/example/CO_storageBlank.c b/example/CO_storageBlank.c new file mode 100644 index 00000000..16f92253 --- /dev/null +++ b/example/CO_storageBlank.c @@ -0,0 +1,111 @@ +/* + * CANopen Object Dictionary storage object (blank example). + * + * @file CO_storageBlank.c + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CO_storageBlank.h" + + +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + + +/* + * Function for writing data on "Store parameters" command - OD object 1010 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t storeBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { + + /* Open a file and write data to it */ + /* file = open(entry->pathToFileOrPointerToMemory); */ + CO_LOCK_OD(CANmodule); + /* write(entry->addr, entry->len, file); */ + CO_UNLOCK_OD(CANmodule); + + return ODR_OK; +} + + +/* + * Function for restoring data on "Restore default parameters" command - OD 1011 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t restoreBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule){ + + /* disable (delete) the file, so default values will stay after startup */ + + return ODR_OK; +} + + +CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, + CO_CANmodule_t *CANmodule, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, + uint8_t entriesCount, + uint32_t *storageInitError) +{ + CO_ReturnError_t ret; + + /* verify arguments */ + if (storage == NULL || entries == NULL || entriesCount == 0 + || storageInitError == NULL + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* initialize storage and OD extensions */ + ret = CO_storage_init(storage, + CANmodule, + OD_1010_StoreParameters, + OD_1011_RestoreDefaultParam, + storeBlank, + restoreBlank, + entries, + entriesCount); + if (ret != CO_ERROR_NO) { + return ret; + } + + /* initialize entries */ + *storageInitError = 0; + for (uint8_t i = 0; i < entriesCount; i++) { + CO_storage_entry_t *entry = &entries[i]; + + /* verify arguments */ + if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { + *storageInitError = i; + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* Open a file and read data from file to entry->addr */ + /* file = open(entry->pathToFileOrPointerToMemory); */ + /* read(entry->addr, entry->len, file); */ + + } + + return ret; +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/example/CO_storageBlank.h b/example/CO_storageBlank.h new file mode 100644 index 00000000..de8ddf9f --- /dev/null +++ b/example/CO_storageBlank.h @@ -0,0 +1,56 @@ +/* + * CANopen data storage object (blank example) + * + * @file CO_storageBlank.h + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CO_STORAGE_BLANK_H +#define CO_STORAGE_BLANK_H + +#include "301/CO_storage.h" + +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/* See socketCAN/storageLinux.h and 301/CO_storage.h for information and + * full example */ + +CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, + CO_CANmodule_t *CANmodule, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, + uint8_t entriesCount, + uint32_t *storageInitError); + +uint32_t CO_storageBlank_auto_process(CO_storage_t *storage, + bool_t closeFiles); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +#endif /* CO_STORAGE_BLANK_H */ diff --git a/example/Makefile b/example/Makefile index 48e4876b..2783298b 100644 --- a/example/Makefile +++ b/example/Makefile @@ -3,7 +3,6 @@ DRV_SRC = . CANOPEN_SRC = .. -OD_SRC = . APPL_SRC = . @@ -13,39 +12,34 @@ LINK_TARGET = canopennode_blank INCLUDE_DIRS = \ -I$(DRV_SRC) \ -I$(CANOPEN_SRC) \ - -I$(OD_SRC) \ -I$(APPL_SRC) SOURCES = \ $(DRV_SRC)/CO_driver_blank.c \ - $(DRV_SRC)/eeprom.c \ + $(DRV_SRC)/CO_storageBlank.c \ $(CANOPEN_SRC)/301/CO_ODinterface.c \ - $(CANOPEN_SRC)/301/CO_SDOserver.c \ - $(CANOPEN_SRC)/301/CO_Emergency.c \ $(CANOPEN_SRC)/301/CO_NMT_Heartbeat.c \ $(CANOPEN_SRC)/301/CO_HBconsumer.c \ + $(CANOPEN_SRC)/301/CO_Emergency.c \ + $(CANOPEN_SRC)/301/CO_SDOserver.c \ + $(CANOPEN_SRC)/301/CO_TIME.c \ $(CANOPEN_SRC)/301/CO_SYNC.c \ $(CANOPEN_SRC)/301/CO_PDO.c \ - $(CANOPEN_SRC)/301/CO_TIME.c \ - $(CANOPEN_SRC)/301/CO_SDOclient.c \ - $(CANOPEN_SRC)/301/crc16-ccitt.c \ - $(CANOPEN_SRC)/301/CO_fifo.c \ + $(CANOPEN_SRC)/301/CO_storage.c \ $(CANOPEN_SRC)/303/CO_LEDs.c \ - $(CANOPEN_SRC)/304/CO_GFC.c \ - $(CANOPEN_SRC)/304/CO_SRDO.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ - $(CANOPEN_SRC)/305/CO_LSSmaster.c \ - $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ - $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ - $(OD_SRC)/CO_OD.c \ - $(APPL_SRC)/main_blank.c + $(APPL_SRC)/OD.c \ + $(DRV_SRC)/main_blank.c OBJS = $(SOURCES:%.c=%.o) CC ?= gcc -OPT = -g +OPT = +OPT += -g +#OPT += -DCO_USE_GLOBALS +#OPT += -DCO_MULTIPLE_OD CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) LDFLAGS = diff --git a/example/eeprom.c b/example/eeprom.c deleted file mode 100644 index c8a0824f..00000000 --- a/example/eeprom.c +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Microcontroller specific code for CANopenNode nonvolatile variables. - * - * This file is a template for other microcontrollers. - * - * @file eeprom.h - * @ingroup CO_eeprom - * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include - -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" -#include "301/CO_Emergency.h" -#include "301/crc16-ccitt.h" -#include "eeprom.h" - - -/** - * OD function for accessing _Store parameters_ (index 0x1010) from SDO server. - * - * For more information see file CO_SDOserver.h. - */ -static CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg); -static CO_SDO_abortCode_t CO_ODF_1010(CO_ODF_arg_t *ODF_arg){ - //CO_EE_t *ee; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - //ee = (CO_EE_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - if(!ODF_arg->reading){ - /* don't change the old value */ - memcpy(ODF_arg->data, ODF_arg->ODdataStorage, 4); - - if(ODF_arg->subIndex == 1U){ - if(value == 0x65766173UL){ - /* write ee->OD_ROMAddress, ee->OD_ROMSize to eeprom (blocking function) */ - - /* verify data */ - if(0/*error*/){ - ret = CO_SDO_AB_HW; - } - } - else{ - ret = CO_SDO_AB_DATA_TRANSF; - } - } - } - - return ret; -} - - -/** - * OD function for accessing _Restore default parameters_ (index 0x1011) from SDO server. - * - * For more information see file CO_SDOserver.h. - */ -static CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg); -static CO_SDO_abortCode_t CO_ODF_1011(CO_ODF_arg_t *ODF_arg){ - //CO_EE_t *ee; - uint32_t value; - CO_SDO_abortCode_t ret = CO_SDO_AB_NONE; - - //ee = (CO_EE_t*) ODF_arg->object; - value = CO_getUint32(ODF_arg->data); - - if(!ODF_arg->reading){ - /* don't change the old value */ - memcpy(ODF_arg->data, ODF_arg->ODdataStorage, 4); - - if(ODF_arg->subIndex >= 1U){ - if(value == 0x64616F6CUL){ - /* Clear the eeprom */ - - } - else{ - ret = CO_SDO_AB_DATA_TRANSF; - } - } - } - - return ret; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_EE_init_1( - CO_EE_t *ee, - uint8_t *OD_EEPROMAddress, - uint32_t OD_EEPROMSize, - uint8_t *OD_ROMAddress, - uint32_t OD_ROMSize) -{ - /* verify arguments */ - if(ee==NULL || OD_EEPROMAddress==NULL || OD_ROMAddress==NULL){ - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure eeprom */ - - - /* configure object variables */ - ee->OD_EEPROMAddress = OD_EEPROMAddress; - ee->OD_EEPROMSize = OD_EEPROMSize; - ee->OD_ROMAddress = OD_ROMAddress; - ee->OD_ROMSize = OD_ROMSize; - ee->OD_EEPROMCurrentIndex = 0U; - ee->OD_EEPROMWriteEnable = false; - - /* read the CO_OD_EEPROM from EEPROM, first verify, if data are OK */ - - /* read the CO_OD_ROM from EEPROM and verify CRC */ - - return CO_ERROR_NO; -} - - -/******************************************************************************/ -void CO_EE_init_2( - CO_EE_t *ee, - CO_ReturnError_t eeStatus, - CO_SDO_t *SDO, - CO_EM_t *em) -{ - CO_OD_configure(SDO, OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)ee, 0, 0U); - CO_OD_configure(SDO, OD_H1011_REST_PARAM_FUNC, CO_ODF_1011, (void*)ee, 0, 0U); - if(eeStatus != CO_ERROR_NO){ - CO_errorReport(em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)eeStatus); - } -} - - -/******************************************************************************/ -void CO_EE_process(CO_EE_t *ee){ - if((ee != 0) && (ee->OD_EEPROMWriteEnable)/* && !isWriteInProcess()*/){ - uint32_t i; - uint8_t RAMdata, eeData; - - /* verify next word */ - if(++ee->OD_EEPROMCurrentIndex == ee->OD_EEPROMSize){ - ee->OD_EEPROMCurrentIndex = 0U; - } - i = ee->OD_EEPROMCurrentIndex; - - /* read eeprom */ - RAMdata = ee->OD_EEPROMAddress[i]; - eeData = 0/*EE_readByte(i)*/; - - /* if bytes in EEPROM and in RAM are different, then write to EEPROM */ - if(eeData != RAMdata){ - /* EE_writeByteNoWait(RAMdata, i);*/ - } - } -} diff --git a/example/eeprom.h b/example/eeprom.h deleted file mode 100644 index 6ed302f6..00000000 --- a/example/eeprom.h +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Eeprom object for generic microcontroller. - * - * This file is a template for other microcontrollers. - * - * @file eeprom.h - * @ingroup CO_eeprom - * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef EEPROM_H -#define EEPROM_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_eeprom Nonvolatile storage - * @ingroup CO_CANopen_extra - * @{ - * - * Storage of nonvolatile CANopen variables into the eeprom. - */ - - -/** - * Eeprom object. - */ -typedef struct{ - uint8_t *OD_EEPROMAddress; /**< From CO_EE_init_1() */ - uint32_t OD_EEPROMSize; /**< From CO_EE_init_1() */ - uint8_t *OD_ROMAddress; /**< From CO_EE_init_1() */ - uint32_t OD_ROMSize; /**< From CO_EE_init_1() */ - uint32_t OD_EEPROMCurrentIndex; /**< Internal variable controls the OD_EEPROM vrite */ - bool_t OD_EEPROMWriteEnable; /**< Writing to EEPROM is enabled */ -}CO_EE_t; - - -/** - * First part of eeprom initialization. Called after microcontroller reset. - * - * @param ee This object will be initialized. - * @param OD_EEPROMAddress Address of OD_EEPROM structure from object dictionary. - * @param OD_EEPROMSize Size of OD_EEPROM structure from object dictionary. - * @param OD_ROMAddress Address of OD_ROM structure from object dictionary. - * @param OD_ROMSize Size of OD_ROM structure from object dictionary. - * - * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_DATA_CORRUPT (Data in eeprom corrupt) or - * CO_ERROR_CRC (CRC from MBR does not match the CRC of OD_ROM block in eeprom). - */ -CO_ReturnError_t CO_EE_init_1( - CO_EE_t *ee, - uint8_t *OD_EEPROMAddress, - uint32_t OD_EEPROMSize, - uint8_t *OD_ROMAddress, - uint32_t OD_ROMSize); - - -/** - * Second part of eeprom initialization. Called after CANopen communication reset. - * - * @param ee - This object. - * @param eeStatus - Return value from CO_EE_init_1(). - * @param SDO - SDO object. - * @param em - Emergency object. - */ -void CO_EE_init_2( - CO_EE_t *ee, - CO_ReturnError_t eeStatus, - CO_SDO_t *SDO, - CO_EM_t *em); - - -/** - * Process eeprom object. - * - * Function must be called cyclically. It strores variables from OD_EEPROM data - * block into eeprom byte by byte (only if values are different). - * - * @param ee This object. - */ -void CO_EE_process(CO_EE_t *ee); - -#ifdef __cplusplus -} -#endif /*__cplusplus*/ - -/** @} */ -#endif diff --git a/example/main_blank.c b/example/main_blank.c index 0138ee6f..96cdd075 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -5,7 +5,7 @@ * * @file main_generic.c * @author Janez Paternoster - * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2021 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -28,36 +28,63 @@ #include #include "CANopen.h" +#include "OD.h" +#include "CO_storageBlank.h" -#define TMR_TASK_INTERVAL (1000) /* Interval of tmrTask thread in microseconds */ -#define INCREMENT_1MS(var) (var++) /* Increment 1ms variable in tmrTask */ - #define log_printf(macropar_message, ...) \ printf(macropar_message, ##__VA_ARGS__) -/* Global variables and objects */ - volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */ - uint8_t LED_red, LED_green; +/* default values for CO_CANopenInit() */ +#define NMT_CONTROL \ + CO_NMT_STARTUP_TO_OPERATIONAL \ + | CO_NMT_ERR_ON_ERR_REG \ + | CO_ERR_REG_GENERIC_ERR \ + | CO_ERR_REG_COMMUNICATION +#define FIRST_HB_TIME 500 +#define SDO_SRV_TIMEOUT_TIME 1000 +#define SDO_CLI_TIMEOUT_TIME 500 +#define SDO_CLI_BLOCK false +#define OD_STATUS_BITS NULL +/* Global variables and objects */ +CO_t *CO = NULL; /* CANopen object */ +uint8_t LED_red, LED_green; + /* main ***********************************************************************/ int main (void){ CO_ReturnError_t err; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; uint32_t heapMemoryUsed; - void *CANmoduleAddress = NULL; /* CAN module address */ + void *CANptr = NULL; /* CAN module address */ uint8_t pendingNodeId = 10; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ + uint8_t activeNodeId = 10; /* Copied from CO_pendingNodeId in the communication reset section */ uint16_t pendingBitRate = 125; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + CO_storage_t storage; + CO_storage_entry_t storageEntries[] = { + { + .addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), + .subIndexOD = 2, + .attr = CO_storage_cmd | CO_storage_restore, + .addrNV = NULL + } + }; + uint8_t storageEntriesCount = sizeof(storageEntries) / sizeof(storageEntries[0]); + uint32_t storageInitError = 0; +#endif + /* Configure microcontroller. */ /* Allocate memory */ - err = CO_new(&heapMemoryUsed); - if (err != CO_ERROR_NO) { + CO = CO_new(NULL, &heapMemoryUsed); + if (CO == NULL) { log_printf("Error: Can't allocate memory\n"); return 0; } @@ -65,38 +92,75 @@ int main (void){ log_printf("Allocated %u bytes for CANopen objects\n", heapMemoryUsed); } - /* initialize EEPROM */ - - /* increase variable each startup. Variable is stored in EEPROM. */ - OD_powerOnCounter++; +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + err = CO_storageBlank_init(&storage, + CO->CANmodule, + OD_ENTRY_H1010_storeParameters, + OD_ENTRY_H1011_restoreDefaultParameters, + storageEntries, + storageEntriesCount, + &storageInitError); - log_printf("CANopenNode - Reset application, count = %d\n", OD_powerOnCounter); + if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) { + log_printf("Error: Storage %d\n", storageInitError); + return 0; + } +#endif while(reset != CO_RESET_APP){ /* CANopen communication reset - initialize CANopen objects *******************/ - uint16_t timer1msPrevious; - log_printf("CANopenNode - Reset communication...\n"); - /* disable CAN and CAN interrupts */ + /* Wait rt_thread. */ + CO->CANmodule->CANnormal = false; + + /* Enter CAN configuration. */ + CO_CANsetConfigurationMode((void *)&CANptr); + CO_CANmodule_disable(CO->CANmodule); /* initialize CANopen */ - err = CO_CANinit(CANmoduleAddress, pendingBitRate); + err = CO_CANinit(CO, CANptr, pendingBitRate); if (err != CO_ERROR_NO) { log_printf("Error: CAN initialization failed: %d\n", err); return 0; } - err = CO_LSSinit(&pendingNodeId, &pendingBitRate); + + CO_LSS_address_t lssAddress = {.identity = { + .vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, + .productCode = OD_PERSIST_COMM.x1018_identity.productCode, + .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, + .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber + }}; + err = CO_LSSinit(CO, &lssAddress, &pendingNodeId, &pendingBitRate); if(err != CO_ERROR_NO) { log_printf("Error: LSS slave initialization failed: %d\n", err); return 0; } - uint8_t activeNodeId = pendingNodeId; - err = CO_CANopenInit(activeNodeId); + + activeNodeId = pendingNodeId; + uint32_t errInfo = 0; + + err = CO_CANopenInit(CO, /* CANopen object */ + NULL, /* alternate NMT */ + NULL, /* alternate em */ + OD, /* Object dictionary */ + OD_STATUS_BITS, /* Optional OD_statusBits */ + NMT_CONTROL, /* CO_NMT_control_t */ + FIRST_HB_TIME, /* firstHBTime_ms */ + SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */ + SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */ + SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ + activeNodeId, + &errInfo); if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - log_printf("Error: CANopen initialization failed: %d\n", err); + if (err == CO_ERROR_OD_PARAMETERS) { + log_printf("Error: Object Dictionary entry 0x%X\n", errInfo); + } + else { + log_printf("Error: CANopen initialization failed: %d\n", err); + } return 0; } @@ -109,35 +173,39 @@ int main (void){ /* Configure CANopen callbacks, etc */ if(!CO->nodeIdUnconfigured) { +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + if(storageInitError != 0) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, + CO_EMC_HARDWARE, storageInitError); + } +#endif + } + else { + log_printf("CANopenNode - Node-id not initialized\n"); } /* start CAN */ - CO_CANsetNormalMode(CO->CANmodule[0]); + CO_CANsetNormalMode(CO->CANmodule); reset = CO_RESET_NOT; - timer1msPrevious = CO_timer1ms; log_printf("CANopenNode - Running...\n"); fflush(stdout); while(reset == CO_RESET_NOT){ /* loop for normal program execution ******************************************/ - uint16_t timer1msCopy, timer1msDiff; - - timer1msCopy = CO_timer1ms; - timer1msDiff = timer1msCopy - timer1msPrevious; - timer1msPrevious = timer1msCopy; - + /* get time difference since last function call */ + uint32_t timeDifference_us = 500; /* CANopen process */ - reset = CO_process(CO, (uint32_t)timer1msDiff*1000, NULL); + reset = CO_process(CO, false, timeDifference_us, NULL); LED_red = CO_LED_RED(CO->LEDs, CO_LED_CANopen); LED_green = CO_LED_GREEN(CO->LEDs, CO_LED_CANopen); /* Nonblocking application code may go here. */ - /* Process EEPROM */ + /* Process automatic storage */ /* optional sleep for short time */ } @@ -149,7 +217,8 @@ int main (void){ /* delete objects from memory */ - CO_delete((void*) 0/* CAN module address */); + CO_CANsetConfigurationMode((void *)&CANptr); + CO_delete(CO); log_printf("CANopenNode finished\n"); @@ -162,30 +231,25 @@ int main (void){ void tmrTask_thread(void){ for(;;) { - - /* sleep for interval */ - - INCREMENT_1MS(CO_timer1ms); - - if(CO->CANmodule[0]->CANnormal) { - bool_t syncWas; - - /* Process Sync */ - syncWas = CO_process_SYNC(CO, TMR_TASK_INTERVAL, NULL); - - /* Read inputs */ - CO_process_RPDO(CO, syncWas); + CO_LOCK_OD(co->CANmodule); + if (!CO->nodeIdUnconfigured && CO->CANmodule->CANnormal) { + bool_t syncWas = false; + /* get time difference since last function call */ + uint32_t timeDifference_us = 1000; + +#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE + syncWas = CO_process_SYNC(CO, timeDifference_us, NULL); +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE + CO_process_RPDO(CO, syncWas, timeDifference_us, NULL); +#endif +#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE + CO_process_TPDO(CO, syncWas, timeDifference_us, NULL); +#endif /* Further I/O or nonblocking application code may go here. */ - - /* Write outputs */ - CO_process_TPDO(CO, syncWas, TMR_TASK_INTERVAL, NULL); - - /* verify timer overflow */ - if(0) { - CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0U); - } } + CO_UNLOCK_OD(co->CANmodule); } } diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h index 1ce9f822..1c23bc00 100644 --- a/socketCAN/CO_error_msgs.h +++ b/socketCAN/CO_error_msgs.h @@ -77,7 +77,7 @@ extern "C" { #define DBG_WRONG_NODE_ID "(%s) Wrong node ID \"%d\"", __func__ #define DBG_WRONG_PRIORITY "(%s) Wrong RT priority \"%d\"", __func__ #define DBG_NO_CAN_DEVICE "(%s) Can't find CAN device \"%s\"", __func__ -#define DBG_OBJECT_DICTIONARY "(%s) Error in Object Dictionary \"%s\"", __func__ +#define DBG_STORAGE "(%s) Error with storage \"%s\"", __func__ #define DBG_OD_ENTRY "(%s) Error in Object Dictionary entry: 0x%X", __func__ #define DBG_CAN_OPEN "(%s) CANopen error in %s, err=%d", __func__ #define DBG_CAN_OPEN_INFO "CANopen device, Node ID = 0x%02X, %s" diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index f0c93990..faacf13d 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -397,9 +397,10 @@ int main (int argc, char *argv[]) { CANptr.can_ifindex = if_nametoindex(CANdevice); } + /* Valid NodeId is 1..127 or 0xFF(unconfigured) in case of LSSslaveEnabled*/ if((CO_pending.nodeId < 1 || CO_pending.nodeId > 127) - && CO_isLSSslaveEnabled(CO) - && CO_pending.nodeId != CO_LSS_NODE_ID_ASSIGNMENT + && (!CO_isLSSslaveEnabled(CO) + || CO_pending.nodeId != CO_LSS_NODE_ID_ASSIGNMENT) ) { log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_pending.nodeId); printUsage(argv[0]); @@ -447,7 +448,7 @@ int main (int argc, char *argv[]) { if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) { char *filename = storageInitError < storageEntriesCount ? storageEntries[storageInitError].filename : "???"; - log_printf(LOG_CRIT, DBG_OBJECT_DICTIONARY, filename); + log_printf(LOG_CRIT, DBG_STORAGE, filename); exit(EXIT_FAILURE); } From 5c4b498b2a8b750a978dce7f8c54358dbfb007fa Mon Sep 17 00:00:00 2001 From: gotocoffee Date: Thu, 8 Apr 2021 11:00:38 +0200 Subject: [PATCH 179/520] remove VLA from SDOclient in newOD branch see issue #288 --- 301/CO_SDOclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 74c0a544..9f7b158b 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -553,7 +553,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* write data, in several passes if necessary */ if (SDO_C->OD_IO.write != NULL) { size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo); - uint8_t buf[count + 2]; + uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 2]; CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); SDO_C->sizeTran += count; @@ -1206,7 +1206,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, OD_size_t countBuf = (countData > 0 && countData <= countFifo) ? countData : countFifo; OD_size_t countRd = 0; - uint8_t buf[countBuf + 1]; + uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); /* load data from OD variable into the buffer */ From 591a91be29c27d04e0bd530b9b0bc198d6406321 Mon Sep 17 00:00:00 2001 From: gotocoffee1 Date: Tue, 27 Apr 2021 16:24:00 +0200 Subject: [PATCH 180/520] fixed some warnings fixed some small bugs --- 301/CO_Emergency.c | 4 +- 301/CO_NMT_Heartbeat.h | 4 +- 301/CO_SDOclient.c | 22 ++++----- 301/CO_SDOserver.c | 110 +++++++++++++++++++++-------------------- 301/CO_fifo.h | 12 ++--- 305/CO_LSSmaster.c | 4 +- 305/CO_LSSmaster.h | 4 +- 305/CO_LSSslave.c | 4 +- 305/CO_LSSslave.h | 4 +- 309/CO_gateway_ascii.c | 8 +-- 10 files changed, 89 insertions(+), 87 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 4e817f43..dbc28508 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -259,7 +259,7 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ - size_t countReadLocal = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; + OD_size_t countReadLocal = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; if (countReadLocal > count) { countReadLocal = count; } @@ -288,7 +288,7 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ - size_t countWrite = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; + OD_size_t countWrite = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; if (countWrite > count) { countWrite = count; } diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index b60b98fd..03627542 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -315,7 +315,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, * @return @ref CO_NMT_internalState_t */ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { - return (NMT == NULL) ? CO_NMT_INITIALIZING : NMT->operatingState; + return (NMT == NULL) ? CO_NMT_INITIALIZING : (CO_NMT_internalState_t)NMT->operatingState; } @@ -330,7 +330,7 @@ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { static inline void CO_NMT_sendInternalCommand(CO_NMT_t *NMT, CO_NMT_command_t command) { - if (NMT != NULL) NMT->internalCommand = command; + if (NMT != NULL) NMT->internalCommand = (uint8_t)command; } diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 9f7b158b..b547bfe8 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -411,8 +411,8 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, if (ret != CO_ERROR_NO || SDO_C->CANtxBuff == NULL) { - return CO_SDO_RT_wrongArguments; SDO_C->valid = false; + return CO_SDO_RT_wrongArguments; } return CO_SDO_RT_ok_communicationEnd; @@ -599,11 +599,11 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, buf[count++] = 0; SDO_C->sizeTran++; } - SDO_C->OD_IO.stream.dataLength = SDO_C->sizeTran; + SDO_C->OD_IO.stream.dataLength = (OD_size_t)SDO_C->sizeTran; } /* Indicate OD data size, if necessary. Used for EOF check. */ else if (sizeInOd == 0) { - SDO_C->OD_IO.stream.dataLength = SDO_C->sizeTran; + SDO_C->OD_IO.stream.dataLength = (OD_size_t)SDO_C->sizeTran; } /* Verify if size of data downloaded matches data size in OD. */ else if (SDO_C->sizeTran != sizeInOd) { @@ -619,7 +619,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* write data to Object Dictionary */ if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } ODR_t odRet = SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, - count, &countWritten); + (OD_size_t)count, &countWritten); if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } /* verify for errors in write */ @@ -910,7 +910,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED /* segmented transfer, indicate data size */ if (SDO_C->sizeInd > 0) { - uint32_t size = CO_SWAP_32(SDO_C->sizeInd); + uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); SDO_C->CANtxBuff->data[0] |= 0x01; memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); } @@ -946,7 +946,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* SDO command specifier */ - SDO_C->CANtxBuff->data[0] = SDO_C->toggle | ((7 - count) << 1); + SDO_C->CANtxBuff->data[0] = (uint8_t)(SDO_C->toggle | ((7 - count) << 1)); /* is end of transfer? Verify also sizeTran */ if (CO_fifo_getOccupied(&SDO_C->bufFifo) == 0 && !bufferPartial) { @@ -976,7 +976,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* indicate data size */ if (SDO_C->sizeInd > 0) { - uint32_t size = CO_SWAP_32(SDO_C->sizeInd); + uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); SDO_C->CANtxBuff->data[0] |= 0x02; memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); } @@ -998,7 +998,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* get up to 7 data bytes */ count = CO_fifo_altRead(&SDO_C->bufFifo, &SDO_C->CANtxBuff->data[1], 7); - SDO_C->block_noData = 7 - count; + SDO_C->block_noData = (uint8_t)(7 - count); /* verify if sizeTran is too large */ SDO_C->sizeTran += count; @@ -1204,7 +1204,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, * use maximum SDO client buffer size. Prepare temp buffer. */ OD_size_t countData = SDO_C->OD_IO.stream.dataLength; OD_size_t countBuf = (countData > 0 && countData <= countFifo) - ? countData : countFifo; + ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); @@ -1225,14 +1225,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, && (SDO_C->OD_IO.stream.attribute & ODA_STR) != 0 ) { buf[countRd] = 0; /* (buf is one byte larger) */ - OD_size_t countStr = strlen((char *)buf); + OD_size_t countStr = (OD_size_t)strlen((char *)buf); if (countStr == 0) countStr = 1; /* no zero length */ if (countStr < countRd) { /* string terminator found, finish read, shorten data */ countRd = countStr; odRet = ODR_OK; SDO_C->OD_IO.stream.dataLength = - SDO_C->sizeTran + countRd; + (OD_size_t)SDO_C->sizeTran + countRd; } } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 22e48820..d31bf9fb 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -339,7 +339,6 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, /* configure CAN identifiers and SDO server parameters if available */ uint16_t CanId_ClientToServer, CanId_ServerToClient; - uint16_t OD_SDOsrvParIdx = OD_getIndex(OD_1200_SDOsrvPar); if (OD_1200_SDOsrvPar == NULL) { /* configure default SDO channel */ @@ -349,60 +348,63 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; } - else if (OD_SDOsrvParIdx == OD_H1200_SDO_SERVER_1_PARAM) { - /* configure default SDO channel and SDO server parameters for it */ - if (nodeId < 1 || nodeId > 127) return CO_ERROR_ILLEGAL_ARGUMENT; - - CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; - CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; - SDO->valid = true; - - OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); - OD_set_u32(OD_1200_SDOsrvPar, 2, CanId_ServerToClient, true); - } - else if (OD_SDOsrvParIdx > OD_H1200_SDO_SERVER_1_PARAM - && OD_SDOsrvParIdx <= (OD_H1200_SDO_SERVER_1_PARAM + 0x7F) - ) { - /* configure additional SDO channel and SDO server parameters for it */ - uint8_t maxSubIndex; - uint32_t COB_IDClientToServer32, COB_IDServerToClient32; - - /* get and verify parameters from Object Dictionary (initial values) */ - ODR_t odRet0 = OD_get_u8(OD_1200_SDOsrvPar, 0, &maxSubIndex, true); - ODR_t odRet1 = OD_get_u32(OD_1200_SDOsrvPar, 1, - &COB_IDClientToServer32, true); - ODR_t odRet2 = OD_get_u32(OD_1200_SDOsrvPar, 2, - &COB_IDServerToClient32, true); - - if (odRet0 != ODR_OK || (maxSubIndex != 2 && maxSubIndex != 3) - || odRet1 != ODR_OK || odRet2 != ODR_OK - ) { - if (errInfo != NULL) *errInfo = OD_SDOsrvParIdx; - return CO_ERROR_OD_PARAMETERS; + else { + uint16_t OD_SDOsrvParIdx = OD_getIndex(OD_1200_SDOsrvPar); + + if (OD_SDOsrvParIdx == OD_H1200_SDO_SERVER_1_PARAM) { + /* configure default SDO channel and SDO server parameters for it */ + if (nodeId < 1 || nodeId > 127) return CO_ERROR_ILLEGAL_ARGUMENT; + + CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; + CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; + SDO->valid = true; + + OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); + OD_set_u32(OD_1200_SDOsrvPar, 2, CanId_ServerToClient, true); } + else if (OD_SDOsrvParIdx > OD_H1200_SDO_SERVER_1_PARAM + && OD_SDOsrvParIdx <= (OD_H1200_SDO_SERVER_1_PARAM + 0x7F) + ) { + /* configure additional SDO channel and SDO server parameters for it */ + uint8_t maxSubIndex; + uint32_t COB_IDClientToServer32, COB_IDServerToClient32; + + /* get and verify parameters from Object Dictionary (initial values) */ + ODR_t odRet0 = OD_get_u8(OD_1200_SDOsrvPar, 0, &maxSubIndex, true); + ODR_t odRet1 = OD_get_u32(OD_1200_SDOsrvPar, 1, + &COB_IDClientToServer32, true); + ODR_t odRet2 = OD_get_u32(OD_1200_SDOsrvPar, 2, + &COB_IDServerToClient32, true); + + if (odRet0 != ODR_OK || (maxSubIndex != 2 && maxSubIndex != 3) + || odRet1 != ODR_OK || odRet2 != ODR_OK + ) { + if (errInfo != NULL) *errInfo = OD_SDOsrvParIdx; + return CO_ERROR_OD_PARAMETERS; + } - CanId_ClientToServer = ((COB_IDClientToServer32 & 0x80000000) == 0) - ? (uint16_t)(COB_IDClientToServer32 & 0x7FF) : 0; - CanId_ServerToClient = ((COB_IDServerToClient32 & 0x80000000) == 0) - ? (uint16_t)(COB_IDServerToClient32 & 0x7FF) : 0; - -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC - SDO->OD_1200_extension.object = SDO; - SDO->OD_1200_extension.read = OD_readOriginal; - SDO->OD_1200_extension.write = OD_write_1201_additional; - ODR_t odRetE = OD_extension_init(OD_1200_SDOsrvPar, - &SDO->OD_1200_extension); - if (odRetE != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_SDOsrvParIdx; - return CO_ERROR_OD_PARAMETERS; + CanId_ClientToServer = ((COB_IDClientToServer32 & 0x80000000) == 0) + ? (uint16_t)(COB_IDClientToServer32 & 0x7FF) : 0; + CanId_ServerToClient = ((COB_IDServerToClient32 & 0x80000000) == 0) + ? (uint16_t)(COB_IDServerToClient32 & 0x7FF) : 0; + + #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC + SDO->OD_1200_extension.object = SDO; + SDO->OD_1200_extension.read = OD_readOriginal; + SDO->OD_1200_extension.write = OD_write_1201_additional; + ODR_t odRetE = OD_extension_init(OD_1200_SDOsrvPar, + &SDO->OD_1200_extension); + if (odRetE != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_SDOsrvParIdx; + return CO_ERROR_OD_PARAMETERS; + } + #endif + } + else { + return CO_ERROR_ILLEGAL_ARGUMENT; } -#endif - } - else { - return CO_ERROR_ILLEGAL_ARGUMENT; } - CO_FLAG_CLEAR(SDO->CANrxNew); /* store the parameters and configure CANrx and CANtx */ @@ -620,7 +622,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* if data is string, send only data up to null termination */ if (countRd > 0 && (SDO->OD_IO.stream.attribute & ODA_STR) != 0) { bufShifted[countRd] = 0; /* (SDO->buf is one byte larger) */ - OD_size_t countStr = strlen((char *)bufShifted); + OD_size_t countStr = (OD_size_t)strlen((char *)bufShifted); if (countStr == 0) countStr = 1; /* zero length is not allowed */ if (countStr < countRd) { /* string terminator found, read is finished, shorten data */ @@ -1070,7 +1072,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* verify, if there is enough data */ - if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize*7) { + if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize*7U) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; } @@ -1260,7 +1262,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* data were already loaded from OD variable */ if (SDO->sizeInd > 0 && SDO->sizeInd <= 4) { /* expedited transfer */ - SDO->CANtxBuff->data[0] = 0x43 | ((4 - SDO->sizeInd) << 2); + SDO->CANtxBuff->data[0] = (uint8_t)(0x43 | ((4 - SDO->sizeInd) << 2)); memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, sizeof(SDO->sizeInd)); SDO->state = CO_SDO_ST_IDLE; @@ -1512,7 +1514,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, count); SDO->bufOffsetRd += count; - SDO->block_noData = 7 - count; + SDO->block_noData = (uint8_t)(7 - count); SDO->sizeTran += count; /* verify if sizeTran is too large or too short if last segment */ diff --git a/301/CO_fifo.h b/301/CO_fifo.h index b7034140..c2413655 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -136,9 +136,9 @@ static inline bool_t CO_fifo_purge(CO_fifo_t *fifo) { * @return number of available bytes */ static inline size_t CO_fifo_getSpace(CO_fifo_t *fifo) { - int sizeLeft = (int)fifo->readPtr - fifo->writePtr - 1; + int sizeLeft = (int)fifo->readPtr - (int)fifo->writePtr - 1; if (sizeLeft < 0) { - sizeLeft += fifo->bufSize; + sizeLeft += (int)fifo->bufSize; } return (size_t) sizeLeft; @@ -153,9 +153,9 @@ static inline size_t CO_fifo_getSpace(CO_fifo_t *fifo) { * @return number of occupied bytes */ static inline size_t CO_fifo_getOccupied(CO_fifo_t *fifo) { - int sizeOccupied = (int)fifo->writePtr - fifo->readPtr; + int sizeOccupied = (int)fifo->writePtr - (int)fifo->readPtr; if (sizeOccupied < 0) { - sizeOccupied += fifo->bufSize; + sizeOccupied += (int)fifo->bufSize; } return (size_t) sizeOccupied; @@ -295,9 +295,9 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc); * @return number of occupied bytes. */ static inline size_t CO_fifo_altGetOccupied(CO_fifo_t *fifo) { - int sizeOccupied = (int)fifo->writePtr - fifo->altReadPtr; + int sizeOccupied = (int)fifo->writePtr - (int)fifo->altReadPtr; if (sizeOccupied < 0) { - sizeOccupied += fifo->bufSize; + sizeOccupied += (int)fifo->bufSize; } return (size_t) sizeOccupied; diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 9a624e61..60721712 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -129,10 +129,10 @@ CO_ReturnError_t CO_LSSmaster_init( uint16_t timeout_ms, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, - uint32_t CANidLssSlave, + uint16_t CANidLssSlave, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, - uint32_t CANidLssMaster) + uint16_t CANidLssMaster) { CO_ReturnError_t ret = CO_ERROR_NO; diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 8be043d9..68028095 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -158,10 +158,10 @@ CO_ReturnError_t CO_LSSmaster_init( uint16_t timeout_ms, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, - uint32_t CANidLssSlave, + uint16_t CANidLssSlave, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, - uint32_t CANidLssMaster); + uint16_t CANidLssMaster); /** * Change LSS master timeout diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 72c7c2ea..ee2e5010 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -199,10 +199,10 @@ CO_ReturnError_t CO_LSSslave_init( uint8_t *pendingNodeID, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, - uint32_t CANidLssMaster, + uint16_t CANidLssMaster, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, - uint32_t CANidLssSlave) + uint16_t CANidLssSlave) { CO_ReturnError_t ret = CO_ERROR_NO; diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index 2b500b2f..5593e7d4 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -164,10 +164,10 @@ CO_ReturnError_t CO_LSSslave_init( uint8_t *pendingNodeID, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, - uint32_t CANidLssMaster, + uint16_t CANidLssMaster, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, - uint32_t CANidLssSlave); + uint16_t CANidLssSlave); /** * Process LSS communication diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index cb5642c0..4922f354 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -485,7 +485,7 @@ static void responseWithError(CO_GTWA_t *gtwa, for (i = 0; i < len; i++) { const errorDescs_t *ed = &errorDescs[i]; - if(ed->code == respErrorCode) { + if((CO_GTWA_respErrorCode_t)ed->code == respErrorCode) { desc = ed->desc; } } @@ -507,7 +507,7 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, for (i = 0; i < len; i++) { const errorDescs_t *ed = &errorDescsSDO[i]; - if(ed->code == abortCode) { + if((CO_SDO_abortCode_t)ed->code == abortCode) { desc = ed->desc; } } @@ -605,7 +605,7 @@ static inline void convertToLower(char *token, size_t maxCount) { if (*c == 0) { break; } else { - *c = tolower((int)*c); + *c = (char)tolower((int)*c); } c++; } @@ -1404,7 +1404,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (closed == 0) { /* more arguments follow */ CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - gtwa->lssNID = getU32(tok, 1, 127, &err); + gtwa->lssNID = (uint8_t)getU32(tok, 1, 127, &err); if (err) break; closed = -1; From 5e089ea025cf9b3bda0440687123b759fbb8cf66 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 May 2021 11:26:40 +0200 Subject: [PATCH 181/520] Add missing NULL protection. --- 301/CO_ODinterface.h | 7 ++++--- CANopen.h | 2 +- example/CO_driver_blank.c | 6 ++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index aa12b796..00c2e22e 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -435,7 +435,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, * @return OD index */ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { - return entry->index; + return (entry != NULL) ? entry->index : 0; } @@ -450,7 +450,8 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { * @return true, if OD variable is mappable. */ static inline bool_t OD_mappable(OD_stream_t *stream) { - return (stream->attribute & (ODA_TRPDO | ODA_TRSRDO)) != 0; + return (stream != NULL) + ? (stream->attribute & (ODA_TRPDO | ODA_TRSRDO)) != 0 : false; } @@ -464,7 +465,7 @@ static inline bool_t OD_mappable(OD_stream_t *stream) { * @param stream Object Dictionary stream object. */ static inline void OD_rwRestart(OD_stream_t *stream) { - stream->dataOffset = 0; + if (stream != NULL) stream->dataOffset = 0; } diff --git a/CANopen.h b/CANopen.h index ecf3ba43..c3819f1b 100644 --- a/CANopen.h +++ b/CANopen.h @@ -492,7 +492,7 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, * If it is unconfigured, then some CANopen objects will not be initialized nor * processed. * @param [out] errInfo Additional information in case of error, may be NULL. - * errInfo can also be set in noncritical errors, where function returns + * errInfo can also be set in noncritical errors, where function returns * CO_ERROR_NO. For example, if OD parameter contains wrong value. * * @return CO_ERROR_NO in case of success. diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index 1cd404a7..9d29edbf 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -113,8 +113,10 @@ CO_ReturnError_t CO_CANmodule_init( /******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){ - /* turn off the module */ +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) { + if (CANmodule != NULL) { + /* turn off the module */ + } } From 67a1ed751260ef550ab8d0e02af81446a546fb7c Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 May 2021 11:34:11 +0200 Subject: [PATCH 182/520] Storage update --- 301/CO_storage.c | 4 +- 301/CO_storage.h | 2 + socketCAN/CO_driver_target.h | 12 +++--- socketCAN/CO_main_basic.c | 75 +++++++++++++++++++++--------------- socketCAN/CO_storageLinux.c | 6 ++- socketCAN/CO_storageLinux.h | 1 - 6 files changed, 57 insertions(+), 43 deletions(-) diff --git a/301/CO_storage.c b/301/CO_storage.c index 57d553f6..503101f1 100644 --- a/301/CO_storage.c +++ b/301/CO_storage.c @@ -43,7 +43,7 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, CO_storage_t *storage = stream->object; - if (stream->subIndex == 0 || storage->store == NULL) { + if (stream->subIndex == 0 || storage->store == NULL || !storage->enabled) { return ODR_READONLY; } @@ -93,7 +93,7 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, CO_storage_t *storage = stream->object; - if (stream->subIndex == 0 || storage->restore == NULL) { + if (stream->subIndex == 0 || storage->restore == NULL || !storage->enabled){ return ODR_READONLY; } diff --git a/301/CO_storage.h b/301/CO_storage.h index d977c5a8..b80be725 100644 --- a/301/CO_storage.h +++ b/301/CO_storage.h @@ -111,6 +111,8 @@ typedef struct { CO_CANmodule_t *CANmodule); /**< From CO_storage_init() */ CO_storage_entry_t *entries; /**< From CO_storage_init() */ uint8_t entriesCount; /**< From CO_storage_init() */ + bool_t enabled; /**< true, if storage is enabled. Setting of this variable + is implementation specific. */ } CO_storage_t; diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h index d9622da2..919c3d3a 100644 --- a/socketCAN/CO_driver_target.h +++ b/socketCAN/CO_driver_target.h @@ -352,12 +352,12 @@ typedef struct { #ifdef CO_SINGLE_THREAD -#define CO_LOCK_CAN_SEND(CAN_MODULE) -#define CO_UNLOCK_CAN_SEND(CAN_MODULE) -#define CO_LOCK_EMCY(CAN_MODULE) -#define CO_UNLOCK_EMCY(CAN_MODULE) -#define CO_LOCK_OD(CAN_MODULE) -#define CO_UNLOCK_OD(CAN_MODULE) +#define CO_LOCK_CAN_SEND(CAN_MODULE) {(void) CAN_MODULE;} +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) {(void) CAN_MODULE;} +#define CO_LOCK_EMCY(CAN_MODULE) {(void) CAN_MODULE;} +#define CO_UNLOCK_EMCY(CAN_MODULE) {(void) CAN_MODULE;} +#define CO_LOCK_OD(CAN_MODULE) {(void) CAN_MODULE;} +#define CO_UNLOCK_OD(CAN_MODULE) {(void) CAN_MODULE;} #define CO_MemoryBarrier() #else diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c index faacf13d..7358051e 100644 --- a/socketCAN/CO_main_basic.c +++ b/socketCAN/CO_main_basic.c @@ -106,13 +106,22 @@ /* CANopen object */ CO_t *CO = NULL; -/* Configurable CAN bit-rate and CANopen node-id, store-able to non-volatile - * memory. Can be set by argument and changed by LSS slave. */ -typedef struct { uint16_t bitRate; uint8_t nodeId; } CO_pending_t; -CO_pending_t CO_pending = { .bitRate = 0, .nodeId = CO_LSS_NODE_ID_ASSIGNMENT }; -/* Active node-id, copied from CO_pending.nodeId in the communication reset */ +/* Active node-id, copied from pendingNodeId in the communication reset */ static uint8_t CO_activeNodeId = CO_LSS_NODE_ID_ASSIGNMENT; +/* Data block for mainline data, which can be stored to non-volatile memory */ +typedef struct { + /* Pending CAN bit rate, can be set by argument or LSS slave. */ + uint16_t pendingBitRate; + /* Pending CANopen NodeId, can be set by argument or LSS slave. */ + uint8_t pendingNodeId; +} mainlineStorage_t; + +mainlineStorage_t mlStorage = { + .pendingBitRate = 0, + .pendingNodeId = CO_LSS_NODE_ID_ASSIGNMENT +}; + #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE static CO_time_t CO_time; /* Object for current time */ #endif @@ -212,9 +221,9 @@ static void HeartbeatNmtChangedCallback(uint8_t nodeId, uint8_t idx, /* callback for storing node id and bitrate */ static bool_t LSScfgStoreCallback(void *object, uint8_t id, uint16_t bitRate) { - (void)object; - CO_pending.nodeId = id; - CO_pending.bitRate = bitRate; + mainlineStorage_t *mainlineStorage = object; + mainlineStorage->pendingNodeId = id; + mainlineStorage->pendingBitRate = bitRate; return true; } @@ -276,7 +285,7 @@ int main (int argc, char *argv[]) { bool_t firstRun = true; char* CANdevice = NULL; /* CAN device, configurable by arguments. */ - bool_t nodeIdFromArgs = false; /* True, if program arguments are used for CANopen Node Id */ + int16_t nodeIdFromArgs = -1; /* May be set by arguments */ bool_t rebootEnable = false; /* Configurable by arguments */ #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE @@ -291,11 +300,12 @@ int main (int argc, char *argv[]) { '.','p','e','r','s','i','s','t','\0'} }, { - .addr = &CO_pending, - .len = sizeof(CO_pending), + .addr = &mlStorage, + .len = sizeof(mlStorage), .subIndexOD = 4, .attr = CO_storage_cmd | CO_storage_auto | CO_storage_restore, - .filename = {'l','s','s','.','p','e','r','s','i','s','t','\0'} + .filename = {'m','a','i','n','l','i','n','e', + '.','p','e','r','s','i','s','t','\0'} }, CO_STORAGE_APPLICATION }; @@ -328,10 +338,12 @@ int main (int argc, char *argv[]) { } while((opt = getopt(argc, argv, "i:p:rc:T:s:")) != -1) { switch (opt) { - case 'i': - nodeIdFromArgs = true; - CO_pending.nodeId = (uint8_t)strtol(optarg, NULL, 0); + case 'i': { + long int nodeIdLong = strtol(optarg, NULL, 0); + nodeIdFromArgs = (nodeIdLong < 0 || nodeIdLong > 0xFF) + ? 0 : (uint8_t)strtol(optarg, NULL, 0); break; + } #ifndef CO_SINGLE_THREAD case 'p': rtPriority = strtol(optarg, NULL, 0); break; @@ -398,11 +410,11 @@ int main (int argc, char *argv[]) { } /* Valid NodeId is 1..127 or 0xFF(unconfigured) in case of LSSslaveEnabled*/ - if((CO_pending.nodeId < 1 || CO_pending.nodeId > 127) + if ((nodeIdFromArgs == 0 || nodeIdFromArgs > 127) && (!CO_isLSSslaveEnabled(CO) - || CO_pending.nodeId != CO_LSS_NODE_ID_ASSIGNMENT) + || nodeIdFromArgs != CO_LSS_NODE_ID_ASSIGNMENT) ) { - log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, CO_pending.nodeId); + log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, nodeIdFromArgs); printUsage(argv[0]); exit(EXIT_FAILURE); } @@ -422,7 +434,7 @@ int main (int argc, char *argv[]) { } - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_pending.nodeId, "starting"); + log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, mlStorage.pendingNodeId,"starting"); /* Allocate memory for CANopen objects */ @@ -436,7 +448,6 @@ int main (int argc, char *argv[]) { #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - uint8_t pendingNodeIdOriginal = CO_pending.nodeId; err = CO_storageLinux_init(&storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, @@ -451,12 +462,12 @@ int main (int argc, char *argv[]) { log_printf(LOG_CRIT, DBG_STORAGE, filename); exit(EXIT_FAILURE); } +#endif /* Overwrite stored node-id, if specified by program arguments */ - if (nodeIdFromArgs) { - CO_pending.nodeId = pendingNodeIdOriginal; + if (nodeIdFromArgs > 0) { + mlStorage.pendingNodeId = (uint8_t)nodeIdFromArgs; } -#endif /* Catch signals SIGINT and SIGTERM */ if(signal(SIGINT, sigHandler) == SIG_ERR) { @@ -508,8 +519,8 @@ int main (int argc, char *argv[]) { while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { - uint32_t errInfo; /* CANopen communication reset - initialize CANopen objects *******************/ + uint32_t errInfo; /* Wait rt_thread. */ if(!firstRun) { @@ -539,7 +550,7 @@ int main (int argc, char *argv[]) { .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber }}; err = CO_LSSinit(CO, &lssAddress, - &CO_pending.nodeId, &CO_pending.bitRate); + &mlStorage.pendingNodeId, &mlStorage.pendingBitRate); if(err != CO_ERROR_NO) { log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_LSSinit()", err); programExit = EXIT_FAILURE; @@ -547,7 +558,7 @@ int main (int argc, char *argv[]) { continue; } - CO_activeNodeId = CO_pending.nodeId; + CO_activeNodeId = mlStorage.pendingNodeId; errInfo = 0; err = CO_CANopenInit(CO, /* CANopen object */ @@ -579,7 +590,7 @@ int main (int argc, char *argv[]) { #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII CO_epoll_initCANopenGtw(&epGtw, CO); #endif - CO_LSSslave_initCfgStoreCallback(CO->LSSslave, NULL, + CO_LSSslave_initCfgStoreCallback(CO->LSSslave, &mlStorage, LSScfgStoreCallback); if(!CO->nodeIdUnconfigured) { if(errInfo != 0) { @@ -647,15 +658,15 @@ int main (int argc, char *argv[]) { } else { log_printf(LOG_CRIT, DBG_CAN_OPEN, "app_programStart()", err); - if(errInfo != 0 && !CO->nodeIdUnconfigured) { - CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, - CO_EMC_DATA_SET, errInfo); - } } programExit = EXIT_FAILURE; CO_endProgram = 1; continue; } + if(errInfo != 0 && !CO->nodeIdUnconfigured) { + CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, + CO_EMC_DATA_SET, errInfo); + } #endif } /* if(firstRun) */ @@ -798,7 +809,7 @@ static void* rt_thread(void* arg) { #ifdef CO_USE_APPLICATION /* Execute optional additional application code */ - app_program1ms(!CO->nodeIdUnconfigured, epRT.timeDifference_us); + app_programRt(!CO->nodeIdUnconfigured, epRT.timeDifference_us); #endif } diff --git a/socketCAN/CO_storageLinux.c b/socketCAN/CO_storageLinux.c index e2235727..cd2a55c0 100644 --- a/socketCAN/CO_storageLinux.c +++ b/socketCAN/CO_storageLinux.c @@ -1,5 +1,5 @@ /* - * CANopen Object Dictionary storage object for Linux SocketCAN. + * CANopen data storage object for Linux * * @file CO_storageLinux.c * @author Janez Paternoster @@ -38,7 +38,6 @@ * For more information see file CO_storage.h, CO_storage_entry_t. */ static ODR_t storeLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { - (void) CANmodule; ODR_t ret = ODR_OK; uint16_t crc_store; @@ -179,6 +178,8 @@ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, return CO_ERROR_ILLEGAL_ARGUMENT; } + storage->enabled = false; + /* initialize storage and OD extensions */ ret = CO_storage_init(storage, CANmodule, @@ -266,6 +267,7 @@ CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, } } /* for (entries) */ + storage->enabled = true; return ret; } diff --git a/socketCAN/CO_storageLinux.h b/socketCAN/CO_storageLinux.h index 04658997..0d92c2c5 100644 --- a/socketCAN/CO_storageLinux.h +++ b/socketCAN/CO_storageLinux.h @@ -27,7 +27,6 @@ #define CO_STORAGE_LINUX_H #include "301/CO_storage.h" -#include #if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN From 76b43c88ef6d5490cb2f1518e10646e8dcb45c76 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 5 May 2021 10:28:05 +0200 Subject: [PATCH 183/520] Create 'storage' directory, move CO_storage.h/c, add CO_storageEeeprom.h/c --- 301/CO_driver.h | 31 +++- CANopen.h | 8 + Doxyfile | 1 + Makefile | 2 +- example/CO_storageBlank.h | 13 +- example/DS301_profile.md | 4 +- example/Makefile | 2 +- socketCAN/CO_storageLinux.c | 5 +- socketCAN/CO_storageLinux.h | 2 +- storage/CO_eeprom.h | 133 +++++++++++++++++ {301 => storage}/CO_storage.c | 2 +- {301 => storage}/CO_storage.h | 16 +- storage/CO_storageEeprom.c | 268 ++++++++++++++++++++++++++++++++++ storage/CO_storageEeprom.h | 131 +++++++++++++++++ 14 files changed, 589 insertions(+), 29 deletions(-) create mode 100644 storage/CO_eeprom.h rename {301 => storage}/CO_storage.c (96%) rename {301 => storage}/CO_storage.h (88%) create mode 100644 storage/CO_storageEeprom.c create mode 100644 storage/CO_storageEeprom.h diff --git a/301/CO_driver.h b/301/CO_driver.h index 7929f185..f881b1b0 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -354,20 +354,39 @@ typedef struct { * Must be defined in the **CO_driver_target.h** file. * * For more information on Data storage see @ref CO_storage or **CO_storage.h** - * file. Structure members documented here are required. Target system shall add - * own additional, hardware specific variables. + * file. Structure members documented here are always required or required with + * @ref CO_storage_eeprom. Target system may add own additional, hardware + * specific variables. */ typedef struct { - /** Address of data to store */ + /** Address of data to store, always required. */ void *addr; - /** Length of data to store */ + /** Length of data to store, always required. */ size_t len; /** Sub index in OD objects 1010 and 1011, from 2 to 127. Writing * 0x65766173 to 1010,subIndexOD will store data to non-volatile memory. - * Writing 0x64616F6C to 1011,subIndexOD will restore default data. */ + * Writing 0x64616F6C to 1011,subIndexOD will restore default data, always + * required. */ uint8_t subIndexOD; - /** Attribute from @ref CO_storage_attributes_t */ + /** Attribute from @ref CO_storage_attributes_t, always required. */ uint8_t attr; + /** Pointer to storage module, target system specific usage, required with + * @ref CO_storage_eeprom. */ + void *storageModule; + /** CRC checksum of the data stored in eeprom, set on store, required with + * @ref CO_storage_eeprom. */ + uint16_t crc; + /** Address of entry signature inside eeprom, set by init, required with + * @ref CO_storage_eeprom. */ + size_t eepromAddrSignature; + /** Address of data inside eeprom, set by init, required with + * @ref CO_storage_eeprom. */ + size_t eepromAddr; + /** Offset of next byte being updated by automatic storage, required with + * @ref CO_storage_eeprom. */ + size_t offset; + /** Additional target specific parameters, optional. */ + void *additionalParameters; } CO_storage_entry_t; diff --git a/CANopen.h b/CANopen.h index c3819f1b..44f6be8e 100644 --- a/CANopen.h +++ b/CANopen.h @@ -147,6 +147,14 @@ extern "C" { * @} */ +/** + * @defgroup CO_CANopen_storage CANopen_storage + * @{ + * + * CANopen Object Dictionary and other data storage. + * @} + */ + /** * @defgroup CO_CANopen_extra CANopen_extra * @{ diff --git a/Doxyfile b/Doxyfile index 86c9b45c..7bfa59ce 100644 --- a/Doxyfile +++ b/Doxyfile @@ -822,6 +822,7 @@ INPUT = README.md \ 304 \ 305 \ 309 \ + storage \ extra \ socketCAN diff --git a/Makefile b/Makefile index 195008a8..081a5f95 100644 --- a/Makefile +++ b/Makefile @@ -31,13 +31,13 @@ SOURCES = \ $(CANOPEN_SRC)/301/CO_PDO.c \ $(CANOPEN_SRC)/301/crc16-ccitt.c \ $(CANOPEN_SRC)/301/CO_fifo.c \ - $(CANOPEN_SRC)/301/CO_storage.c \ $(CANOPEN_SRC)/303/CO_LEDs.c \ $(CANOPEN_SRC)/304/CO_GFC.c \ $(CANOPEN_SRC)/304/CO_SRDO.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ $(CANOPEN_SRC)/305/CO_LSSmaster.c \ $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ + $(CANOPEN_SRC)/storage/CO_storage.c \ $(CANOPEN_SRC)/extra/CO_trace.c \ $(CANOPEN_SRC)/CANopen.c \ $(APPL_SRC)/OD.c \ diff --git a/example/CO_storageBlank.h b/example/CO_storageBlank.h index de8ddf9f..5e562c6a 100644 --- a/example/CO_storageBlank.h +++ b/example/CO_storageBlank.h @@ -25,7 +25,7 @@ #ifndef CO_STORAGE_BLANK_H #define CO_STORAGE_BLANK_H -#include "301/CO_storage.h" +#include "storage/CO_storage.h" #if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN @@ -33,8 +33,15 @@ extern "C" { #endif -/* See socketCAN/storageLinux.h and 301/CO_storage.h for information and - * full example */ +/* This is very basic example of implementing (object dictionary) data storage. + * Data storage is target specific. CO_storageBlank.h and .c files only shows + * the basic principle, but does nothing. For complete example of storage see: + * - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c, + * CANopenNode/storage/CO_storageEeprom.h/.c, CANopenNode/storage/CO_eeprom.h + * and CANopenPIC/PIC32/CO_eepromPIC32.c files. + * - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and + * CANopenLinux/CO_storageLinux.h files. + */ CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, diff --git a/example/DS301_profile.md b/example/DS301_profile.md index dde64d2b..b3987c20 100644 --- a/example/DS301_profile.md +++ b/example/DS301_profile.md @@ -1,5 +1,5 @@ -CANopen documentation -===================== +CANopen device documentation +============================ **New Product** diff --git a/example/Makefile b/example/Makefile index 2783298b..531d4bfd 100644 --- a/example/Makefile +++ b/example/Makefile @@ -26,9 +26,9 @@ SOURCES = \ $(CANOPEN_SRC)/301/CO_TIME.c \ $(CANOPEN_SRC)/301/CO_SYNC.c \ $(CANOPEN_SRC)/301/CO_PDO.c \ - $(CANOPEN_SRC)/301/CO_storage.c \ $(CANOPEN_SRC)/303/CO_LEDs.c \ $(CANOPEN_SRC)/305/CO_LSSslave.c \ + $(CANOPEN_SRC)/storage/CO_storage.c \ $(CANOPEN_SRC)/CANopen.c \ $(APPL_SRC)/OD.c \ $(DRV_SRC)/main_blank.c diff --git a/socketCAN/CO_storageLinux.c b/socketCAN/CO_storageLinux.c index cd2a55c0..9f0422b2 100644 --- a/socketCAN/CO_storageLinux.c +++ b/socketCAN/CO_storageLinux.c @@ -104,9 +104,8 @@ static ODR_t storeLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { /* rename existing file to *.old and *.tmp to existing */ if (ret == ODR_OK) { - if (rename(entry->filename, filename_old) != 0 - || rename(filename_tmp, entry->filename) != 0 - ) { + rename(entry->filename, filename_old); + if (rename(filename_tmp, entry->filename) != 0) { ret = ODR_HW; } } diff --git a/socketCAN/CO_storageLinux.h b/socketCAN/CO_storageLinux.h index 0d92c2c5..54a549db 100644 --- a/socketCAN/CO_storageLinux.h +++ b/socketCAN/CO_storageLinux.h @@ -26,7 +26,7 @@ #ifndef CO_STORAGE_LINUX_H #define CO_STORAGE_LINUX_H -#include "301/CO_storage.h" +#include "storage/CO_storage.h" #if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN diff --git a/storage/CO_eeprom.h b/storage/CO_eeprom.h new file mode 100644 index 00000000..94d1b306 --- /dev/null +++ b/storage/CO_eeprom.h @@ -0,0 +1,133 @@ +/** + * Eeprom interface for use with CO_storageEeprom + * + * @file CO_eeprom.h + * @ingroup CO_storage_eeprom + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CO_EEPROM_H +#define CO_EEPROM_H + +#include "301/CO_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup CO_storage_eeprom + * @{ + */ + +/** + * Initialize eeprom device, target system specific function. + * + * @param storageModule Pointer to storage module. + * + * @return True on success + */ +bool_t CO_eeprom_init(void *storageModule); + + +/** + * Get free address inside eeprom, target system specific function. + * + * Function is called several times for each storage block in the initialization + * phase after CO_eeprom_init(). + * + * @param storageModule Pointer to storage module. + * @param isAuto True, if variable is auto stored or false if protected + * @param len Length of data, which will be stored to that location + * @param [out] overflow set to true, if not enough eeprom memory + * + * @return Asigned eeprom address + */ +size_t CO_eeprom_getAddr(void *storageModule, bool_t isAuto, + size_t len, bool_t *overflow); + + +/** + * Read block of data from the eeprom, target system specific function. + * + * @param storageModule Pointer to storage module. + * @param data Pointer to data buffer, where data will be stored. + * @param eepromAddr Address in eeprom, from where data will be read. + * @param len Length of the data block to be read. + */ +void CO_eeprom_readBlock(void *storageModule, uint8_t *data, + size_t eepromAddr, size_t len); + + +/** + * Write block of data to the eeprom, target system specific function. + * + * It is blocking function, so it waits, until all data is written. + * + * @param storageModule Pointer to storage module. + * @param data Pointer to data buffer which will be written. + * @param eepromAddr Address in eeprom, where data will be written. If data is + * stored accross multiple pages, address must be aligned with page. + * @param len Length of the data block. + * + * @return true on success + */ +bool_t CO_eeprom_writeBlock(void *storageModule, uint8_t *data, + size_t eepromAddr, size_t len); + + +/** + * Get CRC checksum of the block of data stored in the eeprom, target system + * specific function. + * + * @param storageModule Pointer to storage module. + * @param eepromAddr Address of data in eeprom. + * @param len Length of the data. + * + * @return CRC checksum + */ +uint16_t CO_eeprom_getCrcBlock(void *storageModule, + size_t eepromAddr, size_t len); + + +/** + * Update one byte of data in the eeprom, target system specific function. + * + * Function is used by automatic storage. It updates byte in eeprom only if + * differs from data. + * + * @param storageModule Pointer to storage module. + * @param data Data byte to be written + * @param eepromAddr Address in eeprom, from where data will be updated. + * + * @return true if write was successful or false, if still waiting previous + * data to finish writing. + */ +bool_t CO_eeprom_updateByte(void *storageModule, uint8_t data, + size_t eepromAddr); + + +/** @} */ /* CO_storage_eeprom */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CO_EEPROM_H */ diff --git a/301/CO_storage.c b/storage/CO_storage.c similarity index 96% rename from 301/CO_storage.c rename to storage/CO_storage.c index 503101f1..b69f172a 100644 --- a/301/CO_storage.c +++ b/storage/CO_storage.c @@ -22,7 +22,7 @@ * limitations under the License. */ -#include "301/CO_storage.h" +#include "storage/CO_storage.h" #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE diff --git a/301/CO_storage.h b/storage/CO_storage.h similarity index 88% rename from 301/CO_storage.h rename to storage/CO_storage.h index b80be725..36b4d8f5 100644 --- a/301/CO_storage.h +++ b/storage/CO_storage.h @@ -41,8 +41,8 @@ extern "C" { #endif /** - * @defgroup CO_storage Data storage - * @ingroup CO_CANopen_301 + * @defgroup CO_storage Data storage base + * @ingroup CO_CANopen_storage * @{ * * CANopen provides OD objects 0x1010 and 0x1011 for control of storing and @@ -138,15 +138,9 @@ typedef struct { * @ref ODR_t : "ODR_OK" in case of success, "ODR_HW" in case of hardware error. * @param restore Same as 'store', but for restoring default data. * @param entries Pointer to array of storage entries. Array must be defined and - * initialized by application and must exist permanently. Each array element - * contains: - * - Pointer and length of data, which will be stored or restored, - * - subIndexOD, which binds entry to specific subindex in 1010 and 1011 OD - * objects. Multiple entries with the same subIndexOD are possible. - * - Attribute, which specifies, if data is stored on command or automatically - * and also specifies if data is able to restore. @ref CO_storage_attributes_t - * - Additional target specific parameters. See @ref CO_storage_entry_t in - * CO_driver_target.h file. + * initialized by application and must exist permanently. + * Structure @ref CO_storage_entry_t is target specific and must be defined by + * CO_driver_target.h. See CO_driver.h for required parameters. * @param entriesCount Count of storage entries * * @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c new file mode 100644 index 00000000..e49cd35c --- /dev/null +++ b/storage/CO_storageEeprom.c @@ -0,0 +1,268 @@ +/* + * CANopen data storage object for storing data into block device (eeprom) + * + * @file CO_storageEeprom.c + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "storage/CO_storageEeprom.h" +#include "storage/CO_eeprom.h" +#include "301/crc16-ccitt.h" + +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + +/* + * Function for writing data on "Store parameters" command - OD object 1010 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t storeEeprom(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { + bool_t writeOk; + + /* save data to the eeprom */ + CO_LOCK_OD(CANmodule); + writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr, + entry->eepromAddr, entry->len); + entry->crc = crc16_ccitt(entry->addr, entry->len, 0); + CO_UNLOCK_OD(CANmodule); + + /* Verify, if data in eeprom are equal */ + uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, + entry->eepromAddr, entry->len); + if (entry->crc != crc_read || !writeOk) { + return ODR_HW; + } + + /* Write signature (see CO_storageEeprom_init() for info) */ + uint16_t signatureOfEntry = (uint16_t)entry->len; + uint32_t signature = (((uint32_t)entry->crc) << 16) | signatureOfEntry; + writeOk = CO_eeprom_writeBlock(entry->storageModule, + (uint8_t *)&signature, + entry->eepromAddrSignature, + sizeof(signature)); + + /* verify signature and write */ + uint32_t signatureRead; + CO_eeprom_readBlock(entry->storageModule, + (uint8_t *)&signatureRead, + entry->eepromAddrSignature, + sizeof(signatureRead)); + if(signature != signatureRead || !writeOk) { + return ODR_HW; + } + + return ODR_OK; +} + + +/* + * Function for restoring data on "Restore default parameters" command - OD 1011 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t restoreEeprom(CO_storage_entry_t *entry, + CO_CANmodule_t *CANmodule) +{ + (void) CANmodule; + bool_t writeOk; + + /* Write empty signature */ + uint32_t signature = 0xFFFFFFFF; + writeOk = CO_eeprom_writeBlock(entry->storageModule, + (uint8_t *)&signature, + entry->eepromAddrSignature, + sizeof(signature)); + + /* verify signature and protection */ + uint32_t signatureRead; + CO_eeprom_readBlock(entry->storageModule, + (uint8_t *)&signatureRead, + entry->eepromAddrSignature, + sizeof(signatureRead)); + if(signature != signatureRead || !writeOk) { + return ODR_HW; + } + + return ODR_OK; +} + + +/******************************************************************************/ +CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, + CO_CANmodule_t *CANmodule, + void *storageModule, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, + uint8_t entriesCount, + uint32_t *storageInitError) +{ + CO_ReturnError_t ret; + bool_t eepromOvf = false; + + /* verify arguments */ + if (storage == NULL || entries == NULL || entriesCount == 0 + || storageInitError == NULL + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + storage->enabled = false; + + /* Initialize storage hardware */ + if (!CO_eeprom_init(storageModule)) { + *storageInitError = 0xFFFFFFFF; + return CO_ERROR_DATA_CORRUPT; + } + + /* initialize storage and OD extensions */ + ret = CO_storage_init(storage, + CANmodule, + OD_1010_StoreParameters, + OD_1011_RestoreDefaultParam, + storeEeprom, + restoreEeprom, + entries, + entriesCount); + if (ret != CO_ERROR_NO) { + return ret; + } + + /* Read entry signatures from the eeprom */ + uint32_t signatures[entriesCount]; + size_t signaturesAddress = CO_eeprom_getAddr(storageModule, + false, + sizeof(signatures), + &eepromOvf); + CO_eeprom_readBlock(storageModule, + (uint8_t *)signatures, + signaturesAddress, + sizeof(signatures)); + + /* initialize entries */ + *storageInitError = 0; + for (uint8_t i = 0; i < entriesCount; i++) { + CO_storage_entry_t *entry = &entries[i]; + bool_t isAuto = (entry->attr & CO_storage_auto) != 0; + + /* verify arguments */ + if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { + *storageInitError = i; + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* calculate addresses inside eeprom */ + entry->eepromAddrSignature = signaturesAddress + sizeof(uint32_t) * i; + entry->eepromAddr = CO_eeprom_getAddr(storageModule, + isAuto, + entry->len, + &eepromOvf); + entry->offset = 0; + + /* verify if eeprom is too small */ + if (eepromOvf) { + *storageInitError = i; + return CO_ERROR_OUT_OF_MEMORY; + } + + /* 32bit signature (which was stored in eeprom) is combined from + * 16bit signature of the entry and 16bit CRC checksum of the data + * block. 16bit signature of the entry is entry->len. */ + uint32_t signature = signatures[i]; + uint16_t signatureInEeprom = (uint16_t)signature; + entry->crc = (uint16_t)(signature >> 16); + uint16_t signatureOfEntry = (uint16_t)entry->len; + + /* Verify two signatures */ + bool_t dataCorrupt = false; + if (signatureInEeprom != signatureOfEntry) { + dataCorrupt = true; + } + else { + /* Read data into storage location */ + CO_eeprom_readBlock(entry->storageModule, entry->addr, + entry->eepromAddr, entry->len); + + /* Verify CRC, except for auto storage variables */ + if (!isAuto) { + uint16_t crc = crc16_ccitt(entry->addr, entry->len, 0); + if (crc != entry->crc) { + dataCorrupt = true; + } + } + } + + /* additional info in case of error */ + if (dataCorrupt) { + uint32_t errorBit = entry->subIndexOD; + if (errorBit > 31) errorBit = 31; + *storageInitError |= ((uint32_t) 1) << errorBit; + ret = CO_ERROR_DATA_CORRUPT; + } + } /* for (entries) */ + + storage->enabled = true; + return ret; +} + + +/******************************************************************************/ +void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { + /* verify arguments */ + if (storage == NULL || !storage->enabled) { + return; + } + + /* loop through entries */ + for (uint8_t i = 0; i < storage->entriesCount; i++) { + CO_storage_entry_t *entry = &storage->entries[i]; + + if ((entry->attr & CO_storage_auto) == 0) + continue; + + if (saveAll) { + /* update all bytes */ + for (size_t i = 0; i < entry->len; ) { + uint8_t dataByteToUpdate = ((uint8_t *)(entry->addr))[i]; + size_t eepromAddr = entry->eepromAddr + i; + if (CO_eeprom_updateByte(entry->storageModule, + dataByteToUpdate, + eepromAddr) + ) { + i++; + } + } + } + else { + /* update one data byte and if successful increment to next */ + uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[entry->offset]; + size_t eepromAddr = entry->eepromAddr + entry->offset; + if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, + eepromAddr) + ) { + if (++entry->offset >= entry->len) { + entry->offset = 0; + } + } + } + } +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h new file mode 100644 index 00000000..dcb3de11 --- /dev/null +++ b/storage/CO_storageEeprom.h @@ -0,0 +1,131 @@ +/** + * CANopen data storage object for storing data into block device (eeprom) + * + * @file CO_storageEeprom.h + * @ingroup CO_storage_eeprom + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CO_STORAGE_EEPROM_H +#define CO_STORAGE_EEPROM_H + +#include "storage/CO_storage.h" + +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_storage_eeprom Data storage in eeprom + * @ingroup CO_CANopen_storage + * @{ + * + * This is an interface into generic CANopenNode @ref CO_storage for usage with + * eeprom chip like 25LC256. Functions @ref CO_storageEeprom_init() and + * @ref CO_storageEeprom_auto_process are target system independent. Functions + * specified by @ref CO_eeprom.h file, must be defined by target system. + * For example implementation see CANopenPIC/PIC32. + * + * Storage principle: + * This function first reads 'signatures' for all entries from the known address + * from the eeprom. If signature for each entry is correct, then data is read + * from correct address from the eeprom into storage location. If signature is + * wrong, then data for that entry is indicated as corrupt and CANopen + * emergency message is sent. + * + * Signature also includes 16-bit CRC checksum of the data stored in eeprom. If + * it differs from CRC checksum calculated from the data actually loaded (on + * program startup), then entry is indicated as corrupt and CANopen emergency + * message is sent. + * + * Signature is written to eeprom, when data block is stored via CANopen SDO + * write command to object 0x1010. Signature is erased, with CANopen SDO write + * command to object 0x1011. If signature is not valid or is erased for any + * entry, emergency message is sent. If eeprom is new, then all signatures are + * wrong, so it is best to store all parameters by writing to 0x1010, sub 1. + * + * If entry attribute has CO_storage_auto set, then data block is stored + * autonomously, byte by byte, on change, during program run. Those data blocks + * are stored into write unprotected location. For auto storage to work, + * its signature in eeprom must be correct. CRC checksum for the data is not + * used. + */ + + +/** + * Initialize data storage object (block device (eeprom) specific) + * + * This function should be called by application after the program startup, + * before @ref CO_CANopenInit(). This function initializes storage object, + * OD extensions on objects 1010 and 1011, reads data from file, verifies them + * and writes data to addresses specified inside entries. This function + * internally calls @ref CO_storage_init(). + * + * @param storage This object will be initialized. It must be defined by + * application and must exist permanently. + * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. + * @param storageModule Pointer to storage module passed to CO_eeprom functions. + * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". + * Entry is optional, may be NULL. + * @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default + * parameters". Entry is optional, may be NULL. + * @param entries Pointer to array of storage entries, see @ref CO_storage_init. + * @param entriesCount Count of storage entries + * @param [out] storageInitError If function returns CO_ERROR_DATA_CORRUPT, + * then this variable contains a bit mask from subIndexOD values, where data + * was not properly initialized. If other error, then this variable contains + * index or erroneous entry. If there is hardware error like missing eeprom, + * then storageInitError is 0xFFFFFFFF and function returns + * CO_ERROR_DATA_CORRUPT. + * + * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if data can not be initialized, + * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY. + */ +CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, + CO_CANmodule_t *CANmodule, + void *storageModule, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, + uint8_t entriesCount, + uint32_t *storageInitError); + + +/** + * Automatically update data if differs inside eeprom. + * + * Should be called cyclically by program. Each interval it updates one byte. + * + * @param storage This object + * @param saveAll If true, all bytes are updated, useful on program end. + */ +void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll); + +/** @} */ /* CO_storage_eeprom */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +#endif /* CO_STORAGE_EEPROM_H */ From d9af9b04d0318e5237cec3d72bb223078f87205c Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 7 May 2021 23:00:14 +0200 Subject: [PATCH 184/520] Driver for Linux (socketCAN directory) moved to own repository. New repository is https://github.com/CANopenNode/CANopenLinux. --- Makefile | 76 --- README.md | 16 +- doc/CHANGELOG.md | 2 + doc/deviceSupport.md | 14 +- socketCAN/CO_driver.c | 992 --------------------------------- socketCAN/CO_driver_target.h | 491 ---------------- socketCAN/CO_epoll_interface.c | 698 ----------------------- socketCAN/CO_epoll_interface.h | 309 ---------- socketCAN/CO_error.c | 311 ----------- socketCAN/CO_error.h | 191 ------- socketCAN/CO_error_msgs.h | 98 ---- socketCAN/CO_main_basic.c | 819 --------------------------- socketCAN/CO_storageLinux.c | 321 ----------- socketCAN/CO_storageLinux.h | 106 ---- 14 files changed, 14 insertions(+), 4430 deletions(-) delete mode 100644 Makefile delete mode 100644 socketCAN/CO_driver.c delete mode 100644 socketCAN/CO_driver_target.h delete mode 100644 socketCAN/CO_epoll_interface.c delete mode 100644 socketCAN/CO_epoll_interface.h delete mode 100644 socketCAN/CO_error.c delete mode 100644 socketCAN/CO_error.h delete mode 100644 socketCAN/CO_error_msgs.h delete mode 100644 socketCAN/CO_main_basic.c delete mode 100644 socketCAN/CO_storageLinux.c delete mode 100644 socketCAN/CO_storageLinux.h diff --git a/Makefile b/Makefile deleted file mode 100644 index 081a5f95..00000000 --- a/Makefile +++ /dev/null @@ -1,76 +0,0 @@ -# Makefile for CANopenNode with Linux socketCAN - - -DRV_SRC = socketCAN -CANOPEN_SRC = . -APPL_SRC = example - - -LINK_TARGET = canopend - - -INCLUDE_DIRS = \ - -I$(DRV_SRC) \ - -I$(CANOPEN_SRC) \ - -I$(APPL_SRC) - - -SOURCES = \ - $(DRV_SRC)/CO_driver.c \ - $(DRV_SRC)/CO_error.c \ - $(DRV_SRC)/CO_epoll_interface.c \ - $(DRV_SRC)/CO_storageLinux.c \ - $(CANOPEN_SRC)/301/CO_ODinterface.c \ - $(CANOPEN_SRC)/301/CO_NMT_Heartbeat.c \ - $(CANOPEN_SRC)/301/CO_HBconsumer.c \ - $(CANOPEN_SRC)/301/CO_Emergency.c \ - $(CANOPEN_SRC)/301/CO_SDOserver.c \ - $(CANOPEN_SRC)/301/CO_SDOclient.c \ - $(CANOPEN_SRC)/301/CO_TIME.c \ - $(CANOPEN_SRC)/301/CO_SYNC.c \ - $(CANOPEN_SRC)/301/CO_PDO.c \ - $(CANOPEN_SRC)/301/crc16-ccitt.c \ - $(CANOPEN_SRC)/301/CO_fifo.c \ - $(CANOPEN_SRC)/303/CO_LEDs.c \ - $(CANOPEN_SRC)/304/CO_GFC.c \ - $(CANOPEN_SRC)/304/CO_SRDO.c \ - $(CANOPEN_SRC)/305/CO_LSSslave.c \ - $(CANOPEN_SRC)/305/CO_LSSmaster.c \ - $(CANOPEN_SRC)/309/CO_gateway_ascii.c \ - $(CANOPEN_SRC)/storage/CO_storage.c \ - $(CANOPEN_SRC)/extra/CO_trace.c \ - $(CANOPEN_SRC)/CANopen.c \ - $(APPL_SRC)/OD.c \ - $(DRV_SRC)/CO_main_basic.c - - -OBJS = $(SOURCES:%.c=%.o) -CC ?= gcc -OPT = -OPT += -g -#OPT += -O2 -OPT += -DCO_SINGLE_THREAD -#OPT += -DCO_CONFIG_DEBUG=0xFFFF -#OPT += -Wextra -Wshadow -pedantic -fanalyzer -#OPT += -DCO_USE_GLOBALS -#OPT += -DCO_MULTIPLE_OD -CFLAGS = -Wall $(OPT) $(INCLUDE_DIRS) -LDFLAGS = -LDFLAGS += -g -#LDFLAGS += -pthread - -#Options can be also passed via make: 'make OPT="-g" LDFLAGS="-pthread"' - - -.PHONY: all clean - -all: clean $(LINK_TARGET) - -clean: - rm -f $(OBJS) $(LINK_TARGET) - -%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ - -$(LINK_TARGET): $(OBJS) - $(CC) $(LDFLAGS) $^ -o $@ diff --git a/README.md b/README.md index 7fbe12d5..4db53547 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,10 @@ File structure - **CO_LSSslave.h/.c** - CANopen Layer Setting Service - slave protocol. - **309/** - CANopen access from other networks. - **CO_gateway_ascii.h/.c** - Ascii mapping: NMT master, LSS master, SDO client. + - **storage/** + - **CO_OD_storage.h/.c** - CANopen data storage base object. + - **CO_storageEeprom.h/.c** - CANopen data storage object for storing data into block device (eeprom). + - **CO_eeprom.h** - Eeprom interface for use with CO_storageEeprom, functions are target system specific. - **extra/** - **CO_trace.h/.c** - CANopen trace object for recording variables over time. - **example/** - Directory with basic example, should compile on any system. @@ -167,14 +171,6 @@ File structure markdown documentation file, automatically generated from DS301_profile.xpd. - **OD.h/.c** - CANopen Object dictionary source files, automatically generated from DS301_profile.xpd. - - **socketCAN/** - Directory for Linux socketCAN interface. - - **CO_driver_target.h** - Linux socketCAN specific definitions for CANopenNode. - - **CO_driver.c** - Interface between Linux socketCAN and CANopenNode. - - **CO_error.h/.c** - Linux socketCAN Error handling object. - - **CO_error_msgs.h** - Error definition strings and logging function. - - **CO_epoll_interface.h/.c** - Helper functions for Linux epoll interface to CANopenNode. - - **CO_OD_storage.h/.c** - Object Dictionary storage object for Linux SocketCAN. - - **CO_main_basic.c** - Mainline for socketCAN (basic usage). - **doc/** - Directory with documentation - **CHANGELOG.md** - Change Log file. - **deviceSupport.md** - Information about supported devices. @@ -185,7 +181,6 @@ File structure - **codingStyle** - Example of the coding style. - **.clang-format** - Definition file for the coding style. - **Doxyfile** - Configuration file for the documentation generator *doxygen*. - - **Makefile** - Makefile for Linux socketCAN. - **canopend** - Executable for Linux, build with `make`. - **LICENSE** - License. - **README.md** - This file. @@ -231,8 +226,7 @@ CANopenNode can run on many different devices. Each device (or microcontroller) must have own interface to CANopenNode. CANopenNode can run with or without operating system. -It is not practical to have all device interfaces in a single project. For that -reason CANopenNode project only includes interface to Linux socketCAN. +It is not practical to have all device interfaces in a single project. Interfaces to other microcontrollers are in separate projects. See [deviceSupport.md](doc/deviceSupport.md) for list of known device interfaces. diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index d280a777..a2c019d3 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -4,6 +4,8 @@ Change Log [newOD] ------------------------- - [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/master...newOD) +### Removed +- Driver for Linux (socketCAN directory) moved to own repository https://github.com/CANopenNode/CANopenLinux. ### Changed - New Object dictionary interface. It has similar principles as before. Main access to OD variables is via fast read/write functions, but direct access to OD variables is also possible. OD entries are passed with pointers to CANopen objects. All parts of CANopenNode objects, which works with OD entries, are rewritten. - [libedssharp](https://github.com/robincornelius/libedssharp) have new OD exporter, new project file format (standard CANopen XDD v1.1), new documentation generator, and many other improvements. diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index 0e9d4b1d..94034db2 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -22,25 +22,25 @@ There are many advantages of sharing the base code such as this. For the driver Linux ----- * CANopenNode integration with Linux socketCAN with master command interface. SocketCAN is part of the Linux kernel. -* https://github.com/CANopenNode/CANopenNode (this project). -* CANopenNode version: (will be v2.0) +* https://github.com/CANopenNode/CANopenLinux. +* CANopenNode version: (v4.0) * Status: stable * Features: OD storage, error counters, master (SDO client, LSS master, NMT master) * Systems: Linux PC, Raspberry PI, etc. * Development tools: Linux -* Information updated 2020-02-14 +* Information updated 2021-05-21 PIC32, dsPIC30, dsPIC33 ----------------------- * CANopenNode integration with 16 and 32 bit PIC microcontrollers from Microchip. * https://github.com/CANopenNode/CANopenPIC -* CANopenNode version: (near v2.0) +* CANopenNode version: (v4.0) * Status: stable -* Features: OD storage, SDO client demo for PIC32, error counters +* Features: OD storage for PIC32, SDO client demo for PIC32, error counters * Development tools: MPLAB X -* Demo hardware: Explorer 16 from Microchip -* Information updated 2020-02-14 +* Demo hardware: Explorer 16 from Microchip, [Max32 board](https://reference.digilentinc.com/reference/microprocessor/max32/start) +* Information updated 2021-05-07 Zephyr RTOS diff --git a/socketCAN/CO_driver.c b/socketCAN/CO_driver.c deleted file mode 100644 index b10402aa..00000000 --- a/socketCAN/CO_driver.c +++ /dev/null @@ -1,992 +0,0 @@ -/* - * Linux socketCAN interface for CANopenNode. - * - * @file CO_driver.c - * @ingroup CO_driver - * @author Janez Paternoster, Martin Wagner - * @copyright 2004 - 2015 Janez Paternoster, 2017 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "301/CO_driver.h" -#include "CO_error.h" - -#ifndef CO_SINGLE_THREAD -pthread_mutex_t CO_EMCY_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t CO_OD_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -#if CO_DRIVER_MULTI_INTERFACE == 0 -static CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, - int can_ifindex); -#endif - - -#if CO_DRIVER_MULTI_INTERFACE > 0 - -static const uint32_t CO_INVALID_COB_ID = 0xffffffff; - -/******************************************************************************/ -void CO_CANsetIdentToIndex( - uint32_t *lookup, - uint32_t index, - uint32_t identNew, - uint32_t identCurrent) -{ - /* entry changed, remove old one */ - if (identCurrent CO_CAN_MSG_SFF_MAX_COB_ID) { - return; - } - - /* Special case COB ID "0" -> valid value in *xArray[0] (CO_*CAN_NMT), - * "entry unconfigured" for all others */ - if (identNew == 0) { - if (index == 0) { - lookup[0] = 0; - } - } - else { - lookup[identNew] = index; - } -} - - -/******************************************************************************/ -static uint32_t CO_CANgetIndexFromIdent( - uint32_t *lookup, - uint32_t ident) -{ - /* check if this COB ID is part of the table */ - if (ident > CO_CAN_MSG_SFF_MAX_COB_ID) { - return CO_INVALID_COB_ID; - } - - return lookup[ident]; -} - -#endif /* CO_DRIVER_MULTI_INTERFACE */ - - -/** Disable socketCAN rx ******************************************************/ -static CO_ReturnError_t disableRx(CO_CANmodule_t *CANmodule) -{ - uint32_t i; - CO_ReturnError_t retval; - - /* insert a filter that doesn't match any messages */ - retval = CO_ERROR_NO; - for (i = 0; i < CANmodule->CANinterfaceCount; i ++) { - int ret = setsockopt(CANmodule->CANinterfaces[i].fd, SOL_CAN_RAW, CAN_RAW_FILTER, - NULL, 0); - if(ret < 0){ - log_printf(LOG_ERR, CAN_FILTER_FAILED, - CANmodule->CANinterfaces[i].ifName); - log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt()"); - retval = CO_ERROR_SYSCALL; - } - } - - return retval; -} - - -/** Set up or update socketCAN rx filters *************************************/ -static CO_ReturnError_t setRxFilters(CO_CANmodule_t *CANmodule) -{ - size_t i; - int count; - CO_ReturnError_t retval; - - struct can_filter rxFiltersCpy[CANmodule->rxSize]; - - count = 0; - /* remove unused entries ( id == 0 and mask == 0 ) as they would act as - * "pass all" filter */ - for (i = 0; i < CANmodule->rxSize; i ++) { - if ((CANmodule->rxFilter[i].can_id != 0) || - (CANmodule->rxFilter[i].can_mask != 0)) { - - rxFiltersCpy[count] = CANmodule->rxFilter[i]; - - count ++; - } - } - - if (count == 0) { - /* No filter is set, disable RX */ - return disableRx(CANmodule); - } - - retval = CO_ERROR_NO; - for (i = 0; i < CANmodule->CANinterfaceCount; i ++) { - int ret = setsockopt(CANmodule->CANinterfaces[i].fd, SOL_CAN_RAW, CAN_RAW_FILTER, - rxFiltersCpy, sizeof(struct can_filter) * count); - if(ret < 0){ - log_printf(LOG_ERR, CAN_FILTER_FAILED, - CANmodule->CANinterfaces[i].ifName); - log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt()"); - retval = CO_ERROR_SYSCALL; - } - } - - return retval; -} - - -/******************************************************************************/ -void CO_CANsetConfigurationMode(void *CANptr) -{ - (void)CANptr; - /* Can't do anything because no reference to CANmodule_t is provided */ -} - - -/******************************************************************************/ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) -{ - CO_ReturnError_t ret; - - if(CANmodule != NULL) { - CANmodule->CANnormal = false; - ret = setRxFilters(CANmodule); - if (ret == CO_ERROR_NO) { - /* Put CAN module in normal mode */ - CANmodule->CANnormal = true; - } - } -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANmodule_init( - CO_CANmodule_t *CANmodule, - void *CANptr, - CO_CANrx_t rxArray[], - uint16_t rxSize, - CO_CANtx_t txArray[], - uint16_t txSize, - uint16_t CANbitRate) -{ - int32_t ret; - uint16_t i; - (void)CANbitRate; - - /* verify arguments */ - if(CANmodule==NULL || CANptr == NULL || rxArray==NULL || txArray==NULL) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - CO_CANptrSocketCan_t *CANptrReal = (CO_CANptrSocketCan_t *)CANptr; - - /* Configure object variables */ - CANmodule->epoll_fd = CANptrReal->epoll_fd; - CANmodule->CANinterfaces = NULL; - CANmodule->CANinterfaceCount = 0; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANerrorStatus = 0; - CANmodule->CANnormal = false; - CANmodule->CANtxCount = 0; - -#if CO_DRIVER_MULTI_INTERFACE > 0 - for (i = 0; i < CO_CAN_MSG_SFF_MAX_COB_ID; i++) { - CANmodule->rxIdentToIndex[i] = CO_INVALID_COB_ID; - CANmodule->txIdentToIndex[i] = CO_INVALID_COB_ID; - } -#endif - - /* initialize socketCAN filters - * CAN module filters will be configured with CO_CANrxBufferInit() - * functions, called by separate CANopen init functions */ - CANmodule->rxFilter = calloc(CANmodule->rxSize, sizeof(struct can_filter)); - if(CANmodule->rxFilter == NULL){ - log_printf(LOG_DEBUG, DBG_ERRNO, "malloc()"); - return CO_ERROR_OUT_OF_MEMORY; - } - - for(i=0U; ican_ifindex); - if (ret != CO_ERROR_NO) { - CO_CANmodule_disable(CANmodule); - return ret; - } -#endif - return CO_ERROR_NO; -} - - -/** enable socketCAN *********************************************************/ -#if CO_DRIVER_MULTI_INTERFACE == 0 -static -#endif -CO_ReturnError_t CO_CANmodule_addInterface(CO_CANmodule_t *CANmodule, - int can_ifindex) -{ - int32_t ret; - int32_t tmp; - int32_t bytes; - char *ifName; - socklen_t sLen; - CO_CANinterface_t *interface; - struct sockaddr_can sockAddr; - struct epoll_event ev; -#if CO_DRIVER_ERROR_REPORTING > 0 - can_err_mask_t err_mask; -#endif - - if (CANmodule->CANnormal != false) { - /* can't change config now! */ - return CO_ERROR_INVALID_STATE; - } - - /* Add interface to interface list */ - CANmodule->CANinterfaceCount ++; - CANmodule->CANinterfaces = realloc(CANmodule->CANinterfaces, - ((CANmodule->CANinterfaceCount) * sizeof(*CANmodule->CANinterfaces))); - if (CANmodule->CANinterfaces == NULL) { - log_printf(LOG_DEBUG, DBG_ERRNO, "malloc()"); - return CO_ERROR_OUT_OF_MEMORY; - } - interface = &CANmodule->CANinterfaces[CANmodule->CANinterfaceCount - 1]; - - interface->can_ifindex = can_ifindex; - ifName = if_indextoname(can_ifindex, interface->ifName); - if (ifName == NULL) { - log_printf(LOG_DEBUG, DBG_ERRNO, "if_indextoname()"); - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Create socket */ - interface->fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); - if(interface->fd < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "socket(can)"); - return CO_ERROR_SYSCALL; - } - - /* enable socket rx queue overflow detection */ - tmp = 1; - ret = setsockopt(interface->fd, SOL_SOCKET, SO_RXQ_OVFL, &tmp, sizeof(tmp)); - if(ret < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(ovfl)"); - return CO_ERROR_SYSCALL; - } - - /* enable software time stamp mode (hardware timestamps do not work properly - * on all devices)*/ - tmp = (SOF_TIMESTAMPING_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE); - ret = setsockopt(interface->fd, SOL_SOCKET, SO_TIMESTAMPING, &tmp, sizeof(tmp)); - if (ret < 0) { - log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(timestamping)"); - return CO_ERROR_SYSCALL; - } - - //todo - modify rx buffer size? first one needs root - //ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&bytes, sLen); - //ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&bytes, sLen); - - /* print socket rx buffer size in bytes (In my experience, the kernel reserves - * around 450 bytes for each CAN message) */ - sLen = sizeof(bytes); - getsockopt(interface->fd, SOL_SOCKET, SO_RCVBUF, (void *)&bytes, &sLen); - if (sLen == sizeof(bytes)) { - log_printf(LOG_INFO, CAN_SOCKET_BUF_SIZE, interface->ifName, - bytes / 446, bytes); - } - - /* bind socket */ - memset(&sockAddr, 0, sizeof(sockAddr)); - sockAddr.can_family = AF_CAN; - sockAddr.can_ifindex = can_ifindex; - ret = bind(interface->fd, (struct sockaddr*)&sockAddr, sizeof(sockAddr)); - if(ret < 0){ - log_printf(LOG_ERR, CAN_BINDING_FAILED, interface->ifName); - log_printf(LOG_DEBUG, DBG_ERRNO, "bind()"); - return CO_ERROR_SYSCALL; - } - -#if CO_DRIVER_ERROR_REPORTING > 0 - CO_CANerror_init(&interface->errorhandler, interface->fd, interface->ifName); - /* set up error frame generation. What actually is available depends on your - * CAN kernel driver */ -#ifdef DEBUG - err_mask = CAN_ERR_MASK; //enable ALL error frames -#else - err_mask = CAN_ERR_ACK | CAN_ERR_CRTL | CAN_ERR_BUSOFF | CAN_ERR_BUSERROR; -#endif - ret = setsockopt(interface->fd, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, - sizeof(err_mask)); - if(ret < 0){ - log_printf(LOG_ERR, CAN_ERROR_FILTER_FAILED, interface->ifName); - log_printf(LOG_DEBUG, DBG_ERRNO, "setsockopt(can err)"); - return CO_ERROR_SYSCALL; - } -#endif /* CO_DRIVER_ERROR_REPORTING */ - - /* Add socket to epoll */ - ev.events = EPOLLIN; - ev.data.fd = interface->fd; - ret = epoll_ctl(CANmodule->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if(ret < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_ctl(can)"); - return CO_ERROR_SYSCALL; - } - - /* rx is started by calling #CO_CANsetNormalMode() */ - ret = disableRx(CANmodule); - - return ret; -} - - -/******************************************************************************/ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) -{ - uint32_t i; - - if (CANmodule == NULL) { - return; - } - - CANmodule->CANnormal = false; - - /* clear interfaces */ - for (i = 0; i < CANmodule->CANinterfaceCount; i++) { - CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; - -#if CO_DRIVER_ERROR_REPORTING > 0 - CO_CANerror_disable(&interface->errorhandler); -#endif - - epoll_ctl(CANmodule->epoll_fd, EPOLL_CTL_DEL, interface->fd, NULL); - close(interface->fd); - interface->fd = -1; - } - CANmodule->CANinterfaceCount = 0; - if (CANmodule->CANinterfaces != NULL) { - free(CANmodule->CANinterfaces); - } - CANmodule->CANinterfaces = NULL; - - if (CANmodule->rxFilter != NULL) { - free(CANmodule->rxFilter); - } - CANmodule->rxFilter = NULL; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*CANrx_callback)(void *object, void *message)) -{ - CO_ReturnError_t ret = CO_ERROR_NO; - - if((CANmodule!=NULL) && (index < CANmodule->rxSize)){ - CO_CANrx_t *buffer; - - /* buffer, which will be configured */ - buffer = &CANmodule->rxArray[index]; - -#if CO_DRIVER_MULTI_INTERFACE > 0 - CO_CANsetIdentToIndex(CANmodule->rxIdentToIndex, index, ident, - buffer->ident); -#endif - - /* Configure object variables */ - buffer->object = object; - buffer->CANrx_callback = CANrx_callback; - buffer->can_ifindex = 0; - buffer->timestamp.tv_nsec = 0; - buffer->timestamp.tv_sec = 0; - - /* CAN identifier and CAN mask, bit aligned with CAN module */ - buffer->ident = ident & CAN_SFF_MASK; - if(rtr){ - buffer->ident |= CAN_RTR_FLAG; - } - buffer->mask = (mask & CAN_SFF_MASK) | CAN_EFF_FLAG | CAN_RTR_FLAG; - - /* Set CAN hardware module filter and mask. */ - CANmodule->rxFilter[index].can_id = buffer->ident; - CANmodule->rxFilter[index].can_mask = buffer->mask; - if(CANmodule->CANnormal){ - ret = setRxFilters(CANmodule); - } - } - else { - log_printf(LOG_DEBUG, DBG_CAN_RX_PARAM_FAILED, "illegal argument"); - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; -} - -#if CO_DRIVER_MULTI_INTERFACE > 0 - -/******************************************************************************/ -bool_t CO_CANrxBuffer_getInterface( - CO_CANmodule_t *CANmodule, - uint16_t ident, - int *can_ifindexRx, - struct timespec *timestamp) -{ - CO_CANrx_t *buffer; - - if (CANmodule == NULL){ - return false; - } - - const uint32_t index = CO_CANgetIndexFromIdent(CANmodule->rxIdentToIndex, ident); - if ((index == CO_INVALID_COB_ID) || (index > CANmodule->rxSize)) { - return false; - } - buffer = &CANmodule->rxArray[index]; - - /* return values */ - if (can_ifindexRx != NULL) { - *can_ifindexRx = buffer->can_ifindex; - } - if (timestamp != NULL) { - *timestamp = buffer->timestamp; - } - if (buffer->can_ifindex != 0) { - return true; - } - else { - return false; - } -} - -#endif /* CO_DRIVER_MULTI_INTERFACE */ - - -/******************************************************************************/ -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; - -#if CO_DRIVER_MULTI_INTERFACE > 0 - CO_CANsetIdentToIndex(CANmodule->txIdentToIndex, index, ident, buffer->ident); -#endif - - buffer->can_ifindex = 0; - - /* CAN identifier and rtr */ - buffer->ident = ident & CAN_SFF_MASK; - if(rtr){ - buffer->ident |= CAN_RTR_FLAG; - } - buffer->DLC = noOfBytes; - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } - - return buffer; -} - -#if CO_DRIVER_MULTI_INTERFACE > 0 - -/******************************************************************************/ -CO_ReturnError_t CO_CANtxBuffer_setInterface( - CO_CANmodule_t *CANmodule, - uint16_t ident, - int can_ifindexTx) -{ - if (CANmodule != NULL) { - uint32_t index; - - index = CO_CANgetIndexFromIdent(CANmodule->txIdentToIndex, ident); - if ((index == CO_INVALID_COB_ID) || (index > CANmodule->txSize)) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - CANmodule->txArray[index].can_ifindex = can_ifindexTx; - - return CO_ERROR_NO; - } - return CO_ERROR_ILLEGAL_ARGUMENT; -} - -#endif /* CO_DRIVER_MULTI_INTERFACE */ -#if CO_DRIVER_MULTI_INTERFACE > 0 - -/* send CAN message ***********************************************************/ -static CO_ReturnError_t CO_CANCheckSendInterface( - CO_CANmodule_t *CANmodule, - CO_CANtx_t *buffer, - CO_CANinterface_t *interface) -{ - CO_ReturnError_t err = CO_ERROR_NO; -#if CO_DRIVER_ERROR_REPORTING > 0 - CO_CANinterfaceState_t ifState; -#endif - ssize_t n; - - if (CANmodule==NULL || interface==NULL || interface->fd < 0) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - -#if CO_DRIVER_ERROR_REPORTING > 0 - ifState = CO_CANerror_txMsg(&interface->errorhandler); - switch (ifState) { - case CO_INTERFACE_ACTIVE: - /* continue */ - break; - case CO_INTERFACE_LISTEN_ONLY: - /* silently drop message */ - return CO_ERROR_NO; - default: - return CO_ERROR_INVALID_STATE; - } -#endif - - do { - errno = 0; - n = send(interface->fd, buffer, CAN_MTU, MSG_DONTWAIT); - if (errno == EINTR) { - /* try again */ - continue; - } - else if (errno == EAGAIN) { - /* socket queue full */ - break; - } - else if (errno == ENOBUFS) { - /* socketCAN doesn't support blocking write. You can wait here for - * a few hundred us and then try again */ -#if CO_DRIVER_ERROR_REPORTING > 0 - interface->errorhandler.CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; -#endif - return CO_ERROR_TX_BUSY; - } - else if (n != CAN_MTU) { - break; - } - } while (errno != 0); - - if(n != CAN_MTU){ -#if CO_DRIVER_ERROR_REPORTING > 0 - interface->errorhandler.CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; -#endif - log_printf(LOG_ERR, DBG_CAN_TX_FAILED, buffer->ident, interface->ifName); - log_printf(LOG_DEBUG, DBG_ERRNO, "send()"); - err = CO_ERROR_TX_OVERFLOW; - } - - return err; -} - - -/* - * 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. - * - * (It is not in header, because usage of CO_CANCheckSend() is unclear.) - * - * @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); - - -/******************************************************************************/ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) -{ - CO_ReturnError_t err; - err = CO_CANCheckSend(CANmodule, buffer); - if (err == CO_ERROR_TX_BUSY) { - /* send doesn't have "busy" */ - log_printf(LOG_ERR, DBG_CAN_TX_FAILED, buffer->ident, "CANx"); - log_printf(LOG_DEBUG, DBG_ERRNO, "send()"); - err = CO_ERROR_TX_OVERFLOW; - } - return err; -} - - -/******************************************************************************/ -CO_ReturnError_t CO_CANCheckSend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) -{ - uint32_t i; - CO_ReturnError_t err = CO_ERROR_NO; - - /* check on which interfaces to send this messages */ - for (i = 0; i < CANmodule->CANinterfaceCount; i++) { - CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; - - if ((buffer->can_ifindex == 0) || - buffer->can_ifindex == interface->can_ifindex) { - - CO_ReturnError_t tmp; - - /* match, use this one */ - tmp = CO_CANCheckSendInterface(CANmodule, buffer, interface); - if (tmp) { - /* only last error is returned to callee */ - err = tmp; - } - } - } - - return err; -} - -#warning CO_CANsend() is outdated for CO_DRIVER_MULTI_INTERFACE > 0 - -#endif /* CO_DRIVER_MULTI_INTERFACE > 0 */ - - -#if CO_DRIVER_MULTI_INTERFACE == 0 - -/* Change handling of tx buffer full in CO_CANsend(). Use CO_CANtx_t->bufferFull - * flag. Re-transmit undelivered message inside CO_CANmodule_process(). */ -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) -{ - CO_ReturnError_t err = CO_ERROR_NO; - - if (CANmodule==NULL || buffer==NULL || CANmodule->CANinterfaceCount==0) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - CO_CANinterface_t *interface = &CANmodule->CANinterfaces[0]; - if (interface == NULL || interface->fd < 0) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Verify overflow */ - if(buffer->bufferFull){ -#if CO_DRIVER_ERROR_REPORTING > 0 - interface->errorhandler.CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; -#endif - log_printf(LOG_ERR, DBG_CAN_TX_FAILED, buffer->ident, interface->ifName); - err = CO_ERROR_TX_OVERFLOW; - } - - errno = 0; - ssize_t n = send(interface->fd, buffer, CAN_MTU, MSG_DONTWAIT); - if (errno == 0 && n == CAN_MTU) { - /* success */ - if (buffer->bufferFull) { - buffer->bufferFull = false; - CANmodule->CANtxCount--; - } - } - else if (errno == EINTR || errno == EAGAIN || errno == ENOBUFS) { - /* Send failed, message will be re-sent by CO_CANmodule_process() */ - if (!buffer->bufferFull) { - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - err = CO_ERROR_TX_BUSY; - } - else { - /* Unknown error */ - log_printf(LOG_DEBUG, DBG_ERRNO, "send()"); -#if CO_DRIVER_ERROR_REPORTING > 0 - interface->errorhandler.CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; -#endif - err = CO_ERROR_SYSCALL; - } - - return err; -} - -#endif /* CO_DRIVER_MULTI_INTERFACE == 0 */ - - -/******************************************************************************/ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) -{ - (void)CANmodule; - /* Messages are either written to the socket queue or dropped */ -} - - -/******************************************************************************/ -void CO_CANmodule_process(CO_CANmodule_t *CANmodule) -{ - if (CANmodule == NULL || CANmodule->CANinterfaceCount == 0) return; - -#if CO_DRIVER_ERROR_REPORTING > 0 - /* socketCAN doesn't support microcontroller-like error counters. If an - * error has occured, a special can message is created by the driver and - * received by the application like a regular message. - * Therefore, error counter evaluation is included in rx function. - * Here we just copy evaluated CANerrorStatus from the first CAN interface. */ - - CANmodule->CANerrorStatus = - CANmodule->CANinterfaces[0].errorhandler.CANerrorStatus; -#endif - -#if CO_DRIVER_MULTI_INTERFACE == 0 - /* recall CO_CANsend(), if message was unsent before */ - if (CANmodule->CANtxCount > 0) { - bool_t found = false; - - for (uint16_t i = 0; i < CANmodule->txSize; i++) { - CO_CANtx_t *buffer = &CANmodule->txArray[i]; - - if (buffer->bufferFull) { - buffer->bufferFull = false; - CANmodule->CANtxCount--; - CO_CANsend(CANmodule, buffer); - found = true; - break; - } - } - - if (!found) { - CANmodule->CANtxCount = 0; - } - } -#endif /* CO_DRIVER_MULTI_INTERFACE == 0 */ -} - - -/* Read CAN message from socket and verify some errors ************************/ -static CO_ReturnError_t CO_CANread( - CO_CANmodule_t *CANmodule, - CO_CANinterface_t *interface, - struct can_frame *msg, /* CAN message, return value */ - struct timespec *timestamp) /* timestamp of CAN message, return value */ -{ - int32_t n; - uint32_t dropped; - /* recvmsg - like read, but generates statistics about the socket - * example in berlios candump.c */ - struct iovec iov; - struct msghdr msghdr; - char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(dropped))]; - struct cmsghdr *cmsg; - - iov.iov_base = msg; - iov.iov_len = sizeof(*msg); - - msghdr.msg_name = NULL; - msghdr.msg_namelen = 0; - msghdr.msg_iov = &iov; - msghdr.msg_iovlen = 1; - msghdr.msg_control = &ctrlmsg; - msghdr.msg_controllen = sizeof(ctrlmsg); - msghdr.msg_flags = 0; - - n = recvmsg(interface->fd, &msghdr, 0); - if (n != CAN_MTU) { -#if CO_DRIVER_ERROR_REPORTING > 0 - interface->errorhandler.CANerrorStatus |= CO_CAN_ERRRX_OVERFLOW; -#endif - log_printf(LOG_DEBUG, DBG_CAN_RX_FAILED, interface->ifName); - log_printf(LOG_DEBUG, DBG_ERRNO, "recvmsg()"); - return CO_ERROR_SYSCALL; - } - - /* check for rx queue overflow, get rx time */ - for (cmsg = CMSG_FIRSTHDR(&msghdr); - cmsg && (cmsg->cmsg_level == SOL_SOCKET); - cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { - if (cmsg->cmsg_type == SO_TIMESTAMPING) { - /* this is system time, not monotonic time! */ - *timestamp = ((struct timespec*)CMSG_DATA(cmsg))[0]; - } - else if (cmsg->cmsg_type == SO_RXQ_OVFL) { - dropped = *(uint32_t*)CMSG_DATA(cmsg); - if (dropped > CANmodule->rxDropCount) { -#if CO_DRIVER_ERROR_REPORTING > 0 - interface->errorhandler.CANerrorStatus |= CO_CAN_ERRRX_OVERFLOW; -#endif - log_printf(LOG_ERR, CAN_RX_SOCKET_QUEUE_OVERFLOW, - interface->ifName, dropped); - } - CANmodule->rxDropCount = dropped; - //todo use this info! - } - } - - return CO_ERROR_NO; -} - - -/* find msg inside rxArray and call corresponding CANrx_callback **************/ -static int32_t CO_CANrxMsg( /* return index of received message in rxArray or -1 */ - CO_CANmodule_t *CANmodule, - struct can_frame *msg, /* CAN message input */ - CO_CANrxMsg_t *buffer) /* If not NULL, msg will be copied to buffer */ -{ - int32_t retval; - const CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - CO_CANrx_t *rcvMsgObj = NULL; /* receive message object from CO_CANmodule_t object. */ - bool_t msgMatched = false; - - /* CANopenNode can message is binary compatible to the socketCAN one, except - * for extension flags */ - msg->can_id &= CAN_EFF_MASK; - rcvMsg = (CO_CANrxMsg_t *)msg; - - /* Message has been received. Search rxArray from CANmodule for the - * same CAN-ID. */ - rcvMsgObj = &CANmodule->rxArray[0]; - for (index = 0; index < CANmodule->rxSize; index ++) { - if(((rcvMsg->ident ^ rcvMsgObj->ident) & rcvMsgObj->mask) == 0U){ - msgMatched = true; - break; - } - rcvMsgObj++; - } - if(msgMatched) { - /* Call specific function, which will process the message */ - if ((rcvMsgObj != NULL) && (rcvMsgObj->CANrx_callback != NULL)){ - rcvMsgObj->CANrx_callback(rcvMsgObj->object, (void *)rcvMsg); - } - /* return message */ - if (buffer != NULL) { - memcpy(buffer, rcvMsg, sizeof(*buffer)); - } - retval = index; - } - else { - retval = -1; - } - - return retval; -} - - -/******************************************************************************/ -bool_t CO_CANrxFromEpoll(CO_CANmodule_t *CANmodule, - struct epoll_event *ev, - CO_CANrxMsg_t *buffer, - int32_t *msgIndex) -{ - if (CANmodule == NULL || ev == NULL || CANmodule->CANinterfaceCount == 0) { - return false; - } - - /* Verify for epoll events in CAN socket */ - for (uint32_t i = 0; i < CANmodule->CANinterfaceCount; i ++) { - CO_CANinterface_t *interface = &CANmodule->CANinterfaces[i]; - - if (ev->data.fd == interface->fd) { - if ((ev->events & (EPOLLERR | EPOLLHUP)) != 0) { - struct can_frame msg; - /* epoll detected close/error on socket. Try to pull event */ - errno = 0; - recv(ev->data.fd, &msg, sizeof(msg), MSG_DONTWAIT); - log_printf(LOG_DEBUG, DBG_CAN_RX_EPOLL, - ev->events, strerror(errno)); - } - else if ((ev->events & EPOLLIN) != 0) { - struct can_frame msg; - struct timespec timestamp; - - /* get message */ - CO_ReturnError_t err = CO_CANread(CANmodule, interface, - &msg, ×tamp); - - if(err == CO_ERROR_NO && CANmodule->CANnormal) { - - if (msg.can_id & CAN_ERR_FLAG) { - /* error msg */ -#if CO_DRIVER_ERROR_REPORTING > 0 - CO_CANerror_rxMsgError(&interface->errorhandler, &msg); -#endif - } - else { - /* data msg */ -#if CO_DRIVER_ERROR_REPORTING > 0 - /* clear listenOnly and noackCounter if necessary */ - CO_CANerror_rxMsg(&interface->errorhandler); -#endif - int32_t idx = CO_CANrxMsg(CANmodule, &msg, buffer); - if (idx > -1) { - /* Store message info */ - CANmodule->rxArray[idx].timestamp = timestamp; - CANmodule->rxArray[idx].can_ifindex = - interface->can_ifindex; - } - if (msgIndex != NULL) { - *msgIndex = idx; - } - } - } - } - else { - log_printf(LOG_DEBUG, DBG_EPOLL_UNKNOWN, - ev->events, ev->data.fd); - } - return true; - } /* if (ev->data.fd == interface->fd) */ - } - return false; -} diff --git a/socketCAN/CO_driver_target.h b/socketCAN/CO_driver_target.h deleted file mode 100644 index 919c3d3a..00000000 --- a/socketCAN/CO_driver_target.h +++ /dev/null @@ -1,491 +0,0 @@ -/** - * Linux socketCAN specific definitions for CANopenNode. - * - * @file CO_driver_target.h - * @ingroup CO_socketCAN_driver_target - * @author Janez Paternoster - * @author Martin Wagner - * @copyright 2004 - 2020 Janez Paternoster - * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H - -/* This file contains device and application specific definitions. - * It is included from CO_driver.h, which contains documentation - * for common definitions below. */ - -#include -#include -#include -#include -#include -#ifndef CO_SINGLE_THREAD -#include -#endif -#include -#include -#include - -#ifdef CO_DRIVER_CUSTOM -#include "CO_driver_custom.h" -#endif -#include "CO_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Stack configuration override default values. - * For more information see file CO_config.h. */ -#ifdef CO_SINGLE_THREAD -#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE 0 -#else -#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE CO_CONFIG_FLAG_CALLBACK_PRE -#endif -#define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT CO_CONFIG_FLAG_TIMERNEXT - -#ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT (CO_CONFIG_NMT_CALLBACK_CHANGE | \ - CO_CONFIG_NMT_MASTER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) -#endif - -#ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ - CO_CONFIG_HB_CONS_CALLBACK_CHANGE | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - -#ifndef CO_CONFIG_EM -#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ - CO_CONFIG_EM_PROD_CONFIGURABLE | \ - CO_CONFIG_EM_PROD_INHIBIT | \ - CO_CONFIG_EM_HISTORY | \ - CO_CONFIG_EM_STATUS_BITS | \ - CO_CONFIG_EM_CONSUMER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) -#endif - -#ifndef CO_CONFIG_SDO_SRV -#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ - CO_CONFIG_SDO_SRV_BLOCK | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - -#ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE -#define CO_CONFIG_SDO_SRV_BUFFER_SIZE 900 -#endif - -#ifndef CO_CONFIG_SDO_CLI -#define CO_CONFIG_SDO_CLI (CO_CONFIG_SDO_CLI_ENABLE | \ - CO_CONFIG_SDO_CLI_SEGMENTED | \ - CO_CONFIG_SDO_CLI_BLOCK | \ - CO_CONFIG_SDO_CLI_LOCAL | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - -#ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ - CO_CONFIG_TIME_PRODUCER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) -#endif - -#ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ - CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \ - CO_CONFIG_LSS_MASTER | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) -#endif - -#ifndef CO_CONFIG_GTW -#define CO_CONFIG_GTW (CO_CONFIG_GTW_ASCII | \ - CO_CONFIG_GTW_ASCII_SDO | \ - CO_CONFIG_GTW_ASCII_NMT | \ - CO_CONFIG_GTW_ASCII_LSS | \ - CO_CONFIG_GTW_ASCII_LOG | \ - CO_CONFIG_GTW_ASCII_ERROR_DESC | \ - CO_CONFIG_GTW_ASCII_PRINT_HELP | \ - CO_CONFIG_GTW_ASCII_PRINT_LEDS) -#define CO_CONFIG_GTW_BLOCK_DL_LOOP 3 -#define CO_CONFIG_GTWA_COMM_BUF_SIZE 2000 -#define CO_CONFIG_GTWA_LOG_BUF_SIZE 10000 -#endif - -#ifndef CO_CONFIG_CRC16 -#define CO_CONFIG_CRC16 (CO_CONFIG_CRC16_ENABLE) -#endif - -#ifndef CO_CONFIG_FIFO -#define CO_CONFIG_FIFO (CO_CONFIG_FIFO_ENABLE | \ - CO_CONFIG_FIFO_ALT_READ | \ - CO_CONFIG_FIFO_CRC16_CCITT | \ - CO_CONFIG_FIFO_ASCII_COMMANDS | \ - CO_CONFIG_FIFO_ASCII_DATATYPES) -#endif - - -/* Print debug info from some internal parts of the stack */ -#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_COMMON -#include -#include -#define CO_DEBUG_COMMON(msg) log_printf(LOG_DEBUG, DBG_CO_DEBUG, msg); -#endif - - -/** - * @defgroup CO_socketCAN_driver_target CO_driver_target.h - * @ingroup CO_socketCAN - * @{ - * - * Linux socketCAN specific @ref CO_driver definitions for CANopenNode. - */ - -/** - * 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. - * - * If CO_DRIVER_MULTI_INTERFACE is set to 0, then CO_CANmodule_init() - * adds single socketCAN interface specified by CANptr argument. In case of - * failure, CO_CANmodule_init() returns CO_ERROR_SYSCALL. - * - * If CO_DRIVER_MULTI_INTERFACE is set to 1, then CO_CANmodule_init() - * ignores CANptr argument. Interfaces must be added by - * CO_CANmodule_addInterface() function after CO_CANmodule_init(). - * - * Macro is set to 0 (disabled) by default. It can be overridden. - * - * This is not intended to realize interface redundancy!!! - */ -#ifndef CO_DRIVER_MULTI_INTERFACE -#define CO_DRIVER_MULTI_INTERFACE 0 -#endif - -/** - * CAN bus error reporting - * - * CO_DRIVER_ERROR_REPORTING enabled adds 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. - * - * Macro is set to 1 (enabled) by default. It can be overridden. - * - * you need to enable error reporting in your kernel driver using: - * @code{.sh} - * ip link set canX type can berr-reporting on - * @endcode - * Of course, the kernel driver for your hardware needs this functionality to be - * implemented... - */ -#ifndef CO_DRIVER_ERROR_REPORTING -#define CO_DRIVER_ERROR_REPORTING 1 -#endif - -/* skip this section for Doxygen, because it is documented in CO_driver.h */ -#ifndef CO_DOXYGEN - -/* Basic definitions */ -#ifdef __BYTE_ORDER -#if __BYTE_ORDER == __LITTLE_ENDIAN - #define CO_LITTLE_ENDIAN - #define CO_SWAP_16(x) x - #define CO_SWAP_32(x) x - #define CO_SWAP_64(x) x -#else - #define CO_BIG_ENDIAN - #include - #define CO_SWAP_16(x) bswap_16(x) - #define CO_SWAP_32(x) bswap_32(x) - #define CO_SWAP_64(x) bswap_64(x) -#endif -#endif -/* NULL is defined in stddef.h */ -/* true and false are defined in stdbool.h */ -/* int8_t to uint64_t are defined in stdint.h */ -typedef uint_fast8_t bool_t; -typedef float float32_t; -typedef double float64_t; - - -/* CAN receive message structure as aligned in socketCAN. */ -typedef struct { - uint32_t ident; - uint8_t DLC; - uint8_t padding[3]; - uint8_t data[8]; -} CO_CANrxMsg_t; - -/* Access to received CAN message */ -static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg) { - CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; - return (uint16_t) (rxMsgCasted->ident & CAN_SFF_MASK); -} -static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg) { - CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; - return (uint8_t) (rxMsgCasted->DLC); -} -static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg) { - CO_CANrxMsg_t *rxMsgCasted = (CO_CANrxMsg_t *)rxMsg; - return (uint8_t *) (rxMsgCasted->data); -} - - -/* Received message object */ -typedef struct { - uint32_t ident; - uint32_t mask; - void *object; - void (*CANrx_callback)(void *object, void *message); - int can_ifindex; /* CAN Interface index from last message */ - struct timespec timestamp; /* time of reception of last message */ -} CO_CANrx_t; - -/* Transmit message object as aligned in socketCAN. */ -typedef struct { - uint32_t ident; - uint8_t DLC; - uint8_t padding[3]; /* ensure alignment */ - uint8_t data[8]; - volatile bool_t bufferFull; - volatile bool_t syncFlag; /* info about transmit message */ - int can_ifindex; /* CAN Interface index to use */ -} CO_CANtx_t; - - -/* Max COB ID for standard frame format */ -#define CO_CAN_MSG_SFF_MAX_COB_ID (1 << CAN_SFF_ID_BITS) - -/* CAN interface object (CANptr), passed to CO_CANinit() */ -typedef struct { - int can_ifindex; /* CAN Interface index */ - int epoll_fd; /* File descriptor for epoll, which waits for - CAN receive event */ -} CO_CANptrSocketCan_t; - -/* socketCAN interface object */ -typedef struct { - int can_ifindex; /* CAN Interface index */ - char ifName[IFNAMSIZ]; /* CAN Interface name */ - int fd; /* socketCAN file descriptor */ -#if CO_DRIVER_ERROR_REPORTING > 0 || defined CO_DOXYGEN - CO_CANinterfaceErrorhandler_t errorhandler; -#endif -} CO_CANinterface_t; - -/* CAN module object */ -typedef struct { - /* List of can interfaces. From CO_CANmodule_init() or one per - * CO_CANmodule_addInterface() call */ - CO_CANinterface_t *CANinterfaces; - uint32_t CANinterfaceCount; /* interface count */ - CO_CANrx_t *rxArray; - uint16_t rxSize; - struct can_filter *rxFilter;/* socketCAN filter list, one per rx buffer */ - uint32_t rxDropCount; /* messages dropped on rx socket queue */ - CO_CANtx_t *txArray; - uint16_t txSize; - uint16_t CANerrorStatus; - volatile bool_t CANnormal; - volatile uint16_t CANtxCount; - int epoll_fd; /* File descriptor for epoll, which waits for - CAN receive event */ -#if CO_DRIVER_MULTI_INTERFACE > 0 || defined CO_DOXYGEN - /* Lookup tables Cob ID to rx/tx array index. - * Only feasible for SFF Messages. */ - uint32_t rxIdentToIndex[CO_CAN_MSG_SFF_MAX_COB_ID]; - uint32_t txIdentToIndex[CO_CAN_MSG_SFF_MAX_COB_ID]; -#endif -} CO_CANmodule_t; - - -/* Data storage: Maximum file name length including path */ -#ifndef CO_STORAGE_PATH_MAX -#define CO_STORAGE_PATH_MAX 255 -#endif - -/* Data storage object for one entry */ -typedef struct { - void *addr; - size_t len; - uint8_t subIndexOD; - uint8_t attr; - /* Name of the file, where data block is stored */ - char filename[CO_STORAGE_PATH_MAX]; - /* CRC checksum of the data stored previously, for auto storage */ - uint16_t crc; - /* Pointer to opened file, for auto storage */ - FILE *fp; -} CO_storage_entry_t; - - -#ifdef CO_SINGLE_THREAD -#define CO_LOCK_CAN_SEND(CAN_MODULE) {(void) CAN_MODULE;} -#define CO_UNLOCK_CAN_SEND(CAN_MODULE) {(void) CAN_MODULE;} -#define CO_LOCK_EMCY(CAN_MODULE) {(void) CAN_MODULE;} -#define CO_UNLOCK_EMCY(CAN_MODULE) {(void) CAN_MODULE;} -#define CO_LOCK_OD(CAN_MODULE) {(void) CAN_MODULE;} -#define CO_UNLOCK_OD(CAN_MODULE) {(void) CAN_MODULE;} -#define CO_MemoryBarrier() -#else - -/* (un)lock critical section in CO_CANsend() - unused */ -#define CO_LOCK_CAN_SEND(CAN_MODULE) -#define CO_UNLOCK_CAN_SEND(CAN_MODULE) - -/* (un)lock critical section in CO_errorReport() or CO_errorReset() */ -extern pthread_mutex_t CO_EMCY_mutex; -static inline int CO_LOCK_EMCY(CO_CANmodule_t *CANmodule) { - (void)CANmodule; - return pthread_mutex_lock(&CO_EMCY_mutex); -} -static inline void CO_UNLOCK_EMCY(CO_CANmodule_t *CANmodule) { - (void)CANmodule; - (void)pthread_mutex_unlock(&CO_EMCY_mutex); -} - -/* (un)lock critical section when accessing Object Dictionary */ -extern pthread_mutex_t CO_OD_mutex; -static inline int CO_LOCK_OD(CO_CANmodule_t *CANmodule) { - (void)CANmodule; - return pthread_mutex_lock(&CO_OD_mutex); -} -static inline void CO_UNLOCK_OD(CO_CANmodule_t *CANmodule) { - (void)CANmodule; - (void)pthread_mutex_unlock(&CO_OD_mutex); -} - -/* Synchronization between CAN receive and message processing threads. */ -#define CO_MemoryBarrier() {__sync_synchronize();} -#endif /* CO_SINGLE_THREAD */ - -#define CO_FLAG_READ(rxNew) ((rxNew) != NULL) -#define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} -#define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} - -#endif /* #ifndef CO_DOXYGEN */ - - -#if CO_DRIVER_MULTI_INTERFACE > 0 || defined CO_DOXYGEN -/** - * Add socketCAN interface to can driver - * - * Function must be called after CO_CANmodule_init. - * - * @param CANmodule This object will be initialized. - * @param can_ifindex CAN Interface index - * @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, - int can_ifindex); - -/** - * 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] CANptrRx 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, - uint16_t ident, - const void **const CANptrRx, - struct timespec *timestamp); - -/** - * 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 CANptrTx 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, - uint16_t ident, - const void *CANptrTx); -#endif /* CO_DRIVER_MULTI_INTERFACE */ - - -/** - * Receives CAN messages from matching epoll event - * - * This function verifies, if epoll event matches event from any CANinterface. - * In case of match, message is read from CAN and pre-processed for CANopenNode - * objects. CAN error frames are also processed. - * - * In case of CAN message function searches _rxArray_ from CO_CANmodule_t and - * if matched it calls the corresponding CANrx_callback, optionally copies - * received CAN message to _buffer_ and returns index of matched _rxArray_. - * - * This function can be used in two ways, which can be combined: - * - automatic mode: If CANrx_callback is specified for matched _rxArray_, then - * calls its callback. - * - manual mode: evaluate message filters, return received message - * - * @param CANmodule This object. - * @param ev Epoll event, which vill be verified for matches. - * @param [out] buffer Storage for received message or _NULL_ if not used. - * @param [out] msgIndex Index of received message in array from CO_CANmodule_t - * _rxArray_, copy of CAN message is available in _buffer_. - * - * @return True, if epoll event matches any CAN interface. - */ -bool_t CO_CANrxFromEpoll(CO_CANmodule_t *CANmodule, - struct epoll_event *ev, - CO_CANrxMsg_t *buffer, - int32_t *msgIndex); - -/** @} */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CO_DRIVER_TARGET_H */ diff --git a/socketCAN/CO_epoll_interface.c b/socketCAN/CO_epoll_interface.c deleted file mode 100644 index 016a1971..00000000 --- a/socketCAN/CO_epoll_interface.c +++ /dev/null @@ -1,698 +0,0 @@ -/* - * Helper functions for Linux epoll interface to CANopenNode. - * - * @file CO_epoll_interface.c - * @author Janez Paternoster - * @author Martin Wagner - * @copyright 2004 - 2015 Janez Paternoster - * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* following macro is necessary for accept4() function call (sockets) */ -#define _GNU_SOURCE - -#include "CO_epoll_interface.h" - -#include -#include -#include -#include -#include - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -#include -#include -#include -#include -#include -#include -#include - -#ifndef LISTEN_BACKLOG -#define LISTEN_BACKLOG 50 -#endif -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ - -/* delay for recall CANsend(), if CAN TX buffer is full */ -#ifndef CANSEND_DELAY_US -#define CANSEND_DELAY_US 100 -#endif - - -/* EPOLL **********************************************************************/ -/* Helper function - get monotonic clock time in microseconds */ -static inline uint64_t clock_gettime_us(void) { - struct timespec ts; - - (void)clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; -} - -CO_ReturnError_t CO_epoll_create(CO_epoll_t *ep, uint32_t timerInterval_us) { - int ret; - struct epoll_event ev; - - if (ep == NULL) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure epoll for mainline */ - ep->epoll_new = false; - ep->epoll_fd = epoll_create(1); - if (ep->epoll_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_create()"); - return CO_ERROR_SYSCALL; - } - - /* Configure eventfd for notifications and add it to epoll */ - ep->event_fd = eventfd(0, EFD_NONBLOCK); - if (ep->event_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "eventfd()"); - return CO_ERROR_SYSCALL; - } - ev.events = EPOLLIN; - ev.data.fd = ep->event_fd; - ret = epoll_ctl(ep->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(event_fd)"); - return CO_ERROR_SYSCALL; - } - - /* Configure timer for timerInterval_us and add it to epoll */ - ep->timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); - if (ep->timer_fd < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_create()"); - return CO_ERROR_SYSCALL; - } - ep->tm.it_interval.tv_sec = timerInterval_us / 1000000; - ep->tm.it_interval.tv_nsec = (timerInterval_us % 1000000) * 1000; - ep->tm.it_value.tv_sec = 0; - ep->tm.it_value.tv_nsec = 1; - ret = timerfd_settime(ep->timer_fd, 0, &ep->tm, NULL); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "timerfd_settime"); - return CO_ERROR_SYSCALL; - } - ev.events = EPOLLIN; - ev.data.fd = ep->timer_fd; - ret = epoll_ctl(ep->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(timer_fd)"); - return CO_ERROR_SYSCALL; - } - ep->timerInterval_us = timerInterval_us; - ep->previousTime_us = clock_gettime_us(); - ep->timeDifference_us = 0; - - return CO_ERROR_NO; -} - -void CO_epoll_close(CO_epoll_t *ep) { - if (ep == NULL) { - return; - } - - close(ep->epoll_fd); - ep->epoll_fd = -1; - - close(ep->event_fd); - ep->event_fd = -1; - - close(ep->timer_fd); - ep->timer_fd = -1; -} - - -void CO_epoll_wait(CO_epoll_t *ep) { - if (ep == NULL) { - return; - } - - /* wait for an event */ - int ready = epoll_wait(ep->epoll_fd, &ep->ev, 1, -1); - ep->epoll_new = true; - ep->timerEvent = false; - - /* calculate time difference since last call */ - uint64_t now = clock_gettime_us(); - ep->timeDifference_us = (uint32_t)(now - ep->previousTime_us); - ep->previousTime_us = now; - /* application may will lower this */ - ep->timerNext_us = ep->timerInterval_us; - - /* process event */ - if (ready != 1 && errno == EINTR) { - /* event from interrupt or signal, nothing to process, continue */ - ep->epoll_new = false; - } - else if (ready != 1) { - log_printf(LOG_DEBUG, DBG_ERRNO, "epoll_wait"); - ep->epoll_new = false; - } - else if ((ep->ev.events & EPOLLIN) != 0 - && ep->ev.data.fd == ep->event_fd - ) { - uint64_t val; - ssize_t s = read(ep->event_fd, &val, sizeof(uint64_t)); - if (s != sizeof(uint64_t)) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(event_fd)"); - } - ep->epoll_new = false; - } - else if ((ep->ev.events & EPOLLIN) != 0 - && ep->ev.data.fd == ep->timer_fd - ) { - uint64_t val; - ssize_t s = read(ep->timer_fd, &val, sizeof(uint64_t)); - if (s != sizeof(uint64_t) && errno != EAGAIN) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(timer_fd)"); - } - ep->epoll_new = false; - ep->timerEvent = true; - } -} - -void CO_epoll_processLast(CO_epoll_t *ep) { - if (ep == NULL) { - return; - } - - if (ep->epoll_new) { - log_printf(LOG_DEBUG, DBG_EPOLL_UNKNOWN, - ep->ev.events, ep->ev.data.fd); - ep->epoll_new = false; - } - - /* lower next timer interval if changed by application */ - if (ep->timerNext_us < ep->timerInterval_us) { - /* add one microsecond extra delay and make sure it is not zero */ - ep->timerNext_us += 1; - if (ep->timerInterval_us < 1000000) { - ep->tm.it_value.tv_nsec = ep->timerNext_us * 1000; - } - else { - ep->tm.it_value.tv_sec = ep->timerNext_us / 1000000; - ep->tm.it_value.tv_nsec = - (ep->timerNext_us % 1000000) * 1000; - } - int ret = timerfd_settime(ep->timer_fd, 0, &ep->tm, NULL); - if (ret < 0) { - log_printf(LOG_DEBUG, DBG_ERRNO, "timerfd_settime"); - } - } -} - - -/* MAINLINE *******************************************************************/ -#ifndef CO_SINGLE_THREAD -/* Send event to wake CO_epoll_processMain() */ -static void wakeupCallback(void *object) { - CO_epoll_t *ep = (CO_epoll_t *)object; - uint64_t u = 1; - ssize_t s; - s = write(ep->event_fd, &u, sizeof(uint64_t)); - if (s != sizeof(uint64_t)) { - log_printf(LOG_DEBUG, DBG_ERRNO, "write()"); - } -} -#endif - -void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co) { - if (ep == NULL || co == NULL) { - return; - } - -#ifndef CO_SINGLE_THREAD - - /* Configure LSS slave callback function */ - #if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE - #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - CO_LSSslave_initCallbackPre(co->LSSslave, - (void *)ep, wakeupCallback); - #endif - #endif - - if (co->nodeIdUnconfigured) { - return; - } - - /* Configure callback functions */ - #if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_NMT_initCallbackPre(co->NMT, - (void *)ep, wakeupCallback); - #endif - #if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_HBconsumer_initCallbackPre(co->HBcons, - (void *)ep, wakeupCallback); - #endif - #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_EM_initCallbackPre(co->em, - (void *)ep, wakeupCallback); - #endif - #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_SDOserver_initCallbackPre(&co->SDOserver[0], - (void *)ep, wakeupCallback); - #endif - #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_SDOclient_initCallbackPre(&co->SDOclient[0], - (void *)ep, wakeupCallback); - #endif - #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE - CO_TIME_initCallbackPre(co->TIME, - (void *)ep, wakeupCallback); - #endif - #if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE - #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER - CO_LSSmaster_initCallbackPre(co->LSSmaster, - (void *)ep, wakeupCallback); - #endif - #endif - -#endif /* CO_SINGLE_THREAD */ -} - -void CO_epoll_processMain(CO_epoll_t *ep, - CO_t *co, - bool_t enableGateway, - CO_NMT_reset_cmd_t *reset) -{ - if (ep == NULL || co == NULL || reset == NULL) { - return; - } - - /* process CANopen objects */ - *reset = CO_process(co, - enableGateway, - ep->timeDifference_us, - &ep->timerNext_us); - - /* If there are unsent CAN messages, call CO_CANmodule_process() earlier */ - if (co->CANmodule->CANtxCount > 0 && ep->timerNext_us > CANSEND_DELAY_US) { - ep->timerNext_us = CANSEND_DELAY_US; - } -} - - -/* CANrx and REALTIME *********************************************************/ -void CO_epoll_processRT(CO_epoll_t *ep, - CO_t *co, - bool_t realtime) -{ - if (co == NULL || ep == NULL) { - return; - } - - /* Verify for epoll events */ - if (ep->epoll_new) { - if (CO_CANrxFromEpoll(co->CANmodule, &ep->ev, NULL, NULL)) { - ep->epoll_new = false; - } - } - - if (!realtime || ep->timerEvent) { - uint32_t *pTimerNext_us = realtime ? NULL : &ep->timerNext_us; - - CO_LOCK_OD(co->CANmodule); - if (!co->nodeIdUnconfigured && co->CANmodule->CANnormal) { - bool_t syncWas = false; - -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE - syncWas = CO_process_SYNC(co, ep->timeDifference_us, - pTimerNext_us); -#endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE - CO_process_RPDO(co, syncWas, ep->timeDifference_us, - pTimerNext_us); -#endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE - CO_process_TPDO(co, syncWas, ep->timeDifference_us, - pTimerNext_us); -#endif - (void) syncWas; (void) pTimerNext_us; - } - CO_UNLOCK_OD(co->CANmodule); - } -} - -/* GATEWAY ********************************************************************/ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -/* write response string from gateway-ascii object */ -static size_t gtwa_write_response(void *object, - const char *buf, - size_t count, - uint8_t *connectionOK) -{ - int* fd = (int *)object; - /* nWritten = count -> in case of error (non-existing fd) data are purged */ - size_t nWritten = count; - - if (fd != NULL && *fd >= 0) { - ssize_t n = write(*fd, (const void *)buf, count); - if (n >= 0) { - nWritten = (size_t)n; - } - else { - /* probably EAGAIN - "Resource temporarily unavailable". Retry. */ - log_printf(LOG_DEBUG, DBG_ERRNO, "write(gtwa_response)"); - nWritten = 0; - } - } - else { - *connectionOK = 0; - } - return nWritten; -} - -static inline void socetAcceptEnableForEpoll(CO_epoll_gtw_t *epGtw) { - struct epoll_event ev; - int ret; - - ev.events = EPOLLIN | EPOLLONESHOT; - ev.data.fd = epGtw->gtwa_fdSocket; - ret = epoll_ctl(epGtw->epoll_fd, EPOLL_CTL_MOD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fdSocket)"); - } -} - -CO_ReturnError_t CO_epoll_createGtw(CO_epoll_gtw_t *epGtw, - int epoll_fd, - int32_t commandInterface, - uint32_t socketTimeout_ms, - char *localSocketPath) -{ - int ret; - struct epoll_event ev; - - if (epGtw == NULL || epoll_fd < 0) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - - epGtw->epoll_fd = epoll_fd; - epGtw->commandInterface = commandInterface; - - epGtw->socketTimeout_us = (socketTimeout_ms < (UINT_MAX / 1000 - 1000000)) ? - socketTimeout_ms * 1000 : (UINT_MAX - 1000000); - epGtw->gtwa_fdSocket = -1; - epGtw->gtwa_fd = -1; - - if (commandInterface == CO_COMMAND_IF_STDIO) { - epGtw->gtwa_fd = STDIN_FILENO; - log_printf(LOG_INFO, DBG_COMMAND_STDIO_INFO); - } - else if (commandInterface == CO_COMMAND_IF_LOCAL_SOCKET) { - struct sockaddr_un addr; - epGtw->localSocketPath = localSocketPath; - - /* Create, bind and listen local socket */ - epGtw->gtwa_fdSocket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); - if(epGtw->gtwa_fdSocket < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "socket(local)"); - return CO_ERROR_SYSCALL; - } - - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, localSocketPath, sizeof(addr.sun_path) - 1); - ret = bind(epGtw->gtwa_fdSocket, (struct sockaddr *) &addr, - sizeof(struct sockaddr_un)); - if(ret < 0) { - log_printf(LOG_CRIT, DBG_COMMAND_LOCAL_BIND, localSocketPath); - return CO_ERROR_SYSCALL; - } - - ret = listen(epGtw->gtwa_fdSocket, LISTEN_BACKLOG); - if(ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "listen(local)"); - return CO_ERROR_SYSCALL; - } - - /* Ignore the SIGPIPE signal, which may happen, if remote client broke - * the connection. Signal may be triggered by write call inside - * gtwa_write_response() function */ - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { - log_printf(LOG_CRIT, DBG_ERRNO, "signal"); - return CO_ERROR_SYSCALL; - } - - log_printf(LOG_INFO, DBG_COMMAND_LOCAL_INFO, localSocketPath); - } - else if (commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN && - commandInterface <= CO_COMMAND_IF_TCP_SOCKET_MAX - ) { - struct sockaddr_in addr; - const int yes = 1; - - /* Create, bind and listen socket */ - epGtw->gtwa_fdSocket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - if(epGtw->gtwa_fdSocket < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "socket(tcp)"); - return CO_ERROR_SYSCALL; - } - - setsockopt(epGtw->gtwa_fdSocket, SOL_SOCKET, SO_REUSEADDR, - &yes, sizeof(int)); - - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(commandInterface); - addr.sin_addr.s_addr = INADDR_ANY; - - ret = bind(epGtw->gtwa_fdSocket, (struct sockaddr *) &addr, - sizeof(struct sockaddr_in)); - if(ret < 0) { - log_printf(LOG_CRIT, DBG_COMMAND_TCP_BIND, commandInterface); - return CO_ERROR_SYSCALL; - } - - ret = listen(epGtw->gtwa_fdSocket, LISTEN_BACKLOG); - if(ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "listen(tcp)"); - return CO_ERROR_SYSCALL; - } - - /* Ignore the SIGPIPE signal, which may happen, if remote client broke - * the connection. Signal may be triggered by write call inside - * gtwa_write_response() function */ - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { - log_printf(LOG_CRIT, DBG_ERRNO, "signal"); - return CO_ERROR_SYSCALL; - } - - log_printf(LOG_INFO, DBG_COMMAND_TCP_INFO, commandInterface); - } - else { - epGtw->commandInterface = CO_COMMAND_IF_DISABLED; - } - - if (epGtw->gtwa_fd >= 0) { - ev.events = EPOLLIN; - ev.data.fd = epGtw->gtwa_fd; - ret = epoll_ctl(epGtw->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fd)"); - return CO_ERROR_SYSCALL; - } - } - if (epGtw->gtwa_fdSocket >= 0) { - /* prepare epoll for listening for new socket connection. After - * connection will be accepted, fd for io operation will be defined. */ - ev.events = EPOLLIN | EPOLLONESHOT; - ev.data.fd = epGtw->gtwa_fdSocket; - ret = epoll_ctl(epGtw->epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(gtwa_fdSocket)"); - return CO_ERROR_SYSCALL; - } - } - - return CO_ERROR_NO; -} - -void CO_epoll_closeGtw(CO_epoll_gtw_t *epGtw) { - if (epGtw == NULL) { - return; - } - - if (epGtw->commandInterface == CO_COMMAND_IF_LOCAL_SOCKET) { - if (epGtw->gtwa_fd > 0) { - close(epGtw->gtwa_fd); - } - close(epGtw->gtwa_fdSocket); - /* Remove local socket file from filesystem. */ - if(remove(epGtw->localSocketPath) < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "remove(local)"); - } - } - else if (epGtw->commandInterface >= CO_COMMAND_IF_TCP_SOCKET_MIN) { - if (epGtw->gtwa_fd > 0) { - close(epGtw->gtwa_fd); - } - close(epGtw->gtwa_fdSocket); - } - epGtw->gtwa_fd = -1; - epGtw->gtwa_fdSocket = -1; -} - -void CO_epoll_initCANopenGtw(CO_epoll_gtw_t *epGtw, CO_t *co) { - if (epGtw == NULL || co == NULL || co->nodeIdUnconfigured) { - return; - } - - CO_GTWA_initRead(co->gtwa, gtwa_write_response, (void *)&epGtw->gtwa_fd); - epGtw->freshCommand = true; -} - -void CO_epoll_processGtw(CO_epoll_gtw_t *epGtw, - CO_t *co, - CO_epoll_t *ep) -{ - if (epGtw == NULL || co == NULL || ep == NULL) { - return; - } - - /* Verify for epoll events */ - if (ep->epoll_new - && (ep->ev.data.fd == epGtw->gtwa_fdSocket - || ep->ev.data.fd == epGtw->gtwa_fd) - ) { - if ((ep->ev.events & EPOLLIN) != 0 - && ep->ev.data.fd == epGtw->gtwa_fdSocket - ) { - bool_t fail = false; - - epGtw->gtwa_fd = accept4(epGtw->gtwa_fdSocket, - NULL, NULL, SOCK_NONBLOCK); - if (epGtw->gtwa_fd < 0) { - fail = true; - if (errno != EAGAIN && errno != EWOULDBLOCK) { - log_printf(LOG_CRIT, DBG_ERRNO, "accept(gtwa_fdSocket)"); - } - } - else { - /* add fd to epoll */ - struct epoll_event ev2; - ev2.events = EPOLLIN; - ev2.data.fd = epGtw->gtwa_fd; - int ret = epoll_ctl(ep->epoll_fd, - EPOLL_CTL_ADD, ev2.data.fd, &ev2); - if (ret < 0) { - fail = true; - log_printf(LOG_CRIT, DBG_ERRNO, "epoll_ctl(add, gtwa_fd)"); - } - epGtw->socketTimeoutTmr_us = 0; - } - - if (fail) { - socetAcceptEnableForEpoll(epGtw); - } - ep->epoll_new = false; - } - else if ((ep->ev.events & EPOLLIN) != 0 - && ep->ev.data.fd == epGtw->gtwa_fd - ) { - char buf[CO_CONFIG_GTWA_COMM_BUF_SIZE]; - size_t space = co->nodeIdUnconfigured ? - CO_CONFIG_GTWA_COMM_BUF_SIZE : - CO_GTWA_write_getSpace(co->gtwa); - - ssize_t s = read(epGtw->gtwa_fd, buf, space); - - if (space == 0 || co->nodeIdUnconfigured) { - /* continue or purge data */ - } - else if (s < 0 && errno != EAGAIN) { - log_printf(LOG_DEBUG, DBG_ERRNO, "read(gtwa_fd)"); - } - else if (s >= 0) { - if (epGtw->commandInterface == CO_COMMAND_IF_STDIO) { - /* simplify command interface on stdio, make hard to type - * sequence optional, prepend "[0] " to string, if missing */ - const char sequence[] = "[0] "; - bool_t closed = (buf[s-1] == '\n'); /* is command closed? */ - - if (buf[0] != '[' && (space - s) >= strlen(sequence) - && isgraph(buf[0]) && buf[0] != '#' - && closed && epGtw->freshCommand - ) { - CO_GTWA_write(co->gtwa, sequence, strlen(sequence)); - } - epGtw->freshCommand = closed; - CO_GTWA_write(co->gtwa, buf, s); - } - else { /* socket, local or tcp */ - if (s == 0) { - /* EOF received, close connection and enable socket - * accepting */ - int ret = epoll_ctl(ep->epoll_fd, EPOLL_CTL_DEL, - epGtw->gtwa_fd, NULL); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, - "epoll_ctl(del, gtwa_fd)"); - } - if (close(epGtw->gtwa_fd) < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd)"); - } - epGtw->gtwa_fd = -1; - socetAcceptEnableForEpoll(epGtw); - } - else { - CO_GTWA_write(co->gtwa, buf, s); - } - } - } - epGtw->socketTimeoutTmr_us = 0; - - ep->epoll_new = false; - } - else if ((ep->ev.events & (EPOLLERR | EPOLLHUP)) != 0) { - log_printf(LOG_DEBUG, DBG_GENERAL, - "socket error or hangup, event=", ep->ev.events); - if (close(epGtw->gtwa_fd) < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd, hangup)"); - } - } - } /* if (ep->epoll_new) */ - - /* if socket connection is established, verify timeout */ - if (epGtw->socketTimeout_us > 0 - && epGtw->gtwa_fdSocket > 0 && epGtw->gtwa_fd > 0) - { - if (epGtw->socketTimeoutTmr_us > epGtw->socketTimeout_us) { - /* timout expired, close current connection and accept next */ - int ret = epoll_ctl(ep->epoll_fd, - EPOLL_CTL_DEL, epGtw->gtwa_fd, NULL); - if (ret < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, - "epoll_ctl(del, gtwa_fd), tmo"); - } - if (close(epGtw->gtwa_fd) < 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "close(gtwa_fd), tmo"); - } - epGtw->gtwa_fd = -1; - socetAcceptEnableForEpoll(epGtw); - } - else { - epGtw->socketTimeoutTmr_us += ep->timeDifference_us; - } - } -} -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ diff --git a/socketCAN/CO_epoll_interface.h b/socketCAN/CO_epoll_interface.h deleted file mode 100644 index 4244be79..00000000 --- a/socketCAN/CO_epoll_interface.h +++ /dev/null @@ -1,309 +0,0 @@ -/** - * Helper functions for Linux epoll interface to CANopenNode. - * - * @file CO_epoll_interface.h - * @ingroup CO_epoll_interface - * @author Janez Paternoster - * @author Martin Wagner - * @copyright 2004 - 2020 Janez Paternoster - * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CO_EPOLL_INTERFACE_H -#define CO_EPOLL_INTERFACE_H - -#include "CANopen.h" - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_socketCAN socketCAN - * @{ - * - * Linux specific interface to CANopenNode. - * - * Linux includes CAN interface inside its kernel, so called SocketCAN. It - * operates as a network device. For more information on Linux SocketCAN see - * https://www.kernel.org/doc/html/latest/networking/can.html - * - * Linux specific files for interfacing with Linux SocketCAN are located inside - * "CANopenNode/socketCAN" directory. - * - * CANopenNode runs as a set of non-blocking functions. It can run in single or - * multiple threads. Best approach for RT IO device can be with two threads: - * - timer based real-time thread for CAN receive, SYNC and PDO, see - * @ref CO_epoll_processRT() - * - mainline thread for other processing, see @ref CO_epoll_processMain() - * - * Main references for Linux functions used here are Linux man pages and the - * book: The Linux Programming Interface by Michael Kerrisk. - * @} - */ - -/** - * @defgroup CO_epoll_interface Epoll interface - * @ingroup CO_socketCAN - * @{ - * - * Linux epoll interface to CANopenNode. - * - * The Linux epoll API performs a monitoring multiple file descriptors to see - * if I/O is possible on any of them. - * - * CANopenNode uses epoll interface to provide an event based mechanism. Epoll - * waits for multiple different events, such as: interval timer event, - * notification event, CAN receive event or socket based event for gateway. - * CANopenNode non-blocking functions are processed after each event. - * - * CANopenNode itself offers functionality for calculation of time, when next - * interval timer event should trigger the processing. It can also trigger - * notification events in case of multi-thread operation. - */ - -/** - * Object for epoll, timer and event API. - */ -typedef struct { - /** Epoll file descriptor */ - int epoll_fd; - /** Notification event file descriptor */ - int event_fd; - /** Interval timer file descriptor */ - int timer_fd; - /** Interval of the timer in microseconds, from @ref CO_epoll_create() */ - uint32_t timerInterval_us; - /** Time difference since last @ref CO_epoll_wait() execution in - * microseconds */ - uint32_t timeDifference_us; - /** Timer value in microseconds, which can be changed by application and can - * shorten time of next @ref CO_epoll_wait() execution */ - uint32_t timerNext_us; - /** True,if timer event is inside @ref CO_epoll_wait() */ - bool_t timerEvent; - /** time value from the last process call in microseconds */ - uint64_t previousTime_us; - /** Structure for timerfd */ - struct itimerspec tm; - /** Structure for epoll_wait */ - struct epoll_event ev; - /** true, if new epoll event is necessary to process */ - bool_t epoll_new; -} CO_epoll_t; - -/** - * Create Linux epoll, timerfd and eventfd - * - * Create and configure multiple Linux notification facilities, which trigger - * execution of the task. Epoll blocks and monitors multiple file descriptors, - * timerfd triggers in constant timer intervals and eventfd triggers on external - * signal. - * - * @param ep This object - * @param timerInterval_us Timer interval in microseconds - * - * @return @ref CO_ReturnError_t CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or - * CO_ERROR_SYSCALL. - */ -CO_ReturnError_t CO_epoll_create(CO_epoll_t *ep, uint32_t timerInterval_us); - -/** - * Close epoll, timerfd and eventfd - * - * @param ep This object - */ -void CO_epoll_close(CO_epoll_t *ep); - -/** - * Wait for an epoll event - * - * This function blocks until event registered on epoll: timerfd, eventfd, or - * application specified event. Function also calculates timeDifference_us since - * last call and prepares timerNext_us. - * - * @param ep This object - */ -void CO_epoll_wait(CO_epoll_t *ep); - -/** - * Closing function for an epoll event - * - * This function must be called after @ref CO_epoll_wait(). Between them - * should be application specified processing functions, which can check for - * own events and do own processing. Application may also lower timerNext_us - * variable. If lowered, then interval timer will be reconfigured and - * @ref CO_epoll_wait() will be triggered earlier. - * - * @param ep This object - */ -void CO_epoll_processLast(CO_epoll_t *ep); - -/** - * Initialization of functions in CANopen reset-communication section - * - * Configure callbacks for CANopen objects. - * - * @param ep This object - * @param co CANopen object - */ -void CO_epoll_initCANopenMain(CO_epoll_t *ep, CO_t *co); - -/** - * Process CANopen mainline functions - * - * This function calls @ref CO_process(). It is non-blocking and should execute - * cyclically. It should be between @ref CO_epoll_wait() and - * @ref CO_epoll_processLast() functions. - * - * @param ep This object - * @param co CANopen object - * @param enableGateway If true, gateway to external world will be enabled. - * @param [out] reset Return from @ref CO_process(). - */ -void CO_epoll_processMain(CO_epoll_t *ep, - CO_t *co, - bool_t enableGateway, - CO_NMT_reset_cmd_t *reset); - - -/** - * Process CAN receive and realtime functions - * - * This function checks epoll for CAN receive event and processes CANopen - * realtime functions: @ref CO_process_SYNC(), @ref CO_process_RPDO() and - * @ref CO_process_TPDO(). It is non-blocking and should execute cyclically. - * It should be between @ref CO_epoll_wait() and @ref CO_epoll_processLast() - * functions. - * - * Function can be used in the mainline thread or in own realtime thread. - * - * Processing of CANopen realtime functions is protected with @ref CO_LOCK_OD. - * Also Node-Id must be configured and CANmodule must be in CANnormal for - * processing. - * - * @param ep Pointer to @ref CO_epoll_t object. - * @param co CANopen object - * @param realtime Set to true, if function is called from the own realtime - * thread, and is executed at short constant interval. - */ -void CO_epoll_processRT(CO_epoll_t *ep, - CO_t *co, - bool_t realtime); - - -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN -/** - * Command interface type for gateway-ascii - */ -typedef enum { - CO_COMMAND_IF_DISABLED = -100, - CO_COMMAND_IF_STDIO = -2, - CO_COMMAND_IF_LOCAL_SOCKET = -1, - CO_COMMAND_IF_TCP_SOCKET_MIN = 0, - CO_COMMAND_IF_TCP_SOCKET_MAX = 0xFFFF -} CO_commandInterface_t; - -/** - * Object for gateway - */ -typedef struct { - /** Epoll file descriptor, from @ref CO_epoll_createGtw() */ - int epoll_fd; - /** Command interface type or tcp port number, see - * @ref CO_commandInterface_t */ - int32_t commandInterface; - /** Socket timeout in microseconds */ - uint32_t socketTimeout_us; - /** Socket timeout timer in microseconds */ - uint32_t socketTimeoutTmr_us; - /** Path in case of local socket */ - char *localSocketPath; - /** Gateway socket file descriptor */ - int gtwa_fdSocket; - /** Gateway io stream file descriptor */ - int gtwa_fd; - /** Indication of fresh command */ - bool_t freshCommand; -} CO_epoll_gtw_t; - -/** - * Create socket for gateway-ascii command interface and add it to epoll - * - * Depending on arguments function configures stdio interface or local socket - * or IP socket. - * - * @param epGtw This object - * @param epoll_fd Already configured epoll file descriptor - * @param commandInterface Command interface type from CO_commandInterface_t - * @param socketTimeout_ms Timeout for established socket connection in [ms] - * @param localSocketPath File path, if commandInterface is local socket - * - * @return @ref CO_ReturnError_t CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or - * CO_ERROR_SYSCALL. - */ -CO_ReturnError_t CO_epoll_createGtw(CO_epoll_gtw_t *epGtw, - int epoll_fd, - int32_t commandInterface, - uint32_t socketTimeout_ms, - char *localSocketPath); - -/** - * Close gateway-ascii sockets - * - * @param epGtw This object - */ -void CO_epoll_closeGtw(CO_epoll_gtw_t *epGtw); - -/** - * Initialization of gateway functions in CANopen reset-communication section - * - * @param epGtw This object - * @param co CANopen object - */ -void CO_epoll_initCANopenGtw(CO_epoll_gtw_t *epGtw, CO_t *co); - -/** - * Process CANopen gateway functions - * - * This function checks for epoll events and verifies socket connection timeout. - * It is non-blocking and should execute cyclically. It should be between - * @ref CO_epoll_wait() and @ref CO_epoll_processLast() functions. - * - * @param epGtw This object - * @param co CANopen object - * @param ep Pointer to @ref CO_epoll_t object. - */ -void CO_epoll_processGtw(CO_epoll_gtw_t *epGtw, - CO_t *co, - CO_epoll_t *ep); -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ - -/** @} */ - -#ifdef __cplusplus -} -#endif /*__cplusplus*/ - -#endif /* CO_EPOLL_INTERFACE_H */ diff --git a/socketCAN/CO_error.c b/socketCAN/CO_error.c deleted file mode 100644 index 4ceb1bc5..00000000 --- a/socketCAN/CO_error.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * CAN module object for Linux socketCAN Error handling. - * - * @file CO_error.c - * @author Martin Wagner - * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "CO_error.h" -#include "301/CO_driver.h" - - -/** - * Reset CAN interface and set to listen only mode - */ -static CO_CANinterfaceState_t CO_CANerrorSetListenOnly( - CO_CANinterfaceErrorhandler_t *CANerrorhandler, - bool_t resetIf) -{ - log_printf(LOG_DEBUG, DBG_CAN_SET_LISTEN_ONLY, CANerrorhandler->ifName); - - clock_gettime(CLOCK_MONOTONIC, &CANerrorhandler->timestamp); - CANerrorhandler->listenOnly = true; - - if (resetIf) { - int ret; - char command[100]; - snprintf(command, sizeof(command), "ip link set %s down && " - "ip link set %s up " - "&", - CANerrorhandler->ifName, - CANerrorhandler->ifName); - ret = system(command); - if(ret < 0){ - log_printf(LOG_DEBUG, DBG_ERRNO, "system()"); - } - - } - - return CO_INTERFACE_LISTEN_ONLY; -} - - -/** - * Clear listen only - */ -static void CO_CANerrorClearListenOnly( - CO_CANinterfaceErrorhandler_t *CANerrorhandler) -{ - log_printf(LOG_DEBUG, DBG_CAN_CLR_LISTEN_ONLY, CANerrorhandler->ifName); - - CANerrorhandler->listenOnly = false; - CANerrorhandler->timestamp.tv_sec = 0; - CANerrorhandler->timestamp.tv_nsec = 0; -} - - -/** - * Check and handle "bus off" state - */ -static CO_CANinterfaceState_t CO_CANerrorBusoff( - CO_CANinterfaceErrorhandler_t *CANerrorhandler, - const struct can_frame *msg) -{ - CO_CANinterfaceState_t result = CO_INTERFACE_ACTIVE; - - if ((msg->can_id & CAN_ERR_BUSOFF) != 0) { - log_printf(LOG_NOTICE, CAN_BUSOFF, CANerrorhandler->ifName); - - /* The can interface changed it's state to "bus off" (e.g. because of - * a short on the can wires). We re-start the interface and mark it - * "listen only". - * Restarting the interface is the only way to clear kernel and hardware - * tx queues */ - result = CO_CANerrorSetListenOnly(CANerrorhandler, true); - CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_BUS_OFF; - } - return result; -} - - -/** - * Check and handle controller problems - */ -static CO_CANinterfaceState_t CO_CANerrorCrtl( - CO_CANinterfaceErrorhandler_t *CANerrorhandler, - const struct can_frame *msg) -{ - CO_CANinterfaceState_t result = CO_INTERFACE_ACTIVE; - - /* Control - * - error counters (rec/tec) are handled inside CAN hardware, nothing - * to do in here - * - we can't really do anything about buffer overflows here. Confirmed - * CANopen protocols will detect the error, non-confirmed protocols - * need to be error tolerant. - * - There is no information, when CAN controller leaves warning level, - * so we can't clear it. So we also don't set it. */ - if ((msg->can_id & CAN_ERR_CRTL) != 0) { - /* clear bus off here */ - CANerrorhandler->CANerrorStatus &= 0xFFFF ^ CO_CAN_ERRTX_BUS_OFF; - - if ((msg->data[1] & CAN_ERR_CRTL_RX_PASSIVE) != 0) { - log_printf(LOG_NOTICE, CAN_RX_PASSIVE, CANerrorhandler->ifName); - CANerrorhandler->CANerrorStatus |= CO_CAN_ERRRX_PASSIVE; - /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRRX_WARNING; */ - } - else if ((msg->data[1] & CAN_ERR_CRTL_TX_PASSIVE) != 0) { - log_printf(LOG_NOTICE, CAN_TX_PASSIVE, CANerrorhandler->ifName); - CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_PASSIVE; - /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_WARNING; */ - } - else if ((msg->data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) { - log_printf(LOG_NOTICE, CAN_RX_BUF_OVERFLOW, CANerrorhandler->ifName); - CANerrorhandler->CANerrorStatus |= CO_CAN_ERRRX_OVERFLOW; - } - else if ((msg->data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) { - log_printf(LOG_NOTICE, CAN_TX_BUF_OVERFLOW, CANerrorhandler->ifName); - CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; - } - else if ((msg->data[1] & CAN_ERR_CRTL_RX_WARNING) != 0) { - log_printf(LOG_INFO, CAN_RX_LEVEL_WARNING, CANerrorhandler->ifName); - /* clear passive flag, set warning */ - CANerrorhandler->CANerrorStatus &= 0x7FFF ^ CO_CAN_ERRRX_PASSIVE; - /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRRX_WARNING; */ - } - else if ((msg->data[1] & CAN_ERR_CRTL_TX_WARNING) != 0) { - log_printf(LOG_INFO, CAN_TX_LEVEL_WARNING, CANerrorhandler->ifName); - /* clear passive flag, set warning */ - CANerrorhandler->CANerrorStatus &= 0x7FFF ^ CO_CAN_ERRTX_PASSIVE; - /* CANerrorhandler->CANerrorStatus |= CO_CAN_ERRTX_WARNING; */ - } -#ifdef CAN_ERR_CRTL_ACTIVE - else if ((msg->data[1] & CAN_ERR_CRTL_ACTIVE) != 0) { - log_printf(LOG_NOTICE, CAN_TX_LEVEL_ACTIVE, CANerrorhandler->ifName); - } -#endif - } - return result; -} - - -/** - * Check and handle controller problems - */ -static CO_CANinterfaceState_t CO_CANerrorNoack( - CO_CANinterfaceErrorhandler_t *CANerrorhandler, - const struct can_frame *msg) -{ - CO_CANinterfaceState_t result = CO_INTERFACE_ACTIVE; - - if (CANerrorhandler->listenOnly) { - return CO_INTERFACE_LISTEN_ONLY; - } - - /* received no ACK on transmission */ - if ((msg->can_id & CAN_ERR_ACK) != 0) { - CANerrorhandler->noackCounter ++; - if (CANerrorhandler->noackCounter > CO_CANerror_NOACK_MAX) { - log_printf(LOG_INFO, CAN_NOACK, CANerrorhandler->ifName); - - /* We get the NO-ACK error continuously when no other CAN node - * is active on the bus (Error Counting exception 1 in CAN spec). - * todo - you need to pull the message causing no-ack from the CAN - * hardware buffer. This can be done by either resetting interface - * in here or deleting it within Linux Kernel can driver (set "false"). */ - result = CO_CANerrorSetListenOnly(CANerrorhandler, true); - } - } - else { - CANerrorhandler->noackCounter = 0; - } - return result; -} - - -/******************************************************************************/ -void CO_CANerror_init( - CO_CANinterfaceErrorhandler_t *CANerrorhandler, - int fd, - const char *ifName) -{ - if (CANerrorhandler == NULL) { - return; - } - - CANerrorhandler->fd = fd; - memcpy(CANerrorhandler->ifName, ifName, sizeof(CANerrorhandler->ifName)); - CANerrorhandler->noackCounter = 0; - CANerrorhandler->listenOnly = false; - CANerrorhandler->timestamp.tv_sec = 0; - CANerrorhandler->timestamp.tv_nsec = 0; - CANerrorhandler->CANerrorStatus = 0; -} - - -/******************************************************************************/ -void CO_CANerror_disable( - CO_CANinterfaceErrorhandler_t *CANerrorhandler) -{ - if (CANerrorhandler == NULL) { - return; - } - - memset(CANerrorhandler, 0, sizeof(*CANerrorhandler)); - CANerrorhandler->fd = -1; -} - - -/******************************************************************************/ -void CO_CANerror_rxMsg( - CO_CANinterfaceErrorhandler_t *CANerrorhandler) -{ - if (CANerrorhandler == NULL) { - return; - } - - /* someone is active, we can leave listen only immediately */ - if (CANerrorhandler->listenOnly) { - CO_CANerrorClearListenOnly(CANerrorhandler); - } - CANerrorhandler->noackCounter = 0; -} - - -/******************************************************************************/ -CO_CANinterfaceState_t CO_CANerror_txMsg( - CO_CANinterfaceErrorhandler_t *CANerrorhandler) -{ - struct timespec now; - - if (CANerrorhandler == NULL) { - return CO_INTERFACE_BUS_OFF; - } - - if (CANerrorhandler->listenOnly) { - clock_gettime(CLOCK_MONOTONIC, &now); - if (CANerrorhandler->timestamp.tv_sec + CO_CANerror_LISTEN_ONLY < now.tv_sec) { - /* let's try that again. Maybe someone is waiting for LSS now. It - * doesn't matter which message is sent, as all messages are ACKed. */ - CO_CANerrorClearListenOnly(CANerrorhandler); - return CO_INTERFACE_ACTIVE; - } - return CO_INTERFACE_LISTEN_ONLY; - } - return CO_INTERFACE_ACTIVE; -} - - -/******************************************************************************/ -CO_CANinterfaceState_t CO_CANerror_rxMsgError( - CO_CANinterfaceErrorhandler_t *CANerrorhandler, - const struct can_frame *msg) -{ - if (CANerrorhandler == NULL) { - return CO_INTERFACE_BUS_OFF; - } - - CO_CANinterfaceState_t result; - - /* Log all error messages in full to debug log, even if analysis is done - * further on. */ - log_printf(LOG_DEBUG, DBG_CAN_ERROR_GENERAL, (int)msg->can_id, - msg->data[0], msg->data[1], msg->data[2], msg->data[3], - msg->data[4], msg->data[5], msg->data[6], msg->data[7], - CANerrorhandler->ifName); - - /* Process errors - start with the most unambiguous one */ - - result = CO_CANerrorBusoff(CANerrorhandler, msg); - if (result != CO_INTERFACE_ACTIVE) { - return result; - } - - result = CO_CANerrorCrtl(CANerrorhandler, msg); - if (result != CO_INTERFACE_ACTIVE) { - return result; - } - - result = CO_CANerrorNoack(CANerrorhandler, msg); - if (result != CO_INTERFACE_ACTIVE) { - return result; - } - - return CO_INTERFACE_ACTIVE; -} diff --git a/socketCAN/CO_error.h b/socketCAN/CO_error.h deleted file mode 100644 index 5c99772d..00000000 --- a/socketCAN/CO_error.h +++ /dev/null @@ -1,191 +0,0 @@ -/** - * CANopenNode Linux socketCAN Error handling. - * - * @file CO_error.h - * @ingroup CO_socketCAN_ERROR - * @author Martin Wagner - * @copyright 2018 - 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_ERROR_H -#define CO_ERROR_H - -#include -#include -#include -#include -#include - -#if __has_include("CO_error_custom.h") - #include "CO_error_custom.h" -#else - #include "CO_error_msgs.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_socketCAN_ERROR CAN errors & Log - * @ingroup CO_socketCAN - * @{ - * - * CANopen Errors and System message log - */ - -/** - * Message logging function. - * - * Function must be defined by application. It should record log message to some - * place, for example syslog() call in Linux or logging functionality in - * CANopen gateway @ref CO_CANopen_309_3. - * - * By default system stores messages in /var/log/syslog file. - * Log can optionally be configured before, for example to filter out less - * critical errors than LOG_NOTICE, specify program name, print also process PID - * and print also to standard error, set 'user' type of program, use: - * @code - * setlogmask (LOG_UPTO (LOG_NOTICE)); - * openlog ("exampleprog", LOG_PID | LOG_PERROR, LOG_USER); - * @endcode - * - * @param priority one of LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, - * LOG_NOTICE, LOG_INFO, LOG_DEBUG - * @param format format string as in printf - */ -void log_printf(int priority, const char *format, ...); - - -/** - * driver interface state - * - * CAN hardware can be in the followning states: - * - error active (OK) - * - error passive (Can't generate error flags) - * - bus off (no influence on bus) - */ -typedef enum { - CO_INTERFACE_ACTIVE, /**< CAN error passive/active */ - CO_INTERFACE_LISTEN_ONLY, /**< CAN error passive/active, but currently no other device on bus */ - CO_INTERFACE_BUS_OFF /**< CAN bus off */ -} CO_CANinterfaceState_t; - - -/** - * This is how many NO-ACKs need to be received in a row to assume - * that no other nodes are connected to a bus and therefore are - * assuming listen-only - */ -#define CO_CANerror_NOACK_MAX 16 - - -/** - * This is how long we are going to block transmission if listen-only - * mode is active - * - * Time is in seconds. - */ -#define CO_CANerror_LISTEN_ONLY 10 - - -/** - * socketCAN interface error handling - */ -typedef struct { - int fd; /**< interface FD */ - char ifName[IFNAMSIZ]; /**< interface name as string */ - uint32_t noackCounter; /**< counts no ACK on CAN transmission */ - volatile unsigned char listenOnly; /**< set to listen only mode */ - struct timespec timestamp; /**< listen only mode started at this time */ - uint16_t CANerrorStatus; /**< CAN error status bitfield, see @ref CO_CAN_ERR_status_t */ -} CO_CANinterfaceErrorhandler_t; - - -/** - * Initialize CAN error handler - * - * We need one error handler per interface - * - * @param CANerrorhandler This object will be initialized. - * @param fd interface file descriptor - * @param ifname interface name as string - */ -void CO_CANerror_init( - CO_CANinterfaceErrorhandler_t *CANerrorhandler, - int fd, - const char *ifname); - - -/** - * Reset CAN error handler - * - * @param CANerrorhandler CAN error object. - */ -void CO_CANerror_disable( - CO_CANinterfaceErrorhandler_t *CANerrorhandler); - - -/** - * Message received event - * - * When a message is received at least one other CAN module is connected. - * Function clears listenOnly and noackCounter error flags. - * - * @param CANerrorhandler CAN error object. - */ -void CO_CANerror_rxMsg( - CO_CANinterfaceErrorhandler_t *CANerrorhandler); - - -/** - * Check if interface is ready for message transmission - * - * Message mustn't be transmitted if not ready. - * - * @param CANerrorhandler CAN error object. - * @return CO_INTERFACE_ACTIVE message transmission ready - */ -CO_CANinterfaceState_t CO_CANerror_txMsg( - CO_CANinterfaceErrorhandler_t *CANerrorhandler); - - -/** - * Error message received event - * - * This handles all received error messages. - * - * @param CANerrorhandler CAN error object. - * @param msg received error message - * @return #CO_CANinterfaceState_t - */ -CO_CANinterfaceState_t CO_CANerror_rxMsgError( - CO_CANinterfaceErrorhandler_t *CANerrorhandler, - const struct can_frame *msg); - - -/** @} */ - -#ifdef __cplusplus -} -#endif /*__cplusplus*/ - -#endif /* CO_ERROR_H */ diff --git a/socketCAN/CO_error_msgs.h b/socketCAN/CO_error_msgs.h deleted file mode 100644 index 1c23bc00..00000000 --- a/socketCAN/CO_error_msgs.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Definitions for CANopenNode Linux socketCAN Error handling. - * - * @file CO_Error_msgs.h - * @author Martin Wagner - * @copyright 2020 Neuberger Gebaeudeautomation GmbH - * - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef CO_ERROR_MSGS_H -#define CO_ERROR_MSGS_H - -#ifdef __cplusplus -extern "C" { -#endif - - -/* - * Message definitions for Linux CANopen socket driver (notice and errors) - */ -#define CAN_NOT_FOUND "(%s) CAN Interface \"%s\" not found", __func__ -#define CAN_INIT_FAILED "(%s) CAN Interface \"%s\" Init failed", __func__ -#define CAN_BINDING_FAILED "(%s) Binding CAN Interface \"%s\" failed", __func__ -#define CAN_ERROR_FILTER_FAILED "(%s) Setting CAN Interface \"%s\" error filter failed", __func__ -#define CAN_FILTER_FAILED "(%s) Setting CAN Interface \"%s\" message filter failed", __func__ -#define CAN_NAMETOINDEX "CAN Interface \"%s\" -> Index %d" -#define CAN_SOCKET_BUF_SIZE "CAN Interface \"%s\" RX buffer set to %d messages (%d Bytes)" -#define CAN_RX_SOCKET_QUEUE_OVERFLOW "CAN Interface \"%s\" has lost %d messages" -#define CAN_BUSOFF "CAN Interface \"%s\" changed to \"Bus Off\". Switching to Listen Only mode..." -#define CAN_NOACK "CAN Interface \"%s\" no \"ACK\" received. Switching to Listen Only mode..." -#define CAN_RX_PASSIVE "CAN Interface \"%s\" changed state to \"Rx Passive\"" -#define CAN_TX_PASSIVE "CAN Interface \"%s\" changed state to \"Tx Passive\"" -#define CAN_TX_LEVEL_ACTIVE "CAN Interface \"%s\" changed state to \"Active\"" -#define CAN_RX_BUF_OVERFLOW "CAN Interface \"%s\" Rx buffer overflow. Message dropped" -#define CAN_TX_BUF_OVERFLOW "CAN Interface \"%s\" Tx buffer overflow. Message dropped" -#define CAN_RX_LEVEL_WARNING "CAN Interface \"%s\" reached Rx Warning Level" -#define CAN_TX_LEVEL_WARNING "CAN Interface \"%s\" reached Tx Warning Level" - - -/* - * Message definitions for debugging - */ -#define DBG_GENERAL "(%s) Error: %s%d", __func__ -#define DBG_ERRNO "(%s) OS error \"%s\" in %s", __func__, strerror(errno) -#define DBG_CO_DEBUG "(%s) CO_DEBUG: %s", __func__ -#define DBG_CAN_TX_FAILED "(%s) Transmitting CAN msg OID 0x%03x failed(%s)", __func__ -#define DBG_CAN_RX_PARAM_FAILED "(%s) Setting CAN rx buffer failed (%s)", __func__ -#define DBG_CAN_RX_FAILED "(%s) Receiving CAN msg failed (%s)", __func__ -#define DBG_CAN_ERROR_GENERAL "(%s) Socket error msg ID: 0x%08x, Data[0..7]: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x (%s)", __func__ -#define DBG_CAN_RX_EPOLL "(%s) CAN Epoll error (0x%02x - %s)", __func__ -#define DBG_CAN_SET_LISTEN_ONLY "(%s) %s Set Listen Only", __func__ -#define DBG_CAN_CLR_LISTEN_ONLY "(%s) %s Leave Listen Only", __func__ - -/* mainline */ -#define DBG_EMERGENCY_RX "CANopen Emergency message from node 0x%02X: errorCode=0x%04X, errorRegister=0x%02X, errorBit=0x%02X, infoCode=0x%08X" -#define DBG_NMT_CHANGE "CANopen NMT state changed to: \"%s\" (%d)" -#define DBG_HB_CONS_NMT_CHANGE "CANopen Remote node ID = 0x%02X (index = %d): NMT state changed to: \"%s\" (%d)" -#define DBG_ARGUMENT_UNKNOWN "(%s) Unknown %s argument: \"%s\"", __func__ -#define DBG_NOT_TCP_PORT "(%s) -c argument \"%s\" is not a valid tcp port", __func__ -#define DBG_WRONG_NODE_ID "(%s) Wrong node ID \"%d\"", __func__ -#define DBG_WRONG_PRIORITY "(%s) Wrong RT priority \"%d\"", __func__ -#define DBG_NO_CAN_DEVICE "(%s) Can't find CAN device \"%s\"", __func__ -#define DBG_STORAGE "(%s) Error with storage \"%s\"", __func__ -#define DBG_OD_ENTRY "(%s) Error in Object Dictionary entry: 0x%X", __func__ -#define DBG_CAN_OPEN "(%s) CANopen error in %s, err=%d", __func__ -#define DBG_CAN_OPEN_INFO "CANopen device, Node ID = 0x%02X, %s" - -/* CO_epoll_interface */ -#define DBG_EPOLL_UNKNOWN "(%s) CAN Epoll error, events=0x%02x, fd=%d", __func__ -#define DBG_COMMAND_LOCAL_BIND "(%s) Can't bind local socket to path \"%s\"", __func__ -#define DBG_COMMAND_TCP_BIND "(%s) Can't bind tcp socket to port \"%d\"", __func__ -#define DBG_COMMAND_STDIO_INFO "CANopen command interface on \"standard IO\" started" -#define DBG_COMMAND_LOCAL_INFO "CANopen command interface on local socket \"%s\" started" -#define DBG_COMMAND_TCP_INFO "CANopen command interface on tcp port \"%d\" started" - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CO_ERROR_MSGS_H */ diff --git a/socketCAN/CO_main_basic.c b/socketCAN/CO_main_basic.c deleted file mode 100644 index 7358051e..00000000 --- a/socketCAN/CO_main_basic.c +++ /dev/null @@ -1,819 +0,0 @@ -/* - * CANopen main program file for CANopenNode on Linux. - * - * @file CO_main_basic.c - * @author Janez Paternoster - * @copyright 2020 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "CANopen.h" -#include "OD.h" -#include "CO_error.h" -#include "CO_epoll_interface.h" -#include "CO_storageLinux.h" - -/* Call external application functions. */ -#ifdef CO_USE_APPLICATION -#include "CO_application.h" -#endif - -/* Add trace functionality for recording variables over time */ -#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE -#include "CO_time_trace.h" -#endif - - -/* Interval of mainline and real-time thread in microseconds */ -#ifndef MAIN_THREAD_INTERVAL_US -#define MAIN_THREAD_INTERVAL_US 100000 -#endif -#ifndef TMR_THREAD_INTERVAL_US -#define TMR_THREAD_INTERVAL_US 1000 -#endif - -/* default values for CO_CANopenInit() */ -#ifndef NMT_CONTROL -#define NMT_CONTROL \ - CO_NMT_STARTUP_TO_OPERATIONAL \ - | CO_NMT_ERR_ON_ERR_REG \ - | CO_ERR_REG_GENERIC_ERR \ - | CO_ERR_REG_COMMUNICATION -#endif -#ifndef FIRST_HB_TIME -#define FIRST_HB_TIME 500 -#endif -#ifndef SDO_SRV_TIMEOUT_TIME -#define SDO_SRV_TIMEOUT_TIME 1000 -#endif -#ifndef SDO_CLI_TIMEOUT_TIME -#define SDO_CLI_TIMEOUT_TIME 500 -#endif -#ifndef SDO_CLI_BLOCK -#define SDO_CLI_BLOCK false -#endif -#ifndef OD_STATUS_BITS -#define OD_STATUS_BITS NULL -#endif -/* CANopen gateway enable switch for CO_epoll_processMain() */ -#ifndef GATEWAY_ENABLE -#define GATEWAY_ENABLE true -#endif -/* Interval for time stamp message in milliseconds */ -#ifndef TIME_STAMP_INTERVAL_MS -#define TIME_STAMP_INTERVAL_MS 10000 -#endif - -/* Definitions for application specific data storage objects */ -#ifndef CO_STORAGE_APPLICATION -#define CO_STORAGE_APPLICATION -#endif -/* Interval for automatic data storage in microseconds */ -#ifndef CO_STORAGE_AUTO_INTERVAL -#define CO_STORAGE_AUTO_INTERVAL 60000000 -#endif - -/* CANopen object */ -CO_t *CO = NULL; - -/* Active node-id, copied from pendingNodeId in the communication reset */ -static uint8_t CO_activeNodeId = CO_LSS_NODE_ID_ASSIGNMENT; - -/* Data block for mainline data, which can be stored to non-volatile memory */ -typedef struct { - /* Pending CAN bit rate, can be set by argument or LSS slave. */ - uint16_t pendingBitRate; - /* Pending CANopen NodeId, can be set by argument or LSS slave. */ - uint8_t pendingNodeId; -} mainlineStorage_t; - -mainlineStorage_t mlStorage = { - .pendingBitRate = 0, - .pendingNodeId = CO_LSS_NODE_ID_ASSIGNMENT -}; - -#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE -static CO_time_t CO_time; /* Object for current time */ -#endif - - -/* Helper functions ***********************************************************/ -#ifndef CO_SINGLE_THREAD -/* Realtime thread */ -CO_epoll_t epRT; -static void* rt_thread(void* arg); -#endif - -/* Signal handler */ -volatile sig_atomic_t CO_endProgram = 0; -static void sigHandler(int sig) { - (void)sig; - CO_endProgram = 1; -} - -/* Message logging function */ -void log_printf(int priority, const char *format, ...) { - va_list ap; - - va_start(ap, format); - vsyslog(priority, format, ap); - va_end(ap); - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG - if (CO != NULL) { - char buf[200]; - time_t timer; - struct tm* tm_info; - size_t len; - - timer = time(NULL); - tm_info = localtime(&timer); - len = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S: ", tm_info); - - va_start(ap, format); - vsnprintf(buf + len, sizeof(buf) - len - 2, format, ap); - va_end(ap); - strcat(buf, "\r\n"); - CO_GTWA_log_print(CO->gtwa, buf); - } -#endif -} - -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER -/* callback for emergency messages */ -static void EmergencyRxCallback(const uint16_t ident, - const uint16_t errorCode, - const uint8_t errorRegister, - const uint8_t errorBit, - const uint32_t infoCode) -{ - int16_t nodeIdRx = ident ? (ident&0x7F) : CO_activeNodeId; - - log_printf(LOG_NOTICE, DBG_EMERGENCY_RX, nodeIdRx, errorCode, - errorRegister, errorBit, infoCode); -} -#endif - -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) \ - || ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) -/* return string description of NMT state. */ -static char *NmtState2Str(CO_NMT_internalState_t state) -{ - switch(state) { - case CO_NMT_INITIALIZING: return "initializing"; - case CO_NMT_PRE_OPERATIONAL: return "pre-operational"; - case CO_NMT_OPERATIONAL: return "operational"; - case CO_NMT_STOPPED: return "stopped"; - default: return "unknown"; - } -} -#endif - -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE -/* callback for NMT change messages */ -static void NmtChangedCallback(CO_NMT_internalState_t state) -{ - log_printf(LOG_NOTICE, DBG_NMT_CHANGE, NmtState2Str(state), state); -} -#endif - -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE -/* callback for monitoring Heartbeat remote NMT state change */ -static void HeartbeatNmtChangedCallback(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t state, - void *object) -{ - (void)object; - log_printf(LOG_NOTICE, DBG_HB_CONS_NMT_CHANGE, - nodeId, idx, NmtState2Str(state), state); -} -#endif - -/* callback for storing node id and bitrate */ -static bool_t LSScfgStoreCallback(void *object, uint8_t id, uint16_t bitRate) { - mainlineStorage_t *mainlineStorage = object; - mainlineStorage->pendingNodeId = id; - mainlineStorage->pendingBitRate = bitRate; - return true; -} - -/* Print usage */ -static void printUsage(char *progName) { -printf( -"Usage: %s [options]\n", progName); -printf( -"\n" -"Options:\n" -" -i CANopen Node-id (1..127) or 0xFF (LSS unconfigured).\n"); -#ifndef CO_SINGLE_THREAD -printf( -" -p Real-time priority of RT thread (1 .. 99). If not set or\n" -" set to -1, then normal scheduler is used for RT thread.\n"); -#endif -printf( -" -r Enable reboot on CANopen NMT reset_node command. \n"); -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE -printf( -" -s Path and filename prefix for data storage files.\n" -" By default files are stored in current dictionary.\n"); -#endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII -printf( -" -c Enable command interface for master functionality.\n" -" One of three types of interfaces can be specified as:\n" -" 1. \"stdio\" - Standard IO of a program (terminal).\n" -" 2. \"local-\" - Local socket interface on file\n" -" path, for example \"local-/tmp/CO_command_socket\".\n" -" 3. \"tcp-\" - Tcp socket interface on specified \n" -" port, for example \"tcp-60000\".\n" -" Note that this option may affect security of the CAN.\n" -" -T If -c is specified as local or tcp socket, then this\n" -" parameter specifies socket timeout time in milliseconds.\n" -" Default is 0 - no timeout on established connection.\n"); -#endif -printf( -"\n" -"See also: https://github.com/CANopenNode/CANopenNode\n" -"\n"); -} - - -/******************************************************************************* - * Mainline thread - ******************************************************************************/ -int main (int argc, char *argv[]) { - int programExit = EXIT_SUCCESS; - CO_epoll_t epMain; -#ifndef CO_SINGLE_THREAD - pthread_t rt_thread_id; - int rtPriority = -1; -#endif - CO_NMT_reset_cmd_t reset = CO_RESET_NOT; - CO_ReturnError_t err; - CO_CANptrSocketCan_t CANptr = {0}; - int opt; - bool_t firstRun = true; - - char* CANdevice = NULL; /* CAN device, configurable by arguments. */ - int16_t nodeIdFromArgs = -1; /* May be set by arguments */ - bool_t rebootEnable = false; /* Configurable by arguments */ - -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - CO_storage_t storage; - CO_storage_entry_t storageEntries[] = { - { - .addr = &OD_PERSIST_COMM, - .len = sizeof(OD_PERSIST_COMM), - .subIndexOD = 2, - .attr = CO_storage_cmd | CO_storage_restore, - .filename = {'o','d','_','c','o','m','m', - '.','p','e','r','s','i','s','t','\0'} - }, - { - .addr = &mlStorage, - .len = sizeof(mlStorage), - .subIndexOD = 4, - .attr = CO_storage_cmd | CO_storage_auto | CO_storage_restore, - .filename = {'m','a','i','n','l','i','n','e', - '.','p','e','r','s','i','s','t','\0'} - }, - CO_STORAGE_APPLICATION - }; - uint8_t storageEntriesCount = sizeof(storageEntries) / sizeof(storageEntries[0]); - uint32_t storageInitError = 0; - uint32_t storageErrorPrev = 0; - uint32_t storageIntervalTimer = 0; -#endif - -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - CO_epoll_gtw_t epGtw; - /* values from CO_commandInterface_t */ - int32_t commandInterface = CO_COMMAND_IF_DISABLED; - /* local socket path if commandInterface == CO_COMMAND_IF_LOCAL_SOCKET */ - char *localSocketPath = NULL; - uint32_t socketTimeout_ms = 0; -#else - #define commandInterface 0 - #define localSocketPath NULL -#endif - - /* configure system log */ - setlogmask(LOG_UPTO (LOG_DEBUG)); /* LOG_DEBUG - log all messages */ - openlog(argv[0], LOG_PID | LOG_PERROR, LOG_USER); /* print also to standard error */ - - /* Get program options */ - if(argc < 2 || strcmp(argv[1], "--help") == 0){ - printUsage(argv[0]); - exit(EXIT_SUCCESS); - } - while((opt = getopt(argc, argv, "i:p:rc:T:s:")) != -1) { - switch (opt) { - case 'i': { - long int nodeIdLong = strtol(optarg, NULL, 0); - nodeIdFromArgs = (nodeIdLong < 0 || nodeIdLong > 0xFF) - ? 0 : (uint8_t)strtol(optarg, NULL, 0); - break; - } -#ifndef CO_SINGLE_THREAD - case 'p': rtPriority = strtol(optarg, NULL, 0); - break; -#endif - case 'r': rebootEnable = true; - break; -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - case 'c': { - const char *comm_stdio = "stdio"; - const char *comm_local = "local-"; - const char *comm_tcp = "tcp-"; - if (strcmp(optarg, comm_stdio) == 0) { - commandInterface = CO_COMMAND_IF_STDIO; - } - else if (strncmp(optarg, comm_local, strlen(comm_local)) == 0) { - commandInterface = CO_COMMAND_IF_LOCAL_SOCKET; - localSocketPath = &optarg[6]; - } - else if (strncmp(optarg, comm_tcp, strlen(comm_tcp)) == 0) { - const char *portStr = &optarg[4]; - uint16_t port; - int nMatch = sscanf(portStr, "%hu", &port); - if(nMatch != 1) { - log_printf(LOG_CRIT, DBG_NOT_TCP_PORT, portStr); - exit(EXIT_FAILURE); - } - commandInterface = port; - } - else { - log_printf(LOG_CRIT, DBG_ARGUMENT_UNKNOWN, "-c", optarg); - exit(EXIT_FAILURE); - } - break; - } - case 'T': - socketTimeout_ms = strtoul(optarg, NULL, 0); - break; -#endif -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - case 's': { - /* add prefix to each storageEntries[i].filename */ - for (uint8_t i = 0; i < storageEntriesCount; i++) { - char* filePrefix = optarg; - size_t filePrefixLen = strlen(filePrefix); - char* file = storageEntries[i].filename; - size_t fileLen = strlen(file); - if (fileLen + filePrefixLen < CO_STORAGE_PATH_MAX) { - memmove(&file[filePrefixLen], &file[0], fileLen + 1); - memcpy(&file[0], &filePrefix[0], filePrefixLen); - } - } - break; - } -#endif - default: - printUsage(argv[0]); - exit(EXIT_FAILURE); - } - } - - if(optind < argc) { - CANdevice = argv[optind]; - CANptr.can_ifindex = if_nametoindex(CANdevice); - } - - /* Valid NodeId is 1..127 or 0xFF(unconfigured) in case of LSSslaveEnabled*/ - if ((nodeIdFromArgs == 0 || nodeIdFromArgs > 127) - && (!CO_isLSSslaveEnabled(CO) - || nodeIdFromArgs != CO_LSS_NODE_ID_ASSIGNMENT) - ) { - log_printf(LOG_CRIT, DBG_WRONG_NODE_ID, nodeIdFromArgs); - printUsage(argv[0]); - exit(EXIT_FAILURE); - } - -#ifndef CO_SINGLE_THREAD - if(rtPriority != -1 && (rtPriority < sched_get_priority_min(SCHED_FIFO) - || rtPriority > sched_get_priority_max(SCHED_FIFO))) { - log_printf(LOG_CRIT, DBG_WRONG_PRIORITY, rtPriority); - printUsage(argv[0]); - exit(EXIT_FAILURE); - } -#endif - - if(CANptr.can_ifindex == 0) { - log_printf(LOG_CRIT, DBG_NO_CAN_DEVICE, CANdevice); - exit(EXIT_FAILURE); - } - - - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, mlStorage.pendingNodeId,"starting"); - - - /* Allocate memory for CANopen objects */ - uint32_t heapMemoryUsed = 0; - CO = CO_new(NULL, &heapMemoryUsed); - if (CO == NULL) { - log_printf(LOG_CRIT, DBG_GENERAL, - "CO_new(), heapMemoryUsed=", heapMemoryUsed); - exit(EXIT_FAILURE); - } - - -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - err = CO_storageLinux_init(&storage, - CO->CANmodule, - OD_ENTRY_H1010_storeParameters, - OD_ENTRY_H1011_restoreDefaultParameters, - storageEntries, - storageEntriesCount, - &storageInitError); - - if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) { - char *filename = storageInitError < storageEntriesCount - ? storageEntries[storageInitError].filename : "???"; - log_printf(LOG_CRIT, DBG_STORAGE, filename); - exit(EXIT_FAILURE); - } -#endif - - /* Overwrite stored node-id, if specified by program arguments */ - if (nodeIdFromArgs > 0) { - mlStorage.pendingNodeId = (uint8_t)nodeIdFromArgs; - } - - /* Catch signals SIGINT and SIGTERM */ - if(signal(SIGINT, sigHandler) == SIG_ERR) { - log_printf(LOG_CRIT, DBG_ERRNO, "signal(SIGINT, sigHandler)"); - exit(EXIT_FAILURE); - } - if(signal(SIGTERM, sigHandler) == SIG_ERR) { - log_printf(LOG_CRIT, DBG_ERRNO, "signal(SIGTERM, sigHandler)"); - exit(EXIT_FAILURE); - } - - /* get current time for CO_TIME_set(), since January 1, 1984, UTC. */ - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { - log_printf(LOG_CRIT, DBG_GENERAL, "clock_gettime(main)", 0); - exit(EXIT_FAILURE); - } - uint16_t time_days = (uint16_t)(ts.tv_sec / (24 * 60 * 60)); - time_days -= 5113; /* difference between Unix epoch and CANopen Epoch */ - uint32_t time_ms = (uint32_t)(ts.tv_sec % (24 * 60 * 60)) * 1000; - time_ms += ts.tv_nsec / 1000000; - - /* Create epoll functions */ - err = CO_epoll_create(&epMain, MAIN_THREAD_INTERVAL_US); - if(err != CO_ERROR_NO) { - log_printf(LOG_CRIT, DBG_GENERAL, - "CO_epoll_create(main), err=", err); - exit(EXIT_FAILURE); - } -#ifndef CO_SINGLE_THREAD - err = CO_epoll_create(&epRT, TMR_THREAD_INTERVAL_US); - if(err != CO_ERROR_NO) { - log_printf(LOG_CRIT, DBG_GENERAL, - "CO_epoll_create(RT), err=", err); - exit(EXIT_FAILURE); - } - CANptr.epoll_fd = epRT.epoll_fd; -#else - CANptr.epoll_fd = epMain.epoll_fd; -#endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - err = CO_epoll_createGtw(&epGtw, epMain.epoll_fd, commandInterface, - socketTimeout_ms, localSocketPath); - if(err != CO_ERROR_NO) { - log_printf(LOG_CRIT, DBG_GENERAL, "CO_epoll_createGtw(), err=", err); - exit(EXIT_FAILURE); - } -#endif - - - while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) { -/* CANopen communication reset - initialize CANopen objects *******************/ - uint32_t errInfo; - - /* Wait rt_thread. */ - if(!firstRun) { - CO_LOCK_OD(CO->CANmodule); - CO->CANmodule->CANnormal = false; - CO_UNLOCK_OD(CO->CANmodule); - } - - /* Enter CAN configuration. */ - CO_CANsetConfigurationMode((void *)&CANptr); - CO_CANmodule_disable(CO->CANmodule); - - - /* initialize CANopen */ - err = CO_CANinit(CO, (void *)&CANptr, 0 /* bit rate not used */); - if(err != CO_ERROR_NO) { - log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANinit()", err); - programExit = EXIT_FAILURE; - CO_endProgram = 1; - continue; - } - - CO_LSS_address_t lssAddress = {.identity = { - .vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, - .productCode = OD_PERSIST_COMM.x1018_identity.productCode, - .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, - .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber - }}; - err = CO_LSSinit(CO, &lssAddress, - &mlStorage.pendingNodeId, &mlStorage.pendingBitRate); - if(err != CO_ERROR_NO) { - log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_LSSinit()", err); - programExit = EXIT_FAILURE; - CO_endProgram = 1; - continue; - } - - CO_activeNodeId = mlStorage.pendingNodeId; - errInfo = 0; - - err = CO_CANopenInit(CO, /* CANopen object */ - NULL, /* alternate NMT */ - NULL, /* alternate em */ - OD, /* Object dictionary */ - OD_STATUS_BITS, /* Optional OD_statusBits */ - NMT_CONTROL, /* CO_NMT_control_t */ - FIRST_HB_TIME, /* firstHBTime_ms */ - SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */ - SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */ - SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ - CO_activeNodeId, - &errInfo); - if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - if (err == CO_ERROR_OD_PARAMETERS) { - log_printf(LOG_CRIT, DBG_OD_ENTRY, errInfo); - } - else { - log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInit()", err); - } - programExit = EXIT_FAILURE; - CO_endProgram = 1; - continue; - } - - /* initialize part of threadMain and callbacks */ - CO_epoll_initCANopenMain(&epMain, CO); -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - CO_epoll_initCANopenGtw(&epGtw, CO); -#endif - CO_LSSslave_initCfgStoreCallback(CO->LSSslave, &mlStorage, - LSScfgStoreCallback); - if(!CO->nodeIdUnconfigured) { - if(errInfo != 0) { - CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, - CO_EMC_DATA_SET, errInfo); - } -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER - CO_EM_initCallbackRx(CO->em, EmergencyRxCallback); -#endif -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE - CO_NMT_initCallbackChanged(CO->NMT, NmtChangedCallback); -#endif -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE - CO_HBconsumer_initCallbackNmtChanged(CO->HBcons, 0, NULL, - HeartbeatNmtChangedCallback); -#endif -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - if(storageInitError != 0) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, - CO_EMC_HARDWARE, storageInitError); - } -#endif - -#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE - /* Initialize time */ - CO_time_init(&CO_time, CO->SDO[0], &OD_time.epochTimeBaseMs, &OD_time.epochTimeOffsetMs, 0x2130); -#endif - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "communication reset"); - } - else { - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "node-id not initialized"); - } - - /* First time only initialization. */ - if(firstRun) { - firstRun = false; - CO_TIME_set(CO->TIME, time_ms, time_days, TIME_STAMP_INTERVAL_MS); -#ifndef CO_SINGLE_THREAD - /* Create rt_thread and set priority */ - if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "pthread_create(rt_thread)"); - programExit = EXIT_FAILURE; - CO_endProgram = 1; - continue; - } - if(rtPriority > 0) { - struct sched_param param; - - param.sched_priority = rtPriority; - if (pthread_setschedparam(rt_thread_id, SCHED_FIFO, ¶m) != 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "pthread_setschedparam()"); - programExit = EXIT_FAILURE; - CO_endProgram = 1; - continue; - } - } -#endif -#ifdef CO_USE_APPLICATION - /* Execute optional additional application code */ - errInfo = 0; - err = app_programStart(!CO->nodeIdUnconfigured, &errInfo); - if(err != CO_ERROR_NO) { - if (err == CO_ERROR_OD_PARAMETERS) { - log_printf(LOG_CRIT, DBG_OD_ENTRY, errInfo); - } - else { - log_printf(LOG_CRIT, DBG_CAN_OPEN, "app_programStart()", err); - } - programExit = EXIT_FAILURE; - CO_endProgram = 1; - continue; - } - if(errInfo != 0 && !CO->nodeIdUnconfigured) { - CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, - CO_EMC_DATA_SET, errInfo); - } -#endif - } /* if(firstRun) */ - - -#ifdef CO_USE_APPLICATION - /* Execute optional additional application code */ - app_communicationReset(!CO->nodeIdUnconfigured); -#endif - - errInfo = 0; - err = CO_CANopenInitPDO(CO, /* CANopen object */ - CO->em, /* emergency object */ - OD, /* Object dictionary */ - CO_activeNodeId, - &errInfo); - if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - if (err == CO_ERROR_OD_PARAMETERS) { - log_printf(LOG_CRIT, DBG_OD_ENTRY, errInfo); - } - else { - log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInitPDO()", err); - } - programExit = EXIT_FAILURE; - CO_endProgram = 1; - continue; - } - - - /* start CAN */ - CO_CANsetNormalMode(CO->CANmodule); - - reset = CO_RESET_NOT; - - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "running ..."); - - - while(reset == CO_RESET_NOT && CO_endProgram == 0) { -/* loop for normal program execution ******************************************/ - CO_epoll_wait(&epMain); -#ifdef CO_SINGLE_THREAD - CO_epoll_processRT(&epMain, CO, false); -#endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - CO_epoll_processGtw(&epGtw, CO, &epMain); -#endif - CO_epoll_processMain(&epMain, CO, GATEWAY_ENABLE, &reset); - CO_epoll_processLast(&epMain); - -#ifdef CO_USE_APPLICATION - app_programAsync(!CO->nodeIdUnconfigured, epMain.timeDifference_us); -#endif - -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - /* don't save more often than interval */ - if (storageIntervalTimer < CO_STORAGE_AUTO_INTERVAL) { - storageIntervalTimer += epMain.timeDifference_us; - } - else { - uint32_t mask = CO_storageLinux_auto_process(&storage, false); - if(mask != storageErrorPrev && !CO->nodeIdUnconfigured) { - if(mask != 0) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, - CO_EMC_HARDWARE, mask); - } - else { - CO_errorReset(CO->em, CO_EM_NON_VOLATILE_AUTO_SAVE, 0); - } - } - storageErrorPrev = mask; - storageIntervalTimer = 0; - } -#endif - } - } /* while(reset != CO_RESET_APP */ - - -/* program exit ***************************************************************/ - /* join threads */ - CO_endProgram = 1; -#ifndef CO_SINGLE_THREAD - if (pthread_join(rt_thread_id, NULL) != 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "pthread_join()"); - exit(EXIT_FAILURE); - } -#endif -#ifdef CO_USE_APPLICATION - /* Execute optional additional application code */ - app_programEnd(); -#endif - -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - CO_storageLinux_auto_process(&storage, true); -#endif - - /* delete objects from memory */ -#ifndef CO_SINGLE_THREAD - CO_epoll_close(&epRT); -#endif - CO_epoll_close(&epMain); -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - CO_epoll_closeGtw(&epGtw); -#endif - CO_CANsetConfigurationMode((void *)&CANptr); - CO_delete(CO); - - log_printf(LOG_INFO, DBG_CAN_OPEN_INFO, CO_activeNodeId, "finished"); - - /* Flush all buffers (and reboot) */ - if(rebootEnable && reset == CO_RESET_APP) { - sync(); - if(reboot(LINUX_REBOOT_CMD_RESTART) != 0) { - log_printf(LOG_CRIT, DBG_ERRNO, "reboot()"); - exit(EXIT_FAILURE); - } - } - - exit(programExit); -} - -#ifndef CO_SINGLE_THREAD -/******************************************************************************* - * Realtime thread for CAN receive and threadTmr - ******************************************************************************/ -static void* rt_thread(void* arg) { - (void)arg; - /* Endless loop */ - while(CO_endProgram == 0) { - - CO_epoll_wait(&epRT); - CO_epoll_processRT(&epRT, CO, true); - CO_epoll_processLast(&epRT); - -#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE - /* Monitor variables with trace objects */ - CO_time_process(&CO_time); - for(i=0; iCNT_TRACE; i++) { - CO_trace_process(CO->trace[i], *CO_time.epochTimeOffsetMs); - } -#endif - -#ifdef CO_USE_APPLICATION - /* Execute optional additional application code */ - app_programRt(!CO->nodeIdUnconfigured, epRT.timeDifference_us); -#endif - - } - - return NULL; -} -#endif diff --git a/socketCAN/CO_storageLinux.c b/socketCAN/CO_storageLinux.c deleted file mode 100644 index 9f0422b2..00000000 --- a/socketCAN/CO_storageLinux.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * CANopen data storage object for Linux - * - * @file CO_storageLinux.c - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CO_storageLinux.h" -#include "301/crc16-ccitt.h" - -#include -#include -#include - -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - - -/* - * Function for writing data on "Store parameters" command - OD object 1010 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t storeLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { - ODR_t ret = ODR_OK; - uint16_t crc_store; - - /* Create names for temporary and old file */ - size_t fn_len = strlen(entry->filename) + 5; - char *filename_tmp = malloc(fn_len); - char *filename_old = malloc(fn_len); - if (filename_tmp == NULL || filename_old == NULL) { - if (filename_tmp != NULL) free(filename_tmp); - if (filename_old != NULL) free(filename_old); - ret = ODR_OUT_OF_MEM; - } - else { - strcpy(filename_tmp, entry->filename); - strcpy(filename_old, entry->filename); - strcat(filename_tmp, ".tmp"); - strcat(filename_old, ".old"); - } - - /* Open a temporary file and write data to it */ - if (ret == ODR_OK) { - FILE *fp = fopen(filename_tmp, "w"); - if (fp == NULL) { - ret = ODR_HW; - } - else { - CO_LOCK_OD(CANmodule); - size_t cnt = fwrite(entry->addr, 1, entry->len, fp); - crc_store = crc16_ccitt(entry->addr, entry->len, 0); - CO_UNLOCK_OD(CANmodule); - cnt += fwrite(&crc_store, 1, sizeof(crc_store), fp); - fclose(fp); - if (cnt != (entry->len + sizeof(crc_store))) { - ret = ODR_HW; - } - } - } - - /* Verify data */ - if (ret == ODR_OK) { - uint8_t *buf = NULL; - FILE *fp = NULL; - size_t cnt = 0; - uint16_t crc_verify, crc_read; - - buf = malloc(entry->len + 4); - if (buf != NULL) { - fp = fopen(filename_tmp, "r"); - if (fp != NULL) { - cnt = fread(buf, 1, entry->len + 4, fp); - crc_verify = crc16_ccitt(buf, entry->len, 0); - fclose(fp); - memcpy(&crc_read, &buf[entry->len], sizeof(crc_read)); - } - free(buf); - } - /* If size or CRC differs, report error */ - if (buf == NULL || fp == NULL || cnt != (entry->len+sizeof(crc_verify)) - || crc_store != crc_verify || crc_store != crc_read - ) { - ret = ODR_HW; - } - } - - /* rename existing file to *.old and *.tmp to existing */ - if (ret == ODR_OK) { - rename(entry->filename, filename_old); - if (rename(filename_tmp, entry->filename) != 0) { - ret = ODR_HW; - } - } - - free(filename_tmp); - free(filename_old); - - return ret; -} - - -/* - * Function for restoring data on "Restore default parameters" command - OD 1011 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t restoreLinux(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule){ - (void) CANmodule; - ODR_t ret = ODR_OK; - - /* close the file first, if auto storage */ - if ((entry->attr & CO_storage_auto) != 0 && entry->fp != NULL) { - fclose(entry->fp); - entry->fp = NULL; - } - - /* Rename existing filename to *.old. */ - char *filename_old = malloc(strlen(entry->filename) + 5); - if (filename_old == NULL) { - ret = ODR_OUT_OF_MEM; - } - else { - strcpy(filename_old, entry->filename); - strcat(filename_old, ".old"); - rename(entry->filename, filename_old); - free(filename_old); - } - - /* create an empty file and write "-\n" to it. */ - if (ret == ODR_OK) { - FILE *fp = fopen(entry->filename, "w"); - if (fp == NULL) { - ret = ODR_HW; - } - else { - fputs("-\n", fp); - fclose(fp); - } - } - - return ret; -} - - -CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, - CO_CANmodule_t *CANmodule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParam, - CO_storage_entry_t *entries, - uint8_t entriesCount, - uint32_t *storageInitError) -{ - CO_ReturnError_t ret; - - /* verify arguments */ - if (storage == NULL || entries == NULL || entriesCount == 0 - || storageInitError == NULL - ) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - storage->enabled = false; - - /* initialize storage and OD extensions */ - ret = CO_storage_init(storage, - CANmodule, - OD_1010_StoreParameters, - OD_1011_RestoreDefaultParam, - storeLinux, - restoreLinux, - entries, - entriesCount); - if (ret != CO_ERROR_NO) { - return ret; - } - - /* initialize entries */ - *storageInitError = 0; - for (uint8_t i = 0; i < entriesCount; i++) { - CO_storage_entry_t *entry = &entries[i]; - bool_t dataCorrupt = false; - char *writeFileAccess = "w"; - - /* verify arguments */ - if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2 - || strlen(entry->filename) == 0 - ) { - *storageInitError = i; - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Open file, check existence and create temporary buffer */ - uint8_t *buf = NULL; - FILE * fp = fopen(entry->filename, "r"); - if (fp == NULL) { - dataCorrupt = true; - ret = CO_ERROR_DATA_CORRUPT; - } - else { - buf = malloc(entry->len + 4); - if (buf == NULL) { - fclose(fp); - *storageInitError = i; - return CO_ERROR_OUT_OF_MEMORY; - } - } - - /* Read data into temporary buffer first. Then verify and copy to addr*/ - if (!dataCorrupt) { - size_t cnt = fread(buf, 1, entry->len + 4, fp); - - /* If file is empty, just skip loading, default values will be used, - * no error. Otherwise verify length and crc and copy data. */ - if (!(cnt == 2 && buf[0] == '-')) { - uint16_t crc1, crc2; - crc1 = crc16_ccitt(buf, entry->len, 0); - memcpy(&crc2, &buf[entry->len], sizeof(crc2)); - - if (crc1 == crc2 && cnt == (entry->len + sizeof(crc2))) { - memcpy(entry->addr, buf, entry->len); - entry->crc = crc1; - writeFileAccess = "r+"; - } - else { - dataCorrupt = true; - ret = CO_ERROR_DATA_CORRUPT; - } - } - - free(buf); - fclose(fp); - } - - /* additional info in case of error */ - if (dataCorrupt) { - uint32_t errorBit = entry->subIndexOD; - if (errorBit > 31) errorBit = 31; - *storageInitError |= ((uint32_t) 1) << errorBit; - } - - /* open file for auto storage, if set so */ - if ((entry->attr & CO_storage_auto) != 0) { - entry->fp = fopen(entry->filename, writeFileAccess); - if (entry->fp == NULL) { - *storageInitError = i; - return CO_ERROR_ILLEGAL_ARGUMENT; - } - } - } /* for (entries) */ - - storage->enabled = true; - return ret; -} - - -uint32_t CO_storageLinux_auto_process(CO_storage_t *storage, - bool_t closeFiles) -{ - uint32_t storageError = 0; - - /* verify arguments */ - if (storage == NULL) { - return false; - } - - /* loop through entries */ - for (uint8_t i = 0; i < storage->entriesCount; i++) { - CO_storage_entry_t *entry = &storage->entries[i]; - - if ((entry->attr & CO_storage_auto) == 0 || entry->fp == NULL) - continue; - - /* If CRC of the current data differs, save the file */ - uint16_t crc = crc16_ccitt(entry->addr, entry->len, 0); - if (crc != entry->crc) { - size_t cnt; - rewind(entry->fp); - CO_LOCK_OD(storage->CANmodule); - cnt = fwrite(entry->addr, 1, entry->len, entry->fp); - CO_UNLOCK_OD(storage->CANmodule); - cnt += fwrite(&crc, 1, sizeof(crc), entry->fp); - fflush(entry->fp); - if (cnt == (entry->len + sizeof(crc))) { - entry->crc = crc; - } - else { - /* error with save */ - uint32_t errorBit = entry->subIndexOD; - if (errorBit > 31) errorBit = 31; - storageError |= ((uint32_t) 1) << errorBit; - } - } - - if (closeFiles) { - fclose(entry->fp); - entry->fp = NULL; - } - } - - return storageError; -} - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/socketCAN/CO_storageLinux.h b/socketCAN/CO_storageLinux.h deleted file mode 100644 index 54a549db..00000000 --- a/socketCAN/CO_storageLinux.h +++ /dev/null @@ -1,106 +0,0 @@ -/** - * CANopen data storage object for Linux - * - * @file CO_storageLinux.h - * @ingroup CO_storageLinux - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CO_STORAGE_LINUX_H -#define CO_STORAGE_LINUX_H - -#include "storage/CO_storage.h" - -#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_storageLinux Data storage with Linux - * @ingroup CO_socketCAN - * @{ - * - * Data initialize, store and restore functions with Linux, see @ref CO_storage - */ - - -/** - * Initialize data storage object (Linux specific) - * - * This function should be called by application after the program startup, - * before @ref CO_CANopenInit(). This function initializes storage object, - * OD extensions on objects 1010 and 1011, reads data from file, verifies them - * and writes data to addresses specified inside entries. This function - * internally calls @ref CO_storage_init(). - * - * @param storage This object will be initialized. It must be defined by - * application and must exist permanently. - * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. - * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". - * Entry is optional, may be NULL. - * @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default - * parameters". Entry is optional, may be NULL. - * @param entries Pointer to array of storage entries, see @ref CO_storage_init. - * @param entriesCount Count of storage entries - * @param [out] storageInitError If function returns CO_ERROR_DATA_CORRUPT, - * then this variable contains a bit mask from subIndexOD values, where data - * was not properly initialized. If other error, then this variable contains - * index or erroneous entry. - * - * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if data can not be initialized, - * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY. - */ -CO_ReturnError_t CO_storageLinux_init(CO_storage_t *storage, - CO_CANmodule_t *CANmodule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParam, - CO_storage_entry_t *entries, - uint8_t entriesCount, - uint32_t *storageInitError); - - -/** - * Automatically save data if differs from previous call. - * - * Should be called cyclically by program. Each interval it verifies, if crc - * checksum of data differs from previous checksum. If it does, data are saved - * into pre-opened file. - * - * @param storage This object - * @param closeFiles If true, then all files will be closed. Use on end of the - * program. - * - * @return 0 on success or bit mask from subIndexOD values, where data was not - * able to be saved. - */ -uint32_t CO_storageLinux_auto_process(CO_storage_t *storage, - bool_t closeFiles); - -/** @} */ /* CO_storageLinux */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ - -#endif /* CO_STORAGE_LINUX_H */ From f56c96db3c65ef61e051db8c8aa02ea5188cc25c Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 17 May 2021 13:29:13 +0200 Subject: [PATCH 185/520] Documentation arrangement according to doxygen. - Minor changes in most files - add CANopenNode.png - update doxyfile - move doc/LSSusage.md and doc/gettingStarted.md into CANopenDemo repository - update README.md --- 301/CO_Emergency.h | 5 +- 301/CO_HBconsumer.h | 5 +- 301/CO_NMT_Heartbeat.h | 5 +- 301/CO_ODinterface.h | 2 + 301/CO_PDO.h | 5 +- 301/CO_SDOclient.h | 5 +- 301/CO_SDOserver.h | 4 +- 301/CO_SYNC.h | 5 +- 301/CO_TIME.h | 5 +- 301/CO_config.h | 16 +++- 301/CO_driver.h | 8 +- 301/CO_fifo.h | 2 + 301/crc16-ccitt.h | 4 +- 303/CO_LEDs.h | 2 + 304/CO_GFC.h | 5 +- 304/CO_SRDO.h | 5 +- 305/CO_LSS.h | 5 +- 305/CO_LSSmaster.h | 8 +- 305/CO_LSSslave.h | 5 +- 309/CO_gateway_ascii.h | 7 +- CANopen.h | 3 +- Doxyfile | 107 +++++++++++++++------ README.md | 174 +++++++++++++-------------------- codingStyle | 9 +- doc/CANopenNode.png | Bin 0 -> 12693 bytes doc/CHANGELOG.md | 69 +++++++------ doc/LSSusage.md | 121 ----------------------- doc/deviceSupport.md | 9 +- doc/gettingStarted.md | 192 ------------------------------------- doc/traceUsage.md | 2 + example/DS301_profile.md | 18 ++-- extra/CO_trace.h | 5 +- storage/CO_storage.c | 2 +- storage/CO_storage.h | 4 +- storage/CO_storageEeprom.h | 2 + 35 files changed, 265 insertions(+), 560 deletions(-) create mode 100644 doc/CANopenNode.png delete mode 100644 doc/LSSusage.md delete mode 100644 doc/gettingStarted.md diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index e4d71b5f..3015402b 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -60,11 +60,10 @@ extern "C" { /** * @defgroup CO_Emergency Emergency - * @ingroup CO_CANopen_301 - * @{ - * * CANopen Emergency protocol. * + * @ingroup CO_CANopen_301 + * @{ * Error control and Emergency is used for control internal error state * and for sending a CANopen Emergency message. * diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 73a5b096..4409760e 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -50,11 +50,10 @@ extern "C" { /** * @defgroup CO_HBconsumer Heartbeat consumer - * @ingroup CO_CANopen_301 - * @{ - * * CANopen Heartbeat consumer protocol. * + * @ingroup CO_CANopen_301 + * @{ * Heartbeat consumer monitors Heartbeat messages from remote nodes. If any * monitored node don't send his Heartbeat in specified time, Heartbeat consumer * sends emergency message. If all monitored nodes are operational, then diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 03627542..42548061 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -42,11 +42,10 @@ extern "C" { /** * @defgroup CO_NMT_Heartbeat NMT and Heartbeat - * @ingroup CO_CANopen_301 - * @{ - * * CANopen Network management and Heartbeat producer protocol. * + * @ingroup CO_CANopen_301 + * @{ * CANopen device can be in one of the @ref CO_NMT_internalState_t * - Initializing. It is active before CANopen is initialized. * - Pre-operational. All CANopen objects are active, except PDOs. diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 00c2e22e..32c80e6f 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -34,6 +34,8 @@ extern "C" { /** * @defgroup CO_ODinterface OD interface + * CANopen Object Dictionary interface. + * * @ingroup CO_CANopen_301 * @{ * See @ref doc/objectDictionary.md diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 5863db9f..6a6bd872 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -51,11 +51,10 @@ extern "C" { /** * @defgroup CO_PDO PDO - * @ingroup CO_CANopen_301 - * @{ - * * CANopen Process Data Object protocol. * + * @ingroup CO_CANopen_301 + * @{ * Process data objects are used for real-time data transfer with no protocol * overhead. * diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index f84c0440..7c9b32d7 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -52,11 +52,10 @@ extern "C" { /** * @defgroup CO_SDOclient SDO client + * CANopen Service Data Object - client protocol. + * * @ingroup CO_CANopen_301 * @{ - * - * CANopen Service Data Object - client protocol (master functionality). - * * @see @ref CO_SDOserver */ diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 3daa6e8a..594cd5c0 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -46,11 +46,11 @@ extern "C" { /** * @defgroup CO_SDOserver SDO server + * CANopen Service Data Object - server protocol. + * * @ingroup CO_CANopen_301 * @{ * - * CANopen Service Data Object - server protocol. - * * Service data objects (SDOs) allow the access to any entry of the CANopen * Object dictionary. By SDO a peer-to-peer communication channel between two * CANopen devices is established. In addition, the SDO protocol enables to diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 8843bd9a..9bc3384d 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -48,11 +48,10 @@ extern "C" { /** * @defgroup CO_SYNC SYNC - * @ingroup CO_CANopen_301 - * @{ - * * CANopen Synchronisation protocol. * + * @ingroup CO_CANopen_301 + * @{ * For CAN identifier see #CO_Default_CAN_ID_t * * SYNC message is used for synchronization of the nodes on network. One node diff --git a/301/CO_TIME.h b/301/CO_TIME.h index ababf37b..2f12d193 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -46,11 +46,10 @@ extern "C" { /** * @defgroup CO_TIME TIME - * @ingroup CO_CANopen_301 - * @{ - * * CANopen Time-stamp protocol. * + * @ingroup CO_CANopen_301 + * @{ * For CAN identifier see @ref CO_Default_CAN_ID_t * * TIME message is used for time synchronization of the nodes on the network. diff --git a/301/CO_config.h b/301/CO_config.h index 0b905f29..8bef9a07 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -33,9 +33,9 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG Stack configuration - * @ingroup CO_driver + * Stack configuration and enabling macros. * - * Stack configuration macros specify, which parts of the stack will be enabled. + * @ingroup CO_driver * * Default values for stack configuration macros are set in corresponding * header files. The same default values are also provided in this file, but @@ -57,6 +57,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_COMMON Common definitions + * Constants for common definitions. * @{ */ /** @@ -125,6 +126,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_NMT_HB NMT master/slave and HB producer/consumer + * Specified in standard CiA 301 * @{ */ /** @@ -198,6 +200,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_EMERGENCY Emergency producer/consumer + * Specified in standard CiA 301 * @{ */ /** @@ -335,6 +338,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_SDO SDO server/client + * Specified in standard CiA 301 * @{ */ /** @@ -417,6 +421,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_TIME Time producer/consumer + * Specified in standard CiA 301 * @{ */ /** @@ -441,6 +446,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_SYNC_PDO SYNC and PDO producer/consumer + * Specified in standard CiA 301 * @{ */ /** @@ -499,7 +505,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_STORAGE Data storage - * Data storage with CANopen OD objects 1010 and 1011 + * Data storage with CANopen OD objects 1010 and 1011, CiA 301 * @{ */ /** @@ -691,7 +697,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_CRC16 CRC 16 calculation - * Helper object + * Helper object for CRC-16 checksum * @{ */ /** @@ -711,7 +717,7 @@ extern "C" { /** * @defgroup CO_STACK_CONFIG_FIFO FIFO buffer - * Helper object + * Helper object for FIFO buffer * @{ */ /** diff --git a/301/CO_driver.h b/301/CO_driver.h index f881b1b0..3d2bb05d 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -60,11 +60,10 @@ extern "C" { /** * @defgroup CO_driver Driver - * @ingroup CO_CANopen_301 - * @{ - * * Interface between CAN hardware and CANopenNode. * + * @ingroup CO_CANopen_301 + * @{ * CANopenNode is designed for speed and portability. It runs efficiently on * devices from simple 16-bit microcontrollers to PC computers. It can run in * multiple threads. Reception of CAN messages is pre-processed with very fast @@ -393,6 +392,9 @@ typedef struct { /** * @defgroup CO_critical_sections Critical sections * @{ + * + * Protection of critical sections in multi-threaded operation. + * * CANopenNode is designed to run in different threads, as described in * [README.md](index.html). Threads are implemented differently in different * systems. In microcontrollers threads are interrupts with different diff --git a/301/CO_fifo.h b/301/CO_fifo.h index c2413655..b6f657e7 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -41,6 +41,8 @@ extern "C" { /** * @defgroup CO_CANopen_301_fifo FIFO circular buffer + * FIFO circular buffer for continuous data flow. + * * @ingroup CO_CANopen_301 * @{ * diff --git a/301/crc16-ccitt.h b/301/crc16-ccitt.h index 186e5340..8fe3070f 100644 --- a/301/crc16-ccitt.h +++ b/301/crc16-ccitt.h @@ -42,11 +42,11 @@ extern "C" { /** * @defgroup CO_crc16_ccitt CRC 16 CCITT + * Calculation of CRC 16 CCITT polynomial. + * * @ingroup CO_CANopen_301 * @{ * - * Calculation of CRC 16 CCITT polynomial. - * * Equation: * * `x^16 + x^12 + x^5 + 1` diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index d8937f91..21f02deb 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -43,6 +43,8 @@ extern "C" { /** * @defgroup CO_LEDs LED indicators + * Specified in standard CiA 303-3. + * * @ingroup CO_CANopen_303 * @{ * diff --git a/304/CO_GFC.h b/304/CO_GFC.h index 07a0b229..575b6bd5 100644 --- a/304/CO_GFC.h +++ b/304/CO_GFC.h @@ -41,11 +41,10 @@ extern "C" { /** * @defgroup CO_GFC GFC - * @ingroup CO_CANopen_304 - * @{ - * * Global fail-safe command protocol. * + * @ingroup CO_CANopen_304 + * @{ * Very simple consumer/producer protocol. * A net can have multiple GFC producer and multiple GFC consumer. * On a safety-relevant the producer can send a GFC message (ID 0, DLC 0). diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 10ef427b..37783db6 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -47,11 +47,10 @@ extern "C" { /** * @defgroup CO_SRDO SRDO - * @ingroup CO_CANopen_304 - * @{ - * * CANopen Safety Related Data Object protocol. * + * @ingroup CO_CANopen_304 + * @{ * The functionality is very similar to that of the PDOs. * The main differences is every message is send and received twice. * The second message must be bitwise inverted. The delay between the two messages and between each message pair is monitored. diff --git a/305/CO_LSS.h b/305/CO_LSS.h index dae96257..8207a871 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -43,11 +43,10 @@ extern "C" { /** * @defgroup CO_LSS LSS - * @ingroup CO_CANopen_305 - * @{ - * * CANopen Layer Setting Services protocol (common). * + * @ingroup CO_CANopen_305 + * @{ * LSS protocol is according to CiA DSP 305 V3.0.0. * * LSS services and protocols are used to inquire or to change the settings diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 68028095..09578800 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -37,11 +37,10 @@ extern "C" { /** * @defgroup CO_LSSmaster LSS Master - * @ingroup CO_CANopen_305 - * @{ - * * CANopen Layer Setting Service - master protocol. * + * @ingroup CO_CANopen_305 + * @{ * The client/master can use the following services * - node selection via LSS address * - node selection via LSS fastscan @@ -59,8 +58,7 @@ extern "C" { * * ###Usage * - * Usage of the CANopen LSS master is demonstrated in CANopenSocket application, - * see CO_LSS_master.c / CO_LSS_master.h files. + * Usage of the CANopen LSS master is demonstrated in file 309/CO_gateway_ascii.c * * It essentially is always as following: * - select node(s) diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index 5593e7d4..cb3da5d0 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -38,11 +38,10 @@ extern "C" { /** * @defgroup CO_LSSslave LSS Slave - * @ingroup CO_CANopen_305 - * @{ - * * CANopen Layer Setting Service - slave protocol. * + * @ingroup CO_CANopen_305 + * @{ * The slave provides the following services * - node selection via LSS address * - node selection via LSS fastscan diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index b79fe42c..832107b2 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -47,11 +47,10 @@ extern "C" { /** * @defgroup CO_CANopen_309_3 Gateway ASCII mapping - * @ingroup CO_CANopen_309 - * @{ - * * CANopen access from other networks - ASCII mapping (CiA 309-3 DSP v3.0.0) * + * @ingroup CO_CANopen_309 + * @{ * This module enables ascii command interface (CAN gateway), which can be used * for master interaction with CANopen network. Some sort of string input/output * stream can be used, for example serial port + terminal on microcontroller or @@ -70,6 +69,8 @@ extern "C" { /** * @defgroup CO_CANopen_309_3_Syntax Command syntax + * ASCII command syntax. + * * @{ * * @code{.unparsed} diff --git a/CANopen.h b/CANopen.h index 44f6be8e..0fe3434d 100644 --- a/CANopen.h +++ b/CANopen.h @@ -55,8 +55,7 @@ extern "C" { * @defgroup CO_CANopen CANopen * @{ * - * CANopenNode is free and open source implementation of CANopen communication - * protocol. + * CANopenNode is free and open source CANopen communication protocol stack. * * CANopen is the internationally standardized (EN 50325-4) (CiA DS-301) * CAN-based higher-layer protocol for embedded control system. For more diff --git a/Doxyfile b/Doxyfile index 7bfa59ce..acaab7ed 100644 --- a/Doxyfile +++ b/Doxyfile @@ -44,14 +44,14 @@ PROJECT_NUMBER = # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = "CANopen protocol stack" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = doc/CANopenNode.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -126,7 +126,17 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief @@ -326,7 +336,7 @@ MARKDOWN_SUPPORT = YES # Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. -TOC_INCLUDE_HEADINGS = 0 +TOC_INCLUDE_HEADINGS = 5 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can @@ -376,7 +386,7 @@ IDL_PROPERTY_SUPPORT = YES # all members of a group must be documented explicitly. # The default value is: NO. -DISTRIBUTE_GROUP_DOC = YES +DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option @@ -823,8 +833,7 @@ INPUT = README.md \ 305 \ 309 \ storage \ - extra \ - socketCAN + extra # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -851,7 +860,53 @@ INPUT_ENCODING = UTF-8 # C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. -FILE_PATTERNS = +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.doc \ + *.txt \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -906,7 +961,7 @@ EXAMPLE_PATH = # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands @@ -975,7 +1030,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = README.md +USE_MDFILE_AS_MAINPAGE = ./README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -1244,7 +1299,7 @@ HTML_COLORSTYLE_GAMMA = 80 # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_TIMESTAMP = YES +HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that @@ -1263,7 +1318,7 @@ HTML_DYNAMIC_MENUS = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand @@ -1276,7 +1331,7 @@ HTML_DYNAMIC_SECTIONS = NO # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_INDEX_NUM_ENTRIES = 100 +HTML_INDEX_NUM_ENTRIES = 35 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development @@ -1475,7 +1530,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -DISABLE_INDEX = YES +DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag @@ -1492,7 +1547,7 @@ DISABLE_INDEX = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = YES +GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. @@ -1587,7 +1642,7 @@ MATHJAX_FORMAT = HTML-CSS # The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1717,7 +1772,7 @@ LATEX_OUTPUT = latex # the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_CMD_NAME = latex +LATEX_CMD_NAME = # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. @@ -2159,13 +2214,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = CO_DOXYGEN=1 \ - CO_NO_SYNC=1 \ - CO_NO_SDO_CLIENT=1 \ - CO_NO_NMT_MASTER=1 \ - CO_NO_LSS_SERVER=1 \ - CO_NO_LSS_CLIENT=1 \ - CO_NO_TRACE=1 +PREDEFINED = CO_DOXYGEN=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2209,7 +2258,7 @@ TAGFILES = # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = doc/html/CANopenNode.tag # If the ALLEXTERNALS tag is set to YES, all external class will be listed in # the class index. If set to NO, only the inherited external classes will be @@ -2243,7 +2292,7 @@ EXTERNAL_PAGES = YES # powerful graphs. # The default value is: YES. -CLASS_DIAGRAMS = NO +CLASS_DIAGRAMS = YES # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The @@ -2265,7 +2314,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: YES. -HAVE_DOT = NO +HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of @@ -2427,7 +2476,7 @@ DIRECTORY_GRAPH = YES # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_IMAGE_FORMAT = png +DOT_IMAGE_FORMAT = svg # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. @@ -2439,7 +2488,7 @@ DOT_IMAGE_FORMAT = png # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -INTERACTIVE_SVG = NO +INTERACTIVE_SVG = YES # The DOT_PATH tag can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. diff --git a/README.md b/README.md index 4db53547..0df8fb1a 100644 --- a/README.md +++ b/README.md @@ -3,77 +3,62 @@ CANopenNode CANopenNode is free and open source CANopen protocol stack. -CANopen is the internationally standardized (EN 50325-4) -([CiA301](http://can-cia.org/standardization/technical-documents)) -higher-layer protocol for embedded control system built on top of CAN. -For more information on CANopen see http://www.can-cia.org/ +CANopen is the internationally standardized (EN 50325-4) ([CiA301](http://can-cia.org/standardization/technical-documents)) higher-layer protocol for embedded control system built on top of CAN. For more information on CANopen see http://www.can-cia.org/ -CANopenNode is written in ANSI C in object-oriented way. It runs on -different microcontrollers, as standalone application or with RTOS. -Linux implementation with CANopen master functionalities is included. +CANopenNode is written in ANSI C in object-oriented way. It runs on different microcontrollers, as standalone application or with RTOS. -Variables (communication, device, custom) are ordered in CANopen Object -Dictionary and are accessible from both: C code and from CANopen network. +Variables (communication, device, custom) are collected in CANopen Object Dictionary and are accessible from both: C code and from CANopen network. CANopenNode homepage is https://github.com/CANopenNode/CANopenNode -This is version 4 of CANopenNode with new Object Dictionary implementation. -For older versions `git checkout` branches `v1.3-master` or `v2.0-master`. +This is version 4 of CANopenNode with new Object Dictionary implementation. For older versions `git checkout` branches `v1.3-master` or `v2.0-master`. Characteristics --------------- ### CANopen - - [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen/device-architecture/) - offers clear and flexible organisation of any variables. Variables can be accessed - directly or via read/write functions. - - [NMT](https://www.can-cia.org/can-knowledge/canopen/network-management/) - slave to start, stop, reset device. Simple NMT master. - - [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/) - producer/consumer error control for monitoring of CANopen devices. - - [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) for - broadcasting process data with high priority and no protocol overhead. - Variables from Object Dictionary can be dynamically mapped to the TPDO, which - is then transmitted according to communication rules and received as RPDO - by another device. - - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) server - enables expedited, segmented and block transfer access to all Object - Dictionary variables inside CANopen device. - - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client can - access any Object Dictionary variable on any CANopen device inside the network. - - [Emergency](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) - message producer/consumer. - - [Sync](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) - producer/consumer enables network synchronized transmission of the PDO objects, etc. - - [Time-stamp](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) - producer/consumer enables date and time synchronization in millisecond resolution. - - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) CANopen node-id - and bitrate setup, master and slave, LSS fastscan. - - [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/), - CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. - - CANopen Safety, - EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks + - [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen/device-architecture/) offers clear and flexible organisation of any variables. Variables can be accessed directly or via read/write functions. + - [NMT](https://www.can-cia.org/can-knowledge/canopen/network-management/) slave to start, stop, reset device. Simple NMT master. + - [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/) producer/consumer error control for monitoring of CANopen devices. + - [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) for broadcasting process data with high priority and no protocol overhead. Variables from Object Dictionary can be dynamically mapped to the TPDO, which is then transmitted according to communication rules and received as RPDO by another device. + - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) server enables expedited, segmented and block transfer access to all Object Dictionary variables inside CANopen device. + - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client can access any Object Dictionary variable on any CANopen device inside the network. + - [Emergency](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) message producer/consumer. + - [Sync](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) producer/consumer enables network synchronized transmission of the PDO objects, etc. + - [Time-stamp](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) producer/consumer enables date and time synchronization in millisecond resolution. + - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) CANopen node-id and bitrate setup, master and slave, LSS fastscan. + - [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. + - CANopen Safety, EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks ### Other - [Suitable for 16-bit microcontrollers and above](#device-support) - [Multithreaded, real-time](#flowchart-of-a-typical-canopennode-implementation) - [Object Dictionary editor](#object-dictionary-editor) - - Non-volatile storage for Object Dictionary or other variables. Automatic or - controlled by standard CANopen commands, configurable. + - Non-volatile storage for Object Dictionary or other variables. Automatic or controlled by standard CANopen commands, configurable. - [Power saving possible](#power-saving) - [Bootloader possible](https://github.com/CANopenNode/CANopenNode/issues/111) (for firmware update) +Related projects +---------------- + - [CANopenNode](https://github.com/CANopenNode/CANopenNode) (this project): CANopen protocol stack, base for CANopen device. It contains no device specific code (drivers), which must be added separately for each target system. An example shows the basic principles, compiles on any system, but does not connect to any CAN hardware. + - [CANopenDemo](https://github.com/CANopenNode/CANopenDemo): Demo device with CANopenNode and different target systems, tutorial and testing tools. + - [CANopenNode.github.io](https://github.com/CANopenNode/CANopenNode.github.io): Html documentation, compiled by doxygen, for CANopenDemo, CANopenNode and other devices, available also online: https://canopennode.github.io + - [libedssharp](https://github.com/robincornelius/libedssharp): Object Dictionary editor, external GUI tool for editing CANopen Object Dictionary for custom device. It generates C source code, electronic data sheet and documentation for the device. + - [CANopenLinux](https://github.com/CANopenNode/CANopenLinux): CANopenNode on Linux devices. It can be a basic CANopen device or more advanced with commander functionalities. + - [CANopenPIC](https://github.com/CANopenNode/CANopenPIC): CANopenNode on PIC microcontrollers from Microchip. Works with 16-bit and 32 bit devices. Includes example for Arduino style [Max32](https://reference.digilentinc.com/reference/microprocessor/max32/start) board. + - [doc/deviceSupport.md](doc/deviceSupport.md): List of other implementations of CANopenNode on different devices. + + Documentation, support and contributions ---------------------------------------- -Documentation with [Getting started](doc/gettingStarted.md), -[Objec Dictionary](doc/objectDictionary.md) and [LSS usage](doc/LSSusage.md) -is in `doc` directory. -Code is documented in header files. Running [doxygen](http://www.doxygen.nl/) -in project base directory will produce complete html documentation. -Just open CANopenNode/doc/html/index.html in the browser. Alternatively browse -documentation [online](https://canopennode.github.io/CANopenSocket/). -Further documented examples are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket) project. +All code is documented in the source header files. Some additional documents are in `doc` directory. + +To generate complete html documentation, run [doxygen](http://www.doxygen.nl/) in the project base directory: `sudo apt install doxygen graphviz pdf2svg; doxygen > /dev/null` + +Complete generated documentation is also available online: https://canopennode.github.io + +Tutorial, demo device and tests are available in [CANopenDemo](https://github.com/CANopenNode/CANopenDemo) repository. Report issues on https://github.com/CANopenNode/CANopenNode/issues @@ -81,15 +66,13 @@ For discussion on [Slack](https://canopennode.slack.com/) see: https://github.co Older discussion group is on Sourceforge: http://sourceforge.net/p/canopennode/discussion/387151/ -Contributions are welcome. Best way to contribute your code is to fork -a project, modify it and then send a pull request. Some basic formatting -rules should be followed: Linux style with indentation of 4 spaces. There is -also a `codingStyle` file with example and a configuration file for -`clang-format` tool. +Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Some basic formatting +rules should be followed: Linux style with indentation of 4 spaces. There is also a `codingStyle` file with example and a configuration file for `clang-format` tool. -Flowchart of a typical CANopenNode implementation -------------------------------------------------- +CANopenNode configuration +------------------------- +Flowchart of a typical CANopenNode implementation: ~~~ ----------------------- | Program start | @@ -125,6 +108,16 @@ Flowchart of a typical CANopenNode implementation ---------------------- ------------------------ ----------------------- ~~~ +All code of the CANopenNode is non-blocking. Code in source files is collected into objects. Parts of the code can be enabled/disabled, so only files and parts of code can be used, which are required for the project. See stack configuration in 301/CO_config.h file. + +For most efficiency code can run in different thread as seen in above flowchart. This is suitable for microcontrollers. It is also possible to run everything from single thread, as available on Linux devices. Code includes mechanisms, which triggers processing of OD objects when necessary. + +In CANopen initialization section all CANopen objects are initialized. In run time CANopen objects are processed cyclically. + +Files CANopen.h and CANopen.c is a joint of all CANopen objects. It may seems complex, but offers some flexibility and is suitable for most common configurations of the CANopen objects. CANopen objects can be defined in global space or can be dynamically allocated. Object dictionary can be used default (OD.h/.c files), but configuration with multiple object dictionaries is also possible by using the #CO_config_t structure. CANopen.h and CANopen.c files can also be only a reference for more customized implementation of CANopenNode based device. + +Object Dictionary is a collection of all network accessible variables and offers most flexible usage. OD variables can be initialized by object dictionary or application can specify own read/write access functions for specific OD variables. Groups of OD variables are also able to be stored to non-volatile memory, either on command or automatically. + File structure -------------- @@ -154,7 +147,7 @@ File structure - **309/** - CANopen access from other networks. - **CO_gateway_ascii.h/.c** - Ascii mapping: NMT master, LSS master, SDO client. - **storage/** - - **CO_OD_storage.h/.c** - CANopen data storage base object. + - **CO_storage.h/.c** - CANopen data storage base object. - **CO_storageEeprom.h/.c** - CANopen data storage object for storing data into block device (eeprom). - **CO_eeprom.h** - Eeprom interface for use with CO_storageEeprom, functions are target system specific. - **extra/** @@ -163,25 +156,20 @@ File structure - **CO_driver_target.h** - Example hardware definitions for CANopenNode. - **CO_driver_blank.c** - Example blank interface for CANopenNode. - **main_blank.c** - Mainline and other threads - example template. + - **CO_storageBlank.h/.c** - Example blank demonstration for data storage to non-volatile memory. - **Makefile** - Makefile for example. - - **DS301_profile.xpd** - CANopen device description file for DS301. It - includes also CANopenNode specific properties. This file is also available - in Profiles in Object dictionary editor. - - **DS301_profile.eds**, **DS301_profile.md** - Standard CANopen EDS file and - markdown documentation file, automatically generated from DS301_profile.xpd. - - **OD.h/.c** - CANopen Object dictionary source files, automatically - generated from DS301_profile.xpd. + - **DS301_profile.xpd** - CANopen device description file for DS301. It includes also CANopenNode specific properties. This file is also available in Profiles in Object dictionary editor. + - **DS301_profile.eds**, **DS301_profile.md** - Standard CANopen EDS file and markdown documentation file, automatically generated from DS301_profile.xpd. + - **OD.h/.c** - CANopen Object dictionary source files, automatically generated from DS301_profile.xpd. - **doc/** - Directory with documentation - **CHANGELOG.md** - Change Log file. - **deviceSupport.md** - Information about supported devices. - - **gettingStarted.md, LSSusage.md, traceUsage.md** - Getting started and usage. - **objectDictionary.md** - Description of CANopen object dictionary interface. + - **CANopenNode.png** - Little icon. - **html** - Directory with documentation - must be generated by Doxygen. - - **CANopen.h/.c** - Initialization and processing of CANopen objects. + - **CANopen.h/.c** - Initialization and processing of CANopen objects, suitable for common configurations. - **codingStyle** - Example of the coding style. - - **.clang-format** - Definition file for the coding style. - **Doxyfile** - Configuration file for the documentation generator *doxygen*. - - **canopend** - Executable for Linux, build with `make`. - **LICENSE** - License. - **README.md** - This file. @@ -190,62 +178,36 @@ Object dictionary editor ------------------------ Object Dictionary is one of the most essential parts of CANopen. -To customize the Object Dictionary it is necessary to use external application: -[libedssharp](https://github.com/robincornelius/libedssharp). Latest pre-compiled -[binaries](https://github.com/robincornelius/libedssharp/raw/gh-pages/build/OpenEDSEditor-latest.zip) -are also available. Just extract the zip file and run the `EDSEditor.exe`. -In Linux it runs with mono, which is available by default on Ubuntu. Just set -file permissions to "executable" and then execute the program. +To customize the Object Dictionary it is necessary to use external application: [libedssharp](https://github.com/robincornelius/libedssharp). Latest pre-compiled [binaries](https://github.com/robincornelius/libedssharp/raw/gh-pages/build/OpenEDSEditor-latest.zip) are also available. Just extract the zip file and run the `EDSEditor.exe`. In Linux it runs with mono, which is available by default on Ubuntu. Just set file permissions to "executable" and then execute the program. -In program, in preferences, set exporter to "CANopenNode_V4". Then start new -project or open the existing project file. +In program, in preferences, set exporter to "CANopenNode_V4". Then start new project or open the existing project file. -Many project file types are supported, EDS, XDD v1.0, XDD v1.1, old custom XML -format. Generated project file can then be saved in XDD v1.1 file format -(xmlns="http://www.canopen.org/xml/1.1"). Project file can also be exported to -other formats, it can be used to generate documentation and CANopenNode source -files for Object Dictionary. +Many project file types are supported, EDS, XDD v1.0, XDD v1.1, old custom XML format. Generated project file can then be saved in XDD v1.1 file format (xmlns="http://www.canopen.org/xml/1.1"). Project file can also be exported to other formats, it can be used to generate documentation and CANopenNode source files for Object Dictionary. -If new project was started, then `DS301_profile.xpd` may be inserted. -If existing (old) project is edited, then existing `Communication Specific Parameters` -may be deleted and then new `DS301_profile.xpd` may be inserted. Alternative is -editing existing communication parameters with observation to Object Dictionary -Requirements By CANopenNode in [objectDictionary.md](doc/objectDictionary.md). +If new project was started, then `DS301_profile.xpd` may be inserted. If existing (old) project is edited, then existing `Communication Specific Parameters` may be deleted and then new `DS301_profile.xpd` may be inserted. Alternative is editing existing communication parameters with observation to Object Dictionary Requirements By CANopenNode in [objectDictionary.md](doc/objectDictionary.md). -To clone, add or delete, select object(s) and use right click. Some knowledge -of CANopen is required to correctly set-up the custom Object Dictionary. Separate -objects can also be inserted from another project. +To clone, add or delete, select object(s) and use right click. Some knowledge of CANopen is required to correctly set-up the custom Object Dictionary. Separate objects can also be inserted from another project. -CANopenNode includes some custom properties inside standard project file. See -[objectDictionary.md](doc/objectDictionary.md) for more information. +CANopenNode includes some custom properties inside standard project file. See [objectDictionary.md](doc/objectDictionary.md) for more information. Device support -------------- -CANopenNode can run on many different devices. Each device (or microcontroller) -must have own interface to CANopenNode. CANopenNode can run with or without -operating system. +CANopenNode can run on many different devices. Each device (or microcontroller) must have own interface to CANopenNode. CANopenNode can run with or without operating system. -It is not practical to have all device interfaces in a single project. -Interfaces to other microcontrollers are in separate projects. See -[deviceSupport.md](doc/deviceSupport.md) for list of known device interfaces. +It is not practical to have all device interfaces in a single project. Interfaces to other microcontrollers are in separate projects. See [deviceSupport.md](doc/deviceSupport.md) for list of known device interfaces. Some details ------------ ### RTR -RTR (remote transmission request) is a feature of CAN bus. Usage of RTR -is not recommended for CANopen and it is not implemented in CANopenNode. +RTR (remote transmission request) is a feature of CAN bus. Usage of RTR is not recommended for CANopen and it is not implemented in CANopenNode. ### Error control -When node is started (in NMT operational state), it is allowed to send or -receive Process Data Objects (PDO). If Error Register (object 0x1001) is set, -then NMT operational state may not be allowed. +When node is started (in NMT operational state), it is allowed to send or receive Process Data Objects (PDO). If Error Register (object 0x1001) is set, then NMT operational state may not be allowed. ### Power saving -All CANopen objects calculates next timer info for OS. Calculation is based on -various timers which expire in known time. Can be used to put microcontroller -into sleep and wake at the calculated time. +All CANopen objects calculates next timer info for OS. Calculation is based on various timers which expire in known time. Can be used to put microcontroller into sleep and wake at the calculated time. Change Log diff --git a/codingStyle b/codingStyle index 6452ba89..a2dde73a 100644 --- a/codingStyle +++ b/codingStyle @@ -51,9 +51,6 @@ extern "C" { * * Doxygen specifics: If description of the structure member is one sentence * only, don't use period after the sentence. - * - * ###Misra C - * Code shall follow MISRA-C:2012 standard. */ @@ -75,15 +72,15 @@ typedef struct { * This is global function. Local functions (and variables) used inside one file * are declared as static and not documented by Doxygen. * - * @param obj Pointer to object. Function operates on this object (not on global - * variables). + * @param thisObj Pointer to object. Function operates on this object (not on + * global variables). * @param argument_2 Description of the argument. * @param argument_2 Description of the argument. * @param argument_4 Description of the argument. * * @return Some value. */ -int32_t foo1(object1_t *obj, +int32_t foo1(object1_t *thisObj, int32_t argument_2, uint16_t argument_3, float32_t argument_4) diff --git a/doc/CANopenNode.png b/doc/CANopenNode.png new file mode 100644 index 0000000000000000000000000000000000000000..4d8855596963d24a9b25d657681418b846f82f33 GIT binary patch literal 12693 zcmV;GF>20 zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3>tmLxfHg#Y6dJOZ>h4&-~h0gunmfUIgUJ*&v> zoyzLWi~!)m+{}Skv;XJ6kNGeD)KaR6snpzZw)}}LHsATB+V`j5pU%en^Zp6`^O^hg zee?Z+=dGY`zJJ#Id4Kc1|8es=KlkappMJVgi=Pk1uOGC}1-^a;_`Lr$P;j3C*5^h& zeoy&+;6DEzpPA-X%g;-gpP8P|_wG#j&*(=C(Z!ulu{q__@Rs(Q zd%u5kfAjut-c9|zZ+PQZujKF7KfdqMpS@_VuYMXi{}}m~_xE?e{pv0Kch0Kjoc&hU zW5yTxv#777+~4@(kY(;=nZFo^n5(?%Z{u$@q`}0k%T7D^J6&@ge;yaza@`%b@9T7v zDMr6NzVzNt9IW>$zHNR6EB8nJb;p;`!U`3aPog96uK%8kyW_Sy+;o+Jm*bn>aWlsi z-ss2w$KSub(K$*s=WPA974!14IMa~l^pkJl5O==fC|v`8{r&xq{2K6Jx@N8{u-ox& zF_Qblmf|Q}M+d%`czyZg%KF>@6ESvTGA`f&n_WmQJ6pUj&SA%je>yj+K14roflJ9R zX6a)H8Rt~5vAL$W`(2;>dmHe>5h>(Qa7_yxUquj-_$jdxLp_BQQ%X6NR8vbmhaAbK zoJ$sp_7X}gspJB*mR5QVHP%#fEw!53YHz*;P&T#PN~^84-WjxW=g!rgFZ4eA2qTU( z@+hN@Hu@xdW}Io}S!Ok}&A$8!3xHX9l~q?;eY;I4?YPsPLPH>XsGd$*_!{bFBAfUZ`W~+-DbaSVp{v+r0> zu5BEk%KE-A_&5XOgO1$rxY5oT$FH+pEC-{3d3+K!=02zFWd3;V=St$__iH~_TFbS+ zTx$NkasPf;^KXrd$y?brN8B;%9VE?bkZ$}lqMM}+jM&<4gQ74Y83b5z0%w9fIez~~ zujZe9A+Frp&T9j2ySUK_*m*jW0+RBG47mHq*}zXi=mn2QRuGme(~s@a8HE_pz8PnuN3+Q+9i07;|w70|!Ezs>RR6H>g6yw@0` zxHk3S9NC=>&imb6FCs*1WI}i!W^?L_Cv+d$ax=6;(yn@As51Iy4Tl*M2G}X<{r>a& ztS9s|OJ`+i1d@J}>2{~$hbJIq?tS1nC60l+nt0|(1QHX9ZOsw4EciFKk6K+{hIcyQ zs9EV{wN(0;2NFsigGrDG(1G=mnl+rc2Vt=H1cJOD9k3hA9&7^n^skH4^PcWc4fDhPV8q@VS&lq_&JK(QJA+-aB zaADNQ(3NF3yI2|lgXh*_pn+kCfiuTYK#i5A#Xn>EH*!1q<`?%4ga|**22z9LI|gq8 zd2x}ot>nO0F-XSQJ=b9cGOxX=_mm?WRiY10C+WHq(fz1&KWx0zc#eNDzY>*(E?|O#+R&bXFz|gbS4O z;W77)xece}+_npkPU#GLs>l;MuPur&33~_x!fWPD+1teq>hNeCsNKT$+9KKE6)YvJ zW0VwqFYYlqfP@vso{NQ1=)j;HQVScmIzrqnDtM)Gt{h?s!DZ?~3P`xpOBv(6v8kd*!Fszf;yJZdGP_G00sH%ocF!9jF>mHCUk;iB)@lC z3j>Ch6CQ$85x=!EA(#wHhjENjW~@sU2ZuU918f)<{!vFHh453gAa3eVpNrYsEw6d7 zY=oKG6o3e*j}rptivcIEdtGh|1Tz>D3N%6%ampkMIj3)vb6?rs%U~6ht90Xim2_9u zE%mm3m1Of%joy&SysIcFPHVMdde%+a4_G1r)EmLt#7n?PILB%PHVDaAnn}yuBUHz|jd-qy!*%-+-GEO!4-HyUox4sOJ zegl-b2=xP>{sK=d`T`We@C8x8Jnp#w#k>SjIM@tOcIFry1e8Py+zNPLIeE-Vp_kkM zl79fyBC@HXnQC?-8m$e%_Av^(5Zf5uZ%SW=a*R`$RpNS_2_Kq5uv>R+CqfEgMRdb6 z+N~*!<;F5_l17A3JQ3L&I*?MKsyS8Mg{1~8Kde%Bf;w@*Es~%Sd1+6F55z_|^l3=H zPTlbUizAOmTgMT<8MU8Pimj5fhieZe3L;Jm_7m-j56oPq>Txv`XA-e2);9>b1hx#K z`M@2?DF_erg)s=RekkZb3LI@^zdclLqhulyBoId=d>{zHk7e`8vxl*2j4Eyjb){FQ zPG~-L6<99x)>9Qv3J8|8gS?4QjyL-ufnW+8AP>AjlDAScb3ec-`wZG5=@$Y;lxzIu%8?Ws?B)6cOcR>^EGP-thCd5_5qJ&ovO^<87vMj$xCs=P zR418|1@-Ei9Kil`E3=8SXHerfD+qyov`c2)7~o5ZJ;{MZ9crX&<maJRac)Jstq-odVpR z+6SG?FlKTKGm;`ck-1|JvS4pC=eF_9sOs(`JeJX+7$csSL+AxDNjR{0jA92Q1*F|N zQHbNi46N6w$QQ%(#(JcZh`3Zeu6rX3KDGz#YhOF;GcLv1J`W<;#q5VW9VDanZ>$=o zD_?j1Pj75Kcdqxw;Xl8v`QwCty{$VFA(O$+0zJ6WYd|$`{yMoWJHnFy0%;A0s~j?ZsBi1X!raZP`ki1BO)Z3I}2a;2KPi z!b>b5lM>*a1?HjL*$_v;U!+H4CR2KZ1aSju*FS*$lx{ROgf8)ko0^9eq67mvIk0+d z9x(MxmW>-&KUiq17oA|3oiv1+Q2AN?@?lLb0@lbVsz6)Rx@C|;;;U^;m_4};eWOs3 zN}@`T-&1)5ahH3o5R+cj9^z(dk({#0;Jg?un4Zvrlf`&+Ma~H<;)@RO71)tslB5u1 z7c1@v_0fi_-4q>UHu#DzFuV1p4E!w2?{+_?#_Hq0d`dYasU_DolS}m=a4gFU#u6bd zc@Tqw7@Zgl=|?_xiKWLskW3UWiz8ry(aBX|srz-i7%vFSOiNtZV|?BOXn*?xpJ#@a zREH-)Ln)kK0qlNx59iD3yMY|0f>rsbRER4QC8&FWI`Psed5lB8lxKNEaoC#ViTe;K zjRH<2z+w=XHxNKaD)w8ZU*+2X?pFhtPcDf1krISrrd*Khh&7EO@v0yUZd>2?5s6KcWz ziBf}Cu__br)IBMsXsmiP;v&IwHKrguTGWOg@&=1gzMaEMXA$ec52-?oUV4IXDim3H za%$i1WE?Ca7=hy!*bpR^*I3U*5cX62v1$3bE%Q5?E7t9vo4g5kTS|Tsn$Y8P+`$0XX+duA*d_;e1 zL`5HzBQRk6R2~HSKbMC@%KE5Q8}I}fFP2ywSZK5WJLXaVK~3K^Zv-MN9GMYtPo}H{ z>KYmeHiMJ|BW;Sz&OYXmUr$#}GTRG$2e>xNSJjkBvh^z;)JaD&9c*-48|k>JzCDa} zLrEG*!E6dr**T`t8vn)Z4LRi<^$4qI=LVieCC_t-(G$LWPd)wOy{FVvE`r=_(RN2o zfmlIvuQ?2Q8?zUPD$)TP0c7YSE5L4A+2FojtP8qIz3CKqFk(t`Z~OpWs%;#%0mu^4 z9_VKXZs3Uh8-C4&L&~&By2V7o+hNhnj#t&c+2NN#iwjEVZD8+2)+O~vV>H)iA%36; za1p=6JKz|LV%=`jXkmYdG$F?#QTM)4i-8fwM|yAIxqIzPx*YQ*&INqHjNo?`$G>rg z$`=Ff7gp+}sW=e)7h{Vt!DbiO1QWN_QfP`vMR*HT1av5sFbu3C=gSrSor=j1QD)r@L&RpvI7HP zS)>dYhBQkm0=QHHNqabHmswZ=q6$PS{t9{o$ubnJ0K1YhfZ(eg8kbkksw^ds(6C`I zVzGGjJXt!?gtQGR^)Q_ivgClFR^Dxd0Zzj2JX5G@OF%s_TmX!y9$HaeXlRSK@{Oj6 zaGw{yq=HhxYeoAE1BpoOB7fC;&Ebw_MH=3Y$Qz7lCaXLxnKEaYEu|Sz&16khNuwkZ z$pf?q(|wOZE$Vk4fhZbDjeC?x3nR^-a33WX z5s8&>AvU?_#EXhP28bQ#s2USr!_!z4A&PzhqskMZSXTwZ0g~}YnNH*dd|l#H%1+cj z%9}CB0U~UufCU50qmrpD0YP;!#;f~KQw#(Er_eXB}YdlHe%3K%v)y3#d^w7r-_+REfQG!t9C28KcCjhPH z%O5V_`;Wh9lsCp5!CYp|<<$CBf7~gp3IC3z0+m9qM0)PL;S1Ygu?>AF$Ut=|o%%-$ z8#!$Qq)!WnivG&st0$CeNI8-Qb0H5Mvim@JxbT&hyccu=CRPlI3$4emowS7vdzP3J zLJ>v|F}LJ>XpXq{0gAhbevptN6)NDxyLeLcXqghVeS%y4CRjj;y)E2yh#-v#Qx1gj zrs8n7jzhBA&FW2hC>kD*6sQb17&ReDk24oF3@8JCS({E=*hpA|zuN4Tjt+2LR1{ea z-KXYh(;+DCB2eFrl<|m&e-wq<&sbp;fKokjjfIGYlr{A*)xkuhz=E~ab6#W5!4n{{ z(>$SxHbAJWA2cAcSv}rBAznmQRyPFtY^!Pt7E@PfZ>R=TGpe1AuCLpuHUpOU)+4KM zML;m9Q(xq$zlo%xX46X9@40{~L9)r(BKePEnHy3;Z~UdbjAY#Lxr<1AMHdkjADr9( zBfP4z&ugU#D^RWmU z=-Z&|qpMoM@z#mrYZfgMnPEv;-0*+qFu&U)DPXnVO6Cz2@kRx)AhUwXr``dOP0Yq=*Ml%E+SS{thg`32=0a}xnUDl^swyYR_oLEIy&}s7rPbpT>gl@@+e6GIlTK{U7J%Y^6d2!nwt zpOMm08by!tys=x6G=N=xvD^wPnb9P*JIlGTh>aZKRN$J_G_V>DM=6929Q9fK@ZoO* z#0=XI=MYPbvn&$l@}_@3vdnjARqYQ1B>rCiNsyX9Md`a!x>SUl+0f!+zW12LeGNXV zX$#b?Rk zb%-$t5^yCTi|cEHsm-DT2q3hNQ6b)(^#|@>b%LsmiabD-^Lr5EN+t+~l5?#9i5_>4 zy6%!X^ZC0yO`<7E@&2?nL*^iulTOMYBM2Jwe1^z~=ezv5^bdUQUp*56H-I}(9nzLq zpQ`x`Y_Xl%4SpTU+md($jT<_|Pz0C*Msagw?~}z=Xiw-Eq>7nC3zl+__=XGv!94=3 zZZvgJDOCCtg*74U(L3PsOWSlme|Po2^lE;3gBW}O_D*EHt_?xE-`>@@2O?ls;NG}d z2I zs5JGeVn^F=j0>o!5eSDUy7hQn(jKT8xjSs<(IRR?c1aCzC@C7$A$0YJ$0;)^Bl{|E zwaRWKl-guE(4SRi8zw0qAl^wjD081EBDdhc^X?v@l3x4LKdsHRFe=st6Xr%Aid-9! z{dRn=C4gUa1v+|3;xRypN!7~%S}L>MQ}3H2S}CB#E2zM22DQb&-J?KXn_5AQqp1yQ zB(y(p>#TiNc#)27W}T)gw|aE^g6<#%KvoiNcW0caKB)}5hxIIYR3r;QXBfB62CJp4 z-Rx2-WV`A>8@2ud57Wn!s1in=W&rIS`KiMd+KiUFT+-t2PBl^t&WbD%SFb0Ahf!qs zk4!$`j>AS%>{15;xD;C?MhtHx0&}Qwr|tI9Y$$Q5z^KO5183SyAm7ISY9`&oE9HgL z+&aQhL=;EfQ>@T(8M3yn-3xqyGU9sGp%lJfux!$15qj0wagTK0BZ7;0ZkC>;URK>) z6?a=FWz72(O1=Fa4(>?^coTg2(ghgvdaY;#qR4gzzqd*r1*$mp7~YYhKLn@wIXV-7 zp9mdG6))(-;5${t;Vjuz$4@AIsCa#e&=-17nB0Aj6bYq^WvB}`-U+8`dH6=6*uJv4 zV^-zP{8JlSFso4^$Z$f1t%BQpuk13CB}Rgx&A4!iAtCL=Og`sD9L!foS`d0zo{G^Y z>|}-NvsCtPsG%-IxUb+w{l^IP$|!>1n0JKZ;?N7Rp`*?}kONbGutThomx~<|BB#5u zbx;~JNM&nN_->Fg+g&FCnsWlH9PrhPjtG?wIs^4&gsX^CD%|R1q}?(Rtf>{>%xo}j z-y$M2uv#L=ZSM$a_^a=ox@!Zd54+g>AWb00-wxIl+){8NmE|ihL9elcTAI_ofZgG9 zh(RP>VLDBItxKIrL=Ba@{dhTUcnX(dzLMl#yvUn!Of{i0QsP_d{z4|EZ94UObm$-} z6Q6LN61vqgpfb8@b!c?d<~xfb=~&}IH30I3dOPqJ-T@n6{^att!dN;sq_bmEH2M@R zIJFZ1F$q;Y$AhHuw{z7%vl)jD=Me~3ivAw6OGiHa%zz?5aM}G`V#J^by^`*65IM1@ zVLx8tn~y{!bzs%>S6kwZqBwsC@)+cN4N{=pPG{1@1gg62>B8==<}YD5Ea7>%>DVxT z=c97evNEO?bhiZzcg4OoPM9~@TaXai#DT=1?R+OVXT|*Oem_AI4>!|stlf8XL7VMe z{pAWFvFbg*{};(p19Fj6h$4-rM`lZ^zljxpRFC0LVMq%XbI zK8#BzH>LFx5T2Fsymz2n%^zn2P;rve6 zle7tb?QZ(fp;ZtF7(O~3?o{<%X*ws-@R%9{D`qrT3f|of7kFW@V$&3&7OB3?F2m5t zb%;5Jq2RF!>iqgXx>A=o(iQX(Z}Krshs&R;3#yXOTF(2XE3Q zBNJD8hn+LUZ0JykBeI7ZpYy#Xjo=DlN`;CEg-D&%c^zu<+r~&+{VqUj<}Cq~aXu=w z4+xSWB;wS8R6q5|5?8`qy3Tw=9h^bu0Ch)AZ8y;>eQD1EC^+x_+_ep2%2yq?fD0)_9U^%>klve+a0!?{q zLCx5-;bi7(i>J=%C(m(DLa+v*5|f-dU$6E>>P$v$ zJ)j6d?`!ZB@T0BUpPZ8LvW4(&bIQEO^0nEJSPp>%7uaB_1rH{+(y_Q9&haQlUfS6~z6k!)N#ZD*$MS}RV*$-y}*R+LOOcqx7bao-pFt< zlj|zvS%%#Kyjb_>wAw$#jn78jagcu<+%E8W=IU5F>K*z+Z8i}=p^iCqKb|Y}i~)|Y z65}iA>6N*=8hh6d6YBX>_EjgO1m8{0FkPK;=RKW#o1fW{-62raK^d>wq|G0zj$L`} ze=Q2`3_@o>a8`ribW*5sb=Af|Y?LLIPy_csv}qe#o3glz^hB3z|5cWCMDDvL^R9MTu3E1kl$5n0M$ohINQ93#fW$&9 z6+PTTLQzY5aN0K>I(i70Kr9ipZa#ga1EpIEFB?|xZojQVe2SWU&>KL`1IR7am;)5C z=$uCfr{Q=N<#&%bV7Vedp}4VnBSC;%)H!g5hDEflLx;NNZj7I(6zST9!jN|-hNuXE zFwj}E6VwwX;Ebz!S^$m$nPkO*x>j@?r`~P1Mr<>}7KdjMSvwv&iLxNNRY-!)q5}8Q z%oaCmh!`EwuUK7uAUIMWrZ#5N)-iNY0<^WI2T#9E&ToWXTZF!zgVdoD&1R^Jqir2^ zK?<}Q(V*v9JV1|7+xZ;2@H%gpxL(ccXlbVGEQ6O+YC^ z%&JR7HD;iL|0vZ#Sbg+dR&~NlZ9f^E;L*dYGmXlKyJhG-HFWB58 zc1H6=L{HPB(0jAc*tu1*ul!D4$C}Sno$D`zeCGRD0Aptz=bnkLLfaPpgSnu)U@-s& zMvc}~Bn2T2O#z>vkV9K+GaY{HN1`A!W8m58QS|E6&H=jVS%=F~^mHxuH`f6njc8Hb zXbFmYv(O`=3qXTxYo`mm$vOeHx|+ebkCKddUQI{+xB8M!{Ua=BN!el(Cen^6_gd6E z+ak3l>u8fzIzlQD2f^tn79h<}ZKu0A>+5Ih{DX`~KP(S=64yZ$pkQzO%G_(mw-9TL+j@6P7WKabfh;F08^K^go*ado# ztV5WP;YB;908X`lKe8f-eyaRVJs@yPcGu(HlI`i%P5@ih&{KGrRY##%E8LX06}n|v z>oC<>topyxs{LUE6di~nQJv^LC4teXBH7lZPW!@vfbzKy48TAs`=v@YKvt>a}wby7;;7~Wz{;Ac<1f*Zpso>G_&kaopM{`d~&ifF-))D@xZH6SO z#`J2^g9+fpl}qG!5i0A{0P4em`OasklZ7A}=qx1r1#;=|z)gxMW%kvh+qeft9h{P5nDF8$t`RhyNc=Ui>_%Xp z9zUH1<}PuONan`y^)}9KGa=sawZrf>BN9yriy+Y=eFRhk)S$-F0lW&vlVQu}+dzwV zku5)Itg|m5RWci9s^iXz#jJeNBXPEE24Qp`SZGu75Fbc1@Ga)7OhTLhz@q&?KkC60 zD5Oro$}UG0@dj_a!Hbs@2nXm;#8eKlQVGG+)KZo}lJ}+>-CIwKY4c-iH%`aG6-P}6 z5uq!8+HC-Vxv`%8jv{Wrj*5LMCMpp!!(e~3Dk)Eir9uxu!IDhl-wr7WR3QeS^l&y1 z4MVCEe4BM4_HH2S!{28zRrH*m1D3X>@C`lHJ9Mfj0nw<5v8W@sANMbiUrJ5kz&>Ui8XQdtjw4ozcplr4bn<5scSe^9^kqd@T**6fsIP z)u@4`5pm#y8U$!eJt_<|5D=?P{eK(iz`J@+%ZH(+Fqs_?AXJL+57wo&+#<3IW{RXe zQZ}Mv2{sI7k380No*imEw4W%4Wr|Io>ewc21L?U32&i)1NV>rFhfW8?x1!mSx8-iR zD(ND@3;y~g+)&A2RYYFVlC-BrYD3nvo#FI!*K^s{`6rRg>?b@5AZp5s-&RI=0GyQR z{{>BS61YFu6}sEd~Tc;u&U`Ht{;~)TV84-Y1T-lB^P+6OWp7LE=ZQD;~dbF1jr6%&3`3 z&k;w7#bO&PZOlrhMm$LzQ#GCPg{;Ra=Pk}!xyqXNBnxA_*Y$;y52eKzJ8u z)Ewvg*l`*sK=2v3(p&yY9hm+kz1GrVM?lXuaBw3Vu2MI^!67hQr0g}HcXzh;_V1Zye?K5>a)t=El+geH00v@9 zM??Ss00000`9r&Z00009a7bBm000XU000XU0RWnu7ytkO2XskIMF-^t2NDDaI>4~u z0000FbVXQnLvL+uWo~o;LqSe&aAj`XmQ{5C01Tx`L_t(&-p!h8Y+T26$A2^T?%sWI zmrqfmWJwk&krXY-k`>XeEDM1ZOR8lV4lDzXVFXT!_(Kd8L6ClEk+emT7U{R9g^Sj8 zKE!CFAgznqj_MSSVA-%Ok+o$pmQ0G&gW}Q@-`v%{?_>Ibv-FbOB`M2LGr$G8ckj%c zbLRZd`JZ!FFnfNvhCdueDMcg_p{lB?=$_u4R%C8S zDY-gwl@srs;L_wJq>x1YQI3a?vvKuCQWF#OzWzFi{(fScH{)fqjP>-eVgG*WHf`en zYnY2ej$k}7PVYo7letNR5agXaQ#YqrSKGws#fzkdhUj?qSz=91#6S3ePhWfyCzm7k zt#8e`+3$lQp69Xc?rj_yJHm&9A0nkB7KqWht`$3z;p!W2u;#%BS+jL3lLG^cojb?+ zXP#las|!1qyOj`K4?GB1fc*tzcY#a508lU&XE8<43i8;VBOKawaCTQA2nWNYvr}00 z^{nsg#L4Fw>+7Rw?_QdA?qsH~59N8cV!*FSA%0R5_61^*pts`mDZp`Drf%j)<()IY z_kgQr*(BgNj9s`$G9E`riD6kZKlBhnN-{%3TzUI#wmgxU?`9xe9_)re{M}iH*SCsm^C$o z>+4y&V+Z%X@B%$Ay~IF$Jq@j`A`bd zqAe}7A31_)S+~q(q|R3>)?a`Wa*@Hzg+R|23PiVTVdK}o&djda++hX+R5dkGux*TB zkS&J}VP~_r&TPK3A`zrvP$(3zZF^DjTv95b&CIPRvRLub%q~YqM@4s67m1k}gp`Q& z>*pSP_x<;mCs>|GJRWCydRhQ}z_--%*@DgRc!Ivc8zo#*EJ2_J0+>jo7@tYaW9z1V z+6D4mU0vR#OP5^Bvb-YgC{a{+$}t2;5FSFhLP)i6H^*_r|wHxoyWm z(`QxN`P}5twcfYiee*rIG}h*O_pM*QamxF57~ zC%^f9nMjO3rA+l#_*4rv!@`l@4Th@TczS=svh~rj8EnW3bDq6M%Nn2SB`VH>c=^|t^TmW$Ve!)M#DWm&Ar-7rk}4%}ff4DFol``V;Luw^uS@7W zv@o@+lB;Yumn&FUR#0>$FfW}eZvpxX4JnsP6(;br3a%xAHsD_EUN?c>l0-KSICuim zmCh*r4z;0?E-K=@j zIPi~p!Myf)HOC7)X2I^vfxQX%V+~fc5`PDLwu}c@`q~BjP#Yu-{5SA#6+rKrz)*!n zeZW*n*RcRx2YMFyYg)pe%nQFoHz>7!N-Ht6j9V7nsX^~qtk0+P+_C|~{Pv^Gi*7Cx zw-unu&Eti+xoSBKl$}4j_p;b4H&^l{k4ggG>N9iYhg_MICcm%4KoV9yf=XZ`NlBCJ zg5bO&MHCJ#lVq?^IKn1NijWeO z(xO>0ABU76D^etJ@S(_(B`>mf6el_1k`qNA@s`T%X2nSE2XZ2ZEo`JxxFU;7L5LLx zI<e#_vU|>skb;nd$Mt__e;1 zsHe|qj0h1|{m07h4Gq<-M( zBB%2EeO`5SwF-rTp5|EBfgfpdSI#gEz~2B9LI@`u4yjlyrhGo1tCjBt956Ttnz z{{Sh&FuYhSs;a80JSn9OOadVZ!1saUfk2?TqoYIKfBysAbI(20*Vl`DKJQDVQjMArb^#*`_TR3J z@YTAyy1?$;yTzV8owT&Hh+r@%r>CcbwrzK4HhxYs^0JDo1C9e<+q7wuIC}Ib2M!!y z>(;HbwY9N!?OIZ)6vM;A5&fd(cfeqYHFp9(_WS+yot>THvBw@`@7}$%wYAaO+Da%C zVr*lpT><{4gct^Z=Yglf;c(#a;ln)s_~UHfzMU;ww$R+%jBVQt3=EjSM&N>O z0(#{X*#&$Ts6BS<7@eJ+L?RKSl$fSTO-&84Sd33T`GjmX8`bXjVM*Y40eHBzwbeX) z_%IzE9Tu>2#W*p&?l)6smyNfeAgo75EO&x_|$EjvP5cO-&6_N({pw z5{Xb(SI7AHI5%$G2y2|2)#bz@Iu-(|gTWxp&CP^Dq4^QOG-+yTqP4XZT{8q11dO$S zT(@o=EiEmJTK`p5RkXLavwHRFVt_B*ph{mn@W2B^qtSWu4a1i5D$m*_Sy>eZP|VUu4KK9juvDD#gIS0GUjN1)X-{@i_hc{giYzN*e@2fESO) zxqSKZyf?f;2yWiINpEj2qobor7f7WcJX!1&cXxM_NF?T$fUe8v=qMk3^ilEFl$N0^ z*gajRZ%d_8M59q+u^5(Rk3B$ds>Ip-SK$b7mY@#si`3t4C1;j@pznf-g$>pr%s{E z?w5d%DuF$vwcIv2Ik{?ba+2xkX@-Y~xp3hEXU?4A?AfybW6b_w=CuW-=QI#$Kc?g(nk0ZaHV9ft*zYVIL^lF*RRV=Cd0_c2z`Bh zba!`i>eMMb&&%uD{S}t^ol8hJ9eVWQUN{`~48!nr&KTB0)Ky4mO~8+V1mO65J}(#y zdfIX}@V~$T4fb-B>3-n1`gGkuAmI7^eoxo!N#I|AmW8mWgt`E*19%45r=ybtdux1FYdee-~8z=NSg(X@-&AO9$6o_g34FkW_?{P*J^0og1Y$pVPC!%Fr P00000NkvXXu0mjf<1#d6 literal 0 HcmV?d00001 diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index a2c019d3..6f754715 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,9 +1,10 @@ Change Log ========== -[newOD] -------------------------- -- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/master...newOD) +v4.0 - current +-------------- +- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/newOD) +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v2.0-master...newOD) ### Removed - Driver for Linux (socketCAN directory) moved to own repository https://github.com/CANopenNode/CANopenLinux. ### Changed @@ -16,9 +17,11 @@ Change Log - Rewritten PDO. PDO mapped variables are accessed via fast read/write functions. New RPDO event timer (timeout). - CO_Emergency is mostly rewritten. Now is much easier customization. All other objects has been adjusted to newOD, inspected and some parts were redesigned. -[Unreleased master] -------------------------- -- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.3...master) + +v2.0 - 2020-02-25 +----------------- +- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/v2.0-master) +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.3-master...v2.0-master) ### Removed - All drivers removed from this project, except Neuberger-socketCAN for Linux. ### Changed @@ -56,9 +59,11 @@ Change Log - CO_fifo.h/c for fifo data buffer, used with rewritten SDO client, etc. - CANopen gateway-ascii command interface according to CiA309-3 as a microcontroller independent module. It includes NMT master, LSS master and SDO client interface. Interface is non-blocking, it is added to mainline. Example for Linux stdio and socket is included. -[v1.3] - 2020-04-27 -------------------- -- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...v1.3) + +v1.3 - 2020-04-27 +----------------- +- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/v1.3-master) +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.2...v1.3-master) ### Changed - License changed to Apache 2.0. - NMT self start functionality (OD object 1F80) implemented to strictly follow standard. Default value for object 1F80 have to be updated in OD editor. See README.md. @@ -68,8 +73,10 @@ Change Log ### Added - CANopen TIME protocol added. -[v1.2] - 2019-10-08 -------------------- + +v1.2 - 2019-10-08 +----------------- +- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/v1.2) - [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.1...v1.2) ### Fixed - Memory barrier implemented for setting/clearing flags for CAN received message. @@ -80,38 +87,38 @@ Change Log - Emergency consumer added. - Callbacks added to Emergency and Heartbeat consumer. -[v1.1] - 2019-10-08 -------------------- + +v1.1 - 2019-10-08 +----------------- +- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/v1.1) - [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v1.0...v1.1) - Bugfixes. Some non-critical warnings in stack, some formatting warnings in tracing stuff. -[v1.0] - 2017-08-01 -------------------- + +v1.0 - 2017-08-01 +----------------- +- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/v1.0) - [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v0.5...v1.0) - Stable. -[v0.5] - 2015-10-20 -------------------- + +v0.5 - 2015-10-20 +----------------- +- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/v0.5) - Git repository started on GitHub. -[v0.4] - 2012-02-26 -------------------- + +v0.4 - 2012-02-26 +----------------- +- [Source Code](https://sourceforge.net/p/canopennode/code_complete/ci/master/tree/) - Git repository started on Sourceforge git. -[v0.1] - 2004-06-29 -------------------- + +v0.1 - 2004-06-29 +----------------- +- [Source Code](https://sourceforge.net/projects/canopennode/files/canopennode/CANopenNode-0.80/) - First edition of CANopenNode on SourceForge, files section. (V0.80 on SourceForge). ------ Changelog written according to recommendations from https://keepachangelog.com/ - -[newOD]: https://github.com/CANopenNode/CANopenNode/tree/newOD -[Unreleased master]: https://github.com/CANopenNode/CANopenNode -[v1.3]: https://github.com/CANopenNode/CANopenNode/tree/v1.3 -[v1.2]: https://github.com/CANopenNode/CANopenNode/tree/v1.2 -[v1.1]: https://github.com/CANopenNode/CANopenNode/tree/v1.1 -[v1.0]: https://github.com/CANopenNode/CANopenNode/tree/v1.0 -[v0.5]: https://github.com/CANopenNode/CANopenNode/tree/v0.5 -[v0.4]: https://sourceforge.net/p/canopennode/code_complete/ci/master/tree/ -[v0.1]: https://sourceforge.net/projects/canopennode/files/canopennode/CANopenNode-0.80/ diff --git a/doc/LSSusage.md b/doc/LSSusage.md deleted file mode 100644 index f632a960..00000000 --- a/doc/LSSusage.md +++ /dev/null @@ -1,121 +0,0 @@ -LSS usage -========= - -LSS (Layer settings service) is an extension to CANopen described in CiA DSP 305. The -interface is described in CiA DS 309 3.0.0 (ASCII mapping). -LSS allows the user to change node ID and bitrate, as well as setting the node ID on an -unconfigured node. - -LSS uses the the OD Identity register (0x1018) as an unique value to select a node. Therefore -the LSS address always consists of four 32 bit values. This also means that LSS relies -on this register to actually be unique. (_vendorID_, _productCode_, _revisionNumber_ and -_serialNumber_ must be configured and unique on each device.) - -### Preparation for testing on Linux virtual CAN -LSS can be tested on Linux virtual CAN, similar as in gettingStarted.md. - -1. Open terminal, setup _vcan0_ and _cd_ to CANopenNode directory. -2. Make some unique CANopen devices: - - Edit CO_OD.c, change initialization for identity, for example change line to `/*1018*/ {0x4, 0x1L, 0x2L, 0x3L, 0x4L},` - - `make` - - `mv canopend canopend4` - - Edit CO_OD.c, for example: `/*1018*/ {0x4, 0x1L, 0x2L, 0x3L, 0x5L},` - - `make` - - `mv canopend canopend5` - - Repeat this step and create three further "unique" CANopen devices. -3. Clear default OD storage file. We will use default (empty) storage for all instances: - - `echo "-" > od_storage` -4. Run "master" with command interface and node-id = 1. Note that this device - has enabled both: LSS master and LSS slave. But LSS master does not 'see' own LSS slave. - - `make` - - `./canopend vcan0 -i1 -c "stdio"` -5. Run one CANopen device with node-id=22 in own terminal: - - `./canopend4 vcan0 -i22` -6. Run other unique CANopen devices with unconfigured node-id, each in own terminal: - - `./canopend5 vcan0 -i0xFF` - - `./canopend6 vcan0 -i0xFF` - - `./canopend7 vcan0 -i0xFF` - - `./canopend8 vcan0 -i0xFF` -7. Note that `lss_store` does not work in this example. For it to work, OD storage must be used properly. - -### Typical usage of LSS - - Changing the node ID for a known slave, store the new node ID to eeprom, apply new node ID. - The node currently has the node ID 22. - - help lss - - lss_switch_sel 0x00000001 0x00000002 0x00000003 0x00000004 - lss_set_node 10 - lss_store - lss_switch_glob 0 - 22 reset communication - - Note that the node ID change is not done until reset communication/node. - - - Changing the node ID for a known slave, store the new node ID to eeprom, apply new node ID. - The node currently has an invalid node ID. - - lss_switch_sel 0x00000001 0x00000002 0x00000003 0x00000005 - lss_set_node 11 - lss_store - lss_switch_glob 0 - - Note that the node ID is automatically applied. This can be seen on `candump`. - -### LSS fastscan - - Search for a node via LSS fastscan, store the new node ID to eeprom, apply new node ID - - _lss_fastscan - - [0] 0x00000001 0x00000002 0x00000003 0x00000006 - - lss_set_node 12 - lss_store - lss_switch_glob 0 - - To increase scanning speed, you can use - - _lss_fastscan 25 - - where 25 is the scan step delay in ms. Be aware that the scan will become unreliable when - the delay is set to low. - - We won't configure this node now, reset LSS. Now we have 1+3 nodes operational in our example. - - lss_switch_glob 0 - -### Auto enumerate all nodes - - Auto enumerate all nodes via LSS fastscan. Enumeration automatically begins at node ID 2 - and node ID is automatically stored to eeprom. Like with _lss_fastscan, an optional - parameter can be used to change default delay time. - - lss_allnodes - - # Node-ID 2 assigned to: 0x00000001 0x00000002 0x00000003 0x00000007 - # Node-ID 3 assigned to: 0x00000001 0x00000002 0x00000003 0x00000008 - # Found 2 nodes, search finished. - [0] OK - - - To get further control over the fastscan process, the lss_allnodes command supports - an extended parameter set. - Auto enumerate all nodes via LSS fastscan. Set delay time to 25ms, set enumeration start - to node ID 7, do not store LSS address in eeprom, enumerate only devices with vendor ID - "0x428", ignore product code and software revision, scan for serial number - - lss_allnodes 25 7 0 2 0x428 1 0 1 0 0 0 - - The parameters are as following: - - 25 scan step delay time in ms - - 7 enumeration start - - 0 store node IDs to eeprom; 0 = no, 1 = yes - - 2 vendor ID scan selector; 0 = fastscan, 2 = match value in next parameter - - 0x428 vendor ID to match - - 1 product code scan selector; 0 = fastscan, 1 = ignore, 2 = match value in next parameter - - 0 product code to match (ignored in this example) - - 1 software version scan selector; 0 = fastscan, 1 = ignore, 2 = match value in next parameter - - 0 software version to match (ignored in this example) - - 0 serial number scan selector; 0 = fastscan, 1 = ignore, 2 = match value in next parameter - - 0 serial number to match (not used in this example) - - Note that only unconfigured nodes (those without a valid node ID) will take part in - fastscan! diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index 94034db2..fb331004 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -8,15 +8,16 @@ It is necessary to implement interface to specific hardware. Interface to Linux Note for device driver contributors ----------------------------------- -Most up-to-date implementations of CANopenNode are: socketCAN for Linux, which is part of CANopenNode and [CANopenPIC](https://github.com/CANopenNode/CANopenPIC) for PIC32 microcontroller (bare-metal). Those can be used for reference. There is also an example directory, which doesn't include specific device interface. It should compile on any system and can be used as a template. Device interface is documented in common CO_driver.h file. +Most up-to-date implementations of CANopenNode are: [CANopenLinux](https://github.com/CANopenNode/CANopenLinux) and [CANopenPIC](https://github.com/CANopenNode/CANopenPIC) for PIC32 microcontroller (bare-metal). Those can be used for reference. There is also an example directory, which doesn't include specific device interface. It should compile on any system and can be used as a template. Device interface is documented in common CO_driver.h file. There are many advantages of sharing the base code such as this. For the driver developers, who wish to share and cooperate, I recommend the following approach: 1. Make own git repo for the Device specific demo project on the Github or somewhere. 2. Add https://github.com/CANopenNode/CANopenNode into your project (or at side of your project). For example, include it in your project as a git submodule: `git submodule add https://github.com/CANopenNode/CANopenNode` 3. Add specific driver and other files. -4. Add description of new device into this file (deviceSupport.md) and make a pull request to CANopenNode. Alternatively create an issue for new device on https://github.com/CANopenNode/CANopenNode/issues. -5. Make a demo folder, which contains project files, etc., necessary to run the demo. -6. Write a good README.md file, where you describe your project, specify demo board, tools used, etc. +4. Write a good README.md file, where you describe your project, specify demo board, tools used, etc. +5. Optionally prepare a demoDevice in [CANopenDemo](https://github.com/CANopenNode/CANopenDemo) repository and run the tests. +6. Share your work: add description of new device into this file (deviceSupport.md) and make a pull request to CANopenNode. Alternatively create an issue for new device on https://github.com/CANopenNode/CANopenNode/issues. +7. Offer your work for inclusiun under the CANopenNode project and become its developer. It will increase code quality and functionality. Linux diff --git a/doc/gettingStarted.md b/doc/gettingStarted.md deleted file mode 100644 index 5a4cdbf5..00000000 --- a/doc/gettingStarted.md +++ /dev/null @@ -1,192 +0,0 @@ -Getting Started -=============== - -CANopen -------- -Before getting started with CANopenNode you should be familiar with the CANopen. -CANopen is the internationally standardized CAN-based higher-layer protocol for embedded control system. -It is specified by CiA301 (or by EN 50325-4) standard. It can be freely downloaded from https://can-cia.org/groups/specifications/. -Some information about CAN and CANopen can be found on https://can-cia.org/can-knowledge/ website. Very efficient way to get familiar with CANopen is by reading a book, for example [Embedded Networking with CAN and CANopen](https://can-newsletter.org/engineering/engineering-miscellaneous/nr_e_cia_can_books_3-2008_emb_can_pfeiffer_120529). - -CANopen itself is not a typical master/slave protocol. It is more like producer/consumer protocol. It is also possible to operate CANopen network without a master. For example, pre-configured process data objects (PDO) are transmitted from producers. Each PDO may be consumed by multiple nodes. Other useful CANopen functionalities of each CANopen device are also: Heartbeat producer and consumer, Emergency producer, Sync producer or consumer, Time producer or consumer, SDO server (Service data objects - serve variables from Object dictionary), NMT slave (network management - start or stop parts of communication), LSS slave (configuration of Node-Id and Bitrate). - -CANopen network usually has one device with master functionalities for network configuration. It may have additional CANopen functionalities, such as: NMT master, LSS master, SDO client, Emergency consumer. Master functionalities in CANopenNode are implemented with Ascii command line interface according to standard CiA309-3. - - -CANopenNode on Linux --------------------- -CANopenNode should run on any Linux machine. Examples below was tested on Debian based machines, including Ubuntu and Raspberry PI. It is possible to run tests described below without real CAN interface, because Linux kernel already contains virtual CAN interface. -All necessary Linux specific files are included in socketCAN directory of CANopenNode and Makefile is included in base directory. - -Windows or Mac users, who don't have Linux installed, can use [VirtualBox](https://www.virtualbox.org/) and install [Ubuntu](https://ubuntu.com/download/desktop) or similar. - - -### Preparation -We will use Linux command line interface (Terminal) for all examples below. Open the terminal and cd to your working directory. -First install supporting packages: [can-utils](https://github.com/linux-can/can-utils), which is very useful tool for working with CAN interface and [git](https://git-scm.com/), which is recommended for working with repositories. -Then clone [CANopenNode](https://github.com/CANopenNode/CANopenNode) from Github and build the executable program. - - sudo apt-get install git - sudo apt-get install can-utils - git clone https://github.com/CANopenNode/CANopenNode.git - cd CANopenNode - # For update just use 'git pull' here - make - -Now prepare CAN virtual device and run _candump_, which will show all CAN traffic. Use a second terminal: - - sudo modprobe vcan - sudo ip link add dev vcan0 type vcan - sudo ip link set up vcan0 - candump vcan0 - - -### First CANopen device -Go to the first terminal, where we have recently build executable, named _canopend_. -First print help, then run the program with some options. - - ./canopend --help - ./canopend vcan0 -i 4 - -You are now running a fully functional CANopen device on virtual CAN network. It is running in background until you terminate the process (with CTRL+C for example) or it receives a reset message from CAN network. By default process also shows some info messages on terminal, for example changes of NMT state or emergency messages, own and remote. - -On the second terminal you can see some CAN traffic. After _canopend_ startup, first messages are: - - vcan0 704 [1] 00 # Boot-up message. - vcan0 084 [8] 00 50 01 2F 03 00 00 00 # Emergency message. - -Boot-up message of node 4 have CAN-ID equal to 0x704. CAN-ID is 11-bit standard CAN identifier. - -Also, both, first and second terminal shows, that there is an Emergency message after the boot-up. Also Heartbeat messages shows NMT pre-operational state. - -The easiest way to find the reason of the emergency message is to check the byte 4 (errorBit). It has value of 0x2F. Go to CANopenNode source code and open the file "301/CO_Emergency.h", section "Error status bits". 0x2F means "CO_EM_NON_VOLATILE_MEMORY", which is generic, critical error with access to non volatile device memory. - -This byte is CANopenNode specific. You can observe also first two bytes, which shows standard error code (0x5000 - Device Hardware) or third byte, which shows error register. If error register is different than zero, then node may be prohibited to enter operational and PDOs can not be exchanged with it. - -You can follow the reason of the problem inside the source code. However, data storage was not yet initialized, files are missing. CANopen device works, but NMT operational state is not possible. Data storage files on running new device can be generated by CANopen gateway command `4 write 0x1010 1 u32 0x65766173` or `4 write 0x1011 1 u32 0x64616F6C`. Or files can be generated manually with the Linux commands below. - -Go to the first terminal, terminate the application with CTRL+C, add files and run _canopend_ again. - - echo "-" > lss.persist - echo "-" > od_comm.persist - ./canopend vcan0 -i 4 - -Second terminal now shows new boot-up message without emergency. - - vcan0 704 [1] 00 - - -### Second CANopen device -Open the third terminal and cd to the same directory as is in the first terminal. First generate data storage files with prefix, so data won't mix. Then start second instance of _canopend_ with NodeID = 1 and prefix for data storage. Enable command interface on standard IO (terminal). - - echo "-" > node1_lss.persist - echo "-" > node1_od_comm.persist - ./canopend vcan0 -i1 -s "node1_" -c "stdio" - -Now you should see in second terminal (_candump_) boot-up message of new CANopen device. - - -### CANopen command interface -Second instance of _canopend_ was started with command interface enabled. This is CANopen gateway interface with ascii mapping, as specified in standard CiA309-3. This enables usage of CANopen master functionalities via basic terminal. Go to third terminal, type "help" and press enter to see its functionalities. - - help - help datatype - -#### SDO client -For example read Heartbeat producer parameter on CANopen device with ID=4. Parameter is located at index 0x1017, subindex 0, it is 16-bit unsigned integer. - - [1] 4 read 0x1017 0 u16 - -You should see the response, which says that Heartbeats are disabled: - - [1] 0 - -In CAN dump you can see some SDO communication. SDO communication can be quite complicated, if observing on _candump_, especially if larger data is split between multiple segments. However, there is no need to know the details, everything should work correctly in the background. Details about SDO communication can be found in CiA301 standard and partly also in 301/CO_SDOserver.h file, description of CO_SDO_state_t enumerator. - - [2] 4 write 0x1017 0 u16 5000 - [2] OK #response - -In _candump_ you will notice, that heartbeats from node 4 are coming in 5 second interval now. Heartbeat message is similar to boot-up message. 0x7F in heartbeat message means, that node is in NMT pre-operational state. 0x05 means operational and 0x04 means stopped. - -You can do the same also for node 1, but you won't see SDO messages on _candump_, because data are written into itself directly. In "stdio" you can omit sequence number, to make typing easier. - - 1 w 0x1017 0 u16 2500 - [0] OK - -Now store Object dictionary on node-ID 4, so it will preserve variables on next start of the program. - - 4 w 0x1010 1 u32 0x65766173 - [0] OK - -0x65766173 are ascii characters for 's', 'a', 'v', 'e', so it is easier to simply write visible string instead of unsigned 32. This is equivalent to the above command: - - 4 w 0x1010 1 vs save - [0] OK - -More details about Object dictionary variables can be found in CiA301 standard or in example/DS301_profile.md file. - - -#### NMT master -If node is operational (started), it can exchange all objects, including PDO, SDO, etc. In NMT pre-operational, PDOs are disabled, SDOs works. In stopped only NMT messages are accepted. Try following commands and observe _candump_. - - set node 4 - [0] OK - - start - [0] OK - - preop - [0] OK - - stop - [0] OK - - r 0x1017 0 i16 - [0] ERROR: 0x05040000 #SDO protocol timed out. - - reset communication - [0] OK - - 0 start - [0] OK - - reset node - [0] OK - - 1 reset communication - [0] OK - - 1 reset node - [0] OK - - -#### Other communication channels -We used simple stdio for command interface. In Linux also sockets can be used, either local or tcp. See `./canopend --help` for options. Simple Linux tool for establishing socket connection is _netcat_ or _nc_. For example `nc -U /tmp/CO_command_socket` for local socket or `nc 60000` for tcp socket. There are also some tools from [CANopenSocket](https://github.com/CANopenNode/CANopenSocket) project. - -Please be careful when exposing your CANopen network to the outside world, it is your responsibility, if something dangerous happen. - - -### Next steps -Assigning Node-ID or CAN bitrate, which support LSS configuration, is described in *LSSusage.md*. - -Further CANopenNode related tools and examples are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket). Especially interesting is [basicDevice](https://github.com/CANopenNode/CANopenSocket/examples/basicDevice) - -Custom CANopen device can be created based on own Object Dictionary, see README.md. There are also many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download, for example CiA401. - -For own CANopen device with own microcontroller, see *deviceSupport.md*. There is a bare-metal demo for [PIC microcontrollers](https://github.com/CANopenNode/CANopenPIC), most complete example is for PIC32. - -Another interesting tool is [CANopen for Python](https://github.com/christiansandberg/canopen). - -Examples here worked in virtual CAN interface, for simplicity. Virtual CAN runs inside Linux kernel only, it does not have much practical usability. If one has real CAN network configuration, then above examples are suitable also for this network, if Linux machine is connected to it and CAN interface is properly configured. When connecting your devices to real CAN network, make sure, you have at least two devices communicating, connected with ground and pair of wires, terminated with two 120ohm resistors, correct baudrate, etc. - -Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native in Linux kernel are: - - Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with (-s5=250kbps): `sudo slcand -f -o -c -s5 /dev/ttyACM0 can0; sudo ip link set up can0` - - [EMS CPC-USB](https://www.ems-wuensche.com/?post_type=product&p=746) or [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Start with: `sudo ip link set up can0 type can bitrate 250000` - - You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can) (Kconfig files). - - Raspberry PI or similar has CAN capes available. - -Examples here run in Linux, for simplicity. However, real usability of CANopen network is, when simple, microcontroller based devices are connected together with or without more advanced commander device. CANopenNode is basically written for simple microcontrollers and also has more advanced commander features, like above used CANopen gateway with ascii command interface. - -Now you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware). - -Here we played with virtual CAN interface and result shown as pixels on screen. If you connect a real CAN interface to your computer, things may become dangerous. Keep control and safety on your machines! diff --git a/doc/traceUsage.md b/doc/traceUsage.md index 63992a46..ab3ecb63 100644 --- a/doc/traceUsage.md +++ b/doc/traceUsage.md @@ -1,6 +1,8 @@ Trace usage =========== +**TRACE DOES NOT WORK IN THE LAST VERSION** + CANopenNode includes optional trace functionality (non-standard). It monitors choosen variables from Object Dictionary. On change of state of variable it makes a record with timestamp into circular buffer. String with points can later diff --git a/example/DS301_profile.md b/example/DS301_profile.md index b3987c20..df6ca40a 100644 --- a/example/DS301_profile.md +++ b/example/DS301_profile.md @@ -15,15 +15,11 @@ CANopen device documentation This file was automatically generated with [libedssharp](https://github.com/robincornelius/libedssharp) Object Dictionary Editor v0.8-114-gc3a898f -* [Device Information](#device-information) -* [PDO Mapping](#pdo-mapping) -* [Communication Specific Parameters](#communication-specific-parameters) -* [Manufacturer Specific Parameters](#manufacturer-specific-parameters) -* [Device Profile Specific Parameters](#device-profile-specific-parameters) +[TOC] -Device Information {#device-information} ----------------------------------------- +Device Information +------------------ | | | | ------------ | ------------------------------ | | Vendor Name | | @@ -48,11 +44,11 @@ Device Information {#device-information} * [ ] auto -PDO Mapping {#pdo-mapping} --------------------------- +PDO Mapping +----------- -Communication Specific Parameters {#communication-specific-parameters} ----------------------------------------------------------------------- +Communication Specific Parameters +--------------------------------- ### 0x1000 - Device type | Object Type | Count Label | Storage Group | diff --git a/extra/CO_trace.h b/extra/CO_trace.h index 8dc632b5..a2e5ae5f 100644 --- a/extra/CO_trace.h +++ b/extra/CO_trace.h @@ -42,11 +42,10 @@ extern "C" { /** * @defgroup CO_trace Trace - * @ingroup CO_CANopen_extra - * @{ - * * CANopen trace object for recording variables over time. * + * @ingroup CO_CANopen_extra + * @{ * In embedded systems there is often a need to monitor some variables over time. * Results are then displayed on graph, similar as in oscilloscope. * diff --git a/storage/CO_storage.c b/storage/CO_storage.c index b69f172a..fde19998 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -1,5 +1,5 @@ /* - * CANopen data storage object + * CANopen data storage base object * * @file CO_storage.c * @author Janez Paternoster diff --git a/storage/CO_storage.h b/storage/CO_storage.h index 36b4d8f5..f338e9d5 100644 --- a/storage/CO_storage.h +++ b/storage/CO_storage.h @@ -1,5 +1,5 @@ /** - * CANopen data storage object + * CANopen data storage base object * * @file CO_storage.h * @ingroup CO_storage @@ -42,6 +42,8 @@ extern "C" { /** * @defgroup CO_storage Data storage base + * Base module for Data storage. + * * @ingroup CO_CANopen_storage * @{ * diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h index dcb3de11..dc8b180a 100644 --- a/storage/CO_storageEeprom.h +++ b/storage/CO_storageEeprom.h @@ -36,6 +36,8 @@ extern "C" { /** * @defgroup CO_storage_eeprom Data storage in eeprom + * Eeprom specific data storage functions. + * * @ingroup CO_CANopen_storage * @{ * From 1775b96450b2d3d79d8fdfad3a8347cd2ea3701e Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 17 May 2021 13:33:37 +0200 Subject: [PATCH 186/520] Move emergency processing before NMT processing in CANopen.c Hold emergency messages if not operational or pre-operational, don't delete them. There was a problem, if error condition was present after a communication reset, device was in operational state for a short time. --- 301/CO_Emergency.c | 13 +++++++------ CANopen.c | 22 ++++++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index dbc28508..c2c7bf93 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -608,6 +608,10 @@ void CO_EM_process(CO_EM_t *em, errorRegister |= CO_ERR_REG_MANUFACTURER; *em->errorRegister = errorRegister; + if (!NMTisPreOrOperational) { + return; + } + /* post-process Emergency message in fifo buffer. */ #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER uint8_t fifoPpPtr = em->fifoPpPtr; @@ -628,12 +632,9 @@ void CO_EM_process(CO_EM_t *em, em->fifo[fifoPpPtr][0] |= (uint32_t) errorRegister << 16; /* send emergency message */ - if (NMTisPreOrOperational) { - memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr][0], - sizeof(em->CANtxBuff->data)); - - CO_CANsend(em->CANdevTx, em->CANtxBuff); - } + memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr][0], + sizeof(em->CANtxBuff->data)); + CO_CANsend(em->CANdevTx, em->CANtxBuff); #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER /* report also own emergency messages */ diff --git a/CANopen.c b/CANopen.c index 9054a9a5..2be63eed 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1286,6 +1286,8 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, (void) enableGateway; /* may be unused */ CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_NMT_internalState_t NMTstate = CO_NMT_getInternalState(co->NMT); + bool_t NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL + || NMTstate == CO_NMT_OPERATIONAL); /* CAN module */ CO_CANmodule_process(co->CANmodule); @@ -1336,6 +1338,14 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, return reset; } + /* Emergency */ + if (CO_GET_CNT(EM) == 1) { + CO_EM_process(co->em, + NMTisPreOrOperational, + timeDifference_us, + timerNext_us); + } + /* NMT_Heartbeat */ if (CO_GET_CNT(NMT) == 1) { reset = CO_NMT_process(co->NMT, @@ -1343,8 +1353,8 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, timeDifference_us, timerNext_us); } - bool_t NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL - || NMTstate == CO_NMT_OPERATIONAL); + NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL + || NMTstate == CO_NMT_OPERATIONAL); /* SDOserver */ for (uint8_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { @@ -1363,14 +1373,6 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, } #endif - /* Emergency */ - if (CO_GET_CNT(EM) == 1) { - CO_EM_process(co->em, - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); - } - #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE if (CO_GET_CNT(TIME) == 1) { CO_TIME_process(co->TIME, NMTisPreOrOperational, timeDifference_us); From c10043a11044f0c107b486dfbf01759e1ca9b6f5 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 17 May 2021 18:44:08 +0200 Subject: [PATCH 187/520] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..46615805 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: CANopenNode +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From 2957b886e0b3deea89ad54dfa627ee9f117d4a2e Mon Sep 17 00:00:00 2001 From: Geoffrey Van Landeghem Date: Fri, 21 May 2021 09:06:00 +0200 Subject: [PATCH 188/520] fix dead link in README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0df8fb1a..40066064 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Characteristics ### Other - [Suitable for 16-bit microcontrollers and above](#device-support) - - [Multithreaded, real-time](#flowchart-of-a-typical-canopennode-implementation) + - [Multithreaded, real-time](#canopenNode-flowchart) - [Object Dictionary editor](#object-dictionary-editor) - Non-volatile storage for Object Dictionary or other variables. Automatic or controlled by standard CANopen commands, configurable. - [Power saving possible](#power-saving) @@ -70,8 +70,8 @@ Contributions are welcome. Best way to contribute your code is to fork a project rules should be followed: Linux style with indentation of 4 spaces. There is also a `codingStyle` file with example and a configuration file for `clang-format` tool. -CANopenNode configuration -------------------------- +CANopenNode flowchart +--------------------- Flowchart of a typical CANopenNode implementation: ~~~ ----------------------- From cdad71beee39a0409291b4f15718e0a0719468a0 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 26 Jun 2021 13:35:43 +0200 Subject: [PATCH 189/520] Fix reading OD entry 1003,0, etc. --- 301/CO_Emergency.c | 4 +++- 301/CO_config.h | 2 +- CANopen.c | 2 -- doc/deviceSupport.md | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index c2c7bf93..b70a718f 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -186,7 +186,9 @@ static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if (stream == NULL || buf == NULL || count < 4 || countRead == NULL) { + if (stream == NULL || buf == NULL || countRead == NULL + || (count < 4 && stream->subIndex > 0) || count < 1 + ) { return ODR_DEV_INCOMPAT; } diff --git a/301/CO_config.h b/301/CO_config.h index 8bef9a07..56d75cba 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -2,7 +2,7 @@ * Configuration macros for CANopenNode. * * @file CO_config.h - * @ingroup CO_driver + * @ingroup CO_STACK_CONFIG * @author Janez Paternoster * @copyright 2020 Janez Paternoster * diff --git a/CANopen.c b/CANopen.c index 2be63eed..30868f1b 100644 --- a/CANopen.c +++ b/CANopen.c @@ -439,7 +439,6 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { if (p == NULL) break; else co->RPDO = (CO_RPDO_t *)p; mem += sizeof(CO_RPDO_t) * CO_GET_CNT(RPDO); - ON_MULTI_OD(co->CNT_RPDO = config->CNT_RPDO); ON_MULTI_OD(RX_CNT_RPDO = config->CNT_RPDO); } #endif @@ -451,7 +450,6 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { if (p == NULL) break; else co->TPDO = (CO_TPDO_t *)p; mem += sizeof(CO_TPDO_t) * CO_GET_CNT(TPDO); - ON_MULTI_OD(co->CNT_TPDO = config->CNT_TPDO); ON_MULTI_OD(TX_CNT_TPDO = config->CNT_TPDO); } #endif diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index fb331004..a8a65860 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -16,8 +16,8 @@ There are many advantages of sharing the base code such as this. For the driver 3. Add specific driver and other files. 4. Write a good README.md file, where you describe your project, specify demo board, tools used, etc. 5. Optionally prepare a demoDevice in [CANopenDemo](https://github.com/CANopenNode/CANopenDemo) repository and run the tests. -6. Share your work: add description of new device into this file (deviceSupport.md) and make a pull request to CANopenNode. Alternatively create an issue for new device on https://github.com/CANopenNode/CANopenNode/issues. -7. Offer your work for inclusiun under the CANopenNode project and become its developer. It will increase code quality and functionality. +6. Share your work: add description of new device into this file (deviceSupport.md) and make a pull request to CANopenNode. Alternatively create an issue for new device on https://github.com/CANopenNode/CANopenNode/issues. +7. Offer your work for inclusion under the CANopenNode project and become its developer. It will increase code quality and functionality. Linux From 01887f268d3b183cbb759855f0d943e0a217b07e Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 26 Jun 2021 13:37:30 +0200 Subject: [PATCH 190/520] Update example Object dictionary --- example/DS301_profile.eds | 98 +++++++++++++++++++++++++++++++++------ example/DS301_profile.md | 32 ++++++++----- example/DS301_profile.xpd | 59 +++++++++++++++++------ example/OD.c | 19 ++++---- example/OD.h | 92 ++++++++++++++++++++++++++++++------ 5 files changed, 237 insertions(+), 63 deletions(-) diff --git a/example/DS301_profile.eds b/example/DS301_profile.eds index 2c92d406..325c1b1e 100644 --- a/example/DS301_profile.eds +++ b/example/DS301_profile.eds @@ -5,11 +5,11 @@ FileRevision=1 LastEDS= EDSVersion=4.0 Description= -CreationTime=12:00PM +CreationTime=1:00PM CreationDate=11-23-2020 CreatedBy= -ModificationTime=3:01PM -ModificationDate=01-20-2021 +ModificationTime=1:21PM +ModificationDate=06-26-2021 ModifiedBy= [DeviceInfo] @@ -160,7 +160,7 @@ SupportedObjects=30 ParameterName=Pre-defined error field ObjectType=0x8 ;StorageLocation=RAM -SubNumber=0x9 +SubNumber=0x11 [1003sub0] ParameterName=Number of errors @@ -168,7 +168,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0005 AccessType=rw -DefaultValue=0 +DefaultValue= PDOMapping=0 [1003sub1] @@ -177,7 +177,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x00000000 +DefaultValue= PDOMapping=0 [1003sub2] @@ -186,7 +186,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x00000000 +DefaultValue= PDOMapping=0 [1003sub3] @@ -195,7 +195,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x00000000 +DefaultValue= PDOMapping=0 [1003sub4] @@ -204,7 +204,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x00000000 +DefaultValue= PDOMapping=0 [1003sub5] @@ -213,7 +213,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x00000000 +DefaultValue= PDOMapping=0 [1003sub6] @@ -222,7 +222,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x00000000 +DefaultValue= PDOMapping=0 [1003sub7] @@ -231,7 +231,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x00000000 +DefaultValue= PDOMapping=0 [1003sub8] @@ -240,7 +240,79 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x00000000 +DefaultValue= +PDOMapping=0 + +[1003sub9] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1003subA] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1003subB] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1003subC] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1003subD] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1003subE] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1003subF] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1003sub10] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= PDOMapping=0 [1005] diff --git a/example/DS301_profile.md b/example/DS301_profile.md index df6ca40a..d8679705 100644 --- a/example/DS301_profile.md +++ b/example/DS301_profile.md @@ -8,12 +8,12 @@ CANopen device documentation | ------------ | ------------------------------ | | Project File | DS301_profile.xpd | | File Version | 1 | -| Created | 23. 11. 2020 12:00:00 | +| Created | 23. 11. 2020 13:00:00 | | Created By | | -| Modified | 20. 01. 2021 15:01:07 | +| Modified | 26. 06. 2021 13:21:06 | | Modified By | | -This file was automatically generated with [libedssharp](https://github.com/robincornelius/libedssharp) Object Dictionary Editor v0.8-114-gc3a898f +This file was automatically generated by [CANopenEditor](https://github.com/CANopenNode/CANopenEditor) v4.0-49-gd365995 [TOC] @@ -87,15 +87,23 @@ Communication Specific Parameters | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | -| 0x00 | Number of errors | UNSIGNED8 | rw | no | no | 0 | -| 0x01 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | -| 0x02 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | -| 0x03 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | -| 0x04 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | -| 0x05 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | -| 0x06 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | -| 0x07 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | -| 0x08 | Standard error field | UNSIGNED32 | ro | no | no | 0x00000000 | +| 0x00 | Number of errors | UNSIGNED8 | rw | no | no | | +| 0x01 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x02 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x03 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x04 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x05 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x06 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x07 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x08 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x09 | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x0A | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x0B | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x0C | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x0D | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x0E | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x0F | Standard error field | UNSIGNED32 | ro | no | no | | +| 0x10 | Standard error field | UNSIGNED32 | ro | no | no | | * Sub Index 0: Contains number of actual errors. 0 can be written to clear error history. * sub-index 1 and above: diff --git a/example/DS301_profile.xpd b/example/DS301_profile.xpd index 5e402278..690bc4b2 100644 --- a/example/DS301_profile.xpd +++ b/example/DS301_profile.xpd @@ -1,5 +1,5 @@ - + @@ -15,7 +15,7 @@ CANopen - + @@ -45,7 +45,7 @@ - + @@ -663,47 +663,70 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * bit 31: set to 0 @@ -2254,13 +2277,13 @@ CANopen - + - + @@ -2270,6 +2293,14 @@ + + + + + + + + diff --git a/example/OD.c b/example/OD.c index d8ec0d5a..f8fdfc39 100644 --- a/example/OD.c +++ b/example/OD.c @@ -1,11 +1,10 @@ /******************************************************************************* CANopen Object Dictionary definition for CANopenNode V4 - This file was automatically generated with - libedssharp Object Dictionary Editor v0.8-114-gc3a898f + This file was automatically generated by CANopenEditor v4.0-49-gd365995 https://github.com/CANopenNode/CANopenNode - https://github.com/robincornelius/libedssharp + https://github.com/CANopenNode/CANopenEditor DON'T EDIT THIS FILE MANUALLY, UNLESS YOU KNOW WHAT YOU ARE DOING !!!! *******************************************************************************/ @@ -21,7 +20,7 @@ /******************************************************************************* OD data initialization of all groups *******************************************************************************/ -OD_PERSIST_COMM_t OD_PERSIST_COMM = { +OD_ATTR_PERSIST_COMM OD_PERSIST_COMM_t OD_PERSIST_COMM = { .x1000_deviceType = 0x00000000, .x1005_COB_ID_SYNCMessage = 0x00000080, .x1006_communicationCyclePeriod = 0x00000000, @@ -192,10 +191,8 @@ OD_PERSIST_COMM_t OD_PERSIST_COMM = { } }; -OD_RAM_t OD_RAM = { +OD_ATTR_RAM OD_RAM_t OD_RAM = { .x1001_errorRegister = 0x00, - .x1003_pre_definedErrorField_sub0 = 0x00, - .x1003_pre_definedErrorField = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, .x1010_storeParameters_sub0 = 0x04, .x1010_storeParameters = {0x00000001, 0x00000001, 0x00000001, 0x00000001}, .x1011_restoreDefaultParameters_sub0 = 0x04, @@ -260,8 +257,8 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, .o_1003_pre_definedErrorField = { - .dataOrig0 = &OD_RAM.x1003_pre_definedErrorField_sub0, - .dataOrig = &OD_RAM.x1003_pre_definedErrorField[0], + .dataOrig0 = NULL, + .dataOrig = NULL, .attribute0 = ODA_SDO_RW, .attribute = ODA_SDO_R | ODA_MB, .dataElementLength = 4, @@ -1119,10 +1116,10 @@ static CO_PROGMEM ODObjs_t ODObjs = { /******************************************************************************* Object dictionary *******************************************************************************/ -static OD_entry_t ODList[] = { +static OD_ATTR_OD OD_entry_t ODList[] = { {0x1000, 0x01, ODT_VAR, &ODObjs.o_1000_deviceType, NULL}, {0x1001, 0x01, ODT_VAR, &ODObjs.o_1001_errorRegister, NULL}, - {0x1003, 0x09, ODT_ARR, &ODObjs.o_1003_pre_definedErrorField, NULL}, + {0x1003, 0x11, ODT_ARR, &ODObjs.o_1003_pre_definedErrorField, NULL}, {0x1005, 0x01, ODT_VAR, &ODObjs.o_1005_COB_ID_SYNCMessage, NULL}, {0x1006, 0x01, ODT_VAR, &ODObjs.o_1006_communicationCyclePeriod, NULL}, {0x1007, 0x01, ODT_VAR, &ODObjs.o_1007_synchronousWindowLength, NULL}, diff --git a/example/OD.h b/example/OD.h index b50db42e..30dbaf1f 100644 --- a/example/OD.h +++ b/example/OD.h @@ -1,11 +1,10 @@ /******************************************************************************* CANopen Object Dictionary definition for CANopenNode V4 - This file was automatically generated with - libedssharp Object Dictionary Editor v0.8-114-gc3a898f + This file was automatically generated by CANopenEditor v4.0-49-gd365995 https://github.com/CANopenNode/CANopenNode - https://github.com/robincornelius/libedssharp + https://github.com/CANopenNode/CANopenEditor DON'T EDIT THIS FILE MANUALLY !!!! ******************************************************************************** @@ -15,9 +14,9 @@ Project File: DS301_profile.xpd File Version: 1 - Created: 23. 11. 2020 12:00:00 + Created: 23. 11. 2020 13:00:00 Created By: - Modified: 20. 01. 2021 15:01:07 + Modified: 26. 06. 2021 13:21:06 Modified By: Device Info: @@ -49,6 +48,15 @@ #define OD_CNT_TPDO 4 +/******************************************************************************* + Sizes of OD arrays +*******************************************************************************/ +#define OD_CNT_ARR_1003 16 +#define OD_CNT_ARR_1010 4 +#define OD_CNT_ARR_1011 4 +#define OD_CNT_ARR_1016 8 + + /******************************************************************************* OD data declaration of all groups *******************************************************************************/ @@ -61,7 +69,7 @@ typedef struct { uint32_t x1014_COB_ID_EMCY; uint16_t x1015_inhibitTimeEMCY; uint8_t x1016_consumerHeartbeatTime_sub0; - uint32_t x1016_consumerHeartbeatTime[8]; + uint32_t x1016_consumerHeartbeatTime[OD_CNT_ARR_1016]; uint16_t x1017_producerHeartbeatTime; struct { uint8_t highestSub_indexSupported; @@ -225,12 +233,10 @@ typedef struct { typedef struct { uint8_t x1001_errorRegister; - uint8_t x1003_pre_definedErrorField_sub0; - uint32_t x1003_pre_definedErrorField[8]; uint8_t x1010_storeParameters_sub0; - uint32_t x1010_storeParameters[4]; + uint32_t x1010_storeParameters[OD_CNT_ARR_1010]; uint8_t x1011_restoreDefaultParameters_sub0; - uint32_t x1011_restoreDefaultParameters[4]; + uint32_t x1011_restoreDefaultParameters[OD_CNT_ARR_1011]; struct { uint8_t highestSub_indexSupported; uint32_t COB_IDClientToServerRx; @@ -238,9 +244,20 @@ typedef struct { } x1200_SDOServerParameter; } OD_RAM_t; -extern OD_PERSIST_COMM_t OD_PERSIST_COMM; -extern OD_RAM_t OD_RAM; -extern OD_t *OD; +#ifndef OD_ATTR_PERSIST_COMM +#define OD_ATTR_PERSIST_COMM +#endif +extern OD_ATTR_PERSIST_COMM OD_PERSIST_COMM_t OD_PERSIST_COMM; + +#ifndef OD_ATTR_RAM +#define OD_ATTR_RAM +#endif +extern OD_ATTR_RAM OD_RAM_t OD_RAM; + +#ifndef OD_ATTR_OD +#define OD_ATTR_OD +#endif +extern OD_ATTR_OD OD_t *OD; /******************************************************************************* @@ -318,4 +335,53 @@ extern OD_t *OD; #define OD_ENTRY_H1A02_TPDOMappingParameter &OD->list[31] #define OD_ENTRY_H1A03_TPDOMappingParameter &OD->list[32] + +/******************************************************************************* + OD config structure +*******************************************************************************/ +#ifdef CO_MULTIPLE_OD +#define OD_INIT_CONFIG(config) {\ + (config).CNT_NMT = OD_CNT_NMT;\ + (config).ENTRY_H1017 = OD_ENTRY_H1017;\ + (config).CNT_HB_CONS = OD_CNT_HB_CONS;\ + (config).CNT_ARR_1016 = OD_CNT_ARR_1016;\ + (config).ENTRY_H1016 = OD_ENTRY_H1016;\ + (config).CNT_EM = OD_CNT_EM;\ + (config).ENTRY_H1001 = OD_ENTRY_H1001;\ + (config).ENTRY_H1014 = OD_ENTRY_H1014;\ + (config).ENTRY_H1015 = OD_ENTRY_H1015;\ + (config).CNT_ARR_1003 = OD_CNT_ARR_1003;\ + (config).ENTRY_H1003 = OD_ENTRY_H1003;\ + (config).CNT_SDO_SRV = OD_CNT_SDO_SRV;\ + (config).ENTRY_H1200 = OD_ENTRY_H1200;\ + (config).CNT_SDO_CLI = OD_CNT_SDO_CLI;\ + (config).ENTRY_H1280 = OD_ENTRY_H1280;\ + (config).CNT_TIME = OD_CNT_TIME;\ + (config).ENTRY_H1012 = OD_ENTRY_H1012;\ + (config).CNT_SYNC = OD_CNT_SYNC;\ + (config).ENTRY_H1005 = OD_ENTRY_H1005;\ + (config).ENTRY_H1006 = OD_ENTRY_H1006;\ + (config).ENTRY_H1007 = OD_ENTRY_H1007;\ + (config).ENTRY_H1019 = OD_ENTRY_H1019;\ + (config).CNT_RPDO = OD_CNT_RPDO;\ + (config).ENTRY_H1400 = OD_ENTRY_H1400;\ + (config).ENTRY_H1600 = OD_ENTRY_H1600;\ + (config).CNT_TPDO = OD_CNT_TPDO;\ + (config).ENTRY_H1800 = OD_ENTRY_H1800;\ + (config).ENTRY_H1A00 = OD_ENTRY_H1A00;\ + (config).CNT_LEDS = 0;\ + (config).CNT_GFC = 0;\ + (config).ENTRY_H1300 = NULL;\ + (config).CNT_SRDO = 0;\ + (config).ENTRY_H1301 = NULL;\ + (config).ENTRY_H1381 = NULL;\ + (config).ENTRY_H13FE = NULL;\ + (config).ENTRY_H13FF = NULL;\ + (config).CNT_LSS_SLV = 0;\ + (config).CNT_LSS_MST = 0;\ + (config).CNT_GTWA = 0;\ + (config).CNT_TRACE = 0;\ +} +#endif + #endif /* OD_H */ From b8b9011f7f8ac4ecfc833055235c2534dd548e52 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 26 Jun 2021 13:53:49 +0200 Subject: [PATCH 191/520] Remove CO_CONFIG_HB_CONS_SIZE macro, size is fetched from Object Dictionary It is necessary to re-generate OD.h file with the latest CANopenEditor from https://github.com/CANopenNode/CANopenEditor --- 301/CO_HBconsumer.c | 15 +++++++-------- 301/CO_HBconsumer.h | 18 ++++++++++-------- 301/CO_config.h | 12 ------------ CANopen.c | 17 +++++++++++++++-- CANopen.h | 8 +++++--- 5 files changed, 37 insertions(+), 33 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 17a5830f..456162b7 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -33,10 +33,6 @@ #error CO_CONFIG_HB_CONS_CALLBACK_CHANGE and CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously! #endif -#if CO_CONFIG_HB_CONS_SIZE < 1 || CO_CONFIG_HB_CONS_SIZE > 127 -#error CO_CONFIG_HB_CONS_SIZE is not correct -#endif - /* * Read received message from CAN module. * @@ -118,6 +114,8 @@ static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, /******************************************************************************/ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, CO_EM_t *em, + CO_HBconsNode_t *monitoredNodes, + uint8_t monitoredNodesCount, OD_entry_t *OD_1016_HBcons, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdxStart, @@ -126,8 +124,8 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, ODR_t odRet; /* verify arguments */ - if (HBcons == NULL || em == NULL || OD_1016_HBcons == NULL - || CANdevRx == NULL + if (HBcons == NULL || em == NULL || monitoredNodes == NULL + || OD_1016_HBcons == NULL || CANdevRx == NULL ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -135,13 +133,14 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, /* Configure object variables */ memset(HBcons, 0, sizeof(CO_HBconsumer_t)); HBcons->em = em; + HBcons->monitoredNodes = monitoredNodes; HBcons->CANdevRx = CANdevRx; HBcons->CANdevRxIdxStart = CANdevRxIdxStart; /* get actual number of monitored nodes */ HBcons->numberOfMonitoredNodes = - OD_1016_HBcons->subEntriesCount-1 < CO_CONFIG_HB_CONS_SIZE ? - OD_1016_HBcons->subEntriesCount-1 : CO_CONFIG_HB_CONS_SIZE; + OD_1016_HBcons->subEntriesCount-1 < monitoredNodesCount ? + OD_1016_HBcons->subEntriesCount-1 : monitoredNodesCount; for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { uint32_t val; diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 4409760e..1ee1346a 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -38,9 +38,6 @@ CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#ifndef CO_CONFIG_HB_CONS_SIZE -#define CO_CONFIG_HB_CONS_SIZE 8 -#endif #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN @@ -142,10 +139,10 @@ typedef struct { typedef struct { /** From CO_HBconsumer_init() */ CO_EM_t *em; - /** Array of monitored nodes, maximum size CO_CONFIG_HB_CONS_SIZE */ - CO_HBconsNode_t monitoredNodes[CO_CONFIG_HB_CONS_SIZE]; - /** Actual number of monitored nodes, - * MIN(CO_CONFIG_HB_CONS_SIZE or number-of-array-elements-in-OD-0x1016) */ + /** Array of monitored nodes, from CO_HBconsumer_init() */ + CO_HBconsNode_t *monitoredNodes; + /** Actual number of monitored nodes, size-of-the-above-array or + * number-of-array-elements-in-OD-0x1016, whichever is smaller. */ uint8_t numberOfMonitoredNodes; /** True, if all monitored nodes are active or no node is monitored. Can be * read by the application */ @@ -182,17 +179,22 @@ typedef struct { * * @param HBcons This object will be initialized. * @param em Emergency object. + * @param monitoredNodes Array of monitored nodes, must be defined externally. + * @param monitoredNodesCount Size of the above array, usually equal to number + * of array elements in OD 0x1016, valid values are 1 to 127 * @param OD_1016_HBcons OD entry for 0x1016 - "Consumer heartbeat time", entry * is required, IO extension will be applied. * @param CANdevRx CAN device for Heartbeat reception. * @param CANdevRxIdxStart Starting index of receive buffer in the above CAN - * device. Number of used indexes is equal to CO_CONFIG_HB_CONS_SIZE. + * device. Number of used indexes is equal to monitoredNodesCount. * @param [out] errInfo Additional information in case of error, may be NULL. * * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, CO_EM_t *em, + CO_HBconsNode_t *monitoredNodes, + uint8_t monitoredNodesCount, OD_entry_t *OD_1016_HBcons, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdxStart, diff --git a/301/CO_config.h b/301/CO_config.h index 56d75cba..8e232506 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -183,18 +183,6 @@ extern "C" { #define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x02 #define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x04 #define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x08 - -/** - * Number of heartbeat consumer objects, where each object corresponds to one - * sub-index in OD object 0x1016, "Consumer heartbeat time". Each heartbeat - * consumer uses own CANrx object. Actual number of heartbeat consumer objects - * may be lower, if OD variable 1016 has lower number of sub entries. - * - * If heartbeat consumer is enabled, then valid values are 1 to 127. - */ -#ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS_SIZE 8 -#endif /** @} */ /* CO_STACK_CONFIG_NMT_HB */ diff --git a/CANopen.c b/CANopen.c index 30868f1b..4dcdd8e2 100644 --- a/CANopen.c +++ b/CANopen.c @@ -64,7 +64,10 @@ #error OD_CNT_HB_CONS from OD.h not correct! #endif #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) && OD_CNT_HB_CONS == 1 - #define CO_RX_CNT_HB_CONS CO_CONFIG_HB_CONS_SIZE + #if OD_CNT_ARR_1016 < 1 || OD_CNT_ARR_1016 > 127 + #error OD_CNT_ARR_1016 is not defined in Object Dictionary or value is wrong! + #endif + #define CO_RX_CNT_HB_CONS OD_CNT_ARR_1016 #else #define CO_RX_CNT_HB_CONS 0 #endif @@ -353,11 +356,16 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE ON_MULTI_OD(uint8_t RX_CNT_HB_CONS = 0); if (CO_GET_CNT(HB_CONS) == 1) { + uint8_t countOfMonitoredNodes = CO_GET_CNT(ARR_1016); p = calloc(1, sizeof(CO_HBconsumer_t)); if (p == NULL) break; else co->HBcons = (CO_HBconsumer_t *)p; mem += sizeof(CO_HBconsumer_t); - ON_MULTI_OD(RX_CNT_HB_CONS = CO_CONFIG_HB_CONS_SIZE); + p = calloc(countOfMonitoredNodes, sizeof(CO_HBconsNode_t)); + if (p == NULL) break; + else co->HBconsMonitoredNodes = (CO_HBconsNode_t *)p; + mem += countOfMonitoredNodes * sizeof(CO_HBconsNode_t); + ON_MULTI_OD(RX_CNT_HB_CONS = countOfMonitoredNodes); } #endif @@ -700,6 +708,7 @@ void CO_delete(CO_t *co) { free(co->em); #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE + free(co->HBconsMonitoredNodes); free(co->HBcons); #endif @@ -724,6 +733,7 @@ void CO_delete(CO_t *co) { static CO_NMT_t COO_NMT; #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE static CO_HBconsumer_t COO_HBcons; + static CO_HBconsNode_t COO_HBconsMonitoredNodes[OD_CNT_ARR_1016]; #endif static CO_EM_t COO_EM; static CO_SDOserver_t COO_SDOserver[OD_CNT_SDO_SRV]; @@ -782,6 +792,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { co->NMT = &COO_NMT; #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE co->HBcons = &COO_HBcons; + co->HBconsMonitoredNodes = &COO_HBconsMonitoredNodes[0]; #endif co->em = &COO_EM; co->SDOserver = &COO_SDOserver[0]; @@ -1010,6 +1021,8 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, if (CO_GET_CNT(HB_CONS) == 1) { err = CO_HBconsumer_init(co->HBcons, em, + co->HBconsMonitoredNodes, + CO_GET_CNT(ARR_1016), OD_GET(H1016, OD_H1016_CONSUMER_HB_TIME), co->CANmodule, CO_GET_CO(RX_IDX_HB_CONS), diff --git a/CANopen.h b/CANopen.h index 0fe3434d..c392f571 100644 --- a/CANopen.h +++ b/CANopen.h @@ -201,10 +201,11 @@ typedef struct { * There must be one NMT object in the device. */ uint8_t CNT_NMT; OD_entry_t *ENTRY_H1017; /**< OD entry for @ref CO_NMT_init() */ - /** Number of Heartbeat consumer objects, 0 or 1: object uses from 1 to 127 - * internal consumers (CANrx), as specified by @ref CO_CONFIG_HB_CONS_SIZE. - */ + /** Number of Heartbeat consumer objects, 0 or 1 */ uint8_t CNT_HB_CONS; + /** Number of internal consumers (CANrx), used inside Heartbeat consumer + * object, 1 to 127. */ + uint8_t CNT_ARR_1016; OD_entry_t *ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init()*/ /** Number of Emergency objects, 0 or 1: optional producer (CANtx) + * optional consumer (CANrx), configurable by @ref CO_CONFIG_EM. @@ -291,6 +292,7 @@ typedef struct { #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN /** Heartbeat consumer object, initialised by @ref CO_HBconsumer_init() */ CO_HBconsumer_t *HBcons; + CO_HBconsNode_t *HBconsMonitoredNodes; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_HB_CONS; /**< Start index in CANrx. */ #endif From b9927ff1cdc03077ad5b371b19f4335950e13657 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 28 Jun 2021 12:39:03 +0200 Subject: [PATCH 192/520] Remove CO_CONFIG_EM_BUFFER_SIZE macro, size is fetched from Object Dictionary It is necessary to re-generate OD.h file with the latest CANopenEditor from https://github.com/CANopenNode/CANopenEditor --- 301/CO_Emergency.c | 168 +++++++++++++++++++++++++-------------------- 301/CO_Emergency.h | 42 +++++++++--- 301/CO_config.h | 14 ---- CANopen.c | 28 ++++++++ CANopen.h | 12 ++++ 5 files changed, 165 insertions(+), 99 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index b70a718f..6f68be9f 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -34,11 +34,7 @@ #error CO_CONFIG_EM_ERR_STATUS_BITS_COUNT is not correct #endif -#if CO_CONFIG_EM_BUFFER_SIZE < 1 || CO_CONFIG_EM_BUFFER_SIZE > 254 - #error CO_CONFIG_EM_BUFFER_SIZE is not correct -#endif - -/* fifo buffer example for CO_CONFIG_EM_BUFFER_SIZE = 6 (em->fifo size = 6+1) * +/* fifo buffer example for fifoSize = 7 (actual capacity = 6) * * * * 0 * * * * * * 1 pp==wp fifoPpPtr fifoWrPtr * * @@ -194,6 +190,9 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; + if (em->fifoSize < 2) { + return ODR_DEV_INCOMPAT; + } if (stream->subIndex == 0) { CO_setUint8(buf, em->fifoCount); @@ -205,12 +204,12 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, * fifoWrPtr. Get correct index in FIFO buffer. */ int16_t index = (int16_t)em->fifoWrPtr - stream->subIndex; if (index < 0) { - index += CO_CONFIG_EM_BUFFER_SIZE + 1; + index += em->fifoSize; } - else if (index >= (CO_CONFIG_EM_BUFFER_SIZE + 1)) { + else if (index >= (em->fifoSize)) { return ODR_DEV_INCOMPAT; } - CO_setUint32(buf, em->fifo[index][0]); + CO_setUint32(buf, em->fifo[index].msg); *countRead = sizeof(uint32_t); return ODR_OK; @@ -345,12 +344,16 @@ static void CO_EM_receive(void *object, void *msg) { CO_ReturnError_t CO_EM_init(CO_EM_t *em, CO_CANmodule_t *CANdevTx, const OD_entry_t *OD_1001_errReg, +#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + CO_EM_fifo_t *fifo, + uint8_t fifoSize, +#endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER OD_entry_t *OD_1014_cobIdEm, uint16_t CANdevTxIdx, -#if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT OD_entry_t *OD_1015_InhTime, -#endif + #endif #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY OD_entry_t *OD_1003_preDefErr, @@ -371,6 +374,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* verify arguments */ if (em == NULL || OD_1001_errReg == NULL +#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + || (fifo == NULL && fifoSize >= 2) +#endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER || OD_1014_cobIdEm == NULL || CANdevTx == NULL || nodeId < 1 || nodeId > 127 @@ -399,6 +405,10 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, } *em->errorRegister = 0; +#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + em->fifo = fifo; + em->fifoSize = fifoSize; +#endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER /* get initial and verify "COB-ID EMCY" from Object Dictionary */ uint32_t COB_IDEmergency32; @@ -616,77 +626,83 @@ void CO_EM_process(CO_EM_t *em, /* post-process Emergency message in fifo buffer. */ #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER - uint8_t fifoPpPtr = em->fifoPpPtr; + if (em->fifoSize >= 2) { + uint8_t fifoPpPtr = em->fifoPpPtr; #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT - if (em->inhibitEmTimer < em->inhibitEmTime_us) { - em->inhibitEmTimer += timeDifference_us; - } + if (em->inhibitEmTimer < em->inhibitEmTime_us) { + em->inhibitEmTimer += timeDifference_us; + } - if (fifoPpPtr != em->fifoWrPtr && !em->CANtxBuff->bufferFull - && em->inhibitEmTimer >= em->inhibitEmTime_us - ) { - em->inhibitEmTimer = 0; + if (fifoPpPtr != em->fifoWrPtr && !em->CANtxBuff->bufferFull + && em->inhibitEmTimer >= em->inhibitEmTime_us + ) { + em->inhibitEmTimer = 0; #else - if (fifoPpPtr != em->fifoWrPtr && !em->CANtxBuff->bufferFull) { + if (fifoPpPtr != em->fifoWrPtr && !em->CANtxBuff->bufferFull) { #endif - /* add error register to emergency message */ - em->fifo[fifoPpPtr][0] |= (uint32_t) errorRegister << 16; + /* add error register to emergency message */ + em->fifo[fifoPpPtr].msg |= (uint32_t) errorRegister << 16; - /* send emergency message */ - memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr][0], - sizeof(em->CANtxBuff->data)); - CO_CANsend(em->CANdevTx, em->CANtxBuff); + /* send emergency message */ + memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr].msg, + sizeof(em->CANtxBuff->data)); + CO_CANsend(em->CANdevTx, em->CANtxBuff); #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER - /* report also own emergency messages */ - if (em->pFunctSignalRx != NULL) { - uint32_t errMsg = em->fifo[fifoPpPtr][0]; - em->pFunctSignalRx(0, - CO_SWAP_16((uint16_t) errMsg), - errorRegister, - (uint8_t) (errMsg >> 24), - CO_SWAP_32(em->fifo[fifoPpPtr][1])); - } + /* report also own emergency messages */ + if (em->pFunctSignalRx != NULL) { + uint32_t errMsg = em->fifo[fifoPpPtr].msg; + em->pFunctSignalRx(0, + CO_SWAP_16((uint16_t) errMsg), + errorRegister, + (uint8_t) (errMsg >> 24), + CO_SWAP_32(em->fifo[fifoPpPtr].info)); + } #endif - /* increment pointer */ - em->fifoPpPtr = (++fifoPpPtr < (CO_CONFIG_EM_BUFFER_SIZE + 1)) ? - fifoPpPtr : 0; - - /* verify message buffer overflow. Clear error condition if all messages - * from fifo buffer are processed */ - if (em->fifoOverflow == 1) { - em->fifoOverflow = 2; - CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, CO_EMC_GENERIC, 0); - } - else if (em->fifoOverflow == 2 && em->fifoPpPtr == em->fifoWrPtr) { - em->fifoOverflow = 0; - CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); + /* increment pointer */ + em->fifoPpPtr = (++fifoPpPtr < em->fifoSize) ? fifoPpPtr : 0; + + /* verify message buffer overflow. Clear error condition if all + * messages from fifo buffer are processed */ + if (em->fifoOverflow == 1) { + em->fifoOverflow = 2; + CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, + CO_EMC_GENERIC, 0); + } + else if (em->fifoOverflow == 2 && em->fifoPpPtr == em->fifoWrPtr) { + em->fifoOverflow = 0; + CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); + } } - } #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT - else if (timerNext_us != NULL && em->inhibitEmTimer < em->inhibitEmTime_us){ - /* check again after inhibit time elapsed */ - uint32_t diff = em->inhibitEmTime_us - em->inhibitEmTimer; - if (*timerNext_us > diff) { - *timerNext_us = diff; + else if (timerNext_us != NULL + && em->inhibitEmTimer < em->inhibitEmTime_us) + { + /* check again after inhibit time elapsed */ + uint32_t diff = em->inhibitEmTime_us - em->inhibitEmTimer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } } - } #endif #endif + } #elif (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY - uint8_t fifoPpPtr = em->fifoPpPtr; - while (fifoPpPtr != em->fifoWrPtr) { - /* add error register to emergency message and increment pointers */ - em->fifo[fifoPpPtr][0] |= (uint32_t) errorRegister << 16; - - if (++fifoPpPtr >= (CO_CONFIG_EM_BUFFER_SIZE + 1)) { - fifoPpPtr = 0; + if (em->fifoSize >= 2) { + uint8_t fifoPpPtr = em->fifoPpPtr; + while (fifoPpPtr != em->fifoWrPtr) { + /* add error register to emergency message and increment pointers */ + em->fifo[fifoPpPtr].msg |= (uint32_t) errorRegister << 16; + + if (++fifoPpPtr >= em->fifoSize) { + fifoPpPtr = 0; + } } + em->fifoPpPtr = fifoPpPtr; } - em->fifoPpPtr = fifoPpPtr; #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER, #elif CO_CONFIG_EM_HISTORY */ return; @@ -741,22 +757,24 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, else *errorStatusBits &= ~bitmask; #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) - uint8_t fifoWrPtr = em->fifoWrPtr; - uint8_t fifoWrPtrNext = fifoWrPtr + 1; - if (fifoWrPtrNext >= (CO_CONFIG_EM_BUFFER_SIZE + 1)) { - fifoWrPtrNext = 0; - } + if (em->fifoSize >= 2) { + uint8_t fifoWrPtr = em->fifoWrPtr; + uint8_t fifoWrPtrNext = fifoWrPtr + 1; + if (fifoWrPtrNext >= em->fifoSize) { + fifoWrPtrNext = 0; + } - if (fifoWrPtrNext == em->fifoPpPtr) { - em->fifoOverflow = 1; - } - else { - em->fifo[fifoWrPtr][0] = errMsg; + if (fifoWrPtrNext == em->fifoPpPtr) { + em->fifoOverflow = 1; + } + else { + em->fifo[fifoWrPtr].msg = errMsg; #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER - em->fifo[fifoWrPtr][1] = infoCodeSwapped; + em->fifo[fifoWrPtr].info = infoCodeSwapped; #endif - em->fifoWrPtr = fifoWrPtrNext; - if (em->fifoCount < CO_CONFIG_EM_BUFFER_SIZE) em->fifoCount++; + em->fifoWrPtr = fifoWrPtrNext; + if (em->fifoCount < (em->fifoSize - 1)) em->fifoCount++; + } } #endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 3015402b..cfa4c7e9 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -39,9 +39,6 @@ #ifndef CO_CONFIG_EM_ERR_STATUS_BITS_COUNT #define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) #endif -#ifndef CO_CONFIG_EM_BUFFER_SIZE -#define CO_CONFIG_EM_BUFFER_SIZE 16 -#endif #ifndef CO_CONFIG_ERR_CONDITION_GENERIC #define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0) #endif @@ -362,6 +359,21 @@ typedef enum { } CO_EM_errorStatusBits_t; + +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ + || defined CO_DOXYGEN +/** + * Fifo buffer for emergency producer and error history + */ +typedef struct { + uint32_t msg; +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN + uint32_t info; +#endif +} CO_EM_fifo_t; +#endif + + /** * Emergency object. */ @@ -379,13 +391,13 @@ typedef struct { || defined CO_DOXYGEN /** Internal circular FIFO buffer for storing pre-processed emergency * messages. Messages are added by @ref CO_error() function. All messages - * are later post-processed by @ref CO_EM_process() function. Fifo is also - * used for error history - OD object 0x1003, "Pre-defined error field". */ - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN - uint32_t fifo[CO_CONFIG_EM_BUFFER_SIZE + 1][2]; - #else - uint32_t fifo[CO_CONFIG_EM_BUFFER_SIZE + 1][1]; - #endif + * are later post-processed by @ref CO_EM_process() function. In case of + * overflow, error is indicated but emergency message is not sent. Fifo is + * also used for error history, OD object 0x1003, "Pre-defined error field". + * Buffer is defined by @ref CO_EM_init(). */ + CO_EM_fifo_t *fifo; + /** Size of the above buffer, specified by @ref CO_EM_init(). */ + uint8_t fifoSize; /** Pointer for the fifo buffer, where next emergency message will be * written by @ref CO_error() function. */ uint8_t fifoWrPtr; @@ -458,6 +470,11 @@ typedef struct { * Function must be called in the communication reset section. * * @param em This object will be initialized. + * @param fifo Fifo buffer for emergency producer and error history. It must be + * defined externally. Its size must be capacity+1. See also @ref CO_EM_t, fifo. + * @param fifoSize Size of the above fifo buffer. It is usually equal to the + * length of the OD array 0x1003 + 1. If fifoSize is smaller than 2, then + * emergency producer and error history will not work and 'fifo' may be NULL. * @param CANdevTx CAN device for Emergency transmission. * @param OD_1001_errReg OD entry for 0x1001 - "Error register", entry is * required, without IO extension. @@ -484,6 +501,11 @@ typedef struct { CO_ReturnError_t CO_EM_init(CO_EM_t *em, CO_CANmodule_t *CANdevTx, const OD_entry_t *OD_1001_errReg, +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ + || defined CO_DOXYGEN + CO_EM_fifo_t *fifo, + uint8_t fifoSize, +#endif #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN OD_entry_t *OD_1014_cobIdEm, uint16_t CANdevTxIdx, diff --git a/301/CO_config.h b/301/CO_config.h index 8e232506..a8093258 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -232,20 +232,6 @@ extern "C" { #define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) #endif -/** - * Size of the internal buffer, where emergencies are stored after error - * indication with @ref CO_error() function. Each emergency has to be post- - * processed by the @ref CO_EM_process() function. In case of overflow, error is - * indicated but emergency message is not sent. - * - * The same buffer is also used for OD object 0x1003, "Pre-defined error field". - * - * Each buffer element consumes 8 bytes. Valid values are 1 to 254. - */ -#ifdef CO_DOXYGEN -#define CO_CONFIG_EM_BUFFER_SIZE 16 -#endif - /** * Condition for calculating CANopen Error register, "generic" error bit. * diff --git a/CANopen.c b/CANopen.c index 4dcdd8e2..b4e8991a 100644 --- a/CANopen.c +++ b/CANopen.c @@ -78,6 +78,9 @@ #ifndef OD_ENTRY_H1003 #define OD_ENTRY_H1003 NULL #endif +#ifndef OD_CNT_ARR_1003 + #define OD_CNT_ARR_1003 8 +#endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER #if OD_CNT_EM_PROD == 1 #define CO_TX_CNT_EM_PROD OD_CNT_EM_PROD @@ -382,6 +385,18 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER ON_MULTI_OD(TX_CNT_EM_PROD = 1); + #endif + #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + uint8_t fifoSize = CO_GET_CNT(ARR_1003) + 1; + if (fifoSize >= 2) { + p = calloc(fifoSize, sizeof(CO_EM_fifo_t)); + if (p == NULL) break; + else co->em_fifo = (CO_EM_fifo_t *)p; + mem += fifoSize * sizeof(CO_EM_fifo_t); + } + else { + co->em_fifo = NULL; + } #endif } @@ -706,6 +721,9 @@ void CO_delete(CO_t *co) { /* Emergency */ free(co->em); +#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + free(co->em_fifo); +#endif #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE free(co->HBconsMonitoredNodes); @@ -736,6 +754,9 @@ void CO_delete(CO_t *co) { static CO_HBconsNode_t COO_HBconsMonitoredNodes[OD_CNT_ARR_1016]; #endif static CO_EM_t COO_EM; +#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + static CO_EM_fifo_t COO_EM_FIFO[CO_GET_CNT(ARR_1003) + 1]; +#endif static CO_SDOserver_t COO_SDOserver[OD_CNT_SDO_SRV]; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE static CO_SDOclient_t COO_SDOclient[OD_CNT_SDO_CLI]; @@ -795,6 +816,9 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { co->HBconsMonitoredNodes = &COO_HBconsMonitoredNodes[0]; #endif co->em = &COO_EM; +#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + co->em_fifo = &COO_EM_FIFO[0]; +#endif co->SDOserver = &COO_SDOserver[0]; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE co->SDOclient = &COO_SDOclient[0]; @@ -972,6 +996,10 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, err = CO_EM_init(co->em, co->CANmodule, OD_GET(H1001, OD_H1001_ERR_REG), + #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + co->em_fifo, + (CO_GET_CNT(ARR_1003) + 1), + #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER OD_GET(H1014, OD_H1014_COBID_EMERGENCY), CO_GET_CO(TX_IDX_EM_PROD), diff --git a/CANopen.h b/CANopen.h index c392f571..de03169e 100644 --- a/CANopen.h +++ b/CANopen.h @@ -214,6 +214,12 @@ typedef struct { const OD_entry_t *ENTRY_H1001; /**< OD entry for @ref CO_EM_init() */ OD_entry_t *ENTRY_H1014; /**< OD entry for @ref CO_EM_init() */ OD_entry_t *ENTRY_H1015; /**< OD entry for @ref CO_EM_init() */ + /** Size of the fifo buffer, which is used for intermediate storage of + * emergency messages. Fifo is used by emergency producer and by error + * history (OD object 0x1003). Size is usually equal to size of array in + * OD object 0x1003. If later is not used, CNT_ARR_1003 must also be set to + * value greater than 0, or emergency producer will not work. */ + uint8_t CNT_ARR_1003; OD_entry_t *ENTRY_H1003; /**< OD entry for @ref CO_EM_init() */ /** Number of SDO server objects, from 0 to 128 (CANrx + CANtx). There must * be at least one SDO server object in the device. */ @@ -292,6 +298,7 @@ typedef struct { #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN /** Heartbeat consumer object, initialised by @ref CO_HBconsumer_init() */ CO_HBconsumer_t *HBcons; + /** Object for monitored nodes, initialised by @ref CO_HBconsumer_init() */ CO_HBconsNode_t *HBconsMonitoredNodes; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_HB_CONS; /**< Start index in CANrx. */ @@ -303,6 +310,11 @@ typedef struct { uint16_t RX_IDX_EM_CONS; /**< Start index in CANrx. */ uint16_t TX_IDX_EM_PROD; /**< Start index in CANtx. */ #endif +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ + || defined CO_DOXYGEN + /** FIFO for emergency object, initialised by @ref CO_EM_init() */ + CO_EM_fifo_t *em_fifo; +#endif /** SDO server objects, initialised by @ref CO_SDOserver_init() */ CO_SDOserver_t *SDOserver; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN From 598a2bb25f2bddf070f5b545de1325e4b3456bf3 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 28 Jun 2021 13:52:18 +0200 Subject: [PATCH 193/520] Update documentation and Doxyfile --- Doxyfile | 192 +++++++++++++++++++++++++++++++++-------------- README.md | 6 +- doc/CHANGELOG.md | 8 +- 3 files changed, 140 insertions(+), 66 deletions(-) diff --git a/Doxyfile b/Doxyfile index acaab7ed..07892a8a 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.18 +# Doxyfile 1.9.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -227,6 +227,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -315,7 +323,10 @@ OPTIMIZE_OUTPUT_SLICE = NO # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = @@ -449,6 +460,19 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which efficively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -512,6 +536,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -549,11 +580,18 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# (including Cygwin) ands Mac users are advised to set this option to NO. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. # The default value is: system dependent. CASE_SENSE_NAMES = YES @@ -792,7 +830,10 @@ WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO @@ -838,8 +879,8 @@ INPUT = README.md \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: https://www.gnu.org/software/libiconv/) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 @@ -852,13 +893,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen -# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, -# *.vhdl, *.ucf, *.qsf and *.ice. +# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, +# *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -1119,16 +1162,22 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO +# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to +# YES then doxygen will add the directory of each input to the include path. +# The default value is: YES. + +CLANG_ADD_INC_PATHS = YES + # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories @@ -1138,10 +1187,13 @@ CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = # If clang assisted parsing is enabled you can provide the clang parser with the -# path to the compilation database (see: -# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files -# were built. This is equivalent to specifying the "-p" option to a clang tool, -# such as clang-check. These options will then be passed to the parser. +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. @@ -1158,13 +1210,6 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored @@ -1335,10 +1380,11 @@ HTML_INDEX_NUM_ENTRIES = 35 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: https://developer.apple.com/xcode/), introduced with OSX -# 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. @@ -1380,8 +1426,8 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# (see: +# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1411,7 +1457,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1456,7 +1502,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1464,8 +1511,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1473,16 +1520,16 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = @@ -1494,9 +1541,9 @@ QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1577,8 +1624,8 @@ EXT_LINKS_IN_WINDOW = NO # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for # the HTML output. These images will generally look nicer at scaled resolutions. -# Possible values are: png The default and svg Looks nicer but requires the -# pdf2svg tool. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). # The default value is: png. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1623,7 +1670,7 @@ USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1653,7 +1700,8 @@ MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1700,7 +1748,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1713,8 +1762,9 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1878,9 +1928,11 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -2391,10 +2443,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2586,9 +2660,11 @@ DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc and +# plantuml temporary files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES diff --git a/README.md b/README.md index 40066064..3203a758 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Related projects - [CANopenNode](https://github.com/CANopenNode/CANopenNode) (this project): CANopen protocol stack, base for CANopen device. It contains no device specific code (drivers), which must be added separately for each target system. An example shows the basic principles, compiles on any system, but does not connect to any CAN hardware. - [CANopenDemo](https://github.com/CANopenNode/CANopenDemo): Demo device with CANopenNode and different target systems, tutorial and testing tools. - [CANopenNode.github.io](https://github.com/CANopenNode/CANopenNode.github.io): Html documentation, compiled by doxygen, for CANopenDemo, CANopenNode and other devices, available also online: https://canopennode.github.io - - [libedssharp](https://github.com/robincornelius/libedssharp): Object Dictionary editor, external GUI tool for editing CANopen Object Dictionary for custom device. It generates C source code, electronic data sheet and documentation for the device. + - [CANopenEditor](https://github.com/CANopenNode/CANopenEditor): Object Dictionary editor, external GUI tool for editing CANopen Object Dictionary for custom device. It generates C source code, electronic data sheet and documentation for the device. It is a fork from [libedssharp](https://github.com/robincornelius/libedssharp). - [CANopenLinux](https://github.com/CANopenNode/CANopenLinux): CANopenNode on Linux devices. It can be a basic CANopen device or more advanced with commander functionalities. - [CANopenPIC](https://github.com/CANopenNode/CANopenPIC): CANopenNode on PIC microcontrollers from Microchip. Works with 16-bit and 32 bit devices. Includes example for Arduino style [Max32](https://reference.digilentinc.com/reference/microprocessor/max32/start) board. - [doc/deviceSupport.md](doc/deviceSupport.md): List of other implementations of CANopenNode on different devices. @@ -62,8 +62,6 @@ Tutorial, demo device and tests are available in [CANopenDemo](https://github.co Report issues on https://github.com/CANopenNode/CANopenNode/issues -For discussion on [Slack](https://canopennode.slack.com/) see: https://github.com/robincornelius/libedssharp - Older discussion group is on Sourceforge: http://sourceforge.net/p/canopennode/discussion/387151/ Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Some basic formatting @@ -178,7 +176,7 @@ Object dictionary editor ------------------------ Object Dictionary is one of the most essential parts of CANopen. -To customize the Object Dictionary it is necessary to use external application: [libedssharp](https://github.com/robincornelius/libedssharp). Latest pre-compiled [binaries](https://github.com/robincornelius/libedssharp/raw/gh-pages/build/OpenEDSEditor-latest.zip) are also available. Just extract the zip file and run the `EDSEditor.exe`. In Linux it runs with mono, which is available by default on Ubuntu. Just set file permissions to "executable" and then execute the program. +To customize the Object Dictionary it is necessary to use external application: [CANopenEditor](https://github.com/CANopenNode/CANopenEditor). Latest pre-compiled [binaries](https://github.com/CANopenNode/CANopenEditor/archive/refs/heads/build.zip) are also available. Just extract the zip file and run the `EDSEditor.exe`. In Linux it runs with mono, which is available by default on Ubuntu. Just set file permissions to "executable" and then execute the program. In program, in preferences, set exporter to "CANopenNode_V4". Then start new project or open the existing project file. diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 6f754715..99b3631d 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -3,19 +3,19 @@ Change Log v4.0 - current -------------- -- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/newOD) -- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v2.0-master...newOD) +- [Source Code](https://github.com/CANopenNode/CANopenNode/tree/master) +- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v2.0-master...master) ### Removed - Driver for Linux (socketCAN directory) moved to own repository https://github.com/CANopenNode/CANopenLinux. ### Changed - New Object dictionary interface. It has similar principles as before. Main access to OD variables is via fast read/write functions, but direct access to OD variables is also possible. OD entries are passed with pointers to CANopen objects. All parts of CANopenNode objects, which works with OD entries, are rewritten. -- [libedssharp](https://github.com/robincornelius/libedssharp) have new OD exporter, new project file format (standard CANopen XDD v1.1), new documentation generator, and many other improvements. +- [CANopenEditor](https://github.com/CANopenNode/CANopenEditor) (formerly [libedssharp](https://github.com/robincornelius/libedssharp)) has new OD exporter, new project file format (standard CANopen XDD v1.1), new documentation generator, and many other improvements. - New OD.h and OD.c files, replaces CO_OD files. - CANopen.c and CANopen.h files redesigned. `#include OD.h` is optional. Configuration of multiple object dictionaries is possible with one CANopen device. Interface is the same, with some changes to function arguments. - New CO_storage.h/c files enables easier integration to target system for storing OD variables. - Rewritten SDO server. Object dictionary part is moved to CO_ODinterface.h/c files. - Rewritten PDO. PDO mapped variables are accessed via fast read/write functions. New RPDO event timer (timeout). -- CO_Emergency is mostly rewritten. Now is much easier customization. All other objects has been adjusted to newOD, inspected and some parts were redesigned. +- CO_Emergency is mostly rewritten. Now is much easier customisation. All other objects has been adjusted to newOD, inspected and some parts were redesigned. v2.0 - 2020-02-25 From bdcca85d07a730165fe1ca1f2f16d7157164aed8 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 29 Jun 2021 11:16:50 +0200 Subject: [PATCH 194/520] Add example for CO_MULTIPLE_OD configuration. --- example/main_blank.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/example/main_blank.c b/example/main_blank.c index 96cdd075..facb3c2a 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -83,7 +83,16 @@ int main (void){ /* Allocate memory */ - CO = CO_new(NULL, &heapMemoryUsed); + CO_config_t *config_ptr = NULL; +#ifdef CO_MULTIPLE_OD + /* example usage of CO_MULTIPLE_OD (but still single OD here) */ + CO_config_t co_config = {0}; + OD_INIT_CONFIG(co_config); /* helper macro from OD.h */ + co_config.CNT_LEDS = 1; + co_config.CNT_LSS_SLV = 1; + config_ptr = &co_config; +#endif /* CO_MULTIPLE_OD */ + CO = CO_new(config_ptr, &heapMemoryUsed); if (CO == NULL) { log_printf("Error: Can't allocate memory\n"); return 0; From 1ee6a9abc27791c34b6b1fa0899e93151a312e37 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 1 Jul 2021 09:23:39 +0200 Subject: [PATCH 195/520] Move some macros from CO_LSS.h into CO_LSSslave.c, issue #301 --- 305/CO_LSS.h | 15 --------------- 305/CO_LSSslave.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/305/CO_LSS.h b/305/CO_LSS.h index 8207a871..c0cdf15b 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -141,9 +141,6 @@ typedef enum { CO_LSS_FASTSCAN_CONFIRM = 0x80U /**< All LSS slaves waiting for scan respond and previous scan is reset */ } CO_LSS_fastscan_bitcheck; -/* comparision is always true: bit>=CO_LSS_FASTSCAN_BIT0 */ -#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) (bit<=CO_LSS_FASTSCAN_BIT31 || bit==CO_LSS_FASTSCAN_CONFIRM) - /** * Fastscan LSSsub, LSSnext */ @@ -154,9 +151,6 @@ typedef enum { CO_LSS_FASTSCAN_SERIAL = 3 /**< Serial number */ } CO_LSS_fastscan_lss_sub_next; -/* comparision is always true: index>=CO_LSS_FASTSCAN_VENDOR_ID */ -#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=CO_LSS_FASTSCAN_SERIAL) - /** * The LSS address is a 128 bit number, uniquely identifying each node. It * consists of the values in object 0x1018. @@ -218,15 +212,6 @@ static const uint16_t CO_LSS_bitTimingTableLookup[] = { 0 }; -/** - * Macro to check if index contains valid bit timing - */ -#if CO_LSS_BIT_TIMING_1000 != 0 -#error missing comprision index >= CO_LSS_BIT_TIMING_1000 -#endif -/* comparision is always true: index >= CO_LSS_BIT_TIMING_1000 */ -#define CO_LSS_BIT_TIMING_VALID(index) (index != 5 && index <= CO_LSS_BIT_TIMING_AUTO) - /** * Invalid node ID triggers node ID assignment */ diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index ee2e5010..2702fba6 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -31,6 +31,17 @@ #include +/* 'bit' must be unsigned or additional range check must be added: bit>=CO_LSS_FASTSCAN_BIT0 */ +#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) (bit<=CO_LSS_FASTSCAN_BIT31 || bit==CO_LSS_FASTSCAN_CONFIRM) +/* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_FASTSCAN_VENDOR_ID */ +#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=CO_LSS_FASTSCAN_SERIAL) +/* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_BIT_TIMING_1000 */ +#define CO_LSS_BIT_TIMING_VALID(index) (index != 5 && index <= CO_LSS_BIT_TIMING_AUTO) + +#if CO_LSS_FASTSCAN_BIT0!=0 || CO_LSS_FASTSCAN_VENDOR_ID!=0 || CO_LSS_BIT_TIMING_1000!=0 +#error Inconsistency in LSS macros +#endif + /* * Read received message from CAN module. * From e8d40fbfb768aab096d2c0595b6b4c009f8d6d23 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 24 Jun 2021 11:43:04 +0200 Subject: [PATCH 196/520] Fix error in PDO_initMapping() The loop should initialize only existing subindexes. Assuming that every time there are CO_PDO_MAX_MAPPED_ENTRIES subindexes results in the function returning CO_ERROR_OD_PARAMETERS because the call to OD_get_u32() to read a non-existing subindex returns ODR_SUB_NOT_EXIST. --- 301/CO_PDO.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 6eeb2be7..bfed5e17 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -186,6 +186,9 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, uint32_t map = 0; odRet = OD_get_u32(OD_PDOMapPar, i + 1, &map, true); + if (odRet == ODR_SUB_NOT_EXIST) { + continue; + } if (odRet != ODR_OK) { if (errInfo != NULL) { *errInfo = (((uint32_t)OD_getIndex(OD_PDOMapPar))<<8) | i; From db6462cfc119ba16ded704bbf93129f677470256 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 24 Jun 2021 11:49:05 +0200 Subject: [PATCH 197/520] Add CO_CANopenInitPDO() call to example's main() --- example/main_blank.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/example/main_blank.c b/example/main_blank.c index 96cdd075..dd076972 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -164,6 +164,17 @@ int main (void){ return 0; } + err = CO_CANopenInitPDO(CO, CO->em, OD, activeNodeId, &errInfo); + if(err != CO_ERROR_NO) { + if (err == CO_ERROR_OD_PARAMETERS) { + log_printf("Error: Object Dictionary entry 0x%X\n", errInfo); + } + else { + log_printf("Error: PDO initialization failed: %d\n", err); + } + return 0; + } + /* Configure Timer interrupt function for execution every 1 millisecond */ From a1db0180c43df1aeb5d918d6bccdada65ff49b97 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 24 Jun 2021 11:56:21 +0200 Subject: [PATCH 198/520] Fix warning about unused argument in CO_TIME_set() If CO_CONFIG_TIME_PRODUCER is not enabled, `producerInterval_ms` argument for CO_TIME_set() is unused and gives multiple warnings (because the function is in header). --- 301/CO_TIME.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 2f12d193..9602551f 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -176,6 +176,8 @@ static inline void CO_TIME_set(CO_TIME_t *TIME, uint16_t days, uint32_t producerInterval_ms) { + (void)producerInterval_ms; /* may be unused */ + if (TIME != NULL) { TIME->residual_us = 0; TIME->ms = ms; From 2e80d0304adc9196589ccb3fbdb5c7eeeb7966a6 Mon Sep 17 00:00:00 2001 From: Mattia Maldini Date: Wed, 14 Jul 2021 19:19:28 +0200 Subject: [PATCH 199/520] Fixed bug with CANrxData buffer indexing --- 301/CO_PDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index bfed5e17..f0297ddd 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -811,7 +811,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t rpdoReceived = false; while (CO_FLAG_READ(RPDO->CANrxNew[bufNo])) { rpdoReceived = true; - uint8_t *dataRPDO = &RPDO->CANrxData[0][bufNo]; + uint8_t *dataRPDO = RPDO->CANrxData[bufNo]; /* Clear the flag. If between the copy operation CANrxNew is set * by receive thread, then copy the latest data again. */ From b4ddf9be32450e28685b2a48119a327ce51651ef Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 9 Aug 2021 13:56:05 +0200 Subject: [PATCH 200/520] Fixed SDO server - Missing break - expedited transfer: always copied fixed amount of data instead of actual data size. --- 301/CO_SDOserver.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index d31bf9fb..ca40d133 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -348,9 +348,9 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; } - else { + else { uint16_t OD_SDOsrvParIdx = OD_getIndex(OD_1200_SDOsrvPar); - + if (OD_SDOsrvParIdx == OD_H1200_SDO_SERVER_1_PARAM) { /* configure default SDO channel and SDO server parameters for it */ if (nodeId < 1 || nodeId > 127) return CO_ERROR_ILLEGAL_ARGUMENT; @@ -1072,9 +1072,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* verify, if there is enough data */ - if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize*7U) { + if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize*7U){ abortCode = CO_SDO_AB_DEVICE_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; + break; } SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; } @@ -1262,14 +1263,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* data were already loaded from OD variable */ if (SDO->sizeInd > 0 && SDO->sizeInd <= 4) { /* expedited transfer */ - SDO->CANtxBuff->data[0] = (uint8_t)(0x43 | ((4 - SDO->sizeInd) << 2)); - memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, - sizeof(SDO->sizeInd)); + SDO->CANtxBuff->data[0] = (uint8_t)(0x43|((4-SDO->sizeInd)<<2)); + memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, SDO->sizeInd); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } else { - /* data will be transfered with segmented transfer */ + /* data will be transferred with segmented transfer */ if (SDO->sizeInd > 0) { /* indicate data size, if known */ uint32_t sizeInd = SDO->sizeInd; From 20f7af361fc8808b15db56a4cb8ab34a03f65f73 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 9 Aug 2021 13:59:03 +0200 Subject: [PATCH 201/520] Fixed Heartbeat consumer Receive buffer was not disabled, if monitored node has been unconfigured. --- 301/CO_HBconsumer.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 456162b7..cd976546 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -225,16 +225,14 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, monitoredNode->HBstate = CO_HBconsumer_UNCONFIGURED; } - /* configure Heartbeat consumer CAN reception */ - if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) { - ret = CO_CANrxBufferInit(HBcons->CANdevRx, - HBcons->CANdevRxIdxStart + idx, - COB_ID, - 0x7FF, - 0, - (void*)&HBcons->monitoredNodes[idx], - CO_HBcons_receive); - } + /* configure Heartbeat consumer (or disable) CAN reception */ + ret = CO_CANrxBufferInit(HBcons->CANdevRx, + HBcons->CANdevRxIdxStart + idx, + COB_ID, + 0x7FF, + 0, + (void*)&HBcons->monitoredNodes[idx], + CO_HBcons_receive); } return ret; } From bb74ed2cf5a43a976c4f2cb1f35a8abf4004123a Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 9 Aug 2021 14:00:45 +0200 Subject: [PATCH 202/520] SDO server: send abort on wrong block size --- 301/CO_SDOserver.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index ca40d133..5cf0d975 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1068,7 +1068,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* get blksize and verify it */ SDO->block_blksize = SDO->CANrxData[4]; if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { - SDO->block_blksize = 127; + abortCode = CO_SDO_AB_BLOCK_SIZE; + SDO->state = CO_SDO_ST_ABORT; + break; } /* verify, if there is enough data */ @@ -1099,7 +1101,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if (SDO->CANrxData[0] == 0xA2) { SDO->block_blksize = SDO->CANrxData[2]; if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { - SDO->block_blksize = 127; + abortCode = CO_SDO_AB_BLOCK_SIZE; + SDO->state = CO_SDO_ST_ABORT; + break; } /* check number of segments */ From 3ff84e21ff32b10406f2414a5a9dd6b17060437c Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 9 Aug 2021 14:06:08 +0200 Subject: [PATCH 203/520] Fix some SDO abort messages. --- 301/CO_PDO.c | 4 ++-- 301/CO_SYNC.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index f0297ddd..173eccb4 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -243,7 +243,7 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, /* PDO must be disabled before mapping configuration */ if (PDO->valid || (PDO->mappedObjectsCount != 0 && stream->subIndex > 0)) { - return ODR_INVALID_VALUE; + return ODR_UNSUPP_ACCESS; } if (stream->subIndex == 0) { @@ -251,7 +251,7 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, size_t pdoDataLength = 0; if (mappedObjectsCount > CO_PDO_MAX_MAPPED_ENTRIES) { - return ODR_INVALID_VALUE; + return ODR_MAP_LEN; } /* validate enabled mapping parameters */ diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 61990227..17855f09 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -174,7 +174,7 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, if (syncCounterOvf == 1 || syncCounterOvf > 240) { return ODR_INVALID_VALUE; } - if (*SYNC->OD_1006_period != 0 && SYNC->isProducer) { + if (*SYNC->OD_1006_period != 0) { return ODR_DATA_DEV_STATE; } From 5338f110e1db1e86c48b0a6d416585c8a33e6e07 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 9 Aug 2021 14:08:31 +0200 Subject: [PATCH 204/520] Synchronous TPDO: send first in the middle between sync messages. --- 301/CO_PDO.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 173eccb4..c2c82ffd 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -1411,7 +1411,8 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, TPDO->syncCounter = 254; } else { - TPDO->syncCounter = TPDO->transmissionType; + /* Send first TPDO somewhere in the middle */ + TPDO->syncCounter = TPDO->transmissionType / 2 + 1; } } /* If the syncStartValue is in use, start first TPDO after SYNC From fe3777b7817d5adae053694a5dfb31ffd59ae459 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 9 Aug 2021 14:12:19 +0200 Subject: [PATCH 205/520] Verify for restricted CAN-IDs in SYNC, TIME, EMCY, PDO and SDO COB-ID configuration. --- 301/CO_Emergency.c | 2 +- 301/CO_PDO.c | 4 ++-- 301/CO_SDOclient.c | 31 +++++++++++++++++++------------ 301/CO_SDOserver.c | 31 +++++++++++++++++++------------ 301/CO_SYNC.c | 4 ++-- 301/CO_TIME.c | 8 +++++++- 301/CO_driver.h | 16 ++++++++++++++++ 7 files changed, 66 insertions(+), 30 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 6f68be9f..242c71b9 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -94,7 +94,7 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, uint16_t curCanId = em->producerCanId == CO_CAN_ID_EMERGENCY ? CO_CAN_ID_EMERGENCY + em->nodeId : em->producerCanId; bool_t newEnabled = (COB_IDEmergency32 & 0x80000000) == 0 && newCanId != 0; - if ((COB_IDEmergency32 & 0x7FFFF800) != 0 + if ((COB_IDEmergency32 & 0x7FFFF800)!=0 || CO_IS_RESTRICTED_CAN_ID(newCanId) || (em->producerEnabled && newEnabled && newCanId != curCanId) ) { return ODR_INVALID_VALUE; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index c2c82ffd..8db38a1b 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -540,7 +540,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, * enabling the PDO */ if ((COB_ID & 0x3FFFF800) != 0 || (valid && PDO->valid && CAN_ID != PDO->configuredCanId) - || (valid && CAN_ID == 0) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) || (valid && PDO->mappedObjectsCount == 0) ) { return ODR_INVALID_VALUE; @@ -965,7 +965,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, * enabling the PDO */ if ((COB_ID & 0x3FFFF800) != 0 || (valid && PDO->valid && CAN_ID != PDO->configuredCanId) - || (valid && CAN_ID == 0) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) || (valid && PDO->mappedObjectsCount == 0) ) { return ODR_INVALID_VALUE; diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index b547bfe8..77979db4 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -182,20 +182,21 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, } CO_SDOclient_t *SDO_C = (CO_SDOclient_t *)stream->object; - uint32_t COB_ID; - uint8_t nodeId; switch (stream->subIndex) { case 0: /* Highest sub-index supported */ return ODR_READONLY; - case 1: /* COB-ID client -> server */ - COB_ID = CO_getUint32(buf); + case 1: { /* COB-ID client -> server */ + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + uint16_t CAN_ID_cur = (uint16_t)(SDO_C->COB_IDClientToServer&0x7FF); + bool_t valid = (COB_ID & 0x80000000) == 0; /* SDO client must not be valid when changing COB_ID */ if ((COB_ID & 0x3FFFF800) != 0 - || ((uint16_t)COB_ID != (uint16_t)SDO_C->COB_IDClientToServer - && SDO_C->valid && (COB_ID & 0x80000000) == 0) + || (valid && SDO->valid && CAN_ID != CAN_ID_cur) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; } @@ -204,14 +205,18 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, SDO_C->COB_IDServerToClient, SDO_C->nodeIDOfTheSDOServer); break; + } - case 2: /* COB-ID server -> client */ - COB_ID = CO_getUint32(buf); + case 2: { /* COB-ID server -> client */ + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + uint16_t CAN_ID_cur = (uint16_t)(SDO_C->COB_IDServerToClient&0x7FF); + bool_t valid = (COB_ID & 0x80000000) == 0; /* SDO client must not be valid when changing COB_ID */ if ((COB_ID & 0x3FFFF800) != 0 - || ((uint16_t)COB_ID != (uint16_t)SDO_C->COB_IDServerToClient - && SDO_C->valid && (COB_ID & 0x80000000) == 0) + || (valid && SDO->valid && CAN_ID != CAN_ID_cur) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; } @@ -220,14 +225,16 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, COB_ID, SDO_C->nodeIDOfTheSDOServer); break; + } - case 3: /* Node-ID of the SDO server */ - nodeId = CO_getUint8(buf); + case 3: { /* Node-ID of the SDO server */ + uint8_t nodeId = CO_getUint8(buf); if (nodeId > 127) { return ODR_INVALID_VALUE; } SDO_C->nodeIDOfTheSDOServer = nodeId; break; + } default: return ODR_SUB_NOT_EXIST; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 5cf0d975..186a40a8 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -241,20 +241,21 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, } CO_SDOserver_t *SDO = (CO_SDOserver_t *)stream->object; - uint32_t COB_ID; - uint8_t nodeId; switch (stream->subIndex) { case 0: /* Highest sub-index supported */ return ODR_READONLY; - case 1: /* COB-ID client -> server */ - COB_ID = CO_getUint32(buf); + case 1: { /* COB-ID client -> server */ + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + uint16_t CAN_ID_cur = (uint16_t)(SDO->COB_IDClientToServer & 0x7FF); + bool_t valid = (COB_ID & 0x80000000) == 0; /* SDO client must not be valid when changing COB_ID */ if ((COB_ID & 0x3FFFF800) != 0 - || ((uint16_t)COB_ID != (uint16_t)SDO->COB_IDClientToServer - && SDO->valid && (COB_ID & 0x80000000)) + || (valid && SDO->valid && CAN_ID != CAN_ID_cur) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; } @@ -265,14 +266,18 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, COB_ID, SDO->COB_IDServerToClient); break; + } - case 2: /* COB-ID server -> client */ - COB_ID = CO_getUint32(buf); + case 2: { /* COB-ID server -> client */ + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + uint16_t CAN_ID_cur = (uint16_t)(SDO->COB_IDServerToClient & 0x7FF); + bool_t valid = (COB_ID & 0x80000000) == 0; /* SDO client must not be valid when changing COB_ID */ if ((COB_ID & 0x3FFFF800) != 0 - || ((uint16_t)COB_ID != (uint16_t)SDO->COB_IDServerToClient - && SDO->valid && (COB_ID & 0x80000000)) + || (valid && SDO->valid && CAN_ID != CAN_ID_cur) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; } @@ -283,16 +288,18 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, SDO->COB_IDClientToServer, COB_ID); break; + } - case 3: /* Node-ID of the SDO server */ + case 3: { /* Node-ID of the SDO server */ if (count != 1) { return ODR_TYPE_MISMATCH; } - nodeId = CO_getUint8(buf); + uint8_t nodeId = CO_getUint8(buf); if (nodeId < 1 || nodeId > 127) { return ODR_INVALID_VALUE; } break; + } default: return ODR_SUB_NOT_EXIST; diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 17855f09..c8599145 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -96,13 +96,13 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, /* verify written value */ #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER bool_t isProducer = (cobIdSync & 0x40000000) != 0; - if ((cobIdSync & 0xBFFF8000) != 0 + if ((cobIdSync & 0xBFFFF800) != 0 || CO_IS_RESTRICTED_CAN_ID(CAN_ID) || (SYNC->isProducer && isProducer && CAN_ID != SYNC->CAN_ID) ) { return ODR_INVALID_VALUE; } #else - if ((cobIdSync & 0xFFFF8000) != 0) { + if ((cobIdSync & 0xFFFFF800) != 0 || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { return ODR_INVALID_VALUE; } #endif diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 17648d35..48e311a9 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -72,8 +72,14 @@ static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, CO_TIME_t *TIME = stream->object; - /* update object */ + /* verify written value */ uint32_t cobIdTimeStamp = CO_getUint32(buf); + uint16_t CAN_ID = cobIdTimeStamp & 0x7FF; + if ((cobIdTimeStamp & 0x3FFFF800) != 0 || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { + return ODR_INVALID_VALUE; + } + + /* update object */ TIME->isConsumer = (cobIdTimeStamp & 0x80000000L) != 0; TIME->isProducer = (cobIdTimeStamp & 0x40000000L) != 0; diff --git a/301/CO_driver.h b/301/CO_driver.h index 3d2bb05d..2fe360cb 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -500,6 +500,22 @@ typedef enum { } CO_Default_CAN_ID_t; +/** + * Restricted CAN-IDs + * + * Macro for verifying 'Restricted CAN-IDs', as specified by standard CiA301. + * They shall not be used for SYNC, TIME, EMCY, PDO and SDO. + */ +#ifndef CO_IS_RESTRICTED_CAN_ID +#define CO_IS_RESTRICTED_CAN_ID(CAN_ID) ((CAN_ID) <= 0x7F \ + || ((CAN_ID) >= 0x101 && (CAN_ID) <= 0x180) \ + || ((CAN_ID) >= 0x581 && (CAN_ID) <= 0x5FF) \ + || ((CAN_ID) >= 0x601 && (CAN_ID) <= 0x67F) \ + || ((CAN_ID) >= 0x6E0 && (CAN_ID) <= 0x6FF) \ + || (CAN_ID) >= 0x701) +#endif + + /** * CAN error status bitmasks. * From 3d50dd4bf9726c761261acdbb5464daa1a5cdbc6 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 9 Aug 2021 18:45:38 +0200 Subject: [PATCH 206/520] Fixed Object dictionary mapping direction --- example/DS301_profile.eds | 4 ++-- example/DS301_profile.md | 6 +++--- example/DS301_profile.xpd | 8 ++++---- example/OD.c | 4 ++-- example/OD.h | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/example/DS301_profile.eds b/example/DS301_profile.eds index 325c1b1e..1e598e8e 100644 --- a/example/DS301_profile.eds +++ b/example/DS301_profile.eds @@ -8,8 +8,8 @@ Description= CreationTime=1:00PM CreationDate=11-23-2020 CreatedBy= -ModificationTime=1:21PM -ModificationDate=06-26-2021 +ModificationTime=6:39PM +ModificationDate=08-09-2021 ModifiedBy= [DeviceInfo] diff --git a/example/DS301_profile.md b/example/DS301_profile.md index d8679705..ac5d1c7c 100644 --- a/example/DS301_profile.md +++ b/example/DS301_profile.md @@ -10,10 +10,10 @@ CANopen device documentation | File Version | 1 | | Created | 23. 11. 2020 13:00:00 | | Created By | | -| Modified | 26. 06. 2021 13:21:06 | +| Modified | 9. 08. 2021 18:39:55 | | Modified By | | -This file was automatically generated by [CANopenEditor](https://github.com/CANopenNode/CANopenEditor) v4.0-49-gd365995 +This file was automatically generated by [CANopenEditor](https://github.com/CANopenNode/CANopenEditor) v4.0-51-g2d9b1ad [TOC] @@ -69,7 +69,7 @@ Communication Specific Parameters | Data Type | SDO | PDO | SRDO | Default Value | | ----------------------- | --- | --- | ---- | ------------------------------- | -| UNSIGNED8 | ro | tr | no | 0x00 | +| UNSIGNED8 | ro | t | no | 0x00 | * bit 7: manufacturer specific * bit 6: Reserved (always 0) diff --git a/example/DS301_profile.xpd b/example/DS301_profile.xpd index 690bc4b2..913bd715 100644 --- a/example/DS301_profile.xpd +++ b/example/DS301_profile.xpd @@ -1,5 +1,5 @@ - + @@ -15,7 +15,7 @@ CANopen - + @@ -2277,11 +2277,11 @@ CANopen - + - + diff --git a/example/OD.c b/example/OD.c index f8fdfc39..ac19ef37 100644 --- a/example/OD.c +++ b/example/OD.c @@ -1,7 +1,7 @@ /******************************************************************************* CANopen Object Dictionary definition for CANopenNode V4 - This file was automatically generated by CANopenEditor v4.0-49-gd365995 + This file was automatically generated by CANopenEditor v4.0-51-g2d9b1ad https://github.com/CANopenNode/CANopenNode https://github.com/CANopenNode/CANopenEditor @@ -253,7 +253,7 @@ static CO_PROGMEM ODObjs_t ODObjs = { }, .o_1001_errorRegister = { .dataOrig = &OD_RAM.x1001_errorRegister, - .attribute = ODA_SDO_R | ODA_TRPDO, + .attribute = ODA_SDO_R | ODA_TPDO, .dataLength = 1 }, .o_1003_pre_definedErrorField = { diff --git a/example/OD.h b/example/OD.h index 30dbaf1f..6f103d68 100644 --- a/example/OD.h +++ b/example/OD.h @@ -1,7 +1,7 @@ /******************************************************************************* CANopen Object Dictionary definition for CANopenNode V4 - This file was automatically generated by CANopenEditor v4.0-49-gd365995 + This file was automatically generated by CANopenEditor v4.0-51-g2d9b1ad https://github.com/CANopenNode/CANopenNode https://github.com/CANopenNode/CANopenEditor @@ -16,7 +16,7 @@ Created: 23. 11. 2020 13:00:00 Created By: - Modified: 26. 06. 2021 13:21:06 + Modified: 9. 08. 2021 18:39:55 Modified By: Device Info: From 78544f8043b38146ecdcbee2163b58453247bce9 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 9 Aug 2021 18:53:26 +0200 Subject: [PATCH 207/520] CANopen Conformance Test Tool tested and passed. See CANopenDemo for test results. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3203a758..29352160 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Characteristics - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) CANopen node-id and bitrate setup, master and slave, LSS fastscan. - [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. - CANopen Safety, EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks + - [CANopen Conformance Test Tool](https://www.can-cia.org/services/test-center/conformance-test-tool/) passed. ### Other - [Suitable for 16-bit microcontrollers and above](#device-support) From 2117fb6149cefe9a54774c1573f36308b5951bff Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 10 Aug 2021 10:17:46 +0200 Subject: [PATCH 208/520] Add example for basic SDO client usage, #276 --- 301/CO_SDOclient.h | 110 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 7c9b32d7..794ac0ac 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -56,6 +56,116 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ + * SDO client is able to access Object Dictionary variables from remote nodes. + * Usually there is one SDO client on CANopen network, which is able to + * configure other CANopen nodes. It is also possible to establish individual + * SDO client-server communication channels between devices. + * + * SDO client is used in CANopenNode from CO_gateway_ascii.c with default SDO + * CAN identifiers. There is quite advanced usage in non-blocking function. + * + * If enabled, SDO client is initialized in CANopen.c file with + * @ref CO_SDOclient_init() function. + * + * Basic usage: + * @code{.c} +CO_SDO_abortCode_t read_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, + uint16_t index, uint8_t subIndex, + uint8_t *buf, size_t bufSize, size_t *readSize) +{ + CO_SDO_return_t SDO_ret; + + // setup client (this can be skipped, if remote device don't change) + SDO_ret = CO_SDOclient_setup(SDO_C, + CO_CAN_ID_SDO_CLI + nodeId, + CO_CAN_ID_SDO_SRV + nodeId, + nodeId); + if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { + return CO_SDO_AB_GENERAL; + } + + // initiate upload + SDO_ret = CO_SDOclientUploadInitiate(SDO_C, index, subIndex, 1000, false); + if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { + return CO_SDO_AB_GENERAL; + } + + // upload data + do { + uint32_t timeDifference_us = 10000; + CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; + + SDO_ret = CO_SDOclientUpload(SDO_C, + timeDifference_us, + false, + &abortCode, + NULL, NULL, NULL); + if (SDO_ret < 0) { + return abortCode; + } + + sleep_us(timeDifference_us); + } while(SDO_ret > 0); + + // copy data to the user buffer (for long data function must be called + // several times inside the loop) + *readSize = CO_SDOclientUploadBufRead(SDO_C, buf, bufSize); + + return CO_SDO_AB_NONE; +} + +CO_SDO_abortCode_t write_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, + uint16_t index, uint8_t subIndex, + uint8_t *data, size_t dataSize) +{ + CO_SDO_return_t SDO_ret; + bool_t bufferPartial = false; + + // setup client (this can be skipped, if remote device is the same) + SDO_ret = CO_SDOclient_setup(SDO_C, + CO_CAN_ID_SDO_CLI + nodeId, + CO_CAN_ID_SDO_SRV + nodeId, + nodeId); + if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { + return -1 + } + + // initiate download + SDO_ret = CO_SDOclientDownloadInitiate(SDO_C, index, subIndex, + dataSize, 1000, false); + if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { + return -1 + } + + // fill data + size_t nWritten = CO_SDOclientDownloadBufWrite(SDO_C, data, dataSize); + if (nWritten < dataSize) { + bufferPartial = true; + // If SDO Fifo buffer is too small, data can be refilled in the loop. + } + + //download data + do { + uint32_t timeDifference_us = 10000; + CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; + + SDO_ret = CO_SDOclientDownload(SDO_C, + timeDifference_us, + false, + bufferPartial, + &abortCode, + NULL, NULL); + if (SDO_ret < 0) { + return abortCode; + } + + sleep_us(timeDifference_us); + } while(SDO_ret > 0); + + return CO_SDO_AB_NONE; +} + * @endcode + * * @see @ref CO_SDOserver */ From b1b091a46330fdc82a3d5106a2976879b903e0ae Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 10 Aug 2021 16:34:20 +0200 Subject: [PATCH 209/520] Add option for logical devices to have more than four PDOS with pre-defined CAN_IDs. --- 301/CO_PDO.h | 20 ++++++++++++++++++++ CANopen.c | 28 ++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 6a6bd872..f6743835 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -144,6 +144,26 @@ extern "C" { #define CO_PDO_MAX_MAPPED_ENTRIES 8 #endif +/** Number of CANopen RPDO objects, which uses default CAN indentifiers. + * By default first four RPDOs have pre-defined CAN identifiers, which depends + * on node-id. This constant may be set to 0 to disable functionality or set + * to any other value. For example, if there are several logical devices inside + * single CANopen device, then more than four RPDOs may have pre-defined CAN + * identifiers. In that case RPDO5 has CAN_ID=0x200+NodeId+1, RPDO6 has + * CAN_ID=0x300+NodeId+1, RPDO9 has CAN_ID=0x200+NodeId+2 and so on. */ +#ifndef CO_RPDO_DEFAULT_CANID_COUNT +#define CO_RPDO_DEFAULT_CANID_COUNT 4 +#endif + +/** Number of CANopen TPDO objects, which uses default CAN indentifiers. + * If value is more than four, then pre-defined pre-defined CAN identifiers are: + * TPDO5 has CAN_ID=0x180+NodeId+1, TPDO6 has CAN_ID=0x280+NodeId+1, + * TPDO9 has CAN_ID=0x180+NodeId+2 and so on. + * For description see @ref CO_RPDO_DEFAULT_CANID_COUNT. */ +#ifndef CO_TPDO_DEFAULT_CANID_COUNT +#define CO_TPDO_DEFAULT_CANID_COUNT 4 +#endif + #ifndef CO_PDO_OWN_TYPES /** Variable of type CO_PDO_size_t contains data length in bytes of PDO */ typedef uint8_t CO_PDO_size_t; diff --git a/CANopen.c b/CANopen.c index b4e8991a..08bb4335 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1266,9 +1266,17 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { CO_ReturnError_t err; - uint16_t preDefinedCanId = i < 4 - ? (CO_CAN_ID_RPDO_1 + i * 0x100) + nodeId - : 0; + uint16_t preDefinedCanId = 0; + if (i < CO_RPDO_DEFAULT_CANID_COUNT) { +#if CO_RPDO_DEFAULT_CANID_COUNT <= 4 + preDefinedCanId = (CO_CAN_ID_RPDO_1 + i * 0x100) + nodeId; +#else + uint16_t pdoOffset = i % 4; + uint16_t nodeIdOffset = i / 4; + preDefinedCanId = (CO_CAN_ID_RPDO_1 + pdoOffset * 0x100) + + nodeId + nodeIdOffset; +#endif + } err = CO_RPDO_init(&co->RPDO[i], od, em, @@ -1292,9 +1300,17 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { CO_ReturnError_t err; - uint16_t preDefinedCanId = i < 4 - ? (CO_CAN_ID_TPDO_1 + i * 0x100) + nodeId - : 0; + uint16_t preDefinedCanId = 0; + if (i < CO_TPDO_DEFAULT_CANID_COUNT) { +#if CO_TPDO_DEFAULT_CANID_COUNT <= 4 + preDefinedCanId = (CO_CAN_ID_TPDO_1 + i * 0x100) + nodeId; +#else + uint16_t pdoOffset = i % 4; + uint16_t nodeIdOffset = i / 4; + preDefinedCanId = (CO_CAN_ID_TPDO_1 + pdoOffset * 0x100) + + nodeId + nodeIdOffset; +#endif + } err = CO_TPDO_init(&co->TPDO[i], od, em, From 9d1e99f66e34840adab90ad0dbeb23fc19a68c87 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 13 Aug 2021 19:07:19 +0200 Subject: [PATCH 210/520] Use enumerators in CO_NMT_t, #327 --- 301/CO_NMT_Heartbeat.c | 6 +++--- 301/CO_NMT_Heartbeat.h | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index dfe05965..ac35b81c 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -36,7 +36,7 @@ static void CO_NMT_receive(void *object, void *msg) { uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); - uint8_t command = data[0]; + CO_NMT_command_t command = (CO_NMT_command_t)data[0]; uint8_t nodeId = data[1]; CO_NMT_t *NMT = (CO_NMT_t*)object; @@ -258,7 +258,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, /* process internal NMT commands, received from CO_NMT_receive() or * CO_NMT_sendCommand() */ - if (NMT->internalCommand != 0) { + if (NMT->internalCommand != CO_NMT_NO_COMMAND) { switch (NMT->internalCommand) { case CO_NMT_ENTER_OPERATIONAL: NMTstateCpy = CO_NMT_OPERATIONAL; @@ -278,7 +278,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, default: break; } - NMT->internalCommand = 0; + NMT->internalCommand = CO_NMT_NO_COMMAND; } /* verify NMT transitions based on error register */ diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 42548061..57bb56fd 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -92,6 +92,8 @@ typedef enum { * Commands from NMT master. */ typedef enum { + /** 0, No command */ + CO_NMT_NO_COMMAND = 0, /** 1, Start device */ CO_NMT_ENTER_OPERATIONAL = 1, /** 2, Stop device */ @@ -161,12 +163,12 @@ typedef enum { */ typedef struct { /** Current NMT operating state. */ - uint8_t operatingState; + CO_NMT_internalState_t operatingState; /** Previous NMT operating state. */ - uint8_t operatingStatePrev; + CO_NMT_internalState_t operatingStatePrev; /** NMT internal command from CO_NMT_receive() or CO_NMT_sendCommand(), - * processed in CO_NMT_process(). 0 if no command or CO_NMT_command_t */ - uint8_t internalCommand; + * processed in CO_NMT_process(). */ + CO_NMT_command_t internalCommand; /** From CO_NMT_init() */ uint8_t nodeId; /** From CO_NMT_init() */ @@ -314,7 +316,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, * @return @ref CO_NMT_internalState_t */ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { - return (NMT == NULL) ? CO_NMT_INITIALIZING : (CO_NMT_internalState_t)NMT->operatingState; + return (NMT == NULL) ? CO_NMT_INITIALIZING : NMT->operatingState; } @@ -329,7 +331,7 @@ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { static inline void CO_NMT_sendInternalCommand(CO_NMT_t *NMT, CO_NMT_command_t command) { - if (NMT != NULL) NMT->internalCommand = (uint8_t)command; + if (NMT != NULL) NMT->internalCommand = command; } From 88bc36da27de1d662e2fed57675b83cd61b7860d Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 14 Aug 2021 12:00:08 +0200 Subject: [PATCH 211/520] Add conditional compile statement for unused vars --- 301/CO_PDO.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 8db38a1b..98871c0e 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -1323,8 +1323,10 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, bool_t NMTisOperational, bool_t syncWas) { - (void) syncWas; (void) timerNext_us; CO_PDO_common_t *PDO = &TPDO->PDO_common; +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) + (void) syncWas; (void) timerNext_us; +#endif if (PDO->valid && NMTisOperational) { From 309024f3121f904def2dacc25da6379721f98038 Mon Sep 17 00:00:00 2001 From: Yaroslaff Fedin Date: Mon, 23 Aug 2021 14:06:10 +0800 Subject: [PATCH 212/520] Fix typo (co -> CO) in main_blank.c --- example/main_blank.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/main_blank.c b/example/main_blank.c index 5a901d6d..cb54eb01 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -251,7 +251,7 @@ int main (void){ void tmrTask_thread(void){ for(;;) { - CO_LOCK_OD(co->CANmodule); + CO_LOCK_OD(CO->CANmodule); if (!CO->nodeIdUnconfigured && CO->CANmodule->CANnormal) { bool_t syncWas = false; /* get time difference since last function call */ @@ -269,7 +269,7 @@ void tmrTask_thread(void){ /* Further I/O or nonblocking application code may go here. */ } - CO_UNLOCK_OD(co->CANmodule); + CO_UNLOCK_OD(CO->CANmodule); } } From f1e39ccabb4b80ab75796173e2d93f1ec3923150 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 24 Aug 2021 08:20:37 +0200 Subject: [PATCH 213/520] Update CO_PDO.c --- 301/CO_PDO.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 98871c0e..e79ed933 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -1325,8 +1325,9 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, { CO_PDO_common_t *PDO = &TPDO->PDO_common; #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) - (void) syncWas; (void) timerNext_us; + (void) timerNext_us; #endif + (void) syncWas; if (PDO->valid && NMTisOperational) { From 9c146e8b916514f2a53bb5db093d08016d87b0e0 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Thu, 26 Aug 2021 13:25:38 +0200 Subject: [PATCH 214/520] Replace malloc/free with CO_ and add macro for complete allocation --- CANopen.c | 201 +++++++++++++++++++++--------------------------------- 1 file changed, 79 insertions(+), 122 deletions(-) diff --git a/CANopen.c b/CANopen.c index 08bb4335..c65d106f 100644 --- a/CANopen.c +++ b/CANopen.c @@ -291,6 +291,29 @@ #ifndef CO_USE_GLOBALS #include +/* Default allocation strategy ************************************************/ +#if !defined(CO_alloc) || !defined(CO_free) +#if defined(CO_alloc) +#warning CO_alloc is defined but CO_free is not. using default values instead +#undef CO_alloc +#endif +#if defined(CO_free) +#warning CO_free is defined but CO_alloc is not. using default values instead +#undef CO_free +#endif + +/* + * Allocate memory for number of elements, each of specific size + * Allocated memory must be reset to all zeros + */ +#define CO_alloc(num, size) calloc((num), (size)) +#define CO_free(ptr) free((ptr)) + +#endif + +/* Define macros for allocation */ +#define CO_alloc_break_on_fail(var, num, size) if (((var) = CO_alloc((num), (size))) != NULL) { mem += (size) * (num); } else { break; } + #ifdef CO_MULTIPLE_OD #define ON_MULTI_OD(sentence) sentence #else @@ -331,10 +354,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #endif /* CANopen object */ - void *p = calloc(1, sizeof(CO_t)); - if (p == NULL) break; - else co = (CO_t *)p; - mem += sizeof(CO_t); + CO_alloc_break_on_fail(co, 1, sizeof(*co)); #ifdef CO_MULTIPLE_OD co->config = config; @@ -345,10 +365,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t TX_CNT_NMT_MST = 0); ON_MULTI_OD(uint8_t TX_CNT_HB_PROD = 0); if (CO_GET_CNT(NMT) == 1) { - p = calloc(1, sizeof(CO_NMT_t)); - if (p == NULL) break; - else co->NMT = (CO_NMT_t *)p; - mem += sizeof(CO_NMT_t); + CO_alloc_break_on_fail(co->NMT, CO_GET_CNT(NMT), sizeof(*co->NMT)); ON_MULTI_OD(RX_CNT_NMT_SLV = 1); #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER ON_MULTI_OD(TX_CNT_NMT_MST = 1); @@ -360,14 +377,8 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_HB_CONS = 0); if (CO_GET_CNT(HB_CONS) == 1) { uint8_t countOfMonitoredNodes = CO_GET_CNT(ARR_1016); - p = calloc(1, sizeof(CO_HBconsumer_t)); - if (p == NULL) break; - else co->HBcons = (CO_HBconsumer_t *)p; - mem += sizeof(CO_HBconsumer_t); - p = calloc(countOfMonitoredNodes, sizeof(CO_HBconsNode_t)); - if (p == NULL) break; - else co->HBconsMonitoredNodes = (CO_HBconsNode_t *)p; - mem += countOfMonitoredNodes * sizeof(CO_HBconsNode_t); + CO_alloc_break_on_fail(co->HBcons, CO_GET_CNT(HB_CONS), sizeof(*co->HBcons)); + CO_alloc_break_on_fail(co->HBconsMonitoredNodes, countOfMonitoredNodes, sizeof(*co->HBconsMonitoredNodes)); ON_MULTI_OD(RX_CNT_HB_CONS = countOfMonitoredNodes); } #endif @@ -376,10 +387,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_EM_CONS = 0); ON_MULTI_OD(uint8_t TX_CNT_EM_PROD = 0); if (CO_GET_CNT(EM) == 1) { - p = calloc(1, sizeof(CO_EM_t)); - if (p == NULL) break; - else co->em = (CO_EM_t *)p; - mem += sizeof(CO_EM_t); + CO_alloc_break_on_fail(co->em, CO_GET_CNT(EM), sizeof(*co->em)); #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER ON_MULTI_OD(RX_CNT_EM_CONS = 1); #endif @@ -389,13 +397,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) uint8_t fifoSize = CO_GET_CNT(ARR_1003) + 1; if (fifoSize >= 2) { - p = calloc(fifoSize, sizeof(CO_EM_fifo_t)); - if (p == NULL) break; - else co->em_fifo = (CO_EM_fifo_t *)p; - mem += fifoSize * sizeof(CO_EM_fifo_t); - } - else { - co->em_fifo = NULL; + CO_alloc_break_on_fail(co->em_fifo, fifoSize, sizeof(*co->em_fifo)); } #endif } @@ -404,10 +406,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_SDO_SRV = 0); ON_MULTI_OD(uint8_t TX_CNT_SDO_SRV = 0); if (CO_GET_CNT(SDO_SRV) > 0) { - p = calloc(CO_GET_CNT(SDO_SRV), sizeof(CO_SDOserver_t)); - if (p == NULL) break; - else co->SDOserver = (CO_SDOserver_t *)p; - mem += sizeof(CO_SDOserver_t) * CO_GET_CNT(SDO_SRV); + CO_alloc_break_on_fail(co->SDOserver, CO_GET_CNT(SDO_SRV), sizeof(*co->SDOserver)); ON_MULTI_OD(RX_CNT_SDO_SRV = config->CNT_SDO_SRV); ON_MULTI_OD(TX_CNT_SDO_SRV = config->CNT_SDO_SRV); } @@ -416,10 +415,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_SDO_CLI = 0); ON_MULTI_OD(uint8_t TX_CNT_SDO_CLI = 0); if (CO_GET_CNT(SDO_CLI) > 0) { - p = calloc(CO_GET_CNT(SDO_CLI), sizeof(CO_SDOclient_t)); - if (p == NULL) break; - else co->SDOclient = (CO_SDOclient_t *)p; - mem += sizeof(CO_SDOclient_t) * CO_GET_CNT(SDO_CLI); + CO_alloc_break_on_fail(co->SDOclient, CO_GET_CNT(SDO_CLI), sizeof(*co->SDOclient)); ON_MULTI_OD(RX_CNT_SDO_CLI = config->CNT_SDO_CLI); ON_MULTI_OD(TX_CNT_SDO_CLI = config->CNT_SDO_CLI); } @@ -429,10 +425,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_TIME = 0); ON_MULTI_OD(uint8_t TX_CNT_TIME = 0); if (CO_GET_CNT(TIME) == 1) { - p = calloc(1, sizeof(CO_TIME_t)); - if (p == NULL) break; - else co->TIME = (CO_TIME_t *)p; - mem += sizeof(CO_TIME_t); + CO_alloc_break_on_fail(co->TIME, CO_GET_CNT(TIME), sizeof(*co->TIME)); ON_MULTI_OD(RX_CNT_TIME = 1); #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER ON_MULTI_OD(TX_CNT_TIME = 1); @@ -444,10 +437,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_SYNC = 0); ON_MULTI_OD(uint8_t TX_CNT_SYNC = 0); if (CO_GET_CNT(SYNC) == 1) { - p = calloc(1, sizeof(CO_SYNC_t)); - if (p == NULL) break; - else co->SYNC = (CO_SYNC_t *)p; - mem += sizeof(CO_SYNC_t); + CO_alloc_break_on_fail(co->SYNC, CO_GET_CNT(SYNC), sizeof(*co->SYNC)); ON_MULTI_OD(RX_CNT_SYNC = 1); #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER ON_MULTI_OD(TX_CNT_SYNC = 1); @@ -458,10 +448,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE ON_MULTI_OD(uint16_t RX_CNT_RPDO = 0); if (CO_GET_CNT(RPDO) > 0) { - p = calloc(CO_GET_CNT(RPDO), sizeof(CO_RPDO_t)); - if (p == NULL) break; - else co->RPDO = (CO_RPDO_t *)p; - mem += sizeof(CO_RPDO_t) * CO_GET_CNT(RPDO); + CO_alloc_break_on_fail(co->RPDO, CO_GET_CNT(RPDO), sizeof(*co->RPDO)); ON_MULTI_OD(RX_CNT_RPDO = config->CNT_RPDO); } #endif @@ -469,20 +456,14 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE ON_MULTI_OD(uint16_t TX_CNT_TPDO = 0); if (CO_GET_CNT(TPDO) > 0) { - p = calloc(CO_GET_CNT(TPDO), sizeof(CO_TPDO_t)); - if (p == NULL) break; - else co->TPDO = (CO_TPDO_t *)p; - mem += sizeof(CO_TPDO_t) * CO_GET_CNT(TPDO); + CO_alloc_break_on_fail(co->TPDO, CO_GET_CNT(TPDO), sizeof(*co->TPDO)); ON_MULTI_OD(TX_CNT_TPDO = config->CNT_TPDO); } #endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE if (CO_GET_CNT(LEDS) == 1) { - p = calloc(1, sizeof(CO_LEDs_t)); - if (p == NULL) break; - else co->LEDs = (CO_LEDs_t *)p; - mem += sizeof(CO_LEDs_t); + CO_alloc_break_on_fail(co->LEDs, CO_GET_CNT(LEDS), sizeof(*co->LEDs)); } #endif @@ -490,10 +471,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_GFC = 0); ON_MULTI_OD(uint8_t TX_CNT_GFC = 0); if (CO_GET_CNT(GFC) == 1) { - p = calloc(1, sizeof(CO_GFC_t)); - if (p == NULL) break; - else co->GFC = (CO_GFC_t *)p; - mem += sizeof(CO_GFC_t); + CO_alloc_break_on_fail(co->GFC, CO_GET_CNT(GFC), sizeof(*co->GFC)); ON_MULTI_OD(RX_CNT_GFC = 1); ON_MULTI_OD(TX_CNT_GFC = 1); } @@ -503,14 +481,8 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_SRDO = 0); ON_MULTI_OD(uint8_t TX_CNT_SRDO = 0); if (CO_GET_CNT(SRDO) > 0) { - p = calloc(1, sizeof(CO_SRDOGuard_t)); - if (p == NULL) break; - else co->SRDOGuard = (CO_SRDOGuard_t *)p; - mem += sizeof(CO_SRDOGuard_t); - p = calloc(CO_GET_CNT(SRDO), sizeof(CO_SRDO_t)); - if (p == NULL) break; - else co->SRDO = (CO_SRDO_t *)p; - mem += sizeof(CO_SRDO_t) * CO_GET_CNT(SRDO); + CO_alloc_break_on_fail(co->SRDOGuard, 1, sizeof(*co->SRDOGuard)); + CO_alloc_break_on_fail(co->SRDO, CO_GET_CNT(SRDO), sizeof(*co->SRDO)); ON_MULTI_OD(RX_CNT_SRDO = config->CNT_SRDO * 2); ON_MULTI_OD(TX_CNT_SRDO = config->CNT_SRDO * 2); } @@ -520,10 +492,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_LSS_SLV = 0); ON_MULTI_OD(uint8_t TX_CNT_LSS_SLV = 0); if (CO_GET_CNT(LSS_SLV) == 1) { - p = calloc(1, sizeof(CO_LSSslave_t)); - if (p == NULL) break; - else co->LSSslave = (CO_LSSslave_t *)p; - mem += sizeof(CO_LSSslave_t); + CO_alloc_break_on_fail(co->LSSslave, CO_GET_CNT(LSS_SLV), sizeof(*co->LSSslave)); ON_MULTI_OD(RX_CNT_LSS_SLV = 1); ON_MULTI_OD(TX_CNT_LSS_SLV = 1); } @@ -533,10 +502,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_LSS_MST = 0); ON_MULTI_OD(uint8_t TX_CNT_LSS_MST = 0); if (CO_GET_CNT(LSS_MST) == 1) { - p = calloc(1, sizeof(CO_LSSmaster_t)); - if (p == NULL) break; - else co->LSSmaster = (CO_LSSmaster_t *)p; - mem += sizeof(CO_LSSmaster_t); + CO_alloc_break_on_fail(co->LSSmaster, CO_GET_CNT(LSS_MST), sizeof(*co->LSSmaster)); ON_MULTI_OD(RX_CNT_LSS_MST = 1); ON_MULTI_OD(TX_CNT_LSS_MST = 1); } @@ -544,19 +510,13 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII if (CO_GET_CNT(GTWA) == 1) { - p = calloc(1, sizeof(CO_GTWA_t)); - if (p == NULL) break; - else co->gtwa = (CO_GTWA_t *)p; - mem += sizeof(CO_GTWA_t); + CO_alloc_break_on_fail(co->gtwa, CO_GET_CNT(GTWA), sizeof(*co->gtwa)); } #endif #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE if (CO_GET_CNT(TRACE) > 0) { - p = calloc(CO_GET_CNT(TRACE), sizeof(CO_trace_t)); - if (p == NULL) break; - else co->trace = (CO_trace_t *)p; - mem += sizeof(CO_trace_t) * CO_GET_CNT(TRACE); + CO_alloc_break_on_fail(co->trace, CO_GET_CNT(TRACE), sizeof(*co->trace)); } #endif @@ -630,28 +590,25 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #endif /* #ifdef CO_MULTIPLE_OD */ /* CANmodule */ - p = calloc(1, sizeof(CO_CANmodule_t)); - if (p == NULL) break; - else co->CANmodule = (CO_CANmodule_t *)p; - mem += sizeof(CO_CANmodule_t); - p = calloc(CO_GET_CO(CNT_ALL_RX_MSGS), sizeof(CO_CANrx_t)); - if (p == NULL) break; - else co->CANrx = (CO_CANrx_t *)p; - mem += sizeof(CO_CANrx_t) * CO_GET_CO(CNT_ALL_RX_MSGS); - p = calloc(CO_GET_CO(CNT_ALL_TX_MSGS), sizeof(CO_CANtx_t)); - if (p == NULL) break; - else co->CANtx = (CO_CANtx_t *)p; - mem += sizeof(CO_CANtx_t) * CO_GET_CO(CNT_ALL_TX_MSGS); + CO_alloc_break_on_fail(co->CANmodule, 1, sizeof(*co->CANmodule)); + + /* CAN RX blocks */ + CO_alloc_break_on_fail(co->CANrx, CO_GET_CO(CNT_ALL_RX_MSGS), sizeof(*co->CANrx)); + + /* CAN TX blocks */ + CO_alloc_break_on_fail(co->CANtx, CO_GET_CO(CNT_ALL_TX_MSGS), sizeof(*co->CANtx)); /* finish successfully, set other parameters */ co->nodeIdUnconfigured = true; coFinal = co; - } while(false); - - if (coFinal == NULL) CO_delete(co); - - if (heapMemoryUsed != NULL) *heapMemoryUsed = mem; + } while (false); + if (coFinal == NULL) { + CO_delete(co); + } + if (heapMemoryUsed != NULL) { + *heapMemoryUsed = mem; + } return coFinal; } @@ -663,53 +620,53 @@ void CO_delete(CO_t *co) { CO_CANmodule_disable(co->CANmodule); /* CANmodule */ - free(co->CANtx); - free(co->CANrx); - free(co->CANmodule); + CO_free(co->CANtx); + CO_free(co->CANrx); + CO_free(co->CANmodule); #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE - free(co->trace); + CO_free(co->trace); #endif #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII - free(co->gtwa); + CO_free(co->gtwa); #endif #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER - free(co->LSSmaster); + CO_free(co->LSSmaster); #endif #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - free(co->LSSslave); + CO_free(co->LSSslave); #endif #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE - free(co->SRDO); - free(co->SRDOGuard); + CO_free(co->SRDO); + CO_free(co->SRDOGuard); #endif #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE - free(co->GFC); + CO_free(co->GFC); #endif #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE - free(co->LEDs); + CO_free(co->LEDs); #endif #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE - free(co->TPDO); + CO_free(co->TPDO); #endif #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE - free(co->RPDO); + CO_free(co->RPDO); #endif #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE - free(co->SYNC); + CO_free(co->SYNC); #endif #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE - free(co->TIME); + CO_free(co->TIME); #endif #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE @@ -717,24 +674,24 @@ void CO_delete(CO_t *co) { #endif /* SDOserver */ - free(co->SDOserver); + CO_free(co->SDOserver); /* Emergency */ - free(co->em); + CO_free(co->em); #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) - free(co->em_fifo); + CO_free(co->em_fifo); #endif #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE - free(co->HBconsMonitoredNodes); - free(co->HBcons); + CO_free(co->HBconsMonitoredNodes); + CO_free(co->HBcons); #endif /* NMT_Heartbeat */ - free(co->NMT); + CO_free(co->NMT); /* CANopen object */ - free(co); + CO_free(co); } #endif /* #ifndef CO_USE_GLOBALS */ From a5fb680c6c67f9d14e33d19924c7630dc844dfd8 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 30 Aug 2021 07:28:20 +0200 Subject: [PATCH 215/520] Recommended C style and coding rules --- README.md | 3 +-- codingStyle | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 29352160..a041dd2c 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,7 @@ Report issues on https://github.com/CANopenNode/CANopenNode/issues Older discussion group is on Sourceforge: http://sourceforge.net/p/canopennode/discussion/387151/ -Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Some basic formatting -rules should be followed: Linux style with indentation of 4 spaces. There is also a `codingStyle` file with example and a configuration file for `clang-format` tool. +Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Please follow the [Recommended C style and coding rules](https://github.com/MaJerle/c-code-style), like indentation of 4 spaces, etc. There is also a `codingStyle` file with example. CANopenNode flowchart diff --git a/codingStyle b/codingStyle index a2dde73a..94467f44 100644 --- a/codingStyle +++ b/codingStyle @@ -35,11 +35,11 @@ extern "C" { * body at the end. * * ###Style - * - Style is based on Linux style - * - Indent size is 4. - * - Spaces are used, not tabs. - * - More datails are defined in .clang-format file - * - Some (old) code is still not corectly formatted. (To not break git history.) + * - Style is based on https://github.com/MaJerle/c-code-style + * - Indent size is 4 spaces, no tabs. + * - Line width is 80 characters. + * - Some (old) code may not be formatted according to the rules. Try to avoid + * unnecessary changes based on individual taste. * * ###Doxygen * Documentation is generated by doxygen. From 18bac27516d644dda1e296e2eaa51dafb59340fb Mon Sep 17 00:00:00 2001 From: gotocoffee Date: Tue, 31 Aug 2021 15:53:30 +0200 Subject: [PATCH 216/520] fixed typo in sdo client SDO_C instead of SDO --- 301/CO_SDOclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 77979db4..52c93c8f 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -195,7 +195,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, /* SDO client must not be valid when changing COB_ID */ if ((COB_ID & 0x3FFFF800) != 0 - || (valid && SDO->valid && CAN_ID != CAN_ID_cur) + || (valid && SDO_C->valid && CAN_ID != CAN_ID_cur) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; @@ -215,7 +215,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, /* SDO client must not be valid when changing COB_ID */ if ((COB_ID & 0x3FFFF800) != 0 - || (valid && SDO->valid && CAN_ID != CAN_ID_cur) + || (valid && SDO_C->valid && CAN_ID != CAN_ID_cur) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; From 8c7d852902b2d307e8b91a43332c14e366641e00 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 13 Oct 2021 15:25:27 +0200 Subject: [PATCH 217/520] Update README.md Add link to CANOpenSTM32 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a041dd2c..a57a8ae4 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ Related projects - [CANopenNode.github.io](https://github.com/CANopenNode/CANopenNode.github.io): Html documentation, compiled by doxygen, for CANopenDemo, CANopenNode and other devices, available also online: https://canopennode.github.io - [CANopenEditor](https://github.com/CANopenNode/CANopenEditor): Object Dictionary editor, external GUI tool for editing CANopen Object Dictionary for custom device. It generates C source code, electronic data sheet and documentation for the device. It is a fork from [libedssharp](https://github.com/robincornelius/libedssharp). - [CANopenLinux](https://github.com/CANopenNode/CANopenLinux): CANopenNode on Linux devices. It can be a basic CANopen device or more advanced with commander functionalities. + - [CANopenSTM32](https://github.com/CANopenNode/CanOpenSTM32): CANopenNode on STM32 microcontrollers. - [CANopenPIC](https://github.com/CANopenNode/CANopenPIC): CANopenNode on PIC microcontrollers from Microchip. Works with 16-bit and 32 bit devices. Includes example for Arduino style [Max32](https://reference.digilentinc.com/reference/microprocessor/max32/start) board. - [doc/deviceSupport.md](doc/deviceSupport.md): List of other implementations of CANopenNode on different devices. From 7249ea6acdd52a53962bfe3f47b524e0be2a774f Mon Sep 17 00:00:00 2001 From: Blazej1994 <105432342+Blazej1994@users.noreply.github.com> Date: Thu, 14 Jul 2022 11:48:08 +0200 Subject: [PATCH 218/520] TPDO inhibitTime_us / evnetTime_us calculation fix Added inhibiTime and eventTime casting to uint32_t --- 301/CO_PDO.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index e79ed933..42344ccb 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -1178,8 +1178,8 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, uint16_t eventTime = 0; odRet = OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); odRet = OD_get_u16(OD_18xx_TPDOCommPar, 5, &eventTime, true); - TPDO->inhibitTime_us = inhibitTime * 100; - TPDO->eventTime_us = eventTime * 1000; + TPDO->inhibitTime_us = (uint32_t)inhibitTime * 100; + TPDO->eventTime_us = (uint32_t)eventTime * 1000; #endif From 2c97ff7f4cf2b4410733d133e37d3c7111f6eb1c Mon Sep 17 00:00:00 2001 From: Chris Burghart Date: Mon, 18 Jul 2022 10:37:47 -0600 Subject: [PATCH 219/520] Fix a small typo --- doc/objectDictionary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 949ebcba..cd77f763 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -87,7 +87,7 @@ void myFuncGlob(void) { Object Dictionary Example {#object-dictionary-example} ------------------------------------------------------ -Actual Object dictionary for one CANopen device is defined by pair of OD_xyz.h and ODxyz.h files. +Actual Object dictionary for one CANopen device is defined by pair of OD_xyz.h and ODxyz.c files. Suffix "xyz" is unique name of the object dictionary. If single default object dictionary is used, suffix is omitted. Such way configuration with multiple object dictionaries is possible. From 1128bbbaf96774c178d140c2de9ab5adf86b8a85 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 3 Dec 2022 00:08:13 +0100 Subject: [PATCH 220/520] Wrong conditional compilation #420, fixed --- 301/CO_PDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 42344ccb..1a677c72 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -897,7 +897,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, CO_EMC_RPDO_TIMEOUT, RPDO->timeoutTimer); } } - #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT + #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL && RPDO->timeoutTimer < RPDO->timeoutTime_us ) { From d4393e4cc679dfbef696470fa81d6697eb0216eb Mon Sep 17 00:00:00 2001 From: ttmut Date: Thu, 2 Feb 2023 10:44:21 +0300 Subject: [PATCH 221/520] Add Analog Devices MAX32xxx support Add support for Analog Devices MAX32662 and MAX32690 microcontrollers. --- doc/deviceSupport.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index a8a65860..cea652f9 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -44,6 +44,18 @@ PIC32, dsPIC30, dsPIC33 * Information updated 2021-05-07 +MAX32662, MAX32690 +------------------ +* CANopenNode integration with Analog Devices MAX32662 and MAX32690 microcontrollers. +* https://github.com/Analog-Devices-MSDK/CANopenADI +* CANopenNode version: (v4.0) +* Status: seems to be stable +* Features: LED indicators, error counters +* Development tools: Maxim Micros SDK +* Demo hardware: MAX32662-EVKIT and MAX32690-EVKIT +* Information updated 2023-02-02 + + Zephyr RTOS ----------- * CANopenNode integration with Zephyr RTOS From ce9f99950dece08a56e0383a2207f4a5dce1436e Mon Sep 17 00:00:00 2001 From: ttmut Date: Mon, 13 Feb 2023 15:34:27 +0300 Subject: [PATCH 222/520] Update information on Analog Devices MAX32xxx MCUs --- doc/deviceSupport.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index cea652f9..675b492a 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -3,7 +3,7 @@ Device Support CANopenNode can run on many different devices. There are possible many different implementations on many different hardware, with many different development tools, by many different developers. It is not possible for single project maintainer to keep all the hardware interfaces updated. For that reason all hardware specific files are not part of the CANopenNode project. -It is necessary to implement interface to specific hardware. Interface to Linux socketCAN is part of this projects. Interfaces to other controllers are separate projects. There are interfaces to: Zephyr RTOS, PIC, Mbed-os RTOS + STM32, NXP, etc. +It is necessary to implement interface to specific hardware. Interface to Linux socketCAN is part of this projects. Interfaces to other controllers are separate projects. There are interfaces to: Zephyr RTOS, PIC, Analog Devices Inc. (ADI), Mbed-os RTOS + STM32, NXP, etc. Note for device driver contributors @@ -44,7 +44,7 @@ PIC32, dsPIC30, dsPIC33 * Information updated 2021-05-07 -MAX32662, MAX32690 +[Analog Devices Inc](https://www.analog.com): MAX32662, MAX32690 ------------------ * CANopenNode integration with Analog Devices MAX32662 and MAX32690 microcontrollers. * https://github.com/Analog-Devices-MSDK/CANopenADI @@ -53,7 +53,7 @@ MAX32662, MAX32690 * Features: LED indicators, error counters * Development tools: Maxim Micros SDK * Demo hardware: MAX32662-EVKIT and MAX32690-EVKIT -* Information updated 2023-02-02 +* Information updated 2023-02-13 Zephyr RTOS From 4c86a61342ab4fd10b15ae075299e77fca7d1e07 Mon Sep 17 00:00:00 2001 From: "ankit.chudasama1" Date: Thu, 16 Feb 2023 19:24:10 +0530 Subject: [PATCH 223/520] Fix variable name and use of pointer for big endian system 1. Variable name update in CO_PDO.c file 2. Correct use of pointer in the CO_SDOserver.c file --- 301/CO_PDO.c | 4 ++-- 301/CO_SDOserver.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 1a677c72..831f5165 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -1266,8 +1266,8 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { /* swap multibyte data if big-endian */ #ifdef CO_BIG_ENDIAN if ((stream->attribute & ODA_MB) != 0) { - uint8_t *lo = dataOD; - uint8_t *hi = dataOD + ODdataLength - 1; + uint8_t *lo = dataTPDOCopy; + uint8_t *hi = dataTPDOCopy + ODdataLength - 1; while (lo < hi) { uint8_t swap = *lo; *lo++ = *hi; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 186a40a8..090d1e9f 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -661,7 +661,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, reverseBytes(bufShifted, countRd); } else { - abortCode = CO_SDO_AB_PRAM_INCOMPAT; + *abortCode = CO_SDO_AB_PRAM_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; return false; } From 4d7afa6fa3907cff7d1ae04ad1a281ac61aa6b25 Mon Sep 17 00:00:00 2001 From: ttmut Date: Fri, 17 Feb 2023 13:28:31 +0300 Subject: [PATCH 224/520] Add link to ADI homepage --- doc/deviceSupport.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index 675b492a..49719f6a 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -3,7 +3,7 @@ Device Support CANopenNode can run on many different devices. There are possible many different implementations on many different hardware, with many different development tools, by many different developers. It is not possible for single project maintainer to keep all the hardware interfaces updated. For that reason all hardware specific files are not part of the CANopenNode project. -It is necessary to implement interface to specific hardware. Interface to Linux socketCAN is part of this projects. Interfaces to other controllers are separate projects. There are interfaces to: Zephyr RTOS, PIC, Analog Devices Inc. (ADI), Mbed-os RTOS + STM32, NXP, etc. +It is necessary to implement interface to specific hardware. Interface to Linux socketCAN is part of this projects. Interfaces to other controllers are separate projects. There are interfaces to: Zephyr RTOS, PIC, [Analog Devices Inc. (ADI)](https://www.analog.com), Mbed-os RTOS + STM32, NXP, etc. Note for device driver contributors @@ -53,7 +53,7 @@ PIC32, dsPIC30, dsPIC33 * Features: LED indicators, error counters * Development tools: Maxim Micros SDK * Demo hardware: MAX32662-EVKIT and MAX32690-EVKIT -* Information updated 2023-02-13 +* Information updated 2023-02-17 Zephyr RTOS From d8a637dbc549de280af19285198080d5e9c7a283 Mon Sep 17 00:00:00 2001 From: mlout Date: Thu, 16 Mar 2023 14:09:01 +0100 Subject: [PATCH 225/520] Add CO_CONFIG_FLAG_ALWAYS_LOCK_OD to always lock OD Add CO_CONFIG_FLAG_ALWAYS_LOCK_OD which can be used to lock the OD for every SDO read/write operation. Modify the code in CO_SDOserver.c and CO_SDOclient.c to check this config flag. --- 301/CO_SDOclient.c | 8 ++++++++ 301/CO_SDOserver.c | 18 +++++++++++++++++- 301/CO_config.h | 20 +++++++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 52c93c8f..1f46b014 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -621,7 +621,11 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } if (abortCode == CO_SDO_AB_NONE) { OD_size_t countWritten = 0; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD + const bool_t lock = true; +#else bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); +#endif /* write data to Object Dictionary */ if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } @@ -1214,7 +1218,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD + const bool_t lock = true; +#else bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); +#endif /* load data from OD variable into the buffer */ if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 090d1e9f..6455bb56 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -551,9 +551,13 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, /* write data */ OD_size_t countWritten = 0; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD + const bool_t lock = true; +#else bool_t lock = OD_mappable(&SDO->OD_IO.stream); - +#endif if (lock) { CO_LOCK_OD(SDO->CANdevTx); } + ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, SDO->bufOffsetWr, &countWritten); if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } @@ -613,7 +617,11 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* load data from OD variable into the buffer */ OD_size_t countRd = 0; uint8_t *bufShifted = SDO->buf + countRemain; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD + const bool_t lock = true; +#else bool_t lock = OD_mappable(&SDO->OD_IO.stream); +#endif if (lock) { CO_LOCK_OD(SDO->CANdevTx); } ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, bufShifted, @@ -850,7 +858,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Copy data */ OD_size_t countWritten = 0; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD + const bool_t lock = true; +#else bool_t lock = OD_mappable(&SDO->OD_IO.stream); +#endif if (lock) { CO_LOCK_OD(SDO->CANdevTx); } ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, @@ -1299,7 +1311,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #else /* Expedited transfer only */ /* load data from OD variable */ OD_size_t count = 0; +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD + const bool_t lock = true; +#else bool_t lock = OD_mappable(&SDO->OD_IO.stream); +#endif if (lock) { CO_LOCK_OD(SDO->CANdevTx); } ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, diff --git a/301/CO_config.h b/301/CO_config.h index a8093258..10fa997e 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -100,6 +100,17 @@ extern "C" { */ #define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000 +/** + * Always lock the Object Dictionary using the CO_LOCK_OD / CO_UNLOCK_OD macros + * + * By default the Object Dictionary is only locked if a Object Dictionary variable + * is mappable to a PDO or SRDO. If your application uses a RTOS with multiple tasks + * using the Object Dictionary, you want to lock the Object Dictionary on every read/write. + * + * This flag is common to multiple configuration macros. + */ +#define CO_CONFIG_FLAG_ALWAYS_LOCK_OD 0x8000 + /** This flag may be set globally for mainline objects to * @ref CO_CONFIG_FLAG_CALLBACK_PRE */ #ifdef CO_DOXYGEN @@ -121,6 +132,11 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC CO_CONFIG_FLAG_OD_DYNAMIC #endif + +/** This flag may be set globally to @ref CO_CONFIG_FLAG_ALWAYS_LOCK_OD */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_GLOBAL_FLAG_ALWAYS_LOCK_OD (0) +#endif /** @} */ /* CO_STACK_CONFIG_COMMON */ @@ -329,9 +345,10 @@ extern "C" { * inside CO_SDOserver_process(). * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of additional SDO * servers (Writing to object 0x1201+ re-configures the additional server). + * - #CO_CONFIG_FLAG_ALWAYS_LOCK_OD - Always lock object dictionary (regardless if OD var is PDO/SRDO mappable) */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC | CO_CONFIG_GLOBAL_FLAG_ALWAYS_LOCK_OD) #endif #define CO_CONFIG_SDO_SRV_SEGMENTED 0x02 #define CO_CONFIG_SDO_SRV_BLOCK 0x04 @@ -367,6 +384,7 @@ extern "C" { * CO_SDOclientUploadInitiate(), CO_SDOclientUpload(). * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of SDO clients * (Writing to object 0x1280+ re-configures the client). + * - #CO_CONFIG_FLAG_ALWAYS_LOCK_OD - Always lock object dictionary (regardless if OD var is PDO/SRDO mappable) */ #ifdef CO_DOXYGEN #define CO_CONFIG_SDO_CLI (0) From 900ab00a79d10fd61fb53cc46d38fcb863b29053 Mon Sep 17 00:00:00 2001 From: mlout Date: Thu, 16 Mar 2023 14:19:07 +0100 Subject: [PATCH 226/520] Rename CO_CONFIG_FLAG_ALWAYS_LOCK_OD to CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD --- 301/CO_SDOclient.c | 4 ++-- 301/CO_SDOserver.c | 8 ++++---- 301/CO_config.h | 17 +++++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 1f46b014..4a1b93f8 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -621,7 +621,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } if (abortCode == CO_SDO_AB_NONE) { OD_size_t countWritten = 0; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD const bool_t lock = true; #else bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); @@ -1218,7 +1218,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD +#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD const bool_t lock = true; #else bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 6455bb56..92476571 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -551,7 +551,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, /* write data */ OD_size_t countWritten = 0; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD const bool_t lock = true; #else bool_t lock = OD_mappable(&SDO->OD_IO.stream); @@ -617,7 +617,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* load data from OD variable into the buffer */ OD_size_t countRd = 0; uint8_t *bufShifted = SDO->buf + countRemain; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD const bool_t lock = true; #else bool_t lock = OD_mappable(&SDO->OD_IO.stream); @@ -858,7 +858,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Copy data */ OD_size_t countWritten = 0; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD const bool_t lock = true; #else bool_t lock = OD_mappable(&SDO->OD_IO.stream); @@ -1311,7 +1311,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #else /* Expedited transfer only */ /* load data from OD variable */ OD_size_t count = 0; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_ALWAYS_LOCK_OD +#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD const bool_t lock = true; #else bool_t lock = OD_mappable(&SDO->OD_IO.stream); diff --git a/301/CO_config.h b/301/CO_config.h index 10fa997e..fbebd8b2 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -101,15 +101,16 @@ extern "C" { #define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000 /** - * Always lock the Object Dictionary using the CO_LOCK_OD / CO_UNLOCK_OD macros + * Always lock the Object Dictionary when doing a SDO read/write * * By default the Object Dictionary is only locked if a Object Dictionary variable - * is mappable to a PDO or SRDO. If your application uses a RTOS with multiple tasks - * using the Object Dictionary, you want to lock the Object Dictionary on every read/write. + * is mappable to a PDO or SRDO. If your application uses a RTOS with multiple + * tasks accessing the Object Dictionary, you want to lock the Object Dictionary on + * every SDO read/write. * * This flag is common to multiple configuration macros. */ -#define CO_CONFIG_FLAG_ALWAYS_LOCK_OD 0x8000 +#define CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD 0x8000 /** This flag may be set globally for mainline objects to * @ref CO_CONFIG_FLAG_CALLBACK_PRE */ @@ -133,9 +134,9 @@ extern "C" { #define CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC CO_CONFIG_FLAG_OD_DYNAMIC #endif -/** This flag may be set globally to @ref CO_CONFIG_FLAG_ALWAYS_LOCK_OD */ +/** This flag may be set globally to @ref CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD */ #ifdef CO_DOXYGEN -#define CO_CONFIG_GLOBAL_FLAG_ALWAYS_LOCK_OD (0) +#define CO_CONFIG_GLOBAL_FLAG_SDO_ALWAYS_LOCK_OD (0) #endif /** @} */ /* CO_STACK_CONFIG_COMMON */ @@ -345,7 +346,7 @@ extern "C" { * inside CO_SDOserver_process(). * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of additional SDO * servers (Writing to object 0x1201+ re-configures the additional server). - * - #CO_CONFIG_FLAG_ALWAYS_LOCK_OD - Always lock object dictionary (regardless if OD var is PDO/SRDO mappable) + * - #CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - Always lock object dictionary (regardless if OD var is PDO/SRDO mappable) */ #ifdef CO_DOXYGEN #define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC | CO_CONFIG_GLOBAL_FLAG_ALWAYS_LOCK_OD) @@ -384,7 +385,7 @@ extern "C" { * CO_SDOclientUploadInitiate(), CO_SDOclientUpload(). * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of SDO clients * (Writing to object 0x1280+ re-configures the client). - * - #CO_CONFIG_FLAG_ALWAYS_LOCK_OD - Always lock object dictionary (regardless if OD var is PDO/SRDO mappable) + * - #CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - Always lock object dictionary (regardless if OD var is PDO/SRDO mappable) */ #ifdef CO_DOXYGEN #define CO_CONFIG_SDO_CLI (0) From fcd552ef9692adf30f250f9a00e5aed44561d735 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 17 Mar 2023 13:15:10 +0100 Subject: [PATCH 227/520] example: update files with the latest CANopenEditor (v4.1-1) DS301_profile.xpd/.eds: "$NODEID" now appears at the beginning of the expression. OD.h/.c: difference in C variable names generator. --- example/DS301_profile.eds | 28 ++--- example/DS301_profile.md | 28 ++--- example/DS301_profile.xpd | 28 ++--- example/OD.c | 258 +++++++++++++++++++------------------- example/OD.h | 134 ++++++++++---------- 5 files changed, 238 insertions(+), 238 deletions(-) diff --git a/example/DS301_profile.eds b/example/DS301_profile.eds index 1e598e8e..f203a8c3 100644 --- a/example/DS301_profile.eds +++ b/example/DS301_profile.eds @@ -5,11 +5,11 @@ FileRevision=1 LastEDS= EDSVersion=4.0 Description= -CreationTime=1:00PM +CreationTime=12:00PM CreationDate=11-23-2020 CreatedBy= -ModificationTime=6:39PM -ModificationDate=08-09-2021 +ModificationTime=2:07AM +ModificationDate=03-17-2023 ModifiedBy= [DeviceInfo] @@ -459,7 +459,7 @@ ObjectType=0x7 ;StorageLocation=PERSIST_COMM DataType=0x0007 AccessType=rw -DefaultValue=0x80+$NODEID +DefaultValue=$NODEID+0x80 PDOMapping=0 [1015] @@ -597,7 +597,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x600+$NODEID +DefaultValue=$NODEID+0x600 PDOMapping=1 [1200sub2] @@ -606,7 +606,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=ro -DefaultValue=0x580+$NODEID +DefaultValue=$NODEID+0x580 PDOMapping=1 [1280] @@ -672,7 +672,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=rw -DefaultValue=0x80000200+$NODEID +DefaultValue=$NODEID+0x80000200 PDOMapping=0 [1400sub2] @@ -714,7 +714,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=rw -DefaultValue=0x80000300+$NODEID +DefaultValue=$NODEID+0x80000300 PDOMapping=0 [1401sub2] @@ -756,7 +756,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=rw -DefaultValue=0x80000400+$NODEID +DefaultValue=$NODEID+0x80000400 PDOMapping=0 [1402sub2] @@ -798,7 +798,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=rw -DefaultValue=0x80000500+$NODEID +DefaultValue=$NODEID+0x80000500 PDOMapping=0 [1403sub2] @@ -1188,7 +1188,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=rw -DefaultValue=0xC0000180+$NODEID +DefaultValue=$NODEID+0xC0000180 PDOMapping=0 [1800sub2] @@ -1248,7 +1248,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=rw -DefaultValue=0xC0000280+$NODEID +DefaultValue=$NODEID+0xC0000280 PDOMapping=0 [1801sub2] @@ -1308,7 +1308,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=rw -DefaultValue=0xC0000380+$NODEID +DefaultValue=$NODEID+0xC0000380 PDOMapping=0 [1802sub2] @@ -1368,7 +1368,7 @@ ObjectType=0x7 ;StorageLocation=RAM DataType=0x0007 AccessType=rw -DefaultValue=0xC0000480+$NODEID +DefaultValue=$NODEID+0xC0000480 PDOMapping=0 [1803sub2] diff --git a/example/DS301_profile.md b/example/DS301_profile.md index ac5d1c7c..7d1b504b 100644 --- a/example/DS301_profile.md +++ b/example/DS301_profile.md @@ -8,12 +8,12 @@ CANopen device documentation | ------------ | ------------------------------ | | Project File | DS301_profile.xpd | | File Version | 1 | -| Created | 23. 11. 2020 13:00:00 | +| Created | 23. 11. 2020 12:00:00 | | Created By | | -| Modified | 9. 08. 2021 18:39:55 | +| Modified | 17. 03. 2023 02:07:28 | | Modified By | | -This file was automatically generated by [CANopenEditor](https://github.com/CANopenNode/CANopenEditor) v4.0-51-g2d9b1ad +This file was automatically generated by [CANopenEditor](https://github.com/CANopenNode/CANopenEditor) v4.1-1-ga49a51a [TOC] @@ -204,7 +204,7 @@ Sub-indexes 1 and above: | Data Type | SDO | PDO | SRDO | Default Value | | ----------------------- | --- | --- | ---- | ------------------------------- | -| UNSIGNED32 | rw | no | no | 0x80+$NODEID | +| UNSIGNED32 | rw | no | no | $NODEID+0x80 | * bit 31: If set, EMCY does NOT exist / is NOT valid * bit 11-30: set to 0 @@ -296,8 +296,8 @@ Heartbeat producer time in ms (0 = disable transmission). | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 2 | -| 0x01 | COB-ID client to server (rx)| UNSIGNED32 | ro | t | no | 0x600+$NODEID | -| 0x02 | COB-ID server to client (tx)| UNSIGNED32 | ro | t | no | 0x580+$NODEID | +| 0x01 | COB-ID client to server (rx)| UNSIGNED32 | ro | t | no | $NODEID+0x600 | +| 0x02 | COB-ID server to client (tx)| UNSIGNED32 | ro | t | no | $NODEID+0x580 | Sub-indexes 1 and 2: * bit 11-31: set to 0 @@ -330,7 +330,7 @@ Sub-indexes 1 and 2: | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | -| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000200+$NODEID| +| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | $NODEID+0x80000200| | 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | | 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | @@ -353,7 +353,7 @@ Sub-indexes 1 and 2: | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | -| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000300+$NODEID| +| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | $NODEID+0x80000300| | 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | | 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | @@ -376,7 +376,7 @@ Sub-indexes 1 and 2: | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | -| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000400+$NODEID| +| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | $NODEID+0x80000400| | 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | | 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | @@ -399,7 +399,7 @@ Sub-indexes 1 and 2: | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x05 | -| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | 0x80000500+$NODEID| +| 0x01 | COB-ID used by RPDO | UNSIGNED32 | rw | no | no | $NODEID+0x80000500| | 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | | 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | @@ -526,7 +526,7 @@ Sub-indexes 1 and 2: | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | -| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000180+$NODEID| +| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | $NODEID+0xC0000180| | 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | | 0x03 | Inhibit time | UNSIGNED16 | rw | no | no | 0 | | 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | @@ -557,7 +557,7 @@ Sub-indexes 1 and 2: | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | -| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000280+$NODEID| +| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | $NODEID+0xC0000280| | 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | | 0x03 | Inhibit time | UNSIGNED16 | rw | no | no | 0 | | 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | @@ -588,7 +588,7 @@ Sub-indexes 1 and 2: | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | -| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000380+$NODEID| +| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | $NODEID+0xC0000380| | 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | | 0x03 | Inhibit time | UNSIGNED16 | rw | no | no | 0 | | 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | @@ -619,7 +619,7 @@ Sub-indexes 1 and 2: | Sub | Name | Data Type | SDO | PDO | SRDO | Default Value | | ---- | --------------------- | ---------- | --- | --- | ---- | ------------- | | 0x00 | Highest sub-index supported| UNSIGNED8 | ro | no | no | 0x06 | -| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | 0xC0000480+$NODEID| +| 0x01 | COB-ID used by TPDO | UNSIGNED32 | rw | no | no | $NODEID+0xC0000480| | 0x02 | Transmission type | UNSIGNED8 | rw | no | no | 254 | | 0x03 | Inhibit time | UNSIGNED16 | rw | no | no | 0 | | 0x05 | Event timer | UNSIGNED16 | rw | no | no | 0 | diff --git a/example/DS301_profile.xpd b/example/DS301_profile.xpd index 913bd715..26f22454 100644 --- a/example/DS301_profile.xpd +++ b/example/DS301_profile.xpd @@ -1,5 +1,5 @@ - + @@ -15,7 +15,7 @@ CANopen - + @@ -856,7 +856,7 @@ * bit 11-30: set to 0 * bit 0-10: 11-bit CAN-ID - + @@ -1186,12 +1186,12 @@ - + - + * Sub-indexes 1 and 2: @@ -1279,7 +1279,7 @@ - + @@ -1314,7 +1314,7 @@ - + @@ -1349,7 +1349,7 @@ - + @@ -1384,7 +1384,7 @@ - + @@ -1747,7 +1747,7 @@ - + @@ -1798,7 +1798,7 @@ - + @@ -1849,7 +1849,7 @@ - + @@ -1900,7 +1900,7 @@ - + @@ -2277,7 +2277,7 @@ CANopen - + diff --git a/example/OD.c b/example/OD.c index ac19ef37..7db61075 100644 --- a/example/OD.c +++ b/example/OD.c @@ -1,7 +1,7 @@ /******************************************************************************* CANopen Object Dictionary definition for CANopenNode V4 - This file was automatically generated by CANopenEditor v4.0-51-g2d9b1ad + This file was automatically generated by CANopenEditor v4.1-1-ga49a51a https://github.com/CANopenNode/CANopenNode https://github.com/CANopenNode/CANopenEditor @@ -71,47 +71,47 @@ OD_ATTR_PERSIST_COMM OD_PERSIST_COMM_t OD_PERSIST_COMM = { }, .x1600_RPDOMappingParameter = { .numberOfMappedApplicationObjectsInPDO = 0x00, - .applicationObject_1 = 0x00000000, - .applicationObject_2 = 0x00000000, - .applicationObject_3 = 0x00000000, - .applicationObject_4 = 0x00000000, - .applicationObject_5 = 0x00000000, - .applicationObject_6 = 0x00000000, - .applicationObject_7 = 0x00000000, - .applicationObject_8 = 0x00000000 + .applicationObject1 = 0x00000000, + .applicationObject2 = 0x00000000, + .applicationObject3 = 0x00000000, + .applicationObject4 = 0x00000000, + .applicationObject5 = 0x00000000, + .applicationObject6 = 0x00000000, + .applicationObject7 = 0x00000000, + .applicationObject8 = 0x00000000 }, .x1601_RPDOMappingParameter = { .numberOfMappedApplicationObjectsInPDO = 0x00, - .applicationObject_1 = 0x00000000, - .applicationObject_2 = 0x00000000, - .applicationObject_3 = 0x00000000, - .applicationObject_4 = 0x00000000, - .applicationObject_5 = 0x00000000, - .applicationObject_6 = 0x00000000, - .applicationObject_7 = 0x00000000, - .applicationObject_8 = 0x00000000 + .applicationObject1 = 0x00000000, + .applicationObject2 = 0x00000000, + .applicationObject3 = 0x00000000, + .applicationObject4 = 0x00000000, + .applicationObject5 = 0x00000000, + .applicationObject6 = 0x00000000, + .applicationObject7 = 0x00000000, + .applicationObject8 = 0x00000000 }, .x1602_RPDOMappingParameter = { .numberOfMappedApplicationObjectsInPDO = 0x00, - .applicationObject_1 = 0x00000000, - .applicationObject_2 = 0x00000000, - .applicationObject_3 = 0x00000000, - .applicationObject_4 = 0x00000000, - .applicationObject_5 = 0x00000000, - .applicationObject_6 = 0x00000000, - .applicationObject_7 = 0x00000000, - .applicationObject_8 = 0x00000000 + .applicationObject1 = 0x00000000, + .applicationObject2 = 0x00000000, + .applicationObject3 = 0x00000000, + .applicationObject4 = 0x00000000, + .applicationObject5 = 0x00000000, + .applicationObject6 = 0x00000000, + .applicationObject7 = 0x00000000, + .applicationObject8 = 0x00000000 }, .x1603_RPDOMappingParameter = { .numberOfMappedApplicationObjectsInPDO = 0x00, - .applicationObject_1 = 0x00000000, - .applicationObject_2 = 0x00000000, - .applicationObject_3 = 0x00000000, - .applicationObject_4 = 0x00000000, - .applicationObject_5 = 0x00000000, - .applicationObject_6 = 0x00000000, - .applicationObject_7 = 0x00000000, - .applicationObject_8 = 0x00000000 + .applicationObject1 = 0x00000000, + .applicationObject2 = 0x00000000, + .applicationObject3 = 0x00000000, + .applicationObject4 = 0x00000000, + .applicationObject5 = 0x00000000, + .applicationObject6 = 0x00000000, + .applicationObject7 = 0x00000000, + .applicationObject8 = 0x00000000 }, .x1800_TPDOCommunicationParameter = { .highestSub_indexSupported = 0x06, @@ -147,47 +147,47 @@ OD_ATTR_PERSIST_COMM OD_PERSIST_COMM_t OD_PERSIST_COMM = { }, .x1A00_TPDOMappingParameter = { .numberOfMappedApplicationObjectsInPDO = 0x00, - .applicationObject_1 = 0x00000000, - .applicationObject_2 = 0x00000000, - .applicationObject_3 = 0x00000000, - .applicationObject_4 = 0x00000000, - .applicationObject_5 = 0x00000000, - .applicationObject_6 = 0x00000000, - .applicationObject_7 = 0x00000000, - .applicationObject_8 = 0x00000000 + .applicationObject1 = 0x00000000, + .applicationObject2 = 0x00000000, + .applicationObject3 = 0x00000000, + .applicationObject4 = 0x00000000, + .applicationObject5 = 0x00000000, + .applicationObject6 = 0x00000000, + .applicationObject7 = 0x00000000, + .applicationObject8 = 0x00000000 }, .x1A01_TPDOMappingParameter = { .numberOfMappedApplicationObjectsInPDO = 0x00, - .applicationObject_1 = 0x00000000, - .applicationObject_2 = 0x00000000, - .applicationObject_3 = 0x00000000, - .applicationObject_4 = 0x00000000, - .applicationObject_5 = 0x00000000, - .applicationObject_6 = 0x00000000, - .applicationObject_7 = 0x00000000, - .applicationObject_8 = 0x00000000 + .applicationObject1 = 0x00000000, + .applicationObject2 = 0x00000000, + .applicationObject3 = 0x00000000, + .applicationObject4 = 0x00000000, + .applicationObject5 = 0x00000000, + .applicationObject6 = 0x00000000, + .applicationObject7 = 0x00000000, + .applicationObject8 = 0x00000000 }, .x1A02_TPDOMappingParameter = { .numberOfMappedApplicationObjectsInPDO = 0x00, - .applicationObject_1 = 0x00000000, - .applicationObject_2 = 0x00000000, - .applicationObject_3 = 0x00000000, - .applicationObject_4 = 0x00000000, - .applicationObject_5 = 0x00000000, - .applicationObject_6 = 0x00000000, - .applicationObject_7 = 0x00000000, - .applicationObject_8 = 0x00000000 + .applicationObject1 = 0x00000000, + .applicationObject2 = 0x00000000, + .applicationObject3 = 0x00000000, + .applicationObject4 = 0x00000000, + .applicationObject5 = 0x00000000, + .applicationObject6 = 0x00000000, + .applicationObject7 = 0x00000000, + .applicationObject8 = 0x00000000 }, .x1A03_TPDOMappingParameter = { .numberOfMappedApplicationObjectsInPDO = 0x00, - .applicationObject_1 = 0x00000000, - .applicationObject_2 = 0x00000000, - .applicationObject_3 = 0x00000000, - .applicationObject_4 = 0x00000000, - .applicationObject_5 = 0x00000000, - .applicationObject_6 = 0x00000000, - .applicationObject_7 = 0x00000000, - .applicationObject_8 = 0x00000000 + .applicationObject1 = 0x00000000, + .applicationObject2 = 0x00000000, + .applicationObject3 = 0x00000000, + .applicationObject4 = 0x00000000, + .applicationObject5 = 0x00000000, + .applicationObject6 = 0x00000000, + .applicationObject7 = 0x00000000, + .applicationObject8 = 0x00000000 } }; @@ -518,49 +518,49 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, { - .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1600_RPDOMappingParameter.applicationObject8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 @@ -574,49 +574,49 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, { - .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1601_RPDOMappingParameter.applicationObject8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 @@ -630,49 +630,49 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, { - .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1602_RPDOMappingParameter.applicationObject8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 @@ -686,49 +686,49 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, { - .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1603_RPDOMappingParameter.applicationObject8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 @@ -894,49 +894,49 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, { - .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1A00_TPDOMappingParameter.applicationObject8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 @@ -950,49 +950,49 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, { - .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1A01_TPDOMappingParameter.applicationObject8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 @@ -1006,49 +1006,49 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, { - .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1A02_TPDOMappingParameter.applicationObject8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 @@ -1062,49 +1062,49 @@ static CO_PROGMEM ODObjs_t ODObjs = { .dataLength = 1 }, { - .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_1, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject1, .subIndex = 1, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_2, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject2, .subIndex = 2, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_3, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject3, .subIndex = 3, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_4, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject4, .subIndex = 4, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_5, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject5, .subIndex = 5, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_6, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject6, .subIndex = 6, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_7, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject7, .subIndex = 7, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 }, { - .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject_8, + .dataOrig = &OD_PERSIST_COMM.x1A03_TPDOMappingParameter.applicationObject8, .subIndex = 8, .attribute = ODA_SDO_RW | ODA_MB, .dataLength = 4 diff --git a/example/OD.h b/example/OD.h index 6f103d68..aac9fab2 100644 --- a/example/OD.h +++ b/example/OD.h @@ -1,7 +1,7 @@ /******************************************************************************* CANopen Object Dictionary definition for CANopenNode V4 - This file was automatically generated by CANopenEditor v4.0-51-g2d9b1ad + This file was automatically generated by CANopenEditor v4.1-1-ga49a51a https://github.com/CANopenNode/CANopenNode https://github.com/CANopenNode/CANopenEditor @@ -14,9 +14,9 @@ Project File: DS301_profile.xpd File Version: 1 - Created: 23. 11. 2020 13:00:00 + Created: 23. 11. 2020 12:00:00 Created By: - Modified: 9. 08. 2021 18:39:55 + Modified: 17. 03. 2023 02:07:28 Modified By: Device Info: @@ -111,47 +111,47 @@ typedef struct { } x1403_RPDOCommunicationParameter; struct { uint8_t numberOfMappedApplicationObjectsInPDO; - uint32_t applicationObject_1; - uint32_t applicationObject_2; - uint32_t applicationObject_3; - uint32_t applicationObject_4; - uint32_t applicationObject_5; - uint32_t applicationObject_6; - uint32_t applicationObject_7; - uint32_t applicationObject_8; + uint32_t applicationObject1; + uint32_t applicationObject2; + uint32_t applicationObject3; + uint32_t applicationObject4; + uint32_t applicationObject5; + uint32_t applicationObject6; + uint32_t applicationObject7; + uint32_t applicationObject8; } x1600_RPDOMappingParameter; struct { uint8_t numberOfMappedApplicationObjectsInPDO; - uint32_t applicationObject_1; - uint32_t applicationObject_2; - uint32_t applicationObject_3; - uint32_t applicationObject_4; - uint32_t applicationObject_5; - uint32_t applicationObject_6; - uint32_t applicationObject_7; - uint32_t applicationObject_8; + uint32_t applicationObject1; + uint32_t applicationObject2; + uint32_t applicationObject3; + uint32_t applicationObject4; + uint32_t applicationObject5; + uint32_t applicationObject6; + uint32_t applicationObject7; + uint32_t applicationObject8; } x1601_RPDOMappingParameter; struct { uint8_t numberOfMappedApplicationObjectsInPDO; - uint32_t applicationObject_1; - uint32_t applicationObject_2; - uint32_t applicationObject_3; - uint32_t applicationObject_4; - uint32_t applicationObject_5; - uint32_t applicationObject_6; - uint32_t applicationObject_7; - uint32_t applicationObject_8; + uint32_t applicationObject1; + uint32_t applicationObject2; + uint32_t applicationObject3; + uint32_t applicationObject4; + uint32_t applicationObject5; + uint32_t applicationObject6; + uint32_t applicationObject7; + uint32_t applicationObject8; } x1602_RPDOMappingParameter; struct { uint8_t numberOfMappedApplicationObjectsInPDO; - uint32_t applicationObject_1; - uint32_t applicationObject_2; - uint32_t applicationObject_3; - uint32_t applicationObject_4; - uint32_t applicationObject_5; - uint32_t applicationObject_6; - uint32_t applicationObject_7; - uint32_t applicationObject_8; + uint32_t applicationObject1; + uint32_t applicationObject2; + uint32_t applicationObject3; + uint32_t applicationObject4; + uint32_t applicationObject5; + uint32_t applicationObject6; + uint32_t applicationObject7; + uint32_t applicationObject8; } x1603_RPDOMappingParameter; struct { uint8_t highestSub_indexSupported; @@ -187,47 +187,47 @@ typedef struct { } x1803_TPDOCommunicationParameter; struct { uint8_t numberOfMappedApplicationObjectsInPDO; - uint32_t applicationObject_1; - uint32_t applicationObject_2; - uint32_t applicationObject_3; - uint32_t applicationObject_4; - uint32_t applicationObject_5; - uint32_t applicationObject_6; - uint32_t applicationObject_7; - uint32_t applicationObject_8; + uint32_t applicationObject1; + uint32_t applicationObject2; + uint32_t applicationObject3; + uint32_t applicationObject4; + uint32_t applicationObject5; + uint32_t applicationObject6; + uint32_t applicationObject7; + uint32_t applicationObject8; } x1A00_TPDOMappingParameter; struct { uint8_t numberOfMappedApplicationObjectsInPDO; - uint32_t applicationObject_1; - uint32_t applicationObject_2; - uint32_t applicationObject_3; - uint32_t applicationObject_4; - uint32_t applicationObject_5; - uint32_t applicationObject_6; - uint32_t applicationObject_7; - uint32_t applicationObject_8; + uint32_t applicationObject1; + uint32_t applicationObject2; + uint32_t applicationObject3; + uint32_t applicationObject4; + uint32_t applicationObject5; + uint32_t applicationObject6; + uint32_t applicationObject7; + uint32_t applicationObject8; } x1A01_TPDOMappingParameter; struct { uint8_t numberOfMappedApplicationObjectsInPDO; - uint32_t applicationObject_1; - uint32_t applicationObject_2; - uint32_t applicationObject_3; - uint32_t applicationObject_4; - uint32_t applicationObject_5; - uint32_t applicationObject_6; - uint32_t applicationObject_7; - uint32_t applicationObject_8; + uint32_t applicationObject1; + uint32_t applicationObject2; + uint32_t applicationObject3; + uint32_t applicationObject4; + uint32_t applicationObject5; + uint32_t applicationObject6; + uint32_t applicationObject7; + uint32_t applicationObject8; } x1A02_TPDOMappingParameter; struct { uint8_t numberOfMappedApplicationObjectsInPDO; - uint32_t applicationObject_1; - uint32_t applicationObject_2; - uint32_t applicationObject_3; - uint32_t applicationObject_4; - uint32_t applicationObject_5; - uint32_t applicationObject_6; - uint32_t applicationObject_7; - uint32_t applicationObject_8; + uint32_t applicationObject1; + uint32_t applicationObject2; + uint32_t applicationObject3; + uint32_t applicationObject4; + uint32_t applicationObject5; + uint32_t applicationObject6; + uint32_t applicationObject7; + uint32_t applicationObject8; } x1A03_TPDOMappingParameter; } OD_PERSIST_COMM_t; From 4ab0bd10c1cbf751774f2c5e0551e17d516cf078 Mon Sep 17 00:00:00 2001 From: mlout Date: Fri, 17 Mar 2023 17:42:35 +0100 Subject: [PATCH 228/520] Always call OD lock macros on SDO operations --- 301/CO_SDOclient.c | 18 ++++-------------- 301/CO_SDOserver.c | 36 ++++++++---------------------------- 301/CO_config.h | 21 +-------------------- 301/CO_driver.h | 7 +++---- 4 files changed, 16 insertions(+), 66 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 4a1b93f8..a93bf005 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -621,17 +621,12 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } if (abortCode == CO_SDO_AB_NONE) { OD_size_t countWritten = 0; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - const bool_t lock = true; -#else - bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); -#endif /* write data to Object Dictionary */ - if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } + CO_LOCK_OD(SDO_C->CANdevTx); ODR_t odRet = SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, (OD_size_t)count, &countWritten); - if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } + CO_UNLOCK_OD(SDO_C->CANdevTx); /* verify for errors in write */ if (odRet != ODR_OK && odRet != ODR_PARTIAL) { @@ -1218,17 +1213,12 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - const bool_t lock = true; -#else - bool_t lock = OD_mappable(&SDO_C->OD_IO.stream); -#endif /* load data from OD variable into the buffer */ - if (lock) { CO_LOCK_OD(SDO_C->CANdevTx); } + CO_LOCK_OD(SDO_C->CANdevTx); ODR_t odRet = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, buf, countBuf, &countRd); - if (lock) { CO_UNLOCK_OD(SDO_C->CANdevTx); } + CO_UNLOCK_OD(SDO_C->CANdevTx); if (odRet != ODR_OK && odRet != ODR_PARTIAL) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 92476571..aad8619d 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -551,16 +551,11 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, /* write data */ OD_size_t countWritten = 0; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - const bool_t lock = true; -#else - bool_t lock = OD_mappable(&SDO->OD_IO.stream); -#endif - if (lock) { CO_LOCK_OD(SDO->CANdevTx); } + CO_LOCK_OD(SDO->CANdevTx); ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, SDO->bufOffsetWr, &countWritten); - if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } + CO_UNLOCK_OD(SDO->CANdevTx); SDO->bufOffsetWr = 0; @@ -617,16 +612,11 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* load data from OD variable into the buffer */ OD_size_t countRd = 0; uint8_t *bufShifted = SDO->buf + countRemain; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - const bool_t lock = true; -#else - bool_t lock = OD_mappable(&SDO->OD_IO.stream); -#endif - if (lock) { CO_LOCK_OD(SDO->CANdevTx); } + CO_LOCK_OD(SDO->CANdevTx); ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, bufShifted, countRdRequest, &countRd); - if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } + CO_UNLOCK_OD(SDO->CANdevTx); if (odRet != ODR_OK && odRet != ODR_PARTIAL) { *abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); @@ -858,16 +848,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Copy data */ OD_size_t countWritten = 0; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - const bool_t lock = true; -#else - bool_t lock = OD_mappable(&SDO->OD_IO.stream); -#endif - if (lock) { CO_LOCK_OD(SDO->CANdevTx); } + CO_LOCK_OD(SDO->CANdevTx); ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, dataSizeToWrite, &countWritten); - if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } + CO_UNLOCK_OD(SDO->CANdevTx); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); @@ -1311,16 +1296,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #else /* Expedited transfer only */ /* load data from OD variable */ OD_size_t count = 0; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - const bool_t lock = true; -#else - bool_t lock = OD_mappable(&SDO->OD_IO.stream); -#endif - if (lock) { CO_LOCK_OD(SDO->CANdevTx); } + CO_LOCK_OD(SDO->CANdevTx); ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->CANtxBuff->data[4], 4, &count); - if (lock) { CO_UNLOCK_OD(SDO->CANdevTx); } + CO_UNLOCK_OD(SDO->CANdevTx); /* strings are allowed to be shorter */ if (odRet == ODR_PARTIAL diff --git a/301/CO_config.h b/301/CO_config.h index fbebd8b2..a8093258 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -100,18 +100,6 @@ extern "C" { */ #define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000 -/** - * Always lock the Object Dictionary when doing a SDO read/write - * - * By default the Object Dictionary is only locked if a Object Dictionary variable - * is mappable to a PDO or SRDO. If your application uses a RTOS with multiple - * tasks accessing the Object Dictionary, you want to lock the Object Dictionary on - * every SDO read/write. - * - * This flag is common to multiple configuration macros. - */ -#define CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD 0x8000 - /** This flag may be set globally for mainline objects to * @ref CO_CONFIG_FLAG_CALLBACK_PRE */ #ifdef CO_DOXYGEN @@ -133,11 +121,6 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC CO_CONFIG_FLAG_OD_DYNAMIC #endif - -/** This flag may be set globally to @ref CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD */ -#ifdef CO_DOXYGEN -#define CO_CONFIG_GLOBAL_FLAG_SDO_ALWAYS_LOCK_OD (0) -#endif /** @} */ /* CO_STACK_CONFIG_COMMON */ @@ -346,10 +329,9 @@ extern "C" { * inside CO_SDOserver_process(). * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of additional SDO * servers (Writing to object 0x1201+ re-configures the additional server). - * - #CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - Always lock object dictionary (regardless if OD var is PDO/SRDO mappable) */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC | CO_CONFIG_GLOBAL_FLAG_ALWAYS_LOCK_OD) +#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_SDO_SRV_SEGMENTED 0x02 #define CO_CONFIG_SDO_SRV_BLOCK 0x04 @@ -385,7 +367,6 @@ extern "C" { * CO_SDOclientUploadInitiate(), CO_SDOclientUpload(). * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of SDO clients * (Writing to object 0x1280+ re-configures the client). - * - #CO_CONFIG_FLAG_SDO_ALWAYS_LOCK_OD - Always lock object dictionary (regardless if OD var is PDO/SRDO mappable) */ #ifdef CO_DOXYGEN #define CO_CONFIG_SDO_CLI (0) diff --git a/301/CO_driver.h b/301/CO_driver.h index 2fe360cb..42c3b648 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -418,16 +418,15 @@ typedef struct { * variable. CO_LOCK_OD(CAN_MODULE) and CO_UNLOCK_OD(CAN_MODULE) macros * are used to protect: * - Whole real-time thread, - * - SDO server protects read/write access to OD variable, if specific OD - * variable has ODA_TRPDO or ODA_TRSRDO from @ref OD_attributes_t set. If - * those attributes are not set, OD variable is not locked by SDO server. + * - SDO server protects read/write access to OD variable. * Locking of long OD variables, not accessible from real-time thread, may * block RT thread. * - Any mainline code, which accesses PDO-mappable OD variable, must protect * read/write with locking macros. Use @ref OD_mappable() for check. * - Other cases, where non-PDO-mappable OD variable is used inside real-time * thread by some other part of the user application must be considered with - * special care. + * special care. Also when there are multiple threads accessing the OD (e.g. + * when using a RTOS), you should always lock the OD. * * #### Synchronization functions for CAN receive * After CAN message is received, it is pre-processed in CANrx_callback(), which From e79a364983ef25c63b43ca8111f24cc7eaa90d5d Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 17 Mar 2023 22:40:40 +0100 Subject: [PATCH 229/520] Fixed issue #426: SDO Client block transfer has incorrect handling of early server acknowledgments. --- 301/CO_SDOclient.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index a93bf005..6b8d74c1 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -787,11 +787,18 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->CANrxData[0] == 0xA2) { /* check number of segments */ if (SDO_C->CANrxData[1] < SDO_C->block_seqno) { + size_t size_before, size_after; /* NOT all segments transferred successfully. * Re-transmit data after erroneous segment. */ + size_before = CO_fifo_altGetOccupied(&SDO_C->bufFifo); + /* Change alt read pointer after the last successfully + * transmitted data byte (put it back). */ CO_fifo_altBegin(&SDO_C->bufFifo, (size_t)SDO_C->CANrxData[1] * 7); + size_after = CO_fifo_altGetOccupied(&SDO_C->bufFifo); SDO_C->finished = false; + /* Make correction of data size actually transferred */ + SDO_C->sizeTran -= size_after - size_before; } else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) { /* something strange from server, break transmission */ From a8c5dcbbc837afd32c1a16889b5a88fe028dcb19 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 18 Mar 2023 01:11:20 +0100 Subject: [PATCH 230/520] update funding --- .github/FUNDING.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 46615805..437d8e6e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -6,7 +6,7 @@ open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: CANopenNode +liberapay: # CANopenNode issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +custom: ['paypal.me/jnz022'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From 1191979f5764e23d9994b17573a9fc675f934181 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 18 Mar 2023 11:42:50 +0100 Subject: [PATCH 231/520] Issue #426 update: SDO Client block transfer has incorrect handling of early server acknowledgments. --- 301/CO_SDOclient.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 6b8d74c1..9235eac3 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -787,18 +787,15 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->CANrxData[0] == 0xA2) { /* check number of segments */ if (SDO_C->CANrxData[1] < SDO_C->block_seqno) { - size_t size_before, size_after; /* NOT all segments transferred successfully. * Re-transmit data after erroneous segment. */ - size_before = CO_fifo_altGetOccupied(&SDO_C->bufFifo); - /* Change alt read pointer after the last successfully - * transmitted data byte (put it back). */ + size_t cntFailed = SDO_C->block_seqno + - SDO_C->CANrxData[1]; + cntFailed = cntFailed * 7 - SDO_C->block_noData; + SDO_C->sizeTran -= cntFailed; CO_fifo_altBegin(&SDO_C->bufFifo, (size_t)SDO_C->CANrxData[1] * 7); - size_after = CO_fifo_altGetOccupied(&SDO_C->bufFifo); SDO_C->finished = false; - /* Make correction of data size actually transferred */ - SDO_C->sizeTran -= size_after - size_before; } else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) { /* something strange from server, break transmission */ From 8f2a59f478373ce3caaf27dfc4d39ca4d0061636 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 28 Mar 2023 16:44:37 +0200 Subject: [PATCH 232/520] CO_ODinterface, fixed typo in ODR_t, #372 --- 301/CO_ODinterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 32c80e6f..a9a5f06d 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -194,7 +194,7 @@ typedef enum { /** SDO abort 0x08000022 - Data can't be transf. (present device state) */ ODR_DATA_DEV_STATE = 23, /** SDO abort 0x08000023 - Object dictionary not present */ - ODR_OD_MISSING = 23, + ODR_OD_MISSING = 24, /** SDO abort 0x08000024 - No data available */ ODR_NO_DATA = 25, /** Last element, number of responses */ From 90950be0e49709025ad2704a3e3ed89785b44aab Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 28 Mar 2023 18:07:45 +0200 Subject: [PATCH 233/520] Update deviceSupport.md --- doc/deviceSupport.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index 49719f6a..90249cac 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -25,23 +25,24 @@ Linux * CANopenNode integration with Linux socketCAN with master command interface. SocketCAN is part of the Linux kernel. * https://github.com/CANopenNode/CANopenLinux. * CANopenNode version: (v4.0) -* Status: stable * Features: OD storage, error counters, master (SDO client, LSS master, NMT master) * Systems: Linux PC, Raspberry PI, etc. -* Development tools: Linux -* Information updated 2021-05-21 +STM32 +----- +* CANopenNode integration with STM32 microcontrollers. +* https://github.com/CANopenNode/CanOpenSTM32 +* CANopenNode version: (v4.0) + PIC32, dsPIC30, dsPIC33 ----------------------- * CANopenNode integration with 16 and 32 bit PIC microcontrollers from Microchip. * https://github.com/CANopenNode/CANopenPIC * CANopenNode version: (v4.0) -* Status: stable * Features: OD storage for PIC32, SDO client demo for PIC32, error counters * Development tools: MPLAB X * Demo hardware: Explorer 16 from Microchip, [Max32 board](https://reference.digilentinc.com/reference/microprocessor/max32/start) -* Information updated 2021-05-07 [Analog Devices Inc](https://www.analog.com): MAX32662, MAX32690 @@ -109,12 +110,13 @@ S32DS (NXP S32 Design studio for Arm or Powerpc) Other ----- -* [ESP32](https://github.com/CANopenNode/CANopenNode/issues/198#issuecomment-658429391), 2020-07-14 +* ESP32: + * 2023-03-11: https://github.com/CANopenNode/CANopenNode/issues/429 + * 2020-07-14: https://github.com/CANopenNode/CANopenNode/issues/198#issuecomment-658429391 * [FreeRTOS](https://github.com/martinwag/CANopenNode/tree/neuberger-freertos/stack/neuberger-FreeRTOS) by Neuberger, 2020-06-23, based on v1.3-master, see also [issue 198](https://github.com/CANopenNode/CANopenNode/issues/198). * [STM32CubeMX HAL](https://github.com/w1ne/CANOpenNode-CubeMX-HAL), 2019-05-03, demo project for Atollic studio, tested on Nucleo STM32L452xx board. * K64F_FreeRTOS, Kinetis SDK, 2018-02-13, [zip file](https://github.com/CANopenNode/CANopenNode/pull/28#issuecomment-365392867) -* LPC1768 (MBED) (released in 2016) - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), [known example from 2016](https://github.com/exmachina-dev/CANopenMbed) - +* LPC1768 (MBED) (released in 2016) - [CANopenNode v1.0](https://github.com/CANopenNode/CANopenNode/tree/v1.0), [known example from 2016](https://github.com/exmachina-dev/CANopenMbe: d) Other old versions ------------------ From 361080da879b308876d587c60dbcc93d14104bf9 Mon Sep 17 00:00:00 2001 From: ZDH Date: Thu, 18 Aug 2022 12:08:57 +0300 Subject: [PATCH 234/520] uint32_t fix for 16bit mcu's. --- 301/CO_PDO.c | 3 ++- storage/CO_storage.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 831f5165..b12348d5 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -279,7 +279,8 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, PDO->mappedObjectsCount = mappedObjectsCount; } else { - ODR_t odRet = PDOconfigMap(PDO, CO_getUint32(buf), stream->subIndex-1, + uint32_t val = CO_getUint32(buf); + ODR_t odRet = PDOconfigMap(PDO, val, stream->subIndex-1, PDO->isRPDO, PDO->OD); if (odRet != ODR_OK) { return odRet; diff --git a/storage/CO_storage.c b/storage/CO_storage.c index fde19998..dc62d754 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -47,7 +47,8 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, return ODR_READONLY; } - if (CO_getUint32(buf) != 0x65766173) { + uint32_t val = CO_getUint32(buf); + if (val != 0x65766173) { return ODR_DATA_TRANSF; } @@ -97,7 +98,8 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, return ODR_READONLY; } - if (CO_getUint32(buf) != 0x64616F6C) { + uint32_t val = CO_getUint32(buf); + if (val != 0x64616F6C) { return ODR_DATA_TRANSF; } From b0b0724c6f8b652b6f6b5e9368f5fbb2156f76ba Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 7 Sep 2023 16:58:04 +0200 Subject: [PATCH 235/520] Node guarding added --- 301/CO_Node_Guarding.c | 460 ++++++++++++++++++++++++++++++++++++++ 301/CO_Node_Guarding.h | 309 +++++++++++++++++++++++++ 301/CO_config.h | 29 +++ CANopen.c | 99 +++++++- CANopen.h | 23 +- README.md | 4 +- doc/objectDictionary.md | 4 +- example/DS301_profile.xpd | 22 +- 8 files changed, 939 insertions(+), 11 deletions(-) create mode 100644 301/CO_Node_Guarding.c create mode 100644 301/CO_Node_Guarding.h diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c new file mode 100644 index 00000000..7e377a61 --- /dev/null +++ b/301/CO_Node_Guarding.c @@ -0,0 +1,460 @@ +/* + * CANopen Node Guarding slave and master objects. + * + * @file CO_Node_Guarding.c + * @ingroup CO_Node_Guarding + * @author Janez Paternoster + * @copyright 2023 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "301/CO_Node_Guarding.h" + +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + +/* + * Read received message from CAN module. + * + * Function will be called (by CAN receive interrupt) every time, when CAN + * message with correct identifier will be received. For more information and + * description of parameters see file CO_driver.h. + */ +static void CO_ngs_receive(void *object, void *msg) { + (void) msg; + CO_nodeGuardingSlave_t *ngs = (CO_nodeGuardingSlave_t*)object; + + CO_FLAG_SET(ngs->CANrxNew); +} + + +/* + * Custom function for writing OD object "Guard time" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static ODR_t OD_write_100C(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + if (stream == NULL || stream->subIndex != 0 || buf == NULL + || count != sizeof(uint16_t) || countWritten == NULL + ) { + return ODR_DEV_INCOMPAT; + } + + CO_nodeGuardingSlave_t *ngs = (CO_nodeGuardingSlave_t *)stream->object; + + /* update objects */ + ngs->guardTime_us = (uint32_t)CO_getUint16(buf) * 1000; + ngs->lifeTime_us = ngs->guardTime_us * ngs->lifeTimeFactor; + + /* reset running timer */ + if (ngs->lifeTimer > 0) { + ngs->lifeTimer = ngs->lifeTime_us; + } + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, buf, count, countWritten); +} + + +/* + * Custom function for writing OD object "Life time factor" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static ODR_t OD_write_100D(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + if (stream == NULL || stream->subIndex != 0 || buf == NULL + || count != sizeof(uint8_t) || countWritten == NULL + ) { + return ODR_DEV_INCOMPAT; + } + + CO_nodeGuardingSlave_t *ngs = (CO_nodeGuardingSlave_t *)stream->object; + + /* update objects */ + ngs->lifeTimeFactor = (uint8_t)CO_getUint8(buf); + ngs->lifeTime_us = ngs->guardTime_us * ngs->lifeTimeFactor; + + /* reset running timer */ + if (ngs->lifeTimer > 0) { + ngs->lifeTimer = ngs->lifeTime_us; + } + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, buf, count, countWritten); +} + + +/******************************************************************************/ +CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, + OD_entry_t *OD_100C_GuardTime, + OD_entry_t *OD_100D_LifeTimeFactor, + CO_EM_t *em, + uint16_t CANidNodeGuarding, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, + uint32_t *errInfo) +{ + CO_ReturnError_t ret = CO_ERROR_NO; + + /* verify arguments */ + if (ngs == NULL || em == NULL || CANdevRx == NULL || CANdevTx == NULL + || OD_100C_GuardTime == NULL || OD_100D_LifeTimeFactor == NULL + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* clear the object */ + memset(ngs, 0, sizeof(CO_nodeGuardingSlave_t)); + + /* Configure object variables */ + ngs->em = em; + + /* get and verify required "Guard time" from the Object Dictionary */ + uint16_t guardTime_ms; + ODR_t odRet = OD_get_u16(OD_100C_GuardTime, 0, &guardTime_ms, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_100C_GuardTime); + return CO_ERROR_OD_PARAMETERS; + } + ngs->guardTime_us = (uint32_t)guardTime_ms * 1000; + + ngs->OD_100C_extension.object = ngs; + ngs->OD_100C_extension.read = OD_readOriginal; + ngs->OD_100C_extension.write = OD_write_100C; + odRet = OD_extension_init(OD_100C_GuardTime, &ngs->OD_100C_extension); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_100C_GuardTime); + return CO_ERROR_OD_PARAMETERS; + } + + /* get and verify required "Life time factor" from the Object Dictionary */ + uint8_t lifeTimeFactor; + odRet = OD_get_u8(OD_100D_LifeTimeFactor, 0, &lifeTimeFactor, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_100D_LifeTimeFactor); + return CO_ERROR_OD_PARAMETERS; + } + ngs->lifeTimeFactor = lifeTimeFactor; + ngs->lifeTime_us = ngs->guardTime_us * ngs->lifeTimeFactor; + + ngs->OD_100D_extension.object = ngs; + ngs->OD_100D_extension.read = OD_readOriginal; + ngs->OD_100D_extension.write = OD_write_100D; + odRet = OD_extension_init(OD_100D_LifeTimeFactor, &ngs->OD_100D_extension); + if (odRet != ODR_OK) { + if (errInfo != NULL) *errInfo = OD_getIndex(OD_100D_LifeTimeFactor); + return CO_ERROR_OD_PARAMETERS; + } + + /* configure CAN reception */ + ret = CO_CANrxBufferInit( + CANdevRx, /* CAN device */ + CANdevRxIdx, /* rx buffer index */ + CANidNodeGuarding, /* CAN identifier */ + 0x7FF, /* mask */ + true, /* rtr */ + (void*)ngs, /* object passed to receive function */ + CO_ngs_receive); /* this function will process received message*/ + if (ret != CO_ERROR_NO) { + return ret; + } + + /* configure CAN transmission */ + ngs->CANdevTx = CANdevTx; + ngs->CANtxBuff = CO_CANtxBufferInit( + CANdevTx, /* CAN device */ + CANdevTxIdx, /* index of specific buffer inside CAN module */ + CANidNodeGuarding, /* CAN identifier */ + 0, /* rtr */ + 1, /* number of data bytes */ + 0); /* synchronous message flag bit */ + if (ngs->CANtxBuff == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; +} + + +/******************************************************************************/ +void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, + CO_NMT_internalState_t NMTstate, + uint32_t timeDifference_us, + uint32_t *timerNext_us) +{ + (void)timerNext_us; /* may be unused */ + + /* was RTR just received */ + if (CO_FLAG_READ(ngs->CANrxNew)) { + ngs->lifeTimer = ngs->lifeTime_us; + + /* send response */ + ngs->CANtxBuff->data[0] = (uint8_t) NMTstate; + if (ngs->toggle) { + ngs->CANtxBuff->data[0] |= 0x80; + ngs->toggle = false; + } + else { + ngs->toggle = true; + } + CO_CANsend(ngs->CANdevTx, ngs->CANtxBuff); + + if (ngs->lifeTimeTimeout) { + /* error bit is shared with HB consumer */ + CO_errorReset(ngs->em, CO_EM_HEARTBEAT_CONSUMER, 0); + ngs->lifeTimeTimeout = false; + } + + CO_FLAG_CLEAR(ngs->CANrxNew); + } + + /* verify "Life time" timeout and update the timer */ + else if (ngs->lifeTimer > 0) { + if (timeDifference_us < ngs->lifeTimer) { + ngs->lifeTimer -= timeDifference_us; +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT + /* Calculate, when timeout expires */ + if (timerNext_us != NULL && *timerNext_us > ngs->lifeTimer) { + *timerNext_us = ngs->lifeTimer; + } +#endif + } + else { + ngs->lifeTimer = 0; + ngs->lifeTimeTimeout = true; + + /* error bit is shared with HB consumer */ + CO_errorReport(ngs->em, CO_EM_HEARTBEAT_CONSUMER, + CO_EMC_HEARTBEAT, 0); + } + } + + return; +} + +#endif /* (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE */ + + + + +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +/* + * Read received message from CAN module. + * + * Function will be called (by CAN receive interrupt) every time, when CAN + * message with correct identifier will be received. For more information and + * description of parameters see file CO_driver.h. + * + * Function receives messages from CAN identifier from 0x700 to 0x7FF. It + * searches matching node->ident from nodes array. + */ +static void CO_ngm_receive(void *object, void *msg) { + CO_nodeGuardingMaster_t *ngm = (CO_nodeGuardingMaster_t*)object; + + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + uint8_t *data = CO_CANrxMsg_readData(msg); + uint16_t ident = CO_CANrxMsg_readIdent(msg); + CO_nodeGuardingMasterNode_t *node = &ngm->nodes[0]; + + if (DLC == 1) { + for (uint8_t i=0; iident) { + uint8_t toggle = data[0] & 0x80; + if (toggle == node->toggle) { + node->responseRecived = true; + node->NMTstate = (CO_NMT_internalState_t)(data[0] & 0x7F); + node->toggle = (toggle != 0) ? 0x00 : 0x80; + } + break; + } + node ++; + } + } +} + + +/******************************************************************************/ +CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, + CO_EM_t *em, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx) +{ + CO_ReturnError_t ret = CO_ERROR_NO; + + /* verify arguments */ + if (ngm == NULL || em == NULL || CANdevRx == NULL || CANdevTx == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* clear the object */ + memset(ngm, 0, sizeof(CO_nodeGuardingMaster_t)); + + /* Configure object variables */ + ngm->em = em; + + /* configure CAN reception. One buffer will receive all messages + * from CAN-id 0x700 to 0x7FF. */ + ret = CO_CANrxBufferInit( + CANdevRx, /* CAN device */ + CANdevRxIdx, /* rx buffer index */ + CO_CAN_ID_HEARTBEAT,/* CAN identifier = 0x700 */ + 0x780, /* mask - accept any combination of lower 7 bits*/ + false, /* rtr */ + (void*)ngm, /* object passed to receive function */ + CO_ngm_receive); /* this function will process received message*/ + if (ret != CO_ERROR_NO) { + return ret; + } + + /* configure CAN transmission */ + ngm->CANdevTx = CANdevTx; + ngm->CANdevTxIdx = CANdevTxIdx; + ngm->CANtxBuff = CO_CANtxBufferInit( + CANdevTx, /* CAN device */ + CANdevTxIdx, /* index of specific buffer inside CAN module */ + CO_CAN_ID_HEARTBEAT,/* CAN identifier - will be changed later.*/ + true, /* rtr */ + 1, /* number of data bytes (rtr indication only) */ + 0); /* synchronous message flag bit */ + if (ngm->CANtxBuff == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; +} + + +/******************************************************************************/ +CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t *ngm, + uint8_t index, + uint8_t nodeId, + uint16_t guardTime_ms) +{ + if (ngm == NULL || index >= CO_CONFIG_NODE_GUARDING_MASTER_COUNT + || nodeId < 1 || nodeId > 0x7F + ) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + CO_nodeGuardingMasterNode_t *node = &ngm->nodes[index]; + + node->guardTime_us = (uint32_t)guardTime_ms * 1000; + node->guardTimer = 0; + node->ident = CO_CAN_ID_HEARTBEAT + nodeId; + node->NMTstate = CO_NMT_UNKNOWN; /* for the first time */ + node->toggle = false; + node->responseRecived = true; /* for the first time */ + node->CANtxWasBusy = false; + node->monitoringActive = false; + +#if CO_CONFIG_NODE_GUARDING_MASTER_COUNT == 1 + ngm->CANtxBuff = CO_CANtxBufferInit(ngm->CANdevTx, + ngm->CANdevTxIdx, + node->ident, + true, 1, 0); +#endif + + return CO_ERROR_NO; +} + + +/******************************************************************************/ +void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, + uint32_t timeDifference_us, + uint32_t *timerNext_us) +{ + (void)timerNext_us; /* may be unused */ + bool_t allMonitoredActiveCurrent = true; + bool_t allMonitoredOperationalCurrent = true; + CO_nodeGuardingMasterNode_t *node = &ngm->nodes[0]; + + for (uint8_t i=0; iguardTime_us > 0 && node->ident > CO_CAN_ID_HEARTBEAT) { + if (timeDifference_us < node->guardTimer) { + node->guardTimer -= timeDifference_us; +#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT + /* Calculate, when timeout expires */ + if (timerNext_us != NULL && *timerNext_us > node->guardTimer) { + *timerNext_us = node->guardTimer; + } +#endif + } + else { + /* it is time to send new rtr, but first verify last response */ + if (!node->CANtxWasBusy) { + if (!node->responseRecived) { + node->monitoringActive = false; + /* error bit is shared with HB consumer */ + CO_errorReport(ngm->em, CO_EM_HEARTBEAT_CONSUMER, + CO_EMC_HEARTBEAT, node->ident & 0x7F); + } + else if (node->NMTstate != CO_NMT_UNKNOWN) { + node->monitoringActive = true; + CO_errorReset(ngm->em, CO_EM_HEARTBEAT_CONSUMER, + node->ident & 0x7F); + } + } + + if (ngm->CANtxBuff->bufferFull) { + node->guardTimer = 0; + node->CANtxWasBusy = true; + } + else { +#if CO_CONFIG_NODE_GUARDING_MASTER_COUNT > 1 + ngm->CANtxBuff = CO_CANtxBufferInit(ngm->CANdevTx, + ngm->CANdevTxIdx, + node->ident, + true, 1, 0); +#endif + CO_CANsend(ngm->CANdevTx, ngm->CANtxBuff); + node->CANtxWasBusy = false; + node->responseRecived = false; + node->guardTimer = node->guardTime_us; + } + } + + if (allMonitoredActiveCurrent) { + if (node->monitoringActive) { + if (node->NMTstate != CO_NMT_OPERATIONAL) { + allMonitoredOperationalCurrent = false; + } + } + else { + allMonitoredActiveCurrent = false; + allMonitoredOperationalCurrent = false; + } + } + } /* if node enabled */ + + node ++; + } /* for */ + + ngm->allMonitoredActive = allMonitoredActiveCurrent; + ngm->allMonitoredOperational = allMonitoredOperationalCurrent; + + return; +} + +#endif /* (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE */ diff --git a/301/CO_Node_Guarding.h b/301/CO_Node_Guarding.h new file mode 100644 index 00000000..50e139ee --- /dev/null +++ b/301/CO_Node_Guarding.h @@ -0,0 +1,309 @@ +/** + * CANopen Node Guarding slave and master objects. + * + * @file CO_Node_Guarding.h + * @ingroup CO_Node_Guarding + * @author Janez Paternoster + * @copyright 2023 Janez Paternoster + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CO_NODE_GUARDING_H +#define CO_NODE_GUARDING_H + +#include "301/CO_driver.h" +#include "301/CO_ODinterface.h" +#include "301/CO_Emergency.h" +#include "301/CO_NMT_Heartbeat.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_NODE_GUARDING +#define CO_CONFIG_NODE_GUARDING (0) +#endif +#ifndef CO_CONFIG_NODE_GUARDING_MASTER_COUNT +#define CO_CONFIG_NODE_GUARDING_MASTER_COUNT 0x7F +#endif + +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_Node_Guarding Node Guarding + * CANopen Node Guarding, an older alternative to the Heartbeat protocol. + * + * @ingroup CO_CANopen_301 + * @{ + * Node guarding master pools each node guarding slave at time intervals, called + * guard time. Master sends a CAN RTR message, and slave responds. Slave also + * monitors presence of RTR message from master and indicates error, if it + * wasn't received within life time. ('Life time' is 'Guard time' multiplied by + * 'Life time factor'). + * + * Adding Node guarding to the project: + * - Make sure, driver supports it. RTR bit should be part of CAN identifier. + * - Enable it with 'CO_CONFIG_NODE_GUARDING', see CO_config.h + * - For slave add 0x100C and 0x100D objects to the Object dictionary. + * - For master use CO_nodeGuardingMaster_initNode() to add monitored nodes. + * + * @warning Usage of Node guarding is not recommended, as it is outdated and + * uses RTR CAN functionality, which is also not recommended. Use Heartbeat and + * Heartbeat consumer, if possible. + * + * ### Node Guarding slave response message contents: + * + * Byte, bits | Description + * ---------------|----------------------------------------------------------- + * 0, bits 0..6 | @ref CO_NMT_internalState_t + * 0, bit 7 | toggle bit + * + * See @ref CO_Default_CAN_ID_t for CAN identifiers. + */ + +/** + * Node Guarding slave object + */ +typedef struct { + /** From CO_nodeGuardingSlave_init() */ + CO_EM_t *em; + /** Indicates, if new rtr message received from CAN bus */ + volatile void *CANrxNew; + /** Guard time in microseconds, calculated from OD_0x100C */ + uint32_t guardTime_us; + /** Life time in microseconds, calculated from guardTime_us * lifeTimeFactor */ + uint32_t lifeTime_us; + /** Timer for monitoring Life time, counting down from lifeTime_us. */ + uint32_t lifeTimer; + /** Life time factor, from OD_0x100D */ + uint8_t lifeTimeFactor; + /** Toggle bit for response */ + bool_t toggle; + /** True if rtr from master is missing */ + bool_t lifeTimeTimeout; + /** Extension for OD object */ + OD_extension_t OD_100C_extension; + /** Extension for OD object */ + OD_extension_t OD_100D_extension; + /** From CO_nodeGuardingSlave_init() */ + CO_CANmodule_t *CANdevTx; + /** CAN transmit buffer for the message */ + CO_CANtx_t *CANtxBuff; +} CO_nodeGuardingSlave_t; + + +/** + * Initialize Node Guarding slave object. + * + * Function must be called in the communication reset section. + * + * @param ngs This object will be initialized. + * @param OD_100C_GuardTime OD entry for 0x100C -"Guard time", + * entry is required. + * @param OD_100D_LifeTimeFactor OD entry for 0x100D -"Life time factor", + * entry is required. + * @param em Emergency object. + * @param CANidNodeGuarding CAN identifier for Node Guarding rtr and response + * message (usually CO_CAN_ID_HEARTBEAT + nodeId). + * @param CANdevRx CAN device for Node Guarding rtr reception. + * @param CANdevRxIdx Index of the receive buffer in the above CAN device. + * @param CANdevTx CAN device for Node Guarding response transmission. + * @param CANdevTxIdx Index of the transmit buffer in the above CAN device. + * @param [out] errInfo Additional information in case of error, may be NULL. + * + * @return #CO_ReturnError_t CO_ERROR_NO on success. + */ +CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, + OD_entry_t *OD_100C_GuardTime, + OD_entry_t *OD_100D_LifeTimeFactor, + CO_EM_t *em, + uint16_t CANidNodeGuarding, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx, + uint32_t *errInfo); + + +/** + * Process Node Guarding slave. + * + * Function must be called cyclically. + * + * @param ngs This object. + * @param NMTstate NMT operating state. + * @param timeDifference_us Time difference from previous function call in + * microseconds. + * @param [out] timerNext_us info to OS - see CO_process(). + */ +void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, + CO_NMT_internalState_t NMTstate, + uint32_t timeDifference_us, + uint32_t *timerNext_us); + + +/** + * Inquire, if Node guarding slave detected life time timeout + * + * Error is reset after pool request from master. + * + * @param ngs This object. + * + * @return true, if life time timeout was detected. + */ +static inline bool_t CO_nodeGuardingSlave_isTimeout(CO_nodeGuardingSlave_t *ngs) +{ + return (ngs == NULL) || ngs->lifeTimeTimeout; +} + + +/** @} */ /* CO_Node_Guarding */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE */ + + + + +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) || defined CO_DOXYGEN + +#if CO_CONFIG_NODE_GUARDING_MASTER_COUNT < 1 || CO_CONFIG_NODE_GUARDING_MASTER_COUNT > 127 +#error CO_CONFIG_NODE_GUARDING_MASTER_COUNT value is wrong! +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup CO_Node_Guarding + * @{ + */ + +/** + * Node Guarding master - monitored node + */ +typedef struct { + /** Guard time in microseconds */ + uint32_t guardTime_us; + /** Guard timer in microseconds, counting down */ + uint32_t guardTimer; + /** CAN identifier (CO_CAN_ID_HEARTBEAT + Node Id) */ + uint16_t ident; + /** NMT operating state */ + CO_NMT_internalState_t NMTstate; + /** toggle bit7, expected from the next received message */ + uint8_t toggle; + /** True, if response was received since last rtr message */ + bool_t responseRecived; + /** True, if CANtxBuff was busy since last processing */ + bool_t CANtxWasBusy; + /** True, if monitoring is active (response within time). */ + bool_t monitoringActive; +} CO_nodeGuardingMasterNode_t; + +/** + * Node Guarding master object + */ +typedef struct { + /** From CO_nodeGuardingMaster_init() */ + CO_EM_t *em; + /** From CO_nodeGuardingMaster_init() */ + CO_CANmodule_t *CANdevTx; + /** From CO_nodeGuardingMaster_init() */ + uint16_t CANdevTxIdx; + /** CAN transmit buffer for the message */ + CO_CANtx_t *CANtxBuff; + /** True, if all monitored nodes are active or no node is monitored. Can be + * read by the application */ + bool_t allMonitoredActive; + /** True, if all monitored nodes are NMT operational or no node is + * monitored. Can be read by the application */ + bool_t allMonitoredOperational; + /** Array of monitored nodes */ + CO_nodeGuardingMasterNode_t nodes[CO_CONFIG_NODE_GUARDING_MASTER_COUNT]; +} CO_nodeGuardingMaster_t; + +/** + * Initialize Node Guarding master object. + * + * Function must be called in the communication reset section. + * + * @param ngm This object will be initialized. + * @param em Emergency object. + * @param CANdevRx CAN device for Node Guarding reception. + * @param CANdevRxIdx Index of the receive buffer in the above CAN device. + * @param CANdevTx CAN device for Node Guarding rtr transmission. + * @param CANdevTxIdx Index of the transmit buffer in the above CAN device. + * + * @return #CO_ReturnError_t CO_ERROR_NO on success. + */ +CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, + CO_EM_t *em, + CO_CANmodule_t *CANdevRx, + uint16_t CANdevRxIdx, + CO_CANmodule_t *CANdevTx, + uint16_t CANdevTxIdx); + +/** + * Initialize node inside Node Guarding master object. + * + * Function may be called any time after CO_nodeGuardingMaster_init(). It + * configures monitoring of the remote node. + * + * @param ngm Node Guarding master object. + * @param em Emergency object. + * @param index Index of the slot, which will be configured. + * 0 <= index < CO_CONFIG_NODE_GUARDING_MASTER_COUNT. + * @param nodeId Node Id of the monitored node. + * @param guardTime_ms Guard time of the monitored node. + * + * @return #CO_ReturnError_t CO_ERROR_NO on success. + */ +CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t *ngm, + uint8_t index, + uint8_t nodeId, + uint16_t guardTime_ms); + +/** + * Process Node Guarding master. + * + * Function must be called cyclically. + * + * @param ngm This object. + * @param timeDifference_us Time difference from previous function call in + * microseconds. + * @param [out] timerNext_us info to OS - see CO_process(). + */ +void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, + uint32_t timeDifference_us, + uint32_t *timerNext_us); + +/** @} */ /* @addtogroup CO_Node_Guarding */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE */ + +#endif /* CO_NODE_GUARDING_H */ diff --git a/301/CO_config.h b/301/CO_config.h index a8093258..c8836432 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -186,6 +186,35 @@ extern "C" { /** @} */ /* CO_STACK_CONFIG_NMT_HB */ +/** + * @defgroup CO_STACK_CONFIG_NODE_GUARDING CANopen Node Guarding slave and master objects. + * Specified in standard CiA 301 + * @{ + */ +/** + * Configuration of @ref CO_Node_Guarding + * + * Possible flags, can be ORed: + * - CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE - Enable Node guarding slave. + * - CO_CONFIG_NODE_GUARDING_MASTER_ENABLE - Enable Node guarding master. + * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable + * inside CO_nodeGuardingSlave_process(). + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_NODE_GUARDING (0) +#endif +#define CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE 0x01 +#define CO_CONFIG_NODE_GUARDING_MASTER_ENABLE 0x02 + +/** + * Maximum number of nodes monitored by master + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_NODE_GUARDING_MASTER_COUNT 0x7F +#endif +/** @} */ /* CO_STACK_CONFIG_NODE_GUARDING */ + + /** * @defgroup CO_STACK_CONFIG_EMERGENCY Emergency producer/consumer * Specified in standard CiA 301 diff --git a/CANopen.c b/CANopen.c index c65d106f..b6660eb3 100644 --- a/CANopen.c +++ b/CANopen.c @@ -4,7 +4,7 @@ * @file CANopen.c * @ingroup CO_CANopen * @author Janez Paternoster - * @copyright 2010 - 2020 Janez Paternoster + * @copyright 2010 - 2023 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -72,6 +72,21 @@ #define CO_RX_CNT_HB_CONS 0 #endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + #define CO_RX_CNT_NG_SLV 1 + #define CO_TX_CNT_NG_SLV 1 +#else + #define CO_RX_CNT_NG_SLV 0 + #define CO_TX_CNT_NG_SLV 0 +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + #define CO_RX_CNT_NG_MST 1 + #define CO_TX_CNT_NG_MST 1 +#else + #define CO_RX_CNT_NG_MST 0 + #define CO_TX_CNT_NG_MST 0 +#endif + #if OD_CNT_EM != 1 #error OD_CNT_EM from OD.h not correct! #endif @@ -267,7 +282,9 @@ #define CO_RX_IDX_SDO_SRV (CO_RX_IDX_RPDO + CO_RX_CNT_RPDO) #define CO_RX_IDX_SDO_CLI (CO_RX_IDX_SDO_SRV + CO_RX_CNT_SDO_SRV) #define CO_RX_IDX_HB_CONS (CO_RX_IDX_SDO_CLI + CO_RX_CNT_SDO_CLI) -#define CO_RX_IDX_LSS_SLV (CO_RX_IDX_HB_CONS + CO_RX_CNT_HB_CONS) +#define CO_RX_IDX_NG_SLV (CO_RX_IDX_HB_CONS + CO_RX_CNT_HB_CONS) +#define CO_RX_IDX_NG_MST (CO_RX_IDX_NG_SLV + CO_RX_CNT_NG_SLV) +#define CO_RX_IDX_LSS_SLV (CO_RX_IDX_NG_MST + CO_RX_CNT_NG_MST) #define CO_RX_IDX_LSS_MST (CO_RX_IDX_LSS_SLV + CO_RX_CNT_LSS_SLV) #define CO_CNT_ALL_RX_MSGS (CO_RX_IDX_LSS_MST + CO_RX_CNT_LSS_MST) @@ -281,7 +298,9 @@ #define CO_TX_IDX_SDO_SRV (CO_TX_IDX_TPDO + CO_TX_CNT_TPDO) #define CO_TX_IDX_SDO_CLI (CO_TX_IDX_SDO_SRV + CO_TX_CNT_SDO_SRV) #define CO_TX_IDX_HB_PROD (CO_TX_IDX_SDO_CLI + CO_TX_CNT_SDO_CLI) -#define CO_TX_IDX_LSS_SLV (CO_TX_IDX_HB_PROD + CO_TX_CNT_HB_PROD) +#define CO_TX_IDX_NG_SLV (CO_TX_IDX_HB_PROD + CO_TX_CNT_HB_PROD) +#define CO_TX_IDX_NG_MST (CO_TX_IDX_NG_SLV + CO_TX_CNT_NG_SLV) +#define CO_TX_IDX_LSS_SLV (CO_TX_IDX_NG_MST + CO_TX_CNT_NG_MST) #define CO_TX_IDX_LSS_MST (CO_TX_IDX_LSS_SLV + CO_TX_CNT_LSS_SLV) #define CO_CNT_ALL_TX_MSGS (CO_TX_IDX_LSS_MST + CO_TX_CNT_LSS_MST) #endif /* #ifdef #else CO_MULTIPLE_OD */ @@ -383,6 +402,14 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif + /* Node guarding */ +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + CO_alloc_break_on_fail(co->NGslave, 1, sizeof(*co->NGslave)); +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + CO_alloc_break_on_fail(co->NGmaster, 1, sizeof(*co->NGmaster)); +#endif + /* Emergency */ ON_MULTI_OD(uint8_t RX_CNT_EM_CONS = 0); ON_MULTI_OD(uint8_t TX_CNT_EM_PROD = 0); @@ -549,6 +576,12 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE co->RX_IDX_HB_CONS = idxRx; idxRx += RX_CNT_HB_CONS; #endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + co->RX_IDX_NG_SLV = idxRx; idxRx += 1; +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + co->RX_IDX_NG_MST = idxRx; idxRx += 1; +#endif #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE co->RX_IDX_LSS_SLV = idxRx; idxRx += RX_CNT_LSS_SLV; #endif @@ -580,6 +613,12 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { co->TX_IDX_SDO_CLI = idxTx; idxTx += TX_CNT_SDO_CLI; #endif co->TX_IDX_HB_PROD = idxTx; idxTx += TX_CNT_HB_PROD; +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + co->TX_IDX_NG_SLV = idxTx; idxTx += 1; +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + co->TX_IDX_NG_MST = idxTx; idxTx += 1; +#endif #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE co->TX_IDX_LSS_SLV = idxTx; idxTx += TX_CNT_LSS_SLV; #endif @@ -682,6 +721,13 @@ void CO_delete(CO_t *co) { CO_free(co->em_fifo); #endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + CO_free(co->NGslave); +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + CO_free(co->NGmaster); +#endif + #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE CO_free(co->HBconsMonitoredNodes); CO_free(co->HBcons); @@ -709,6 +755,12 @@ void CO_delete(CO_t *co) { #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE static CO_HBconsumer_t COO_HBcons; static CO_HBconsNode_t COO_HBconsMonitoredNodes[OD_CNT_ARR_1016]; +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + static CO_nodeGuardingSlave_t COO_NGslave; +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + static CO_nodeGuardingMaster_t COO_NGmaster; #endif static CO_EM_t COO_EM; #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) @@ -771,6 +823,12 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE co->HBcons = &COO_HBcons; co->HBconsMonitoredNodes = &COO_HBconsMonitoredNodes[0]; +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + co->NGslave = &COO_NGslave; +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + co->NGmaster = &COO_NGmaster; #endif co->em = &COO_EM; #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) @@ -1016,6 +1074,29 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + err = CO_nodeGuardingSlave_init(co->NGslave, + OD_GET(H100C, OD_H100C_GUARD_TIME), + OD_GET(H100D, OD_H100D_LIFETIME_FACTOR), + em, + CO_CAN_ID_HEARTBEAT + nodeId, + co->CANmodule, + CO_GET_CO(RX_IDX_NG_SLV), + co->CANmodule, + CO_GET_CO(TX_IDX_NG_SLV), + errInfo); + if (err) return err; +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + err = CO_nodeGuardingMaster_init(co->NGmaster, + em, + co->CANmodule, + CO_GET_CO(RX_IDX_NG_MST), + co->CANmodule, + CO_GET_CO(TX_IDX_NG_MST)); + if (err) return err; +#endif + /* SDOserver */ if (CO_GET_CNT(SDO_SRV) > 0) { OD_entry_t *SDOsrvPar = OD_GET(H1200, OD_H1200_SDO_SERVER_1_PARAM); @@ -1385,6 +1466,18 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, } #endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE + CO_nodeGuardingSlave_process(co->NGslave, + NMTstate, + timeDifference_us, + timerNext_us); +#endif +#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE + CO_nodeGuardingMaster_process(co->NGmaster, + timeDifference_us, + timerNext_us); +#endif + #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE if (CO_GET_CNT(TIME) == 1) { CO_TIME_process(co->TIME, NMTisPreOrOperational, timeDifference_us); diff --git a/CANopen.h b/CANopen.h index de03169e..a1f8f146 100644 --- a/CANopen.h +++ b/CANopen.h @@ -5,7 +5,7 @@ * @ingroup CO_CANopen * @author Janez Paternoster * @author Uwe Kindler - * @copyright 2010 - 2020 Janez Paternoster + * @copyright 2010 - 2023 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -32,6 +32,7 @@ #include "301/CO_ODinterface.h" #include "301/CO_NMT_Heartbeat.h" #include "301/CO_HBconsumer.h" +#include "301/CO_Node_Guarding.h" #include "301/CO_Emergency.h" #include "301/CO_SDOserver.h" #include "301/CO_SDOclient.h" @@ -207,6 +208,10 @@ typedef struct { * object, 1 to 127. */ uint8_t CNT_ARR_1016; OD_entry_t *ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init()*/ + /** OD entry for @ref CO_nodeGuardingSlave_init() */ + OD_entry_t *ENTRY_H100C; + /** OD entry for @ref CO_nodeGuardingSlave_init() */ + OD_entry_t *ENTRY_H100D; /** Number of Emergency objects, 0 or 1: optional producer (CANtx) + * optional consumer (CANrx), configurable by @ref CO_CONFIG_EM. * There must be one Emergency object in the device. */ @@ -303,6 +308,22 @@ typedef struct { #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_HB_CONS; /**< Start index in CANrx. */ #endif +#endif +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) || defined CO_DOXYGEN + /** Node guarding slave object, initialised by @ref CO_nodeGuardingSlave_init() */ + CO_nodeGuardingSlave_t *NGslave; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_NG_SLV; /**< Start index in CANrx. */ + uint16_t TX_IDX_NG_SLV; /**< Start index in CANtx. */ + #endif +#endif +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) || defined CO_DOXYGEN + /** Node guarding master object, initialised by @ref CO_nodeGuardingMaster_init() */ + CO_nodeGuardingMaster_t *NGmaster; + #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + uint16_t RX_IDX_NG_MST; /**< Start index in CANrx. */ + uint16_t TX_IDX_NG_MST; /**< Start index in CANtx. */ + #endif #endif /** Emergency object, initialised by @ref CO_EM_init() */ CO_EM_t *em; diff --git a/README.md b/README.md index a57a8ae4..17871d5f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Characteristics ### CANopen - [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen/device-architecture/) offers clear and flexible organisation of any variables. Variables can be accessed directly or via read/write functions. - [NMT](https://www.can-cia.org/can-knowledge/canopen/network-management/) slave to start, stop, reset device. Simple NMT master. - - [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/) producer/consumer error control for monitoring of CANopen devices. + - [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/) producer/consumer error control for monitoring of CANopen devices. An older alternative, 'node guarding', is also available. - [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) for broadcasting process data with high priority and no protocol overhead. Variables from Object Dictionary can be dynamically mapped to the TPDO, which is then transmitted according to communication rules and received as RPDO by another device. - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) server enables expedited, segmented and block transfer access to all Object Dictionary variables inside CANopen device. - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client can access any Object Dictionary variable on any CANopen device inside the network. @@ -200,7 +200,7 @@ It is not practical to have all device interfaces in a single project. Interface Some details ------------ ### RTR -RTR (remote transmission request) is a feature of CAN bus. Usage of RTR is not recommended for CANopen and it is not implemented in CANopenNode. +RTR (remote transmission request) is a feature of CAN bus. Usage of RTR is not recommended for CANopen. RTR PDO is not implemented in CANopenNode. ### Error control When node is started (in NMT operational state), it is allowed to send or receive Process Data Objects (PDO). If Error Register (object 0x1001) is set, then NMT operational state may not be allowed. diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index cd77f763..f2f31ab2 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -467,8 +467,8 @@ Object Dictionary Requirements By CANopenNode {#object-dictionary-requirements-b | 1008 | Manufacturer device name | | | | 1009 | Manufacturer hardware version | | | | 100A | Manufacturer software version | | | -| 100C | Guard time | | | -| 100D | Life time factor | | | +| 100C | Guard time | Node guarding slave | | +| 100D | Life time factor | Node guarding slave | | | 1010 | Store parameters | | STORAGE | | 1011 | Restore default parameters | | | | 1012 | COB-ID time stamp object | TIME, req | TIME | diff --git a/example/DS301_profile.xpd b/example/DS301_profile.xpd index 26f22454..40de57b1 100644 --- a/example/DS301_profile.xpd +++ b/example/DS301_profile.xpd @@ -1,5 +1,5 @@ - + @@ -15,7 +15,7 @@ CANopen - + @@ -769,6 +769,20 @@ + + + + + + + + + + + + + + Sub-indexes 1 and above: * Reading provides information about its storage functionality: @@ -2277,7 +2291,7 @@ CANopen - + @@ -2308,6 +2322,8 @@ + + From a4b4e6df6663b9b0ba663afb25299e322a81f9fb Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 19 Oct 2023 12:16:37 +0200 Subject: [PATCH 236/520] Node guarding disable, if heartbeat is used. --- 301/CO_Node_Guarding.c | 8 ++++++++ 301/CO_Node_Guarding.h | 3 ++- CANopen.c | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 7e377a61..edba347b 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -199,11 +199,19 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, /******************************************************************************/ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, CO_NMT_internalState_t NMTstate, + bool_t slaveDisable, uint32_t timeDifference_us, uint32_t *timerNext_us) { (void)timerNext_us; /* may be unused */ + if (slaveDisable) { + ngs->toggle = false; + ngs->lifeTimer = 0; + CO_FLAG_CLEAR(ngs->CANrxNew); + return; + } + /* was RTR just received */ if (CO_FLAG_READ(ngs->CANrxNew)) { ngs->lifeTimer = ngs->lifeTime_us; diff --git a/301/CO_Node_Guarding.h b/301/CO_Node_Guarding.h index 50e139ee..6cf17355 100644 --- a/301/CO_Node_Guarding.h +++ b/301/CO_Node_Guarding.h @@ -148,12 +148,14 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, * * @param ngs This object. * @param NMTstate NMT operating state. + * @param slaveDisable If true, then Node guarding slave is disabled. * @param timeDifference_us Time difference from previous function call in * microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, CO_NMT_internalState_t NMTstate, + bool_t slaveDisable, uint32_t timeDifference_us, uint32_t *timerNext_us); @@ -271,7 +273,6 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, * configures monitoring of the remote node. * * @param ngm Node Guarding master object. - * @param em Emergency object. * @param index Index of the slot, which will be configured. * 0 <= index < CO_CONFIG_NODE_GUARDING_MASTER_COUNT. * @param nodeId Node Id of the monitored node. diff --git a/CANopen.c b/CANopen.c index b6660eb3..3f4518ac 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1469,6 +1469,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE CO_nodeGuardingSlave_process(co->NGslave, NMTstate, + (co->NMT->HBproducerTime_us > 0), timeDifference_us, timerNext_us); #endif From 99eb6b704a06ef080b074bfc577ec5f49a59d4a7 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 26 Oct 2023 16:35:22 +0200 Subject: [PATCH 237/520] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 17871d5f..9a71d9fd 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Related projects - [CANopenEditor](https://github.com/CANopenNode/CANopenEditor): Object Dictionary editor, external GUI tool for editing CANopen Object Dictionary for custom device. It generates C source code, electronic data sheet and documentation for the device. It is a fork from [libedssharp](https://github.com/robincornelius/libedssharp). - [CANopenLinux](https://github.com/CANopenNode/CANopenLinux): CANopenNode on Linux devices. It can be a basic CANopen device or more advanced with commander functionalities. - [CANopenSTM32](https://github.com/CANopenNode/CanOpenSTM32): CANopenNode on STM32 microcontrollers. + - [Analog Devices Inc.](https://github.com/Analog-Devices-MSDK/CANopenADI): CANopenNode on Analog Devices Inc. MAX32xx microcontrollers. - [CANopenPIC](https://github.com/CANopenNode/CANopenPIC): CANopenNode on PIC microcontrollers from Microchip. Works with 16-bit and 32 bit devices. Includes example for Arduino style [Max32](https://reference.digilentinc.com/reference/microprocessor/max32/start) board. - [doc/deviceSupport.md](doc/deviceSupport.md): List of other implementations of CANopenNode on different devices. From 4f68e4404a8d329958ec4db6e9da8d1e93e947e2 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 10 Nov 2023 19:08:38 +0100 Subject: [PATCH 238/520] Update README.md - notice about NOT up-to-date for the current version. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a71d9fd..157bb2e0 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ File structure - **crc16-ccitt.h/.c** - Calculation of CRC 16 CCITT polynomial. - **303/** - CANopen Recommendation - **CO_LEDs.h/.c** - CANopen LED Indicators - - **304/** - CANopen Safety. + - **304/** - CANopen Safety (Implemented only in v1.3, not updated for the latest version). - **CO_SRDO.h/.c** - CANopen Safety-relevant Data Object protocol. - **CO_GFC.h/.c** - CANopen Global Failsafe Command (producer and consumer). - **305/** - CANopen layer setting services (LSS) and protocols. From 91653819e79072efeb585d56279dc87dbfc4d84a Mon Sep 17 00:00:00 2001 From: sicris Date: Sun, 3 Dec 2023 14:43:18 +0800 Subject: [PATCH 239/520] + added CANopenNode ESP32 device support for ESP-IDF framework --- doc/deviceSupport.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index 90249cac..e49b7522 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -113,6 +113,7 @@ Other * ESP32: * 2023-03-11: https://github.com/CANopenNode/CANopenNode/issues/429 * 2020-07-14: https://github.com/CANopenNode/CANopenNode/issues/198#issuecomment-658429391 + * [CANopenNode_ESP32](https://github.com/sicrisembay/CANopenNode_ESP32) is a CANopenNode component for ESP-IDF framework. For ease of maintenance, this uses unmodified CANopenNode stack. For project examples, refer to [CANopenNode_ESP32_Test](https://github.com/sicrisembay/CANopenNode_ESP32_Test). * [FreeRTOS](https://github.com/martinwag/CANopenNode/tree/neuberger-freertos/stack/neuberger-FreeRTOS) by Neuberger, 2020-06-23, based on v1.3-master, see also [issue 198](https://github.com/CANopenNode/CANopenNode/issues/198). * [STM32CubeMX HAL](https://github.com/w1ne/CANOpenNode-CubeMX-HAL), 2019-05-03, demo project for Atollic studio, tested on Nucleo STM32L452xx board. * K64F_FreeRTOS, Kinetis SDK, 2018-02-13, [zip file](https://github.com/CANopenNode/CANopenNode/pull/28#issuecomment-365392867) From 32274bef99668a91022c56263783765dd56b711c Mon Sep 17 00:00:00 2001 From: Oleksii Slabchenko Date: Mon, 26 Feb 2024 11:00:55 +0100 Subject: [PATCH 240/520] Fix bit shifting in CO_CANtxBufferInit Shifting by 12 overlaps RTR bit if DLC is 8 bytes. --- example/CO_driver_blank.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index 9d29edbf..5d2265d1 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -178,7 +178,7 @@ CO_CANtx_t *CO_CANtxBufferInit( /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer. * Microcontroller specific. */ buffer->ident = ((uint32_t)ident & 0x07FFU) - | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 12U)) + | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) | ((uint32_t)(rtr ? 0x8000U : 0U)); buffer->bufferFull = false; From 9d2a65cda7b8a22e1831ae57cebf35f945c34848 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 13 Mar 2024 12:23:10 +0100 Subject: [PATCH 241/520] Fix CO_storageEeprom. CO_LOCK_OD must not be used, as it is used inside SDO server already. --- 301/CO_ODinterface.h | 10 ++++------ storage/CO_storageEeprom.c | 3 +-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index a9a5f06d..8b672170 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -257,9 +257,8 @@ typedef struct { * not large enough. ("*returnCode" must not return 'ODR_PARTIAL', if there * is still space in "buf".) * - * @warning When accessing OD variables by calling the read() function, it - * may be necessary to use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros. - * See @ref CO_critical_sections for more information. + * @warning Do not use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros + * inside the read() function. See also @ref CO_critical_sections. * * @param stream Object Dictionary stream object. * @param buf Pointer to external buffer, where to data will be copied. @@ -288,9 +287,8 @@ typedef struct { * "write" function must always copy all available data from buf. If OD * variable expect more data, then "*returnCode" must return 'ODR_PARTIAL'. * - * @warning When accessing OD variables by calling the read() function, it - * may be necessary to use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros. - * See @ref CO_critical_sections for more information. + * @warning Do not use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros + * inside the write() function. See also @ref CO_critical_sections. * * @param stream Object Dictionary stream object. * @param buf Pointer to external buffer, from where data will be copied. diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index e49cd35c..a59c6076 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -34,14 +34,13 @@ * For more information see file CO_storage.h, CO_storage_entry_t. */ static ODR_t storeEeprom(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { + (void) CANmodule; bool_t writeOk; /* save data to the eeprom */ - CO_LOCK_OD(CANmodule); writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len); entry->crc = crc16_ccitt(entry->addr, entry->len, 0); - CO_UNLOCK_OD(CANmodule); /* Verify, if data in eeprom are equal */ uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, From 1204042a1f83cbbb3dc6398ed410bb9f58fc5102 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 13 Mar 2024 16:56:21 +0100 Subject: [PATCH 242/520] OD_extension, callback function: add information about the OD index. --- 301/CO_ODinterface.c | 3 +++ 301/CO_ODinterface.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index ff61cec1..4da762e7 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -255,6 +255,9 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, /* Reset stream data offset */ stream->dataOffset = 0; + + /* Add informative data */ + stream->index = entry->index; stream->subIndex = subIndex; return ODR_OK; diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 8b672170..07ec11af 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -223,6 +223,8 @@ typedef struct { OD_size_t dataOffset; /** Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */ OD_attr_t attribute; + /** Index of the OD object, informative */ + uint16_t index; /** Sub index of the OD sub-object, informative */ uint8_t subIndex; } OD_stream_t; From a52db428f699394f58e12ce15acadfe1461e50ea Mon Sep 17 00:00:00 2001 From: Brian Linari <45798461+NLI-BrianLinari@users.noreply.github.com> Date: Wed, 13 Mar 2024 09:20:42 -0700 Subject: [PATCH 243/520] Misra (#501) Make MISRA compliant for: MISRA C 2004 rule 14.10 MISRA C 2004 rule 14.9 MISRA C 2004 rule 13.1 MISRA C 2004 rule 15.3 MISRA style guild update --- 301/CO_Emergency.c | 67 ++++++++++++++++++++++++------------------ 301/CO_HBconsumer.c | 10 +++---- 301/CO_NMT_Heartbeat.c | 7 +++-- 301/CO_NMT_Heartbeat.h | 2 +- 301/CO_ODinterface.c | 23 ++++++++------- 301/CO_ODinterface.h | 4 +-- 301/CO_PDO.c | 40 ++++++++++++++++--------- 301/CO_PDO.h | 2 +- 301/CO_SDOserver.c | 40 ++++++++++++++++++------- 301/CO_SYNC.c | 36 ++++++++++++++++------- 301/CO_SYNC.h | 2 +- 301/CO_TIME.c | 5 ++-- 301/CO_fifo.c | 9 ++++++ 303/CO_LEDs.c | 42 +++++++++++++------------- 305/CO_LSSslave.c | 1 + 309/CO_gateway_ascii.c | 3 ++ CANopen.c | 48 +++++++++++++++++------------- codingStyle | 37 ++++++++++++++++++++++- extra/CO_trace.c | 6 ++++ 19 files changed, 250 insertions(+), 134 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 242c71b9..cd553739 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -209,6 +209,7 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, else if (index >= (em->fifoSize)) { return ODR_DEV_INCOMPAT; } + else { /* MISRA C 2004 14.10 */ } CO_setUint32(buf, em->fifo[index].msg); *countRead = sizeof(uint32_t); @@ -400,7 +401,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* get and verify "Error register" from Object Dictionary */ em->errorRegister = OD_getPtr(OD_1001_errReg, 0, sizeof(uint8_t), NULL); if (em->errorRegister == NULL) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1001_errReg); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1001_errReg); } return CO_ERROR_OD_PARAMETERS; } *em->errorRegister = 0; @@ -414,10 +415,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint32_t COB_IDEmergency32; odRet = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); if (odRet != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1014_cobIdEm); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1014_cobIdEm); } /* don't break a program, if only value of a parameter is wrong */ - if (odRet != ODR_OK) - return CO_ERROR_OD_PARAMETERS; + if (odRet != ODR_OK) { return CO_ERROR_OD_PARAMETERS; } } #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE @@ -449,7 +449,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1014_extension.write = OD_writeOriginal; odRet = OD_extension_init(OD_1014_cobIdEm, &em->OD_1014_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1014_cobIdEm); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1014_cobIdEm); } return CO_ERROR_OD_PARAMETERS; } #endif @@ -564,60 +564,68 @@ void CO_EM_process(CO_EM_t *em, uint16_t CANerrStChanged = CANerrSt ^ em->CANerrorStatusOld; em->CANerrorStatusOld = CANerrSt; - if (CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) + if (CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) { CO_error(em, (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, 0); - - if (CANerrStChanged & CO_CAN_ERRTX_PASSIVE) + } + if (CANerrStChanged & CO_CAN_ERRTX_PASSIVE) { CO_error(em, (CANerrSt & CO_CAN_ERRTX_PASSIVE) != 0, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); - - if (CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) + } + if (CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) { CO_error(em, (CANerrSt & CO_CAN_ERRTX_BUS_OFF) != 0, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, 0); - - if (CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) + } + if (CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) { CO_error(em, (CANerrSt & CO_CAN_ERRTX_OVERFLOW) != 0, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); - - if (CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) + } + if (CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) { CO_error(em, (CANerrSt & CO_CAN_ERRTX_PDO_LATE) != 0, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, 0); - - if (CANerrStChanged & CO_CAN_ERRRX_PASSIVE) + } + if (CANerrStChanged & CO_CAN_ERRRX_PASSIVE) { CO_error(em, (CANerrSt & CO_CAN_ERRRX_PASSIVE) != 0, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); - - if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) + } + if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) { CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0, CO_EM_CAN_RXB_OVERFLOW, CO_EM_CAN_RXB_OVERFLOW, 0); + } } /* calculate Error register */ uint8_t errorRegister = 0U; - if (CO_CONFIG_ERR_CONDITION_GENERIC) + if (CO_CONFIG_ERR_CONDITION_GENERIC) { errorRegister |= CO_ERR_REG_GENERIC_ERR; + } #ifdef CO_CONFIG_ERR_CONDITION_CURRENT - if (CO_CONFIG_ERR_CONDITION_CURRENT) + if (CO_CONFIG_ERR_CONDITION_CURRENT) { errorRegister |= CO_ERR_REG_CURRENT; + } #endif #ifdef CO_CONFIG_ERR_CONDITION_VOLTAGE - if (CO_CONFIG_ERR_CONDITION_VOLTAGE) + if (CO_CONFIG_ERR_CONDITION_VOLTAGE) { errorRegister |= CO_ERR_REG_VOLTAGE; + } #endif #ifdef CO_CONFIG_ERR_CONDITION_TEMPERATURE - if (CO_CONFIG_ERR_CONDITION_TEMPERATURE) + if (CO_CONFIG_ERR_CONDITION_TEMPERATURE) { errorRegister |= CO_ERR_REG_TEMPERATURE; + } #endif - if (CO_CONFIG_ERR_CONDITION_COMMUNICATION) + if (CO_CONFIG_ERR_CONDITION_COMMUNICATION) { errorRegister |= CO_ERR_REG_COMMUNICATION; + } #ifdef CO_CONFIG_ERR_CONDITION_DEV_PROFILE - if (CO_CONFIG_ERR_CONDITION_DEV_PROFILE) + if (CO_CONFIG_ERR_CONDITION_DEV_PROFILE) { errorRegister |= CO_ERR_REG_DEV_PROFILE; + } #endif - if (CO_CONFIG_ERR_CONDITION_MANUFACTURER) + if (CO_CONFIG_ERR_CONDITION_MANUFACTURER) { errorRegister |= CO_ERR_REG_MANUFACTURER; + } *em->errorRegister = errorRegister; if (!NMTisPreOrOperational) { @@ -675,6 +683,7 @@ void CO_EM_process(CO_EM_t *em, em->fifoOverflow = 0; CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); } + else { /* MISRA C 2004 14.10 */ } } #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT @@ -713,7 +722,7 @@ void CO_EM_process(CO_EM_t *em, void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) { - if (em == NULL) return; + if (em == NULL) { return; } uint8_t index = errorBit >> 3; uint8_t bitmask = 1 << (errorBit & 0x7); @@ -753,8 +762,8 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, /* safely write data, and increment pointers */ CO_LOCK_EMCY(em->CANdevTx); - if (setError) *errorStatusBits |= bitmask; - else *errorStatusBits &= ~bitmask; + if (setError) { *errorStatusBits |= bitmask; } + else { *errorStatusBits &= ~bitmask; } #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) if (em->fifoSize >= 2) { @@ -773,7 +782,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, em->fifo[fifoWrPtr].info = infoCodeSwapped; #endif em->fifoWrPtr = fifoWrPtrNext; - if (em->fifoCount < (em->fifoSize - 1)) em->fifoCount++; + if (em->fifoCount < (em->fifoSize - 1)) { em->fifoCount++; } } } #endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index cd976546..41bdd249 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -146,7 +146,7 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, uint32_t val; odRet = OD_get_u32(OD_1016_HBcons, i + 1, &val, true); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1016_HBcons); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } return CO_ERROR_OD_PARAMETERS; } @@ -154,10 +154,9 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, uint16_t time = val & 0xFFFF; CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); if (ret != CO_ERROR_NO) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1016_HBcons); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } /* don't break a program, if only value of a parameter is wrong */ - if (ret != CO_ERROR_OD_PARAMETERS) - return ret; + if (ret != CO_ERROR_OD_PARAMETERS) { return ret; } } } @@ -168,7 +167,7 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, HBcons->OD_1016_extension.write = OD_write_1016; odRet = OD_extension_init(OD_1016_HBcons, &HBcons->OD_1016_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1016_HBcons); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } return CO_ERROR_OD_PARAMETERS; } #endif @@ -488,6 +487,7 @@ void CO_HBconsumer_process( allMonitoredActiveCurrent = false; allMonitoredOperationalCurrent = false; } + else { /* MISRA C 2004 14.10 */ } /* Clear emergencies when all monitored nodes becomes active. * We only have one emergency index for all monitored nodes! */ diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index ac35b81c..fad6921d 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -126,7 +126,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, uint16_t HBprodTime_ms; ODR_t odRet = OD_get_u16(OD_1017_ProducerHbTime, 0, &HBprodTime_ms, true); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1017_ProducerHbTime); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1017_ProducerHbTime); } return CO_ERROR_OD_PARAMETERS; } NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000; @@ -136,7 +136,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, NMT->OD_1017_extension.write = OD_write_1017; odRet = OD_extension_init(OD_1017_ProducerHbTime, &NMT->OD_1017_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1017_ProducerHbTime); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1017_ProducerHbTime); } return CO_ERROR_OD_PARAMETERS; } @@ -298,6 +298,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, ) { NMTstateCpy = CO_NMT_OPERATIONAL; } + else { /* MISRA C 2004 14.10 */ } #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE /* Notify operating state change */ @@ -321,7 +322,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, #endif NMT->operatingState = NMTstateCpy; - if (NMTstate != NULL) *NMTstate = NMTstateCpy; + if (NMTstate != NULL) { *NMTstate = NMTstateCpy; } return resetCommand; } diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 57bb56fd..ddee475b 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -331,7 +331,7 @@ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { static inline void CO_NMT_sendInternalCommand(CO_NMT_t *NMT, CO_NMT_command_t command) { - if (NMT != NULL) NMT->internalCommand = command; + if (NMT != NULL) { NMT->internalCommand = command; } } diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 4da762e7..f71fbca1 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -182,15 +182,15 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index) { ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, OD_IO_t *io, bool_t odOrig) { - if (entry == NULL || entry->odObject == NULL) return ODR_IDX_NOT_EXIST; - if (io == NULL) return ODR_DEV_INCOMPAT; + if (entry == NULL || entry->odObject == NULL) { return ODR_IDX_NOT_EXIST; } + if (io == NULL) { return ODR_DEV_INCOMPAT; } OD_stream_t *stream = &io->stream; /* attribute, dataOrig and dataLength, depends on object type */ switch (entry->odObjectType & ODT_TYPE_MASK) { case ODT_VAR: { - if (subIndex > 0) return ODR_SUB_NOT_EXIST; + if (subIndex > 0) { return ODR_SUB_NOT_EXIST; } CO_PROGMEM OD_obj_var_t *odo = entry->odObject; @@ -200,7 +200,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, break; } case ODT_ARR: { - if (subIndex >= entry->subEntriesCount) return ODR_SUB_NOT_EXIST; + if (subIndex >= entry->subEntriesCount) { return ODR_SUB_NOT_EXIST; } CO_PROGMEM OD_obj_array_t *odo = entry->odObject; if (subIndex == 0) { @@ -226,7 +226,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, break; } } - if (odo == NULL) return ODR_SUB_NOT_EXIST; + if (odo == NULL) { return ODR_SUB_NOT_EXIST; } stream->attribute = odo->attribute; stream->dataOrig = odo->dataOrig; @@ -303,7 +303,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, void *val, OD_size_t len, bool_t odOrig) { - if (val == NULL) return ODR_DEV_INCOMPAT; + if (val == NULL) { return ODR_DEV_INCOMPAT; } OD_IO_t io; OD_stream_t *stream = (OD_stream_t *)&io; @@ -311,8 +311,8 @@ ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - if (ret != ODR_OK) return ret; - if (stream->dataLength != len) return ODR_TYPE_MISMATCH; + if (ret != ODR_OK) { return ret; } + if (stream->dataLength != len) { return ODR_TYPE_MISMATCH; } return io.read(stream, val, len, &countRd); } @@ -326,8 +326,8 @@ ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - if (ret != ODR_OK) return ret; - if (stream->dataLength != len) return ODR_TYPE_MISMATCH; + if (ret != ODR_OK) { return ret; } + if (stream->dataLength != len) { return ODR_TYPE_MISMATCH; } return io.write(stream, val, len, &countWritten); } @@ -348,9 +348,10 @@ void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, else if (len != 0 && len != stream->dataLength) { errCopy = ODR_TYPE_MISMATCH; } + else { /* MISRA C 2004 14.10 */ } } - if (err != NULL) *err = errCopy; + if (err != NULL) { *err = errCopy; } return errCopy == ODR_OK ? stream->dataOrig : NULL; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 07ec11af..cb0a4cd8 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -467,7 +467,7 @@ static inline bool_t OD_mappable(OD_stream_t *stream) { * @param stream Object Dictionary stream object. */ static inline void OD_rwRestart(OD_stream_t *stream) { - if (stream != NULL) stream->dataOffset = 0; + if (stream != NULL) { stream->dataOffset = 0; } } @@ -588,7 +588,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); static inline ODR_t OD_extension_init(OD_entry_t *entry, OD_extension_t *extension) { - if (entry == NULL) return ODR_IDX_NOT_EXIST; + if (entry == NULL) { return ODR_IDX_NOT_EXIST; } entry->extension = extension; return ODR_OK; } diff --git a/301/CO_PDO.c b/301/CO_PDO.c index b12348d5..20b1128a 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -45,7 +45,7 @@ static ODR_t OD_write_dummy(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { (void) stream; (void) buf; - if (countWritten != NULL) *countWritten = count; + if (countWritten != NULL) { *countWritten = count; } return ODR_OK; } @@ -201,7 +201,7 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, /* indicate erroneous mapping in initialization phase */ OD_IO->stream.dataLength = 0; OD_IO->stream.dataOffset = 0xFF; - if (*erroneousMap == 0) *erroneousMap = map; + if (*erroneousMap == 0) { *erroneousMap = map; } } if (i < mappedObjectsCount) { @@ -211,7 +211,7 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, if (pdoDataLength > CO_PDO_MAX_SIZE || (pdoDataLength == 0 && mappedObjectsCount > 0) ) { - if (*erroneousMap == 0) *erroneousMap = 1; + if (*erroneousMap == 0) { *erroneousMap = 1; } } if (*erroneousMap == 0) { @@ -428,7 +428,7 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, } /* If PDO is not valid, set bit 31 */ - if (!PDO->valid) COB_ID |= 0x80000000; + if (!PDO->valid) { COB_ID |= 0x80000000; } CO_setUint32(buf, COB_ID); } @@ -474,10 +474,10 @@ static void CO_PDO_receive(void *object, void *msg) { if (DLC >= PDO->dataLength) { /* indicate errors in PDO length */ if (DLC == PDO->dataLength) { - if (err == CO_RPDO_RX_ACK_ERROR) err = CO_RPDO_RX_OK; + if (err == CO_RPDO_RX_ACK_ERROR) { err = CO_RPDO_RX_OK; } } else { - if (err == CO_RPDO_RX_ACK_NO_ERROR) err = CO_RPDO_RX_LONG; + if (err == CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_LONG; } } /* Determine, to which of the two rx buffers copy the message. */ @@ -505,6 +505,7 @@ static void CO_PDO_receive(void *object, void *msg) { else if (err == CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_SHORT; } + else { /* MISRA C 2004 14.10 */ } } RPDO->receiveError = err; @@ -616,6 +617,9 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, break; } #endif + default: + /* MISRA C 2004 15.3 */ + break; } /* write value to the original location in the Object Dictionary */ @@ -683,7 +687,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); if (valid && (PDO->mappedObjectsCount == 0 || CAN_ID == 0)) { valid = false; - if (erroneousMap == 0) erroneousMap = 1; + if (erroneousMap == 0) { erroneousMap = 1; } } if (erroneousMap != 0) { @@ -804,8 +808,10 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* Determine, which of the two rx buffers contains relevant message. */ uint8_t bufNo = 0; #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if (RPDO->synchronous && RPDO->SYNC != NULL && !RPDO->SYNC->CANrxToggle) + if (RPDO->synchronous && RPDO->SYNC != NULL + && !RPDO->SYNC->CANrxToggle) { bufNo = 1; + } #endif /* copy RPDO into OD variables according to mappings */ @@ -828,9 +834,9 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* length of OD variable may be larger than mappedLength */ OD_size_t ODdataLength = OD_IO->stream.dataLength; - if (ODdataLength > CO_PDO_MAX_SIZE) + if (ODdataLength > CO_PDO_MAX_SIZE) { ODdataLength = CO_PDO_MAX_SIZE; - + } /* Prepare data for writing into OD variable. If mappedLength * is smaller than ODdataLength, then use auxiliary buffer */ uint8_t buf[CO_PDO_MAX_SIZE]; @@ -898,6 +904,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, CO_EMC_RPDO_TIMEOUT, RPDO->timeoutTimer); } } + else { /* MISRA C 2004 14.10 */ } #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT if (timerNext_us != NULL && RPDO->timeoutTimer < RPDO->timeoutTime_us @@ -1056,6 +1063,9 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, break; } #endif + default: + /* MISRA C 2004 15.3 */ + break; } /* write value to the original location in the Object Dictionary */ @@ -1141,7 +1151,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); if (valid && (PDO->mappedObjectsCount == 0 || CAN_ID == 0)) { valid = false; - if (erroneousMap == 0) erroneousMap = 1; + if (erroneousMap == 0) { erroneousMap = 1; } } if (erroneousMap != 0) { @@ -1243,9 +1253,9 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { /* length of OD variable may be larger than mappedLength */ OD_size_t ODdataLength = stream->dataLength; - if (ODdataLength > CO_PDO_MAX_SIZE) + if (ODdataLength > CO_PDO_MAX_SIZE) { ODdataLength = CO_PDO_MAX_SIZE; - + } /* If mappedLength is smaller than ODdataLength, use auxiliary buffer */ uint8_t buf[CO_PDO_MAX_SIZE]; uint8_t *dataTPDOCopy; @@ -1402,7 +1412,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, else if (TPDO->SYNC != NULL && syncWas) { /* send synchronous acyclic TPDO */ if (TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { - if (TPDO->sendRequest) CO_TPDOsend(TPDO); + if (TPDO->sendRequest) { CO_TPDOsend(TPDO); } } /* send synchronous cyclic TPDO */ else { @@ -1432,8 +1442,10 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, TPDO->syncCounter = TPDO->transmissionType; CO_TPDOsend(TPDO); } + else { /* MISRA C 2004 14.10 */ } } } /* else if (TPDO->SYNC && syncWas) */ + else { /* MISRA C 2004 14.10 */ } #endif } diff --git a/301/CO_PDO.h b/301/CO_PDO.h index f6743835..76df0eb7 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -451,7 +451,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, * @param TPDO TPDO object. */ static inline void CO_TPDOsendRequest(CO_TPDO_t *TPDO) { - if (TPDO != NULL) TPDO->sendRequest = true; + if (TPDO != NULL) { TPDO->sendRequest = true; } } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index aad8619d..fac86283 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -245,6 +245,7 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, switch (stream->subIndex) { case 0: /* Highest sub-index supported */ return ODR_READONLY; + break; case 1: { /* COB-ID client -> server */ uint32_t COB_ID = CO_getUint32(buf); @@ -349,7 +350,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (OD_1200_SDOsrvPar == NULL) { /* configure default SDO channel */ - if (nodeId < 1 || nodeId > 127) return CO_ERROR_ILLEGAL_ARGUMENT; + if (nodeId < 1 || nodeId > 127) { return CO_ERROR_ILLEGAL_ARGUMENT; } CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; @@ -360,7 +361,9 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (OD_SDOsrvParIdx == OD_H1200_SDO_SERVER_1_PARAM) { /* configure default SDO channel and SDO server parameters for it */ - if (nodeId < 1 || nodeId > 127) return CO_ERROR_ILLEGAL_ARGUMENT; + if (nodeId < 1 || nodeId > 127) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; @@ -386,7 +389,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (odRet0 != ODR_OK || (maxSubIndex != 2 && maxSubIndex != 3) || odRet1 != ODR_OK || odRet2 != ODR_OK ) { - if (errInfo != NULL) *errInfo = OD_SDOsrvParIdx; + if (errInfo != NULL) { *errInfo = OD_SDOsrvParIdx; } return CO_ERROR_OD_PARAMETERS; } @@ -403,7 +406,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, ODR_t odRetE = OD_extension_init(OD_1200_SDOsrvPar, &SDO->OD_1200_extension); if (odRetE != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_SDOsrvParIdx; + if (errInfo != NULL) { *errInfo = OD_SDOsrvParIdx; } return CO_ERROR_OD_PARAMETERS; } #endif @@ -525,6 +528,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; return false; } + else { /* MISRA C 2004 14.10 */ } } else { /* Verify if size of data downloaded is not too large. */ @@ -577,6 +581,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; return false; } + else { /* MISRA C 2004 14.10 */ } return true; } @@ -628,7 +633,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, if (countRd > 0 && (SDO->OD_IO.stream.attribute & ODA_STR) != 0) { bufShifted[countRd] = 0; /* (SDO->buf is one byte larger) */ OD_size_t countStr = (OD_size_t)strlen((char *)bufShifted); - if (countStr == 0) countStr = 1; /* zero length is not allowed */ + if (countStr == 0) { countStr = 1; }/* zero length is not allowed */ if (countStr < countRd) { /* string terminator found, read is finished, shorten data */ countRd = countStr; @@ -763,6 +768,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_READONLY; SDO->state = CO_SDO_ST_ABORT; } + else { /* MISRA C 2004 14.10 */ } } } @@ -787,6 +793,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_DEVICE_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; } + else { /* MISRA C 2004 14.10 */ } } else { /* If data type is string, size is not known */ @@ -799,7 +806,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ } /* (SDO->state == CO_SDO_ST_IDLE) */ - if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) + if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) { switch (SDO->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { if (SDO->CANrxData[0] & 0x02) { @@ -810,10 +817,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Get SDO data size (indicated by SDO client or get from OD) */ OD_size_t dataSizeToWrite = 4; - if (SDO->CANrxData[0] & 0x01) + if (SDO->CANrxData[0] & 0x01) { dataSizeToWrite -= (SDO->CANrxData[0] >> 2) & 0x03; - else if (sizeInOd > 0 && sizeInOd < 4) + } + else if (sizeInOd > 0 && sizeInOd < 4) { dataSizeToWrite = sizeInOd; + } + else { /* MISRA C 2004 14.10 */ } /* copy data to the temp buffer, swap data if necessary */ uint8_t buf[6] = {0}; @@ -845,6 +855,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; break; } + else { /* MISRA C 2004 14.10 */ } /* Copy data */ OD_size_t countWritten = 0; @@ -891,6 +902,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; break; } + else { /* MISRA C 2004 14.10 */ } } } else { @@ -938,8 +950,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if (SDO->finished || (CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7+2) ) { - if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) + if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) { break; + } } SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; @@ -1151,14 +1164,17 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* unknown message received */ abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; + break; } } /* switch (SDO->state) */ + } /* if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) */ #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED SDO->timeoutTimer = 0; #endif timeDifference_us = 0; CO_FLAG_CLEAR(SDO->CANrxNew); - } /* if (isNew) */ + } /* else if (isNew) */ + else { /* MISRA C 2004 14.10 */ } /* Timeout timers and transmit bufferFull flag ****************************/ #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED @@ -1338,8 +1354,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { /* refill the data buffer if necessary */ - if (!readFromOd(SDO, &abortCode, 7, false)) + if (!readFromOd(SDO, &abortCode, 7, false)) { break; + } /* SDO command specifier with toggle bit */ SDO->CANtxBuff->data[0] = SDO->toggle; @@ -1380,6 +1397,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; break; } + else { /* MISRA C 2004 14.10 */ } } /* send message */ diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index c8599145..8e735b45 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -236,7 +236,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, odRet = OD_get_u32(OD_1005_cobIdSync, 0, &cobIdSync, true); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1005_cobIdSync); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1005_cobIdSync); } return CO_ERROR_OD_PARAMETERS; } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC @@ -251,12 +251,16 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, sizeof(uint32_t), NULL); #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER if (SYNC->OD_1006_period == NULL) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1006_commCyclePeriod); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1006_commCyclePeriod); + } return CO_ERROR_OD_PARAMETERS; } #else if (OD_1006_commCyclePeriod != NULL && SYNC->OD_1006_period == NULL) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1006_commCyclePeriod); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1006_commCyclePeriod); + } return CO_ERROR_OD_PARAMETERS; } #endif @@ -265,7 +269,9 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, SYNC->OD_1007_window = OD_getPtr(OD_1007_syncWindowLen, 0, sizeof(uint32_t), NULL); if (OD_1007_syncWindowLen != NULL && SYNC->OD_1007_window == NULL) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1007_syncWindowLen); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1007_syncWindowLen); + } return CO_ERROR_OD_PARAMETERS; } @@ -276,11 +282,14 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, if (OD_1019_syncCounterOvf != NULL) { odRet = OD_get_u8(OD_1019_syncCounterOvf, 0, &syncCounterOvf, true); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1019_syncCounterOvf); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1019_syncCounterOvf); + } return CO_ERROR_OD_PARAMETERS; } - if (syncCounterOvf == 1) syncCounterOvf = 2; - else if (syncCounterOvf > 240) syncCounterOvf = 240; + if (syncCounterOvf == 1) { syncCounterOvf = 2; } + else if (syncCounterOvf > 240) { syncCounterOvf = 240; } + else { /* MISRA C 2004 14.10 */ } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER @@ -317,8 +326,9 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, 0, /* rtr */ (void*)SYNC, /* object passed to receive function */ CO_SYNC_receive); /* this function will process received message*/ - if (ret != CO_ERROR_NO) + if (ret != CO_ERROR_NO) { return ret; + } #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER SYNC->CANtxBuff = CO_CANtxBufferInit( @@ -329,8 +339,9 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, syncCounterOvf != 0 ? 1 : 0, /* number of data bytes */ 0); /* synchronous message flag bit */ - if (SYNC->CANtxBuff == NULL) + if (SYNC->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; + } #endif return CO_ERROR_NO; @@ -365,7 +376,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, if (NMTisPreOrOperational) { /* update sync timer, no overflow */ uint32_t timerNew = SYNC->timer + timeDifference_us; - if (timerNew > SYNC->timer) SYNC->timer = timerNew; + if (timerNew > SYNC->timer) { SYNC->timer = timerNew; } /* was SYNC just received */ if (CO_FLAG_READ(SYNC->CANrxNew)) { @@ -401,7 +412,9 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, if (SYNC->timeoutError == 1) { /* periodTimeout is 1,5 * OD_1006_period, no overflow */ uint32_t periodTimeout = OD_1006_period + (OD_1006_period >> 1); - if (periodTimeout < OD_1006_period) periodTimeout = 0xFFFFFFFF; + if (periodTimeout < OD_1006_period) { + periodTimeout = 0xFFFFFFFF; + } if (SYNC->timer > periodTimeout) { CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, @@ -417,6 +430,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } #endif } + else { /* MISRA C 2004 14.10 */ } } /* if (OD_1006_period > 0) */ /* Synchronous PDOs are allowed only inside time window */ diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 9bc3384d..d78bd86b 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -223,7 +223,7 @@ void CO_SYNC_initCallbackPre(CO_SYNC_t *SYNC, * @return Same as CO_CANsend(). */ static inline CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC) { - if (++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1; + if (++SYNC->counter > SYNC->counterOverflowValue) { SYNC->counter = 1; } SYNC->timer = 0; SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; SYNC->CANtxBuff->data[0] = SYNC->counter; diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 48e311a9..6335593b 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -114,7 +114,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, uint32_t cobIdTimeStamp; ODR_t odRet = OD_get_u32(OD_1012_cobIdTimeStamp, 0, &cobIdTimeStamp, true); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1012_cobIdTimeStamp); + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1012_cobIdTimeStamp); } return CO_ERROR_OD_PARAMETERS; } #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC @@ -140,8 +140,9 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, 0, /* rtr */ (void*)TIME, /* object passed to receive function */ CO_TIME_receive);/*this function will process received message*/ - if (ret != CO_ERROR_NO) + if (ret != CO_ERROR_NO) { return ret; + } } #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 1ec77ac2..e9266724 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -398,6 +398,9 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, delimCommandFound = true; } break; + default: + /* MISRA C 2004 15.3 */ + break; } if (delimCommentFound == true) { /* Comment delimiter found, clear all till end of the line. */ @@ -745,6 +748,9 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { buf[len++] = base64EncTable[(word >> 6) & 0x3F]; buf[len++] = '='; break; + default: + /* MISRA C 2004 15.3 */ + break; } } break; @@ -1344,6 +1350,9 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { CO_fifo_putc(dest, (uint8_t)(dword >> 2)); destSpace -= 2; break; + default: + /* MISRA C 2004 15.3 */ + break; } bool_t insideComment = false; diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 9e3ce8c7..b5921bd4 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -75,8 +75,8 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, LEDs->LEDtmr200ms = 0; rd = gr = 0; - if ((LEDs->LEDred & CO_LED_blink) == 0) rd |= CO_LED_blink; - else gr |= CO_LED_blink; + if ((LEDs->LEDred & CO_LED_blink) == 0) { rd |= CO_LED_blink; } + else { gr |= CO_LED_blink; } switch (++LEDs->LEDtmrflash_1) { case 1: rd |= CO_LED_flash_1; break; @@ -110,8 +110,8 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, } /* calculate 10Hz flickering */ - if (rdFlickerNext) rd |= CO_LED_flicker; - else gr |= CO_LED_flicker; + if (rdFlickerNext) { rd |= CO_LED_flicker; } + else { gr |= CO_LED_flicker; } } /* while (LEDs->LEDtmr50ms >= 50000) */ @@ -119,25 +119,25 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, uint8_t rd_co, gr_co; /* CANopen red ERROR LED */ - if (ErrCANbusOff) rd_co = 1; - else if (NMTstate == CO_NMT_INITIALIZING) rd_co = rd & CO_LED_flicker; - else if (ErrRpdo) rd_co = rd & CO_LED_flash_4; - else if (ErrSync) rd_co = rd & CO_LED_flash_3; - else if (ErrHbCons) rd_co = rd & CO_LED_flash_2; - else if (ErrCANbusWarn) rd_co = rd & CO_LED_flash_1; - else if (ErrOther) rd_co = rd & CO_LED_blink; - else rd_co = 0; + if (ErrCANbusOff) { rd_co = 1;} + else if (NMTstate == CO_NMT_INITIALIZING){ rd_co = rd & CO_LED_flicker;} + else if (ErrRpdo) { rd_co = rd & CO_LED_flash_4;} + else if (ErrSync) { rd_co = rd & CO_LED_flash_3;} + else if (ErrHbCons) { rd_co = rd & CO_LED_flash_2;} + else if (ErrCANbusWarn) { rd_co = rd & CO_LED_flash_1;} + else if (ErrOther) { rd_co = rd & CO_LED_blink;} + else { rd_co = 0;} /* CANopen green RUN LED */ - if (LSSconfig) gr_co = gr & CO_LED_flicker; - else if (firmwareDownload) gr_co = gr & CO_LED_flash_3; - else if (NMTstate == CO_NMT_STOPPED) gr_co = gr & CO_LED_flash_1; - else if (NMTstate == CO_NMT_PRE_OPERATIONAL)gr_co = gr & CO_LED_blink; - else if (NMTstate == CO_NMT_OPERATIONAL) gr_co = 1; - else gr_co = 0; - - if (rd_co != 0) rd |= CO_LED_CANopen; - if (gr_co != 0) gr |= CO_LED_CANopen; + if (LSSconfig) {gr_co = gr & CO_LED_flicker;} + else if (firmwareDownload) {gr_co = gr & CO_LED_flash_3;} + else if (NMTstate == CO_NMT_STOPPED) {gr_co = gr & CO_LED_flash_1;} + else if (NMTstate == CO_NMT_PRE_OPERATIONAL){gr_co = gr & CO_LED_blink;} + else if (NMTstate == CO_NMT_OPERATIONAL) {gr_co = 1;} + else {gr_co = 0;} + + if (rd_co != 0) { rd |= CO_LED_CANopen; } + if (gr_co != 0) { gr |= CO_LED_CANopen; } LEDs->LEDred = rd; LEDs->LEDgreen = gr; } /* if (tick) */ diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 2702fba6..a5b26d49 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -163,6 +163,7 @@ static void CO_LSSslave_receive(void *object, void *msg) } } } + else { /* MISRA C 2004 14.10 */ } if (ack) { #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 4922f354..ebdb580c 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -742,6 +742,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, case 3: /* token contains digit */ err = true; break; + default: + /* MISRA C 2004 15.3 */ + break; } if (err) break; diff --git a/CANopen.c b/CANopen.c index 3f4518ac..aa5d6e54 100644 --- a/CANopen.c +++ b/CANopen.c @@ -331,7 +331,9 @@ #endif /* Define macros for allocation */ -#define CO_alloc_break_on_fail(var, num, size) if (((var) = CO_alloc((num), (size))) != NULL) { mem += (size) * (num); } else { break; } +#define CO_alloc_break_on_fail(var, num, size) { \ + var = CO_alloc((num), (size)); \ + if((var) != NULL) { mem += (size) * (num); } else { break; } } #ifdef CO_MULTIPLE_OD #define ON_MULTI_OD(sentence) sentence @@ -893,7 +895,7 @@ bool_t CO_isLSSslaveEnabled(CO_t *co) { (void) co; /* may be unused */ bool_t en = false; #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - if (CO_GET_CNT(LSS_SLV) == 1) en = true; + if (CO_GET_CNT(LSS_SLV) == 1) { en = true; } #endif return en; } @@ -902,7 +904,7 @@ bool_t CO_isLSSslaveEnabled(CO_t *co) { CO_ReturnError_t CO_CANinit(CO_t *co, void *CANptr, uint16_t bitRate) { CO_ReturnError_t err; - if (co == NULL) return CO_ERROR_ILLEGAL_ARGUMENT; + if (co == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } co->CANmodule->CANnormal = false; CO_CANsetConfigurationMode(CANptr); @@ -993,11 +995,12 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, if (nodeId < 1 || nodeId > 127) { return CO_ERROR_ILLEGAL_ARGUMENT; } + else { /* MISRA C 2004 14.10 */ } #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE if (CO_GET_CNT(LEDS) == 1) { err = CO_LEDs_init(co->LEDs); - if (err) return err; + if (err) { return err; } } #endif @@ -1034,7 +1037,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif nodeId, errInfo); - if (err) return err; + if (err) { return err; } } /* NMT_Heartbeat */ @@ -1057,7 +1060,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(TX_IDX_HB_PROD), CO_CAN_ID_HEARTBEAT + nodeId, errInfo); - if (err) return err; + if (err) { return err; } } #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE @@ -1070,7 +1073,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(RX_IDX_HB_CONS), errInfo); - if (err) return err; + if (err) { return err; } } #endif @@ -1085,7 +1088,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_NG_SLV), errInfo); - if (err) return err; + if (err) { return err; } #endif #if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE err = CO_nodeGuardingMaster_init(co->NGmaster, @@ -1094,7 +1097,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(RX_IDX_NG_MST), co->CANmodule, CO_GET_CO(TX_IDX_NG_MST)); - if (err) return err; + if (err) { return err; } #endif /* SDOserver */ @@ -1111,7 +1114,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_SDO_SRV) + i, errInfo); - if (err) return err; + if (err) { return err; } } } @@ -1128,7 +1131,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_SDO_CLI) + i, errInfo); - if (err) return err; + if (err) { return err; } } } #endif @@ -1144,7 +1147,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(TX_IDX_TIME), #endif errInfo); - if (err) return err; + if (err) { return err; } } #endif @@ -1163,7 +1166,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(TX_IDX_SYNC), #endif errInfo); - if (err) return err; + if (err) { return err; } } #endif @@ -1177,7 +1180,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_GFC), CO_CAN_ID_GFC); - if (err) return err; + if (err) { return err; } } #endif @@ -1189,7 +1192,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, &OD_configurationValid, OD_H13FE_SRDO_VALID, OD_H13FF_SRDO_CHECKSUM); - if (err) return err; + if (err) { return err; } OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); OD_entry_t *SRDOmap = OD_GET(H1318, OD_H1381_SRDO_1_MAPPING); @@ -1214,7 +1217,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CANdevTxIdx, CANdevTxIdx + 1); - if (err) return err; + if (err) { return err; } } } #endif @@ -1229,7 +1232,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_LSS_MST), CO_CAN_ID_LSS_MST); - if (err) return err; + if (err) { return err; } } #endif @@ -1251,7 +1254,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->LEDs, #endif 0); - if (err) return err; + if (err) { return err; } } #endif @@ -1274,7 +1277,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, &OD_trace[i].triggerTime, OD_INDEX_TRACE_CONFIG + i, OD_INDEX_TRACE + i); - if (err) return err; + if (err) { return err; } } } #endif @@ -1327,7 +1330,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, co->CANmodule, CO_GET_CO(RX_IDX_RPDO) + i, errInfo); - if (err) return err; + if (err) { return err; } } } #endif @@ -1361,7 +1364,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_TPDO) + i, errInfo); - if (err) return err; + if (err) { return err; } } } #endif @@ -1525,6 +1528,9 @@ bool_t CO_process_SYNC(CO_t *co, case CO_SYNC_PASSED_WINDOW: CO_CANclearPendingSyncPDOs(co->CANmodule); break; + default: + /* MISRA C 2004 15.3 */ + break; } } diff --git a/codingStyle b/codingStyle index 94467f44..70d0e937 100644 --- a/codingStyle +++ b/codingStyle @@ -91,19 +91,54 @@ int32_t foo1(object1_t *thisObj, * comment. */ + /* All if and else statement must have use { } around their bodies + * (MISRA C 2004 rule 14.9) + */ if (xy == yz) { /* Comment. '//' comments are not allowed */ a = b; - } else { + } else if (xy < yz) { a = c; } + else { + /* To stay compliant with MISRA C 2004 14.10 + * all else if statements need a final else even if empty + */ + } + + /* Assignment operators shall not be used in expressions which return + * boolean values (MISRA C 2004 rule 13.1) + * This is true for: 'if' and 'while' statements. + * For instance: + */ + if (xy = yz){ + } + while (xy = yz){ + } switch (zx) { case 1: a = b; + break + default: + /* To stay compliant with MISRA C 2004 15.3 + * the default case must be present */ break; } } +/* MISRA C 2004 Rule E14.4.3 + * There should be no more than one break or goto statement used to terminate + * any iteration statement. + */ + +/* MISRA C 2004 Rule 14.5 + * The continue statement shall not be used. + */ + +/* More about MISRA C + * https://www.ibm.com/docs/en/devops-test-embedded/9.0.0?topic=review-code-misra-2004-rules + */ + /** @} */ #ifdef __cplusplus diff --git a/extra/CO_trace.c b/extra/CO_trace.c index 96b3c76a..3902f8f9 100644 --- a/extra/CO_trace.c +++ b/extra/CO_trace.c @@ -236,6 +236,9 @@ static CO_SDO_abortCode_t CO_ODF_traceConfig(CO_ODF_arg_t *ODF_arg) { } } break; + default: + /* MISRA C 2004 15.3 */ + break; } return ret; @@ -387,6 +390,9 @@ static CO_SDO_abortCode_t CO_ODF_trace(CO_ODF_arg_t *ODF_arg) { } } break; + default: + /* MISRA C 2004 15.3 */ + break; } return ret; From f96ffb2526b9c70a9b1a6dd5271e64ee553092e2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 <163388497+temi54c1l8@users.noreply.github.com> Date: Tue, 9 Apr 2024 11:56:43 +0200 Subject: [PATCH 244/520] Porting SRDO to v4.0 (#505) * Renamed structure from CO_SDO_t to CO_SDOserver_t * Porting SRDOGuard * Porting SRDO * Porting SRDO on CANopen.c with new parameters * Misra for SRDO * Fix extension read and write control count * Remove pointer to configurationValid and CRC and connect to OD * Remove dependencies from CO_SDOserver.h and CO_NMT_Heartbeat.h * Replaced CO_driver.h with CO_ODinterface.h --- 304/CO_SRDO.c | 774 ++++++++++++++++++++++++++++++-------------------- 304/CO_SRDO.h | 117 ++++---- CANopen.c | 28 +- 3 files changed, 536 insertions(+), 383 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 33d0a64e..980d8ffa 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -41,6 +41,9 @@ #define CO_SRDO_VALID_MAGIC (0xA5) +#define CO_SRDO_BITCMD_OPERATIONAL (0x01U) +#define CO_SRDO_BITCMD_CALC_CRC (0x02U) + static void CO_SRDO_receive_normal(void *object, void *msg){ CO_SRDO_t *SRDO; uint8_t DLC = CO_CANrxMsg_readDLC(msg); @@ -49,8 +52,7 @@ static void CO_SRDO_receive_normal(void *object, void *msg){ SRDO = (CO_SRDO_t*)object; /* this is the correct pointer type of the first argument */ if( (SRDO->valid == CO_SRDO_RX) && - (DLC >= SRDO->dataLength) && !CO_FLAG_READ(SRDO->CANrxNew[1])) - { + (DLC >= SRDO->dataLength) && !CO_FLAG_READ(SRDO->CANrxNew[1])){ /* copy data into appropriate buffer and set 'new message' flag */ memcpy(SRDO->CANrxData[0], data, sizeof(SRDO->CANrxData[0])); CO_FLAG_SET(SRDO->CANrxNew[0]); @@ -72,8 +74,7 @@ static void CO_SRDO_receive_inverted(void *object, void *msg){ SRDO = (CO_SRDO_t*)object; /* this is the correct pointer type of the first argument */ if( (SRDO->valid == CO_SRDO_RX) && - (DLC >= SRDO->dataLength) && CO_FLAG_READ(SRDO->CANrxNew[0])) - { + (DLC >= SRDO->dataLength) && CO_FLAG_READ(SRDO->CANrxNew[0])){ /* copy data into appropriate buffer and set 'new message' flag */ memcpy(SRDO->CANrxData[1], data, sizeof(SRDO->CANrxData[1])); CO_FLAG_SET(SRDO->CANrxNew[1]); @@ -101,18 +102,18 @@ static void CO_SRDOconfigCom(CO_SRDO_t* SRDO, uint32_t COB_IDnormal, uint32_t CO SRDO->valid = CO_SRDO_INVALID; /* is SRDO used? */ - if(*SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC && (SRDO->SRDOCommPar->informationDirection == CO_SRDO_TX || SRDO->SRDOCommPar->informationDirection == CO_SRDO_RX) && + if((SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC) && ((SRDO->CommPar_informationDirection == CO_SRDO_TX) || (SRDO->CommPar_informationDirection == CO_SRDO_RX)) && SRDO->dataLength){ - ID = &IDs[SRDO->SRDOCommPar->informationDirection - 1][0]; + ID = &IDs[SRDO->CommPar_informationDirection - 1][0]; /* is used default COB-ID? */ for(i = 0; i < 2; i++){ if(!(COB_ID[i] & 0xBFFFF800L)){ ID[i] = (uint16_t)COB_ID[i] & 0x7FF; - if(ID[i] == SRDO->defaultCOB_ID[i] && SRDO->nodeId <= 64){ - ID[i] += 2*SRDO->nodeId; + if((ID[i] == SRDO->defaultCOB_ID[i]) && (SRDO->nodeId <= 64U)){ + ID[i] += (uint16_t)SRDO->nodeId*2; } - if(0x101 <= ID[i] && ID[i] <= 0x180 && ((ID[i] & 1) != i )){ + if((0x101U <= ID[i]) && (ID[i] <= 0x180U) && ((ID[i] & 1) != i )){ successCount++; } } @@ -120,14 +121,15 @@ static void CO_SRDOconfigCom(CO_SRDO_t* SRDO, uint32_t COB_IDnormal, uint32_t CO } /* all ids are ok*/ if(successCount == 2){ - SRDO->valid = SRDO->SRDOCommPar->informationDirection; + SRDO->valid = SRDO->CommPar_informationDirection; if (SRDO->valid == CO_SRDO_TX){ - SRDO->timer = 500 * SRDO->nodeId; /* 0.5ms * node-ID delay*/ + SRDO->timer = (uint32_t)SRDO->nodeId * 500U; /* 0.5ms * node-ID delay*/ } else if (SRDO->valid == CO_SRDO_RX){ - SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U; + SRDO->timer = (uint32_t)SRDO->CommPar_safetyCycleTime * 1000U; } + else { /* MISRA C 2004 14.10 */ } } else{ memset(IDs, 0, sizeof(IDs)); @@ -166,357 +168,435 @@ static void CO_SRDOconfigCom(CO_SRDO_t* SRDO, uint32_t COB_IDnormal, uint32_t CO } } -static uint32_t CO_SRDOfindMap( - CO_SDO_t *SDO, - uint32_t map, - uint8_t R_T, - uint8_t **ppData, - uint8_t *pLength, - uint8_t *pSendIfCOSFlags, - uint8_t *pIsMultibyteVar) -{ - uint16_t entryNo; - uint16_t index; - uint8_t subIndex; - uint8_t dataLen; - uint8_t objectLen; - uint8_t attr; - - index = (uint16_t)(map>>16); - subIndex = (uint8_t)(map>>8); - dataLen = (uint8_t) map; /* data length in bits */ - - /* data length must be byte aligned */ - if(dataLen&0x07) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ - - dataLen >>= 3; /* new data length is in bytes */ - *pLength += dataLen; - - /* total PDO length can not be more than 8 bytes */ - if(*pLength > 8) return CO_SDO_AB_MAP_LEN; /* The number and length of the objects to be mapped would exceed PDO length. */ - - /* is there a reference to dummy entries */ - if(index <=7 && subIndex == 0){ - static uint32_t dummyTX = 0; - static uint32_t dummyRX; - uint8_t dummySize = 4; - - if(index<2) dummySize = 0; - else if(index==2 || index==5) dummySize = 1; - else if(index==3 || index==6) dummySize = 2; - - /* is size of variable big enough for map */ - if(dummySize < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ - - /* Data and ODE pointer */ - if(R_T == 0) *ppData = (uint8_t*) &dummyRX; - else *ppData = (uint8_t*) &dummyTX; - - return 0; - } - - /* find object in Object Dictionary */ - entryNo = CO_OD_find(SDO, index); - - /* Does object exist in OD? */ - if(entryNo == 0xFFFF || subIndex > SDO->OD[entryNo].maxSubIndex) - return CO_SDO_AB_NOT_EXIST; /* Object does not exist in the object dictionary. */ - - attr = CO_OD_getAttribute(SDO, entryNo, subIndex); - /* Is object Mappable for RPDO? */ - if(R_T==0 && !((attr&CO_ODA_RPDO_MAPABLE) && (attr&CO_ODA_WRITEABLE))) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ - /* Is object Mappable for TPDO? */ - if(R_T!=0 && !((attr&CO_ODA_TPDO_MAPABLE) && (attr&CO_ODA_READABLE))) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ - - /* is size of variable big enough for map */ - objectLen = CO_OD_getLength(SDO, entryNo, subIndex); - if(objectLen < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */ +static CO_ReturnError_t SRDO_configMap(CO_SRDO_t* SRDO, + OD_t *OD, + OD_entry_t *OD_SRDOMapPar){ + ODR_t odRet; + size_t pdoDataLength[2] = { 0, 0 }; + uint8_t mappedObjectsCount = 0; + uint8_t *errInfo = NULL; + //uint32_t *erroneousMap = NULL; + + /* number of mapped application objects in SRDO */ + odRet = OD_get_u8(OD_SRDOMapPar, 0, &mappedObjectsCount, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_SRDOMapPar)) << 8) | 0U; + } + return CO_ERROR_OD_PARAMETERS; + } + if (mappedObjectsCount > CO_SRDO_MAX_SIZE) { + //*erroneousMap = 1; + return CO_ERROR_NO; + } + + /* iterate mapped OD variables */ + for(uint8_t i=0; iCommPar_informationDirection == CO_SRDO_RX; + uint32_t map = 0; + uint8_t plain_inverted = i%2; + + odRet = OD_get_u32(OD_SRDOMapPar, i + 1, &map, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_SRDOMapPar)) << 8) | i; + } + return CO_ERROR_OD_PARAMETERS; + } - /* mark multibyte variable */ - *pIsMultibyteVar = (attr&CO_ODA_MB_VALUE) ? 1 : 0; + uint16_t index = (uint16_t) (map >> 16); + uint8_t subIndex = (uint8_t) (map >> 8); + uint8_t mappedLengthBits = (uint8_t) map; + uint8_t mappedLength = mappedLengthBits >> 3; + uint8_t pdoDataStart = pdoDataLength[plain_inverted]; + pdoDataLength[plain_inverted] += mappedLength; - /* pointer to data */ - *ppData = (uint8_t*) CO_OD_getDataPointer(SDO, entryNo, subIndex); -#ifdef CO_BIG_ENDIAN - /* skip unused MSB bytes */ - if(*pIsMultibyteVar){ - *ppData += objectLen - dataLen; - } -#endif + if (((mappedLengthBits & 0x07) != 0) || (pdoDataLength[plain_inverted] > CO_SRDO_MAX_SIZE)) { + //*erroneousMap = map; + return CO_ERROR_NO; + } - /* setup change of state flags */ - if(attr&CO_ODA_TPDO_DETECT_COS){ - int16_t i; - for(i=*pLength-dataLen; i<*pLength; i++){ - *pSendIfCOSFlags |= 1<mapPointer[plain_inverted][j] = isRSRDO ? &dummyRX : &dummyTX; + } + continue; } - } - return 0; -} + /* find entry in the Object Dictionary, original location */ + OD_IO_t OD_IO; + OD_entry_t *entry = OD_find(OD, index); + OD_attr_t testAttribute = isRSRDO ? ODA_RSRDO : ODA_TSRDO; + + odRet = OD_getSub(entry, subIndex, &OD_IO, true); + if (odRet != ODR_OK + || (OD_IO.stream.attribute & testAttribute) == 0 + || OD_IO.stream.dataLength < mappedLength + || OD_IO.stream.dataOrig == NULL + ) { + //*erroneousMap = map; + return CO_ERROR_NO; + } -static uint32_t CO_SRDOconfigMap(CO_SRDO_t* SRDO, uint8_t noOfMappedObjects){ - int16_t i; - uint8_t lengths[2] = {0}; - uint32_t ret = 0; - const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0]; - - - for(i=noOfMappedObjects; i>0; i--){ - int16_t j; - uint8_t* pData; - uint8_t dummy = 0; - uint8_t* length = &lengths[i%2]; - uint8_t** mapPointer = SRDO->mapPointer[i%2]; - uint8_t prevLength = *length; - uint8_t MBvar; - uint32_t map = *(pMap++); - - /* function do much checking of errors in map */ - ret = CO_SRDOfindMap( - SRDO->SDO, - map, - SRDO->SRDOCommPar->informationDirection == CO_SRDO_TX, - &pData, - length, - &dummy, - &MBvar); - if(ret){ - *length = 0; - CO_errorReport(SRDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, map); - break; - } - - /* write SRDO data pointers */ + /* write locations to OD variable data bytes into PDO map pointers */ #ifdef CO_BIG_ENDIAN - if(MBvar){ - for(j=*length-1; j>=prevLength; j--) - mapPointer[j] = pData++; - } - else{ - for(j=prevLength; j<*length; j++) - mapPointer[j] = pData++; - } -#else - for(j=prevLength; j<*length; j++){ - mapPointer[j] = pData++; + if((OD_IO.stream.attribute & ODA_MB) != 0) { + uint8_t *odDataPointer = OD_IO.stream.dataOrig + + OD_IO.stream.dataLength - 1; + for (uint8_t j = pdoDataStart; j < pdoDataLength; j++) { + SRDO->mapPointer[j] = odDataPointer--; + } } + else #endif - + { + uint8_t *odDataPointer = OD_IO.stream.dataOrig; + for (uint8_t j = pdoDataStart; j < pdoDataLength[plain_inverted]; j++) { + SRDO->mapPointer[plain_inverted][j] = odDataPointer++; + } + } } - if(lengths[0] == lengths[1]) - SRDO->dataLength = lengths[0]; - else{ + + if(pdoDataLength[0] == pdoDataLength[1]){ + SRDO->dataLength = pdoDataLength[0]; + //SRDO->mappedObjectsCount = pdoDataLength[0]; + }else{ SRDO->dataLength = 0; CO_errorReport(SRDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, 0); - ret = CO_SDO_AB_MAP_LEN; + return CO_ERROR_OD_PARAMETERS; } - return ret; + return CO_ERROR_NO; } static uint16_t CO_SRDOcalcCrc(const CO_SRDO_t *SRDO){ - uint16_t i; + uint16_t i,tmp_u16; uint16_t result = 0x0000; uint8_t buffer[4]; - uint32_t cob; - - const CO_SRDOCommPar_t *com = SRDO->SRDOCommPar; - const CO_SRDOMapPar_t *map = SRDO->SRDOMapPar; - - result = crc16_ccitt(&com->informationDirection, 1, result); - CO_memcpySwap2(&buffer[0], &com->safetyCycleTime); + uint32_t cob, tmp_u32; + uint32_t map; + ODR_t odRet; + + result = crc16_ccitt(&SRDO->CommPar_informationDirection, 1, result); + tmp_u16 = CO_SWAP_16(SRDO->CommPar_safetyCycleTime); + memcpy(&buffer[0], &tmp_u16, sizeof(tmp_u16)); result = crc16_ccitt(&buffer[0], 2, result); - result = crc16_ccitt(&com->safetyRelatedValidationTime, 1, result); + result = crc16_ccitt(&SRDO->CommPar_safetyRelatedValidationTime, 1, result); /* adjust COB-ID if the default is used Caution: if the node id changes and you are using the default COB-ID you have to recalculate the checksum This behaviour is controversial and could be changed or made optional. */ - cob = com->COB_ID1_normal; - if(((cob)&0x7FF) == SRDO->defaultCOB_ID[0] && SRDO->nodeId <= 64) - cob += SRDO->nodeId; - CO_memcpySwap4(&buffer[0], &cob); + cob = SRDO->CommPar_COB_ID1_normal; + if(((cob&0x7FFU) == SRDO->defaultCOB_ID[0]) && (SRDO->nodeId <= 64U)){ + cob += (uint32_t)SRDO->nodeId*2; + } + tmp_u32 = CO_SWAP_32(cob); + memcpy(&buffer[0], &tmp_u32, sizeof(tmp_u32)); result = crc16_ccitt(&buffer[0], 4, result); - cob = com->COB_ID2_inverted; - if(((cob)&0x7FF) == SRDO->defaultCOB_ID[1] && SRDO->nodeId <= 64) - cob += SRDO->nodeId; - CO_memcpySwap4(&buffer[0], &cob); + cob = SRDO->CommPar_COB_ID2_inverted; + if(((cob&0x7FFU) == SRDO->defaultCOB_ID[1]) && (SRDO->nodeId <= 64U)){ + cob += (uint32_t)SRDO->nodeId*2; + } + tmp_u32 = CO_SWAP_32(cob); + memcpy(&buffer[0], &tmp_u32, sizeof(tmp_u32)); result = crc16_ccitt(&buffer[0], 4, result); - result = crc16_ccitt(&map->numberOfMappedObjects, 1, result); - for(i = 0; i < map->numberOfMappedObjects;){ - uint8_t subindex = i + 1; + result = crc16_ccitt(&SRDO->mappedObjectsCount, 1, result); + for(i = 0; i < SRDO->mappedObjectsCount;){ + uint8_t subindex = i + 1U; result = crc16_ccitt(&subindex, 1, result); - CO_memcpySwap4(&buffer[0], &map->mappedObjects[i]); + odRet = OD_get_u32(SRDO->SRDOMapPar, subindex, &map, true); + if (odRet != ODR_OK) { + map = 0; + } + tmp_u32 = CO_SWAP_32(map); + memcpy(&buffer[0], &tmp_u32, sizeof(tmp_u32)); result = crc16_ccitt(&buffer[0], 4, result); i = subindex; } return result; } -static CO_SDO_abortCode_t CO_ODF_SRDOcom(CO_ODF_arg_t *ODF_arg){ - CO_SRDO_t *SRDO; - SRDO = (CO_SRDO_t*) ODF_arg->object; +static ODR_t OD_read_SRDO_communicationParam(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) +{ + ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); + if ( returnCode != ODR_OK ){ + return returnCode; + } + + if ((stream == NULL) || (buf == NULL) || (countRead == NULL) + ) { + return ODR_DEV_INCOMPAT; + } + + CO_SRDO_t *SRDO = stream->object; + /* Reading Object Dictionary variable */ - if(ODF_arg->reading){ - if(ODF_arg->subIndex == 5 || ODF_arg->subIndex == 6){ - uint32_t value = CO_getUint32(ODF_arg->data); - uint16_t index = ODF_arg->subIndex - 5; + if ((stream->subIndex == 5U) || (stream->subIndex == 6U)){ + uint32_t value = CO_getUint32(buf); + uint16_t index = stream->subIndex - 5U; - /* if default COB ID is used, write default value here */ - if(((value)&0x7FF) == SRDO->defaultCOB_ID[index] && SRDO->nodeId <= 64) - value += SRDO->nodeId; + /* if default COB ID is used, write default value here */ + if(((value&0x7FFU) == SRDO->defaultCOB_ID[index]) && (SRDO->nodeId <= 64U)){ + value += (uint32_t)SRDO->nodeId*2; + } - /* If SRDO is not valid, set bit 31. but I do not think this applies to SRDO ?! */ - /* if(!SRDO->valid) value |= 0x80000000L; */ + /* If SRDO is not valid, set bit 31. but I do not think this applies to SRDO ?! */ + /* if(!SRDO->valid){ value |= 0x80000000L; }*/ - CO_setUint32(ODF_arg->data, value); - } - return CO_SDO_AB_NONE; + CO_setUint32(buf, value); } + return ODR_OK; +} + + +static ODR_t OD_write_SRDO_communicationParam(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) + || (countWritten == NULL) || (count > 4) + ) { + return ODR_DEV_INCOMPAT; + } + + CO_SRDO_t *SRDO = stream->object; + CO_SRDOGuard_t *SRDOGuard = SRDO->SRDOGuard; + uint8_t bufCopy[4]; + memcpy(bufCopy, buf, count); /* Writing Object Dictionary variable */ - if(*SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL) - return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + if(SRDOGuard->operatingState){ + return ODR_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + } - if(ODF_arg->subIndex == 1){ - uint8_t value = ODF_arg->data[0]; - if (value > 2) - return CO_SDO_AB_INVALID_VALUE; + if(stream->subIndex == 1U){ + uint8_t value = CO_getUint8(buf); + if (value > 2U){ + return ODR_INVALID_VALUE; + } + SRDO->CommPar_informationDirection = value; } - else if(ODF_arg->subIndex == 2){ - uint16_t value = CO_getUint16(ODF_arg->data); - if (value == 0) - return CO_SDO_AB_INVALID_VALUE; + else if(stream->subIndex == 2U){ + uint16_t value = CO_getUint16(buf); + if (value == 0U){ + return ODR_INVALID_VALUE; + } + SRDO->CommPar_safetyCycleTime = value; } - else if(ODF_arg->subIndex == 3){ - uint8_t value = ODF_arg->data[0]; - if (value == 0) - return CO_SDO_AB_INVALID_VALUE; + else if(stream->subIndex == 3U){ + uint8_t value = CO_getUint8(buf); + if (value == 0U){ + return ODR_INVALID_VALUE; + } + SRDO->CommPar_safetyRelatedValidationTime = value; } - else if(ODF_arg->subIndex == 4){ /* Transmission_type */ - uint8_t *value = (uint8_t*) ODF_arg->data; - if(*value != 254) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + else if(stream->subIndex == 4){ /* Transmission_type */ + uint8_t value = CO_getUint8(buf); + if(value != 254){ + return ODR_INVALID_VALUE; /* Invalid value for parameter (download only). */ + } + SRDO->CommPar_transmissionType = value; } - else if(ODF_arg->subIndex == 5 || ODF_arg->subIndex == 6){ /* COB_ID */ - uint32_t value = CO_getUint32(ODF_arg->data); - uint16_t index = ODF_arg->subIndex - 5; + else if(stream->subIndex == 5U || stream->subIndex == 6U){ /* COB_ID */ + uint32_t value = CO_getUint32(buf); + uint16_t index = stream->subIndex - 5U; /* check value range, the spec does not specify if COB-ID flags are allowed */ - if(value < 0x101 || value > 0x180 || (value & 1) == index) - return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */ + if((value < 0x101) || (value > 0x180U) || ((value & 1) == index)){ + return ODR_INVALID_VALUE; /* Invalid value for parameter (download only). */ + } /* if default COB-ID is being written, write defaultCOB_ID without nodeId */ - if(SRDO->nodeId <= 64 && value == (SRDO->defaultCOB_ID[index] + SRDO->nodeId)){ + if((SRDO->nodeId <= 64U) && (value == (SRDO->defaultCOB_ID[index] + ((uint32_t)SRDO->nodeId*2)))){ value = SRDO->defaultCOB_ID[index]; - CO_setUint32(ODF_arg->data, value); + CO_setUint32(bufCopy, value); + } + if(index == 0U){ + SRDO->CommPar_COB_ID1_normal = value; + } + else{ + SRDO->CommPar_COB_ID2_inverted = value; } } + else { /* MISRA C 2004 14.10 */ } - *SRDO->SRDOGuard->configurationValid = CO_SRDO_INVALID; + SRDOGuard->configurationValid = CO_SRDO_INVALID; - return CO_SDO_AB_NONE; + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, bufCopy, count, countWritten); } -static CO_SDO_abortCode_t CO_ODF_SRDOmap(CO_ODF_arg_t *ODF_arg){ - CO_SRDO_t *SRDO; - SRDO = (CO_SRDO_t*) ODF_arg->object; - if(ODF_arg->reading) - return CO_SDO_AB_NONE; + +static ODR_t OD_write_SRDO_mappingParam(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || + (stream->subIndex > CO_SRDO_MAX_MAPPED_ENTRIES) + ) { + return ODR_DEV_INCOMPAT; + } + + CO_SRDO_t *SRDO = stream->object; + CO_SRDOGuard_t *SRDOGuard = SRDO->SRDOGuard; /* Writing Object Dictionary variable */ + if(SRDOGuard->operatingState){ + return ODR_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + } - if(*SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL) - return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ - if(SRDO->SRDOCommPar->informationDirection) /* SRDO must be deleted */ - return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */ + if(SRDO->CommPar_informationDirection){ /* SRDO must be deleted */ + return ODR_UNSUPP_ACCESS; /* Unsupported access to an object. */ + } /* numberOfMappedObjects */ - if(ODF_arg->subIndex == 0){ - uint8_t *value = (uint8_t*) ODF_arg->data; - - if(*value > 16 || *value & 1) /*only odd numbers are allowed*/ - return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds SRDO length. */ + if(stream->subIndex == 0U){ + uint8_t value = CO_getUint8(buf); + if((value > 16U) || (value & 1)){ /*only odd numbers are allowed*/ + return ODR_MAP_LEN; /* Number and length of object to be mapped exceeds SRDO length. */ + } + SRDO->mappedObjectsCount = value; } else{ - if (SRDO->SRDOMapPar->numberOfMappedObjects != 0) - return CO_SDO_AB_UNSUPPORTED_ACCESS; + if (SRDO->mappedObjectsCount != 0U){ + return ODR_UNSUPP_ACCESS; + } } - *SRDO->SRDOGuard->configurationValid = CO_SRDO_INVALID; - return CO_SDO_AB_NONE; + SRDOGuard->configurationValid = CO_SRDO_INVALID; + + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, buf, count, countWritten); } -static CO_SDO_abortCode_t CO_ODF_SRDOcrc(CO_ODF_arg_t *ODF_arg){ - CO_SRDOGuard_t *SRDOGuard; +static ODR_t OD_read_13FE(OD_stream_t *stream, void *buf, + OD_size_t count, OD_size_t *countRead) +{ + ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); + if ( returnCode != ODR_OK ){ + return returnCode; + } + + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countRead == NULL) + ) { + return ODR_DEV_INCOMPAT; + } + + CO_SRDOGuard_t *SRDOGuard = stream->object; + CO_setUint8(buf, SRDOGuard->configurationValid); + + return ODR_OK; +} + +static ODR_t OD_write_13FE(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countWritten == NULL) + ) { + return ODR_DEV_INCOMPAT; + } - SRDOGuard = (CO_SRDOGuard_t*) ODF_arg->object; + CO_SRDOGuard_t *SRDOGuard = stream->object; + uint8_t value = CO_getUint8(buf); - if (!ODF_arg->reading){ - if(*SRDOGuard->operatingState == CO_NMT_OPERATIONAL) - return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ - *SRDOGuard->configurationValid = CO_SRDO_INVALID; + if(SRDOGuard->operatingState){ + return ODR_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ } - return CO_SDO_AB_NONE; + SRDOGuard->checkCRC = ( value == CO_SRDO_VALID_MAGIC ); + + SRDOGuard->configurationValid = value; + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, buf, count, countWritten); } -static CO_SDO_abortCode_t CO_ODF_SRDOvalid(CO_ODF_arg_t *ODF_arg){ - CO_SRDOGuard_t *SRDOGuard; +static ODR_t OD_write_13FF(OD_stream_t *stream, const void *buf, + OD_size_t count, OD_size_t *countWritten) +{ + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (countWritten == NULL) + ) { + return ODR_DEV_INCOMPAT; + } - SRDOGuard = (CO_SRDOGuard_t*) ODF_arg->object; + CO_SRDOGuard_t *SRDOGuard = stream->object; + uint16_t value = CO_getUint16(buf); - if(!ODF_arg->reading){ - if(*SRDOGuard->operatingState == CO_NMT_OPERATIONAL) - return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ - SRDOGuard->checkCRC = ODF_arg->data[0] == CO_SRDO_VALID_MAGIC; + if(SRDOGuard->operatingState){ + return ODR_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ } - return CO_SDO_AB_NONE; + SRDOGuard->configurationValid = CO_SRDO_INVALID; + + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, buf, count, countWritten); } CO_ReturnError_t CO_SRDOGuard_init( CO_SRDOGuard_t *SRDOGuard, - CO_SDO_t *SDO, - CO_NMT_internalState_t *operatingState, - uint8_t *configurationValid, - uint16_t idx_SRDOvalid, - uint16_t idx_SRDOcrc) + OD_entry_t *OD_13FE_SRDOValid, + OD_entry_t *OD_13FF_SRDOCRC, + uint32_t *errInfo) { + ODR_t odRet; + /* verify arguments */ - if(SRDOGuard==NULL || SDO==NULL || operatingState==NULL || configurationValid==NULL){ + if((SRDOGuard==NULL) || (OD_13FE_SRDOValid==NULL) || (OD_13FF_SRDOCRC==NULL)){ return CO_ERROR_ILLEGAL_ARGUMENT; } - SRDOGuard->operatingState = operatingState; - SRDOGuard->operatingStatePrev = CO_NMT_INITIALIZING; - SRDOGuard->configurationValid = configurationValid; - SRDOGuard->checkCRC = *configurationValid == CO_SRDO_VALID_MAGIC; + /* clear object */ + memset(SRDOGuard, 0, sizeof(CO_SRDOGuard_t)); + + SRDOGuard->operatingState = false; + SRDOGuard->SRDO_CRC = OD_13FF_SRDOCRC; + uint8_t value = 0; + odRet = OD_get_u8(OD_13FE_SRDOValid, 0, &value, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_13FE_SRDOValid)) << 8) | 1U; + } + return CO_ERROR_OD_PARAMETERS; + } + SRDOGuard->configurationValid = value; + + SRDOGuard->checkCRC = (SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC); /* Configure Object dictionary entry at index 0x13FE and 0x13FF */ - CO_OD_configure(SDO, idx_SRDOvalid, CO_ODF_SRDOvalid, (void*)SRDOGuard, 0, 0); - CO_OD_configure(SDO, idx_SRDOcrc, CO_ODF_SRDOcrc, (void*)SRDOGuard, 0, 0); + SRDOGuard->OD_13FE_extension.object = SRDOGuard; + SRDOGuard->OD_13FE_extension.read = OD_read_13FE; + SRDOGuard->OD_13FE_extension.write = OD_write_13FE; + OD_extension_init(OD_13FE_SRDOValid, &SRDOGuard->OD_13FE_extension); + + SRDOGuard->OD_13FF_extension.object = SRDOGuard; + SRDOGuard->OD_13FF_extension.read = OD_readOriginal; + SRDOGuard->OD_13FF_extension.write = OD_write_13FF; + OD_extension_init(OD_13FF_SRDOCRC, &SRDOGuard->OD_13FF_extension); return CO_ERROR_NO; } uint8_t CO_SRDOGuard_process( - CO_SRDOGuard_t *SRDOGuard) + CO_SRDOGuard_t *SRDOGuard, + bool_t NMTisOperational) { uint8_t result = 0; - CO_NMT_internalState_t operatingState = *SRDOGuard->operatingState; - if(operatingState != SRDOGuard->operatingStatePrev){ - SRDOGuard->operatingStatePrev = operatingState; - if (operatingState == CO_NMT_OPERATIONAL) - result |= 1 << 0; + if(NMTisOperational != SRDOGuard->operatingState){ + SRDOGuard->operatingState = NMTisOperational; + if (NMTisOperational){ + result |= CO_SRDO_BITCMD_OPERATIONAL; + } } if(SRDOGuard->checkCRC){ - result |= 1 << 1; + result |= CO_SRDO_BITCMD_CALC_CRC; SRDOGuard->checkCRC = 0; } return result; @@ -550,35 +630,40 @@ void CO_SRDO_initCallbackEnterSafeState( CO_ReturnError_t CO_SRDO_init( CO_SRDO_t *SRDO, + uint8_t SRDO_Index, CO_SRDOGuard_t *SRDOGuard, + OD_t *OD, CO_EM_t *em, - CO_SDO_t *SDO, uint8_t nodeId, uint16_t defaultCOB_ID, - const CO_SRDOCommPar_t *SRDOCommPar, - const CO_SRDOMapPar_t *SRDOMapPar, - const uint16_t *checksum, - uint16_t idx_SRDOCommPar, - uint16_t idx_SRDOMapPar, + OD_entry_t *OD_130x_SRDOCommPar, + OD_entry_t *OD_138x_SRDOMapPar, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdxNormal, uint16_t CANdevRxIdxInverted, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdxNormal, - uint16_t CANdevTxIdxInverted) + uint16_t CANdevTxIdxInverted, + uint32_t *errInfo) { + ODR_t odRet; + /* verify arguments */ - if(SRDO==NULL || SRDOGuard==NULL || em==NULL || SDO==NULL || checksum==NULL || - SRDOCommPar==NULL || SRDOMapPar==NULL || CANdevRx==NULL || CANdevTx==NULL){ + if((SRDO==NULL) || (SRDOGuard==NULL) || (OD==NULL) || (em==NULL) || + (OD_130x_SRDOCommPar==NULL) || (OD_138x_SRDOMapPar==NULL) || (CANdevRx==NULL) || (CANdevTx==NULL)){ return CO_ERROR_ILLEGAL_ARGUMENT; } + + /* clear object */ + memset(SRDO, 0, sizeof(CO_SRDO_t)); + /* Configure object variables */ + SRDO->SRDO_Index = SRDO_Index; SRDO->SRDOGuard = SRDOGuard; SRDO->em = em; - SRDO->SDO = SDO; - SRDO->SRDOCommPar = SRDOCommPar; - SRDO->SRDOMapPar = SRDOMapPar; - SRDO->checksum = checksum; + SRDO->OD = OD; + SRDO->SRDOCommPar = OD_130x_SRDOCommPar; + SRDO->SRDOMapPar = OD_138x_SRDOMapPar; SRDO->CANdevRx = CANdevRx; SRDO->CANdevRxIdx[0] = CANdevRxIdxNormal; SRDO->CANdevRxIdx[1] = CANdevRxIdxInverted; @@ -587,7 +672,7 @@ CO_ReturnError_t CO_SRDO_init( SRDO->CANdevTxIdx[1] = CANdevTxIdxInverted; SRDO->nodeId = nodeId; SRDO->defaultCOB_ID[0] = defaultCOB_ID; - SRDO->defaultCOB_ID[1] = defaultCOB_ID + 1; + SRDO->defaultCOB_ID[1] = defaultCOB_ID + 1U; SRDO->valid = CO_SRDO_INVALID; SRDO->toogle = 0; SRDO->timer = 0; @@ -598,9 +683,86 @@ CO_ReturnError_t CO_SRDO_init( SRDO->functSignalObjectPre = NULL; #endif + uint8_t informationDirection = 0; + odRet = OD_get_u8(OD_130x_SRDOCommPar, 1, &informationDirection, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 1U; + } + return CO_ERROR_OD_PARAMETERS; + } + SRDO->CommPar_informationDirection = informationDirection; + + uint16_t safetyCycleTime = 0; + odRet = OD_get_u16(OD_130x_SRDOCommPar, 2, &safetyCycleTime, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 2U; + } + return CO_ERROR_OD_PARAMETERS; + } + SRDO->CommPar_safetyCycleTime= safetyCycleTime; + + uint8_t safetyRelatedValidationTime = 0; + odRet = OD_get_u8(OD_130x_SRDOCommPar, 3, &safetyRelatedValidationTime, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 3U; + } + return CO_ERROR_OD_PARAMETERS; + } + SRDO->CommPar_safetyRelatedValidationTime = safetyRelatedValidationTime; + + uint8_t transmissionType = 0; + odRet = OD_get_u8(OD_130x_SRDOCommPar, 4, &transmissionType, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 4U; + } + return CO_ERROR_OD_PARAMETERS; + } + SRDO->CommPar_transmissionType = transmissionType; + + uint32_t COB_ID1_normal = 0; + odRet = OD_get_u32(OD_130x_SRDOCommPar, 5, &COB_ID1_normal, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 5U; + } + return CO_ERROR_OD_PARAMETERS; + } + SRDO->CommPar_COB_ID1_normal = COB_ID1_normal; + + uint32_t COB_ID2_inverted = 0; + odRet = OD_get_u32(OD_130x_SRDOCommPar, 6, &COB_ID2_inverted, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 6U; + } + return CO_ERROR_OD_PARAMETERS; + } + SRDO->CommPar_COB_ID2_inverted = COB_ID2_inverted; + /* Configure Object dictionary entry at index 0x1301+ and 0x1381+ */ - CO_OD_configure(SDO, idx_SRDOCommPar, CO_ODF_SRDOcom, (void*)SRDO, 0, 0); - CO_OD_configure(SDO, idx_SRDOMapPar, CO_ODF_SRDOmap, (void*)SRDO, 0, 0); + SRDO->OD_communicationParam_ext.object = SRDO; + SRDO->OD_communicationParam_ext.read = OD_read_SRDO_communicationParam; + SRDO->OD_communicationParam_ext.write = OD_write_SRDO_communicationParam; + OD_extension_init(OD_130x_SRDOCommPar, &SRDO->OD_communicationParam_ext); + + uint8_t numberOfMappedObjects = 0; + odRet = OD_get_u8(OD_138x_SRDOMapPar, 0, &numberOfMappedObjects, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_138x_SRDOMapPar)) << 8) | 0U; + } + return CO_ERROR_OD_PARAMETERS; + } + SRDO->mappedObjectsCount = numberOfMappedObjects; + + SRDO->OD_mappingParam_extension.object = SRDO; + SRDO->OD_mappingParam_extension.read = OD_readOriginal; + SRDO->OD_mappingParam_extension.write = OD_write_SRDO_mappingParam; + OD_extension_init(OD_138x_SRDOMapPar, &SRDO->OD_mappingParam_extension); return CO_ERROR_NO; } @@ -608,14 +770,17 @@ CO_ReturnError_t CO_SRDO_init( CO_ReturnError_t CO_SRDO_requestSend( CO_SRDO_t *SRDO) { - if (*SRDO->SRDOGuard->operatingState != CO_NMT_OPERATIONAL) + if (SRDO->SRDOGuard->operatingState == false){ return CO_ERROR_WRONG_NMT_STATE; + } - if (SRDO->valid != CO_SRDO_TX) + if (SRDO->valid != CO_SRDO_TX){ return CO_ERROR_TX_UNCONFIGURED; + } - if(SRDO->toogle != 0) + if(SRDO->toogle != 0U){ return CO_ERROR_TX_BUSY; + } SRDO->timer = 0; return CO_ERROR_NO; @@ -627,34 +792,38 @@ void CO_SRDO_process( uint32_t timeDifference_us, uint32_t *timerNext_us) { + ODR_t odRet; + (void)timerNext_us; /* may be unused */ - if(commands & (1<<1)){ + if(commands & CO_SRDO_BITCMD_CALC_CRC){ uint16_t crcValue = CO_SRDOcalcCrc(SRDO); - if (*SRDO->checksum != crcValue) - *SRDO->SRDOGuard->configurationValid = 0; + uint16_t crcSRDO = 0; + odRet = OD_get_u16(SRDO->SRDOGuard->SRDO_CRC, SRDO->SRDO_Index+1, &crcSRDO, true); + if ((odRet != ODR_OK) || (crcSRDO != crcValue)) { + SRDO->SRDOGuard->configurationValid = 0; + } } - if((commands & (1<<0)) && *SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC){ - if(CO_SRDOconfigMap(SRDO, SRDO->SRDOMapPar->numberOfMappedObjects) == 0){ - CO_SRDOconfigCom(SRDO, SRDO->SRDOCommPar->COB_ID1_normal, SRDO->SRDOCommPar->COB_ID2_inverted); + if((commands & CO_SRDO_BITCMD_OPERATIONAL) && (SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC)){ + if(SRDO_configMap(SRDO,SRDO->OD,SRDO->SRDOMapPar) == CO_ERROR_NO){ + CO_SRDOconfigCom(SRDO, SRDO->CommPar_COB_ID1_normal, SRDO->CommPar_COB_ID2_inverted); } else{ SRDO->valid = CO_SRDO_INVALID; } } - if(SRDO->valid && *SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL){ - SRDO->timer = (SRDO->timer > timeDifference_us) ? (SRDO->timer - timeDifference_us) : 0; + if(SRDO->valid && SRDO->SRDOGuard->operatingState){ + SRDO->timer = (SRDO->timer > timeDifference_us) ? (SRDO->timer - timeDifference_us) : 0U; if(SRDO->valid == CO_SRDO_TX){ - if(SRDO->timer == 0){ + if(SRDO->timer == 0U){ if(SRDO->toogle){ CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[1]); - SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U - CO_CONFIG_SRDO_MINIMUM_DELAY; + SRDO->timer = ((uint32_t)SRDO->CommPar_safetyCycleTime * 1000U) - CO_CONFIG_SRDO_MINIMUM_DELAY; } else{ - - int16_t i; + uint16_t i; uint8_t* pSRDOdataByte_normal; uint8_t* pSRDOdataByte_inverted; @@ -666,9 +835,9 @@ void CO_SRDO_process( if(SRDO->SDO->ODExtensions){ /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0]; - CO_SDO_t *pSDO = SRDO->SDO; + CO_SDOserver_t *pSDO = SRDO->SDO; - for(i=SRDO->SRDOMapPar->numberOfMappedObjects; i>0; i--){ + for(i=SRDO->mappedObjectsCount; i>0; i--){ uint32_t map = *(pMap++); uint16_t index = (uint16_t)(map>>16); uint8_t subIndex = (uint8_t)(map>>8); @@ -755,7 +924,7 @@ void CO_SRDO_process( pSRDOdataByte_normal = &SRDO->CANrxData[0][0]; pSRDOdataByte_inverted = &SRDO->CANrxData[1][0]; for(i = 0; idataLength; i++){ - uint8_t invert = ~pSRDOdataByte_inverted[i]; + uint8_t invert = (uint8_t)(~pSRDOdataByte_inverted[i]); if(pSRDOdataByte_normal[i] != invert){ data_ok = false; break; @@ -779,9 +948,9 @@ void CO_SRDO_process( int16_t i; /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0]; - CO_SDO_t *pSDO = SRDO->SDO; + CO_SDOserver_t *pSDO = SRDO->SDO; - for(i=SRDO->SRDOMapPar->numberOfMappedObjects; i>0; i--){ + for(i=SRDO->mappedObjectsCount; i>0; i--){ uint32_t map = *(pMap++); uint16_t index = (uint16_t)(map>>16); uint8_t subIndex = (uint8_t)(map>>8); @@ -817,17 +986,17 @@ void CO_SRDO_process( } } - SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U; + SRDO->timer = (uint32_t)SRDO->CommPar_safetyCycleTime * 1000U; } else{ - SRDO->timer = SRDO->SRDOCommPar->safetyRelatedValidationTime * 1000U; + SRDO->timer = (uint32_t)SRDO->CommPar_safetyRelatedValidationTime * 1000U; } - SRDO->toogle = !SRDO->toogle; + SRDO->toogle = (uint8_t)(!SRDO->toogle); } - if(SRDO->timer == 0){ + if(SRDO->timer == 0U){ SRDO->toogle = 0; - SRDO->timer = SRDO->SRDOCommPar->safetyRelatedValidationTime * 1000U; + SRDO->timer = (uint32_t)SRDO->CommPar_safetyRelatedValidationTime * 1000U; CO_FLAG_CLEAR(SRDO->CANrxNew[0]); CO_FLAG_CLEAR(SRDO->CANrxNew[1]); /* save state */ @@ -836,6 +1005,7 @@ void CO_SRDO_process( } } } + else { /* MISRA C 2004 14.10 */ } } else{ SRDO->valid = CO_SRDO_INVALID; diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 37783db6..810ca88b 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -26,17 +26,15 @@ #ifndef CO_SRDO_H #define CO_SRDO_H -#include "301/CO_driver.h" -#include "301/CO_SDOserver.h" +#include "301/CO_ODinterface.h" #include "301/CO_Emergency.h" -#include "301/CO_NMT_Heartbeat.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_SRDO #define CO_CONFIG_SRDO (0) #endif #ifndef CO_CONFIG_SRDO_MINIMUM_DELAY -#define CO_CONFIG_SRDO_MINIMUM_DELAY 0 +#define CO_CONFIG_SRDO_MINIMUM_DELAY 0U #endif #if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN @@ -58,50 +56,22 @@ extern "C" { * If the security protocol is used, at least one SRDO is mandatory. */ +/** Maximum size of SRDO message, 8 for standard CAN */ +#ifndef CO_SRDO_MAX_SIZE +#define CO_SRDO_MAX_SIZE 8U +#endif -/** - * SRDO communication parameter. The same as record from Object dictionary (index 0x1301-0x1340). - */ -typedef struct{ - uint8_t maxSubIndex; /**< Equal to 6 */ - /** Direction of the SRDO. Values: - - 0: SRDO is invalid (deleted) - - 1: SRDO is transmiting data - - 2: SRDO is receive data */ - uint8_t informationDirection; - /** Refresh-time / SCT - - in tx mode (Refresh-time): transmission interval - - in rx mode (SCT): receive timeout between two SRDO */ - uint16_t safetyCycleTime; - /** SRVT - - in tx mode: unsed - - in rx mode: receive timeout between first and second SRDO message */ - uint8_t safetyRelatedValidationTime; - /** Transmission type. Values: - - 254: Manufacturer specific.*/ - uint8_t transmissionType; - /** Communication object identifier for message received. Meaning of the specific bits: - - Bit 0-10: COB-ID for SRDO - - Bit 11-31: set to 0 for 11 bit COB-ID. */ - uint32_t COB_ID1_normal; - /** Communication object identifier for message received. Meaning of the specific bits: - - Bit 0-10: COB-ID for SRDO - - Bit 11-31: set to 0 for 11 bit COB-ID. */ - uint32_t COB_ID2_inverted; -}CO_SRDOCommPar_t; +/** Maximum number of entries, which can be mapped to PDO, 8 for standard CAN, + * may be less to preserve RAM usage */ +#ifndef CO_SRDO_MAX_MAPPED_ENTRIES +#define CO_SRDO_MAX_MAPPED_ENTRIES 8U +#endif +#ifndef CO_SRDO_OWN_TYPES +/** Variable of type CO_SRDO_size_t contains data length in bytes of SRDO */ +typedef uint8_t CO_SRDO_size_t; +#endif -typedef struct{ - /** Actual number of mapped objects from 0 to 16. Only even numbers are allowed. To change mapped object, - this value must be 0. */ - uint8_t numberOfMappedObjects; - /** Location and size of the mapped object. - Even index is the normal object. Odd index is the inverted object. Bit meanings `0xIIIISSLL`: - - Bit 0-7: Data Length in bits. - - Bit 8-15: Subindex from object distionary. - - Bit 16-31: Index from object distionary. */ - uint32_t mappedObjects[16]; -}CO_SRDOMapPar_t; /** * Gurad Object for SRDO @@ -111,10 +81,13 @@ typedef struct{ * - change in operation state */ typedef struct{ - CO_NMT_internalState_t *operatingState; /**< pointer to current operation state */ - CO_NMT_internalState_t operatingStatePrev; /**< last operation state */ - uint8_t *configurationValid; /**< pointer to the configuration valid flag in OD */ + bool operatingState; + uint8_t configurationValid; + OD_entry_t *SRDO_CRC; uint8_t checkCRC; /**< specifies whether a CRC check should be performed */ + /** Extension for OD object */ + OD_extension_t OD_13FE_extension; + OD_extension_t OD_13FF_extension; }CO_SRDOGuard_t; /** @@ -122,19 +95,21 @@ typedef struct{ */ typedef struct{ CO_EM_t *em; /**< From CO_SRDO_init() */ - CO_SDO_t *SDO; /**< From CO_SRDO_init() */ CO_SRDOGuard_t *SRDOGuard; /**< From CO_SRDO_init() */ + OD_t *OD; + uint8_t SRDO_Index; /**< From CO_SRDO_init() */ + /** Number of mapped objects in SRDO */ + uint8_t mappedObjectsCount; /** Pointers to 2*8 data objects, where SRDO will be copied */ - uint8_t *mapPointer[2][8]; + uint8_t *mapPointer[2][CO_SRDO_MAX_SIZE]; /** Data length of the received SRDO message. Calculated from mapping */ - uint8_t dataLength; + CO_SRDO_size_t dataLength; uint8_t nodeId; /**< From CO_SRDO_init() */ uint16_t defaultCOB_ID[2]; /**< From CO_SRDO_init() */ /** 0 - invalid, 1 - tx, 2 - rx */ uint8_t valid; - const CO_SRDOCommPar_t *SRDOCommPar; /**< From CO_SRDO_init() */ - const CO_SRDOMapPar_t *SRDOMapPar; /**< From CO_SRDO_init() */ - const uint16_t *checksum; /**< From CO_SRDO_init() */ + OD_entry_t *SRDOCommPar; /**< From CO_SRDO_init() */ + OD_entry_t *SRDOMapPar; /**< From CO_SRDO_init() */ CO_CANmodule_t *CANdevRx; /**< From CO_SRDO_init() */ CO_CANmodule_t *CANdevTx; /**< From CO_SRDO_init() */ CO_CANtx_t *CANtxBuff[2]; /**< CAN transmit buffer inside CANdevTx */ @@ -156,6 +131,16 @@ typedef struct{ /** From CO_SRDO_initCallbackPre() or NULL */ void *functSignalObjectPre; #endif + /** Extension for OD object */ + OD_extension_t OD_communicationParam_ext; + OD_extension_t OD_mappingParam_extension; + + uint8_t CommPar_informationDirection; + uint16_t CommPar_safetyCycleTime; + uint8_t CommPar_safetyRelatedValidationTime; + uint8_t CommPar_transmissionType; + uint32_t CommPar_COB_ID1_normal; + uint32_t CommPar_COB_ID2_inverted; }CO_SRDO_t; /** @@ -174,11 +159,9 @@ typedef struct{ */ CO_ReturnError_t CO_SRDOGuard_init( CO_SRDOGuard_t *SRDOGuard, - CO_SDO_t *SDO, - CO_NMT_internalState_t *operatingState, - uint8_t *configurationValid, - uint16_t idx_SRDOvalid, - uint16_t idx_SRDOcrc); + OD_entry_t *OD_13FE_SRDOValid, + OD_entry_t *OD_13FF_SRDOCRC, + uint32_t *errInfo); /** * Process operation and valid state changes. @@ -189,7 +172,8 @@ CO_ReturnError_t CO_SRDOGuard_init( * - bit 1 validate checksum */ uint8_t CO_SRDOGuard_process( - CO_SRDOGuard_t *SRDOGuard); + CO_SRDOGuard_t *SRDOGuard, + bool_t NMTisOperational); /** * Initialize SRDO object. @@ -220,22 +204,21 @@ uint8_t CO_SRDOGuard_process( */ CO_ReturnError_t CO_SRDO_init( CO_SRDO_t *SRDO, + uint8_t SRDO_Index, CO_SRDOGuard_t *SRDOGuard, + OD_t *OD, CO_EM_t *em, - CO_SDO_t *SDO, uint8_t nodeId, uint16_t defaultCOB_ID, - const CO_SRDOCommPar_t *SRDOCommPar, - const CO_SRDOMapPar_t *SRDOMapPar, - const uint16_t *checksum, - uint16_t idx_SRDOCommPar, - uint16_t idx_SRDOMapPar, + OD_entry_t *SRDOCommPar, + OD_entry_t *SRDOMapPar, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdxNormal, uint16_t CANdevRxIdxInverted, CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdxNormal, - uint16_t CANdevTxIdxInverted); + uint16_t CANdevTxIdxInverted, + uint32_t *errInfo); #if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** diff --git a/CANopen.c b/CANopen.c index aa5d6e54..b2957273 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1187,36 +1187,32 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE if (CO_GET_CNT(SRDO) > 0) { err = CO_SRDOGuard_init(co->SRDOGuard, - co->SDO[0], - &co->NMT->operatingState, - &OD_configurationValid, - OD_H13FE_SRDO_VALID, - OD_H13FF_SRDO_CHECKSUM); + OD_GET(H13FE, OD_H13FE_SRDO_VALID), + OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), + errInfo); if (err) { return err; } OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); - OD_entry_t *SRDOmap = OD_GET(H1318, OD_H1381_SRDO_1_MAPPING); + OD_entry_t *SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { uint16_t CANdevRxIdx = CO_GET_CO(RX_IDX_SRDO) + 2 * i; uint16_t CANdevTxIdx = CO_GET_CO(TX_IDX_SRDO) + 2 * i; - err = CO_SRDO_init(&co->SRDO[i], + err = CO_SRDO_init(&co->SRDO[i], i, co->SRDOGuard, + od, em, - co->SDO[0], nodeId, ((i == 0) ? CO_CAN_ID_SRDO_1 : 0), SRDOcomm++, SRDOmap++, - &OD_safetyConfigurationChecksum[i], - OD_H1301_SRDO_1_PARAM + i, - OD_H1381_SRDO_1_MAPPING + i, co->CANmodule, CANdevRxIdx, CANdevRxIdx + 1, co->CANmodule, CANdevTxIdx, - CANdevTxIdx + 1); + CANdevTxIdx + 1, + errInfo); if (err) { return err; } } } @@ -1604,11 +1600,15 @@ void CO_process_SRDO(CO_t *co, if (co->nodeIdUnconfigured) { return; } + + bool_t NMTisOperational = + CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; - uint8_t firstOperational = CO_SRDOGuard_process(co->SRDOGuard); + uint8_t firstOperational = CO_SRDOGuard_process(co->SRDOGuard, + NMTisOperational); for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { - CO_SRDO_process(&co->SRDO[i], + CO_SRDO_process(&co->SRDO[i], firstOperational, timeDifference_us, timerNext_us); From 39fc9212e69c40bbd2d3fb34865885c5d012419b Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 25 Apr 2024 16:51:37 +0200 Subject: [PATCH 245/520] Fixed Compiler warnings, issue #512 --- 301/CO_Emergency.c | 2 +- 305/CO_LSSslave.c | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index cd553739..b2cffc0d 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -371,7 +371,6 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, { (void) nodeId; /* may be unused */ CO_ReturnError_t ret = CO_ERROR_NO; - ODR_t odRet; /* verify arguments */ if (em == NULL || OD_1001_errReg == NULL @@ -413,6 +412,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER /* get initial and verify "COB-ID EMCY" from Object Dictionary */ uint32_t COB_IDEmergency32; + ODR_t odRet; odRet = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); if (odRet != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1014_cobIdEm); } diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index a5b26d49..ee8b83ff 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -38,10 +38,6 @@ /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_BIT_TIMING_1000 */ #define CO_LSS_BIT_TIMING_VALID(index) (index != 5 && index <= CO_LSS_BIT_TIMING_AUTO) -#if CO_LSS_FASTSCAN_BIT0!=0 || CO_LSS_FASTSCAN_VENDOR_ID!=0 || CO_LSS_BIT_TIMING_1000!=0 -#error Inconsistency in LSS macros -#endif - /* * Read received message from CAN module. * From 57ce72e6a24c0f80d48c09c8857902e3a71efbed Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 24 May 2024 14:29:15 +0200 Subject: [PATCH 246/520] .clang-format file changed to the same from 'https://github.com/MaJerle/c-code-style' Auto formatted the file 'codingStyle' --- .clang-format | 204 ++++++++++++++++++++++++++++++++++++++++++++++---- codingStyle | 32 +++----- 2 files changed, 203 insertions(+), 33 deletions(-) diff --git a/.clang-format b/.clang-format index 1ac2aa8e..33bb7d7f 100644 --- a/.clang-format +++ b/.clang-format @@ -1,15 +1,193 @@ -# https://clang.llvm.org/docs/ClangFormatStyleOptions.html -BasedOnStyle: LLVM - -# indent 4 spaces +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +SortIncludes: true +InsertBraces: true # Control statements must have curly brackets +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: AllDefinitions +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: "^ IWYU pragma:" +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: "" +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: "^<(.*)>" + Priority: 0 + - Regex: '^"(.*)"' + Priority: 1 + - Regex: "(.*)" + Priority: 2 +IncludeIsMainRegex: "(Test)?$" +IncludeIsMainSourceRegex: "" +IndentAccessModifiers: false +IndentCaseLabels: true +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: true IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 50 +PenaltyBreakBeforeFirstCallParameter: 9 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: false +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 1 +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +--- -# break before function -BreakBeforeBraces: Linux - -# arguments and parameters in same line or one line for each -BinPackArguments: false -BinPackParameters: false - -# keep up to two empty lines -MaxEmptyLinesToKeep: 2 diff --git a/codingStyle b/codingStyle index 70d0e937..d6923a3e 100644 --- a/codingStyle +++ b/codingStyle @@ -53,7 +53,6 @@ extern "C" { * only, don't use period after the sentence. */ - /** * Brief description of the object ends at this dot. Details follow * here. @@ -65,7 +64,6 @@ typedef struct { char_t stringMember[5]; } object1_t; - /** * Function example 1. * @@ -80,11 +78,9 @@ typedef struct { * * @return Some value. */ -int32_t foo1(object1_t *thisObj, - int32_t argument_2, - uint16_t argument_3, - float32_t argument_4) -{ +int32_t +foo1(object1_t* thisObj, int32_t argument_2, uint16_t argument_3, float32_t argument_4, bool_t argument_5, + int32_t argument_6) { /* Comment */ /* Multiline @@ -98,8 +94,7 @@ int32_t foo1(object1_t *thisObj, a = b; } else if (xy < yz) { a = c; - } - else { + } else { /* To stay compliant with MISRA C 2004 14.10 * all else if statements need a final else even if empty */ @@ -110,19 +105,16 @@ int32_t foo1(object1_t *thisObj, * This is true for: 'if' and 'while' statements. * For instance: */ - if (xy = yz){ - } - while (xy = yz){ - } + if (xy = yz) {} + while (xy = yz) {} switch (zx) { - case 1: - a = b; - break - default: - /* To stay compliant with MISRA C 2004 15.3 - * the default case must be present */ - break; + case 1: + a = b; + break default : + /* To stay compliant with MISRA C 2004 15.3 + * the default case must be present */ + break; } } From f054501d0ef7aaeaee28f25bc5688e52a840ae98 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 31 May 2024 01:47:28 +0200 Subject: [PATCH 247/520] SRDO updated to current CANopenNode --- 301/CO_Emergency.h | 4 +- 301/CO_config.h | 6 - 304/CO_GFC.c | 134 ++-- 304/CO_GFC.h | 46 +- 304/CO_SRDO.c | 1465 +++++++++++++++++++++----------------------- 304/CO_SRDO.h | 293 ++++----- CANopen.c | 177 +++--- CANopen.h | 44 +- README.md | 2 +- 9 files changed, 1107 insertions(+), 1064 deletions(-) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index cfa4c7e9..f4e3b24f 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -304,8 +304,8 @@ typedef enum { /** 0x1C, communication, critical, Heartbeat consumer detected remote node * reset */ CO_EM_HB_CONSUMER_REMOTE_RESET = 0x1CU, - /** 0x1D, communication, critical, (unused) */ - CO_EM_1D_unused = 0x1DU, + /** 0x1D, communication, critical, Error in SRDO configuration parameters. */ + CO_EM_SRDO_CONFIGURATION = 0x1DU, /** 0x1E, communication, critical, (unused) */ CO_EM_1E_unused = 0x1EU, /** 0x1F, communication, critical, (unused) */ diff --git a/301/CO_config.h b/301/CO_config.h index c8836432..a5e8f893 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -570,10 +570,6 @@ extern "C" { * Possible flags, can be ORed: * - CO_CONFIG_SRDO_ENABLE - Enable the SRDO object. * - CO_CONFIG_SRDO_CHECK_TX - Enable checking data before sending. - * - CO_CONFIG_RSRDO_CALLS_EXTENSION - Enable calling configured extension - * callbacks when received RSRDO CAN message modifies OD entries. - * - CO_CONFIG_TRSRDO_CALLS_EXTENSION - Enable calling configured extension - * callbacks before TSRDO CAN message is sent. * - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing * received RSRDO CAN message. * Callback is configured by CO_SRDO_initCallbackPre(). @@ -585,8 +581,6 @@ extern "C" { #endif #define CO_CONFIG_SRDO_ENABLE 0x01 #define CO_CONFIG_SRDO_CHECK_TX 0x02 -#define CO_CONFIG_RSRDO_CALLS_EXTENSION 0x04 -#define CO_CONFIG_TSRDO_CALLS_EXTENSION 0x08 /** * SRDO Tx time delay diff --git a/304/CO_GFC.c b/304/CO_GFC.c index 4b315c55..191268ec 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -4,7 +4,8 @@ * @file CO_GFC.c * @ingroup CO_GFC * @author Robert Grüning - * @copyright 2020 - 2020 Robert Grüning + * @copyright 2020 Robert Grüning + * @copyright 2024 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -27,32 +28,49 @@ #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER +/* + * Custom function for reading or writing OD object. + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static ODR_t +OD_write_1300(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countWritten == NULL)) { + return ODR_DEV_INCOMPAT; + } -static void CO_GFC_receive(void *object, void *msg) -{ - CO_GFC_t *GFC; - uint8_t DLC = CO_CANrxMsg_readDLC(msg); + CO_GFC_t* GFC = stream->object; + + uint8_t value = CO_getUint8(buf); + if (value > 1) { + return ODR_INVALID_VALUE; + } - GFC = (CO_GFC_t *) - object; /* this is the correct pointer type of the first argument */ + GFC->valid = (value == 1); - if ((*GFC->valid == 0x01) && (DLC == 0)) { + /* write value to the original location in the Object Dictionary */ + return OD_writeOriginal(stream, buf, count, countWritten); +} #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER - /* Optional signal to RTOS, which can resume task, which handles SRDO. - */ +static void +CO_GFC_receive(void* object, void* msg) { + CO_GFC_t* GFC; + uint8_t DLC = CO_CANrxMsg_readDLC(msg); + + GFC = (CO_GFC_t*)object; /* this is the correct pointer type of the first argument */ + + if (GFC->valid && (DLC == 0)) { + + /* Callback signals Global Failsafe Command */ if (GFC->pFunctSignalSafe != NULL) { GFC->pFunctSignalSafe(GFC->functSignalObjectSafe); } -#endif } } -void CO_GFC_initCallbackEnterSafeState(CO_GFC_t *GFC, - void *object, - void (*pFunctSignalSafe)(void *object)) -{ +void +CO_GFC_initCallbackEnterSafeState(CO_GFC_t* GFC, void* object, void (*pFunctSignalSafe)(void* object)) { if (GFC != NULL) { GFC->functSignalObjectSafe = object; GFC->pFunctSignalSafe = pFunctSignalSafe; @@ -60,70 +78,70 @@ void CO_GFC_initCallbackEnterSafeState(CO_GFC_t *GFC, } #endif -CO_ReturnError_t CO_GFC_init(CO_GFC_t *GFC, - uint8_t *valid, - CO_CANmodule_t *GFC_CANdevRx, - uint16_t GFC_rxIdx, - uint16_t CANidRxGFC, - CO_CANmodule_t *GFC_CANdevTx, - uint16_t GFC_txIdx, - uint16_t CANidTxGFC) -{ - if (GFC == NULL || valid == NULL || GFC_CANdevRx == NULL || - GFC_CANdevTx == NULL) { + +CO_ReturnError_t +CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC_CANdevRx, uint16_t GFC_rxIdx, uint16_t CANidRxGFC, + CO_CANmodule_t* GFC_CANdevTx, uint16_t GFC_txIdx, uint16_t CANidTxGFC) { + if (GFC == NULL || OD_1300_gfcParameter == NULL || GFC_CANdevRx == NULL || GFC_CANdevTx == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } - GFC->valid = valid; -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER - GFC->CANdevTx = GFC_CANdevTx; -#endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER - GFC->functSignalObjectSafe = NULL; - GFC->pFunctSignalSafe = NULL; -#endif + + uint8_t valid = 0; + if (OD_get_u8(OD_1300_gfcParameter, 0, &valid, true) != ODR_OK) { + return CO_ERROR_OD_PARAMETERS; + } + GFC->valid = (valid == 1); + + /* Configure Object dictionary entry at index 0x1300+ */ + GFC->OD_gfcParam_ext.object = GFC; + GFC->OD_gfcParam_ext.read = OD_readOriginal; + GFC->OD_gfcParam_ext.write = OD_write_1300; + OD_extension_init(OD_1300_gfcParameter, &GFC->OD_gfcParam_ext); #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER - GFC->CANtxBuff = CO_CANtxBufferInit( - GFC->CANdevTx, /* CAN device */ - GFC_txIdx, /* index of specific buffer inside CAN module */ - CANidTxGFC, /* CAN identifier */ - 0, /* rtr */ - 0, /* number of data bytes */ - 0); /* synchronous message flag bit */ + GFC->CANdevTx = GFC_CANdevTx; + GFC->CANtxBuff = CO_CANtxBufferInit(GFC->CANdevTx, /* CAN device */ + GFC_txIdx, /* index of specific buffer inside CAN module */ + CANidTxGFC, /* CAN identifier */ + 0, /* rtr */ + 0, /* number of data bytes */ + 0); /* synchronous message flag bit */ if (GFC->CANtxBuff == NULL) { return CO_ERROR_TX_UNCONFIGURED; } #else - (void)GFC_txIdx; /* unused */ - (void)CANidTxGFC; /* unused */ + (void)GFC_txIdx; /* unused */ + (void)CANidTxGFC; /* unused */ #endif + #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER - const CO_ReturnError_t r = CO_CANrxBufferInit( - GFC_CANdevRx, /* CAN device */ - GFC_rxIdx, /* rx buffer index */ - CANidRxGFC, /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void *)GFC, /* object passed to receive function */ - CO_GFC_receive); /* this function will process received message */ + GFC->functSignalObjectSafe = NULL; + GFC->pFunctSignalSafe = NULL; + const CO_ReturnError_t r = CO_CANrxBufferInit(GFC_CANdevRx, /* CAN device */ + GFC_rxIdx, /* rx buffer index */ + CANidRxGFC, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)GFC, /* object passed to receive function */ + CO_GFC_receive); /* this function will process received message */ if (r != CO_ERROR_NO) { return r; } #else - (void)GFC_rxIdx; /* unused */ - (void)CANidRxGFC; /* unused */ + (void)GFC_rxIdx; /* unused */ + (void)CANidRxGFC; /* unused */ #endif return CO_ERROR_NO; } #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER - -CO_ReturnError_t CO_GFCsend(CO_GFC_t *GFC) -{ - if (*GFC->valid == 0x01) +CO_ReturnError_t +CO_GFCsend(CO_GFC_t* GFC) { + if (GFC->valid) { return CO_CANsend(GFC->CANdevTx, GFC->CANtxBuff); + } return CO_ERROR_NO; } #endif diff --git a/304/CO_GFC.h b/304/CO_GFC.h index 575b6bd5..677f22ee 100644 --- a/304/CO_GFC.h +++ b/304/CO_GFC.h @@ -4,7 +4,8 @@ * @file CO_GFC.h * @ingroup CO_GFC * @author Robert Grüning - * @copyright 2020 - 2020 Robert Grüning + * @copyright 2020 Robert Grüning + * @copyright 2024 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -27,6 +28,7 @@ #define CO_GFC_H #include "301/CO_driver.h" +#include "301/CO_ODinterface.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_GFC @@ -47,26 +49,26 @@ extern "C" { * @{ * Very simple consumer/producer protocol. * A net can have multiple GFC producer and multiple GFC consumer. - * On a safety-relevant the producer can send a GFC message (ID 0, DLC 0). + * On a safety-relevant the producer can send a GFC message (ID 1, DLC 0). * The consumer can use this message to start the transition to a safe state. * The GFC is optional for the security protocol and is not monitored (timed). */ - /** * GFC object. */ typedef struct { - uint8_t *valid; /**< From CO_GFC_init() */ -#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_PRODUCER) || defined CO_DOXYGEN - CO_CANmodule_t *CANdevTx; /**< From CO_GFC_init() */ - CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ + bool_t valid; /**< From OD parameter 1300 */ + OD_extension_t OD_gfcParam_ext; /**< Extension for OD object */ +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) || defined CO_DOXYGEN + CO_CANmodule_t* CANdevTx; /**< From CO_GFC_init() */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ #endif -#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) || defined CO_DOXYGEN +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) || defined CO_DOXYGEN /** From CO_GFC_initCallbackEnterSafeState() or NULL */ - void (*pFunctSignalSafe)(void *object); + void (*pFunctSignalSafe)(void* object); /** From CO_GFC_initCallbackEnterSafeState() or NULL */ - void *functSignalObjectSafe; + void* functSignalObjectSafe; #endif } CO_GFC_t; @@ -76,7 +78,8 @@ typedef struct { * Function must be called in the communication reset section. * * @param GFC This object will be initialized. - * @param valid pointer to the valid flag in OD (0x1300) + * @param OD_1300_gfcParameter Pointer to _Global fail-safe command parameter_ + * variable from Object dictionary (index 0x1300). * @param GFC_CANdevRx CAN device used for SRDO reception. * @param GFC_rxIdx Index of receive buffer in the above CAN device. * @param CANidRxGFC GFC CAN ID for reception @@ -86,16 +89,11 @@ typedef struct { * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_GFC_init(CO_GFC_t *GFC, - uint8_t *valid, - CO_CANmodule_t *GFC_CANdevRx, - uint16_t GFC_rxIdx, - uint16_t CANidRxGFC, - CO_CANmodule_t *GFC_CANdevTx, - uint16_t GFC_txIdx, - uint16_t CANidTxGFC); +CO_ReturnError_t CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, + CO_CANmodule_t* GFC_CANdevRx, uint16_t GFC_rxIdx, uint16_t CANidRxGFC, + CO_CANmodule_t* GFC_CANdevTx, uint16_t GFC_txIdx, uint16_t CANidTxGFC); -#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) || defined CO_DOXYGEN +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) || defined CO_DOXYGEN /** * Initialize GFC callback function. * @@ -107,12 +105,10 @@ CO_ReturnError_t CO_GFC_init(CO_GFC_t *GFC, * Can be NULL * @param pFunctSignalSafe Pointer to the callback function. Not called if NULL. */ -void CO_GFC_initCallbackEnterSafeState(CO_GFC_t *GFC, - void *object, - void (*pFunctSignalSafe)(void *object)); +void CO_GFC_initCallbackEnterSafeState(CO_GFC_t* GFC, void* object, void (*pFunctSignalSafe)(void* object)); #endif -#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_PRODUCER) || defined CO_DOXYGEN +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) || defined CO_DOXYGEN /** * Send GFC message. * @@ -123,7 +119,7 @@ void CO_GFC_initCallbackEnterSafeState(CO_GFC_t *GFC, * * @return Same as CO_CANsend(). */ -CO_ReturnError_t CO_GFCsend(CO_GFC_t *GFC); +CO_ReturnError_t CO_GFCsend(CO_GFC_t* GFC); #endif /** @} */ /* CO_GFC */ diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 980d8ffa..18bdeb31 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -4,7 +4,9 @@ * @file CO_SRDO.c * @ingroup CO_SRDO * @author Robert Grüning - * @copyright 2020 - 2020 Robert Grüning + * @copyright 2020 Robert Grüning + * @copyright 2024 temi54c1l8@github + * @copyright 2024 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -31,987 +33,940 @@ /* verify configuration */ #if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) - #error CO_CONFIG_CRC16_ENABLE must be enabled. +#error CO_CONFIG_CRC16_ENABLE must be enabled. #endif -#define CO_SRDO_INVALID (0U) -#define CO_SRDO_TX (1U) -#define CO_SRDO_RX (2U) +/* values for informationDirection and configurationValid */ +#define CO_SRDO_INVALID (0U) +#define CO_SRDO_TX (1U) +#define CO_SRDO_RX (2U) +#define CO_SRDO_VALID_MAGIC (0xA5) -#define CO_SRDO_VALID_MAGIC (0xA5) +/* macro for information about SRDO configuration error */ +#define ERR_INFO(index, subindex, info) (((uint32_t)(index) << 16) | ((uint32_t)(subindex) << 8) | ((uint32_t)(info))) - -#define CO_SRDO_BITCMD_OPERATIONAL (0x01U) -#define CO_SRDO_BITCMD_CALC_CRC (0x02U) - -static void CO_SRDO_receive_normal(void *object, void *msg){ - CO_SRDO_t *SRDO; +static void +CO_SRDO_receive_normal(void* object, void* msg) { + CO_SRDO_t* SRDO = (CO_SRDO_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); - - SRDO = (CO_SRDO_t*)object; /* this is the correct pointer type of the first argument */ + uint8_t* data = CO_CANrxMsg_readData(msg); - if( (SRDO->valid == CO_SRDO_RX) && - (DLC >= SRDO->dataLength) && !CO_FLAG_READ(SRDO->CANrxNew[1])){ + if ((SRDO->informationDirection == CO_SRDO_RX) && (DLC >= SRDO->dataLength) && !CO_FLAG_READ(SRDO->CANrxNew[1])) { /* copy data into appropriate buffer and set 'new message' flag */ memcpy(SRDO->CANrxData[0], data, sizeof(SRDO->CANrxData[0])); CO_FLAG_SET(SRDO->CANrxNew[0]); #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles SRDO. */ - if(SRDO->pFunctSignalPre != NULL) { + if (SRDO->pFunctSignalPre != NULL) { SRDO->pFunctSignalPre(SRDO->functSignalObjectPre); } #endif } + else if (DLC < SRDO->dataLength) { + SRDO->rxSrdoShort = true; + } + else { /* MISRA C 2004 14.10 */ } } -static void CO_SRDO_receive_inverted(void *object, void *msg){ - CO_SRDO_t *SRDO; +static void +CO_SRDO_receive_inverted(void* object, void* msg) { + CO_SRDO_t* SRDO = (CO_SRDO_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + uint8_t* data = CO_CANrxMsg_readData(msg); - SRDO = (CO_SRDO_t*)object; /* this is the correct pointer type of the first argument */ - - if( (SRDO->valid == CO_SRDO_RX) && - (DLC >= SRDO->dataLength) && CO_FLAG_READ(SRDO->CANrxNew[0])){ + if ((SRDO->informationDirection == CO_SRDO_RX) && (DLC >= SRDO->dataLength) && CO_FLAG_READ(SRDO->CANrxNew[0])) { /* copy data into appropriate buffer and set 'new message' flag */ memcpy(SRDO->CANrxData[1], data, sizeof(SRDO->CANrxData[1])); CO_FLAG_SET(SRDO->CANrxNew[1]); #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles SRDO. */ - if(SRDO->pFunctSignalPre != NULL) { + if (SRDO->pFunctSignalPre != NULL) { SRDO->pFunctSignalPre(SRDO->functSignalObjectPre); } #endif } -} - -static void CO_SRDOconfigCom(CO_SRDO_t* SRDO, uint32_t COB_IDnormal, uint32_t COB_IDinverted){ - uint16_t IDs[2][2] = {0}; - uint16_t* ID; - uint16_t successCount = 0; - - int16_t i; - - uint32_t COB_ID[2]; - COB_ID[0] = COB_IDnormal; - COB_ID[1] = COB_IDinverted; - - SRDO->valid = CO_SRDO_INVALID; - - /* is SRDO used? */ - if((SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC) && ((SRDO->CommPar_informationDirection == CO_SRDO_TX) || (SRDO->CommPar_informationDirection == CO_SRDO_RX)) && - SRDO->dataLength){ - ID = &IDs[SRDO->CommPar_informationDirection - 1][0]; - /* is used default COB-ID? */ - for(i = 0; i < 2; i++){ - if(!(COB_ID[i] & 0xBFFFF800L)){ - ID[i] = (uint16_t)COB_ID[i] & 0x7FF; - - if((ID[i] == SRDO->defaultCOB_ID[i]) && (SRDO->nodeId <= 64U)){ - ID[i] += (uint16_t)SRDO->nodeId*2; - } - if((0x101U <= ID[i]) && (ID[i] <= 0x180U) && ((ID[i] & 1) != i )){ - successCount++; - } - } - } - } - /* all ids are ok*/ - if(successCount == 2){ - SRDO->valid = SRDO->CommPar_informationDirection; - - if (SRDO->valid == CO_SRDO_TX){ - SRDO->timer = (uint32_t)SRDO->nodeId * 500U; /* 0.5ms * node-ID delay*/ - } - else if (SRDO->valid == CO_SRDO_RX){ - SRDO->timer = (uint32_t)SRDO->CommPar_safetyCycleTime * 1000U; - } - else { /* MISRA C 2004 14.10 */ } + else if (DLC < SRDO->dataLength) { + SRDO->rxSrdoShort = true; } - else{ - memset(IDs, 0, sizeof(IDs)); - CO_FLAG_CLEAR(SRDO->CANrxNew[0]); - CO_FLAG_CLEAR(SRDO->CANrxNew[1]); - SRDO->valid = CO_SRDO_INVALID; - } - + else { /* MISRA C 2004 14.10 */ } +} - for(i = 0; i < 2; i++){ - CO_ReturnError_t r; - SRDO->CANtxBuff[i] = CO_CANtxBufferInit( - SRDO->CANdevTx, /* CAN device */ - SRDO->CANdevTxIdx[i], /* index of specific buffer inside CAN module */ - IDs[0][i], /* CAN identifier */ - 0, /* rtr */ - SRDO->dataLength, /* number of data bytes */ - 0); /* synchronous message flag bit */ +/* Set OD object 13FE:00 to CO_SRDO_INVALID and clear configurationValid flag. */ +static void +configurationValidUnset(CO_SRDOGuard_t* SRDOGuard) { + if (SRDOGuard != NULL) { + OD_IO_t* OD_IO = &SRDOGuard->OD_IO_configurationValid; + uint8_t val = CO_SRDO_INVALID; + OD_size_t dummy; - if(SRDO->CANtxBuff[i] == 0){ - SRDO->valid = CO_SRDO_INVALID; - } + SRDOGuard->configurationValid = SRDOGuard->_configurationValid = false; - r = CO_CANrxBufferInit( - SRDO->CANdevRx, /* CAN device */ - SRDO->CANdevRxIdx[i], /* rx buffer index */ - IDs[1][i], /* CAN identifier */ - 0x7FF, /* mask */ - 0, /* rtr */ - (void*)SRDO, /* object passed to receive function */ - i ? CO_SRDO_receive_inverted : CO_SRDO_receive_normal); /* this function will process received message */ - if(r != CO_ERROR_NO){ - SRDO->valid = CO_SRDO_INVALID; - CO_FLAG_CLEAR(SRDO->CANrxNew[i]); - } + OD_IO->write(&OD_IO->stream, &val, sizeof(val), &dummy); } } -static CO_ReturnError_t SRDO_configMap(CO_SRDO_t* SRDO, - OD_t *OD, - OD_entry_t *OD_SRDOMapPar){ - ODR_t odRet; - size_t pdoDataLength[2] = { 0, 0 }; - uint8_t mappedObjectsCount = 0; - uint8_t *errInfo = NULL; - //uint32_t *erroneousMap = NULL; - - /* number of mapped application objects in SRDO */ - odRet = OD_get_u8(OD_SRDOMapPar, 0, &mappedObjectsCount, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_SRDOMapPar)) << 8) | 0U; - } - return CO_ERROR_OD_PARAMETERS; - } - if (mappedObjectsCount > CO_SRDO_MAX_SIZE) { - //*erroneousMap = 1; - return CO_ERROR_NO; - } - - /* iterate mapped OD variables */ - for(uint8_t i=0; iCommPar_informationDirection == CO_SRDO_RX; - uint32_t map = 0; - uint8_t plain_inverted = i%2; - - odRet = OD_get_u32(OD_SRDOMapPar, i + 1, &map, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_SRDOMapPar)) << 8) | i; - } - return CO_ERROR_OD_PARAMETERS; - } - - uint16_t index = (uint16_t) (map >> 16); - uint8_t subIndex = (uint8_t) (map >> 8); - uint8_t mappedLengthBits = (uint8_t) map; - uint8_t mappedLength = mappedLengthBits >> 3; - uint8_t pdoDataStart = pdoDataLength[plain_inverted]; - pdoDataLength[plain_inverted] += mappedLength; - - if (((mappedLengthBits & 0x07) != 0) || (pdoDataLength[plain_inverted] > CO_SRDO_MAX_SIZE)) { - //*erroneousMap = map; - return CO_ERROR_NO; - } - - /* is there a reference to the dummy entry */ - if ((index < 0x20) && (subIndex == 0U)) { - for (uint8_t j = pdoDataStart; j < pdoDataLength[plain_inverted]; j++) { - static uint8_t dummyTX = 0; - static uint8_t dummyRX; - SRDO->mapPointer[plain_inverted][j] = isRSRDO ? &dummyRX : &dummyTX; - } - continue; - } - - /* find entry in the Object Dictionary, original location */ - OD_IO_t OD_IO; - OD_entry_t *entry = OD_find(OD, index); - OD_attr_t testAttribute = isRSRDO ? ODA_RSRDO : ODA_TSRDO; - - odRet = OD_getSub(entry, subIndex, &OD_IO, true); - if (odRet != ODR_OK - || (OD_IO.stream.attribute & testAttribute) == 0 - || OD_IO.stream.dataLength < mappedLength - || OD_IO.stream.dataOrig == NULL - ) { - //*erroneousMap = map; - return CO_ERROR_NO; - } +/* + * Custom functions for reading or writing OD object. + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static ODR_t +OD_write_dummy(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) +{ + (void) stream; (void) buf; + if (countWritten != NULL) { *countWritten = count; } + return ODR_OK; +} - /* write locations to OD variable data bytes into PDO map pointers */ -#ifdef CO_BIG_ENDIAN - if((OD_IO.stream.attribute & ODA_MB) != 0) { - uint8_t *odDataPointer = OD_IO.stream.dataOrig - + OD_IO.stream.dataLength - 1; - for (uint8_t j = pdoDataStart; j < pdoDataLength; j++) { - SRDO->mapPointer[j] = odDataPointer--; - } - } - else -#endif - { - uint8_t *odDataPointer = OD_IO.stream.dataOrig; - for (uint8_t j = pdoDataStart; j < pdoDataLength[plain_inverted]; j++) { - SRDO->mapPointer[plain_inverted][j] = odDataPointer++; - } - } +static ODR_t +OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) +{ + if (buf == NULL || stream == NULL || countRead == NULL) { + return ODR_DEV_INCOMPAT; } - if(pdoDataLength[0] == pdoDataLength[1]){ - SRDO->dataLength = pdoDataLength[0]; - //SRDO->mappedObjectsCount = pdoDataLength[0]; - }else{ - SRDO->dataLength = 0; - CO_errorReport(SRDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, 0); - return CO_ERROR_OD_PARAMETERS; + if (count > stream->dataLength) { + count = stream->dataLength; } - return CO_ERROR_NO; -} + memset(buf, 0, count); -static uint16_t CO_SRDOcalcCrc(const CO_SRDO_t *SRDO){ - uint16_t i,tmp_u16; - uint16_t result = 0x0000; - uint8_t buffer[4]; - uint32_t cob, tmp_u32; - uint32_t map; - ODR_t odRet; - - result = crc16_ccitt(&SRDO->CommPar_informationDirection, 1, result); - tmp_u16 = CO_SWAP_16(SRDO->CommPar_safetyCycleTime); - memcpy(&buffer[0], &tmp_u16, sizeof(tmp_u16)); - result = crc16_ccitt(&buffer[0], 2, result); - result = crc16_ccitt(&SRDO->CommPar_safetyRelatedValidationTime, 1, result); - - /* adjust COB-ID if the default is used - Caution: if the node id changes and you are using the default COB-ID you have to recalculate the checksum - This behaviour is controversial and could be changed or made optional. - */ - cob = SRDO->CommPar_COB_ID1_normal; - if(((cob&0x7FFU) == SRDO->defaultCOB_ID[0]) && (SRDO->nodeId <= 64U)){ - cob += (uint32_t)SRDO->nodeId*2; - } - tmp_u32 = CO_SWAP_32(cob); - memcpy(&buffer[0], &tmp_u32, sizeof(tmp_u32)); - result = crc16_ccitt(&buffer[0], 4, result); - - cob = SRDO->CommPar_COB_ID2_inverted; - if(((cob&0x7FFU) == SRDO->defaultCOB_ID[1]) && (SRDO->nodeId <= 64U)){ - cob += (uint32_t)SRDO->nodeId*2; - } - tmp_u32 = CO_SWAP_32(cob); - memcpy(&buffer[0], &tmp_u32, sizeof(tmp_u32)); - result = crc16_ccitt(&buffer[0], 4, result); - - result = crc16_ccitt(&SRDO->mappedObjectsCount, 1, result); - for(i = 0; i < SRDO->mappedObjectsCount;){ - uint8_t subindex = i + 1U; - result = crc16_ccitt(&subindex, 1, result); - odRet = OD_get_u32(SRDO->SRDOMapPar, subindex, &map, true); - if (odRet != ODR_OK) { - map = 0; - } - tmp_u32 = CO_SWAP_32(map); - memcpy(&buffer[0], &tmp_u32, sizeof(tmp_u32)); - result = crc16_ccitt(&buffer[0], 4, result); - i = subindex; - } - return result; + *countRead = count; + return ODR_OK; } +static ODR_t +OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); + /* When reading COB_ID, add Node-Id to the read value, if necessary */ + if (returnCode == ODR_OK && (stream->subIndex == 5U || stream->subIndex == 6U) && *countRead == 4) { + CO_SRDO_t* SRDO = stream->object; -static ODR_t OD_read_SRDO_communicationParam(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ - ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); - if ( returnCode != ODR_OK ){ - return returnCode; - } - - if ((stream == NULL) || (buf == NULL) || (countRead == NULL) - ) { - return ODR_DEV_INCOMPAT; - } - - CO_SRDO_t *SRDO = stream->object; - - /* Reading Object Dictionary variable */ - if ((stream->subIndex == 5U) || (stream->subIndex == 6U)){ uint32_t value = CO_getUint32(buf); - uint16_t index = stream->subIndex - 5U; + uint16_t defaultCOB_ID = SRDO->defaultCOB_ID + (stream->subIndex - 5U); - /* if default COB ID is used, write default value here */ - if(((value&0x7FFU) == SRDO->defaultCOB_ID[index]) && (SRDO->nodeId <= 64U)){ - value += (uint32_t)SRDO->nodeId*2; + /* If default COB ID is used, then OD entry does not contain $NodeId. Add it here. */ + if ((value == defaultCOB_ID) && (SRDO->nodeId <= 64U)) { + value += (uint32_t)SRDO->nodeId * 2; } - /* If SRDO is not valid, set bit 31. but I do not think this applies to SRDO ?! */ - /* if(!SRDO->valid){ value |= 0x80000000L; }*/ - CO_setUint32(buf, value); } - return ODR_OK; -} + return returnCode; +} -static ODR_t OD_write_SRDO_communicationParam(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) - || (countWritten == NULL) || (count > 4) - ) { +static ODR_t +OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4)) { return ODR_DEV_INCOMPAT; } - CO_SRDO_t *SRDO = stream->object; - CO_SRDOGuard_t *SRDOGuard = SRDO->SRDOGuard; + CO_SRDO_t* SRDO = stream->object; + CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; uint8_t bufCopy[4]; memcpy(bufCopy, buf, count); /* Writing Object Dictionary variable */ - if(SRDOGuard->operatingState){ - return ODR_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + if (SRDOGuard->NMTisOperational) { + /* Data cannot be transferred or stored to the application because of the present device state. */ + return ODR_DATA_DEV_STATE; } - if(stream->subIndex == 1U){ + if (stream->subIndex == 1U) { /* Information direction */ uint8_t value = CO_getUint8(buf); - if (value > 2U){ + if (value > 2U) { return ODR_INVALID_VALUE; } - SRDO->CommPar_informationDirection = value; - } - else if(stream->subIndex == 2U){ + SRDO->informationDirection = value; + } else if (stream->subIndex == 2) { /* SCT */ uint16_t value = CO_getUint16(buf); - if (value == 0U){ + if (value < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000) + 1)) { return ODR_INVALID_VALUE; } - SRDO->CommPar_safetyCycleTime = value; - } - else if(stream->subIndex == 3U){ + } else if (stream->subIndex == 3) { /* SRVT */ uint8_t value = CO_getUint8(buf); - if (value == 0U){ + if (value == 0) { return ODR_INVALID_VALUE; } - SRDO->CommPar_safetyRelatedValidationTime = value; - } - else if(stream->subIndex == 4){ /* Transmission_type */ + } else if (stream->subIndex == 4) { /* Transmission_type */ uint8_t value = CO_getUint8(buf); - if(value != 254){ - return ODR_INVALID_VALUE; /* Invalid value for parameter (download only). */ + if (value != 254) { + return ODR_INVALID_VALUE; } - SRDO->CommPar_transmissionType = value; - } - else if(stream->subIndex == 5U || stream->subIndex == 6U){ /* COB_ID */ + } else if (stream->subIndex == 5U || stream->subIndex == 6U) { /* COB_ID */ uint32_t value = CO_getUint32(buf); uint16_t index = stream->subIndex - 5U; + uint16_t defaultCOB_ID = SRDO->defaultCOB_ID + index; /* check value range, the spec does not specify if COB-ID flags are allowed */ - if((value < 0x101) || (value > 0x180U) || ((value & 1) == index)){ - return ODR_INVALID_VALUE; /* Invalid value for parameter (download only). */ + if ((value < 0x101) || (value > 0x180U) || ((value & 1) == index)) { + return ODR_INVALID_VALUE; /* Invalid value for parameter (download only). */ } /* if default COB-ID is being written, write defaultCOB_ID without nodeId */ - if((SRDO->nodeId <= 64U) && (value == (SRDO->defaultCOB_ID[index] + ((uint32_t)SRDO->nodeId*2)))){ - value = SRDO->defaultCOB_ID[index]; + if ((SRDO->nodeId <= 64U) && (value == (defaultCOB_ID + ((uint32_t)SRDO->nodeId * 2)))) { + value = defaultCOB_ID; CO_setUint32(bufCopy, value); } - if(index == 0U){ - SRDO->CommPar_COB_ID1_normal = value; - } - else{ - SRDO->CommPar_COB_ID2_inverted = value; - } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } - SRDOGuard->configurationValid = CO_SRDO_INVALID; + /* set OD object 13FE:00 to CO_SRDO_INVALID */ + configurationValidUnset(SRDOGuard); /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, bufCopy, count, countWritten); } - - -static ODR_t OD_write_SRDO_mappingParam(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || - (stream->subIndex > CO_SRDO_MAX_MAPPED_ENTRIES) - ) { +static ODR_t +OD_write_SRDO_mappingParam(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) + || (stream->subIndex > CO_SRDO_MAX_MAPPED_ENTRIES)) { return ODR_DEV_INCOMPAT; } - - CO_SRDO_t *SRDO = stream->object; - CO_SRDOGuard_t *SRDOGuard = SRDO->SRDOGuard; + + CO_SRDO_t* SRDO = stream->object; + CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; /* Writing Object Dictionary variable */ - if(SRDOGuard->operatingState){ - return ODR_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + if (SRDOGuard->NMTisOperational) { + /* Data cannot be transferred or stored to the application because of the present device state. */ + return ODR_DATA_DEV_STATE; } - if(SRDO->CommPar_informationDirection){ /* SRDO must be deleted */ - return ODR_UNSUPP_ACCESS; /* Unsupported access to an object. */ + /* SRDO must be disabled */ + if (SRDO->informationDirection != 0) { + return ODR_UNSUPP_ACCESS; /* Unsupported access to an object. */ } /* numberOfMappedObjects */ - if(stream->subIndex == 0U){ + if (stream->subIndex == 0U) { uint8_t value = CO_getUint8(buf); - if((value > 16U) || (value & 1)){ /*only odd numbers are allowed*/ - return ODR_MAP_LEN; /* Number and length of object to be mapped exceeds SRDO length. */ + /* only odd numbers are allowed */ + if ((value > CO_SRDO_MAX_MAPPED_ENTRIES) || (value & 1)) { + return ODR_MAP_LEN; /* Number and length of object to be mapped exceeds SRDO length. */ } SRDO->mappedObjectsCount = value; } - else{ - if (SRDO->mappedObjectsCount != 0U){ + /* mapping objects */ + else { + if (SRDO->mappedObjectsCount != 0U) { return ODR_UNSUPP_ACCESS; } + /* No other checking is implemented here. Values are validated in the configuration function. */ } - SRDOGuard->configurationValid = CO_SRDO_INVALID; - - + + /* set OD object 13FE:00 to CO_SRDO_INVALID */ + configurationValidUnset(SRDOGuard); + /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, buf, count, countWritten); } -static ODR_t OD_read_13FE(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ - ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); - if ( returnCode != ODR_OK ){ - return returnCode; - } - - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countRead == NULL) - ) { - return ODR_DEV_INCOMPAT; - } - - CO_SRDOGuard_t *SRDOGuard = stream->object; - CO_setUint8(buf, SRDOGuard->configurationValid); - - return ODR_OK; -} - -static ODR_t OD_write_13FE(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countWritten == NULL) - ) { +static ODR_t +OD_write_13FE(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_SRDOGuard_t *SRDOGuard = stream->object; - uint8_t value = CO_getUint8(buf); + CO_SRDOGuard_t* SRDOGuard = stream->object; - if(SRDOGuard->operatingState){ - return ODR_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + if (SRDOGuard->NMTisOperational) { + /* Data cannot be transferred or stored to the application because of the present device state. */ + return ODR_DATA_DEV_STATE; } - SRDOGuard->checkCRC = ( value == CO_SRDO_VALID_MAGIC ); - - SRDOGuard->configurationValid = value; /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, buf, count, countWritten); } -static ODR_t OD_write_13FF(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (countWritten == NULL) - ) { +static ODR_t +OD_write_13FF(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_SRDOGuard_t *SRDOGuard = stream->object; - uint16_t value = CO_getUint16(buf); + CO_SRDOGuard_t* SRDOGuard = stream->object; - if(SRDOGuard->operatingState){ - return ODR_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */ + if (SRDOGuard->NMTisOperational) { + /* Data cannot be transferred or stored to the application because of the present device state. */ + return ODR_DATA_DEV_STATE; } - SRDOGuard->configurationValid = CO_SRDO_INVALID; + + /* set OD object 13FE:00 to CO_SRDO_INVALID */ + configurationValidUnset(SRDOGuard); /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, buf, count, countWritten); } -CO_ReturnError_t CO_SRDOGuard_init( - CO_SRDOGuard_t *SRDOGuard, - OD_entry_t *OD_13FE_SRDOValid, - OD_entry_t *OD_13FF_SRDOCRC, - uint32_t *errInfo) -{ +#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE +void +CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalPre)(void* object)) { + if (SRDO != NULL) { + SRDO->functSignalObjectPre = object; + SRDO->pFunctSignalPre = pFunctSignalPre; + } +} +#endif + +CO_ReturnError_t +CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, + OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo) { ODR_t odRet; /* verify arguments */ - if((SRDOGuard==NULL) || (OD_13FE_SRDOValid==NULL) || (OD_13FF_SRDOCRC==NULL)){ + if ((SRDOGuard == NULL) || (OD_13FE_configurationValid == NULL) || (OD_13FF_safetyConfigurationSignature == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } /* clear object */ memset(SRDOGuard, 0, sizeof(CO_SRDOGuard_t)); - SRDOGuard->operatingState = false; - SRDOGuard->SRDO_CRC = OD_13FF_SRDOCRC; + /* Configure Object dictionary extensions */ + SRDOGuard->OD_13FE_extension.object = SRDOGuard; + SRDOGuard->OD_13FE_extension.read = OD_readOriginal; + SRDOGuard->OD_13FE_extension.write = OD_write_13FE; + OD_extension_init(OD_13FE_configurationValid, &SRDOGuard->OD_13FE_extension); - uint8_t value = 0; - odRet = OD_get_u8(OD_13FE_SRDOValid, 0, &value, true); - if (odRet != ODR_OK) { + SRDOGuard->OD_13FF_extension.object = SRDOGuard; + SRDOGuard->OD_13FF_extension.read = OD_readOriginal; + SRDOGuard->OD_13FF_extension.write = OD_write_13FF; + OD_extension_init(OD_13FF_safetyConfigurationSignature, &SRDOGuard->OD_13FF_extension); + + /* Configure SRDOGuard->OD_IO_configurationValid variable. + * It will be used for writing 0 to OD variable 13FE,00 */ + odRet = OD_getSub(OD_13FE_configurationValid, 0, &SRDOGuard->OD_IO_configurationValid, false); + if (odRet != ODR_OK || SRDOGuard->OD_IO_configurationValid.stream.dataLength != 1) { if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_13FE_SRDOValid)) << 8) | 1U; + *errInfo = (((uint32_t)OD_getIndex(OD_13FE_configurationValid)) << 8) | 1U; } return CO_ERROR_OD_PARAMETERS; } - SRDOGuard->configurationValid = value; - - SRDOGuard->checkCRC = (SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC); - /* Configure Object dictionary entry at index 0x13FE and 0x13FF */ - SRDOGuard->OD_13FE_extension.object = SRDOGuard; - SRDOGuard->OD_13FE_extension.read = OD_read_13FE; - SRDOGuard->OD_13FE_extension.write = OD_write_13FE; - OD_extension_init(OD_13FE_SRDOValid, &SRDOGuard->OD_13FE_extension); - - SRDOGuard->OD_13FF_extension.object = SRDOGuard; - SRDOGuard->OD_13FF_extension.read = OD_readOriginal; - SRDOGuard->OD_13FF_extension.write = OD_write_13FF; - OD_extension_init(OD_13FF_SRDOCRC, &SRDOGuard->OD_13FF_extension); + /* Private variable, erroneous SRDO initialization will clear this. */ + SRDOGuard->_configurationValid = true; return CO_ERROR_NO; } -uint8_t CO_SRDOGuard_process( - CO_SRDOGuard_t *SRDOGuard, - bool_t NMTisOperational) -{ - uint8_t result = 0; - if(NMTisOperational != SRDOGuard->operatingState){ - SRDOGuard->operatingState = NMTisOperational; - if (NMTisOperational){ - result |= CO_SRDO_BITCMD_OPERATIONAL; - } - } +CO_ReturnError_t +CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_t* OD, CO_EM_t* em, uint8_t nodeId, + uint16_t defaultCOB_ID, OD_entry_t* OD_130x_SRDOCommPar, OD_entry_t* OD_138x_SRDOMapPar, + OD_entry_t* OD_13FE_configurationValid, OD_entry_t* OD_13FF_safetyConfigurationSignature, + CO_CANmodule_t* CANdevRxNormal, CO_CANmodule_t* CANdevRxInverted, uint16_t CANdevRxIdxNormal, + uint16_t CANdevRxIdxInverted, CO_CANmodule_t* CANdevTxNormal, CO_CANmodule_t* CANdevTxInverted, + uint16_t CANdevTxIdxNormal, uint16_t CANdevTxIdxInverted, uint32_t* errInfo) { + + CO_ReturnError_t ret = CO_ERROR_NO; + uint32_t err = 0; + bool_t configurationInProgress = false; + + /* variables will be retrieved from Object Dictionary */ + uint8_t cp_highestSubindexSupported; + uint8_t informationDirection; + uint16_t safetyCycleTime; + uint8_t safetyRelatedValidationTime; + uint8_t transmissionType; + uint32_t COB_ID1_normal; + uint32_t COB_ID2_inverted; + uint8_t configurationValid; + uint16_t crcSignatureFromOD; + uint8_t mappedObjectsCount; + uint32_t mapping[CO_SRDO_MAX_MAPPED_ENTRIES]; - if(SRDOGuard->checkCRC){ - result |= CO_SRDO_BITCMD_CALC_CRC; - SRDOGuard->checkCRC = 0; + /* verify arguments */ + if ((SRDO == NULL) || (SRDOGuard == NULL) || (OD == NULL) || (em == NULL) || (OD_130x_SRDOCommPar == NULL) + || (OD_138x_SRDOMapPar == NULL) || (OD_13FE_configurationValid == NULL) || (OD_13FF_safetyConfigurationSignature == NULL) + || (CANdevRxNormal == NULL) || (CANdevRxInverted == NULL) || (CANdevTxNormal == NULL) || (CANdevTxInverted == NULL)) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + err = 1; } - return result; -} -#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE -/******************************************************************************/ -void CO_SRDO_initCallbackPre( - CO_SRDO_t *SRDO, - void *object, - void (*pFunctSignalPre)(void *object)) -{ - if(SRDO != NULL){ - SRDO->functSignalObjectPre = object; - SRDO->pFunctSignalPre = pFunctSignalPre; - } -} -#endif + /* clear object and configure some object variables */ + if (err == 0) { + memset(SRDO, 0, sizeof(CO_SRDO_t)); -/******************************************************************************/ -void CO_SRDO_initCallbackEnterSafeState( - CO_SRDO_t *SRDO, - void *object, - void (*pFunctSignalSafe)(void *object)) -{ - if(SRDO != NULL){ - SRDO->functSignalObjectSafe = object; - SRDO->pFunctSignalSafe = pFunctSignalSafe; - } -} + SRDO->SRDOGuard = SRDOGuard; + SRDO->em = em; + SRDO->defaultCOB_ID = defaultCOB_ID; + SRDO->nodeId = nodeId; + SRDO->CANdevTx[0] = CANdevTxNormal; + SRDO->CANdevTx[1] = CANdevTxInverted; -CO_ReturnError_t CO_SRDO_init( - CO_SRDO_t *SRDO, - uint8_t SRDO_Index, - CO_SRDOGuard_t *SRDOGuard, - OD_t *OD, - CO_EM_t *em, - uint8_t nodeId, - uint16_t defaultCOB_ID, - OD_entry_t *OD_130x_SRDOCommPar, - OD_entry_t *OD_138x_SRDOMapPar, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdxNormal, - uint16_t CANdevRxIdxInverted, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdxNormal, - uint16_t CANdevTxIdxInverted, - uint32_t *errInfo) -{ - ODR_t odRet; + /* Configure Object dictionary entry at index 0x1301+ */ + SRDO->OD_communicationParam_ext.object = SRDO; + SRDO->OD_communicationParam_ext.read = OD_read_SRDO_communicationParam; + SRDO->OD_communicationParam_ext.write = OD_write_SRDO_communicationParam; + OD_extension_init(OD_130x_SRDOCommPar, &SRDO->OD_communicationParam_ext); - /* verify arguments */ - if((SRDO==NULL) || (SRDOGuard==NULL) || (OD==NULL) || (em==NULL) || - (OD_130x_SRDOCommPar==NULL) || (OD_138x_SRDOMapPar==NULL) || (CANdevRx==NULL) || (CANdevTx==NULL)){ - return CO_ERROR_ILLEGAL_ARGUMENT; + /* Configure Object dictionary entry at index 0x1381+ */ + SRDO->OD_mappingParam_extension.object = SRDO; + SRDO->OD_mappingParam_extension.read = OD_readOriginal; + SRDO->OD_mappingParam_extension.write = OD_write_SRDO_mappingParam; + OD_extension_init(OD_138x_SRDOMapPar, &SRDO->OD_mappingParam_extension); } - - /* clear object */ - memset(SRDO, 0, sizeof(CO_SRDO_t)); - - /* Configure object variables */ - SRDO->SRDO_Index = SRDO_Index; - SRDO->SRDOGuard = SRDOGuard; - SRDO->em = em; - SRDO->OD = OD; - SRDO->SRDOCommPar = OD_130x_SRDOCommPar; - SRDO->SRDOMapPar = OD_138x_SRDOMapPar; - SRDO->CANdevRx = CANdevRx; - SRDO->CANdevRxIdx[0] = CANdevRxIdxNormal; - SRDO->CANdevRxIdx[1] = CANdevRxIdxInverted; - SRDO->CANdevTx = CANdevTx; - SRDO->CANdevTxIdx[0] = CANdevTxIdxNormal; - SRDO->CANdevTxIdx[1] = CANdevTxIdxInverted; - SRDO->nodeId = nodeId; - SRDO->defaultCOB_ID[0] = defaultCOB_ID; - SRDO->defaultCOB_ID[1] = defaultCOB_ID + 1U; - SRDO->valid = CO_SRDO_INVALID; - SRDO->toogle = 0; - SRDO->timer = 0; - SRDO->pFunctSignalSafe = NULL; - SRDO->functSignalObjectSafe = NULL; -#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE - SRDO->pFunctSignalPre = NULL; - SRDO->functSignalObjectPre = NULL; -#endif - uint8_t informationDirection = 0; - odRet = OD_get_u8(OD_130x_SRDOCommPar, 1, &informationDirection, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 1U; + /* Get variables from object Dictionary and verify it's structure. */ + if (err == 0) { + if (OD_get_u8(OD_130x_SRDOCommPar, 0, &cp_highestSubindexSupported, true) != ODR_OK) { + err = ERR_INFO(0x1301 + SRDO_Index, 0, 1); + } + else if (OD_get_u8(OD_130x_SRDOCommPar, 1, &informationDirection, true) != ODR_OK) { + err = ERR_INFO(0x1301 + SRDO_Index, 1, 1); + } + else if (OD_get_u16(OD_130x_SRDOCommPar, 2, &safetyCycleTime, true) != ODR_OK) { + err = ERR_INFO(0x1301 + SRDO_Index, 2, 1); + } + else if (OD_get_u8(OD_130x_SRDOCommPar, 3, &safetyRelatedValidationTime, true) != ODR_OK) { + err = ERR_INFO(0x1301 + SRDO_Index, 3, 1); + } + else if (OD_get_u8(OD_130x_SRDOCommPar, 4, &transmissionType, true) != ODR_OK) { + err = ERR_INFO(0x1301 + SRDO_Index, 4, 1); + } + else if (OD_get_u32(OD_130x_SRDOCommPar, 5, &COB_ID1_normal, true) != ODR_OK) { + err = ERR_INFO(0x1301 + SRDO_Index, 5, 1); + } + else if (OD_get_u32(OD_130x_SRDOCommPar, 6, &COB_ID2_inverted, true) != ODR_OK) { + err = ERR_INFO(0x1301 + SRDO_Index, 6, 1); + } + else if (OD_get_u8(OD_13FE_configurationValid, 0, &configurationValid, true) != ODR_OK) { + err = ERR_INFO(0x13FE, 0, 1); + } + else if (OD_get_u16(OD_13FF_safetyConfigurationSignature, SRDO_Index + 1, &crcSignatureFromOD, true) != ODR_OK) { + err = ERR_INFO(0x13FF, SRDO_Index + 1, 1); + } + else if (OD_get_u8(OD_138x_SRDOMapPar, 0, &mappedObjectsCount, true) != ODR_OK) { + err = ERR_INFO(0x1381 + SRDO_Index, 0, 1); + } + else { + for (uint8_t i = 1; i <= CO_SRDO_MAX_MAPPED_ENTRIES; i++) { + if (OD_get_u32(OD_138x_SRDOMapPar, i, &mapping[i], true) != ODR_OK) { + err = ERR_INFO(0x1381 + SRDO_Index, i, 1); + break; + } + } } - return CO_ERROR_OD_PARAMETERS; - } - SRDO->CommPar_informationDirection = informationDirection; - uint16_t safetyCycleTime = 0; - odRet = OD_get_u16(OD_130x_SRDOCommPar, 2, &safetyCycleTime, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 2U; + /* if OD contains default COB_IDs, add node-id */ + if (COB_ID1_normal == defaultCOB_ID && COB_ID2_inverted == (defaultCOB_ID + 1) && nodeId <= 64U) { + uint32_t add = (uint32_t)SRDO->nodeId * 2; + COB_ID1_normal += add; + COB_ID2_inverted += add; } - return CO_ERROR_OD_PARAMETERS; - } - SRDO->CommPar_safetyCycleTime= safetyCycleTime; - - uint8_t safetyRelatedValidationTime = 0; - odRet = OD_get_u8(OD_130x_SRDOCommPar, 3, &safetyRelatedValidationTime, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 3U; + + /* If this fails, something is wrong with the Object Dictionary. Device have to be reprogrammed. */ + if (err != 0) { + ret = CO_ERROR_OD_PARAMETERS; } - return CO_ERROR_OD_PARAMETERS; } - SRDO->CommPar_safetyRelatedValidationTime = safetyRelatedValidationTime; - - uint8_t transmissionType = 0; - odRet = OD_get_u8(OD_130x_SRDOCommPar, 4, &transmissionType, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 4U; - } - return CO_ERROR_OD_PARAMETERS; + + /* If configurationValid is set and SRDO is valid, continue with further configuration */ + if (err == 0 && configurationValid == CO_SRDO_VALID_MAGIC && informationDirection != CO_SRDO_INVALID) { + configurationInProgress = true; } - SRDO->CommPar_transmissionType = transmissionType; - - uint32_t COB_ID1_normal = 0; - odRet = OD_get_u32(OD_130x_SRDOCommPar, 5, &COB_ID1_normal, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 5U; + + /* Verify parameters from OD */ + if (err == 0 && configurationInProgress) { + if (cp_highestSubindexSupported != 6) { + err = ERR_INFO(0x1301 + SRDO_Index, 0, 2); } - return CO_ERROR_OD_PARAMETERS; - } - SRDO->CommPar_COB_ID1_normal = COB_ID1_normal; - - uint32_t COB_ID2_inverted = 0; - odRet = OD_get_u32(OD_130x_SRDOCommPar, 6, &COB_ID2_inverted, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_130x_SRDOCommPar)) << 8) | 6U; + else if (informationDirection > 3) { + err = ERR_INFO(0x1301 + SRDO_Index, 1, 2); } - return CO_ERROR_OD_PARAMETERS; - } - SRDO->CommPar_COB_ID2_inverted = COB_ID2_inverted; - - /* Configure Object dictionary entry at index 0x1301+ and 0x1381+ */ - SRDO->OD_communicationParam_ext.object = SRDO; - SRDO->OD_communicationParam_ext.read = OD_read_SRDO_communicationParam; - SRDO->OD_communicationParam_ext.write = OD_write_SRDO_communicationParam; - OD_extension_init(OD_130x_SRDOCommPar, &SRDO->OD_communicationParam_ext); - - uint8_t numberOfMappedObjects = 0; - odRet = OD_get_u8(OD_138x_SRDOMapPar, 0, &numberOfMappedObjects, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_138x_SRDOMapPar)) << 8) | 0U; + else if (safetyCycleTime < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000) + 1)) { + err = ERR_INFO(0x1301 + SRDO_Index, 2, 2); + } + else if (safetyRelatedValidationTime < 1) { + err = ERR_INFO(0x1301 + SRDO_Index, 3, 2); + } + else if (transmissionType != 254) { + err = ERR_INFO(0x1301 + SRDO_Index, 4, 2); + } + else if (COB_ID1_normal < 0x101 || (COB_ID1_normal & 1) == 0) { + err = ERR_INFO(0x1301 + SRDO_Index, 5, 2); + } + else if ((COB_ID1_normal + 1) != COB_ID2_inverted || COB_ID2_inverted > 0x180) { + err = ERR_INFO(0x1301 + SRDO_Index, 6, 2); + } + else if (mappedObjectsCount > CO_SRDO_MAX_MAPPED_ENTRIES || (mappedObjectsCount & 1) != 0) { + err = ERR_INFO(0x1381 + SRDO_Index, 0, 2); + } + else { + /* MISRA C 2004 14.10 */ } - return CO_ERROR_OD_PARAMETERS; } - SRDO->mappedObjectsCount = numberOfMappedObjects; - SRDO->OD_mappingParam_extension.object = SRDO; - SRDO->OD_mappingParam_extension.read = OD_readOriginal; - SRDO->OD_mappingParam_extension.write = OD_write_SRDO_mappingParam; - OD_extension_init(OD_138x_SRDOMapPar, &SRDO->OD_mappingParam_extension); + /* Verify CRC */ + if (err == 0 && configurationInProgress) { + uint16_t crcResult = 0x0000; + uint16_t tmp_u16; + uint32_t tmp_u32; - return CO_ERROR_NO; -} + crcResult = crc16_ccitt(&informationDirection, 1, crcResult); + tmp_u16 = CO_SWAP_16(safetyCycleTime); + crcResult = crc16_ccitt((uint8_t *)&tmp_u16, 2, crcResult); + crcResult = crc16_ccitt(&safetyRelatedValidationTime, 1, crcResult); + tmp_u32 = CO_SWAP_32(COB_ID1_normal); + crcResult = crc16_ccitt((uint8_t *)&tmp_u32, 4, crcResult); + tmp_u32 = CO_SWAP_32(COB_ID2_inverted); + crcResult = crc16_ccitt((uint8_t *)&tmp_u32, 4, crcResult); + crcResult = crc16_ccitt(&mappedObjectsCount, 1, crcResult); + for (uint8_t i = 0; i < mappedObjectsCount; i++) { + uint8_t subindex = i + 1U; + crcResult = crc16_ccitt(&subindex, 1, crcResult); + tmp_u32 = CO_SWAP_32(mapping[i]); + crcResult = crc16_ccitt((uint8_t *)&tmp_u32, 4, crcResult); + } -CO_ReturnError_t CO_SRDO_requestSend( - CO_SRDO_t *SRDO) -{ - if (SRDO->SRDOGuard->operatingState == false){ - return CO_ERROR_WRONG_NMT_STATE; + if (crcResult != crcSignatureFromOD) { + err = ERR_INFO(0x13FF, SRDO_Index + 1, 3); + } } - if (SRDO->valid != CO_SRDO_TX){ - return CO_ERROR_TX_UNCONFIGURED; - } + /* Configure mappings */ + if (err == 0 && configurationInProgress) { + size_t srdoDataLength[2] = {0, 0}; + + for (uint8_t i = 0; i < mappedObjectsCount; i++) { + uint8_t plain_inverted = i % 2; + uint32_t map = mapping[i]; + uint16_t index = (uint16_t) (map >> 16); + uint8_t subIndex = (uint8_t) (map >> 8); + uint8_t mappedLengthBits = (uint8_t) map; + uint8_t mappedLength = mappedLengthBits >> 3; + OD_IO_t *OD_IO = &SRDO->OD_IO[i]; + + /* total SRDO length can not be more than CO_SRDO_MAX_SIZE bytes */ + if (mappedLength > CO_SRDO_MAX_SIZE) { + err = ERR_INFO(0x1381 + SRDO_Index, i + 1, 4); + } + /* is there a reference to the dummy entry */ + else if (index < 0x20 && subIndex == 0) { + OD_stream_t *stream = &OD_IO->stream; + memset(stream, 0, sizeof(OD_stream_t)); + stream->dataLength = stream->dataOffset = mappedLength; + OD_IO->read = OD_read_dummy; + OD_IO->write = OD_write_dummy; + } + /* find entry in the Object Dictionary */ + else { + OD_IO_t OD_IOcopy; + OD_entry_t *entry = OD_find(OD, index); + ODR_t odRet = OD_getSub(entry, subIndex, &OD_IOcopy, false); + if (odRet != ODR_OK) { + err = ERR_INFO(0x1381 + SRDO_Index, i + 1, 5); + } + else { + /* verify access attributes, byte alignment and length */ + OD_attr_t testAttribute = (informationDirection == CO_SRDO_RX) ? ODA_RSRDO : ODA_TSRDO; + if ((OD_IOcopy.stream.attribute & testAttribute) == 0 + || (mappedLengthBits & 0x07) != 0 + || OD_IOcopy.stream.dataLength < mappedLength + ) { + err = ERR_INFO(0x1381 + SRDO_Index, i + 1, 6); + } + + /* Copy values and store mappedLength temporary. */ + *OD_IO = OD_IOcopy; + OD_IO->stream.dataOffset = mappedLength; + srdoDataLength[plain_inverted] += mappedLength; + } + } + if (err != 0) { + break; + } + } /* for (uint8_t i = 0; i < mappedObjectsCount; i++) */ - if(SRDO->toogle != 0U){ - return CO_ERROR_TX_BUSY; + if (err == 0) { + if (srdoDataLength[0] != srdoDataLength[1]) { + err = ERR_INFO(0x1381 + SRDO_Index, 0, 7); + } + else if (srdoDataLength[0] == 0 || srdoDataLength[0] > CO_SRDO_MAX_SIZE) { + err = ERR_INFO(0x1381 + SRDO_Index, 0, 8); + } + else { + SRDO->dataLength = srdoDataLength[0]; + SRDO->mappedObjectsCount = mappedObjectsCount; + } + } } - SRDO->timer = 0; - return CO_ERROR_NO; -} + /* Configure CAN tx buffers */ + if (err == 0 && configurationInProgress && informationDirection == CO_SRDO_TX) { -void CO_SRDO_process( - CO_SRDO_t *SRDO, - uint8_t commands, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ - ODR_t odRet; + SRDO->CANtxBuff[0] = CO_CANtxBufferInit(CANdevTxNormal, /* CAN device */ + CANdevTxIdxNormal, /* index of specific buffer inside CAN module */ + COB_ID1_normal, /* CAN identifier */ + 0, /* rtr */ + SRDO->dataLength, /* number of data bytes */ + 0); /* synchronous message flag bit */ - (void)timerNext_us; /* may be unused */ + if (SRDO->CANtxBuff[0] == NULL) { + err = ERR_INFO(0x1301 + SRDO_Index, 5, 10); + } + + SRDO->CANtxBuff[1] = CO_CANtxBufferInit(CANdevTxInverted, /* CAN device */ + CANdevTxIdxInverted, /* index of specific buffer inside CAN module */ + COB_ID2_inverted, /* CAN identifier */ + 0, /* rtr */ + SRDO->dataLength, /* number of data bytes */ + 0); /* synchronous message flag bit */ - if(commands & CO_SRDO_BITCMD_CALC_CRC){ - uint16_t crcValue = CO_SRDOcalcCrc(SRDO); - uint16_t crcSRDO = 0; - odRet = OD_get_u16(SRDO->SRDOGuard->SRDO_CRC, SRDO->SRDO_Index+1, &crcSRDO, true); - if ((odRet != ODR_OK) || (crcSRDO != crcValue)) { - SRDO->SRDOGuard->configurationValid = 0; + if (SRDO->CANtxBuff[1] == NULL) { + err = ERR_INFO(0x1301 + SRDO_Index, 6, 10); } } - if((commands & CO_SRDO_BITCMD_OPERATIONAL) && (SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC)){ - if(SRDO_configMap(SRDO,SRDO->OD,SRDO->SRDOMapPar) == CO_ERROR_NO){ - CO_SRDOconfigCom(SRDO, SRDO->CommPar_COB_ID1_normal, SRDO->CommPar_COB_ID2_inverted); + /* Configure CAN rx buffers */ + if (err == 0 && configurationInProgress && informationDirection == CO_SRDO_RX) { + CO_ReturnError_t ret; + + ret = CO_CANrxBufferInit(CANdevRxNormal, /* CAN device */ + CANdevRxIdxNormal, /* rx buffer index */ + COB_ID1_normal, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)SRDO, /* object passed to the receive function */ + CO_SRDO_receive_normal); /* this function will process received message */ + + if (ret != CO_ERROR_NO) { + err = ERR_INFO(0x1301 + SRDO_Index, 5, 11); } - else{ - SRDO->valid = CO_SRDO_INVALID; + + ret = CO_CANrxBufferInit(CANdevRxInverted, /* CAN device */ + CANdevRxIdxInverted, /* rx buffer index */ + COB_ID2_inverted, /* CAN identifier */ + 0x7FF, /* mask */ + 0, /* rtr */ + (void*)SRDO, /* object passed to the receive function */ + CO_SRDO_receive_inverted); /* this function will process received message */ + + if (ret != CO_ERROR_NO) { + err = ERR_INFO(0x1301 + SRDO_Index, 6, 11); } } - if(SRDO->valid && SRDO->SRDOGuard->operatingState){ - SRDO->timer = (SRDO->timer > timeDifference_us) ? (SRDO->timer - timeDifference_us) : 0U; - if(SRDO->valid == CO_SRDO_TX){ - if(SRDO->timer == 0U){ - if(SRDO->toogle){ - CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[1]); - SRDO->timer = ((uint32_t)SRDO->CommPar_safetyCycleTime * 1000U) - CO_CONFIG_SRDO_MINIMUM_DELAY; - } - else{ - uint16_t i; - uint8_t* pSRDOdataByte_normal; - uint8_t* pSRDOdataByte_inverted; + /* Configure remaining variables */ + if (err == 0) { + SRDO->informationDirection = informationDirection; + SRDO->cycleTime_us = (uint32_t)safetyCycleTime * 1000U; + SRDO->validationTime_us = (uint32_t)safetyRelatedValidationTime * 1000U; + } + else { + if (ret == CO_ERROR_NO) { + CO_errorReport(em, CO_EM_SRDO_CONFIGURATION, CO_EMC_DATA_SET, err); + configurationValidUnset(SRDO->SRDOGuard); + } + } - uint8_t** ppODdataByte_normal; - uint8_t** ppODdataByte_inverted; + if (errInfo != NULL) { + *errInfo = err; + } - bool_t data_ok = true; -#if (CO_CONFIG_SRDO) & CO_CONFIG_TSRDO_CALLS_EXTENSION - if(SRDO->SDO->ODExtensions){ - /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ - const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0]; - CO_SDOserver_t *pSDO = SRDO->SDO; - - for(i=SRDO->mappedObjectsCount; i>0; i--){ - uint32_t map = *(pMap++); - uint16_t index = (uint16_t)(map>>16); - uint8_t subIndex = (uint8_t)(map>>8); - uint16_t entryNo = CO_OD_find(pSDO, index); - if ( entryNo != 0xFFFF ) - { - CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo]; - if( ext->pODFunc != NULL) - { - CO_ODF_arg_t ODF_arg; - memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t)); - ODF_arg.reading = true; - ODF_arg.index = index; - ODF_arg.subIndex = subIndex; - ODF_arg.object = ext->object; - ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex); - ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex); - ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); /* https://github.com/CANopenNode/CANopenNode/issues/100 */ - ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex); - ext->pODFunc(&ODF_arg); - } - } - } - } -#endif - pSRDOdataByte_normal = &SRDO->CANtxBuff[0]->data[0]; - ppODdataByte_normal = &SRDO->mapPointer[0][0]; + return ret; +} - pSRDOdataByte_inverted = &SRDO->CANtxBuff[1]->data[0]; - ppODdataByte_inverted = &SRDO->mapPointer[1][0]; +CO_ReturnError_t +CO_SRDO_requestSend(CO_SRDO_t* SRDO) { + CO_ReturnError_t ret; -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX - /* check data before sending (optional) */ - for(i = 0; idataLength; i++){ - uint8_t invert = ~*(ppODdataByte_inverted[i]); - if (*(ppODdataByte_normal[i]) != invert) - { - data_ok = false; + if (SRDO->SRDOGuard->NMTisOperational == false) { + ret = CO_ERROR_WRONG_NMT_STATE; + } else if (SRDO->SRDOGuard->configurationValid == false) { + ret = CO_ERROR_OD_PARAMETERS; + } else if (SRDO->informationDirection != CO_SRDO_TX) { + ret = CO_ERROR_TX_UNCONFIGURED; + } else if (SRDO->nextIsNormal == false) { + ret = CO_ERROR_TX_BUSY; + } else { + SRDO->cycleTimer = 0; + ret = CO_ERROR_NO; + } + + return ret; +} + +CO_SRDO_state_t +CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext_us, bool_t NMTisOperational) { + (void)timerNext_us; /* may be unused */ + + if (NMTisOperational && SRDO->informationDirection != CO_SRDO_INVALID && SRDO->SRDOGuard->configurationValid + && SRDO->internalState >= CO_SRDO_state_unknown) { + SRDO->cycleTimer = (SRDO->cycleTimer > timeDifference_us) ? (SRDO->cycleTimer - timeDifference_us) : 0U; + SRDO->validationTimer = (SRDO->validationTimer > timeDifference_us) ? (SRDO->validationTimer - timeDifference_us) : 0U; + + /* Detect transition to NMT operational */ + if (!SRDO->NMTisOperationalPrevious) { + SRDO->cycleTimer = (SRDO->informationDirection == CO_SRDO_TX) + ? (uint32_t)SRDO->nodeId * 500U /* 0.5ms * node-ID delay*/ + : SRDO->cycleTime_us; + SRDO->validationTimer = SRDO->cycleTime_us; + SRDO->internalState = CO_SRDO_state_initializing; + SRDO->nextIsNormal = true; + } + + if (SRDO->internalState <= CO_SRDO_state_unknown) { + SRDO->internalState = CO_SRDO_state_error_internal; /* should not happen */ + } + else if (SRDO->informationDirection == CO_SRDO_TX) { + if (SRDO->cycleTimer == 0U) { + if (SRDO->nextIsNormal) { + uint8_t *dataSRDO[2] = {&SRDO->CANtxBuff[0]->data[0], &SRDO->CANtxBuff[1]->data[0]}; + size_t verifyLength = 0; + + /* copy mapped data from Object Dictionary into CAN buffers */ + for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) { + uint8_t plain_inverted = i % 2; + OD_IO_t *OD_IO = &SRDO->OD_IO[i]; + OD_stream_t *stream = &OD_IO->stream; + + /* get mappedLength from temporary storage */ + uint8_t mappedLength = (uint8_t) stream->dataOffset; + + /* additional safety check */ + verifyLength += mappedLength; + if (verifyLength > CO_SRDO_MAX_SIZE) { break; } - } + + /* length of OD variable may be larger than mappedLength */ + OD_size_t ODdataLength = stream->dataLength; + if (ODdataLength > CO_SRDO_MAX_SIZE) { + ODdataLength = CO_SRDO_MAX_SIZE; + } + /* If mappedLength is smaller than ODdataLength, use auxiliary buffer */ + uint8_t buf[CO_SRDO_MAX_SIZE]; + uint8_t *dataSRDOCopy; + if (ODdataLength > mappedLength) { + memset(buf, 0, sizeof(buf)); + dataSRDOCopy = buf; + } + else { + dataSRDOCopy = dataSRDO[plain_inverted]; + } + + /* Set stream.dataOffset to zero, perform OD_IO.read() + * and store mappedLength back to stream.dataOffset */ + stream->dataOffset= 0; + OD_size_t countRd; + OD_IO->read(stream, dataSRDOCopy, ODdataLength, &countRd); + stream->dataOffset = mappedLength; + + /* swap multibyte data if big-endian */ +#ifdef CO_BIG_ENDIAN + if ((stream->attribute & ODA_MB) != 0) { + uint8_t *lo = dataSRDOCopy; + uint8_t *hi = dataSRDOCopy + ODdataLength - 1; + while (lo < hi) { + uint8_t swap = *lo; + *lo++ = *hi; + *hi-- = swap; + } + } #endif - if(data_ok){ - /* Copy data from Object dictionary. */ - for(i = 0; idataLength; i++){ - pSRDOdataByte_normal[i] = *(ppODdataByte_normal[i]); - pSRDOdataByte_inverted[i] = *(ppODdataByte_inverted[i]); + + /* If auxiliary buffer, copy it to the SRDO */ + if (ODdataLength > mappedLength) { + memcpy(dataSRDO[plain_inverted], buf, mappedLength); } - CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[0]); + dataSRDO[plain_inverted] += mappedLength; + } - SRDO->timer = CO_CONFIG_SRDO_MINIMUM_DELAY; + if (verifyLength > CO_SRDO_MAX_SIZE || verifyLength != SRDO->dataLength) { + SRDO->internalState = CO_SRDO_state_error_internal; /* should not happen */ } - else{ - SRDO->toogle = 1; - /* save state */ - if(SRDO->pFunctSignalSafe != NULL){ - SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe); + else { + bool_t data_ok = true; +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX + /* check data before sending (optional) */ + for (uint8_t i = 0; i < SRDO->dataLength; i++) { + if (~SRDO->CANtxBuff[0]->data[i] != SRDO->CANtxBuff[1]->data[i]) { + SRDO->internalState = CO_SRDO_state_error_txNotInverted; + data_ok = false; + break; + } + } +#endif + if (data_ok) { + if (CO_CANsend(SRDO->CANdevTx[0], SRDO->CANtxBuff[0]) == CO_ERROR_NO) { + SRDO->cycleTimer = CO_CONFIG_SRDO_MINIMUM_DELAY; + SRDO->internalState = CO_SRDO_state_communicationEstablished; + } + else { + SRDO->internalState = CO_SRDO_state_error_txFail; + } } } + } else { + if (CO_CANsend(SRDO->CANdevTx[1], SRDO->CANtxBuff[1]) == CO_ERROR_NO) { + SRDO->cycleTimer = SRDO->cycleTime_us - CO_CONFIG_SRDO_MINIMUM_DELAY; /* cycleTime_us is verified, result can't be <0 */ + } + else { + SRDO->internalState = CO_SRDO_state_error_txFail; + } } - SRDO->toogle = !SRDO->toogle; + SRDO->nextIsNormal = !SRDO->nextIsNormal; } #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT - if(timerNext_us != NULL){ - if(*timerNext_us > SRDO->timer){ - *timerNext_us = SRDO->timer; /* Schedule for next message timer */ + if (timerNext_us != NULL) { + if (*timerNext_us > SRDO->cycleTimer) { + *timerNext_us = SRDO->cycleTimer; /* Schedule for the next message timer */ } } #endif } - else if(SRDO->valid == CO_SRDO_RX){ - if(CO_FLAG_READ(SRDO->CANrxNew[SRDO->toogle])){ - - if(SRDO->toogle){ - int16_t i; - uint8_t* pSRDOdataByte_normal; - uint8_t* pSRDOdataByte_inverted; + else { /* CO_SRDO_RX */ + /* verify error from receive function */ + if (SRDO->rxSrdoShort) { + CO_errorReport(SRDO->em, CO_EM_RPDO_WRONG_LENGTH, CO_EMC_PDO_LENGTH, 0); + SRDO->internalState = CO_SRDO_state_error_rxShort; + } + else if (CO_FLAG_READ(SRDO->CANrxNew[SRDO->nextIsNormal ? 0 : 1])) { + /* normal message received ? */ + if (SRDO->nextIsNormal) { + SRDO->validationTimer = SRDO->validationTime_us; + SRDO->nextIsNormal = false; + } + /* inverted message received */ + else { + SRDO->cycleTimer = SRDO->validationTimer = SRDO->cycleTime_us; + SRDO->nextIsNormal = true; - uint8_t** ppODdataByte_normal; - uint8_t** ppODdataByte_inverted; + uint8_t *dataSRDO[2] = {&SRDO->CANrxData[0][0], &SRDO->CANrxData[1][0]}; bool_t data_ok = true; - pSRDOdataByte_normal = &SRDO->CANrxData[0][0]; - pSRDOdataByte_inverted = &SRDO->CANrxData[1][0]; - for(i = 0; idataLength; i++){ - uint8_t invert = (uint8_t)(~pSRDOdataByte_inverted[i]); - if(pSRDOdataByte_normal[i] != invert){ + /* Verify, if normal and inverted data matches properly */ + for (uint8_t i = 0; i < SRDO->dataLength; i++) { + if (~dataSRDO[0][i] != dataSRDO[1][i]) { data_ok = false; + SRDO->internalState = CO_SRDO_state_error_rxNotInverted; break; } } - if(data_ok){ - ppODdataByte_normal = &SRDO->mapPointer[0][0]; - ppODdataByte_inverted = &SRDO->mapPointer[1][0]; - /* Copy data to Object dictionary. If between the copy operation CANrxNew - * is set to true by receive thread, then copy the latest data again. */ + /* copy data from CAN messages into mapped data from Object Dictionary */ + if (data_ok) { + size_t verifyLength = 0; + for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) { + uint8_t plain_inverted = i % 2; + OD_IO_t *OD_IO = &SRDO->OD_IO[i]; + OD_stream_t *stream = &OD_IO->stream; + + /* get mappedLength from temporary storage */ + OD_size_t *dataOffset = &stream->dataOffset; + uint8_t mappedLength = (uint8_t) (*dataOffset); + + /* additional safety check */ + verifyLength += mappedLength; + if (verifyLength > CO_SRDO_MAX_SIZE) { + break; + } - for(i = 0; idataLength; i++){ - *(ppODdataByte_normal[i]) = pSRDOdataByte_normal[i]; - *(ppODdataByte_inverted[i]) = pSRDOdataByte_inverted[i]; - } - CO_FLAG_CLEAR(SRDO->CANrxNew[0]); - CO_FLAG_CLEAR(SRDO->CANrxNew[1]); -#if (CO_CONFIG_SRDO) & CO_CONFIG_RSRDO_CALLS_EXTENSION - if(SRDO->SDO->ODExtensions){ - int16_t i; - /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */ - const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0]; - CO_SDOserver_t *pSDO = SRDO->SDO; - - for(i=SRDO->mappedObjectsCount; i>0; i--){ - uint32_t map = *(pMap++); - uint16_t index = (uint16_t)(map>>16); - uint8_t subIndex = (uint8_t)(map>>8); - uint16_t entryNo = CO_OD_find(pSDO, index); - if ( entryNo != 0xFFFF ) - { - CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo]; - if( ext->pODFunc != NULL) - { - CO_ODF_arg_t ODF_arg; - memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t)); - ODF_arg.reading = false; - ODF_arg.index = index; - ODF_arg.subIndex = subIndex; - ODF_arg.object = ext->object; - ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex); - ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex); - ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); /* https://github.com/CANopenNode/CANopenNode/issues/100 */ - ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex); - ext->pODFunc(&ODF_arg); - } + /* length of OD variable may be larger than mappedLength */ + OD_size_t ODdataLength = stream->dataLength; + if (ODdataLength > CO_SRDO_MAX_SIZE) { + ODdataLength = CO_SRDO_MAX_SIZE; + } + /* Prepare data for writing into OD variable. If mappedLength + * is smaller than ODdataLength, then use auxiliary buffer */ + uint8_t buf[CO_SRDO_MAX_SIZE]; + uint8_t *dataOD; + if (ODdataLength > mappedLength) { + memset(buf, 0, sizeof(buf)); + memcpy(buf, dataSRDO[plain_inverted], mappedLength); + dataOD = buf; + } + else { + dataOD = dataSRDO[plain_inverted]; + } + + /* swap multibyte data if big-endian */ +#ifdef CO_BIG_ENDIAN + if ((stream->attribute & ODA_MB) != 0) { + uint8_t *lo = dataOD; + uint8_t *hi = dataOD + ODdataLength - 1; + while (lo < hi) { + uint8_t swap = *lo; + *lo++ = *hi; + *hi-- = swap; } } - } #endif - } - else{ - CO_FLAG_CLEAR(SRDO->CANrxNew[0]); - CO_FLAG_CLEAR(SRDO->CANrxNew[1]); - /* save state */ - if(SRDO->pFunctSignalSafe != NULL){ - SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe); + + /* Set stream.dataOffset to zero, perform OD_IO.write() + * and store mappedLength back to stream.dataOffset */ + *dataOffset = 0; + OD_size_t countWritten; + OD_IO->write(&OD_IO->stream, dataOD, + ODdataLength, &countWritten); + *dataOffset = mappedLength; + + dataSRDO[plain_inverted] += mappedLength; + } /* for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) */ + + /* safety check, this should not happen */ + if (verifyLength > CO_SRDO_MAX_SIZE || verifyLength != SRDO->dataLength) { + SRDO->internalState = CO_SRDO_state_error_internal; } - } + else { + SRDO->internalState = CO_SRDO_state_communicationEstablished; + } + } /* if (data_ok) { */ - SRDO->timer = (uint32_t)SRDO->CommPar_safetyCycleTime * 1000U; - } - else{ - SRDO->timer = (uint32_t)SRDO->CommPar_safetyRelatedValidationTime * 1000U; - } - SRDO->toogle = (uint8_t)(!SRDO->toogle); + CO_FLAG_CLEAR(SRDO->CANrxNew[0]); + CO_FLAG_CLEAR(SRDO->CANrxNew[1]); + } /* inverted message received */ } - if(SRDO->timer == 0U){ - SRDO->toogle = 0; - SRDO->timer = (uint32_t)SRDO->CommPar_safetyRelatedValidationTime * 1000U; - CO_FLAG_CLEAR(SRDO->CANrxNew[0]); - CO_FLAG_CLEAR(SRDO->CANrxNew[1]); - /* save state */ - if(SRDO->pFunctSignalSafe != NULL){ - SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe); + /* verify timeouts */ + if (SRDO->cycleTimer == 0U) { + SRDO->internalState = CO_SRDO_state_error_rxTimeoutSCT; + } + else if (SRDO->validationTimer == 0U) { + SRDO->internalState = CO_SRDO_state_error_rxTimeoutSRVT; + } + else { + /* MISRA C 2004 14.10 */ + } +#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT + if (timerNext_us != NULL) { + if (*timerNext_us > SRDO->cycleTimer) { + *timerNext_us = SRDO->cycleTimer; /* Schedule for the next message timer */ + } + if (*timerNext_us > SRDO->validationTimer) { + *timerNext_us = SRDO->validationTimer; /* Schedule for the next message timer */ } } - } - else { /* MISRA C 2004 14.10 */ } - } - else{ - SRDO->valid = CO_SRDO_INVALID; +#endif + } /* CO_SRDO_RX */ + } /* if (NMTisOperational && ... */ + else { CO_FLAG_CLEAR(SRDO->CANrxNew[0]); CO_FLAG_CLEAR(SRDO->CANrxNew[1]); + if (!SRDO->SRDOGuard->configurationValid) { + SRDO->internalState = CO_SRDO_state_error_configuration; + } + else if (!NMTisOperational) { + SRDO->internalState = CO_SRDO_state_nmtNotOperational; + } + else if (SRDO->informationDirection == CO_SRDO_INVALID) { + SRDO->internalState = CO_SRDO_state_deleted; + } + else { + /* keep internalState unchanged */ + /* MISRA C 2004 14.10 */ + } } + + SRDO->NMTisOperationalPrevious = SRDO->SRDOGuard->NMTisOperational = NMTisOperational; + + return SRDO->internalState; } #endif /* (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE */ diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 810ca88b..e24bcd6c 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -4,7 +4,9 @@ * @file CO_SRDO.h * @ingroup CO_SRDO * @author Robert Grüning - * @copyright 2020 - 2020 Robert Grüning + * @copyright 2020 Robert Grüning + * @copyright 2024 temi54c1l8@github + * @copyright 2024 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is . @@ -26,8 +28,8 @@ #ifndef CO_SRDO_H #define CO_SRDO_H -#include "301/CO_ODinterface.h" #include "301/CO_Emergency.h" +#include "301/CO_ODinterface.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_SRDO @@ -39,21 +41,42 @@ #if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN +#warning SRDO is draft version and is not fully tested! + #ifdef __cplusplus extern "C" { #endif /** * @defgroup CO_SRDO SRDO - * CANopen Safety Related Data Object protocol. + * CANopen Safety Related Data Object protocol * * @ingroup CO_CANopen_304 * @{ - * The functionality is very similar to that of the PDOs. - * The main differences is every message is send and received twice. + * Safety Related Data Object protocol is specified by standard EN 50325-5:2010 (formerly CiA304). + * Its functionality is very similar to that of the PDOs. The main differences is every message is send and received twice. * The second message must be bitwise inverted. The delay between the two messages and between each message pair is monitored. * The distinction between sending and receiving SRDO is made at runtime (for PDO it is compile time). * If the security protocol is used, at least one SRDO is mandatory. + * + * If there is erroneous structure of OD entries for SRDO parameters, then @CO_SRDO_init() function + * returns error and CANopen device doesn't work. It is necessary to repair Object Dictionary and reprogram the device. + * + * If there are erroneous values inside SRDO parameters, then Emergency message CO_EM_SRDO_CONFIGURATION is sent. + * Info code (32bit) contains OD index, subindex and additional byte, which helps to determine erroneous OD object. + * + * SRDO configuration consists of one @CO_SRDO_init_start(), @CO_SRDO_init() for each SRDO and one @CO_SRDO_init_end(). + * These may be called in CANopen initialization section after all other CANopen objects are initialized. + * If SRDO OD parameters are edited (in NMT pre-operational state), NMT communication reset is necessary. + * Alternatively SRDO configuration may be executed just after transition to NMT operational state. + * + * @CO_SRDO_process() must be executed cyclically, similar as PDO processing. Function is fast, no time consuming tasks. + * Function returns @CO_SRDO_state_t value, which may be used to determine working-state or safe-state of safety related + * device. If return values from all SRDO objects are >= CO_SRDO_state_communicationEstablished, then working state is allowed. + * Otherwise SR device must be in safe state. + * + * Requirement for mapped objects: + * - @OD_attributes_t must have set bit ODA_RSRDO or ODA_RSRDO or ODA_TRSRDO (by CANopenEditor). */ /** Maximum size of SRDO message, 8 for standard CAN */ @@ -61,10 +84,10 @@ extern "C" { #define CO_SRDO_MAX_SIZE 8U #endif -/** Maximum number of entries, which can be mapped to PDO, 8 for standard CAN, - * may be less to preserve RAM usage */ +/** Maximum number of entries, which can be mapped to SRDO, 2*8 for standard + * CAN, may be less to preserve RAM usage. Must be multiple of 2. */ #ifndef CO_SRDO_MAX_MAPPED_ENTRIES -#define CO_SRDO_MAX_MAPPED_ENTRIES 8U +#define CO_SRDO_MAX_MAPPED_ENTRIES 16U #endif #ifndef CO_SRDO_OWN_TYPES @@ -72,108 +95,133 @@ extern "C" { typedef uint8_t CO_SRDO_size_t; #endif +/** + * SRDO internal state + */ +typedef enum { + CO_SRDO_state_error_internal = -10, /**< internal software error */ + CO_SRDO_state_error_configuration = -9, /**< error in parameters, emergency message was sent */ + CO_SRDO_state_error_txNotInverted = -6, /**< Transmitting SRDO messages was not inverted */ + CO_SRDO_state_error_txFail = -5, /**< SRDO CAN message transmission failed */ + CO_SRDO_state_error_rxTimeoutSRVT = -4, /**< SRDO message didn't receive inside SRVT time */ + CO_SRDO_state_error_rxTimeoutSCT = -3, /**< SRDO inverted message didn't receive inside SCT time */ + CO_SRDO_state_error_rxNotInverted = -2, /**< Received SRDO messages was not inverted */ + CO_SRDO_state_error_rxShort = -1, /**< Received SRDO message is too short */ + CO_SRDO_state_unknown = 0, /**< unknown state, set by @CO_SRDO_init */ + CO_SRDO_state_nmtNotOperational = 1, /**< Internal NMT operating state is not NMT operational */ + CO_SRDO_state_initializing = 2, /**< Just entered NMT operational state, SRDO message not yet received or transmitted */ + CO_SRDO_state_communicationEstablished = 3, /**< SRDO communication established, fully functional */ + CO_SRDO_state_deleted = 10 /**< informationDirection for this SRDO is set to 0 */ +} CO_SRDO_state_t; /** - * Gurad Object for SRDO - * monitors: + * Guard Object for SRDO. + * + * Guard object monitors all SRDO objects for: * - access to CRC objects * - access configuration valid flag * - change in operation state */ -typedef struct{ - bool operatingState; - uint8_t configurationValid; - OD_entry_t *SRDO_CRC; - uint8_t checkCRC; /**< specifies whether a CRC check should be performed */ +typedef struct { + /** True if NMT operating state is operational */ + bool_t NMTisOperational; + /** True if all SRDO objects are properly configured. Set after successful + * finish of all @CO_SRDO_init() functions. Cleared on configuration change. */ + bool_t configurationValid; + /** Private helper variable set on the start of SRDO configuration */ + bool_t _configurationValid; + /** Object for input / output on the OD variable 13FE:00. Configuration + * of any of the the SRDO parameters will write 0 to that variable. */ + OD_IO_t OD_IO_configurationValid; /** Extension for OD object */ OD_extension_t OD_13FE_extension; + /** Extension for OD object */ OD_extension_t OD_13FF_extension; -}CO_SRDOGuard_t; +} CO_SRDOGuard_t; /** * SRDO object. */ -typedef struct{ - CO_EM_t *em; /**< From CO_SRDO_init() */ - CO_SRDOGuard_t *SRDOGuard; /**< From CO_SRDO_init() */ - OD_t *OD; - uint8_t SRDO_Index; /**< From CO_SRDO_init() */ - /** Number of mapped objects in SRDO */ - uint8_t mappedObjectsCount; - /** Pointers to 2*8 data objects, where SRDO will be copied */ - uint8_t *mapPointer[2][CO_SRDO_MAX_SIZE]; +typedef struct { + CO_SRDOGuard_t* SRDOGuard; /**< From CO_SRDO_init() */ + CO_EM_t* em; /**< From CO_SRDO_init() */ + uint16_t defaultCOB_ID; /**< From CO_SRDO_init() */ + uint8_t nodeId; /**< From CO_SRDO_init() */ + CO_CANmodule_t* CANdevTx[2];/**< From CO_SRDO_init() */ + /** Internal state of this SRDO. */ + CO_SRDO_state_t internalState; + /** Copy of variable, internal usage. */ + bool_t NMTisOperationalPrevious; + /** 0 - SRDO is disabled; 1 - SRDO is producer (tx); 2 - SRDO is consumer (rx) */ + uint8_t informationDirection; + /** Safety Cycle Time from object dictionary translated to microseconds */ + uint32_t cycleTime_us; + /** Safety related validation time from object dictionary translated to microseconds */ + uint32_t validationTime_us; + /** cycle timer variable in microseconds */ + uint32_t cycleTimer; + /** validation timer variable in microseconds */ + uint32_t validationTimer; /** Data length of the received SRDO message. Calculated from mapping */ - CO_SRDO_size_t dataLength; - uint8_t nodeId; /**< From CO_SRDO_init() */ - uint16_t defaultCOB_ID[2]; /**< From CO_SRDO_init() */ - /** 0 - invalid, 1 - tx, 2 - rx */ - uint8_t valid; - OD_entry_t *SRDOCommPar; /**< From CO_SRDO_init() */ - OD_entry_t *SRDOMapPar; /**< From CO_SRDO_init() */ - CO_CANmodule_t *CANdevRx; /**< From CO_SRDO_init() */ - CO_CANmodule_t *CANdevTx; /**< From CO_SRDO_init() */ - CO_CANtx_t *CANtxBuff[2]; /**< CAN transmit buffer inside CANdevTx */ - uint16_t CANdevRxIdx[2]; /**< From CO_SRDO_init() */ - uint16_t CANdevTxIdx[2]; /**< From CO_SRDO_init() */ - uint8_t toogle; /**< defines the current state */ - uint32_t timer; /**< transmit timer and receive timeout */ + CO_SRDO_size_t dataLength; + /** Number of mapped objects in SRDO */ + uint8_t mappedObjectsCount; + /** Object dictionary interface for all mapped entries. OD_IO.dataOffset has + * special usage with SRDO. It stores information about mappedLength of + * the variable. mappedLength can be less or equal to the OD_IO.dataLength. + * mappedLength greater than OD_IO.dataLength indicates erroneous mapping. + * OD_IO.dataOffset is set to 0 before read/write function call and after + * the call OD_IO.dataOffset is set back to mappedLength. */ + OD_IO_t OD_IO[CO_SRDO_MAX_MAPPED_ENTRIES]; + /** CAN transmit buffers inside CANdevTx */ + CO_CANtx_t* CANtxBuff[2]; /** Variable indicates, if new SRDO message received from CAN bus. */ - volatile void *CANrxNew[2]; - /** 2*8 data bytes of the received message. */ - uint8_t CANrxData[2][8]; - /** From CO_SRDO_initCallbackEnterSafeState() or NULL */ - void (*pFunctSignalSafe)(void *object); - /** From CO_SRDO_initCallbackEnterSafeState() or NULL */ - void *functSignalObjectSafe; + volatile void* CANrxNew[2]; + /** true, if received SRDO is too short */ + bool_t rxSrdoShort; + /** two buffers of data bytes for the received message. */ + uint8_t CANrxData[2][CO_SRDO_MAX_SIZE]; + /** If true, next processed SRDO message is normal (not inverted) */ + bool_t nextIsNormal; + /** Extension for OD object */ + OD_extension_t OD_communicationParam_ext; + /** Extension for OD object */ + OD_extension_t OD_mappingParam_extension; #if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** From CO_SRDO_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void* object); /** From CO_SRDO_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void* functSignalObjectPre; #endif - /** Extension for OD object */ - OD_extension_t OD_communicationParam_ext; - OD_extension_t OD_mappingParam_extension; - - uint8_t CommPar_informationDirection; - uint16_t CommPar_safetyCycleTime; - uint8_t CommPar_safetyRelatedValidationTime; - uint8_t CommPar_transmissionType; - uint32_t CommPar_COB_ID1_normal; - uint32_t CommPar_COB_ID2_inverted; -}CO_SRDO_t; +} CO_SRDO_t; /** * Initialize SRDOGuard object. * - * Function must be called in the communication reset section. + * Function must be called in the communication reset section before @CO_SRDO_init functions. * * @param SRDOGuard This object will be initialized. - * @param SDO SDO object. - * @param operatingState Pointer to variable indicating CANopen device NMT internal state. - * @param configurationValid Pointer to variable with the SR valid flag - * @param idx_SRDOvalid Index in Object Dictionary - * @param idx_SRDOcrc Index in Object Dictionary + * @param OD_13FE_configurationValid Pointer to _Configuration valid_ variable from Object + * dictionary (index 0x13FE). + * @param OD_13FF_safetyConfigurationSignature Pointer to _Safety configuration signature_ variable + * from Object dictionary (index 0x13FF). + * @param [out] errInfo Additional information in case of error, may be NULL. * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_SRDOGuard_init( - CO_SRDOGuard_t *SRDOGuard, - OD_entry_t *OD_13FE_SRDOValid, - OD_entry_t *OD_13FF_SRDOCRC, - uint32_t *errInfo); +CO_ReturnError_t CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, + OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo); /** - * Process operation and valid state changes. + * Finalize SRDOGuard object. * - * @param SRDOGuard This object. - * @return uint8_t command for CO_SRDO_process(). - * - bit 0 entered operational - * - bit 1 validate checksum + * Function must be called in the communication reset section after @CO_SRDO_init functions. + * + * @param SRDOGuard This object will be finalized. */ -uint8_t CO_SRDOGuard_process( - CO_SRDOGuard_t *SRDOGuard, - bool_t NMTisOperational); +static inline void CO_SRDO_init_end(CO_SRDOGuard_t* SRDOGuard) { + SRDOGuard->configurationValid = SRDOGuard->_configurationValid; +} /** * Initialize SRDO object. @@ -181,44 +229,37 @@ uint8_t CO_SRDOGuard_process( * Function must be called in the communication reset section. * * @param SRDO This object will be initialized. + * @param SRDO_Index OD index of this SRDO, 0 for the first. * @param SRDOGuard SRDOGuard object. + * @param OD CANopen Object Dictionary * @param em Emergency object. - * @param SDO SDO object. * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. - * @param defaultCOB_ID Default COB ID for this SRDO (without NodeId). - * @param SRDOCommPar Pointer to _SRDO communication parameter_ record from Object + * @param defaultCOB_ID Default COB ID for this SRDO for plain data (without NodeId). + * @param OD_130x_SRDOCommPar Pointer to _SRDO communication parameter_ record from Object * dictionary (index 0x1301+). - * @param SRDOMapPar Pointer to _SRDO mapping parameter_ record from Object + * @param OD_138x_SRDOMapPar Pointer to _SRDO mapping parameter_ record from Object * dictionary (index 0x1381+). - * @param checksum - * @param idx_SRDOCommPar Index in Object Dictionary - * @param idx_SRDOMapPar Index in Object Dictionary + * @param OD_13FE_configurationValid Pointer to _Configuration valid_ variable from Object + * dictionary (index 0x13FE). + * @param OD_13FF_safetyConfigurationSignature Pointer to _Safety configuration signature_ variable + * from Object dictionary (index 0x13FF). * @param CANdevRx CAN device used for SRDO reception. * @param CANdevRxIdxNormal Index of receive buffer in the above CAN device. * @param CANdevRxIdxInverted Index of receive buffer in the above CAN device. * @param CANdevTx CAN device used for SRDO transmission. * @param CANdevTxIdxNormal Index of transmit buffer in the above CAN device. * @param CANdevTxIdxInverted Index of transmit buffer in the above CAN device. + * @param [out] errInfo Additional information in case of error, may be NULL. * - * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OD_PARAMETERS. */ -CO_ReturnError_t CO_SRDO_init( - CO_SRDO_t *SRDO, - uint8_t SRDO_Index, - CO_SRDOGuard_t *SRDOGuard, - OD_t *OD, - CO_EM_t *em, - uint8_t nodeId, - uint16_t defaultCOB_ID, - OD_entry_t *SRDOCommPar, - OD_entry_t *SRDOMapPar, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdxNormal, - uint16_t CANdevRxIdxInverted, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdxNormal, - uint16_t CANdevTxIdxInverted, - uint32_t *errInfo); +CO_ReturnError_t CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_t* OD, CO_EM_t* em, + uint8_t nodeId, uint16_t defaultCOB_ID, OD_entry_t* OD_130x_SRDOCommPar, + OD_entry_t* OD_138x_SRDOMapPar, OD_entry_t* OD_13FE_configurationValid, + OD_entry_t* OD_13FF_safetyConfigurationSignature, CO_CANmodule_t* CANdevRxNormal, + CO_CANmodule_t* CANdevRxInverted, uint16_t CANdevRxIdxNormal, uint16_t CANdevRxIdxInverted, + CO_CANmodule_t* CANdevTxNormal, CO_CANmodule_t* CANdevTxInverted, + uint16_t CANdevTxIdxNormal, uint16_t CANdevTxIdxInverted, uint32_t* errInfo); #if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN /** @@ -232,58 +273,32 @@ CO_ReturnError_t CO_SRDO_init( * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_SRDO_initCallbackPre( - CO_SRDO_t *SRDO, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalPre)(void* object)); #endif -/** - * Initialize SRDO callback function. - * - * Function initializes optional callback function, that is called when SRDO enters a safe state. - * This happens when a timeout is reached or the data is inconsistent. The safe state itself is not further defined. - * One measure, for example, would be to go back to the pre-operational state - * Callback is called from CO_SRDO_process(). - * - * @param SRDO This object. - * @param object Pointer to object, which will be passed to pFunctSignalSafe(). Can be NULL - * @param pFunctSignalSafe Pointer to the callback function. Not called if NULL. - */ -void CO_SRDO_initCallbackEnterSafeState( - CO_SRDO_t *SRDO, - void *object, - void (*pFunctSignalSafe)(void *object)); - - /** * Send SRDO on event * - * Sends SRDO before the next refresh timer tiggers. The message itself is send in CO_SRDO_process(). + * Sends SRDO before the next refresh timer tiggers. The message itself is send + * in @CO_SRDO_process(). Note that RTOS have to trigger its processing quickly. * After the transmission the timer is reset to the full refresh time. * * @param SRDO This object. * @return CO_ReturnError_t CO_ERROR_NO if request is granted */ -CO_ReturnError_t CO_SRDO_requestSend( - CO_SRDO_t *SRDO); +CO_ReturnError_t CO_SRDO_requestSend(CO_SRDO_t* SRDO); /** - * Process transmitting/receiving SRDO messages. - * - * This function verifies the checksum on demand. - * This function also configures the SRDO on operation state change to operational + * Process transmitting/receiving individual SRDO message. * * @param SRDO This object. - * @param commands result from CO_SRDOGuard_process(). * @param timeDifference_us Time difference from previous function call in [microseconds]. - * @param [out] timerNext_us info to OS. + * @param [out] timerNext_us info to OS, may be null. + * @param NMTisOperational True if this node is in NMT_OPERATIONAL state. + * + * @return CO_SRDO_state_t internal state */ -void CO_SRDO_process( - CO_SRDO_t *SRDO, - uint8_t commands, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +CO_SRDO_state_t CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext_us, bool_t NMTisOperational); /** @} */ /* CO_SRDO */ diff --git a/CANopen.c b/CANopen.c index b2957273..3cebb054 100644 --- a/CANopen.c +++ b/CANopen.c @@ -273,11 +273,11 @@ * number of them. Indexes are sorted in a way, that objects with highest * priority of the CAN identifier are listed first. */ #define CO_RX_IDX_NMT_SLV 0 -#define CO_RX_IDX_SYNC (CO_RX_IDX_NMT_SLV + CO_RX_CNT_NMT_SLV) +#define CO_RX_IDX_GFC (CO_RX_IDX_NMT_SLV + CO_RX_CNT_NMT_SLV) +#define CO_RX_IDX_SYNC (CO_RX_IDX_GFC + CO_RX_CNT_GFC) #define CO_RX_IDX_EM_CONS (CO_RX_IDX_SYNC + CO_RX_CNT_SYNC) #define CO_RX_IDX_TIME (CO_RX_IDX_EM_CONS + CO_RX_CNT_EM_CONS) -#define CO_RX_IDX_GFC (CO_RX_IDX_TIME + CO_RX_CNT_TIME) -#define CO_RX_IDX_SRDO (CO_RX_IDX_GFC + CO_RX_CNT_GFC) +#define CO_RX_IDX_SRDO (CO_RX_IDX_TIME + CO_RX_CNT_TIME) #define CO_RX_IDX_RPDO (CO_RX_IDX_SRDO + CO_RX_CNT_SRDO * 2) #define CO_RX_IDX_SDO_SRV (CO_RX_IDX_RPDO + CO_RX_CNT_RPDO) #define CO_RX_IDX_SDO_CLI (CO_RX_IDX_SDO_SRV + CO_RX_CNT_SDO_SRV) @@ -289,11 +289,11 @@ #define CO_CNT_ALL_RX_MSGS (CO_RX_IDX_LSS_MST + CO_RX_CNT_LSS_MST) #define CO_TX_IDX_NMT_MST 0 -#define CO_TX_IDX_SYNC (CO_TX_IDX_NMT_MST + CO_TX_CNT_NMT_MST) +#define CO_TX_IDX_GFC (CO_TX_IDX_NMT_MST + CO_TX_CNT_NMT_MST) +#define CO_TX_IDX_SYNC (CO_TX_IDX_GFC + CO_TX_CNT_GFC) #define CO_TX_IDX_EM_PROD (CO_TX_IDX_SYNC + CO_TX_CNT_SYNC) #define CO_TX_IDX_TIME (CO_TX_IDX_EM_PROD + CO_TX_CNT_EM_PROD) -#define CO_TX_IDX_GFC (CO_TX_IDX_TIME + CO_TX_CNT_TIME) -#define CO_TX_IDX_SRDO (CO_TX_IDX_GFC + CO_TX_CNT_GFC) +#define CO_TX_IDX_SRDO (CO_TX_IDX_TIME + CO_TX_CNT_TIME) #define CO_TX_IDX_TPDO (CO_TX_IDX_SRDO + CO_TX_CNT_SRDO * 2) #define CO_TX_IDX_SDO_SRV (CO_TX_IDX_TPDO + CO_TX_CNT_TPDO) #define CO_TX_IDX_SDO_CLI (CO_TX_IDX_SDO_SRV + CO_TX_CNT_SDO_SRV) @@ -555,6 +555,9 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { * highest priority of the CAN identifier are listed first. */ int16_t idxRx = 0; co->RX_IDX_NMT_SLV = idxRx; idxRx += RX_CNT_NMT_SLV; +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + co->RX_IDX_GFC = idxRx; idxRx += RX_CNT_GFC; +#endif #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE co->RX_IDX_SYNC = idxRx; idxRx += RX_CNT_SYNC; #endif @@ -562,9 +565,6 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE co->RX_IDX_TIME = idxRx; idxRx += RX_CNT_TIME; #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE - co->RX_IDX_GFC = idxRx; idxRx += RX_CNT_GFC; -#endif #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE co->RX_IDX_SRDO = idxRx; idxRx += RX_CNT_SRDO * 2; #endif @@ -594,6 +594,9 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { int16_t idxTx = 0; co->TX_IDX_NMT_MST = idxTx; idxTx += TX_CNT_NMT_MST; +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + co->TX_IDX_GFC = idxTx; idxTx += TX_CNT_GFC; +#endif #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE co->TX_IDX_SYNC = idxTx; idxTx += TX_CNT_SYNC; #endif @@ -601,9 +604,6 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE co->TX_IDX_TIME = idxTx; idxTx += TX_CNT_TIME; #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE - co->TX_IDX_GFC = idxTx; idxTx += TX_CNT_GFC; -#endif #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE co->TX_IDX_SRDO = idxTx; idxTx += TX_CNT_SRDO * 2; #endif @@ -1170,54 +1170,6 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE - if (CO_GET_CNT(GFC) == 1) { - err = CO_GFC_init(co->GFC, - &OD_globalFailSafeCommandParameter, - co->CANmodule, - CO_GET_CO(RX_IDX_GFC), - CO_CAN_ID_GFC, - co->CANmodule, - CO_GET_CO(TX_IDX_GFC), - CO_CAN_ID_GFC); - if (err) { return err; } - } -#endif - -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE - if (CO_GET_CNT(SRDO) > 0) { - err = CO_SRDOGuard_init(co->SRDOGuard, - OD_GET(H13FE, OD_H13FE_SRDO_VALID), - OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), - errInfo); - if (err) { return err; } - - OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); - OD_entry_t *SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); - for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { - uint16_t CANdevRxIdx = CO_GET_CO(RX_IDX_SRDO) + 2 * i; - uint16_t CANdevTxIdx = CO_GET_CO(TX_IDX_SRDO) + 2 * i; - - err = CO_SRDO_init(&co->SRDO[i], i, - co->SRDOGuard, - od, - em, - nodeId, - ((i == 0) ? CO_CAN_ID_SRDO_1 : 0), - SRDOcomm++, - SRDOmap++, - co->CANmodule, - CANdevRxIdx, - CANdevRxIdx + 1, - co->CANmodule, - CANdevTxIdx, - CANdevTxIdx + 1, - errInfo); - if (err) { return err; } - } - } -#endif - #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER if (CO_GET_CNT(LSS_MST) == 1) { err = CO_LSSmaster_init(co->LSSmaster, @@ -1369,6 +1321,84 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, } +/******************************************************************************/ +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) +CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, + CO_EM_t *em, + OD_t *od, + uint8_t nodeId, + uint32_t *errInfo) +{ + if (co == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + if (nodeId < 1 || nodeId > 127 || co->nodeIdUnconfigured) { + return (co->nodeIdUnconfigured) + ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; + } + + +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE + if (CO_GET_CNT(GFC) == 1) { + CO_ReturnError_t err; + err = CO_GFC_init(co->GFC, + OD_GET(H1300, OD_H1300_GFC_PARAM), + co->CANmodule, + CO_GET_CO(RX_IDX_GFC), + CO_CAN_ID_GFC, + co->CANmodule, + CO_GET_CO(TX_IDX_GFC), + CO_CAN_ID_GFC); + if (err) { return err; } + } +#endif + +#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE + if (CO_GET_CNT(SRDO) > 0) { + CO_ReturnError_t err; + err = CO_SRDO_init_start(co->SRDOGuard, + OD_GET(H13FE, OD_H13FE_SRDO_VALID), + OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), + errInfo); + if (err) { return err; } + + OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); + OD_entry_t *SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); + for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { + uint16_t CANdevRxIdx = CO_GET_CO(RX_IDX_SRDO) + 2 * i; + uint16_t CANdevTxIdx = CO_GET_CO(TX_IDX_SRDO) + 2 * i; + + err = CO_SRDO_init(&co->SRDO[i], + i, + co->SRDOGuard, + od, + em, + nodeId, + ((i == 0) ? CO_CAN_ID_SRDO_1 : 0), + SRDOcomm++, + SRDOmap++, + OD_GET(H13FE, OD_H13FE_SRDO_VALID), + OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), + co->CANmodule, + co->CANmodule, + CANdevRxIdx, + CANdevRxIdx + 1, + co->CANmodule, + co->CANmodule, + CANdevTxIdx, + CANdevTxIdx + 1, + errInfo); + if (err) { return err; } + } + + CO_SRDO_init_end(co->SRDOGuard); + } +#endif + + return CO_ERROR_NO; +} +#endif + /******************************************************************************/ CO_NMT_reset_cmd_t CO_process(CO_t *co, bool_t enableGateway, @@ -1593,25 +1623,30 @@ void CO_process_TPDO(CO_t *co, /******************************************************************************/ #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE -void CO_process_SRDO(CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us) +CO_SRDO_state_t CO_process_SRDO(CO_t *co, + uint32_t timeDifference_us, + uint32_t *timerNext_us) { if (co->nodeIdUnconfigured) { - return; + return CO_SRDO_state_unknown; } - + bool_t NMTisOperational = CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; - uint8_t firstOperational = CO_SRDOGuard_process(co->SRDOGuard, - NMTisOperational); + + CO_SRDO_state_t lowestState = CO_SRDO_state_deleted; for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { - CO_SRDO_process(&co->SRDO[i], - firstOperational, - timeDifference_us, - timerNext_us); + CO_SRDO_state_t state = CO_SRDO_process(&co->SRDO[i], + timeDifference_us, + timerNext_us, + NMTisOperational); + if (state < lowestState) { + state = lowestState; + } } + + return lowestState; } #endif diff --git a/CANopen.h b/CANopen.h index a1f8f146..5930b79b 100644 --- a/CANopen.h +++ b/CANopen.h @@ -261,8 +261,8 @@ typedef struct { uint8_t CNT_SRDO; OD_entry_t *ENTRY_H1301; /**< OD entry for @ref CO_SRDO_init() */ OD_entry_t *ENTRY_H1381; /**< OD entry for @ref CO_SRDO_init() */ - OD_entry_t *ENTRY_H13FE; /**< OD entry for @ref CO_SRDOGuard_init() */ - OD_entry_t *ENTRY_H13FF; /**< OD entry for @ref CO_SRDOGuard_init() */ + OD_entry_t *ENTRY_H13FE; /**< OD entry for @ref CO_SRDO_init() */ + OD_entry_t *ENTRY_H13FF; /**< OD entry for @ref CO_SRDO_init() */ /** Number of LSSslave objects, 0 or 1 (CANrx + CANtx). */ uint8_t CNT_LSS_SLV; /** Number of LSSmaster objects, 0 or 1 (CANrx + CANtx). */ @@ -393,8 +393,8 @@ typedef struct { #endif #endif #if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN - /** SRDO object, initialised by @ref CO_SRDOGuard_init(), single SRDOGuard - * object is included inside all SRDO objects */ + /** SRDO guard object, initialised by @ref CO_SRDO_init_start(), single + * SRDOGuard object is included inside all SRDO objects */ CO_SRDOGuard_t *SRDOGuard; /** SRDO objects, initialised by @ref CO_SRDO_init() */ CO_SRDO_t *SRDO; @@ -577,6 +577,34 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, uint32_t *errInfo); + + +/** + * Initialize Safety related Data Objects. + * + * Function must be called in the end of communication reset section after all + * CANopen and application initialization, otherwise some OD variables wont be + * mapped into SRDO correctly. + * + * @param co CANopen object. + * @param em Emergency object, which is used inside PDO objects for error + * reporting. + * @param od CANopen Object dictionary + * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). If + * unconfigured, then PDO will not be initialized nor processed. + * @param [out] errInfo Additional information in case of error, may be NULL. + * + * @return CO_ERROR_NO in case of success. + */ +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) +CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, + CO_EM_t *em, + OD_t *od, + uint8_t nodeId, + uint32_t *errInfo); +#endif + + /** * Process CANopen objects. * @@ -682,10 +710,12 @@ void CO_process_TPDO(CO_t *co, * @param timeDifference_us Time difference from previous function call in * microseconds. * @param [out] timerNext_us info to OS - see CO_process(). + * + * @return @CO_SRDO_state_t lowest state of the SRDO objects. */ -void CO_process_SRDO(CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +CO_SRDO_state_t CO_process_SRDO(CO_t *co, + uint32_t timeDifference_us, + uint32_t *timerNext_us); #endif /** @} */ /* CO_CANopen */ diff --git a/README.md b/README.md index 157bb2e0..44a47bd6 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ File structure - **crc16-ccitt.h/.c** - Calculation of CRC 16 CCITT polynomial. - **303/** - CANopen Recommendation - **CO_LEDs.h/.c** - CANopen LED Indicators - - **304/** - CANopen Safety (Implemented only in v1.3, not updated for the latest version). + - **304/** - CANopen Safety Related Data Object, as specified by EN 50325-5:2010 - **CO_SRDO.h/.c** - CANopen Safety-relevant Data Object protocol. - **CO_GFC.h/.c** - CANopen Global Failsafe Command (producer and consumer). - **305/** - CANopen layer setting services (LSS) and protocols. From 359cda28e885d909a3e5bc8a1f3ccf464613eed6 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 3 Jun 2024 10:24:37 +0200 Subject: [PATCH 248/520] Fixed out of memory !!! --- 304/CO_SRDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 18bdeb31..f820fb25 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -445,7 +445,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } else { for (uint8_t i = 1; i <= CO_SRDO_MAX_MAPPED_ENTRIES; i++) { - if (OD_get_u32(OD_138x_SRDOMapPar, i, &mapping[i], true) != ODR_OK) { + if (OD_get_u32(OD_138x_SRDOMapPar, i, &mapping[i-1], true) != ODR_OK) { err = ERR_INFO(0x1381 + SRDO_Index, i, 1); break; } From aa119f5ca222faeaefeb0d91851838f3d5db3996 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 3 Jun 2024 10:26:03 +0200 Subject: [PATCH 249/520] Fixed control verifyLength with CO_SRDO_MAX_SIZE divided in two for straight and inverted data --- 304/CO_SRDO.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index f820fb25..ab8807e4 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -717,7 +717,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext if (SRDO->cycleTimer == 0U) { if (SRDO->nextIsNormal) { uint8_t *dataSRDO[2] = {&SRDO->CANtxBuff[0]->data[0], &SRDO->CANtxBuff[1]->data[0]}; - size_t verifyLength = 0; + size_t verifyLength[2] = { 0, 0 }; /* copy mapped data from Object Dictionary into CAN buffers */ for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) { @@ -729,8 +729,8 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext uint8_t mappedLength = (uint8_t) stream->dataOffset; /* additional safety check */ - verifyLength += mappedLength; - if (verifyLength > CO_SRDO_MAX_SIZE) { + verifyLength[plain_inverted] += mappedLength; + if (verifyLength[plain_inverted] > CO_SRDO_MAX_SIZE) { break; } @@ -778,7 +778,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext dataSRDO[plain_inverted] += mappedLength; } - if (verifyLength > CO_SRDO_MAX_SIZE || verifyLength != SRDO->dataLength) { + if (verifyLength[0]!=verifyLength[1] || verifyLength[0] > CO_SRDO_MAX_SIZE || verifyLength[0] != SRDO->dataLength) { SRDO->internalState = CO_SRDO_state_error_internal; /* should not happen */ } else { @@ -852,7 +852,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* copy data from CAN messages into mapped data from Object Dictionary */ if (data_ok) { - size_t verifyLength = 0; + size_t verifyLength[2] = { 0, 0 }; for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) { uint8_t plain_inverted = i % 2; OD_IO_t *OD_IO = &SRDO->OD_IO[i]; @@ -863,8 +863,8 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext uint8_t mappedLength = (uint8_t) (*dataOffset); /* additional safety check */ - verifyLength += mappedLength; - if (verifyLength > CO_SRDO_MAX_SIZE) { + verifyLength[plain_inverted] += mappedLength; + if (verifyLength[plain_inverted] > CO_SRDO_MAX_SIZE) { break; } @@ -911,7 +911,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } /* for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) */ /* safety check, this should not happen */ - if (verifyLength > CO_SRDO_MAX_SIZE || verifyLength != SRDO->dataLength) { + if (verifyLength[0]!=verifyLength[1] || verifyLength[0] > CO_SRDO_MAX_SIZE || verifyLength[0] != SRDO->dataLength) { SRDO->internalState = CO_SRDO_state_error_internal; } else { From c8f161cb42a7fdfc1077abf5ef4c435952fac4df Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 3 Jun 2024 10:27:09 +0200 Subject: [PATCH 250/520] fix variable lowestState assignment --- CANopen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CANopen.c b/CANopen.c index 3cebb054..97d1c152 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1643,7 +1643,7 @@ CO_SRDO_state_t CO_process_SRDO(CO_t *co, timerNext_us, NMTisOperational); if (state < lowestState) { - state = lowestState; + lowestState = state; } } From 2a43af442460bf5498cd8d6d2d3223be776803a0 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 3 Jun 2024 14:51:20 +0200 Subject: [PATCH 251/520] Cast data after bitwise, for non-8bit CPU compatibility --- 304/CO_SRDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index ab8807e4..13f1a22d 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -843,7 +843,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* Verify, if normal and inverted data matches properly */ for (uint8_t i = 0; i < SRDO->dataLength; i++) { - if (~dataSRDO[0][i] != dataSRDO[1][i]) { + if ( (uint8_t)(~dataSRDO[0][i]) != dataSRDO[1][i]) { data_ok = false; SRDO->internalState = CO_SRDO_state_error_rxNotInverted; break; From 520981b48c2445a71224e88e33e682655126a430 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 3 Jun 2024 14:58:30 +0200 Subject: [PATCH 252/520] The number of objects in the mapping are mappedObjectsCount (not CO_SRDO_MAX_MAPPED_ENTRIES) --- 304/CO_SRDO.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 13f1a22d..4c6db2ff 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -444,9 +444,9 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ err = ERR_INFO(0x1381 + SRDO_Index, 0, 1); } else { - for (uint8_t i = 1; i <= CO_SRDO_MAX_MAPPED_ENTRIES; i++) { - if (OD_get_u32(OD_138x_SRDOMapPar, i, &mapping[i-1], true) != ODR_OK) { - err = ERR_INFO(0x1381 + SRDO_Index, i, 1); + for (uint8_t i = 0; i < mappedObjectsCount; i++) { + if (OD_get_u32(OD_138x_SRDOMapPar, i+1, &mapping[i], true) != ODR_OK) { + err = ERR_INFO(0x1381 + SRDO_Index, i+1, 1); break; } } From 83b358abb5ff83a31d8ae6e6a0f323369b4ba540 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 3 Jun 2024 17:11:41 +0200 Subject: [PATCH 253/520] Another cast data after bitwise --- 304/CO_SRDO.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 4c6db2ff..ebcae2fd 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -778,7 +778,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext dataSRDO[plain_inverted] += mappedLength; } - if (verifyLength[0]!=verifyLength[1] || verifyLength[0] > CO_SRDO_MAX_SIZE || verifyLength[0] != SRDO->dataLength) { + if (verifyLength[0] != verifyLength[1] || verifyLength[0] > CO_SRDO_MAX_SIZE || verifyLength[0] != SRDO->dataLength) { SRDO->internalState = CO_SRDO_state_error_internal; /* should not happen */ } else { @@ -786,7 +786,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX /* check data before sending (optional) */ for (uint8_t i = 0; i < SRDO->dataLength; i++) { - if (~SRDO->CANtxBuff[0]->data[i] != SRDO->CANtxBuff[1]->data[i]) { + if ((uint8_t)(~SRDO->CANtxBuff[0]->data[i]) != SRDO->CANtxBuff[1]->data[i]) { SRDO->internalState = CO_SRDO_state_error_txNotInverted; data_ok = false; break; @@ -843,7 +843,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* Verify, if normal and inverted data matches properly */ for (uint8_t i = 0; i < SRDO->dataLength; i++) { - if ( (uint8_t)(~dataSRDO[0][i]) != dataSRDO[1][i]) { + if ((uint8_t)(~dataSRDO[0][i]) != dataSRDO[1][i]) { data_ok = false; SRDO->internalState = CO_SRDO_state_error_rxNotInverted; break; @@ -911,7 +911,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } /* for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) */ /* safety check, this should not happen */ - if (verifyLength[0]!=verifyLength[1] || verifyLength[0] > CO_SRDO_MAX_SIZE || verifyLength[0] != SRDO->dataLength) { + if (verifyLength[0] != verifyLength[1] || verifyLength[0] > CO_SRDO_MAX_SIZE || verifyLength[0] != SRDO->dataLength) { SRDO->internalState = CO_SRDO_state_error_internal; } else { From 39c2d7a89760954a182e4a7bfd4afc63a199bafe Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 4 Jun 2024 14:16:19 +0200 Subject: [PATCH 254/520] Implemented "elegant" solution to avoid problems with conformance test tool --- 304/CO_SRDO.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index ebcae2fd..c11bb552 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -137,6 +137,24 @@ OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countR return ODR_OK; } +bool_t +OD_not_write_same_value(OD_stream_t *stream, const void *buf, OD_size_t count) { + // The conformance test tool does not recognize CANopen Safety and on all object dictionaty tries to read and write the same value + OD_size_t countRead = 0; + uint8_t bufRead[6] = { 0 }; + if( count > 6 ) { + return false; + } + ODR_t returnCode = OD_readOriginal(stream, bufRead, count, &countRead); + if ( returnCode != ODR_OK ){ + return false; + } + if ( memcmp(buf,bufRead,count) == 0 ){ + return true; + } + return false; +} + static ODR_t OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); @@ -165,6 +183,10 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t return ODR_DEV_INCOMPAT; } + if( OD_not_write_same_value(stream, buf, count) ) { + return ODR_OK; + } + CO_SRDO_t* SRDO = stream->object; CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; uint8_t bufCopy[4]; @@ -229,6 +251,10 @@ OD_write_SRDO_mappingParam(OD_stream_t* stream, const void* buf, OD_size_t count return ODR_DEV_INCOMPAT; } + if( OD_not_write_same_value(stream, buf, count) ) { + return ODR_OK; + } + CO_SRDO_t* SRDO = stream->object; CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; From 3fe59fed4bb1661916e2814eaa354adcb9ac1eb0 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 Jun 2024 19:16:00 +0200 Subject: [PATCH 255/520] Use CO_CONFORMANCE_TEST_TOOL_ADAPTATION macro to make code optional. --- 304/CO_SRDO.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index c11bb552..984cd6e0 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -36,6 +36,10 @@ #error CO_CONFIG_CRC16_ENABLE must be enabled. #endif +#ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION +#warning CO_CONFORMANCE_TEST_TOOL_ADAPTATION may be used only for conformance testing (because of CTT limitations) +#endif + /* values for informationDirection and configurationValid */ #define CO_SRDO_INVALID (0U) #define CO_SRDO_TX (1U) @@ -137,6 +141,7 @@ OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countR return ODR_OK; } +#ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION bool_t OD_not_write_same_value(OD_stream_t *stream, const void *buf, OD_size_t count) { // The conformance test tool does not recognize CANopen Safety and on all object dictionaty tries to read and write the same value @@ -154,6 +159,7 @@ OD_not_write_same_value(OD_stream_t *stream, const void *buf, OD_size_t count) { } return false; } +#endif static ODR_t OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { @@ -183,9 +189,11 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t return ODR_DEV_INCOMPAT; } +#ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION if( OD_not_write_same_value(stream, buf, count) ) { return ODR_OK; } +#endif CO_SRDO_t* SRDO = stream->object; CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; @@ -251,9 +259,11 @@ OD_write_SRDO_mappingParam(OD_stream_t* stream, const void* buf, OD_size_t count return ODR_DEV_INCOMPAT; } +#ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION if( OD_not_write_same_value(stream, buf, count) ) { return ODR_OK; } +#endif CO_SRDO_t* SRDO = stream->object; CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; From 0dd1a0811833bfb80290afae44fc63ef0841d7a4 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 Jun 2024 19:26:13 +0200 Subject: [PATCH 256/520] remove SRDO warning --- 304/CO_SRDO.h | 2 -- README.md | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index e24bcd6c..e23c4847 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -41,8 +41,6 @@ #if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN -#warning SRDO is draft version and is not fully tested! - #ifdef __cplusplus extern "C" { #endif diff --git a/README.md b/README.md index 44a47bd6..78f43d03 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Characteristics - [Time-stamp](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) producer/consumer enables date and time synchronization in millisecond resolution. - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) CANopen node-id and bitrate setup, master and slave, LSS fastscan. - [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. - - CANopen Safety, EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks + - [CANopen Safety](https://standards.globalspec.com/std/1284438/en-50325-5), EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks - [CANopen Conformance Test Tool](https://www.can-cia.org/services/test-center/conformance-test-tool/) passed. ### Other From f407bc6d0590dc4d4363ffd0e386053fce7ae165 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 29 Mar 2024 13:14:49 +0100 Subject: [PATCH 257/520] Fixed txErrors variable name --- example/CO_driver_blank.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index 5d2265d1..e0ef6391 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -290,7 +290,7 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { /* tx bus warning or passive */ if (txErrors >= 128) { status |= CO_CAN_ERRTX_WARNING | CO_CAN_ERRTX_PASSIVE; - } else if (rxErrors >= 96) { + } else if (txErrors >= 96) { status |= CO_CAN_ERRTX_WARNING; } From 6a0df55b010ae459a9f93957258ff39dd03780a2 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 4 Jun 2024 19:54:00 +0200 Subject: [PATCH 258/520] Overrun not correctly reported in CO_Emergency.c, by H-Grobben #466 --- 301/CO_Emergency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index b2cffc0d..897c4ff1 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -591,7 +591,7 @@ void CO_EM_process(CO_EM_t *em, } if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) { CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0, - CO_EM_CAN_RXB_OVERFLOW, CO_EM_CAN_RXB_OVERFLOW, 0); + CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } } From 1b63929837aac3610c1b46bd03962fec75027ed4 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 6 Jun 2024 16:39:44 +0200 Subject: [PATCH 259/520] Only if the configuration is valid, the private variable is activated (otherwise CO_SRDO_process will generate errors) --- 304/CO_SRDO.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 984cd6e0..1b5ad748 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -354,6 +354,7 @@ CO_ReturnError_t CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo) { ODR_t odRet; + uint8_t configurationValid; /* verify arguments */ if ((SRDOGuard == NULL) || (OD_13FE_configurationValid == NULL) || (OD_13FF_safetyConfigurationSignature == NULL)) { @@ -383,9 +384,16 @@ CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationV } return CO_ERROR_OD_PARAMETERS; } - - /* Private variable, erroneous SRDO initialization will clear this. */ - SRDOGuard->_configurationValid = true; + + if (OD_get_u8(OD_13FE_configurationValid, 0, &configurationValid, true) != ODR_OK) { + *errInfo = (((uint32_t)OD_getIndex(OD_13FE_configurationValid)) << 8) | 1U; + return CO_ERROR_OD_PARAMETERS; + } + + if (configurationValid == CO_SRDO_VALID_MAGIC) { + /* Private variable, erroneous SRDO initialization will clear this. */ + SRDOGuard->_configurationValid = true; + } return CO_ERROR_NO; } From ddaa8974f1cdd7819802ccef23e2b6ba619145a5 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 10 Jun 2024 10:30:59 +0200 Subject: [PATCH 260/520] static analysis: Ignoring return value of function 'memcpy' [MISRA 2012 Directive 4.7, required] --- 301/CO_Emergency.c | 10 +++++----- 301/CO_ODinterface.c | 4 ++-- 301/CO_PDO.c | 10 +++++----- 301/CO_SDOclient.c | 22 +++++++++++----------- 301/CO_SDOserver.c | 24 ++++++++++++------------ 301/CO_TIME.c | 2 +- 304/CO_SRDO.c | 10 +++++----- 305/CO_LSSmaster.c | 2 +- 305/CO_LSSslave.c | 22 +++++++++++----------- 309/CO_gateway_ascii.c | 2 +- 10 files changed, 54 insertions(+), 54 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 897c4ff1..f62ad07d 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -272,7 +272,7 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, stream->dataLength = countReadLocal; } - memcpy (buf, &em->errorStatusBits[0], countReadLocal); + (void)memcpy (buf, &em->errorStatusBits[0], countReadLocal); *countRead = countReadLocal; return ODR_OK; @@ -301,7 +301,7 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, stream->dataLength = countWrite; } - memcpy (&em->errorStatusBits[0], buf, countWrite); + (void)memcpy (&em->errorStatusBits[0], buf, countWrite); *countWritten = countWrite; return ODR_OK; @@ -328,8 +328,8 @@ static void CO_EM_receive(void *object, void *msg) { uint16_t errorCode; uint32_t infoCode; - memcpy(&errorCode, &data[0], sizeof(errorCode)); - memcpy(&infoCode, &data[4], sizeof(infoCode)); + (void)memcpy(&errorCode, &data[0], sizeof(errorCode)); + (void)memcpy(&infoCode, &data[4], sizeof(infoCode)); em->pFunctSignalRx(ident, CO_SWAP_16(errorCode), data[2], @@ -653,7 +653,7 @@ void CO_EM_process(CO_EM_t *em, em->fifo[fifoPpPtr].msg |= (uint32_t) errorRegister << 16; /* send emergency message */ - memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr].msg, + (void)memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr].msg, sizeof(em->CANtxBuff->data)); CO_CANsend(em->CANdevTx, em->CANtxBuff); diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index f71fbca1..ab39fcbc 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -65,7 +65,7 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, } } - memcpy(buf, dataOrig, dataLenToCopy); + (void)memcpy(buf, dataOrig, dataLenToCopy); *countRead = dataLenToCopy; return returnCode; @@ -116,7 +116,7 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, return ODR_DATA_LONG; } - memcpy(dataOrig, buf, dataLenToCopy); + (void)memcpy(dataOrig, buf, dataLenToCopy); *countWritten = dataLenToCopy; return returnCode; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 20b1128a..4fd630d7 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -491,7 +491,7 @@ static void CO_PDO_receive(void *object, void *msg) { #endif /* copy data into appropriate buffer and set 'new message' flag */ - memcpy(RPDO->CANrxData[bufNo], data,sizeof(RPDO->CANrxData[bufNo])); + (void)memcpy(RPDO->CANrxData[bufNo], data,sizeof(RPDO->CANrxData[bufNo])); CO_FLAG_SET(RPDO->CANrxNew[bufNo]); #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE @@ -529,7 +529,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, CO_RPDO_t *RPDO = stream->object; CO_PDO_common_t *PDO = &RPDO->PDO_common; uint8_t bufCopy[4]; - memcpy(bufCopy, buf, count); + (void)memcpy(bufCopy, buf, count); switch (stream->subIndex) { case 1: { /* COB-ID used by PDO */ @@ -843,7 +843,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, uint8_t *dataOD; if (ODdataLength > mappedLength) { memset(buf, 0, sizeof(buf)); - memcpy(buf, dataRPDO, mappedLength); + (void)memcpy(buf, dataRPDO, mappedLength); dataOD = buf; } else { @@ -960,7 +960,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, CO_TPDO_t *TPDO = stream->object; CO_PDO_common_t *PDO = &TPDO->PDO_common; uint8_t bufCopy[4]; - memcpy(bufCopy, buf, count); + (void)memcpy(bufCopy, buf, count); switch (stream->subIndex) { case 1: { /* COB-ID used by PDO */ @@ -1289,7 +1289,7 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { /* If auxiliary buffer, copy it to the TPDO */ if (ODdataLength > mappedLength) { - memcpy(dataTPDO, buf, mappedLength); + (void)memcpy(dataTPDO, buf, mappedLength); } /* In event driven TPDO indicate transmission of OD variable */ diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 9235eac3..7052d125 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -77,7 +77,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { ) { #endif /* copy data and set 'new message' flag */ - memcpy((void *)&SDO_C->CANrxData[0], (const void *)&data[0], 8); + (void)memcpy((void *)&SDO_C->CANrxData[0], (const void *)&data[0], 8); CO_FLAG_SET(SDO_C->CANrxNew); #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles @@ -106,7 +106,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { if ((data[0] & 0x80) != 0) { /* copy data to temporary buffer, because we don't know the * number of bytes not containing data */ - memcpy((void *)&SDO_C->block_dataUploadLast[0], + (void)memcpy((void *)&SDO_C->block_dataUploadLast[0], (const void *)&data[1], 7); SDO_C->finished = true; state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; @@ -674,7 +674,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80) { uint32_t code; - memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); + (void)memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; @@ -922,7 +922,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->sizeInd > 0) { uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); SDO_C->CANtxBuff->data[0] |= 0x01; - memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); + (void)memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); } #else SDO_C->state = CO_SDO_ST_IDLE; @@ -988,7 +988,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->sizeInd > 0) { uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); SDO_C->CANtxBuff->data[0] |= 0x02; - memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); + (void)memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); } /* reset timeout timer and send message */ @@ -1076,7 +1076,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); + (void)memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; @@ -1289,7 +1289,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80) { uint32_t code; - memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); + (void)memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; @@ -1334,7 +1334,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* segmented transfer, is size indicated? */ if (SDO_C->CANrxData[0] & 0x01) { uint32_t size; - memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } SDO_C->toggle = 0x00; @@ -1428,7 +1428,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } if (SDO_C->CANrxData[0] & 0x02) { uint32_t size; - memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } @@ -1477,7 +1477,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* segmented transfer, is size indicated? */ if (SDO_C->CANrxData[0] & 0x01) { uint32_t size; - memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } SDO_C->toggle = 0x00; @@ -1787,7 +1787,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); + (void)memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index fac86283..9c8b3d4c 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -89,7 +89,7 @@ static void CO_SDO_receive(void *object, void *msg) { /* Copy data. There is always enough space in buffer, * because block_blksize was calculated before */ - memcpy(SDO->buf + SDO->bufOffsetWr, &data[1], 7); + (void)memcpy(SDO->buf + SDO->bufOffsetWr, &data[1], 7); SDO->bufOffsetWr += 7; SDO->sizeTran += 7; @@ -149,7 +149,7 @@ static void CO_SDO_receive(void *object, void *msg) { else { /* copy data and set 'new message' flag, data will be processed in * CO_SDOserver_process() */ - memcpy(SDO->CANrxData, data, DLC); + (void)memcpy(SDO->CANrxData, data, DLC); CO_FLAG_SET(SDO->CANrxNew); #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE /* Optional signal to RTOS, which can resume task, which handles @@ -827,7 +827,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* copy data to the temp buffer, swap data if necessary */ uint8_t buf[6] = {0}; - memcpy(buf, &SDO->CANrxData[4], dataSizeToWrite); + (void)memcpy(buf, &SDO->CANrxData[4], dataSizeToWrite); #ifdef CO_BIG_ENDIAN if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { reverseBytes(buf, dataSizeToWrite); @@ -884,7 +884,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, uint32_t size; OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - memcpy(&size, &SDO->CANrxData[4], sizeof(size)); + (void)memcpy(&size, &SDO->CANrxData[4], sizeof(size)); SDO->sizeInd = CO_SWAP_32(size); /* Indicated size of SDO matches sizeof OD variable? */ @@ -933,7 +933,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* get data size and write data to the buffer */ OD_size_t count = 7 - ((SDO->CANrxData[0] >> 1) & 0x07); - memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); + (void)memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); SDO->bufOffsetWr += count; SDO->sizeTran += count; @@ -999,7 +999,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, uint32_t size; OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - memcpy(&size, &SDO->CANrxData[4], sizeof(size)); + (void)memcpy(&size, &SDO->CANrxData[4], sizeof(size)); SDO->sizeInd = CO_SWAP_32(size); /* Indicated size of SDO matches sizeof OD variable? */ @@ -1288,7 +1288,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if (SDO->sizeInd > 0 && SDO->sizeInd <= 4) { /* expedited transfer */ SDO->CANtxBuff->data[0] = (uint8_t)(0x43|((4-SDO->sizeInd)<<2)); - memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, SDO->sizeInd); + (void)memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, SDO->sizeInd); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } @@ -1299,7 +1299,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, uint32_t sizeInd = SDO->sizeInd; uint32_t sizeIndSw = CO_SWAP_32(sizeInd); SDO->CANtxBuff->data[0] = 0x41; - memcpy(&SDO->CANtxBuff->data[4], + (void)memcpy(&SDO->CANtxBuff->data[4], &sizeIndSw, sizeof(sizeIndSw)); } else { @@ -1377,7 +1377,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* copy data segment to CAN message */ - memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, + (void)memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, count); SDO->bufOffsetRd += count; SDO->sizeTran += count; @@ -1513,7 +1513,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if (SDO->sizeInd > 0) { uint32_t size = CO_SWAP_32(SDO->sizeInd); SDO->CANtxBuff->data[0] |= 0x02; - memcpy(&SDO->CANtxBuff->data[4], &size, sizeof(size)); + (void)memcpy(&SDO->CANtxBuff->data[4], &size, sizeof(size)); } /* reset timeout timer and send message */ @@ -1536,7 +1536,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* copy data segment to CAN message */ - memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, + (void)memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, count); SDO->bufOffsetRd += count; SDO->block_noData = (uint8_t)(7 - count); @@ -1606,7 +1606,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); SDO->CANtxBuff->data[3] = SDO->subIndex; - memcpy(&SDO->CANtxBuff->data[4], &code, sizeof(code)); + (void)memcpy(&SDO->CANtxBuff->data[4], &code, sizeof(code)); CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 6335593b..43dadc56 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -42,7 +42,7 @@ static void CO_TIME_receive(void *object, void *msg) { uint8_t *data = CO_CANrxMsg_readData(msg); if (DLC == CO_TIME_MSG_LENGTH) { - memcpy(TIME->timeStamp, data, sizeof(TIME->timeStamp)); + (void)memcpy(TIME->timeStamp, data, sizeof(TIME->timeStamp)); CO_FLAG_SET(TIME->CANrxNew); #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 1b5ad748..5916deb8 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -57,7 +57,7 @@ CO_SRDO_receive_normal(void* object, void* msg) { if ((SRDO->informationDirection == CO_SRDO_RX) && (DLC >= SRDO->dataLength) && !CO_FLAG_READ(SRDO->CANrxNew[1])) { /* copy data into appropriate buffer and set 'new message' flag */ - memcpy(SRDO->CANrxData[0], data, sizeof(SRDO->CANrxData[0])); + (void)memcpy(SRDO->CANrxData[0], data, sizeof(SRDO->CANrxData[0])); CO_FLAG_SET(SRDO->CANrxNew[0]); #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE @@ -81,7 +81,7 @@ CO_SRDO_receive_inverted(void* object, void* msg) { if ((SRDO->informationDirection == CO_SRDO_RX) && (DLC >= SRDO->dataLength) && CO_FLAG_READ(SRDO->CANrxNew[0])) { /* copy data into appropriate buffer and set 'new message' flag */ - memcpy(SRDO->CANrxData[1], data, sizeof(SRDO->CANrxData[1])); + (void)memcpy(SRDO->CANrxData[1], data, sizeof(SRDO->CANrxData[1])); CO_FLAG_SET(SRDO->CANrxNew[1]); #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE @@ -198,7 +198,7 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t CO_SRDO_t* SRDO = stream->object; CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; uint8_t bufCopy[4]; - memcpy(bufCopy, buf, count); + (void)memcpy(bufCopy, buf, count); /* Writing Object Dictionary variable */ if (SRDOGuard->NMTisOperational) { @@ -816,7 +816,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* If auxiliary buffer, copy it to the SRDO */ if (ODdataLength > mappedLength) { - memcpy(dataSRDO[plain_inverted], buf, mappedLength); + (void)memcpy(dataSRDO[plain_inverted], buf, mappedLength); } dataSRDO[plain_inverted] += mappedLength; @@ -923,7 +923,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext uint8_t *dataOD; if (ODdataLength > mappedLength) { memset(buf, 0, sizeof(buf)); - memcpy(buf, dataSRDO[plain_inverted], mappedLength); + (void)memcpy(buf, dataSRDO[plain_inverted], mappedLength); dataOD = buf; } else { diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 60721712..a46c1eb3 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -87,7 +87,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING){ /* copy data and set 'new message' flag */ - memcpy(LSSmaster->CANrxData, data, sizeof(LSSmaster->CANrxData)); + (void)memcpy(LSSmaster->CANrxData, data, sizeof(LSSmaster->CANrxData)); CO_FLAG_SET(LSSmaster->CANrxNew); diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index ee8b83ff..e9983c35 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -83,25 +83,25 @@ static void CO_LSSslave_receive(void *object, void *msg) switch (cs) { case CO_LSS_SWITCH_STATE_SEL_VENDOR: { uint32_t valSw; - memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy(&valSw, &data[1], sizeof(valSw)); LSSslave->lssSelect.identity.vendorID = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_PRODUCT: { uint32_t valSw; - memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy(&valSw, &data[1], sizeof(valSw)); LSSslave->lssSelect.identity.productCode = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_REV: { uint32_t valSw; - memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy(&valSw, &data[1], sizeof(valSw)); LSSslave->lssSelect.identity.revisionNumber = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_SERIAL: { uint32_t valSw; - memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy(&valSw, &data[1], sizeof(valSw)); LSSslave->lssSelect.identity.serialNumber = CO_SWAP_32(valSw); if (CO_LSS_ADDRESS_EQUAL(LSSslave->lssAddress, @@ -132,7 +132,7 @@ static void CO_LSSslave_receive(void *object, void *msg) break; } - memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy(&valSw, &data[1], sizeof(valSw)); idNumber = CO_SWAP_32(valSw); ack = false; @@ -180,7 +180,7 @@ static void CO_LSSslave_receive(void *object, void *msg) } } else { /* LSSslave->lssState == CO_LSS_STATE_CONFIGURATION */ - memcpy(&LSSslave->CANdata, &data[0], sizeof(LSSslave->CANdata)); + (void)memcpy(&LSSslave->CANdata, &data[0], sizeof(LSSslave->CANdata)); LSSslave->service = cs; request_LSSslave_process = true; } @@ -228,7 +228,7 @@ CO_ReturnError_t CO_LSSslave_init( memset(LSSslave, 0, sizeof(CO_LSSslave_t)); /* Configure object variables */ - memcpy(&LSSslave->lssAddress, lssAddress, sizeof(LSSslave->lssAddress)); + (void)memcpy(&LSSslave->lssAddress, lssAddress, sizeof(LSSslave->lssAddress)); LSSslave->lssState = CO_LSS_STATE_WAITING; LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; @@ -444,28 +444,28 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { case CO_LSS_INQUIRE_VENDOR: { LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.vendorID); - memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); + (void)memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_PRODUCT: { LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.productCode); - memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); + (void)memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_REV: { LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.revisionNumber); - memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); + (void)memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_SERIAL: { LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.serialNumber); - memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); + (void)memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); CANsend = true; break; } diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index ebdb580c..ba7161be 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -2013,7 +2013,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, size_t lenHelpRemain = lenHelp - gtwa->helpStringOffset; size_t lenCopied = lenBuf < lenHelpRemain ? lenBuf : lenHelpRemain; - memcpy(gtwa->respBuf, + (void)memcpy(gtwa->respBuf, >wa->helpString[gtwa->helpStringOffset], lenCopied); From e3206f2c7faee27a55100d2e1f7daa5223b3e15c Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 10 Jun 2024 11:56:47 +0200 Subject: [PATCH 261/520] static analysis: Ignoring return value of function 'memset' [MISRA 2012 Directive 4.7, required] --- 301/CO_Emergency.c | 2 +- 301/CO_HBconsumer.c | 2 +- 301/CO_NMT_Heartbeat.c | 2 +- 301/CO_Node_Guarding.c | 4 ++-- 301/CO_PDO.c | 12 ++++++------ 301/CO_SDOclient.c | 4 ++-- 301/CO_SDOserver.c | 2 +- 301/CO_SYNC.c | 2 +- 301/CO_TIME.c | 2 +- 303/CO_LEDs.c | 2 +- 304/CO_SRDO.c | 12 ++++++------ 305/CO_LSSmaster.c | 20 ++++++++++---------- 305/CO_LSSslave.c | 10 +++++----- 309/CO_gateway_ascii.c | 8 ++++---- 14 files changed, 42 insertions(+), 42 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index f62ad07d..c6b546fd 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -392,7 +392,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, } /* clear the object */ - memset(em, 0, sizeof(CO_EM_t)); + (void)memset(em, 0, sizeof(CO_EM_t)); /* set object variables */ em->CANdevTx = CANdevTx; diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 41bdd249..fcf833e0 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -131,7 +131,7 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, } /* Configure object variables */ - memset(HBcons, 0, sizeof(CO_HBconsumer_t)); + (void)memset(HBcons, 0, sizeof(CO_HBconsumer_t)); HBcons->em = em; HBcons->monitoredNodes = monitoredNodes; HBcons->CANdevRx = CANdevRx; diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index fad6921d..38e00ab3 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -112,7 +112,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, } /* clear the object */ - memset(NMT, 0, sizeof(CO_NMT_t)); + (void)memset(NMT, 0, sizeof(CO_NMT_t)); /* Configure object variables */ NMT->operatingState = CO_NMT_INITIALIZING; diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index edba347b..1fe660fa 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -124,7 +124,7 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, } /* clear the object */ - memset(ngs, 0, sizeof(CO_nodeGuardingSlave_t)); + (void)memset(ngs, 0, sizeof(CO_nodeGuardingSlave_t)); /* Configure object variables */ ngs->em = em; @@ -317,7 +317,7 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, } /* clear the object */ - memset(ngm, 0, sizeof(CO_nodeGuardingMaster_t)); + (void)memset(ngm, 0, sizeof(CO_nodeGuardingMaster_t)); /* Configure object variables */ ngm->em = em; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 4fd630d7..6bdb0471 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -65,7 +65,7 @@ static ODR_t OD_read_dummy(OD_stream_t *stream, void *buf, count = stream->dataLength; } - memset(buf, 0, count); + (void)memset(buf, 0, count); *countRead = count; return ODR_OK; @@ -104,7 +104,7 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, /* is there a reference to the dummy entry */ if (index < 0x20 && subIndex == 0) { OD_stream_t *stream = &OD_IO->stream; - memset(stream, 0, sizeof(OD_stream_t)); + (void)memset(stream, 0, sizeof(OD_stream_t)); stream->dataLength = stream->dataOffset = mappedLength; OD_IO->read = OD_read_dummy; OD_IO->write = OD_write_dummy; @@ -654,7 +654,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, } /* clear object */ - memset(RPDO, 0, sizeof(CO_RPDO_t)); + (void)memset(RPDO, 0, sizeof(CO_RPDO_t)); /* Configure object variables */ PDO->em = em; @@ -842,7 +842,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, uint8_t buf[CO_PDO_MAX_SIZE]; uint8_t *dataOD; if (ODdataLength > mappedLength) { - memset(buf, 0, sizeof(buf)); + (void)memset(buf, 0, sizeof(buf)); (void)memcpy(buf, dataRPDO, mappedLength); dataOD = buf; } @@ -1099,7 +1099,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, } /* clear object */ - memset(TPDO, 0, sizeof(CO_TPDO_t)); + (void)memset(TPDO, 0, sizeof(CO_TPDO_t)); /* Configure object variables */ PDO->em = em; @@ -1260,7 +1260,7 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { uint8_t buf[CO_PDO_MAX_SIZE]; uint8_t *dataTPDOCopy; if (ODdataLength > mappedLength) { - memset(buf, 0, sizeof(buf)); + (void)memset(buf, 0, sizeof(buf)); dataTPDOCopy = buf; } else { diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 7052d125..9edad02c 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -879,7 +879,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* Transmit CAN data ******************************************************/ if (ret == CO_SDO_RT_waitingResponse) { size_t count; - memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); + (void)memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); switch (SDO_C->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { @@ -1615,7 +1615,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK size_t count; #endif - memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); + (void)memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); switch (SDO_C->state) { case CO_SDO_ST_UPLOAD_INITIATE_REQ: { diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 9c8b3d4c..7158778e 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1230,7 +1230,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Transmit CAN data ******************************************************/ if (ret == CO_SDO_RT_waitingResponse) { /* clear response buffer */ - memset(SDO->CANtxBuff->data, 0, sizeof(SDO->CANtxBuff->data)); + (void)memset(SDO->CANtxBuff->data, 0, sizeof(SDO->CANtxBuff->data)); switch (SDO->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 8e735b45..fcdb33cf 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -229,7 +229,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, } /* clear object */ - memset(SYNC, 0, sizeof(CO_SYNC_t)); + (void)memset(SYNC, 0, sizeof(CO_SYNC_t)); /* get and verify "COB-ID SYNC message" from OD and configure extension */ uint32_t cobIdSync = 0x00000080; diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 43dadc56..2344d053 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -108,7 +108,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, return CO_ERROR_ILLEGAL_ARGUMENT; } - memset(TIME, 0, sizeof(CO_TIME_t)); + (void)memset(TIME, 0, sizeof(CO_TIME_t)); /* get parameters from object dictionary and configure extension */ uint32_t cobIdTimeStamp; diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index b5921bd4..c7e4c4d3 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -37,7 +37,7 @@ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { } /* clear the object */ - memset(LEDs, 0, sizeof(CO_LEDs_t)); + (void)memset(LEDs, 0, sizeof(CO_LEDs_t)); return ret; } diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 5916deb8..c1458219 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -135,7 +135,7 @@ OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countR count = stream->dataLength; } - memset(buf, 0, count); + (void)memset(buf, 0, count); *countRead = count; return ODR_OK; @@ -362,7 +362,7 @@ CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationV } /* clear object */ - memset(SRDOGuard, 0, sizeof(CO_SRDOGuard_t)); + (void)memset(SRDOGuard, 0, sizeof(CO_SRDOGuard_t)); /* Configure Object dictionary extensions */ SRDOGuard->OD_13FE_extension.object = SRDOGuard; @@ -433,7 +433,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* clear object and configure some object variables */ if (err == 0) { - memset(SRDO, 0, sizeof(CO_SRDO_t)); + (void)memset(SRDO, 0, sizeof(CO_SRDO_t)); SRDO->SRDOGuard = SRDOGuard; SRDO->em = em; @@ -592,7 +592,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* is there a reference to the dummy entry */ else if (index < 0x20 && subIndex == 0) { OD_stream_t *stream = &OD_IO->stream; - memset(stream, 0, sizeof(OD_stream_t)); + (void)memset(stream, 0, sizeof(OD_stream_t)); stream->dataLength = stream->dataOffset = mappedLength; OD_IO->read = OD_read_dummy; OD_IO->write = OD_write_dummy; @@ -787,7 +787,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext uint8_t buf[CO_SRDO_MAX_SIZE]; uint8_t *dataSRDOCopy; if (ODdataLength > mappedLength) { - memset(buf, 0, sizeof(buf)); + (void)memset(buf, 0, sizeof(buf)); dataSRDOCopy = buf; } else { @@ -922,7 +922,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext uint8_t buf[CO_SRDO_MAX_SIZE]; uint8_t *dataOD; if (ODdataLength > mappedLength) { - memset(buf, 0, sizeof(buf)); + (void)memset(buf, 0, sizeof(buf)); (void)memcpy(buf, dataSRDO[plain_inverted], mappedLength); dataOD = buf; } diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index a46c1eb3..c244dca3 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -146,7 +146,7 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); - memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); + (void)memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); #if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE LSSmaster->pFunctSignal = NULL; LSSmaster->functSignalObject = NULL; @@ -222,7 +222,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); - memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6); + (void)memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -245,7 +245,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION; - memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); + (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -338,7 +338,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_WAITING; - memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); + (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -442,7 +442,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( LSSmaster->TXbuff->data[0] = CO_LSS_CFG_BIT_TIMING; LSSmaster->TXbuff->data[1] = 0; LSSmaster->TXbuff->data[2] = bitTiming; - memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); + (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -487,7 +487,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_NODE_ID; LSSmaster->TXbuff->data[1] = nodeId; - memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); + (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -527,7 +527,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_STORE; - memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); + (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -566,7 +566,7 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); - memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); + (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -585,7 +585,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( { CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = cs; - memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); + (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); return CO_LSSmaster_WAIT_SLAVE; @@ -1047,7 +1047,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( case CO_LSSmaster_FS_STATE_CHECK: ret = CO_LSSmaster_FsCheckWait(LSSmaster, timeDifference_us); if (ret == CO_LSSmaster_SCAN_FINISHED) { - memset(&fastscan->found, 0, sizeof(fastscan->found)); + (void)memset(&fastscan->found, 0, sizeof(fastscan->found)); /* start scanning procedure by triggering vendor ID scan */ CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_us, diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index e9983c35..fd737cfd 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -69,7 +69,7 @@ static void CO_LSSslave_receive(void *object, void *msg) request_LSSslave_process = true; } LSSslave->lssState = CO_LSS_STATE_WAITING; - memset(&LSSslave->lssSelect, 0, + (void)memset(&LSSslave->lssSelect, 0, sizeof(LSSslave->lssSelect)); break; case CO_LSS_STATE_CONFIGURATION: @@ -140,7 +140,7 @@ static void CO_LSSslave_receive(void *object, void *msg) /* Confirm, Reset */ ack = true; LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; - memset(&LSSslave->lssFastscan, 0, + (void)memset(&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); } else if (LSSslave->fastscanPos == lssSub) { @@ -163,7 +163,7 @@ static void CO_LSSslave_receive(void *object, void *msg) if (ack) { #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; - memset(&LSSslave->TXbuff->data[1], 0, + (void)memset(&LSSslave->TXbuff->data[1], 0, sizeof(LSSslave->TXbuff->data) - 1); CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); #else @@ -225,7 +225,7 @@ CO_ReturnError_t CO_LSSslave_init( /* Application must make sure that lssAddress is filled with data. */ /* clear the object */ - memset(LSSslave, 0, sizeof(CO_LSSslave_t)); + (void)memset(LSSslave, 0, sizeof(CO_LSSslave_t)); /* Configure object variables */ (void)memcpy(&LSSslave->lssAddress, lssAddress, sizeof(LSSslave->lssAddress)); @@ -332,7 +332,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { bool_t CANsend = false; uint32_t valSw; - memset(&LSSslave->TXbuff->data[0], 0, sizeof(LSSslave->TXbuff->data)); + (void)memset(&LSSslave->TXbuff->data[0], 0, sizeof(LSSslave->TXbuff->data)); switch (LSSslave->service) { case CO_LSS_SWITCH_STATE_GLOBAL: { diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index ba7161be..bc4a5160 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -85,7 +85,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, } /* clear the object */ - memset(gtwa, 0, sizeof(CO_GTWA_t)); + (void)memset(gtwa, 0, sizeof(CO_GTWA_t)); /* initialize variables */ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO @@ -1351,7 +1351,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_LSSmaster_changeTimeout(gtwa->LSSmaster, timeout_ms); /* prepare lssFastscan, all zero */ - memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); + (void)memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); /* continue with state machine */ gtwa->state = CO_GTWA_ST__LSS_FASTSCAN; @@ -1402,7 +1402,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* store node ID in node's NVM */ gtwa->lssStore = true; /* prepare lssFastscan, all zero */ - memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); + (void)memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); } if (closed == 0) { /* more arguments follow */ @@ -1417,7 +1417,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (closed == 1) { /* No other arguments, prepare lssFastscan, all zero */ - memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); + (void)memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); } } if (closed == 0) { From 187650d073ccb1f42dd0a5e6b25bc8579718d861 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 10 Jun 2024 11:58:55 +0200 Subject: [PATCH 262/520] static analysis: Ignoring return value of function 'memmove' [MISRA 2012 Directive 4.7, required] --- 301/CO_SDOserver.c | 2 +- 301/CO_driver.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 7158778e..e93c6abe 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -607,7 +607,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, if (!SDO->finished && countRemain < countMinimum) { /* first move remaining data to the start of the buffer */ - memmove(SDO->buf, SDO->buf + SDO->bufOffsetRd, countRemain); + (void)memmove(SDO->buf, SDO->buf + SDO->bufOffsetRd, countRemain); SDO->bufOffsetRd = 0; SDO->bufOffsetWr = countRemain; diff --git a/301/CO_driver.h b/301/CO_driver.h index 42c3b648..559e616f 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -737,15 +737,15 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule); * @return Value */ static inline uint8_t CO_getUint8(const void *buf) { - uint8_t value; memmove(&value, buf, sizeof(value)); return value; + uint8_t value; (void)memmove(&value, buf, sizeof(value)); return value; } /** Get uint16_t value from memory buffer, see @ref CO_getUint8 */ static inline uint16_t CO_getUint16(const void *buf) { - uint16_t value; memmove(&value, buf, sizeof(value)); return value; + uint16_t value; (void)memmove(&value, buf, sizeof(value)); return value; } /** Get uint32_t value from memory buffer, see @ref CO_getUint8 */ static inline uint32_t CO_getUint32(const void *buf) { - uint32_t value; memmove(&value, buf, sizeof(value)); return value; + uint32_t value; (void)memmove(&value, buf, sizeof(value)); return value; } /** @@ -757,15 +757,15 @@ static inline uint32_t CO_getUint32(const void *buf) { * @return number of bytes written. */ static inline uint8_t CO_setUint8(void *buf, uint8_t value) { - memmove(buf, &value, sizeof(value)); return sizeof(value); + (void)memmove(buf, &value, sizeof(value)); return sizeof(value); } /** Write uint16_t value into memory buffer, see @ref CO_setUint8 */ static inline uint8_t CO_setUint16(void *buf, uint16_t value) { - memmove(buf, &value, sizeof(value)); return sizeof(value); + (void)memmove(buf, &value, sizeof(value)); return sizeof(value); } /** Write uint32_t value into memory buffer, see @ref CO_setUint8 */ static inline uint8_t CO_setUint32(void *buf, uint32_t value) { - memmove(buf, &value, sizeof(value)); return sizeof(value); + (void)memmove(buf, &value, sizeof(value)); return sizeof(value); } /** @} */ /* CO_driver */ From a17b9fa20996fa878c002d8dcc6b18512111fd0b Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 10 Jun 2024 12:07:41 +0200 Subject: [PATCH 263/520] static analysis: Ignoring return value of functions: CO_setUint8, CO_setUint16, CO_setUint32 [MISRA 2012 Directive 4.7, required] --- 301/CO_Emergency.c | 8 ++++---- 301/CO_PDO.c | 6 +++--- 301/CO_TIME.c | 4 ++-- 304/CO_SRDO.c | 4 ++-- 305/CO_LSSmaster.c | 12 ++++++------ 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index c6b546fd..ef364b0d 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -70,7 +70,7 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, CO_CAN_ID_EMERGENCY + em->nodeId : em->producerCanId; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; COB_IDEmergency32 |= canId; - CO_setUint32(buf, COB_IDEmergency32); + (void)CO_setUint32(buf, COB_IDEmergency32); *countRead = sizeof(uint32_t); @@ -139,7 +139,7 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + em->nodeId; - CO_setUint32(buf, COB_IDEmergency32); + (void)CO_setUint32(buf, COB_IDEmergency32); *countRead = sizeof(uint32_t); return ODR_OK; @@ -194,7 +194,7 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, return ODR_DEV_INCOMPAT; } if (stream->subIndex == 0) { - CO_setUint8(buf, em->fifoCount); + (void)CO_setUint8(buf, em->fifoCount); *countRead = sizeof(uint8_t); return ODR_OK; @@ -210,7 +210,7 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, return ODR_DEV_INCOMPAT; } else { /* MISRA C 2004 14.10 */ } - CO_setUint32(buf, em->fifo[index].msg); + (void)CO_setUint32(buf, em->fifo[index].msg); *countRead = sizeof(uint32_t); return ODR_OK; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 6bdb0471..93f7d6d5 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -430,7 +430,7 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, /* If PDO is not valid, set bit 31 */ if (!PDO->valid) { COB_ID |= 0x80000000; } - CO_setUint32(buf, COB_ID); + (void)CO_setUint32(buf, COB_ID); } return returnCode; @@ -552,7 +552,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, if (valid != PDO->valid || CAN_ID != PDO->configuredCanId) { /* if default CAN-ID is written, store to OD without Node-ID */ if (CAN_ID == PDO->preDefinedCanId) { - CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); + (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); } if (!valid) { CAN_ID = 0; @@ -983,7 +983,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, if (valid != PDO->valid || CAN_ID != PDO->configuredCanId) { /* if default CAN-ID is written, store to OD without Node-ID */ if (CAN_ID == PDO->preDefinedCanId) { - CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); + (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); } if (!valid) { CAN_ID = 0; diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 2344d053..dcc1a8a3 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -223,8 +223,8 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, uint32_t ms_swapped = CO_SWAP_32(TIME->ms); uint16_t days_swapped = CO_SWAP_16(TIME->days); - CO_setUint32(&TIME->CANtxBuff->data[0], ms_swapped); - CO_setUint16(&TIME->CANtxBuff->data[4], days_swapped); + (void)CO_setUint32(&TIME->CANtxBuff->data[0], ms_swapped); + (void)CO_setUint16(&TIME->CANtxBuff->data[4], days_swapped); CO_CANsend(TIME->CANdevTx, TIME->CANtxBuff); } else { diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index c1458219..97187b03 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -177,7 +177,7 @@ OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, value += (uint32_t)SRDO->nodeId * 2; } - CO_setUint32(buf, value); + (void)CO_setUint32(buf, value); } return returnCode; @@ -240,7 +240,7 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t /* if default COB-ID is being written, write defaultCOB_ID without nodeId */ if ((SRDO->nodeId <= 64U) && (value == (defaultCOB_ID + ((uint32_t)SRDO->nodeId * 2)))) { value = defaultCOB_ID; - CO_setUint32(bufCopy, value); + (void)CO_setUint32(bufCopy, value); } } else { /* MISRA C 2004 14.10 */ } diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index c244dca3..ae14c4ec 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -224,16 +224,16 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( CO_FLAG_CLEAR(LSSmaster->CANrxNew); (void)memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; - CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_PRODUCT; - CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.productCode); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.productCode); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_REV; - CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.revisionNumber); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.revisionNumber); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_SERIAL; - CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.serialNumber); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.serialNumber); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -565,7 +565,7 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; - CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); + (void)CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -757,7 +757,7 @@ static void CO_LSSmaster_FsSendMsg( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_IDENT_FASTSCAN; - CO_setUint32(&LSSmaster->TXbuff->data[1], idNumber); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], idNumber); LSSmaster->TXbuff->data[5] = bitCheck; LSSmaster->TXbuff->data[6] = lssSub; LSSmaster->TXbuff->data[7] = lssNext; From dc10900ad58ed4d6ea8cfdb611e9300c884f9ee3 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 10 Jun 2024 14:20:16 +0200 Subject: [PATCH 264/520] static analysis: Aggiunte parentesi per la dipendenza posta sulla precedenza dell'operatore [MISRA 2012 Rule 12.1, advisory] --- 301/CO_Emergency.c | 20 ++--- 301/CO_HBconsumer.c | 24 +++--- 301/CO_NMT_Heartbeat.c | 34 ++++---- 301/CO_Node_Guarding.c | 12 +-- 301/CO_ODinterface.c | 30 +++---- 301/CO_ODinterface.h | 8 +- 301/CO_PDO.c | 114 +++++++++++++------------- 301/CO_SDOclient.c | 162 ++++++++++++++++++------------------- 301/CO_SDOserver.c | 98 +++++++++++----------- 301/CO_SYNC.c | 22 ++--- 301/CO_TIME.c | 10 +-- 301/CO_driver.h | 12 +-- 301/CO_fifo.c | 140 ++++++++++++++++---------------- 304/CO_SRDO.c | 48 +++++------ 305/CO_LSS.h | 10 +-- 305/CO_LSSmaster.c | 66 +++++++-------- 305/CO_LSSslave.c | 24 +++--- 309/CO_gateway_ascii.c | 94 ++++++++++----------- storage/CO_storage.c | 20 ++--- storage/CO_storageEeprom.c | 12 +-- 20 files changed, 480 insertions(+), 480 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index ef364b0d..c06697cd 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -129,8 +129,8 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count < sizeof(uint32_t) || countRead == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count < sizeof(uint32_t)) || (countRead == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -373,13 +373,13 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if (em == NULL || OD_1001_errReg == NULL + if ((em == NULL) || (OD_1001_errReg == NULL) #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) - || (fifo == NULL && fifoSize >= 2) + || ((fifo == NULL) && (fifoSize >= 2)) #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER - || OD_1014_cobIdEm == NULL || CANdevTx == NULL - || nodeId < 1 || nodeId > 127 + || (OD_1014_cobIdEm == NULL) || (CANdevTx == NULL) + || (nodeId < 1) || (nodeId > 127) #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY || OD_1003_preDefErr == NULL @@ -414,7 +414,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint32_t COB_IDEmergency32; ODR_t odRet; odRet = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); - if (odRet != ODR_OK || (COB_IDEmergency32 & 0x7FFFF800) != 0) { + if ((odRet != ODR_OK) || ((COB_IDEmergency32 & 0x7FFFF800) != 0)) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1014_cobIdEm); } /* don't break a program, if only value of a parameter is wrong */ if (odRet != ODR_OK) { return CO_ERROR_OD_PARAMETERS; } @@ -647,7 +647,7 @@ void CO_EM_process(CO_EM_t *em, ) { em->inhibitEmTimer = 0; #else - if (fifoPpPtr != em->fifoWrPtr && !em->CANtxBuff->bufferFull) { + if ((fifoPpPtr != em->fifoWrPtr) && (!em->CANtxBuff->bufferFull)) { #endif /* add error register to emergency message */ em->fifo[fifoPpPtr].msg |= (uint32_t) errorRegister << 16; @@ -679,7 +679,7 @@ void CO_EM_process(CO_EM_t *em, CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, CO_EMC_GENERIC, 0); } - else if (em->fifoOverflow == 2 && em->fifoPpPtr == em->fifoWrPtr) { + else if ((em->fifoOverflow == 2) && (em->fifoPpPtr == em->fifoWrPtr)) { em->fifoOverflow = 0; CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); } @@ -754,7 +754,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) /* prepare emergency message. Error register will be added in post-process*/ - uint32_t errMsg = (uint32_t)errorBit << 24 | CO_SWAP_16(errorCode); + uint32_t errMsg = ((uint32_t)errorBit << 24) | CO_SWAP_16(errorCode); #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER uint32_t infoCodeSwapped = CO_SWAP_32(infoCode); #endif diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index fcf833e0..2dcb87b8 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -88,10 +88,10 @@ static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, { CO_HBconsumer_t *HBcons = stream->object; - if (stream == NULL || buf == NULL - || stream->subIndex < 1 - || stream->subIndex > HBcons->numberOfMonitoredNodes - || count != sizeof(uint32_t) || countWritten == NULL + if ((stream == NULL) || (buf == NULL) + || (stream->subIndex < 1) + || (stream->subIndex > HBcons->numberOfMonitoredNodes) + || (count != sizeof(uint32_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -124,8 +124,8 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, ODR_t odRet; /* verify arguments */ - if (HBcons == NULL || em == NULL || monitoredNodes == NULL - || OD_1016_HBcons == NULL || CANdevRx == NULL + if ((HBcons == NULL) || (em == NULL) || (monitoredNodes == NULL) + || (OD_1016_HBcons == NULL) || (CANdevRx == NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -139,8 +139,8 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, /* get actual number of monitored nodes */ HBcons->numberOfMonitoredNodes = - OD_1016_HBcons->subEntriesCount-1 < monitoredNodesCount ? - OD_1016_HBcons->subEntriesCount-1 : monitoredNodesCount; + ((OD_1016_HBcons->subEntriesCount-1) < monitoredNodesCount) ? + (OD_1016_HBcons->subEntriesCount-1) : monitoredNodesCount; for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { uint32_t val; @@ -185,15 +185,15 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if (HBcons == NULL || idx >= HBcons->numberOfMonitoredNodes) { + if ((HBcons == NULL) || (idx >= HBcons->numberOfMonitoredNodes)) { return CO_ERROR_ILLEGAL_ARGUMENT; } /* verify for duplicate entries */ - if(consumerTime_ms != 0 && nodeId != 0) { + if((consumerTime_ms != 0) && (nodeId != 0)) { for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { CO_HBconsNode_t node = HBcons->monitoredNodes[i]; - if(idx != i && node.time_us != 0 && node.nodeId == nodeId) { + if((idx != i) && (node.time_us != 0) && (node.nodeId == nodeId)) { ret = CO_ERROR_OD_PARAMETERS; } } @@ -214,7 +214,7 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, CO_FLAG_CLEAR(monitoredNode->CANrxNew); /* is channel used */ - if (monitoredNode->nodeId != 0 && monitoredNode->time_us != 0) { + if ((monitoredNode->nodeId != 0) && (monitoredNode->time_us != 0)) { COB_ID = monitoredNode->nodeId + CO_CAN_ID_HEARTBEAT; monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; } diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 38e00ab3..1280b5ca 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -41,7 +41,7 @@ static void CO_NMT_receive(void *object, void *msg) { CO_NMT_t *NMT = (CO_NMT_t*)object; - if (DLC == 2 && (nodeId == 0 || nodeId == NMT->nodeId)) { + if ((DLC == 2) && ((nodeId == 0) || (nodeId == NMT->nodeId))) { NMT->internalCommand = command; #if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE @@ -62,8 +62,8 @@ static void CO_NMT_receive(void *object, void *msg) { static ODR_t OD_write_1017(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint16_t) || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count != sizeof(uint16_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -102,10 +102,10 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if (NMT == NULL || OD_1017_ProducerHbTime == NULL || em == NULL - || NMT_CANdevRx == NULL || HB_CANdevTx == NULL + if ((NMT == NULL) || (OD_1017_ProducerHbTime == NULL) || (em == NULL) + || (NMT_CANdevRx == NULL) || (HB_CANdevTx == NULL) #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER - || NMT_CANdevTx == NULL + || (NMT_CANdevTx == NULL) #endif ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -234,16 +234,16 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, /* Send heartbeat producer message if: * - First start, send bootup message or * - HB producer enabled and: Timer expired or NMT->operatingState changed*/ - if (NNTinit || (NMT->HBproducerTime_us != 0 - && (NMT->HBproducerTimer == 0 - || NMTstateCpy != NMT->operatingStatePrev) + if (NNTinit || ((NMT->HBproducerTime_us != 0) + && ((NMT->HBproducerTimer == 0) + || (NMTstateCpy != NMT->operatingStatePrev)) )) { NMT->HB_TXbuff->data[0] = (uint8_t) NMTstateCpy; CO_CANsend(NMT->HB_CANdevTx, NMT->HB_TXbuff); if (NMTstateCpy == CO_NMT_INITIALIZING) { /* NMT slave self starting */ - NMTstateCpy = (NMT->NMTcontrol & CO_NMT_STARTUP_TO_OPERATIONAL) != 0 + NMTstateCpy = ((NMT->NMTcontrol & CO_NMT_STARTUP_TO_OPERATIONAL) != 0) ? CO_NMT_OPERATIONAL : CO_NMT_PRE_OPERATIONAL; } else { @@ -282,19 +282,19 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, } /* verify NMT transitions based on error register */ - bool_t busOff_HB = (NMT->NMTcontrol & CO_NMT_ERR_ON_BUSOFF_HB) != 0 + bool_t busOff_HB = ((NMT->NMTcontrol & CO_NMT_ERR_ON_BUSOFF_HB) != 0) && (CO_isError(NMT->em, CO_EM_CAN_TX_BUS_OFF) || CO_isError(NMT->em, CO_EM_HEARTBEAT_CONSUMER) || CO_isError(NMT->em, CO_EM_HB_CONSUMER_REMOTE_RESET)); - bool_t errRegMasked = (NMT->NMTcontrol & CO_NMT_ERR_ON_ERR_REG) != 0 - && (CO_getErrorRegister(NMT->em) & NMT->NMTcontrol) != 0; + bool_t errRegMasked = ((NMT->NMTcontrol & CO_NMT_ERR_ON_ERR_REG) != 0) + && ((CO_getErrorRegister(NMT->em) & NMT->NMTcontrol) != 0); - if (NMTstateCpy == CO_NMT_OPERATIONAL && (busOff_HB || errRegMasked)) { - NMTstateCpy = (NMT->NMTcontrol & CO_NMT_ERR_TO_STOPPED) != 0 + if ((NMTstateCpy == CO_NMT_OPERATIONAL) && (busOff_HB || errRegMasked)) { + NMTstateCpy = ((NMT->NMTcontrol & CO_NMT_ERR_TO_STOPPED) != 0) ? CO_NMT_STOPPED : CO_NMT_PRE_OPERATIONAL; } - else if ((NMT->NMTcontrol & CO_NMT_ERR_FREE_TO_OPERATIONAL) != 0 - && NMTstateCpy == CO_NMT_PRE_OPERATIONAL && !busOff_HB && !errRegMasked + else if (((NMT->NMTcontrol & CO_NMT_ERR_FREE_TO_OPERATIONAL) != 0) + && (NMTstateCpy == CO_NMT_PRE_OPERATIONAL) && (!busOff_HB && !errRegMasked) ) { NMTstateCpy = CO_NMT_OPERATIONAL; } diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 1fe660fa..354ef54e 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -50,8 +50,8 @@ static void CO_ngs_receive(void *object, void *msg) { static ODR_t OD_write_100C(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint16_t) || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count != sizeof(uint16_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -80,8 +80,8 @@ static ODR_t OD_write_100C(OD_stream_t *stream, const void *buf, static ODR_t OD_write_100D(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint8_t) || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count != sizeof(uint8_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -117,8 +117,8 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if (ngs == NULL || em == NULL || CANdevRx == NULL || CANdevTx == NULL - || OD_100C_GuardTime == NULL || OD_100D_LifeTimeFactor == NULL + if ((ngs == NULL) || (em == NULL) || (CANdevRx == NULL) || (CANdevTx == NULL) + || (OD_100C_GuardTime == NULL) || (OD_100D_LifeTimeFactor == NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index ab39fcbc..296254c6 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -31,7 +31,7 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if (stream == NULL || buf == NULL || countRead == NULL) { + if ((stream == NULL) || (buf == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } @@ -46,7 +46,7 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, /* If previous read was partial or OD variable length is larger than * current buffer size, then data was (will be) read in several segments */ - if (stream->dataOffset > 0 || dataLenToCopy > count) { + if ((stream->dataOffset > 0) || (dataLenToCopy > count)) { if (stream->dataOffset >= dataLenToCopy) { return ODR_DEV_INCOMPAT; } @@ -75,7 +75,7 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || buf == NULL || countWritten == NULL) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } @@ -91,7 +91,7 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, /* If previous write was partial or OD variable length is larger than * current buffer size, then data was (will be) written in several * segments */ - if (stream->dataOffset > 0 || dataLenToCopy > count) { + if ((stream->dataOffset > 0) || (dataLenToCopy > count)) { if (stream->dataOffset >= dataLenToCopy) { return ODR_DEV_INCOMPAT; } @@ -141,7 +141,7 @@ static ODR_t OD_writeDisabled(OD_stream_t *stream, const void *buf, /******************************************************************************/ OD_entry_t *OD_find(OD_t *od, uint16_t index) { - if (od == NULL || od->size == 0) { + if ((od == NULL) || (od->size == 0)) { return NULL; } @@ -182,7 +182,7 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index) { ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, OD_IO_t *io, bool_t odOrig) { - if (entry == NULL || entry->odObject == NULL) { return ODR_IDX_NOT_EXIST; } + if ((entry == NULL) || (entry->odObject == NULL)) { return ODR_IDX_NOT_EXIST; } if (io == NULL) { return ODR_DEV_INCOMPAT; } OD_stream_t *stream = &io->stream; @@ -211,8 +211,8 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, else { stream->attribute = odo->attribute; uint8_t *ptr = odo->dataOrig; - stream->dataOrig = ptr == NULL ? ptr - : ptr + odo->dataElementSizeof * (subIndex - 1); + stream->dataOrig = (ptr == NULL) ? ptr + : (ptr + (odo->dataElementSizeof * (subIndex - 1))); stream->dataLength = odo->dataElementLength; } break; @@ -239,16 +239,16 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, } /* Access data from the original OD location */ - if (entry->extension == NULL || odOrig) { + if ((entry->extension == NULL) || odOrig) { io->read = OD_readOriginal; io->write = OD_writeOriginal; stream->object = NULL; } /* Access data from extension specified by application */ else { - io->read = entry->extension->read != NULL ? + io->read = (entry->extension->read != NULL) ? entry->extension->read : OD_readDisabled; - io->write = entry->extension->write != NULL ? + io->write = (entry->extension->write != NULL) ? entry->extension->write : OD_writeDisabled; stream->object = entry->extension->object; } @@ -294,7 +294,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { 0x08000024UL /* No data available */ }; - return (returnCode < 0 || returnCode >= ODR_COUNT) ? + return ((returnCode < 0) || (returnCode >= ODR_COUNT)) ? abortCodes[ODR_DEV_INCOMPAT] : abortCodes[returnCode]; } @@ -342,10 +342,10 @@ void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, errCopy = OD_getSub(entry, subIndex, &io, true); if (errCopy == ODR_OK) { - if (stream->dataOrig == NULL || stream->dataLength == 0) { + if ((stream->dataOrig == NULL) || (stream->dataLength == 0)) { errCopy = ODR_DEV_INCOMPAT; } - else if (len != 0 && len != stream->dataLength) { + else if ((len != 0) && (len != stream->dataLength)) { errCopy = ODR_TYPE_MISMATCH; } else { /* MISRA C 2004 14.10 */ } @@ -353,5 +353,5 @@ void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, if (err != NULL) { *err = errCopy; } - return errCopy == ODR_OK ? stream->dataOrig : NULL; + return (errCopy == ODR_OK) ? stream->dataOrig : NULL; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index cb0a4cd8..e9225ee3 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -453,7 +453,7 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { */ static inline bool_t OD_mappable(OD_stream_t *stream) { return (stream != NULL) - ? (stream->attribute & (ODA_TRPDO | ODA_TRSRDO)) != 0 : false; + ? ((stream->attribute & (ODA_TRPDO | ODA_TRSRDO)) != 0) : false; } @@ -482,7 +482,7 @@ static inline void OD_rwRestart(OD_stream_t *stream) { */ static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) { #if OD_FLAGS_PDO_SIZE > 0 - if (entry != NULL && entry->extension != NULL) { + if ((entry != NULL) && (entry->extension != NULL)) { return &entry->extension->flagsPDO[0]; } #endif @@ -509,7 +509,7 @@ static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) { */ static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) { #if OD_FLAGS_PDO_SIZE > 0 - if (flagsPDO != NULL && subIndex < (OD_FLAGS_PDO_SIZE * 8)) { + if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8))) { /* clear subIndex-th bit */ uint8_t mask = ~(1 << (subIndex & 0x07)); flagsPDO[subIndex >> 3] &= mask; @@ -531,7 +531,7 @@ static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) { */ static inline bool_t OD_TPDOtransmitted(uint8_t *flagsPDO, uint8_t subIndex) { #if OD_FLAGS_PDO_SIZE > 0 - if (flagsPDO != NULL && subIndex < (OD_FLAGS_PDO_SIZE * 8)) { + if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8))) { /* return true, if subIndex-th bit is set */ uint8_t mask = 1 << (subIndex & 0x07); if ((flagsPDO[subIndex >> 3] & mask) != 0) { diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 93f7d6d5..1be2bf3b 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -57,7 +57,7 @@ static ODR_t OD_write_dummy(OD_stream_t *stream, const void *buf, static ODR_t OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if (buf == NULL || stream == NULL || countRead == NULL) { + if ((buf == NULL) || (stream == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } @@ -102,7 +102,7 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, } /* is there a reference to the dummy entry */ - if (index < 0x20 && subIndex == 0) { + if ((index < 0x20) && (subIndex == 0)) { OD_stream_t *stream = &OD_IO->stream; (void)memset(stream, 0, sizeof(OD_stream_t)); stream->dataLength = stream->dataOffset = mappedLength; @@ -121,9 +121,9 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, /* verify access attributes, byte alignment and length */ OD_attr_t testAttribute = isRPDO ? ODA_RPDO : ODA_TPDO; - if ((OD_IOcopy.stream.attribute & testAttribute) == 0 - || (mappedLengthBits & 0x07) != 0 - || OD_IOcopy.stream.dataLength < mappedLength + if (((OD_IOcopy.stream.attribute & testAttribute) == 0) + || ((mappedLengthBits & 0x07) != 0) + || (OD_IOcopy.stream.dataLength < mappedLength) ) { return ODR_NO_MAP; /* Object cannot be mapped to the PDO. */ } @@ -135,7 +135,7 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, /* get TPDO request flag byte from extension */ #if OD_FLAGS_PDO_SIZE > 0 if (!isRPDO) { - if (subIndex < (OD_FLAGS_PDO_SIZE * 8) && entry->extension != NULL) { + if ((subIndex < (OD_FLAGS_PDO_SIZE * 8)) && (entry->extension != NULL)) { PDO->flagPDObyte[mapIndex] = &entry->extension->flagsPDO[subIndex >> 3]; PDO->flagPDObitmask[mapIndex] = 1 << (subIndex & 0x07); @@ -208,8 +208,8 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, pdoDataLength += OD_IO->stream.dataOffset; } } - if (pdoDataLength > CO_PDO_MAX_SIZE - || (pdoDataLength == 0 && mappedObjectsCount > 0) + if ((pdoDataLength > CO_PDO_MAX_SIZE) + || ((pdoDataLength == 0) && (mappedObjectsCount > 0)) ) { if (*erroneousMap == 0) { *erroneousMap = 1; } } @@ -232,8 +232,8 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* "count" is already verified in *_init() function */ - if (stream == NULL || buf == NULL || countWritten == NULL - || stream->subIndex > CO_PDO_MAX_MAPPED_ENTRIES + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) + || (stream->subIndex > CO_PDO_MAX_MAPPED_ENTRIES) ) { return ODR_DEV_INCOMPAT; } @@ -242,7 +242,7 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, CO_PDO_common_t *PDO = stream->object; /* PDO must be disabled before mapping configuration */ - if (PDO->valid || (PDO->mappedObjectsCount != 0 && stream->subIndex > 0)) { + if ((PDO->valid) || ((PDO->mappedObjectsCount != 0) && (stream->subIndex > 0))) { return ODR_UNSUPP_ACCESS; } @@ -270,7 +270,7 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, if (pdoDataLength > CO_PDO_MAX_SIZE) { return ODR_MAP_LEN; } - if (pdoDataLength == 0 && mappedObjectsCount > 0) { + if ((pdoDataLength == 0) && (mappedObjectsCount > 0)) { return ODR_INVALID_VALUE; } @@ -416,14 +416,14 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); /* When reading COB_ID, add Node-Id to the read value, if necessary */ - if (returnCode == ODR_OK && stream->subIndex == 1 && *countRead == 4) { + if ((returnCode == ODR_OK) && (stream->subIndex == 1) && (*countRead == 4)) { /* Only common part of the CO_RPDO_t or CO_TPDO_t will be used */ CO_PDO_common_t *PDO = stream->object; uint32_t COB_ID = CO_getUint32(buf); uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ - if (CAN_ID != 0 && CAN_ID == (PDO->preDefinedCanId & 0xFF80)) { + if ((CAN_ID != 0) && (CAN_ID == (PDO->preDefinedCanId & 0xFF80))) { COB_ID = (COB_ID & 0xFFFF0000) | PDO->preDefinedCanId; } @@ -483,7 +483,7 @@ static void CO_PDO_receive(void *object, void *msg) { /* Determine, to which of the two rx buffers copy the message. */ uint8_t bufNo = 0; #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if (RPDO->synchronous && RPDO->SYNC != NULL + if (RPDO->synchronous && (RPDO->SYNC != NULL) && RPDO->SYNC->CANrxToggle ) { bufNo = 1; @@ -522,7 +522,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* "count" is also verified in *_init() function */ - if (stream == NULL || buf == NULL || countWritten == NULL || count > 4) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4)) { return ODR_DEV_INCOMPAT; } @@ -540,16 +540,16 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, /* bits 11...29 must be zero, PDO must be disabled on change, * CAN_ID == 0 is not allowed, mapping must be configured before * enabling the PDO */ - if ((COB_ID & 0x3FFFF800) != 0 - || (valid && PDO->valid && CAN_ID != PDO->configuredCanId) + if (((COB_ID & 0x3FFFF800) != 0) + || (valid && PDO->valid && (CAN_ID != PDO->configuredCanId)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - || (valid && PDO->mappedObjectsCount == 0) + || (valid && (PDO->mappedObjectsCount == 0)) ) { return ODR_INVALID_VALUE; } /* parameter changed? */ - if (valid != PDO->valid || CAN_ID != PDO->configuredCanId) { + if ((valid != PDO->valid) || (CAN_ID != PDO->configuredCanId)) { /* if default CAN-ID is written, store to OD without Node-ID */ if (CAN_ID == PDO->preDefinedCanId) { (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); @@ -567,7 +567,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, (void*)RPDO, /* object passed to receive function */ CO_PDO_receive); /* this function will process rx msg */ - if (valid && ret == CO_ERROR_NO) { + if (valid && (ret == CO_ERROR_NO)) { PDO->valid = true; PDO->configuredCanId = CAN_ID; } @@ -588,8 +588,8 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if (transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240 - && transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO + if ((transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240) + && (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { return ODR_INVALID_VALUE; } @@ -647,8 +647,8 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, ODR_t odRet; /* verify arguments */ - if (RPDO == NULL || OD == NULL || em == NULL || OD_14xx_RPDOCommPar == NULL - || OD_16xx_RPDOMapPar == NULL || CANdevRx == NULL + if ((RPDO == NULL) || (OD == NULL) || (em == NULL) || (OD_14xx_RPDOCommPar == NULL) + || (OD_16xx_RPDOMapPar == NULL) || (CANdevRx == NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -685,7 +685,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, bool_t valid = (COB_ID & 0x80000000) == 0; uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - if (valid && (PDO->mappedObjectsCount == 0 || CAN_ID == 0)) { + if (valid && ((PDO->mappedObjectsCount == 0) || (CAN_ID == 0))) { valid = false; if (erroneousMap == 0) { erroneousMap = 1; } } @@ -693,14 +693,14 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, if (erroneousMap != 0) { CO_errorReport(PDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, - erroneousMap != 1 ? erroneousMap : COB_ID); + (erroneousMap != 1) ? erroneousMap : COB_ID); } if (!valid) { CAN_ID = 0; } /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ - if (CAN_ID != 0 && CAN_ID == (preDefinedCanId & 0xFF80)) { + if ((CAN_ID != 0) && (CAN_ID == (preDefinedCanId & 0xFF80))) { CAN_ID = preDefinedCanId; } @@ -797,7 +797,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* Verify errors in length of received RPDO CAN message */ if (RPDO->receiveError > CO_RPDO_RX_ACK) { bool_t setError = RPDO->receiveError != CO_RPDO_RX_OK; - uint16_t code = RPDO->receiveError == CO_RPDO_RX_SHORT + uint16_t code = (RPDO->receiveError == CO_RPDO_RX_SHORT) ? CO_EMC_PDO_LENGTH : CO_EMC_PDO_LENGTH_EXC; CO_error(PDO->em, setError, CO_EM_RPDO_WRONG_LENGTH, code, PDO->dataLength); @@ -808,7 +808,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* Determine, which of the two rx buffers contains relevant message. */ uint8_t bufNo = 0; #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if (RPDO->synchronous && RPDO->SYNC != NULL + if (RPDO->synchronous && (RPDO->SYNC != NULL) && !RPDO->SYNC->CANrxToggle) { bufNo = 1; } @@ -894,8 +894,8 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* enable monitoring */ RPDO->timeoutTimer = 1; } - else if (RPDO->timeoutTimer > 0 - && RPDO->timeoutTimer < RPDO->timeoutTime_us + else if ((RPDO->timeoutTimer > 0) + && (RPDO->timeoutTimer < RPDO->timeoutTime_us) ) { RPDO->timeoutTimer += timeDifference_us; @@ -953,7 +953,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* "count" is also verified in *_init() function */ - if (stream == NULL || buf == NULL || countWritten == NULL || count > 4) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4)) { return ODR_DEV_INCOMPAT; } @@ -971,16 +971,16 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, /* bits 11...29 must be zero, PDO must be disabled on change, * CAN_ID == 0 is not allowed, mapping must be configured before * enabling the PDO */ - if ((COB_ID & 0x3FFFF800) != 0 - || (valid && PDO->valid && CAN_ID != PDO->configuredCanId) + if (((COB_ID & 0x3FFFF800) != 0) + || (valid && (PDO->valid && (CAN_ID != PDO->configuredCanId))) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - || (valid && PDO->mappedObjectsCount == 0) + || (valid && (PDO->mappedObjectsCount == 0)) ) { return ODR_INVALID_VALUE; } /* parameter changed? */ - if (valid != PDO->valid || CAN_ID != PDO->configuredCanId) { + if ((valid != PDO->valid) || (CAN_ID != PDO->configuredCanId)) { /* if default CAN-ID is written, store to OD without Node-ID */ if (CAN_ID == PDO->preDefinedCanId) { (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); @@ -1012,8 +1012,8 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if (transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240 - && transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO + if ((transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240) + && (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { return ODR_INVALID_VALUE; } @@ -1056,7 +1056,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, case 6: { /* SYNC start value */ uint8_t syncStartValue = CO_getUint8(buf); - if (PDO->valid || syncStartValue > 240) { + if (PDO->valid || (syncStartValue > 240)) { return ODR_INVALID_VALUE; } TPDO->syncStartValue = syncStartValue; @@ -1092,8 +1092,8 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, ODR_t odRet; /* verify arguments */ - if (TPDO == NULL || OD == NULL || em == NULL || OD_18xx_TPDOCommPar == NULL - || OD_1Axx_TPDOMapPar == NULL || CANdevTx == NULL + if ((TPDO == NULL) || (OD == NULL) || (em == NULL) || (OD_18xx_TPDOCommPar == NULL) + || (OD_1Axx_TPDOMapPar == NULL) || (CANdevTx == NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -1127,9 +1127,9 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, } return CO_ERROR_OD_PARAMETERS; } - if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO + if ((transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - && transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240 + && (transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240) #endif ) { transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; @@ -1149,7 +1149,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, bool_t valid = (COB_ID & 0x80000000) == 0; uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - if (valid && (PDO->mappedObjectsCount == 0 || CAN_ID == 0)) { + if (valid && ((PDO->mappedObjectsCount == 0) || (CAN_ID == 0))) { valid = false; if (erroneousMap == 0) { erroneousMap = 1; } } @@ -1157,14 +1157,14 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, if (erroneousMap != 0) { CO_errorReport(PDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, - erroneousMap != 1 ? erroneousMap : COB_ID); + (erroneousMap != 1) ? erroneousMap : COB_ID); } if (!valid) { CAN_ID = 0; } /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ - if (CAN_ID != 0 && CAN_ID == (preDefinedCanId & 0xFF80)) { + if ((CAN_ID != 0) && (CAN_ID == (preDefinedCanId & 0xFF80))) { CAN_ID = preDefinedCanId; } @@ -1239,8 +1239,8 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { uint8_t *dataTPDO = &TPDO->CANtxBuff->data[0]; #if OD_FLAGS_PDO_SIZE > 0 bool_t eventDriven = - (TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC - || TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO); + ((TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) + || (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)); #endif #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS @@ -1295,7 +1295,7 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { /* In event driven TPDO indicate transmission of OD variable */ #if OD_FLAGS_PDO_SIZE > 0 uint8_t *flagPDObyte = PDO->flagPDObyte[i]; - if (flagPDObyte != NULL && eventDriven) { + if ((flagPDObyte != NULL) && eventDriven) { *flagPDObyte |= PDO->flagPDObitmask[i]; } #endif @@ -1344,8 +1344,8 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, /* check for event timer or application event */ #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || (OD_FLAGS_PDO_SIZE > 0) - if (TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC - || TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO + if ((TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) + || (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { /* event timer */ #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE @@ -1388,7 +1388,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, ? (TPDO->inhibitTimer - timeDifference_us) : 0; /* send TPDO */ - if (TPDO->sendRequest && TPDO->inhibitTimer == 0) { + if (TPDO->sendRequest && (TPDO->inhibitTimer == 0)) { CO_TPDOsend(TPDO); } @@ -1409,7 +1409,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, /* Synchronous PDOs */ #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - else if (TPDO->SYNC != NULL && syncWas) { + else if ((TPDO->SYNC != NULL) && syncWas) { /* send synchronous acyclic TPDO */ if (TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { if (TPDO->sendRequest) { CO_TPDOsend(TPDO); } @@ -1418,15 +1418,15 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, else { /* is the start of synchronous TPDO transmission */ if (TPDO->syncCounter == 255) { - if (TPDO->SYNC->counterOverflowValue != 0 - && TPDO->syncStartValue != 0 + if ((TPDO->SYNC->counterOverflowValue != 0) + && (TPDO->syncStartValue != 0) ) { /* syncStartValue is in use */ TPDO->syncCounter = 254; } else { /* Send first TPDO somewhere in the middle */ - TPDO->syncCounter = TPDO->transmissionType / 2 + 1; + TPDO->syncCounter = (TPDO->transmissionType / 2) + 1; } } /* If the syncStartValue is in use, start first TPDO after SYNC diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 9edad02c..e69466a2 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -67,13 +67,13 @@ static void CO_SDOclient_receive(void *object, void *msg) { /* Ignore messages in idle state and messages with wrong length. Ignore * message also if previous message was not processed yet and not abort */ - if (SDO_C->state != CO_SDO_ST_IDLE && DLC == 8U - && (!CO_FLAG_READ(SDO_C->CANrxNew) || data[0] == 0x80) + if ((SDO_C->state != CO_SDO_ST_IDLE) && (DLC == 8U) + && (!CO_FLAG_READ(SDO_C->CANrxNew) || (data[0] == 0x80)) ) { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - if (data[0] == 0x80 /* abort from server */ - || (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ - && SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP) + if ((data[0] == 0x80) /* abort from server */ + || ((SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) + && (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP)) ) { #endif /* copy data and set 'new message' flag */ @@ -97,8 +97,8 @@ static void CO_SDOclient_receive(void *object, void *msg) { SDO_C->block_timeoutTimer = 0; /* verify if sequence number is correct */ - if (seqno <= SDO_C->block_blksize - && seqno == (SDO_C->block_seqno + 1) + if ((seqno <= SDO_C->block_blksize) + && (seqno == (SDO_C->block_seqno + 1)) ) { SDO_C->block_seqno = seqno; @@ -127,7 +127,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { /* If message is duplicate or sequence didn't start yet, ignore * it. Otherwise seqno is wrong, so break sub-block. Data after * last good seqno will be re-transmitted. */ - else if (seqno != SDO_C->block_seqno && SDO_C->block_seqno != 0U) { + else if ((seqno != SDO_C->block_seqno) && (SDO_C->block_seqno != 0U)) { state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; #ifdef CO_DEBUG_SDO_CLIENT char msg[80]; @@ -177,7 +177,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* "count" is already verified in *_init() function */ - if (stream == NULL || buf == NULL || countWritten == NULL) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } @@ -194,8 +194,8 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, bool_t valid = (COB_ID & 0x80000000) == 0; /* SDO client must not be valid when changing COB_ID */ - if ((COB_ID & 0x3FFFF800) != 0 - || (valid && SDO_C->valid && CAN_ID != CAN_ID_cur) + if (((COB_ID & 0x3FFFF800) != 0) + || (valid && SDO_C->valid && (CAN_ID != CAN_ID_cur)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; @@ -214,8 +214,8 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, bool_t valid = (COB_ID & 0x80000000) == 0; /* SDO client must not be valid when changing COB_ID */ - if ((COB_ID & 0x3FFFF800) != 0 - || (valid && SDO_C->valid && CAN_ID != CAN_ID_cur) + if (((COB_ID & 0x3FFFF800) != 0) + || (valid && SDO_C->valid && (CAN_ID != CAN_ID_cur)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; @@ -258,10 +258,10 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, uint32_t *errInfo) { /* verify arguments */ - if (SDO_C == NULL || OD_1280_SDOcliPar == NULL - || OD_getIndex(OD_1280_SDOcliPar) < OD_H1280_SDO_CLIENT_1_PARAM - || OD_getIndex(OD_1280_SDOcliPar) > (OD_H1280_SDO_CLIENT_1_PARAM + 0x7F) - || CANdevRx==NULL || CANdevTx==NULL + if ((SDO_C == NULL) || (OD_1280_SDOcliPar == NULL) + || (OD_getIndex(OD_1280_SDOcliPar) < OD_H1280_SDO_CLIENT_1_PARAM) + || (OD_getIndex(OD_1280_SDOcliPar) > (OD_H1280_SDO_CLIENT_1_PARAM + 0x7F)) + || (CANdevRx==NULL) || (CANdevTx==NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -292,8 +292,8 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, ODR_t odRet2 = OD_get_u32(OD_1280_SDOcliPar, 2, &COB_IDServerToClient, true); ODR_t odRet3 = OD_get_u8(OD_1280_SDOcliPar, 3, &nodeIDOfTheSDOServer, true); - if (odRet0 != ODR_OK || maxSubIndex != 3 - || odRet1 != ODR_OK || odRet2 != ODR_OK || odRet3 != ODR_OK + if ((odRet0 != ODR_OK) || (maxSubIndex != 3) + || (odRet1 != ODR_OK) || (odRet2 != ODR_OK) || (odRet3 != ODR_OK) ) { if (errInfo != NULL) *errInfo = OD_getIndex(OD_1280_SDOcliPar); return CO_ERROR_OD_PARAMETERS; @@ -373,8 +373,8 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC /* proceed only, if parameters change */ - if (COB_IDClientToServer == SDO_C->COB_IDClientToServer - && COB_IDServerToClient == SDO_C->COB_IDServerToClient + if ((COB_IDClientToServer == SDO_C->COB_IDClientToServer) + && (COB_IDServerToClient == SDO_C->COB_IDServerToClient) ) { return CO_SDO_RT_ok_communicationEnd; } @@ -388,7 +388,7 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, (uint16_t)(COB_IDClientToServer & 0x7FF) : 0; uint16_t CanIdS2C = ((COB_IDServerToClient & 0x80000000L) == 0) ? (uint16_t)(COB_IDServerToClient & 0x7FF) : 0; - if (CanIdC2S != 0 && CanIdS2C != 0) { + if ((CanIdC2S != 0) && (CanIdS2C != 0)) { SDO_C->valid = true; } else { @@ -417,7 +417,7 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, 0); /* synchronous message flag bit */ - if (ret != CO_ERROR_NO || SDO_C->CANtxBuff == NULL) { + if ((ret != CO_ERROR_NO) || (SDO_C->CANtxBuff == NULL)) { SDO_C->valid = false; return CO_SDO_RT_wrongArguments; } @@ -437,7 +437,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, bool_t blockEnable) { /* verify parameters */ - if (SDO_C == NULL || !SDO_C->valid) { + if ((SDO_C == NULL) || !SDO_C->valid) { return CO_SDO_RT_wrongArguments; } @@ -454,8 +454,8 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ - if (SDO_C->OD != NULL && SDO_C->nodeId != 0 - && SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId + if ((SDO_C->OD != NULL) && (SDO_C->nodeId != 0) + && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId) ) { SDO_C->OD_IO.write = NULL; SDO_C->state = CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER; @@ -463,8 +463,8 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, else #endif #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - if (blockEnable && (sizeIndicated == 0 || - sizeIndicated > CO_CONFIG_SDO_CLI_PST) + if (blockEnable && ((sizeIndicated == 0) || + (sizeIndicated > CO_CONFIG_SDO_CLI_PST)) ) { SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ; } @@ -486,8 +486,8 @@ void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, if (SDO_C != NULL) { SDO_C->sizeInd = sizeIndicated; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ - && sizeIndicated > 0 && sizeIndicated <= CO_CONFIG_SDO_CLI_PST + if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ) + && (sizeIndicated > 0) && (sizeIndicated <= CO_CONFIG_SDO_CLI_PST) ) { SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; } @@ -502,7 +502,7 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, size_t count) { size_t ret = 0; - if (SDO_C != NULL && buf != NULL) { + if ((SDO_C != NULL) && (buf != NULL)) { ret = CO_fifo_write(&SDO_C->bufFifo, buf, count, NULL); } return ret; @@ -523,7 +523,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; - if (SDO_C == NULL || !SDO_C->valid) { + if ((SDO_C == NULL) || !SDO_C->valid) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_wrongArguments; } @@ -532,7 +532,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ - else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER && !abort) { + else if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) && !abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.write == NULL) { ODR_t odRet; @@ -571,14 +571,14 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, ret = CO_SDO_RT_endedWithClientAbort; } /* verify if sizeTran is too large */ - else if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + else if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { SDO_C->sizeTran -= count; abortCode = CO_SDO_AB_DATA_LONG; ret = CO_SDO_RT_endedWithClientAbort; } /* Verify sizeTran is too small in last segment of data */ else if (!bufferPartial - && SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd + && (SDO_C->sizeInd > 0) && (SDO_C->sizeTran < SDO_C->sizeInd) ) { abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; @@ -597,12 +597,12 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, * shorter than size of OD data buffer. If so, add two zero * bytes to terminate (unicode) string. Shorten also OD data * size, (temporary, send info about EOF into OD_IO.write) */ - if ((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0 - && (sizeInOd == 0 || SDO_C->sizeTran < sizeInOd) + if (((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0) + && ((sizeInOd == 0) || (SDO_C->sizeTran < sizeInOd)) ) { buf[count++] = 0; SDO_C->sizeTran++; - if (sizeInOd == 0 || sizeInOd > SDO_C->sizeTran) { + if ((sizeInOd == 0) || (sizeInOd > SDO_C->sizeTran)) { buf[count++] = 0; SDO_C->sizeTran++; } @@ -629,13 +629,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, CO_UNLOCK_OD(SDO_C->CANdevTx); /* verify for errors in write */ - if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + if ((odRet != ODR_OK) && (odRet != ODR_PARTIAL)) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithServerAbort; } /* error if OD variable was written completely, * but SDO download still has data */ - else if (bufferPartial && odRet == ODR_OK) { + else if (bufferPartial && (odRet == ODR_OK)) { abortCode = CO_SDO_AB_DATA_LONG; ret = CO_SDO_RT_endedWithClientAbort; } @@ -693,7 +693,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, index = ((uint16_t) SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; - if (index != SDO_C->index || subindex != SDO_C->subIndex) { + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { abortCode = CO_SDO_AB_PRAM_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -761,7 +761,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, index = ((uint16_t) SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; - if (index != SDO_C->index || subindex != SDO_C->subIndex) { + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { abortCode = CO_SDO_AB_PRAM_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -769,7 +769,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->block_crc = 0; SDO_C->block_blksize = SDO_C->CANrxData[4]; - if (SDO_C->block_blksize < 1 || SDO_C->block_blksize > 127) + if ((SDO_C->block_blksize < 1) || (SDO_C->block_blksize > 127)) SDO_C->block_blksize = 127; SDO_C->block_seqno = 0; CO_fifo_altBegin(&SDO_C->bufFifo, 0); @@ -791,7 +791,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, * Re-transmit data after erroneous segment. */ size_t cntFailed = SDO_C->block_seqno - SDO_C->CANrxData[1]; - cntFailed = cntFailed * 7 - SDO_C->block_noData; + cntFailed = (cntFailed * 7) - SDO_C->block_noData; SDO_C->sizeTran -= cntFailed; CO_fifo_altBegin(&SDO_C->bufFifo, (size_t)SDO_C->CANrxData[1] * 7); @@ -892,14 +892,14 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, count = CO_fifo_getOccupied(&SDO_C->bufFifo); /* is expedited transfer, <= 4bytes of data */ - if ((SDO_C->sizeInd == 0 && count <= 4) - || (SDO_C->sizeInd > 0 && SDO_C->sizeInd <= 4) + if (((SDO_C->sizeInd == 0) && (count <= 4)) + || ((SDO_C->sizeInd > 0) && (SDO_C->sizeInd <= 4)) ) { SDO_C->CANtxBuff->data[0] |= 0x02; /* verify length, indicate data size */ - if (count == 0 || (SDO_C->sizeInd > 0 && - SDO_C->sizeInd != count) + if ((count == 0) || ((SDO_C->sizeInd > 0) && + (SDO_C->sizeInd != count)) ) { SDO_C->state = CO_SDO_ST_IDLE; abortCode = CO_SDO_AB_TYPE_MISMATCH; @@ -948,7 +948,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* verify if sizeTran is too large */ SDO_C->sizeTran += count; - if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { SDO_C->sizeTran -= count; abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; @@ -959,8 +959,8 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[0] = (uint8_t)(SDO_C->toggle | ((7 - count) << 1)); /* is end of transfer? Verify also sizeTran */ - if (CO_fifo_getOccupied(&SDO_C->bufFifo) == 0 && !bufferPartial) { - if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) { + if ((CO_fifo_getOccupied(&SDO_C->bufFifo) == 0) && !bufferPartial) { + if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran < SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -999,7 +999,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { - if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) < 7 && bufferPartial) { + if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) < 7) && bufferPartial) { /* wait until data are refilled */ break; } @@ -1012,7 +1012,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* verify if sizeTran is too large */ SDO_C->sizeTran += count; - if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { SDO_C->sizeTran -= count; abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; @@ -1020,8 +1020,8 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* is end of transfer? Verify also sizeTran */ - if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0 && !bufferPartial){ - if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) { + if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0) && !bufferPartial){ + if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran < SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -1109,7 +1109,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, bool_t blockEnable) { /* verify parameters */ - if (SDO_C == NULL || !SDO_C->valid) { + if ((SDO_C == NULL) || !SDO_C->valid) { return CO_SDO_RT_wrongArguments; } @@ -1129,8 +1129,8 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ - if (SDO_C->OD != NULL && SDO_C->nodeId != 0 - && SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId + if (((SDO_C->OD != NULL) && (SDO_C->nodeId != 0)) + && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId) ) { SDO_C->OD_IO.read = NULL; SDO_C->state = CO_SDO_ST_UPLOAD_LOCAL_TRANSFER; @@ -1167,7 +1167,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; - if (SDO_C == NULL || !SDO_C->valid) { + if ((SDO_C == NULL) || !SDO_C->valid) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_wrongArguments; } @@ -1176,7 +1176,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* Transfer data locally **************************************************/ - else if (SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER && !abort) { + else if ((SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) && !abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.read == NULL) { ODR_t odRet; @@ -1213,7 +1213,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* Get size of data in Object Dictionary. If size is not indicated * use maximum SDO client buffer size. Prepare temp buffer. */ OD_size_t countData = SDO_C->OD_IO.stream.dataLength; - OD_size_t countBuf = (countData > 0 && countData <= countFifo) + OD_size_t countBuf = ((countData > 0) && (countData <= countFifo)) ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; @@ -1224,14 +1224,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, buf, countBuf, &countRd); CO_UNLOCK_OD(SDO_C->CANdevTx); - if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + if ((odRet != ODR_OK) && (odRet != ODR_PARTIAL)) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithServerAbort; } else { /* if data is string, send only data up to null termination */ - if (countRd > 0 - && (SDO_C->OD_IO.stream.attribute & ODA_STR) != 0 + if ((countRd > 0) + && ((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0) ) { buf[countRd] = 0; /* (buf is one byte larger) */ OD_size_t countStr = (OD_size_t)strlen((char *)buf); @@ -1250,14 +1250,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* verify if size of data uploaded is too large */ SDO_C->sizeInd = SDO_C->OD_IO.stream.dataLength; - if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_LONG; ret = CO_SDO_RT_endedWithClientAbort; } /* If no more segments to be upload, finish */ else if (odRet == ODR_OK) { /* verify size of data uploaded */ - if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd){ + if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran < SDO_C->sizeInd)){ abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; } @@ -1271,8 +1271,8 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } } - if (ret != CO_SDO_RT_uploadDataBufferFull - && ret != CO_SDO_RT_waitingLocalTransfer + if ((ret != CO_SDO_RT_uploadDataBufferFull) + && (ret != CO_SDO_RT_waitingLocalTransfer) ) { SDO_C->state = CO_SDO_ST_IDLE; } @@ -1308,7 +1308,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, index = ((uint16_t) SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; - if (index != SDO_C->index || subindex != SDO_C->subIndex) { + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { abortCode = CO_SDO_AB_PRAM_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -1381,8 +1381,8 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* verify if size of data uploaded is too large */ - if (SDO_C->sizeInd > 0 - && SDO_C->sizeTran > SDO_C->sizeInd + if ((SDO_C->sizeInd > 0) + && (SDO_C->sizeTran > SDO_C->sizeInd) ) { abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; @@ -1392,8 +1392,8 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* If no more segments to be upload, finish */ if (SDO_C->CANrxData[0] & 0x01) { /* verify size of data uploaded */ - if (SDO_C->sizeInd > 0 - && SDO_C->sizeTran < SDO_C->sizeInd + if ((SDO_C->sizeInd > 0) + && (SDO_C->sizeTran < SDO_C->sizeInd) ) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; @@ -1436,7 +1436,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, index = ((uint16_t) SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; - if (index != SDO_C->index || subindex != SDO_C->subIndex) { + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { abortCode = CO_SDO_AB_PRAM_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; } @@ -1452,7 +1452,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, index = ((uint16_t) SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; - if (index != SDO_C->index || subindex != SDO_C->subIndex) { + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { abortCode = CO_SDO_AB_PRAM_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -1508,8 +1508,8 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->sizeTran += 7 - noData; /* verify length */ - if (SDO_C->sizeInd > 0 - && SDO_C->sizeTran != SDO_C->sizeInd + if ((SDO_C->sizeInd > 0) + && (SDO_C->sizeTran != SDO_C->sizeInd) ) { abortCode = (SDO_C->sizeTran > SDO_C->sizeInd) ? CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; @@ -1560,8 +1560,8 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->timeoutTimer += timeDifference_us; } if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { - if (SDO_C->state == CO_SDO_ST_UPLOAD_SEGMENT_REQ || - SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP + if ((SDO_C->state == CO_SDO_ST_UPLOAD_SEGMENT_REQ) || + (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP) ) { /* application didn't empty buffer */ abortCode = CO_SDO_AB_GENERAL; @@ -1706,7 +1706,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else { /* verify if size of data uploaded is too large */ - if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) { + if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -1819,7 +1819,7 @@ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, size_t count) { size_t ret = 0; - if (SDO_C != NULL && buf != NULL) { + if ((SDO_C != NULL) && (buf != NULL)) { ret = CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); } return ret; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index e93c6abe..afb9c174 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -173,8 +173,8 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, { #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC /* proceed only, if parameters change */ - if (COB_IDClientToServer == SDO->COB_IDClientToServer - && COB_IDServerToClient == SDO->COB_IDServerToClient + if ((COB_IDClientToServer == SDO->COB_IDClientToServer) + && (COB_IDServerToClient == SDO->COB_IDServerToClient) ) { return CO_ERROR_NO; } @@ -188,7 +188,7 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, (uint16_t)COB_IDClientToServer : 0; uint16_t idS2C = ((COB_IDServerToClient & 0x80000000L) == 0) ? (uint16_t)COB_IDServerToClient : 0; - if (idC2S != 0 && idS2C != 0) { + if ((idC2S != 0) && (idS2C != 0)) { SDO->valid = true; } else { @@ -236,7 +236,7 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* "count" is already verified in *_init() function */ - if (stream == NULL || buf == NULL || countWritten == NULL) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } @@ -254,8 +254,8 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, bool_t valid = (COB_ID & 0x80000000) == 0; /* SDO client must not be valid when changing COB_ID */ - if ((COB_ID & 0x3FFFF800) != 0 - || (valid && SDO->valid && CAN_ID != CAN_ID_cur) + if (((COB_ID & 0x3FFFF800) != 0) + || ((valid && SDO->valid) && (CAN_ID != CAN_ID_cur)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; @@ -276,8 +276,8 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, bool_t valid = (COB_ID & 0x80000000) == 0; /* SDO client must not be valid when changing COB_ID */ - if ((COB_ID & 0x3FFFF800) != 0 - || (valid && SDO->valid && CAN_ID != CAN_ID_cur) + if (((COB_ID & 0x3FFFF800) != 0) + || (valid && (SDO->valid && (CAN_ID != CAN_ID_cur))) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { return ODR_INVALID_VALUE; @@ -296,7 +296,7 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, return ODR_TYPE_MISMATCH; } uint8_t nodeId = CO_getUint8(buf); - if (nodeId < 1 || nodeId > 127) { + if ((nodeId < 1) || (nodeId > 127)) { return ODR_INVALID_VALUE; } break; @@ -325,7 +325,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, uint32_t *errInfo) { /* verify arguments */ - if (SDO == NULL || OD == NULL || CANdevRx == NULL || CANdevTx == NULL) { + if ((SDO == NULL) || (OD == NULL) || (CANdevRx == NULL) || (CANdevTx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -350,7 +350,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (OD_1200_SDOsrvPar == NULL) { /* configure default SDO channel */ - if (nodeId < 1 || nodeId > 127) { return CO_ERROR_ILLEGAL_ARGUMENT; } + if ((nodeId < 1) || (nodeId > 127)) { return CO_ERROR_ILLEGAL_ARGUMENT; } CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; @@ -361,7 +361,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (OD_SDOsrvParIdx == OD_H1200_SDO_SERVER_1_PARAM) { /* configure default SDO channel and SDO server parameters for it */ - if (nodeId < 1 || nodeId > 127) { + if ((nodeId < 1) || (nodeId > 127)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -372,8 +372,8 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); OD_set_u32(OD_1200_SDOsrvPar, 2, CanId_ServerToClient, true); } - else if (OD_SDOsrvParIdx > OD_H1200_SDO_SERVER_1_PARAM - && OD_SDOsrvParIdx <= (OD_H1200_SDO_SERVER_1_PARAM + 0x7F) + else if ((OD_SDOsrvParIdx > OD_H1200_SDO_SERVER_1_PARAM) + && (OD_SDOsrvParIdx <= (OD_H1200_SDO_SERVER_1_PARAM + 0x7F)) ) { /* configure additional SDO channel and SDO server parameters for it */ uint8_t maxSubIndex; @@ -386,8 +386,8 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, ODR_t odRet2 = OD_get_u32(OD_1200_SDOsrvPar, 2, &COB_IDServerToClient32, true); - if (odRet0 != ODR_OK || (maxSubIndex != 2 && maxSubIndex != 3) - || odRet1 != ODR_OK || odRet2 != ODR_OK + if ((odRet0 != ODR_OK) || ((maxSubIndex != 2) && (maxSubIndex != 3)) + || (odRet1 != ODR_OK) || (odRet2 != ODR_OK) ) { if (errInfo != NULL) { *errInfo = OD_SDOsrvParIdx; } return CO_ERROR_OD_PARAMETERS; @@ -485,7 +485,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, if (SDO->finished) { /* Verify if size of data downloaded matches size indicated. */ - if (SDO->sizeInd > 0 && SDO->sizeTran != SDO->sizeInd) { + if ((SDO->sizeInd > 0) && (SDO->sizeTran != SDO->sizeInd)) { *abortCode = (SDO->sizeTran > SDO->sizeInd) ? CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; @@ -505,13 +505,13 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, * shorter than size of OD data buffer. If so, add two zero bytes * to terminate (unicode) string. Shorten also OD data size, * (temporary, send information about EOF into OD_IO.write) */ - if ((SDO->OD_IO.stream.attribute & ODA_STR) != 0 - && (sizeInOd == 0 || SDO->sizeTran < sizeInOd) - && (SDO->bufOffsetWr + 2) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE + if (((SDO->OD_IO.stream.attribute & ODA_STR) != 0) + && ((sizeInOd == 0) || (SDO->sizeTran < sizeInOd)) + && ((SDO->bufOffsetWr + 2) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE) ) { SDO->buf[SDO->bufOffsetWr++] = 0; SDO->sizeTran++; - if (sizeInOd == 0 || SDO->sizeTran < sizeInOd) { + if ((sizeInOd == 0) || (SDO->sizeTran < sizeInOd)) { SDO->buf[SDO->bufOffsetWr++] = 0; SDO->sizeTran++; } @@ -532,7 +532,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, } else { /* Verify if size of data downloaded is not too large. */ - if (SDO->sizeInd > 0 && SDO->sizeTran > SDO->sizeInd) { + if ((SDO->sizeInd > 0) && (SDO->sizeTran > SDO->sizeInd)) { *abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; return false; @@ -564,18 +564,18 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, SDO->bufOffsetWr = 0; /* verify write error value */ - if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + if ((odRet != ODR_OK) && (odRet != ODR_PARTIAL)) { *abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); SDO->state = CO_SDO_ST_ABORT; return false; } - else if (SDO->finished && odRet == ODR_PARTIAL) { + else if (SDO->finished && (odRet == ODR_PARTIAL)) { /* OD variable was not written completely, but SDO download finished */ *abortCode = CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; return false; } - else if (!SDO->finished && odRet == ODR_OK) { + else if (!SDO->finished && (odRet == ODR_OK)) { /* OD variable was written completely, but SDO download still has data*/ *abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; @@ -605,7 +605,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, { OD_size_t countRemain = SDO->bufOffsetWr - SDO->bufOffsetRd; - if (!SDO->finished && countRemain < countMinimum) { + if (!SDO->finished && (countRemain < countMinimum)) { /* first move remaining data to the start of the buffer */ (void)memmove(SDO->buf, SDO->buf + SDO->bufOffsetRd, countRemain); SDO->bufOffsetRd = 0; @@ -623,14 +623,14 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, countRdRequest, &countRd); CO_UNLOCK_OD(SDO->CANdevTx); - if (odRet != ODR_OK && odRet != ODR_PARTIAL) { + if ((odRet != ODR_OK) && (odRet != ODR_PARTIAL)) { *abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); SDO->state = CO_SDO_ST_ABORT; return false; } /* if data is string, send only data up to null termination */ - if (countRd > 0 && (SDO->OD_IO.stream.attribute & ODA_STR) != 0) { + if ((countRd > 0) && ((SDO->OD_IO.stream.attribute & ODA_STR) != 0)) { bufShifted[countRd] = 0; /* (SDO->buf is one byte larger) */ OD_size_t countStr = (OD_size_t)strlen((char *)bufShifted); if (countStr == 0) { countStr = 1; }/* zero length is not allowed */ @@ -644,7 +644,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* partial or finished read */ SDO->bufOffsetWr = countRemain + countRd; - if (SDO->bufOffsetWr == 0 || odRet == ODR_PARTIAL) { + if ((SDO->bufOffsetWr == 0) || (odRet == ODR_PARTIAL)) { SDO->finished = false; if (SDO->bufOffsetWr < countMinimum) { *abortCode = CO_SDO_AB_DEVICE_INCOMPAT; @@ -701,7 +701,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, bool_t isNew = CO_FLAG_READ(SDO->CANrxNew); - if (SDO->valid && SDO->state == CO_SDO_ST_IDLE && !isNew) { + if (SDO->valid && (SDO->state == CO_SDO_ST_IDLE) && !isNew) { /* Idle and nothing new */ ret = CO_SDO_RT_ok_communicationEnd; } @@ -741,7 +741,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* if no error search object dictionary for new SDO request */ if (abortCode == CO_SDO_AB_NONE) { ODR_t odRet; - SDO->index = ((uint16_t)SDO->CANrxData[2]) << 8 + SDO->index = (((uint16_t)SDO->CANrxData[2]) << 8) | SDO->CANrxData[1]; SDO->subIndex = SDO->CANrxData[3]; odRet = OD_getSub(OD_find(SDO->OD, SDO->index), SDO->subIndex, @@ -757,13 +757,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; } else if (upload - && (SDO->OD_IO.stream.attribute & ODA_SDO_R) == 0 + && ((SDO->OD_IO.stream.attribute & ODA_SDO_R) == 0) ) { abortCode = CO_SDO_AB_WRITEONLY; SDO->state = CO_SDO_ST_ABORT; } else if (!upload - && (SDO->OD_IO.stream.attribute & ODA_SDO_W) == 0 + && ((SDO->OD_IO.stream.attribute & ODA_SDO_W) == 0) ) { abortCode = CO_SDO_AB_READONLY; SDO->state = CO_SDO_ST_ABORT; @@ -774,7 +774,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED /* load data from object dictionary, if upload and no error */ - if (upload && abortCode == CO_SDO_AB_NONE) { + if (upload && (abortCode == CO_SDO_AB_NONE)) { SDO->bufOffsetRd = SDO->bufOffsetWr = 0; SDO->sizeTran = 0; SDO->finished = false; @@ -797,7 +797,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } else { /* If data type is string, size is not known */ - SDO->sizeInd = (SDO->OD_IO.stream.attribute&ODA_STR)==0 + SDO->sizeInd = ((SDO->OD_IO.stream.attribute&ODA_STR)==0) ? SDO->OD_IO.stream.dataLength : 0; } @@ -806,7 +806,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ } /* (SDO->state == CO_SDO_ST_IDLE) */ - if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) { + if ((SDO->state != CO_SDO_ST_IDLE) && (SDO->state != CO_SDO_ST_ABORT)) { switch (SDO->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { if (SDO->CANrxData[0] & 0x02) { @@ -820,7 +820,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if (SDO->CANrxData[0] & 0x01) { dataSizeToWrite -= (SDO->CANrxData[0] >> 2) & 0x03; } - else if (sizeInOd > 0 && sizeInOd < 4) { + else if ((sizeInOd > 0) && (sizeInOd < 4)) { dataSizeToWrite = sizeInOd; } else { /* MISRA C 2004 14.10 */ } @@ -838,11 +838,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, * shorter as size of OD data buffer. If so, add two zero bytes * to terminate (unicode) string. Shorten also OD data size, * (temporary, send information about EOF into OD_IO.write) */ - if ((SDO->OD_IO.stream.attribute & ODA_STR) != 0 - && (sizeInOd == 0 || dataSizeToWrite < sizeInOd) + if (((SDO->OD_IO.stream.attribute & ODA_STR) != 0) + && ((sizeInOd == 0) || (dataSizeToWrite < sizeInOd)) ) { OD_size_t delta = sizeInOd - dataSizeToWrite; - dataSizeToWrite += delta == 1 ? 1 : 2; + dataSizeToWrite += (delta == 1) ? 1 : 2; SDO->OD_IO.stream.dataLength = dataSizeToWrite; } else if (sizeInOd == 0) { @@ -895,8 +895,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } /* strings are allowed to be shorter */ - else if (SDO->sizeInd < sizeInOd - && (SDO->OD_IO.stream.attribute & ODA_STR) == 0 + else if ((SDO->sizeInd < sizeInOd) + && ((SDO->OD_IO.stream.attribute & ODA_STR) == 0) ) { abortCode = CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; @@ -938,8 +938,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->sizeTran += count; /* if data size exceeds variable size, abort */ - if (SDO->OD_IO.stream.dataLength > 0 - && SDO->sizeTran > SDO->OD_IO.stream.dataLength + if ((SDO->OD_IO.stream.dataLength > 0) + && (SDO->sizeTran > SDO->OD_IO.stream.dataLength) ) { abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; @@ -948,7 +948,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* if necessary, empty the buffer */ if (SDO->finished - || (CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7+2) + || ((CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7+2)) ) { if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) { break; @@ -1285,7 +1285,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_UPLOAD_INITIATE_RSP: { #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED /* data were already loaded from OD variable */ - if (SDO->sizeInd > 0 && SDO->sizeInd <= 4) { + if ((SDO->sizeInd > 0) && (SDO->sizeInd <= 4)) { /* expedited transfer */ SDO->CANtxBuff->data[0] = (uint8_t)(0x43|((4-SDO->sizeInd)<<2)); (void)memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, SDO->sizeInd); @@ -1364,7 +1364,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; /* verify, if this is the last segment */ - if (count < 7 || (SDO->finished && count == 7)) { + if ((count < 7) || (SDO->finished && (count == 7))) { /* indicate last segment and nnn */ SDO->CANtxBuff->data[0] |= ((7 - count) << 1) | 0x01; SDO->state = CO_SDO_ST_IDLE; @@ -1389,8 +1389,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; break; } - else if (ret == CO_SDO_RT_ok_communicationEnd - && SDO->sizeTran < SDO->sizeInd + else if ((ret == CO_SDO_RT_ok_communicationEnd) + && (SDO->sizeTran < SDO->sizeInd) ) { abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_waitingResponse; diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index fcdb33cf..42dce65e 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -83,8 +83,8 @@ static void CO_SYNC_receive(void *object, void *msg) { static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count != sizeof(uint32_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -102,7 +102,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, return ODR_INVALID_VALUE; } #else - if ((cobIdSync & 0xFFFFF800) != 0 || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { + if (((cobIdSync & 0xFFFFF800) != 0) || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { return ODR_INVALID_VALUE; } #endif @@ -219,11 +219,11 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, ODR_t odRet; /* verify arguments */ - if (SYNC == NULL || em == NULL || OD_1005_cobIdSync == NULL + if ((SYNC == NULL) || (em == NULL) || (OD_1005_cobIdSync == NULL) #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER - || OD_1006_commCyclePeriod == NULL || CANdevTx == NULL + || (OD_1006_commCyclePeriod == NULL) || (CANdevTx == NULL) #endif - || CANdevRx == NULL + || (CANdevRx == NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -257,7 +257,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, return CO_ERROR_OD_PARAMETERS; } #else - if (OD_1006_commCyclePeriod != NULL && SYNC->OD_1006_period == NULL) { + if ((OD_1006_commCyclePeriod != NULL) && (SYNC->OD_1006_period == NULL)) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1006_commCyclePeriod); } @@ -268,7 +268,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, /* get "Synchronous window length" from OD (optional parameter) */ SYNC->OD_1007_window = OD_getPtr(OD_1007_syncWindowLen, 0, sizeof(uint32_t), NULL); - if (OD_1007_syncWindowLen != NULL && SYNC->OD_1007_window == NULL) { + if ((OD_1007_syncWindowLen != NULL) && (SYNC->OD_1007_window == NULL)) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1007_syncWindowLen); } @@ -385,7 +385,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, CO_FLAG_CLEAR(SYNC->CANrxNew); } - uint32_t OD_1006_period = SYNC->OD_1006_period != NULL + uint32_t OD_1006_period = (SYNC->OD_1006_period != NULL) ? *SYNC->OD_1006_period : 0; if (OD_1006_period > 0) { @@ -434,8 +434,8 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } /* if (OD_1006_period > 0) */ /* Synchronous PDOs are allowed only inside time window */ - if (SYNC->OD_1007_window != NULL && *SYNC->OD_1007_window > 0 - && SYNC->timer > *SYNC->OD_1007_window + if ((SYNC->OD_1007_window != NULL) && (*SYNC->OD_1007_window > 0) + && (SYNC->timer > *SYNC->OD_1007_window) ) { if (!SYNC->syncIsOutsideWindow) { syncStatus = CO_SYNC_PASSED_WINDOW; diff --git a/301/CO_TIME.c b/301/CO_TIME.c index dcc1a8a3..fe8da0e4 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -64,8 +64,8 @@ static void CO_TIME_receive(void *object, void *msg) { static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count != sizeof(uint32_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -75,7 +75,7 @@ static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, /* verify written value */ uint32_t cobIdTimeStamp = CO_getUint32(buf); uint16_t CAN_ID = cobIdTimeStamp & 0x7FF; - if ((cobIdTimeStamp & 0x3FFFF800) != 0 || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { + if (((cobIdTimeStamp & 0x3FFFF800) != 0) || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { return ODR_INVALID_VALUE; } @@ -100,7 +100,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, uint32_t *errInfo) { /* verify arguments */ - if (TIME == NULL || OD_1012_cobIdTimeStamp == NULL || CANdevRx == NULL + if ((TIME == NULL) || (OD_1012_cobIdTimeStamp == NULL) || (CANdevRx == NULL) #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER || CANdevTx == NULL #endif @@ -203,7 +203,7 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, /* Update time */ uint32_t ms = 0; - if (!timestampReceived && timeDifference_us > 0) { + if (!timestampReceived && (timeDifference_us > 0)) { uint32_t us = timeDifference_us + TIME->residual_us; ms = us / 1000; TIME->residual_us = us % 1000; diff --git a/301/CO_driver.h b/301/CO_driver.h index 559e616f..99830b10 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -506,12 +506,12 @@ typedef enum { * They shall not be used for SYNC, TIME, EMCY, PDO and SDO. */ #ifndef CO_IS_RESTRICTED_CAN_ID -#define CO_IS_RESTRICTED_CAN_ID(CAN_ID) ((CAN_ID) <= 0x7F \ - || ((CAN_ID) >= 0x101 && (CAN_ID) <= 0x180) \ - || ((CAN_ID) >= 0x581 && (CAN_ID) <= 0x5FF) \ - || ((CAN_ID) >= 0x601 && (CAN_ID) <= 0x67F) \ - || ((CAN_ID) >= 0x6E0 && (CAN_ID) <= 0x6FF) \ - || (CAN_ID) >= 0x701) +#define CO_IS_RESTRICTED_CAN_ID(CAN_ID) (((CAN_ID) <= 0x7F) \ + || (((CAN_ID) >= 0x101) && ((CAN_ID) <= 0x180)) \ + || (((CAN_ID) >= 0x581) && ((CAN_ID) <= 0x5FF)) \ + || (((CAN_ID) >= 0x601) && ((CAN_ID) <= 0x67F)) \ + || (((CAN_ID) >= 0x6E0) && ((CAN_ID) <= 0x6FF)) \ + || ((CAN_ID) >= 0x701)) #endif diff --git a/301/CO_fifo.c b/301/CO_fifo.c index e9266724..12cb414c 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -54,7 +54,7 @@ /******************************************************************************/ void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize) { - if (fifo == NULL || buf == NULL || bufSize < 2) { + if ((fifo == NULL) || (buf == NULL) || (bufSize < 2)) { return; } @@ -88,7 +88,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, size_t i; uint8_t *bufDest; - if (fifo == NULL || fifo->buf == NULL || buf == NULL) { + if ((fifo == NULL) || (fifo->buf == NULL) || (buf == NULL)) { return 0; } @@ -97,8 +97,8 @@ size_t CO_fifo_write(CO_fifo_t *fifo, size_t writePtrNext = fifo->writePtr + 1; /* is circular buffer full */ - if (writePtrNext == fifo->readPtr || - (writePtrNext == fifo->bufSize && fifo->readPtr == 0)) { + if ((writePtrNext == fifo->readPtr) || + ((writePtrNext == fifo->bufSize) && (fifo->readPtr == 0))) { break; } @@ -134,7 +134,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { if (eof != NULL) { *eof = false; } - if (fifo == NULL || buf == NULL || fifo->readPtr == fifo->writePtr) { + if ((fifo == NULL) || (buf == NULL) || (fifo->readPtr == fifo->writePtr)) { return 0; } @@ -161,7 +161,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { #if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS /* is delimiter? */ - if (eof != NULL && c == DELIM_COMMAND) { + if ((eof != NULL) && (c == DELIM_COMMAND)) { *eof = true; break; } @@ -261,7 +261,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { size_t count; uint8_t *commandEnd; - if (fifo == NULL || fifo->readPtr == fifo->writePtr) { + if ((fifo == NULL) || (fifo->readPtr == fifo->writePtr)) { return 0; } @@ -282,12 +282,12 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { commandEnd = (uint8_t *)memchr((const void *)&fifo->buf[0], (int)DELIM_COMMAND, fifo->writePtr); - if (commandEnd != NULL || fifo->readPtr == (fifo->writePtr + 1)) { + if ((commandEnd != NULL) || (fifo->readPtr == (fifo->writePtr + 1))) { /* command delimiter found or buffer full */ newCommand = true; } } - else if (fifo->readPtr == 0 && fifo->writePtr == (fifo->bufSize - 1)) { + else if ((fifo->readPtr == 0) && (fifo->writePtr == (fifo->bufSize - 1))) { /* buffer full */ newCommand = true; } @@ -313,14 +313,14 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { bool_t delimCommandFound = false; - if (fifo != NULL && insideComment != NULL) { + if ((fifo != NULL) && (insideComment != NULL)) { while (fifo->readPtr != fifo->writePtr) { uint8_t c = fifo->buf[fifo->readPtr]; if (c == DELIM_COMMENT) { *insideComment = true; } - else if (isgraph((int)c) != 0 && !(*insideComment)) { + else if ((isgraph((int)c) != 0) && !(*insideComment)) { break; } if (++fifo->readPtr == fifo->bufSize) { @@ -348,8 +348,8 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, bool_t delimCommentFound = false; size_t tokenSize = 0; - if (fifo != NULL && buf != NULL && count > 1 && (err == NULL || *err == 0) - && fifo->readPtr != fifo->writePtr + if ((fifo != NULL) && (buf != NULL) && (count > 1) && ((err == NULL) || (*err == 0)) + && (fifo->readPtr != fifo->writePtr) ) { bool_t finished = false; uint8_t step = 0; @@ -438,10 +438,10 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, } /* set 'err' return value */ - if (err != NULL && *err == false) { - if (tokenSize == count || (closed != NULL && - ((*closed == 1 && (!delimCommandFound || tokenSize == 0)) || - (*closed == 0 && (delimCommandFound || tokenSize == 0))) + if ((err != NULL) && (*err == false)) { + if ((tokenSize == count) || ((closed != NULL) && + (((*closed == 1) && (!delimCommandFound || (tokenSize == 0))) || + ((*closed == 0) && (delimCommandFound || (tokenSize == 0)))) )) { *err = true; } @@ -456,7 +456,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, tokenSize = 0; } /* write string terminator character */ - if (buf != NULL && count > tokenSize) { + if ((buf != NULL) && (count > tokenSize)) { buf[tokenSize] = '\0'; } @@ -488,7 +488,7 @@ static const uint8_t base64DecTable[] = { size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; - if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 6) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, &n, sizeof(n), NULL); return sprintf(buf, "%"PRIu8, n); } @@ -500,7 +500,7 @@ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; - if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 8) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); } @@ -512,7 +512,7 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; - if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 12) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); } @@ -524,7 +524,7 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; - if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 20) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); } @@ -536,7 +536,7 @@ size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; - if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 6) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%02"PRIX8, n); } @@ -548,7 +548,7 @@ size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; - if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 8) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); } @@ -560,7 +560,7 @@ size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; - if (fifo != NULL && count >= 12 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 12) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); } @@ -572,7 +572,7 @@ size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; - if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 20) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); } @@ -584,7 +584,7 @@ size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int8_t n=0; - if (fifo != NULL && count >= 6 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 6) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId8, n); } @@ -596,7 +596,7 @@ size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int16_t n=0; - if (fifo != NULL && count >= 8 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 8) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId16, CO_SWAP_16(n)); } @@ -608,7 +608,7 @@ size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int32_t n=0; - if (fifo != NULL && count >= 13 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 13) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId32, CO_SWAP_32(n)); } @@ -620,7 +620,7 @@ size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int64_t n=0; - if (fifo != NULL && count >= 23 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 23) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId64, CO_SWAP_64(n)); } @@ -632,7 +632,7 @@ size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float32_t n=0; - if (fifo != NULL && count >= 20 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 20) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", (double)CO_SWAP_32(n)); } @@ -644,7 +644,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float64_t n=0; - if (fifo != NULL && count >= 30 && CO_fifo_getOccupied(fifo) == sizeof(n)) { + if ((fifo != NULL) && (count >= 30) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", (double)CO_SWAP_64(n)); } @@ -658,7 +658,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t len = 0; - if (fifo != NULL && count > 3) { + if ((fifo != NULL) && (count > 3)) { /* Very first write is without leading space */ if (!fifo->started) { uint8_t c; @@ -683,7 +683,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t len = 0; - if (fifo != NULL && count > 3) { + if ((fifo != NULL) && (count > 3)) { /* Start with '"' */ if (!fifo->started) { buf[len++] = '"'; @@ -698,7 +698,7 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } break; } - else if (c != 0 && c != (uint8_t)'\r') { + else if ((c != 0) && (c != (uint8_t)'\r')) { /* skip null and CR inside string */ buf[len++] = (char)c; if (c == DELIM_DQUOTE) { @@ -716,7 +716,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t len = 0; - if (fifo != NULL && count >= 4) { + if ((fifo != NULL) && (count >= 4)) { uint8_t step; uint16_t word; @@ -775,7 +775,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } /* memorize variables for next iteration */ - fifo->aux = (uint32_t)step << 16 | word; + fifo->aux = ((uint32_t)step << 16) | word; } return len; @@ -790,11 +790,11 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if (sRet != strchr(buf, '\0') || u32 > UINT8_MAX) st |= CO_fifo_st_errVal; + if ((sRet != strchr(buf, '\0')) || (u32 > UINT8_MAX)) st |= CO_fifo_st_errVal; else { uint8_t num = (uint8_t) u32; nWr = CO_fifo_write(dest, &num, sizeof(num), NULL); @@ -812,11 +812,11 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if (sRet != strchr(buf, '\0') || u32 > UINT16_MAX) st |= CO_fifo_st_errVal; + if ((sRet != strchr(buf, '\0')) || (u32 > UINT16_MAX)) st |= CO_fifo_st_errVal; else { uint16_t num = CO_SWAP_16((uint16_t) u32); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); @@ -834,7 +834,7 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); @@ -856,7 +856,7 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; uint64_t u64 = strtoull(buf, &sRet, 0); @@ -878,11 +878,11 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if (sRet != strchr(buf, '\0') || i32 < INT8_MIN || i32 > INT8_MAX) { + if ((sRet != strchr(buf, '\0')) || (i32 < INT8_MIN) || (i32 > INT8_MAX)) { st |= CO_fifo_st_errVal; } else { int8_t num = (int8_t) i32; @@ -901,11 +901,11 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if (sRet != strchr(buf, '\0') || i32 < INT16_MIN || i32 > INT16_MAX) { + if ((sRet != strchr(buf, '\0')) || (i32 < INT16_MIN) || (i32 > INT16_MAX)) { st |= CO_fifo_st_errVal; } else { int16_t num = CO_SWAP_16((int16_t) i32); @@ -924,7 +924,7 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); @@ -946,7 +946,7 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; int64_t i64 = strtoll(buf, &sRet, 0); @@ -968,7 +968,7 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; float32_t f32 = strtof(buf, &sRet); @@ -990,7 +990,7 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if (nRd == 0 || err) st |= CO_fifo_st_errTok; + if ((nRd == 0) || err) st |= CO_fifo_st_errTok; else { char *sRet; float64_t f64 = strtof(buf, &sRet); @@ -1012,7 +1012,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { uint8_t firstChar; CO_fifo_st st = 0; - if (dest == NULL || src == NULL) { + if ((dest == NULL) || (src == NULL)) { return 0; } @@ -1038,7 +1038,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* repeat until destination space available and no error and not finished * and source characters available */ - while (destSpace > 0 && (st & CO_fifo_st_errMask) == 0 && !finished) { + while ((destSpace > 0) && ((st & CO_fifo_st_errMask) == 0) && !finished) { uint8_t c; if (!CO_fifo_getc(src, &c)) { break; @@ -1047,7 +1047,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (step == 6) { /* command is inside comment, waiting for command delimiter */ bool_t insideComment = true; - if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { st |= CO_fifo_st_closed; finished = true; } @@ -1091,7 +1091,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { step = 0; } bool_t insideComment = false; - if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { /* newline found, finish */ st |= CO_fifo_st_closed; finished = true; @@ -1105,7 +1105,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (!finished) { st |= CO_fifo_st_partial; /* memorize variables for next iteration */ - dest->aux = (uint32_t)step << 8 | firstChar; + dest->aux = ((uint32_t)step << 8) | firstChar; } if (status != NULL) *status = st; @@ -1119,7 +1119,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { uint8_t step; CO_fifo_st st = 0; - if (dest == NULL || src == NULL) { + if ((dest == NULL) || (src == NULL)) { return 0; } @@ -1143,7 +1143,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* repeat until destination space available and no error and not finished * and source characters available */ - while (destSpace > 0 && (st & CO_fifo_st_errMask) == 0 && !finished) { + while ((destSpace > 0) && ((st & CO_fifo_st_errMask) == 0) && !finished) { uint8_t c; if (!CO_fifo_getc(src, &c)) { break; @@ -1171,10 +1171,10 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { * double quote (with two double quotes) */ step += 2; } - else if (isgraph((int)c) == 0 && step == 2) { + else if ((isgraph((int)c) == 0) && (step == 2)) { /* end of single word string */ bool_t insideComment = false; - if (c == DELIM_COMMAND + if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment) ) { st |= CO_fifo_st_closed; @@ -1213,7 +1213,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (isgraph((int)c) == 0) { /* end of quoted string */ bool_t insideComment = false; - if (c == DELIM_COMMAND + if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment) ) { st |= CO_fifo_st_closed; @@ -1233,7 +1233,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { case 5: { /* String token is finished, waiting for command delimiter */ bool_t insideComment = false; - if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { st |= CO_fifo_st_closed; finished = true; } @@ -1250,7 +1250,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } case 6: { /* String token is finished, waiting for command delimiter */ bool_t insideComment = true; - if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { st |= CO_fifo_st_closed; finished = true; } @@ -1282,7 +1282,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { uint32_t dword; CO_fifo_st st = 0; - if (dest == NULL || src == NULL) { + if ((dest == NULL) || (src == NULL)) { return 0; } @@ -1308,7 +1308,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* repeat until destination space available and no error and not finished * and source characters available */ - while (destSpace >= 3 && (st & CO_fifo_st_errMask) == 0 && !finished) { + while ((destSpace >= 3) && ((st & CO_fifo_st_errMask) == 0) && !finished) { uint8_t c; if (!CO_fifo_getc(src, &c)) { break; @@ -1317,14 +1317,14 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (step >= 5) { /* String token is finished, waiting for command delimiter */ bool_t insideComment = step > 5; - if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { st |= CO_fifo_st_closed; finished = true; } else if (insideComment) { step = 6; } - else if (isgraph((int)c) != 0 && c != (uint8_t)'=') { + else if ((isgraph((int)c) != 0) && (c != (uint8_t)'=')) { if (c == DELIM_COMMENT) /* comment start */ step = 6; else /* syntax error */ @@ -1335,7 +1335,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { uint8_t code = base64DecTable[c & 0x7F]; - if ((c & 0x80) != 0 || (code & 0x80) != 0) { + if (((c & 0x80) != 0) || ((code & 0x80) != 0)) { st |= CO_fifo_st_errTok; } else if (code >= 64 /* '=' (pad) or DELIM_COMMAND or space */) { @@ -1356,7 +1356,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } bool_t insideComment = false; - if (c == DELIM_COMMAND || CO_fifo_trimSpaces(src, &insideComment)) { + if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { st |= CO_fifo_st_closed; finished = true; } @@ -1380,7 +1380,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (!finished) { st |= CO_fifo_st_partial; /* memorize variables for next iteration */ - dest->aux = (uint32_t)step << 24 | (dword & 0xFFFFFF); + dest->aux = ((uint32_t)step << 24) | (dword & 0xFFFFFF); } if (status != NULL) *status = st; diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 97187b03..088eff6c 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -127,7 +127,7 @@ OD_write_dummy(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t static ODR_t OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if (buf == NULL || stream == NULL || countRead == NULL) { + if ((buf == NULL) || (stream == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } @@ -166,7 +166,7 @@ OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); /* When reading COB_ID, add Node-Id to the read value, if necessary */ - if (returnCode == ODR_OK && (stream->subIndex == 5U || stream->subIndex == 6U) && *countRead == 4) { + if ((returnCode == ODR_OK) && ((stream->subIndex == 5U) || (stream->subIndex == 6U)) && (*countRead == 4)) { CO_SRDO_t* SRDO = stream->object; uint32_t value = CO_getUint32(buf); @@ -227,7 +227,7 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t if (value != 254) { return ODR_INVALID_VALUE; } - } else if (stream->subIndex == 5U || stream->subIndex == 6U) { /* COB_ID */ + } else if ((stream->subIndex == 5U) || (stream->subIndex == 6U)) { /* COB_ID */ uint32_t value = CO_getUint32(buf); uint16_t index = stream->subIndex - 5U; uint16_t defaultCOB_ID = SRDO->defaultCOB_ID + index; @@ -378,7 +378,7 @@ CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationV /* Configure SRDOGuard->OD_IO_configurationValid variable. * It will be used for writing 0 to OD variable 13FE,00 */ odRet = OD_getSub(OD_13FE_configurationValid, 0, &SRDOGuard->OD_IO_configurationValid, false); - if (odRet != ODR_OK || SRDOGuard->OD_IO_configurationValid.stream.dataLength != 1) { + if ((odRet != ODR_OK) || (SRDOGuard->OD_IO_configurationValid.stream.dataLength != 1)) { if (errInfo != NULL) { *errInfo = (((uint32_t)OD_getIndex(OD_13FE_configurationValid)) << 8) | 1U; } @@ -497,7 +497,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* if OD contains default COB_IDs, add node-id */ - if (COB_ID1_normal == defaultCOB_ID && COB_ID2_inverted == (defaultCOB_ID + 1) && nodeId <= 64U) { + if ((COB_ID1_normal == defaultCOB_ID) && (COB_ID2_inverted == (defaultCOB_ID + 1)) && (nodeId <= 64U)) { uint32_t add = (uint32_t)SRDO->nodeId * 2; COB_ID1_normal += add; COB_ID2_inverted += add; @@ -510,12 +510,12 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* If configurationValid is set and SRDO is valid, continue with further configuration */ - if (err == 0 && configurationValid == CO_SRDO_VALID_MAGIC && informationDirection != CO_SRDO_INVALID) { + if ((err == 0) && (configurationValid == CO_SRDO_VALID_MAGIC) && (informationDirection != CO_SRDO_INVALID)) { configurationInProgress = true; } /* Verify parameters from OD */ - if (err == 0 && configurationInProgress) { + if ((err == 0) && configurationInProgress) { if (cp_highestSubindexSupported != 6) { err = ERR_INFO(0x1301 + SRDO_Index, 0, 2); } @@ -531,13 +531,13 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ else if (transmissionType != 254) { err = ERR_INFO(0x1301 + SRDO_Index, 4, 2); } - else if (COB_ID1_normal < 0x101 || (COB_ID1_normal & 1) == 0) { + else if ((COB_ID1_normal < 0x101) || ((COB_ID1_normal & 1) == 0)) { err = ERR_INFO(0x1301 + SRDO_Index, 5, 2); } - else if ((COB_ID1_normal + 1) != COB_ID2_inverted || COB_ID2_inverted > 0x180) { + else if (((COB_ID1_normal + 1) != COB_ID2_inverted) || (COB_ID2_inverted > 0x180)) { err = ERR_INFO(0x1301 + SRDO_Index, 6, 2); } - else if (mappedObjectsCount > CO_SRDO_MAX_MAPPED_ENTRIES || (mappedObjectsCount & 1) != 0) { + else if ((mappedObjectsCount > CO_SRDO_MAX_MAPPED_ENTRIES) || ((mappedObjectsCount & 1) != 0)) { err = ERR_INFO(0x1381 + SRDO_Index, 0, 2); } else { @@ -546,7 +546,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* Verify CRC */ - if (err == 0 && configurationInProgress) { + if ((err == 0) && configurationInProgress) { uint16_t crcResult = 0x0000; uint16_t tmp_u16; uint32_t tmp_u32; @@ -573,7 +573,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* Configure mappings */ - if (err == 0 && configurationInProgress) { + if ((err == 0) && configurationInProgress) { size_t srdoDataLength[2] = {0, 0}; for (uint8_t i = 0; i < mappedObjectsCount; i++) { @@ -590,7 +590,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ err = ERR_INFO(0x1381 + SRDO_Index, i + 1, 4); } /* is there a reference to the dummy entry */ - else if (index < 0x20 && subIndex == 0) { + else if ((index < 0x20) && (subIndex == 0)) { OD_stream_t *stream = &OD_IO->stream; (void)memset(stream, 0, sizeof(OD_stream_t)); stream->dataLength = stream->dataOffset = mappedLength; @@ -608,9 +608,9 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ else { /* verify access attributes, byte alignment and length */ OD_attr_t testAttribute = (informationDirection == CO_SRDO_RX) ? ODA_RSRDO : ODA_TSRDO; - if ((OD_IOcopy.stream.attribute & testAttribute) == 0 - || (mappedLengthBits & 0x07) != 0 - || OD_IOcopy.stream.dataLength < mappedLength + if (((OD_IOcopy.stream.attribute & testAttribute) == 0) + || ((mappedLengthBits & 0x07) != 0) + || (OD_IOcopy.stream.dataLength < mappedLength) ) { err = ERR_INFO(0x1381 + SRDO_Index, i + 1, 6); } @@ -630,7 +630,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ if (srdoDataLength[0] != srdoDataLength[1]) { err = ERR_INFO(0x1381 + SRDO_Index, 0, 7); } - else if (srdoDataLength[0] == 0 || srdoDataLength[0] > CO_SRDO_MAX_SIZE) { + else if ((srdoDataLength[0] == 0) || (srdoDataLength[0] > CO_SRDO_MAX_SIZE)) { err = ERR_INFO(0x1381 + SRDO_Index, 0, 8); } else { @@ -641,7 +641,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* Configure CAN tx buffers */ - if (err == 0 && configurationInProgress && informationDirection == CO_SRDO_TX) { + if ((err == 0) && configurationInProgress && (informationDirection == CO_SRDO_TX)) { SRDO->CANtxBuff[0] = CO_CANtxBufferInit(CANdevTxNormal, /* CAN device */ CANdevTxIdxNormal, /* index of specific buffer inside CAN module */ @@ -667,7 +667,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* Configure CAN rx buffers */ - if (err == 0 && configurationInProgress && informationDirection == CO_SRDO_RX) { + if ((err == 0) && configurationInProgress && (informationDirection == CO_SRDO_RX)) { CO_ReturnError_t ret; ret = CO_CANrxBufferInit(CANdevRxNormal, /* CAN device */ @@ -739,15 +739,15 @@ CO_SRDO_state_t CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext_us, bool_t NMTisOperational) { (void)timerNext_us; /* may be unused */ - if (NMTisOperational && SRDO->informationDirection != CO_SRDO_INVALID && SRDO->SRDOGuard->configurationValid - && SRDO->internalState >= CO_SRDO_state_unknown) { + if (NMTisOperational && (SRDO->informationDirection != CO_SRDO_INVALID) && SRDO->SRDOGuard->configurationValid + && (SRDO->internalState >= CO_SRDO_state_unknown)) { SRDO->cycleTimer = (SRDO->cycleTimer > timeDifference_us) ? (SRDO->cycleTimer - timeDifference_us) : 0U; SRDO->validationTimer = (SRDO->validationTimer > timeDifference_us) ? (SRDO->validationTimer - timeDifference_us) : 0U; /* Detect transition to NMT operational */ if (!SRDO->NMTisOperationalPrevious) { SRDO->cycleTimer = (SRDO->informationDirection == CO_SRDO_TX) - ? (uint32_t)SRDO->nodeId * 500U /* 0.5ms * node-ID delay*/ + ? ((uint32_t)SRDO->nodeId * 500U) /* 0.5ms * node-ID delay*/ : SRDO->cycleTime_us; SRDO->validationTimer = SRDO->cycleTime_us; SRDO->internalState = CO_SRDO_state_initializing; @@ -822,7 +822,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext dataSRDO[plain_inverted] += mappedLength; } - if (verifyLength[0] != verifyLength[1] || verifyLength[0] > CO_SRDO_MAX_SIZE || verifyLength[0] != SRDO->dataLength) { + if ((verifyLength[0] != verifyLength[1]) || (verifyLength[0] > CO_SRDO_MAX_SIZE) || (verifyLength[0] != SRDO->dataLength)) { SRDO->internalState = CO_SRDO_state_error_internal; /* should not happen */ } else { @@ -955,7 +955,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } /* for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) */ /* safety check, this should not happen */ - if (verifyLength[0] != verifyLength[1] || verifyLength[0] > CO_SRDO_MAX_SIZE || verifyLength[0] != SRDO->dataLength) { + if ((verifyLength[0] != verifyLength[1]) || (verifyLength[0] > CO_SRDO_MAX_SIZE) || (verifyLength[0] != SRDO->dataLength)) { SRDO->internalState = CO_SRDO_state_error_internal; } else { diff --git a/305/CO_LSS.h b/305/CO_LSS.h index c0cdf15b..d8e9051b 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -220,16 +220,16 @@ static const uint16_t CO_LSS_bitTimingTableLookup[] = { /** * Macro to check if node id is valid */ -#define CO_LSS_NODE_ID_VALID(nid) ((nid >= 1 && nid <= 0x7F) || nid == CO_LSS_NODE_ID_ASSIGNMENT) +#define CO_LSS_NODE_ID_VALID(nid) (((nid >= 1) && (nid <= 0x7F)) || (nid == CO_LSS_NODE_ID_ASSIGNMENT)) /** * Macro to check if two LSS addresses are equal */ #define CO_LSS_ADDRESS_EQUAL(/*CO_LSS_address_t*/ a1, /*CO_LSS_address_t*/ a2) \ - (a1.identity.productCode == a2.identity.productCode && \ - a1.identity.revisionNumber == a2.identity.revisionNumber && \ - a1.identity.serialNumber == a2.identity.serialNumber && \ - a1.identity.vendorID == a2.identity.vendorID) + ((a1.identity.productCode == a2.identity.productCode) && \ + (a1.identity.revisionNumber == a2.identity.revisionNumber) && \ + (a1.identity.serialNumber == a2.identity.serialNumber) && \ + (a1.identity.vendorID == a2.identity.vendorID)) /** @} */ /*@defgroup CO_LSS*/ diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index ae14c4ec..7331b974 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -83,8 +83,8 @@ static void CO_LSSmaster_receive(void *object, void *msg) LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */ /* verify message length and message overflow (previous message was not processed yet) */ - if(DLC==8 && !CO_FLAG_READ(LSSmaster->CANrxNew) && - LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING){ + if((DLC==8) && !CO_FLAG_READ(LSSmaster->CANrxNew) && + (LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING)){ /* copy data and set 'new message' flag */ (void)memcpy(LSSmaster->CANrxData, data, sizeof(LSSmaster->CANrxData)); @@ -137,7 +137,7 @@ CO_ReturnError_t CO_LSSmaster_init( CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if (LSSmaster==NULL || CANdevRx==NULL || CANdevTx==NULL){ + if ((LSSmaster==NULL) || (CANdevRx==NULL) || (CANdevTx==NULL)){ return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -295,8 +295,8 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( } /* Initiate select */ - if (LSSmaster->state==CO_LSSmaster_STATE_WAITING && - LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){ + if ((LSSmaster->state==CO_LSSmaster_STATE_WAITING) && + (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)){ ret = CO_LSSmaster_switchStateSelectInitiate(LSSmaster, lssAddress); } @@ -305,7 +305,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( ret = CO_LSSmaster_switchStateSelectWait(LSSmaster, timeDifference_us); } - if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) { + if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -397,7 +397,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } - if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) { + if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -432,8 +432,8 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( } /* Initiate config bit */ - if (LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE && - LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){ + if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE) && + (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)){ LSSmaster->command = CO_LSSmaster_COMMAND_CFG_BIT_TIMING; LSSmaster->timeoutTimer = 0; @@ -454,7 +454,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( CO_LSS_CFG_BIT_TIMING); } - if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) { + if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -470,16 +470,16 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if (LSSmaster==NULL || !CO_LSS_NODE_ID_VALID(nodeId)){ + if ((LSSmaster==NULL) || !CO_LSS_NODE_ID_VALID(nodeId)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* Initiate config node ID */ - if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE || + if (((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE) || /* Let un-config node ID also be run in global mode for unconfiguring all nodes */ - (LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL && - nodeId == CO_LSS_NODE_ID_ASSIGNMENT)) && - LSSmaster->command==CO_LSSmaster_COMMAND_WAITING) { + ((LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL) && + (nodeId == CO_LSS_NODE_ID_ASSIGNMENT))) && + (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)) { LSSmaster->command = CO_LSSmaster_COMMAND_CFG_NODE_ID; LSSmaster->timeoutTimer = 0; @@ -499,7 +499,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( CO_LSS_CFG_NODE_ID); } - if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) { + if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -519,8 +519,8 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( } /* Initiate config store */ - if (LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE && - LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){ + if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE) && + (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)){ LSSmaster->command = CO_LSSmaster_COMMAND_CFG_STORE; LSSmaster->timeoutTimer = 0; @@ -539,7 +539,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( CO_LSS_CFG_STORE); } - if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) { + if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -560,8 +560,8 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( /* for activating bit timing, we need to have all slaves set to config * state. This check makes it a bit harder to shoot ourselves in the foot */ - if (LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL && - LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){ + if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL) && + (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)){ CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; @@ -630,7 +630,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; CO_LSSmaster_command_t next = CO_LSSmaster_COMMAND_WAITING; - if (LSSmaster==NULL || lssAddress==NULL){ + if ((LSSmaster==NULL) || (lssAddress==NULL)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } @@ -671,8 +671,8 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSS_INQUIRE_SERIAL, &lssAddress->identity.serialNumber); } /* Check for next request */ - if (LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE || - LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL) { + if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || + (LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL)) { if (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING) { LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_VENDOR; @@ -700,7 +700,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( } } - if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) { + if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -717,14 +717,14 @@ CO_LSSmaster_return_t CO_LSSmaster_Inquire( { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if (LSSmaster==NULL || value==NULL){ + if ((LSSmaster==NULL) || (value==NULL)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* send request */ - if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE || - LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL) && - LSSmaster->command == CO_LSSmaster_COMMAND_WAITING) { + if (((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE) || + (LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL)) && + (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE; LSSmaster->timeoutTimer = 0; @@ -988,7 +988,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( CO_LSS_fastscan_lss_sub_next next; /* parameter validation */ - if (LSSmaster==NULL || fastscan==NULL){ + if ((LSSmaster==NULL) || (fastscan==NULL)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } if (fastscan->scan[0] == CO_LSSmaster_FS_SKIP) { @@ -1007,9 +1007,9 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } /* state machine validation */ - if (LSSmaster->state!=CO_LSSmaster_STATE_WAITING || - (LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING && - LSSmaster->command!=CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN)) { + if ((LSSmaster->state!=CO_LSSmaster_STATE_WAITING) || + ((LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING) && + (LSSmaster->command!=CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN))) { /* state machine not ready, other command is already processed */ return CO_LSSmaster_INVALID_STATE; } diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index fd737cfd..605592e3 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -32,11 +32,11 @@ #include /* 'bit' must be unsigned or additional range check must be added: bit>=CO_LSS_FASTSCAN_BIT0 */ -#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) (bit<=CO_LSS_FASTSCAN_BIT31 || bit==CO_LSS_FASTSCAN_CONFIRM) +#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit<=CO_LSS_FASTSCAN_BIT31) || (bit==CO_LSS_FASTSCAN_CONFIRM)) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_FASTSCAN_VENDOR_ID */ #define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=CO_LSS_FASTSCAN_SERIAL) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_BIT_TIMING_1000 */ -#define CO_LSS_BIT_TIMING_VALID(index) (index != 5 && index <= CO_LSS_BIT_TIMING_AUTO) +#define CO_LSS_BIT_TIMING_VALID(index) ((index != 5) && (index <= CO_LSS_BIT_TIMING_AUTO)) /* * Read received message from CAN module. @@ -50,7 +50,7 @@ static void CO_LSSslave_receive(void *object, void *msg) CO_LSSslave_t *LSSslave = (CO_LSSslave_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - if(DLC == 8U && !CO_FLAG_READ(LSSslave->sendResponse)) { + if((DLC == 8U) && !CO_FLAG_READ(LSSslave->sendResponse)) { bool_t request_LSSslave_process = false; uint8_t *data = CO_CANrxMsg_readData(msg); CO_LSS_cs_t cs = (CO_LSS_cs_t) data[0]; @@ -60,9 +60,9 @@ static void CO_LSSslave_receive(void *object, void *msg) switch (mode) { case CO_LSS_STATE_WAITING: - if (LSSslave->lssState == CO_LSS_STATE_CONFIGURATION && - LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT && - *LSSslave->pendingNodeID != CO_LSS_NODE_ID_ASSIGNMENT) + if ((LSSslave->lssState == CO_LSS_STATE_CONFIGURATION) && + (LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT) && + (*LSSslave->pendingNodeID != CO_LSS_NODE_ID_ASSIGNMENT)) { /* Slave process function will request NMT Reset comm.*/ LSSslave->service = cs; @@ -115,8 +115,8 @@ static void CO_LSSslave_receive(void *object, void *msg) } case CO_LSS_IDENT_FASTSCAN: { /* fastscan is only active on unconfigured nodes */ - if (*LSSslave->pendingNodeID == CO_LSS_NODE_ID_ASSIGNMENT && - LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT) + if ((*LSSslave->pendingNodeID == CO_LSS_NODE_ID_ASSIGNMENT) && + (LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT)) { uint8_t bitCheck = data[5]; uint8_t lssSub = data[6]; @@ -153,7 +153,7 @@ static void CO_LSSslave_receive(void *object, void *msg) ack = true; LSSslave->fastscanPos = lssNext; - if (bitCheck == 0 && lssNext < lssSub) { + if ((bitCheck == 0) && (lssNext < lssSub)) { /* complete match, enter configuration state */ LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; } @@ -215,8 +215,8 @@ CO_ReturnError_t CO_LSSslave_init( CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if (LSSslave==NULL || pendingBitRate == NULL || pendingNodeID == NULL || - CANdevRx==NULL || CANdevTx==NULL || + if ((LSSslave==NULL) || (pendingBitRate == NULL) || (pendingNodeID == NULL) || + (CANdevRx==NULL) || (CANdevTx==NULL) || !CO_LSS_NODE_ID_VALID(*pendingNodeID) ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -375,7 +375,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { errorCode = CO_LSS_CFG_BIT_TIMING_OK; errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OK; - if (tableSelector == 0 && CO_LSS_BIT_TIMING_VALID(tableIndex)) { + if ((tableSelector == 0) && CO_LSS_BIT_TIMING_VALID(tableIndex)) { uint16_t bit = CO_LSS_bitTimingTableLookup[tableIndex]; bool_t bit_rate_supported = LSSslave->pFunctLSScheckBitRate( LSSslave->functLSScheckBitRateObject, bit); diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index bc4a5160..ee4e5c54 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -139,7 +139,7 @@ void CO_GTWA_initRead(CO_GTWA_t* gtwa, /******************************************************************************/ #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { - if (gtwa != NULL && message != NULL) { + if ((gtwa != NULL) && (message != NULL)) { const char *c; for (c = &message[0]; *c != 0; c++) { @@ -243,7 +243,7 @@ static inline uint32_t getU32(char *token, uint32_t min, char *sRet; uint32_t num = strtoul(token, &sRet, 0); - if (sRet != strchr(token, '\0') || num < min || num > max) { + if ((sRet != strchr(token, '\0')) || (num < min) || (num > max)) { *err = true; } @@ -262,7 +262,7 @@ static bool_t checkNetNode(CO_GTWA_t *gtwa, eCode = CO_GTWA_respErrorNoDefaultNodeSet; e = true; } - else if (node < NodeMin || node > 127) { + else if ((node < NodeMin) || (node > 127)) { eCode = CO_GTWA_respErrorUnsupportedNode; e = true; } @@ -349,7 +349,7 @@ static const CO_GTWA_dataType_t dataTypes[] = { /* get data type from token */ static const CO_GTWA_dataType_t *CO_GTWA_getDataType(char *token, bool_t *err) { - if (token != NULL && *err == false) { + if ((token != NULL) && (*err == false)) { int i; int len = sizeof(dataTypes) / sizeof(CO_GTWA_dataType_t); @@ -655,7 +655,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * COMMAND PARSER ***************************************************************************/ /* if idle, search for new command, skip comments or empty lines */ - while (gtwa->state == CO_GTWA_ST_IDLE + while ((gtwa->state == CO_GTWA_ST_IDLE) && CO_fifo_CommSearch(>wa->commFifo, false) ) { char tok[20]; @@ -671,16 +671,16 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); /* Break if error in token or token was found, but closed with * command delimiter. */ - if (err || (n > 0 && closed != 0)) { + if (err || ((n > 0) && (closed != 0))) { err = true; break; } /* If empty line or just comment, continue with next command */ - else if (n == 0 && closed != 0) { + else if ((n == 0) && (closed != 0)) { responseWithEmpty(gtwa); continue; } - if (tok[0] != '[' || tok[strlen(tok)-1] != ']') { + if ((tok[0] != '[') || (tok[strlen(tok)-1] != ']')) { err = true; break; } @@ -695,7 +695,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = -1; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - if (err || n == 0) { + if (err || (n == 0)) { /* empty token, break on error */ err = true; break; @@ -789,7 +789,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t value; - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -810,7 +810,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t value; - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -830,7 +830,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t value; - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -842,7 +842,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, value = (uint16_t)getU32(tok, 0, 1, &err); if (err) break; - gtwa->SDOblockTransferEnable = value==1 ? true : false; + gtwa->SDOblockTransferEnable = (value==1) ? true : false; responseWithOK(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ @@ -855,13 +855,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO /* Upload SDO command - 'r[ead] ' */ - else if (strcmp(tok, "r") == 0 || strcmp(tok, "read") == 0) { + else if ((strcmp(tok, "r") == 0) || (strcmp(tok, "read") == 0)) { uint16_t idx; uint8_t subidx; CO_SDO_return_t SDO_ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -877,7 +877,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); - if (err || n == 0) { + if (err || (n == 0)) { err = true; break; } @@ -924,7 +924,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* Download SDO comm. - w[rite] */ - else if (strcmp(tok, "w") == 0 || strcmp(tok, "write") == 0) { + else if ((strcmp(tok, "w") == 0) || (strcmp(tok, "write") == 0)) { uint16_t idx; uint8_t subidx; CO_fifo_st status; @@ -932,7 +932,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, size_t size; bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -992,15 +992,15 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* is syntax error in command or size is zero or not the last token * in command */ - if ((status & CO_fifo_st_errMask) != 0 || size == 0 - || (gtwa->SDOdataCopyStatus == false && closed != 1) + if (((status & CO_fifo_st_errMask) != 0) || (size == 0) + || ((gtwa->SDOdataCopyStatus == false) && (closed != 1)) ) { err = true; break; } /* if data size was not known before and is known now, update SDO */ - if (gtwa->SDOdataType->length == 0 && !gtwa->SDOdataCopyStatus) { + if ((gtwa->SDOdataType->length == 0) && !gtwa->SDOdataCopyStatus) { CO_SDOclientDownloadInitiateSize(gtwa->SDO_C, size); } @@ -1018,7 +1018,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_OPERATIONAL; - if (closed != 1 || NodeErr) { + if ((closed != 1) || NodeErr) { err = true; break; } @@ -1040,7 +1040,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_STOPPED; - if (closed != 1 || NodeErr) { + if ((closed != 1) || NodeErr) { err = true; break; } @@ -1057,14 +1057,14 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* NMT Set node to pre-operational - 'preop[erational]' */ - else if (strcmp(tok, "preop") == 0 || - strcmp(tok, "preoperational") == 0 + else if ((strcmp(tok, "preop") == 0) || + (strcmp(tok, "preoperational") == 0) ) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_PRE_OPERATIONAL; - if (closed != 1 || NodeErr) { + if ((closed != 1) || NodeErr) { err = true; break; } @@ -1086,7 +1086,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2; - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -1099,8 +1099,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, convertToLower(tok, sizeof(tok)); if (strcmp(tok, "node") == 0) { command2 = CO_NMT_RESET_NODE; - } else if (strcmp(tok, "comm") == 0 || - strcmp(tok, "communication") == 0 + } else if ((strcmp(tok, "comm") == 0) || + (strcmp(tok, "communication") == 0) ) { command2 = CO_NMT_RESET_COMMUNICATION; } else { @@ -1127,7 +1127,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t select; - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -1162,7 +1162,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); CO_LSS_address_t *addr = >wa->lssAddress; - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -1193,7 +1193,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(tok, "lss_set_node") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -1202,7 +1202,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); gtwa->lssNID = (uint8_t)getU32(tok, 0, 0xFF, &err); - if (gtwa->lssNID > 0x7F && gtwa->lssNID < 0xFF) err = true; + if ((gtwa->lssNID > 0x7F) && (gtwa->lssNID < 0xFF)) err = true; if (err) break; /* continue with state machine */ @@ -1218,7 +1218,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, int maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / sizeof(CO_LSS_bitTimingTableLookup[0])) - 1; - if (closed != 0 || NodeErr) { + if ((closed != 0)|| NodeErr) { err = true; break; } @@ -1247,7 +1247,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, uint16_t switchDelay; CO_LSSmaster_return_t ret; - if (closed != 0 || NodeErr) { + if ((closed != 0) || NodeErr) { err = true; break; } @@ -1273,7 +1273,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(tok, "lss_store") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - if (closed != 1 || NodeErr) { + if ((closed != 1) || NodeErr) { err = true; break; } @@ -1316,7 +1316,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(tok, "lss_get_node") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - if (closed != 1 || NodeErr) { + if ((closed != 1) || NodeErr) { err = true; break; } @@ -1389,7 +1389,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* If timeout not specified, use 100ms. Should work in most cases */ - gtwa->lssTimeout_ms = timeout_ms == 0 ? 100 : timeout_ms; + gtwa->lssTimeout_ms = (timeout_ms == 0) ? 100 : timeout_ms; CO_LSSmaster_changeTimeout(gtwa->LSSmaster, gtwa->lssTimeout_ms); gtwa->lssNodeCount = 0; gtwa->lssSubState = 0; @@ -1568,8 +1568,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_IDLE; } /* Response data must be read, partially or whole */ - else if (ret == CO_SDO_RT_uploadDataBufferFull - || ret == CO_SDO_RT_ok_communicationEnd + else if ((ret == CO_SDO_RT_uploadDataBufferFull) + || (ret == CO_SDO_RT_ok_communicationEnd) ) { size_t fifoRemain; @@ -1595,7 +1595,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, fifoRemain = CO_fifo_getOccupied(>wa->SDO_C->bufFifo); /* end of communication, print newline and enter idle state */ - if (ret == CO_SDO_RT_ok_communicationEnd && fifoRemain == 0) { + if ((ret == CO_SDO_RT_ok_communicationEnd) && (fifoRemain == 0)) { gtwa->respBufCount += sprintf(>wa->respBuf[gtwa->respBufCount], "\r\n"); gtwa->state = CO_GTWA_ST_IDLE; @@ -1615,7 +1615,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_IDLE; break; } - } while (gtwa->respHold == false && fifoRemain > 0); + } while ((gtwa->respHold == false) && (fifoRemain > 0)); } break; } @@ -1641,8 +1641,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0; /* is syntax error in command or not the last token in command */ - if ((status & CO_fifo_st_errMask) != 0 - || (gtwa->SDOdataCopyStatus == false && closed != 1) + if (((status & CO_fifo_st_errMask) != 0) + || ((gtwa->SDOdataCopyStatus == false) && (closed != 1)) ) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; abort = true; /* abort SDO communication */ @@ -2011,7 +2011,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, do { size_t lenHelpRemain = lenHelp - gtwa->helpStringOffset; - size_t lenCopied = lenBuf < lenHelpRemain ? lenBuf : lenHelpRemain; + size_t lenCopied = (lenBuf < lenHelpRemain) ? lenBuf : lenHelpRemain; (void)memcpy(gtwa->respBuf, >wa->helpString[gtwa->helpStringOffset], @@ -2040,7 +2040,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, i = 4; } else { - i = CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2 + + i = (CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2) + CO_LED_GREEN(gtwa->LEDs, CO_LED_CANopen); } if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1)) @@ -2067,7 +2067,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* execute next CANopen processing immediately, if idle and more commands * available */ - if (timerNext_us != NULL && gtwa->state == CO_GTWA_ST_IDLE + if ((timerNext_us != NULL) && (gtwa->state == CO_GTWA_ST_IDLE) && CO_fifo_CommSearch(>wa->commFifo, false) ) { *timerNext_us = 0; diff --git a/storage/CO_storage.c b/storage/CO_storage.c index dc62d754..a80131b0 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -35,15 +35,15 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* verify arguments */ - if (stream == NULL || stream->subIndex == 0 || buf == NULL || count != 4 - || countWritten == NULL + if ((stream == NULL) || (stream->subIndex == 0) || (buf == NULL) || (count != 4) + || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } CO_storage_t *storage = stream->object; - if (stream->subIndex == 0 || storage->store == NULL || !storage->enabled) { + if ((stream->subIndex == 0) || (storage->store == NULL) || !storage->enabled) { return ODR_READONLY; } @@ -59,7 +59,7 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; - if (stream->subIndex == 1 || entry->subIndexOD == stream->subIndex) { + if ((stream->subIndex == 1) || (entry->subIndexOD == stream->subIndex)) { if (found == 0) found = 1; if ((entry->attr & CO_storage_cmd) != 0) { ODR_t code = storage->store(entry, storage->CANmodule); @@ -70,7 +70,7 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, } if (found != 2) - returnCode = found == 0 ? ODR_SUB_NOT_EXIST : ODR_READONLY; + returnCode = (found == 0) ? ODR_SUB_NOT_EXIST : ODR_READONLY; if (returnCode == ODR_OK) *countWritten = sizeof(uint32_t); return returnCode; @@ -86,15 +86,15 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* verify arguments */ - if (stream == NULL || stream->subIndex == 0 || buf == NULL || count != 4 - || countWritten == NULL + if ((stream == NULL) || (stream->subIndex == 0) || (buf == NULL) || (count != 4) + || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } CO_storage_t *storage = stream->object; - if (stream->subIndex == 0 || storage->restore == NULL || !storage->enabled){ + if ((stream->subIndex == 0) || (storage->restore == NULL) || !storage->enabled){ return ODR_READONLY; } @@ -110,7 +110,7 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; - if (stream->subIndex == 1 || entry->subIndexOD == stream->subIndex) { + if ((stream->subIndex == 1) || (entry->subIndexOD == stream->subIndex)) { if (found == 0) found = 1; if ((entry->attr & CO_storage_restore) != 0) { ODR_t code = storage->restore(entry, storage->CANmodule); @@ -121,7 +121,7 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, } if (found != 2) - returnCode = found == 0 ? ODR_SUB_NOT_EXIST : ODR_READONLY; + returnCode = (found == 0) ? ODR_SUB_NOT_EXIST : ODR_READONLY; if (returnCode == ODR_OK) *countWritten = sizeof(uint32_t); return returnCode; diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index a59c6076..6eacb0b2 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -63,7 +63,7 @@ static ODR_t storeEeprom(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { (uint8_t *)&signatureRead, entry->eepromAddrSignature, sizeof(signatureRead)); - if(signature != signatureRead || !writeOk) { + if((signature != signatureRead) || !writeOk) { return ODR_HW; } @@ -95,7 +95,7 @@ static ODR_t restoreEeprom(CO_storage_entry_t *entry, (uint8_t *)&signatureRead, entry->eepromAddrSignature, sizeof(signatureRead)); - if(signature != signatureRead || !writeOk) { + if((signature != signatureRead) || !writeOk) { return ODR_HW; } @@ -117,8 +117,8 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, bool_t eepromOvf = false; /* verify arguments */ - if (storage == NULL || entries == NULL || entriesCount == 0 - || storageInitError == NULL + if ((storage == NULL) || (entries == NULL) || (entriesCount == 0) + || (storageInitError == NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -162,7 +162,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, bool_t isAuto = (entry->attr & CO_storage_auto) != 0; /* verify arguments */ - if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { + if ((entry->addr == NULL) || (entry->len == 0) || (entry->subIndexOD < 2)) { *storageInitError = i; return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -225,7 +225,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, /******************************************************************************/ void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { /* verify arguments */ - if (storage == NULL || !storage->enabled) { + if ((storage == NULL) || !storage->enabled) { return; } From 446925be63d7ecb7eb1d4897e601bd3c4cc02806 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 10 Jun 2024 17:57:42 +0200 Subject: [PATCH 265/520] static analysis: add 'U' of unsigned [MISRA 2012 Rule 10.4, required] --- 301/CO_Emergency.c | 20 ++-- 301/CO_Emergency.h | 10 +- 301/CO_HBconsumer.c | 26 ++--- 301/CO_NMT_Heartbeat.c | 14 +-- 301/CO_Node_Guarding.c | 16 +-- 301/CO_ODinterface.c | 20 ++-- 301/CO_ODinterface.h | 38 +++---- 301/CO_PDO.c | 132 +++++++++++----------- 301/CO_PDO.h | 18 +-- 301/CO_SDOclient.c | 218 ++++++++++++++++++------------------- 301/CO_SDOserver.c | 146 ++++++++++++------------- 301/CO_SDOserver.h | 4 +- 301/CO_SYNC.c | 40 +++---- 301/CO_TIME.c | 30 ++--- 301/CO_TIME.h | 2 +- 301/CO_driver.h | 68 ++++++------ 301/CO_fifo.c | 150 ++++++++++++------------- 303/CO_LEDs.c | 6 +- 303/CO_LEDs.h | 18 +-- 304/CO_SRDO.c | 152 +++++++++++++------------- 305/CO_LSS.h | 22 ++-- 305/CO_LSSslave.c | 4 +- CANopen.c | 70 ++++++------ storage/CO_storage.c | 32 +++--- storage/CO_storageEeprom.c | 10 +- 25 files changed, 633 insertions(+), 633 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index c06697cd..1ad363d7 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -129,7 +129,7 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count < sizeof(uint32_t)) || (countRead == NULL) ) { return ODR_DEV_INCOMPAT; @@ -137,8 +137,8 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; - uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + em->nodeId; + uint32_t COB_IDEmergency32 = em->producerEnabled ? 0U : 0x80000000U; (void)CO_setUint32(buf, COB_IDEmergency32); *countRead = sizeof(uint32_t); @@ -375,11 +375,11 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* verify arguments */ if ((em == NULL) || (OD_1001_errReg == NULL) #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) - || ((fifo == NULL) && (fifoSize >= 2)) + || ((fifo == NULL) && (fifoSize >= 2U)) #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER || (OD_1014_cobIdEm == NULL) || (CANdevTx == NULL) - || (nodeId < 1) || (nodeId > 127) + || (nodeId < 1U) || (nodeId > 127U) #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY || OD_1003_preDefErr == NULL @@ -414,7 +414,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint32_t COB_IDEmergency32; ODR_t odRet; odRet = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); - if ((odRet != ODR_OK) || ((COB_IDEmergency32 & 0x7FFFF800) != 0)) { + if ((odRet != ODR_OK) || ((COB_IDEmergency32 & 0x7FFFF800U) != 0U)) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1014_cobIdEm); } /* don't break a program, if only value of a parameter is wrong */ if (odRet != ODR_OK) { return CO_ERROR_OD_PARAMETERS; } @@ -442,7 +442,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, if (producerCanId == CO_CAN_ID_EMERGENCY) producerCanId += nodeId; #else uint16_t producerCanId = CO_CAN_ID_EMERGENCY + nodeId; - em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0; + em->producerEnabled = (COB_IDEmergency32 & 0x80000000U) == 0U; em->OD_1014_extension.object = em; em->OD_1014_extension.read = OD_read_1014_default; @@ -634,7 +634,7 @@ void CO_EM_process(CO_EM_t *em, /* post-process Emergency message in fifo buffer. */ #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER - if (em->fifoSize >= 2) { + if (em->fifoSize >= 2U) { uint8_t fifoPpPtr = em->fifoPpPtr; #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT @@ -670,16 +670,16 @@ void CO_EM_process(CO_EM_t *em, #endif /* increment pointer */ - em->fifoPpPtr = (++fifoPpPtr < em->fifoSize) ? fifoPpPtr : 0; + em->fifoPpPtr = (++fifoPpPtr < em->fifoSize) ? fifoPpPtr : 0U; /* verify message buffer overflow. Clear error condition if all * messages from fifo buffer are processed */ - if (em->fifoOverflow == 1) { + if (em->fifoOverflow == 1U) { em->fifoOverflow = 2; CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, CO_EMC_GENERIC, 0); } - else if ((em->fifoOverflow == 2) && (em->fifoPpPtr == em->fifoWrPtr)) { + else if ((em->fifoOverflow == 2U) && (em->fifoPpPtr == em->fifoWrPtr)) { em->fifoOverflow = 0; CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); } diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index f4e3b24f..35a0e9ab 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -40,15 +40,15 @@ #define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) #endif #ifndef CO_CONFIG_ERR_CONDITION_GENERIC -#define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0) +#define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0U) #endif #ifndef CO_CONFIG_ERR_CONDITION_COMMUNICATION -#define CO_CONFIG_ERR_CONDITION_COMMUNICATION (em->errorStatusBits[2] \ - || em->errorStatusBits[3]) +#define CO_CONFIG_ERR_CONDITION_COMMUNICATION ((em->errorStatusBits[2] != 0U) \ + || (em->errorStatusBits[3] != 0U)) #endif #ifndef CO_CONFIG_ERR_CONDITION_MANUFACTURER -#define CO_CONFIG_ERR_CONDITION_MANUFACTURER (em->errorStatusBits[8] \ - || em->errorStatusBits[9]) +#define CO_CONFIG_ERR_CONDITION_MANUFACTURER (( em->errorStatusBits[8] != 0U) \ + || (em->errorStatusBits[9] != 0U)) #endif #ifdef __cplusplus diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 2dcb87b8..275d6ab8 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -45,7 +45,7 @@ static void CO_HBcons_receive(void *object, void *msg) { uint8_t DLC = CO_CANrxMsg_readDLC(msg); uint8_t *data = CO_CANrxMsg_readData(msg); - if (DLC == 1) { + if (DLC == 1U) { /* copy data and set 'new message' flag. */ HBconsNode->NMTstate = (CO_NMT_internalState_t)data[0]; CO_FLAG_SET(HBconsNode->CANrxNew); @@ -89,7 +89,7 @@ static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, CO_HBconsumer_t *HBcons = stream->object; if ((stream == NULL) || (buf == NULL) - || (stream->subIndex < 1) + || (stream->subIndex < 1U) || (stream->subIndex > HBcons->numberOfMonitoredNodes) || (count != sizeof(uint32_t)) || (countWritten == NULL) ) { @@ -97,9 +97,9 @@ static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, } uint32_t val = CO_getUint32(buf); - uint8_t nodeId = (val >> 16) & 0xFF; - uint16_t time = val & 0xFFFF; - CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, stream->subIndex - 1, + uint8_t nodeId = (val >> 16) & 0xFFU; + uint16_t time = val & 0xFFFFU; + CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, stream->subIndex - 1U, nodeId, time); if (ret != CO_ERROR_NO) { return ODR_PAR_INCOMPAT; @@ -139,19 +139,19 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, /* get actual number of monitored nodes */ HBcons->numberOfMonitoredNodes = - ((OD_1016_HBcons->subEntriesCount-1) < monitoredNodesCount) ? - (OD_1016_HBcons->subEntriesCount-1) : monitoredNodesCount; + ((OD_1016_HBcons->subEntriesCount-1U) < monitoredNodesCount) ? + (OD_1016_HBcons->subEntriesCount-1U) : monitoredNodesCount; for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { uint32_t val; - odRet = OD_get_u32(OD_1016_HBcons, i + 1, &val, true); + odRet = OD_get_u32(OD_1016_HBcons, i + 1U, &val, true); if (odRet != ODR_OK) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } return CO_ERROR_OD_PARAMETERS; } - uint8_t nodeId = (val >> 16) & 0xFF; - uint16_t time = val & 0xFFFF; + uint8_t nodeId = (val >> 16) & 0xFFU; + uint16_t time = val & 0xFFFFU; CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); if (ret != CO_ERROR_NO) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } @@ -190,10 +190,10 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, } /* verify for duplicate entries */ - if((consumerTime_ms != 0) && (nodeId != 0)) { + if((consumerTime_ms != 0U) && (nodeId != 0U)) { for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { CO_HBconsNode_t node = HBcons->monitoredNodes[i]; - if((idx != i) && (node.time_us != 0) && (node.nodeId == nodeId)) { + if((idx != i) && (node.time_us != 0U) && (node.nodeId == nodeId)) { ret = CO_ERROR_OD_PARAMETERS; } } @@ -214,8 +214,8 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, CO_FLAG_CLEAR(monitoredNode->CANrxNew); /* is channel used */ - if ((monitoredNode->nodeId != 0) && (monitoredNode->time_us != 0)) { COB_ID = monitoredNode->nodeId + CO_CAN_ID_HEARTBEAT; + if ((monitoredNode->nodeId != 0U) && (monitoredNode->time_us != 0U)) { monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; } else { diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 1280b5ca..8424af5f 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -41,7 +41,7 @@ static void CO_NMT_receive(void *object, void *msg) { CO_NMT_t *NMT = (CO_NMT_t*)object; - if ((DLC == 2) && ((nodeId == 0) || (nodeId == NMT->nodeId))) { + if ((DLC == 2U) && ((nodeId == 0U) || (nodeId == NMT->nodeId))) { NMT->internalCommand = command; #if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE @@ -62,7 +62,7 @@ static void CO_NMT_receive(void *object, void *msg) { static ODR_t OD_write_1017(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint16_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -71,7 +71,7 @@ static ODR_t OD_write_1017(OD_stream_t *stream, const void *buf, CO_NMT_t *NMT = (CO_NMT_t *)stream->object; /* update object, send Heartbeat immediately */ - NMT->HBproducerTime_us = (uint32_t)CO_getUint16(buf) * 1000; + NMT->HBproducerTime_us = (uint32_t)CO_getUint16(buf) * 1000U; NMT->HBproducerTimer = 0; /* write value to the original location in the Object Dictionary */ @@ -129,7 +129,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1017_ProducerHbTime); } return CO_ERROR_OD_PARAMETERS; } - NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000; + NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000U; NMT->OD_1017_extension.object = NMT; NMT->OD_1017_extension.read = OD_readOriginal; @@ -229,13 +229,13 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, bool_t NNTinit = NMTstateCpy == CO_NMT_INITIALIZING; NMT->HBproducerTimer = (NMT->HBproducerTimer > timeDifference_us ) - ? (NMT->HBproducerTimer - timeDifference_us) : 0; + ? (NMT->HBproducerTimer - timeDifference_us) : 0U; /* Send heartbeat producer message if: * - First start, send bootup message or * - HB producer enabled and: Timer expired or NMT->operatingState changed*/ - if (NNTinit || ((NMT->HBproducerTime_us != 0) - && ((NMT->HBproducerTimer == 0) + if (NNTinit || ((NMT->HBproducerTime_us != 0U) + && ((NMT->HBproducerTimer == 0U) || (NMTstateCpy != NMT->operatingStatePrev)) )) { NMT->HB_TXbuff->data[0] = (uint8_t) NMTstateCpy; diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 354ef54e..784fae21 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -50,7 +50,7 @@ static void CO_ngs_receive(void *object, void *msg) { static ODR_t OD_write_100C(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint16_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -59,11 +59,11 @@ static ODR_t OD_write_100C(OD_stream_t *stream, const void *buf, CO_nodeGuardingSlave_t *ngs = (CO_nodeGuardingSlave_t *)stream->object; /* update objects */ - ngs->guardTime_us = (uint32_t)CO_getUint16(buf) * 1000; + ngs->guardTime_us = (uint32_t)CO_getUint16(buf) * 1000U; ngs->lifeTime_us = ngs->guardTime_us * ngs->lifeTimeFactor; /* reset running timer */ - if (ngs->lifeTimer > 0) { + if (ngs->lifeTimer > 0U) { ngs->lifeTimer = ngs->lifeTime_us; } @@ -80,7 +80,7 @@ static ODR_t OD_write_100C(OD_stream_t *stream, const void *buf, static ODR_t OD_write_100D(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint8_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -93,7 +93,7 @@ static ODR_t OD_write_100D(OD_stream_t *stream, const void *buf, ngs->lifeTime_us = ngs->guardTime_us * ngs->lifeTimeFactor; /* reset running timer */ - if (ngs->lifeTimer > 0) { + if (ngs->lifeTimer > 0U) { ngs->lifeTimer = ngs->lifeTime_us; } @@ -136,7 +136,7 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, if (errInfo != NULL) *errInfo = OD_getIndex(OD_100C_GuardTime); return CO_ERROR_OD_PARAMETERS; } - ngs->guardTime_us = (uint32_t)guardTime_ms * 1000; + ngs->guardTime_us = (uint32_t)guardTime_ms * 1000U; ngs->OD_100C_extension.object = ngs; ngs->OD_100C_extension.read = OD_readOriginal; @@ -219,7 +219,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, /* send response */ ngs->CANtxBuff->data[0] = (uint8_t) NMTstate; if (ngs->toggle) { - ngs->CANtxBuff->data[0] |= 0x80; + ngs->CANtxBuff->data[0] |= 0x80U; ngs->toggle = false; } else { @@ -237,7 +237,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, } /* verify "Life time" timeout and update the timer */ - else if (ngs->lifeTimer > 0) { + else if (ngs->lifeTimer > 0U) { if (timeDifference_us < ngs->lifeTimer) { ngs->lifeTimer -= timeDifference_us; #if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 296254c6..824d7ad5 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -46,7 +46,7 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, /* If previous read was partial or OD variable length is larger than * current buffer size, then data was (will be) read in several segments */ - if ((stream->dataOffset > 0) || (dataLenToCopy > count)) { + if ((stream->dataOffset > 0U) || (dataLenToCopy > count)) { if (stream->dataOffset >= dataLenToCopy) { return ODR_DEV_INCOMPAT; } @@ -91,7 +91,7 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, /* If previous write was partial or OD variable length is larger than * current buffer size, then data was (will be) written in several * segments */ - if ((stream->dataOffset > 0) || (dataLenToCopy > count)) { + if ((stream->dataOffset > 0U) || (dataLenToCopy > count)) { if (stream->dataOffset >= dataLenToCopy) { return ODR_DEV_INCOMPAT; } @@ -141,12 +141,12 @@ static ODR_t OD_writeDisabled(OD_stream_t *stream, const void *buf, /******************************************************************************/ OD_entry_t *OD_find(OD_t *od, uint16_t index) { - if ((od == NULL) || (od->size == 0)) { + if ((od == NULL) || (od->size == 0U)) { return NULL; } uint16_t min = 0; - uint16_t max = od->size - 1; + uint16_t max = od->size - 1U; /* Fast search in ordered Object Dictionary. If indexes are mixed, * this won't work. If Object Dictionary has up to N entries, then the @@ -161,10 +161,10 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index) { } if (index < entry->index) { - max = (cur > 0) ? (cur - 1) : cur; + max = (cur > 0U) ? (cur - 1U) : cur; } else { - min = cur + 1; + min = cur + 1U; } } @@ -190,7 +190,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, /* attribute, dataOrig and dataLength, depends on object type */ switch (entry->odObjectType & ODT_TYPE_MASK) { case ODT_VAR: { - if (subIndex > 0) { return ODR_SUB_NOT_EXIST; } + if (subIndex > 0U) { return ODR_SUB_NOT_EXIST; } CO_PROGMEM OD_obj_var_t *odo = entry->odObject; @@ -203,7 +203,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, if (subIndex >= entry->subEntriesCount) { return ODR_SUB_NOT_EXIST; } CO_PROGMEM OD_obj_array_t *odo = entry->odObject; - if (subIndex == 0) { + if (subIndex == 0U) { stream->attribute = odo->attribute0; stream->dataOrig = odo->dataOrig0; stream->dataLength = 1; @@ -342,10 +342,10 @@ void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, errCopy = OD_getSub(entry, subIndex, &io, true); if (errCopy == ODR_OK) { - if ((stream->dataOrig == NULL) || (stream->dataLength == 0)) { + if ((stream->dataOrig == NULL) || (stream->dataLength == 0U)) { errCopy = ODR_DEV_INCOMPAT; } - else if ((len != 0) && (len != stream->dataLength)) { + else if ((len != 0U) && (len != stream->dataLength)) { errCopy = ODR_TYPE_MISMATCH; } else { /* MISRA C 2004 14.10 */ } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index e9225ee3..f9441c93 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -50,7 +50,7 @@ typedef uint8_t OD_attr_t; #ifndef OD_FLAGS_PDO_SIZE /** Size of of flagsPDO variable inside @ref OD_extension_t, from 0 to 32. */ -#define OD_FLAGS_PDO_SIZE 4 +#define OD_FLAGS_PDO_SIZE 4U #endif #ifndef CO_PROGMEM @@ -118,17 +118,17 @@ typedef enum { * Attributes (bit masks) for OD sub-object. */ typedef enum { - ODA_SDO_R = 0x01, /**< SDO server may read from the variable */ - ODA_SDO_W = 0x02, /**< SDO server may write to the variable */ - ODA_SDO_RW = 0x03, /**< SDO server may read from or write to the variable */ - ODA_TPDO = 0x04, /**< Variable is mappable into TPDO (can be read) */ - ODA_RPDO = 0x08, /**< Variable is mappable into RPDO (can be written) */ - ODA_TRPDO = 0x0C, /**< Variable is mappable into TPDO or RPDO */ - ODA_TSRDO = 0x10, /**< Variable is mappable into transmitting SRDO */ - ODA_RSRDO = 0x20, /**< Variable is mappable into receiving SRDO */ - ODA_TRSRDO = 0x30, /**< Variable is mappable into tx or rx SRDO */ - ODA_MB = 0x40, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */ - ODA_STR = 0x80 /**< Shorter value, than specified variable size, may be + ODA_SDO_R = 0x01U, /**< SDO server may read from the variable */ + ODA_SDO_W = 0x02U, /**< SDO server may write to the variable */ + ODA_SDO_RW = 0x03U, /**< SDO server may read from or write to the variable */ + ODA_TPDO = 0x04U, /**< Variable is mappable into TPDO (can be read) */ + ODA_RPDO = 0x08U, /**< Variable is mappable into RPDO (can be written) */ + ODA_TRPDO = 0x0CU, /**< Variable is mappable into TPDO or RPDO */ + ODA_TSRDO = 0x10U, /**< Variable is mappable into transmitting SRDO */ + ODA_RSRDO = 0x20U, /**< Variable is mappable into receiving SRDO */ + ODA_TRSRDO = 0x30U, /**< Variable is mappable into tx or rx SRDO */ + ODA_MB = 0x40U, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */ + ODA_STR = 0x80U /**< Shorter value, than specified variable size, may be written to the variable. SDO write will fill remaining memory with zeroes. Attribute is used for VISIBLE_STRING and UNICODE_STRING. */ } OD_attributes_t; @@ -437,7 +437,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, * @return OD index */ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { - return (entry != NULL) ? entry->index : 0; + return (entry != NULL) ? entry->index : 0U; } @@ -467,7 +467,7 @@ static inline bool_t OD_mappable(OD_stream_t *stream) { * @param stream Object Dictionary stream object. */ static inline void OD_rwRestart(OD_stream_t *stream) { - if (stream != NULL) { stream->dataOffset = 0; } + if (stream != NULL) { stream->dataOffset = 0U; } } @@ -509,9 +509,9 @@ static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) { */ static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) { #if OD_FLAGS_PDO_SIZE > 0 - if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8))) { + if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) { /* clear subIndex-th bit */ - uint8_t mask = ~(1 << (subIndex & 0x07)); + uint8_t mask = ~(1U << (subIndex & 0x07U)); flagsPDO[subIndex >> 3] &= mask; } #endif @@ -531,10 +531,10 @@ static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) { */ static inline bool_t OD_TPDOtransmitted(uint8_t *flagsPDO, uint8_t subIndex) { #if OD_FLAGS_PDO_SIZE > 0 - if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8))) { + if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) { /* return true, if subIndex-th bit is set */ - uint8_t mask = 1 << (subIndex & 0x07); - if ((flagsPDO[subIndex >> 3] & mask) != 0) { + uint8_t mask = 1U << (subIndex & 0x07U); + if ((flagsPDO[subIndex >> 3] & mask) != 0U) { return true; } } diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 1be2bf3b..249e8a8b 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -102,7 +102,7 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, } /* is there a reference to the dummy entry */ - if ((index < 0x20) && (subIndex == 0)) { + if ((index < 0x20U) && (subIndex == 0U)) { OD_stream_t *stream = &OD_IO->stream; (void)memset(stream, 0, sizeof(OD_stream_t)); stream->dataLength = stream->dataOffset = mappedLength; @@ -121,8 +121,8 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, /* verify access attributes, byte alignment and length */ OD_attr_t testAttribute = isRPDO ? ODA_RPDO : ODA_TPDO; - if (((OD_IOcopy.stream.attribute & testAttribute) == 0) - || ((mappedLengthBits & 0x07) != 0) + if (((OD_IOcopy.stream.attribute & testAttribute) == 0U) + || ((mappedLengthBits & 0x07U) != 0U) || (OD_IOcopy.stream.dataLength < mappedLength) ) { return ODR_NO_MAP; /* Object cannot be mapped to the PDO. */ @@ -135,10 +135,10 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, /* get TPDO request flag byte from extension */ #if OD_FLAGS_PDO_SIZE > 0 if (!isRPDO) { - if ((subIndex < (OD_FLAGS_PDO_SIZE * 8)) && (entry->extension != NULL)) { + if ((subIndex < (OD_FLAGS_PDO_SIZE * 8U)) && (entry->extension != NULL)) { PDO->flagPDObyte[mapIndex] = &entry->extension->flagsPDO[subIndex >> 3]; - PDO->flagPDObitmask[mapIndex] = 1 << (subIndex & 0x07); + PDO->flagPDObitmask[mapIndex] = 1U << (subIndex & 0x07U); } else { PDO->flagPDObyte[mapIndex] = NULL; @@ -185,7 +185,7 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, OD_IO_t *OD_IO = &PDO->OD_IO[i]; uint32_t map = 0; - odRet = OD_get_u32(OD_PDOMapPar, i + 1, &map, true); + odRet = OD_get_u32(OD_PDOMapPar, i + 1U, &map, true); if (odRet == ODR_SUB_NOT_EXIST) { continue; } @@ -201,7 +201,7 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, /* indicate erroneous mapping in initialization phase */ OD_IO->stream.dataLength = 0; OD_IO->stream.dataOffset = 0xFF; - if (*erroneousMap == 0) { *erroneousMap = map; } + if (*erroneousMap == 0U) { *erroneousMap = map; } } if (i < mappedObjectsCount) { @@ -209,12 +209,12 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, } } if ((pdoDataLength > CO_PDO_MAX_SIZE) - || ((pdoDataLength == 0) && (mappedObjectsCount > 0)) + || ((pdoDataLength == 0U) && (mappedObjectsCount > 0U)) ) { - if (*erroneousMap == 0) { *erroneousMap = 1; } + if (*erroneousMap == 0U) { *erroneousMap = 1; } } - if (*erroneousMap == 0) { + if (*erroneousMap == 0U) { PDO->dataLength = (CO_PDO_size_t)pdoDataLength; PDO->mappedObjectsCount = mappedObjectsCount; } @@ -242,11 +242,11 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, CO_PDO_common_t *PDO = stream->object; /* PDO must be disabled before mapping configuration */ - if ((PDO->valid) || ((PDO->mappedObjectsCount != 0) && (stream->subIndex > 0))) { + if ((PDO->valid) || ((PDO->mappedObjectsCount != 0U) && (stream->subIndex > 0U))) { return ODR_UNSUPP_ACCESS; } - if (stream->subIndex == 0) { + if (stream->subIndex == 0U) { uint8_t mappedObjectsCount = CO_getUint8(buf); size_t pdoDataLength = 0; @@ -270,7 +270,7 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, if (pdoDataLength > CO_PDO_MAX_SIZE) { return ODR_MAP_LEN; } - if ((pdoDataLength == 0) && (mappedObjectsCount > 0)) { + if ((pdoDataLength == 0U) && (mappedObjectsCount > 0U)) { return ODR_INVALID_VALUE; } @@ -280,7 +280,7 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, } else { uint32_t val = CO_getUint32(buf); - ODR_t odRet = PDOconfigMap(PDO, val, stream->subIndex-1, + ODR_t odRet = PDOconfigMap(PDO, val, stream->subIndex-1U, PDO->isRPDO, PDO->OD); if (odRet != ODR_OK) { return odRet; @@ -416,15 +416,15 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); /* When reading COB_ID, add Node-Id to the read value, if necessary */ - if ((returnCode == ODR_OK) && (stream->subIndex == 1) && (*countRead == 4)) { + if ((returnCode == ODR_OK) && (stream->subIndex == 1U) && (*countRead == 4U)) { /* Only common part of the CO_RPDO_t or CO_TPDO_t will be used */ CO_PDO_common_t *PDO = stream->object; uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ - if ((CAN_ID != 0) && (CAN_ID == (PDO->preDefinedCanId & 0xFF80))) { - COB_ID = (COB_ID & 0xFFFF0000) | PDO->preDefinedCanId; + if ((CAN_ID != 0U) && (CAN_ID == (PDO->preDefinedCanId & 0xFF80U))) { + COB_ID = (COB_ID & 0xFFFF0000U) | PDO->preDefinedCanId; } /* If PDO is not valid, set bit 31 */ @@ -522,7 +522,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* "count" is also verified in *_init() function */ - if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4)) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4U)) { return ODR_DEV_INCOMPAT; } @@ -534,16 +534,16 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, switch (stream->subIndex) { case 1: { /* COB-ID used by PDO */ uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - bool_t valid = (COB_ID & 0x80000000) == 0; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + bool_t valid = (COB_ID & 0x80000000U) == 0U; /* bits 11...29 must be zero, PDO must be disabled on change, * CAN_ID == 0 is not allowed, mapping must be configured before * enabling the PDO */ - if (((COB_ID & 0x3FFFF800) != 0) + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && PDO->valid && (CAN_ID != PDO->configuredCanId)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - || (valid && (PDO->mappedObjectsCount == 0)) + || (valid && (PDO->mappedObjectsCount == 0U)) ) { return ODR_INVALID_VALUE; } @@ -612,7 +612,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE case 5: { /* event-timer */ uint32_t eventTime = CO_getUint16(buf); - RPDO->timeoutTime_us = eventTime * 1000; + RPDO->timeoutTime_us = eventTime * 1000U; RPDO->timeoutTimer = 0; break; } @@ -678,29 +678,29 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, odRet = OD_get_u32(OD_14xx_RPDOCommPar, 1, &COB_ID, true); if (odRet != ODR_OK) { if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_14xx_RPDOCommPar)) << 8) | 1; + *errInfo = (((uint32_t)OD_getIndex(OD_14xx_RPDOCommPar)) << 8) | 1U; } return CO_ERROR_OD_PARAMETERS; } - bool_t valid = (COB_ID & 0x80000000) == 0; - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - if (valid && ((PDO->mappedObjectsCount == 0) || (CAN_ID == 0))) { + bool_t valid = (COB_ID & 0x80000000U) == 0U; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + if (valid && ((PDO->mappedObjectsCount == 0U) || (CAN_ID == 0U))) { valid = false; - if (erroneousMap == 0) { erroneousMap = 1; } + if (erroneousMap == 0U) { erroneousMap = 1; } } - if (erroneousMap != 0) { + if (erroneousMap != 0U) { CO_errorReport(PDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, - (erroneousMap != 1) ? erroneousMap : COB_ID); + (erroneousMap != 1U) ? erroneousMap : COB_ID); } if (!valid) { CAN_ID = 0; } /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ - if ((CAN_ID != 0) && (CAN_ID == (preDefinedCanId & 0xFF80))) { + if ((CAN_ID != 0U) && (CAN_ID == (preDefinedCanId & 0xFF80U))) { CAN_ID = preDefinedCanId; } @@ -725,7 +725,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, odRet = OD_get_u8(OD_14xx_RPDOCommPar, 2, &transmissionType, true); if (odRet != ODR_OK) { if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_14xx_RPDOCommPar)) << 8) | 2; + *errInfo = (((uint32_t)OD_getIndex(OD_14xx_RPDOCommPar)) << 8) | 2U; } return CO_ERROR_OD_PARAMETERS; } @@ -739,7 +739,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE uint16_t eventTime = 0; odRet = OD_get_u16(OD_14xx_RPDOCommPar, 5, &eventTime, true); - RPDO->timeoutTime_us = (uint32_t)eventTime * 1000; + RPDO->timeoutTime_us = (uint32_t)eventTime * 1000U; #endif @@ -885,7 +885,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* verify RPDO timeout */ (void) rpdoReceived; #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE - if (RPDO->timeoutTime_us > 0) { + if (RPDO->timeoutTime_us > 0U) { if (rpdoReceived) { if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { CO_errorReset(PDO->em, CO_EM_RPDO_TIME_OUT, @@ -894,7 +894,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* enable monitoring */ RPDO->timeoutTimer = 1; } - else if ((RPDO->timeoutTimer > 0) + else if ((RPDO->timeoutTimer > 0U) && (RPDO->timeoutTimer < RPDO->timeoutTime_us) ) { RPDO->timeoutTimer += timeDifference_us; @@ -953,7 +953,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* "count" is also verified in *_init() function */ - if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4)) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4U)) { return ODR_DEV_INCOMPAT; } @@ -965,16 +965,16 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, switch (stream->subIndex) { case 1: { /* COB-ID used by PDO */ uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - bool_t valid = (COB_ID & 0x80000000) == 0; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + bool_t valid = (COB_ID & 0x80000000U) == 0U; /* bits 11...29 must be zero, PDO must be disabled on change, * CAN_ID == 0 is not allowed, mapping must be configured before * enabling the PDO */ - if (((COB_ID & 0x3FFFF800) != 0) + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && (PDO->valid && (CAN_ID != PDO->configuredCanId))) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - || (valid && (PDO->mappedObjectsCount == 0)) + || (valid && (PDO->mappedObjectsCount == 0U)) ) { return ODR_INVALID_VALUE; } @@ -1039,14 +1039,14 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, return ODR_INVALID_VALUE; } uint32_t inhibitTime = CO_getUint16(buf); - TPDO->inhibitTime_us = inhibitTime * 100; + TPDO->inhibitTime_us = inhibitTime * 100U; TPDO->inhibitTimer = 0; break; } case 5: { /* event-timer */ uint32_t eventTime = CO_getUint16(buf); - TPDO->eventTime_us = eventTime * 1000; + TPDO->eventTime_us = eventTime * 1000U; TPDO->eventTimer = 0; break; } @@ -1056,7 +1056,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, case 6: { /* SYNC start value */ uint8_t syncStartValue = CO_getUint8(buf); - if (PDO->valid || (syncStartValue > 240)) { + if (PDO->valid || (syncStartValue > 240U)) { return ODR_INVALID_VALUE; } TPDO->syncStartValue = syncStartValue; @@ -1142,29 +1142,29 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, odRet = OD_get_u32(OD_18xx_TPDOCommPar, 1, &COB_ID, true); if (odRet != ODR_OK) { if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 1; + *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 1U; } return CO_ERROR_OD_PARAMETERS; } - bool_t valid = (COB_ID & 0x80000000) == 0; - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - if (valid && ((PDO->mappedObjectsCount == 0) || (CAN_ID == 0))) { + bool_t valid = (COB_ID & 0x80000000U) == 0U; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + if (valid && ((PDO->mappedObjectsCount == 0U) || (CAN_ID == 0U))) { valid = false; - if (erroneousMap == 0) { erroneousMap = 1; } + if (erroneousMap == 0U) { erroneousMap = 1; } } - if (erroneousMap != 0) { + if (erroneousMap != 0U) { CO_errorReport(PDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, - (erroneousMap != 1) ? erroneousMap : COB_ID); + (erroneousMap != 1U) ? erroneousMap : COB_ID); } if (!valid) { CAN_ID = 0; } /* If default CAN-ID is stored in OD (without Node-ID), add Node-ID */ - if ((CAN_ID != 0) && (CAN_ID == (preDefinedCanId & 0xFF80))) { + if ((CAN_ID != 0U) && (CAN_ID == (preDefinedCanId & 0xFF80U))) { CAN_ID = preDefinedCanId; } @@ -1189,8 +1189,8 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, uint16_t eventTime = 0; odRet = OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); odRet = OD_get_u16(OD_18xx_TPDOCommPar, 5, &eventTime, true); - TPDO->inhibitTime_us = (uint32_t)inhibitTime * 100; - TPDO->eventTime_us = (uint32_t)eventTime * 1000; + TPDO->inhibitTime_us = (uint32_t)inhibitTime * 100U; + TPDO->eventTime_us = (uint32_t)eventTime * 1000U; #endif @@ -1349,10 +1349,10 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, ) { /* event timer */ #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE - if (TPDO->eventTime_us != 0) { + if (TPDO->eventTime_us != 0U) { TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) - ? (TPDO->eventTimer - timeDifference_us) : 0; - if (TPDO->eventTimer == 0) { + ? (TPDO->eventTimer - timeDifference_us) : 0U; + if (TPDO->eventTimer == 0U) { TPDO->sendRequest = true; } #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT @@ -1369,7 +1369,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { uint8_t *flagPDObyte = PDO->flagPDObyte[i]; if (flagPDObyte != NULL) { - if ((*flagPDObyte & PDO->flagPDObitmask[i]) == 0) { + if ((*flagPDObyte & PDO->flagPDObitmask[i]) == 0U) { TPDO->sendRequest = true; break; } @@ -1385,10 +1385,10 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, if (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) - ? (TPDO->inhibitTimer - timeDifference_us) : 0; + ? (TPDO->inhibitTimer - timeDifference_us) : 0U; /* send TPDO */ - if (TPDO->sendRequest && (TPDO->inhibitTimer == 0)) { + if (TPDO->sendRequest && (TPDO->inhibitTimer == 0U)) { CO_TPDOsend(TPDO); } @@ -1417,28 +1417,28 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, /* send synchronous cyclic TPDO */ else { /* is the start of synchronous TPDO transmission */ - if (TPDO->syncCounter == 255) { - if ((TPDO->SYNC->counterOverflowValue != 0) - && (TPDO->syncStartValue != 0) + if (TPDO->syncCounter == 255U) { + if ((TPDO->SYNC->counterOverflowValue != 0U) + && (TPDO->syncStartValue != 0U) ) { /* syncStartValue is in use */ TPDO->syncCounter = 254; } else { /* Send first TPDO somewhere in the middle */ - TPDO->syncCounter = (TPDO->transmissionType / 2) + 1; + TPDO->syncCounter = (TPDO->transmissionType / 2U) + 1U; } } /* If the syncStartValue is in use, start first TPDO after SYNC * with matched syncStartValue. */ - if (TPDO->syncCounter == 254) { + if (TPDO->syncCounter == 254U) { if (TPDO->SYNC->counter == TPDO->syncStartValue) { TPDO->syncCounter = TPDO->transmissionType; CO_TPDOsend(TPDO); } } /* Send TPDO after every N-th Sync */ - else if (--TPDO->syncCounter == 0) { + else if (--TPDO->syncCounter == 0U) { TPDO->syncCounter = TPDO->transmissionType; CO_TPDOsend(TPDO); } diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 76df0eb7..ee8dca32 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -135,13 +135,13 @@ extern "C" { /** Maximum size of PDO message, 8 for standard CAN */ #ifndef CO_PDO_MAX_SIZE -#define CO_PDO_MAX_SIZE 8 +#define CO_PDO_MAX_SIZE 8U #endif /** Maximum number of entries, which can be mapped to PDO, 8 for standard CAN, * may be less to preserve RAM usage */ #ifndef CO_PDO_MAX_MAPPED_ENTRIES -#define CO_PDO_MAX_MAPPED_ENTRIES 8 +#define CO_PDO_MAX_MAPPED_ENTRIES 8U #endif /** Number of CANopen RPDO objects, which uses default CAN indentifiers. @@ -152,7 +152,7 @@ extern "C" { * identifiers. In that case RPDO5 has CAN_ID=0x200+NodeId+1, RPDO6 has * CAN_ID=0x300+NodeId+1, RPDO9 has CAN_ID=0x200+NodeId+2 and so on. */ #ifndef CO_RPDO_DEFAULT_CANID_COUNT -#define CO_RPDO_DEFAULT_CANID_COUNT 4 +#define CO_RPDO_DEFAULT_CANID_COUNT 4U #endif /** Number of CANopen TPDO objects, which uses default CAN indentifiers. @@ -161,7 +161,7 @@ extern "C" { * TPDO9 has CAN_ID=0x180+NodeId+2 and so on. * For description see @ref CO_RPDO_DEFAULT_CANID_COUNT. */ #ifndef CO_TPDO_DEFAULT_CANID_COUNT -#define CO_TPDO_DEFAULT_CANID_COUNT 4 +#define CO_TPDO_DEFAULT_CANID_COUNT 4U #endif #ifndef CO_PDO_OWN_TYPES @@ -173,13 +173,13 @@ typedef uint8_t CO_PDO_size_t; * PDO transmission Types */ typedef enum { - CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC = 0, /**< synchronous (acyclic) */ - CO_PDO_TRANSM_TYPE_SYNC_1 = 1, /**< synchronous (cyclic every sync) */ - CO_PDO_TRANSM_TYPE_SYNC_240 = 0xF0, /**< synchronous (cyclic every 240-th + CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC = 0U, /**< synchronous (acyclic) */ + CO_PDO_TRANSM_TYPE_SYNC_1 = 1U, /**< synchronous (cyclic every sync) */ + CO_PDO_TRANSM_TYPE_SYNC_240 = 0xF0U, /**< synchronous (cyclic every 240-th sync) */ - CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO = 0xFE, /**< event-driven, lower value + CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO = 0xFEU, /**< event-driven, lower value (manufacturer specific), */ - CO_PDO_TRANSM_TYPE_SYNC_EVENT_HI = 0xFF /**< event-driven, higher value + CO_PDO_TRANSM_TYPE_SYNC_EVENT_HI = 0xFFU /**< event-driven, higher value (device profile and application profile specific) */ } CO_PDO_transmissionTypes_t; diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index e69466a2..8b2e6849 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -68,10 +68,10 @@ static void CO_SDOclient_receive(void *object, void *msg) { /* Ignore messages in idle state and messages with wrong length. Ignore * message also if previous message was not processed yet and not abort */ if ((SDO_C->state != CO_SDO_ST_IDLE) && (DLC == 8U) - && (!CO_FLAG_READ(SDO_C->CANrxNew) || (data[0] == 0x80)) + && (!CO_FLAG_READ(SDO_C->CANrxNew) || (data[0] == 0x80U)) ) { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - if ((data[0] == 0x80) /* abort from server */ + if ((data[0] == 0x80U) /* abort from server */ || ((SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) && (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP)) ) { @@ -92,18 +92,18 @@ static void CO_SDOclient_receive(void *object, void *msg) { else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { /* block upload, copy data directly */ CO_SDO_state_t state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; - uint8_t seqno = data[0] & 0x7F; + uint8_t seqno = data[0] & 0x7FU; SDO_C->timeoutTimer = 0; SDO_C->block_timeoutTimer = 0; /* verify if sequence number is correct */ if ((seqno <= SDO_C->block_blksize) - && (seqno == (SDO_C->block_seqno + 1)) + && (seqno == (SDO_C->block_seqno + 1U)) ) { SDO_C->block_seqno = seqno; /* is this the last segment? */ - if ((data[0] & 0x80) != 0) { + if ((data[0] & 0x80U) != 0U) { /* copy data to temporary buffer, because we don't know the * number of bytes not containing data */ (void)memcpy((void *)&SDO_C->block_dataUploadLast[0], @@ -117,7 +117,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { CO_fifo_write(&SDO_C->bufFifo, &data[1], 7, &SDO_C->block_crc); - SDO_C->sizeTran += 7; + SDO_C->sizeTran += 7U; /* all segments in sub-block has been transferred */ if (seqno == SDO_C->block_blksize) { state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; @@ -189,12 +189,12 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, case 1: { /* COB-ID client -> server */ uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - uint16_t CAN_ID_cur = (uint16_t)(SDO_C->COB_IDClientToServer&0x7FF); - bool_t valid = (COB_ID & 0x80000000) == 0; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + uint16_t CAN_ID_cur = (uint16_t)(SDO_C->COB_IDClientToServer & 0x7FFU); + bool_t valid = (COB_ID & 0x80000000U) == 0U; /* SDO client must not be valid when changing COB_ID */ - if (((COB_ID & 0x3FFFF800) != 0) + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && SDO_C->valid && (CAN_ID != CAN_ID_cur)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { @@ -209,12 +209,12 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, case 2: { /* COB-ID server -> client */ uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - uint16_t CAN_ID_cur = (uint16_t)(SDO_C->COB_IDServerToClient&0x7FF); - bool_t valid = (COB_ID & 0x80000000) == 0; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + uint16_t CAN_ID_cur = (uint16_t)(SDO_C->COB_IDServerToClient & 0x7FFU); + bool_t valid = (COB_ID & 0x80000000U) == 0U; /* SDO client must not be valid when changing COB_ID */ - if (((COB_ID & 0x3FFFF800) != 0) + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && SDO_C->valid && (CAN_ID != CAN_ID_cur)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { @@ -229,7 +229,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, case 3: { /* Node-ID of the SDO server */ uint8_t nodeId = CO_getUint8(buf); - if (nodeId > 127) { + if (nodeId > 127U) { return ODR_INVALID_VALUE; } SDO_C->nodeIDOfTheSDOServer = nodeId; @@ -260,7 +260,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, /* verify arguments */ if ((SDO_C == NULL) || (OD_1280_SDOcliPar == NULL) || (OD_getIndex(OD_1280_SDOcliPar) < OD_H1280_SDO_CLIENT_1_PARAM) - || (OD_getIndex(OD_1280_SDOcliPar) > (OD_H1280_SDO_CLIENT_1_PARAM + 0x7F)) + || (OD_getIndex(OD_1280_SDOcliPar) > (OD_H1280_SDO_CLIENT_1_PARAM + 0x7FU)) || (CANdevRx==NULL) || (CANdevTx==NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -292,7 +292,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, ODR_t odRet2 = OD_get_u32(OD_1280_SDOcliPar, 2, &COB_IDServerToClient, true); ODR_t odRet3 = OD_get_u8(OD_1280_SDOcliPar, 3, &nodeIDOfTheSDOServer, true); - if ((odRet0 != ODR_OK) || (maxSubIndex != 3) + if ((odRet0 != ODR_OK) || (maxSubIndex != 3U) || (odRet1 != ODR_OK) || (odRet2 != ODR_OK) || (odRet3 != ODR_OK) ) { if (errInfo != NULL) *errInfo = OD_getIndex(OD_1280_SDOcliPar); @@ -384,11 +384,11 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, #endif /* verify valid bit */ - uint16_t CanIdC2S = ((COB_IDClientToServer & 0x80000000L) == 0) ? - (uint16_t)(COB_IDClientToServer & 0x7FF) : 0; - uint16_t CanIdS2C = ((COB_IDServerToClient & 0x80000000L) == 0) ? - (uint16_t)(COB_IDServerToClient & 0x7FF) : 0; - if ((CanIdC2S != 0) && (CanIdS2C != 0)) { + uint16_t CanIdC2S = ((COB_IDClientToServer & 0x80000000UL) == 0U) ? + (uint16_t)(COB_IDClientToServer & 0x7FFU) : 0U; + uint16_t CanIdS2C = ((COB_IDServerToClient & 0x80000000UL) == 0U) ? + (uint16_t)(COB_IDServerToClient & 0x7FFU) : 0U; + if ((CanIdC2S != 0U) && (CanIdS2C != 0U)) { SDO_C->valid = true; } else { @@ -447,14 +447,14 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, SDO_C->sizeInd = sizeIndicated; SDO_C->sizeTran = 0; SDO_C->finished = false; - SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; + SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000U; SDO_C->timeoutTimer = 0; CO_fifo_reset(&SDO_C->bufFifo); #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ - if ((SDO_C->OD != NULL) && (SDO_C->nodeId != 0) + if ((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U) && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId) ) { SDO_C->OD_IO.write = NULL; @@ -463,7 +463,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, else #endif #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - if (blockEnable && ((sizeIndicated == 0) || + if (blockEnable && ((sizeIndicated == 0U) || (sizeIndicated > CO_CONFIG_SDO_CLI_PST)) ) { SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ; @@ -487,7 +487,7 @@ void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, SDO_C->sizeInd = sizeIndicated; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ) - && (sizeIndicated > 0) && (sizeIndicated <= CO_CONFIG_SDO_CLI_PST) + && (sizeIndicated > 0U) && (sizeIndicated <= CO_CONFIG_SDO_CLI_PST) ) { SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; } @@ -566,19 +566,19 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->sizeTran += count; /* error: no data */ - if (count == 0) { + if (count == 0U) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; } /* verify if sizeTran is too large */ - else if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { + else if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { SDO_C->sizeTran -= count; abortCode = CO_SDO_AB_DATA_LONG; ret = CO_SDO_RT_endedWithClientAbort; } /* Verify sizeTran is too small in last segment of data */ else if (!bufferPartial - && (SDO_C->sizeInd > 0) && (SDO_C->sizeTran < SDO_C->sizeInd) + && (SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd) ) { abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; @@ -598,18 +598,18 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, * bytes to terminate (unicode) string. Shorten also OD data * size, (temporary, send info about EOF into OD_IO.write) */ if (((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0) - && ((sizeInOd == 0) || (SDO_C->sizeTran < sizeInOd)) + && ((sizeInOd == 0U) || (SDO_C->sizeTran < sizeInOd)) ) { buf[count++] = 0; SDO_C->sizeTran++; - if ((sizeInOd == 0) || (sizeInOd > SDO_C->sizeTran)) { + if ((sizeInOd == 0U) || (sizeInOd > SDO_C->sizeTran)) { buf[count++] = 0; SDO_C->sizeTran++; } SDO_C->OD_IO.stream.dataLength = (OD_size_t)SDO_C->sizeTran; } /* Indicate OD data size, if necessary. Used for EOF check. */ - else if (sizeInOd == 0) { + else if (sizeInOd == 0U) { SDO_C->OD_IO.stream.dataLength = (OD_size_t)SDO_C->sizeTran; } /* Verify if size of data downloaded matches data size in OD. */ @@ -672,7 +672,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* CAN data received ******************************************************/ else if (CO_FLAG_READ(SDO_C->CANrxNew)) { /* is SDO abort */ - if (SDO_C->CANrxData[0] == 0x80) { + if (SDO_C->CANrxData[0] == 0x80U) { uint32_t code; (void)memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); @@ -686,7 +686,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } else switch (SDO_C->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { - if (SDO_C->CANrxData[0] == 0x60) { + if (SDO_C->CANrxData[0] == 0x60U) { /* verify index and subindex */ uint16_t index; uint8_t subindex; @@ -725,15 +725,15 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { - if ((SDO_C->CANrxData[0] & 0xEF) == 0x20) { + if ((SDO_C->CANrxData[0] & 0xEFU) == 0x20U) { /* verify and alternate toggle bit */ - uint8_t toggle = SDO_C->CANrxData[0] & 0x10; + uint8_t toggle = SDO_C->CANrxData[0] & 0x10U; if (toggle != SDO_C->toggle) { abortCode = CO_SDO_AB_TOGGLE_BIT; SDO_C->state = CO_SDO_ST_ABORT; break; } - SDO_C->toggle = (toggle == 0x00) ? 0x10 : 0x00; + SDO_C->toggle = (toggle == 0x00U) ? 0x10 : 0x00; /* is end of transfer? */ if (SDO_C->finished) { @@ -754,7 +754,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { - if ((SDO_C->CANrxData[0] & 0xFB) == 0xA0) { + if ((SDO_C->CANrxData[0] & 0xFBU) == 0xA0U) { /* verify index and subindex */ uint16_t index; uint8_t subindex; @@ -769,7 +769,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->block_crc = 0; SDO_C->block_blksize = SDO_C->CANrxData[4]; - if ((SDO_C->block_blksize < 1) || (SDO_C->block_blksize > 127)) + if ((SDO_C->block_blksize < 1U) || (SDO_C->block_blksize > 127U)) SDO_C->block_blksize = 127; SDO_C->block_seqno = 0; CO_fifo_altBegin(&SDO_C->bufFifo, 0); @@ -784,17 +784,17 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { - if (SDO_C->CANrxData[0] == 0xA2) { + if (SDO_C->CANrxData[0] == 0xA2U) { /* check number of segments */ if (SDO_C->CANrxData[1] < SDO_C->block_seqno) { /* NOT all segments transferred successfully. * Re-transmit data after erroneous segment. */ size_t cntFailed = SDO_C->block_seqno - SDO_C->CANrxData[1]; - cntFailed = (cntFailed * 7) - SDO_C->block_noData; + cntFailed = (cntFailed * 7U) - SDO_C->block_noData; SDO_C->sizeTran -= cntFailed; CO_fifo_altBegin(&SDO_C->bufFifo, - (size_t)SDO_C->CANrxData[1] * 7); + (size_t)SDO_C->CANrxData[1] * 7U); SDO_C->finished = false; } else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) { @@ -824,7 +824,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { - if (SDO_C->CANrxData[0] == 0xA1) { + if (SDO_C->CANrxData[0] == 0xA1U) { /* SDO block download successfully transferred */ SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; @@ -892,13 +892,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, count = CO_fifo_getOccupied(&SDO_C->bufFifo); /* is expedited transfer, <= 4bytes of data */ - if (((SDO_C->sizeInd == 0) && (count <= 4)) - || ((SDO_C->sizeInd > 0) && (SDO_C->sizeInd <= 4)) + if (((SDO_C->sizeInd == 0U) && (count <= 4U)) + || ((SDO_C->sizeInd > 0U) && (SDO_C->sizeInd <= 4U)) ) { - SDO_C->CANtxBuff->data[0] |= 0x02; + SDO_C->CANtxBuff->data[0] |= 0x02U; /* verify length, indicate data size */ - if ((count == 0) || ((SDO_C->sizeInd > 0) && + if ((count == 0U) || ((SDO_C->sizeInd > 0U) && (SDO_C->sizeInd != count)) ) { SDO_C->state = CO_SDO_ST_IDLE; @@ -906,8 +906,8 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, ret = CO_SDO_RT_endedWithClientAbort; break; } - if (SDO_C->sizeInd > 0) { - SDO_C->CANtxBuff->data[0] |= 0x01 | ((4 - count) << 2); + if (SDO_C->sizeInd > 0U) { + SDO_C->CANtxBuff->data[0] |= 0x01U | ((4U - count) << 2); } /* copy data */ @@ -919,9 +919,9 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED /* segmented transfer, indicate data size */ - if (SDO_C->sizeInd > 0) { + if (SDO_C->sizeInd > 0U) { uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); - SDO_C->CANtxBuff->data[0] |= 0x01; + SDO_C->CANtxBuff->data[0] |= 0x01U; (void)memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); } #else @@ -948,7 +948,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* verify if sizeTran is too large */ SDO_C->sizeTran += count; - if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { SDO_C->sizeTran -= count; abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; @@ -956,16 +956,16 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* SDO command specifier */ - SDO_C->CANtxBuff->data[0] = (uint8_t)(SDO_C->toggle | ((7 - count) << 1)); + SDO_C->CANtxBuff->data[0] = (uint8_t)(SDO_C->toggle | ((7U - count) << 1)); /* is end of transfer? Verify also sizeTran */ - if ((CO_fifo_getOccupied(&SDO_C->bufFifo) == 0) && !bufferPartial) { - if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran < SDO_C->sizeInd)) { + if ((CO_fifo_getOccupied(&SDO_C->bufFifo) == 0U) && !bufferPartial) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; break; } - SDO_C->CANtxBuff->data[0] |= 0x01; + SDO_C->CANtxBuff->data[0] |= 0x01U; SDO_C->finished = true; } @@ -985,9 +985,9 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; /* indicate data size */ - if (SDO_C->sizeInd > 0) { + if (SDO_C->sizeInd > 0U) { uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); - SDO_C->CANtxBuff->data[0] |= 0x02; + SDO_C->CANtxBuff->data[0] |= 0x02U; (void)memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); } @@ -999,7 +999,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { - if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) < 7) && bufferPartial) { + if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) < 7U) && bufferPartial) { /* wait until data are refilled */ break; } @@ -1008,11 +1008,11 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* get up to 7 data bytes */ count = CO_fifo_altRead(&SDO_C->bufFifo, &SDO_C->CANtxBuff->data[1], 7); - SDO_C->block_noData = (uint8_t)(7 - count); + SDO_C->block_noData = (uint8_t)(7U - count); /* verify if sizeTran is too large */ SDO_C->sizeTran += count; - if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { SDO_C->sizeTran -= count; abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; @@ -1020,13 +1020,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* is end of transfer? Verify also sizeTran */ - if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0) && !bufferPartial){ - if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran < SDO_C->sizeInd)) { + if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0U) && !bufferPartial){ + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; break; } - SDO_C->CANtxBuff->data[0] |= 0x80; + SDO_C->CANtxBuff->data[0] |= 0x80U; SDO_C->finished = true; SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; } @@ -1049,7 +1049,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { - SDO_C->CANtxBuff->data[0] = 0xC1 | (SDO_C->block_noData << 2); + SDO_C->CANtxBuff->data[0] = 0xC1U | (SDO_C->block_noData << 2); SDO_C->CANtxBuff->data[1] = (uint8_t) SDO_C->block_crc; SDO_C->CANtxBuff->data[2] = (uint8_t) (SDO_C->block_crc >> 8); @@ -1120,16 +1120,16 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, SDO_C->sizeTran = 0; SDO_C->finished = false; CO_fifo_reset(&SDO_C->bufFifo); - SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; + SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000U; SDO_C->timeoutTimer = 0; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - SDO_C->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700; + SDO_C->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700U; #endif #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ - if (((SDO_C->OD != NULL) && (SDO_C->nodeId != 0)) + if (((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U)) && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId) ) { SDO_C->OD_IO.read = NULL; @@ -1205,7 +1205,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, size_t countFifo = CO_fifo_getSpace(&SDO_C->bufFifo); /* skip copying if buffer full */ - if (countFifo == 0) { + if (countFifo == 0U) { ret = CO_SDO_RT_uploadDataBufferFull; } /* read data, in several passes if necessary */ @@ -1213,7 +1213,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* Get size of data in Object Dictionary. If size is not indicated * use maximum SDO client buffer size. Prepare temp buffer. */ OD_size_t countData = SDO_C->OD_IO.stream.dataLength; - OD_size_t countBuf = ((countData > 0) && (countData <= countFifo)) + OD_size_t countBuf = ((countData > 0U) && (countData <= countFifo)) ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; @@ -1230,12 +1230,12 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else { /* if data is string, send only data up to null termination */ - if ((countRd > 0) + if ((countRd > 0U) && ((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0) ) { buf[countRd] = 0; /* (buf is one byte larger) */ OD_size_t countStr = (OD_size_t)strlen((char *)buf); - if (countStr == 0) countStr = 1; /* no zero length */ + if (countStr == 0U) countStr = 1; /* no zero length */ if (countStr < countRd) { /* string terminator found, finish read, shorten data */ countRd = countStr; @@ -1250,14 +1250,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* verify if size of data uploaded is too large */ SDO_C->sizeInd = SDO_C->OD_IO.stream.dataLength; - if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_LONG; ret = CO_SDO_RT_endedWithClientAbort; } /* If no more segments to be upload, finish */ else if (odRet == ODR_OK) { /* verify size of data uploaded */ - if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran < SDO_C->sizeInd)){ + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)){ abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; } @@ -1287,7 +1287,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* CAN data received ******************************************************/ else if (CO_FLAG_READ(SDO_C->CANrxNew)) { /* is SDO abort */ - if (SDO_C->CANrxData[0] == 0x80) { + if (SDO_C->CANrxData[0] == 0x80U) { uint32_t code; (void)memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); @@ -1301,7 +1301,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else switch (SDO_C->state) { case CO_SDO_ST_UPLOAD_INITIATE_RSP: { - if ((SDO_C->CANrxData[0] & 0xF0) == 0x40) { + if ((SDO_C->CANrxData[0] & 0xF0U) == 0x40U) { /* verify index and subindex */ uint16_t index; uint8_t subindex; @@ -1314,12 +1314,12 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } - if (SDO_C->CANrxData[0] & 0x02) { + if (SDO_C->CANrxData[0] & 0x02U) { /* Expedited transfer */ size_t count = 4; /* is size indicated? */ - if (SDO_C->CANrxData[0] & 0x01) { - count -= (SDO_C->CANrxData[0] >> 2) & 0x03; + if (SDO_C->CANrxData[0] & 0x01U) { + count -= (SDO_C->CANrxData[0] >> 2) & 0x03U; } /* copy data, indicate size and finish */ CO_fifo_write(&SDO_C->bufFifo, @@ -1332,7 +1332,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, else { #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED /* segmented transfer, is size indicated? */ - if (SDO_C->CANrxData[0] & 0x01) { + if (SDO_C->CANrxData[0] & 0x01U) { uint32_t size; (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); @@ -1354,20 +1354,20 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { - if ((SDO_C->CANrxData[0] & 0xE0) == 0x00) { + if ((SDO_C->CANrxData[0] & 0xE0U) == 0x00U) { size_t count, countWr; /* verify and alternate toggle bit */ - uint8_t toggle = SDO_C->CANrxData[0] & 0x10; + uint8_t toggle = SDO_C->CANrxData[0] & 0x10U; if (toggle != SDO_C->toggle) { abortCode = CO_SDO_AB_TOGGLE_BIT; SDO_C->state = CO_SDO_ST_ABORT; break; } - SDO_C->toggle = (toggle == 0x00) ? 0x10 : 0x00; + SDO_C->toggle = (toggle == 0x00U) ? 0x10 : 0x00; /* get data size and write data to the buffer */ - count = 7 - ((SDO_C->CANrxData[0] >> 1) & 0x07); + count = 7U - ((SDO_C->CANrxData[0] >> 1) & 0x07U); countWr = CO_fifo_write(&SDO_C->bufFifo, &SDO_C->CANrxData[1], count, NULL); @@ -1381,7 +1381,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* verify if size of data uploaded is too large */ - if ((SDO_C->sizeInd > 0) + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd) ) { abortCode = CO_SDO_AB_DATA_LONG; @@ -1390,9 +1390,9 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* If no more segments to be upload, finish */ - if (SDO_C->CANrxData[0] & 0x01) { + if (SDO_C->CANrxData[0] & 0x01U) { /* verify size of data uploaded */ - if ((SDO_C->sizeInd > 0) + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd) ) { abortCode = CO_SDO_AB_DATA_SHORT; @@ -1416,17 +1416,17 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { - if ((SDO_C->CANrxData[0] & 0xF9) == 0xC0) { + if ((SDO_C->CANrxData[0] & 0xF9U) == 0xC0U) { uint16_t index; uint8_t subindex; /* get server CRC support info and data size */ - if ((SDO_C->CANrxData[0] & 0x04) != 0) { + if ((SDO_C->CANrxData[0] & 0x04U) != 0U) { SDO_C->block_crcEnabled = true; } else { SDO_C->block_crcEnabled = false; } - if (SDO_C->CANrxData[0] & 0x02) { + if (SDO_C->CANrxData[0] & 0x02U) { uint32_t size; (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); @@ -1445,7 +1445,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } } /* switch to regular transfer, CO_SDO_ST_UPLOAD_INITIATE_RSP */ - else if ((SDO_C->CANrxData[0] & 0xF0) == 0x40) { + else if ((SDO_C->CANrxData[0] & 0xF0U) == 0x40U) { /* verify index and subindex */ uint16_t index; uint8_t subindex; @@ -1458,12 +1458,12 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } - if (SDO_C->CANrxData[0] & 0x02) { + if (SDO_C->CANrxData[0] & 0x02U) { /* Expedited transfer */ size_t count = 4; /* is size indicated? */ - if (SDO_C->CANrxData[0] & 0x01) { - count -= (SDO_C->CANrxData[0] >> 2) & 0x03; + if (SDO_C->CANrxData[0] & 0x01U) { + count -= (SDO_C->CANrxData[0] >> 2) & 0x03U; } /* copy data, indicate size and finish */ CO_fifo_write(&SDO_C->bufFifo, @@ -1475,7 +1475,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else { /* segmented transfer, is size indicated? */ - if (SDO_C->CANrxData[0] & 0x01) { + if (SDO_C->CANrxData[0] & 0x01U) { uint32_t size; (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); @@ -1497,18 +1497,18 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { - if ((SDO_C->CANrxData[0] & 0xE3) == 0xC1) { + if ((SDO_C->CANrxData[0] & 0xE3U) == 0xC1U) { /* Get number of data bytes in last segment, that do not * contain data. Then copy remaining data into fifo */ - uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07); + uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07U); CO_fifo_write(&SDO_C->bufFifo, &SDO_C->block_dataUploadLast[0], - 7 - noData, + 7U - noData, &SDO_C->block_crc); - SDO_C->sizeTran += 7 - noData; + SDO_C->sizeTran += 7U - noData; /* verify length */ - if ((SDO_C->sizeInd > 0) + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran != SDO_C->sizeInd) ) { abortCode = (SDO_C->sizeTran > SDO_C->sizeInd) ? @@ -1634,11 +1634,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { /* verify, if there is enough space in data buffer */ - if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7) { + if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7U) { ret = CO_SDO_RT_uploadDataBufferFull; break; } - SDO_C->CANtxBuff->data[0] = 0x60 | SDO_C->toggle; + SDO_C->CANtxBuff->data[0] = 0x60U | SDO_C->toggle; /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; @@ -1656,11 +1656,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; /* calculate number of block segments from free buffer space */ - count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7; - if (count > 127) { + count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7U; + if (count > 127U) { count = 127; } - else if (count == 0) { + else if (count == 0U) { abortCode = CO_SDO_AB_OUT_OF_MEM; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -1706,18 +1706,18 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else { /* verify if size of data uploaded is too large */ - if ((SDO_C->sizeInd > 0) && (SDO_C->sizeTran > SDO_C->sizeInd)) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; break; } /* calculate number of block segments from free buffer space */ - count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7; - if (count >= 127) { + count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7U; + if (count >= 127U) { count = 127; } - else if (CO_fifo_getOccupied(&SDO_C->bufFifo) > 0) { + else if (CO_fifo_getOccupied(&SDO_C->bufFifo) > 0U) { /* application must empty data buffer first */ ret = CO_SDO_RT_uploadDataBufferFull; #ifdef CO_DEBUG_SDO_CLIENT diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index afb9c174..9cc53109 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -59,8 +59,8 @@ static void CO_SDO_receive(void *object, void *msg) { uint8_t *data = CO_CANrxMsg_readData(msg); /* ignore messages with wrong length */ - if (DLC == 8) { - if (data[0] == 0x80) { + if (DLC == 8U) { + if (data[0] == 0x80U) { /* abort from client, just make idle */ SDO->state = CO_SDO_ST_IDLE; } @@ -184,11 +184,11 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, #endif /* verify valid bit */ - uint16_t idC2S = ((COB_IDClientToServer & 0x80000000L) == 0) ? - (uint16_t)COB_IDClientToServer : 0; - uint16_t idS2C = ((COB_IDServerToClient & 0x80000000L) == 0) ? - (uint16_t)COB_IDServerToClient : 0; - if ((idC2S != 0) && (idS2C != 0)) { + uint16_t idC2S = ((COB_IDClientToServer & 0x80000000UL) == 0U) ? + (uint16_t)COB_IDClientToServer : 0U; + uint16_t idS2C = ((COB_IDServerToClient & 0x80000000UL) == 0U) ? + (uint16_t)COB_IDServerToClient : 0U; + if ((idC2S != 0U) && (idS2C != 0U)) { SDO->valid = true; } else { @@ -249,12 +249,12 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, case 1: { /* COB-ID client -> server */ uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - uint16_t CAN_ID_cur = (uint16_t)(SDO->COB_IDClientToServer & 0x7FF); - bool_t valid = (COB_ID & 0x80000000) == 0; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + uint16_t CAN_ID_cur = (uint16_t)(SDO->COB_IDClientToServer & 0x7FFU); + bool_t valid = (COB_ID & 0x80000000U) == 0U; /* SDO client must not be valid when changing COB_ID */ - if (((COB_ID & 0x3FFFF800) != 0) + if (((COB_ID & 0x3FFFF800U) != 0U) || ((valid && SDO->valid) && (CAN_ID != CAN_ID_cur)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { @@ -271,12 +271,12 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, case 2: { /* COB-ID server -> client */ uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FF); - uint16_t CAN_ID_cur = (uint16_t)(SDO->COB_IDServerToClient & 0x7FF); - bool_t valid = (COB_ID & 0x80000000) == 0; + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + uint16_t CAN_ID_cur = (uint16_t)(SDO->COB_IDServerToClient & 0x7FFU); + bool_t valid = (COB_ID & 0x80000000U) == 0U; /* SDO client must not be valid when changing COB_ID */ - if (((COB_ID & 0x3FFFF800) != 0) + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && (SDO->valid && (CAN_ID != CAN_ID_cur))) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) ) { @@ -292,11 +292,11 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, } case 3: { /* Node-ID of the SDO server */ - if (count != 1) { + if (count != 1U) { return ODR_TYPE_MISMATCH; } uint8_t nodeId = CO_getUint8(buf); - if ((nodeId < 1) || (nodeId > 127)) { + if ((nodeId < 1U) || (nodeId > 127U)) { return ODR_INVALID_VALUE; } break; @@ -333,7 +333,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, SDO->OD = OD; SDO->nodeId = nodeId; #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) - SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000; + SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000U; #endif #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK SDO->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700; @@ -350,18 +350,18 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (OD_1200_SDOsrvPar == NULL) { /* configure default SDO channel */ - if ((nodeId < 1) || (nodeId > 127)) { return CO_ERROR_ILLEGAL_ARGUMENT; } + if ((nodeId < 1U) || (nodeId > 127U)) { return CO_ERROR_ILLEGAL_ARGUMENT; } - CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; - CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; + CanId_ClientToServer = (uint16_t)CO_CAN_ID_SDO_CLI + nodeId; + CanId_ServerToClient = (uint16_t)CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; } else { uint16_t OD_SDOsrvParIdx = OD_getIndex(OD_1200_SDOsrvPar); - if (OD_SDOsrvParIdx == OD_H1200_SDO_SERVER_1_PARAM) { + if (OD_SDOsrvParIdx == (uint16_t)OD_H1200_SDO_SERVER_1_PARAM) { /* configure default SDO channel and SDO server parameters for it */ - if ((nodeId < 1) || (nodeId > 127)) { + if ((nodeId < 1U) || (nodeId > 127U)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -386,7 +386,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, ODR_t odRet2 = OD_get_u32(OD_1200_SDOsrvPar, 2, &COB_IDServerToClient32, true); - if ((odRet0 != ODR_OK) || ((maxSubIndex != 2) && (maxSubIndex != 3)) + if ((odRet0 != ODR_OK) || ((maxSubIndex != 2U) && (maxSubIndex != 3U)) || (odRet1 != ODR_OK) || (odRet2 != ODR_OK) ) { if (errInfo != NULL) { *errInfo = OD_SDOsrvParIdx; } @@ -394,10 +394,10 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, } - CanId_ClientToServer = ((COB_IDClientToServer32 & 0x80000000) == 0) - ? (uint16_t)(COB_IDClientToServer32 & 0x7FF) : 0; - CanId_ServerToClient = ((COB_IDServerToClient32 & 0x80000000) == 0) - ? (uint16_t)(COB_IDServerToClient32 & 0x7FF) : 0; + CanId_ClientToServer = ((COB_IDClientToServer32 & 0x80000000U) == 0U) + ? (uint16_t)(COB_IDClientToServer32 & 0x7FFU) : 0U; + CanId_ServerToClient = ((COB_IDServerToClient32 & 0x80000000U) == 0U) + ? (uint16_t)(COB_IDServerToClient32 & 0x7FFU) : 0U; #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC SDO->OD_1200_extension.object = SDO; @@ -485,7 +485,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, if (SDO->finished) { /* Verify if size of data downloaded matches size indicated. */ - if ((SDO->sizeInd > 0) && (SDO->sizeTran != SDO->sizeInd)) { + if ((SDO->sizeInd > 0U) && (SDO->sizeTran != SDO->sizeInd)) { *abortCode = (SDO->sizeTran > SDO->sizeInd) ? CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; @@ -505,20 +505,20 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, * shorter than size of OD data buffer. If so, add two zero bytes * to terminate (unicode) string. Shorten also OD data size, * (temporary, send information about EOF into OD_IO.write) */ - if (((SDO->OD_IO.stream.attribute & ODA_STR) != 0) - && ((sizeInOd == 0) || (SDO->sizeTran < sizeInOd)) - && ((SDO->bufOffsetWr + 2) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE) + if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) + && ((sizeInOd == 0U) || (SDO->sizeTran < sizeInOd)) + && ((SDO->bufOffsetWr + 2U) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE) ) { SDO->buf[SDO->bufOffsetWr++] = 0; SDO->sizeTran++; - if ((sizeInOd == 0) || (SDO->sizeTran < sizeInOd)) { + if ((sizeInOd == 0U) || (SDO->sizeTran < sizeInOd)) { SDO->buf[SDO->bufOffsetWr++] = 0; SDO->sizeTran++; } SDO->OD_IO.stream.dataLength = SDO->sizeTran; } /* Indicate OD data size, if not indicated. Can be used for EOF check.*/ - else if (sizeInOd == 0) { + else if (sizeInOd == 0U) { SDO->OD_IO.stream.dataLength = SDO->sizeTran; } /* Verify if size of data downloaded matches data size in OD. */ @@ -532,7 +532,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, } else { /* Verify if size of data downloaded is not too large. */ - if ((SDO->sizeInd > 0) && (SDO->sizeTran > SDO->sizeInd)) { + if ((SDO->sizeInd > 0U) && (SDO->sizeTran > SDO->sizeInd)) { *abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; return false; @@ -630,10 +630,10 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, } /* if data is string, send only data up to null termination */ - if ((countRd > 0) && ((SDO->OD_IO.stream.attribute & ODA_STR) != 0)) { + if ((countRd > 0U) && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U)) { bufShifted[countRd] = 0; /* (SDO->buf is one byte larger) */ OD_size_t countStr = (OD_size_t)strlen((char *)bufShifted); - if (countStr == 0) { countStr = 1; }/* zero length is not allowed */ + if (countStr == 0U) { countStr = 1; }/* zero length is not allowed */ if (countStr < countRd) { /* string terminator found, read is finished, shorten data */ countRd = countStr; @@ -644,7 +644,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* partial or finished read */ SDO->bufOffsetWr = countRemain + countRd; - if ((SDO->bufOffsetWr == 0) || (odRet == ODR_PARTIAL)) { + if ((SDO->bufOffsetWr == 0U) || (odRet == ODR_PARTIAL)) { SDO->finished = false; if (SDO->bufOffsetWr < countMinimum) { *abortCode = CO_SDO_AB_DEVICE_INCOMPAT; @@ -717,10 +717,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if (SDO->state == CO_SDO_ST_IDLE) { /* new SDO communication? */ bool_t upload = false; - if ((SDO->CANrxData[0] & 0xF0) == 0x20) { + if ((SDO->CANrxData[0] & 0xF0U) == 0x20U) { SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; } - else if (SDO->CANrxData[0] == 0x40) { + else if (SDO->CANrxData[0] == 0x40U) { upload = true; SDO->state = CO_SDO_ST_UPLOAD_INITIATE_REQ; } @@ -752,18 +752,18 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } else { /* verify read/write attributes */ - if ((SDO->OD_IO.stream.attribute & ODA_SDO_RW) == 0) { + if ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_RW) == 0U) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; SDO->state = CO_SDO_ST_ABORT; } else if (upload - && ((SDO->OD_IO.stream.attribute & ODA_SDO_R) == 0) + && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_R) == 0U) ) { abortCode = CO_SDO_AB_WRITEONLY; SDO->state = CO_SDO_ST_ABORT; } else if (!upload - && ((SDO->OD_IO.stream.attribute & ODA_SDO_W) == 0) + && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_W) == 0U) ) { abortCode = CO_SDO_AB_READONLY; SDO->state = CO_SDO_ST_ABORT; @@ -786,7 +786,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->sizeInd = SDO->OD_IO.stream.dataLength; - if (SDO->sizeInd == 0) { + if (SDO->sizeInd == 0U) { SDO->sizeInd = SDO->bufOffsetWr; } else if (SDO->sizeInd != SDO->bufOffsetWr) { @@ -797,9 +797,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } else { /* If data type is string, size is not known */ - SDO->sizeInd = ((SDO->OD_IO.stream.attribute&ODA_STR)==0) + SDO->sizeInd = ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR)==0U) ? SDO->OD_IO.stream.dataLength - : 0; + : 0U; } } } @@ -809,7 +809,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if ((SDO->state != CO_SDO_ST_IDLE) && (SDO->state != CO_SDO_ST_ABORT)) { switch (SDO->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { - if (SDO->CANrxData[0] & 0x02) { + if (SDO->CANrxData[0] & 0x02U) { /* Expedited transfer, max 4 bytes of data */ /* Size of OD variable (>0 if indicated) */ @@ -817,10 +817,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Get SDO data size (indicated by SDO client or get from OD) */ OD_size_t dataSizeToWrite = 4; - if (SDO->CANrxData[0] & 0x01) { - dataSizeToWrite -= (SDO->CANrxData[0] >> 2) & 0x03; + if (SDO->CANrxData[0] & 0x01U) { + dataSizeToWrite -= (SDO->CANrxData[0] >> 2) & 0x03U; } - else if ((sizeInOd > 0) && (sizeInOd < 4)) { + else if ((sizeInOd > 0U) && (sizeInOd < 4U)) { dataSizeToWrite = sizeInOd; } else { /* MISRA C 2004 14.10 */ } @@ -838,14 +838,14 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, * shorter as size of OD data buffer. If so, add two zero bytes * to terminate (unicode) string. Shorten also OD data size, * (temporary, send information about EOF into OD_IO.write) */ - if (((SDO->OD_IO.stream.attribute & ODA_STR) != 0) - && ((sizeInOd == 0) || (dataSizeToWrite < sizeInOd)) + if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) + && ((sizeInOd == 0U) || (dataSizeToWrite < sizeInOd)) ) { OD_size_t delta = sizeInOd - dataSizeToWrite; - dataSizeToWrite += (delta == 1) ? 1 : 2; + dataSizeToWrite += (delta == 1U) ? 1U : 2U; SDO->OD_IO.stream.dataLength = dataSizeToWrite; } - else if (sizeInOd == 0) { + else if (sizeInOd == 0U) { SDO->OD_IO.stream.dataLength = dataSizeToWrite; } /* Verify if size of data downloaded matches data size in OD. */ @@ -880,7 +880,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, else { #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED /* segmented transfer, is size indicated? */ - if (SDO->CANrxData[0] & 0x01) { + if (SDO->CANrxData[0] & 0x01U) { uint32_t size; OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; @@ -888,7 +888,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->sizeInd = CO_SWAP_32(size); /* Indicated size of SDO matches sizeof OD variable? */ - if (sizeInOd > 0) { + if (sizeInOd > 0U) { if (SDO->sizeInd > sizeInOd) { abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; @@ -920,11 +920,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { - if ((SDO->CANrxData[0] & 0xE0) == 0x00) { - SDO->finished = (SDO->CANrxData[0] & 0x01) != 0; + if ((SDO->CANrxData[0] & 0xE0U) == 0x00U) { + SDO->finished = (SDO->CANrxData[0] & 0x01U) != 0U; /* verify and alternate toggle bit */ - uint8_t toggle = SDO->CANrxData[0] & 0x10; + uint8_t toggle = SDO->CANrxData[0] & 0x10U; if (toggle != SDO->toggle) { abortCode = CO_SDO_AB_TOGGLE_BIT; SDO->state = CO_SDO_ST_ABORT; @@ -932,13 +932,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* get data size and write data to the buffer */ - OD_size_t count = 7 - ((SDO->CANrxData[0] >> 1) & 0x07); + OD_size_t count = 7U - ((SDO->CANrxData[0] >> 1) & 0x07U); (void)memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); SDO->bufOffsetWr += count; SDO->sizeTran += count; /* if data size exceeds variable size, abort */ - if ((SDO->OD_IO.stream.dataLength > 0) + if ((SDO->OD_IO.stream.dataLength > 0U) && (SDO->sizeTran > SDO->OD_IO.stream.dataLength) ) { abortCode = CO_SDO_AB_DATA_LONG; @@ -948,7 +948,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* if necessary, empty the buffer */ if (SDO->finished - || ((CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7+2)) + || ((CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7U+2U)) ) { if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) { break; @@ -972,9 +972,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { - if ((SDO->CANrxData[0] & 0xEF) == 0x60) { + if ((SDO->CANrxData[0] & 0xEFU) == 0x60U) { /* verify and alternate toggle bit */ - uint8_t toggle = SDO->CANrxData[0] & 0x10; + uint8_t toggle = SDO->CANrxData[0] & 0x10U; if (toggle != SDO->toggle) { abortCode = CO_SDO_AB_TOGGLE_BIT; SDO->state = CO_SDO_ST_ABORT; @@ -1265,8 +1265,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { - SDO->CANtxBuff->data[0] = 0x20 | SDO->toggle; - SDO->toggle = (SDO->toggle == 0x00) ? 0x10 : 0x00; + SDO->CANtxBuff->data[0] = 0x20U | SDO->toggle; + SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; /* reset timeout timer and send message */ SDO->timeoutTimer = 0; @@ -1285,16 +1285,16 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_UPLOAD_INITIATE_RSP: { #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED /* data were already loaded from OD variable */ - if ((SDO->sizeInd > 0) && (SDO->sizeInd <= 4)) { + if ((SDO->sizeInd > 0U) && (SDO->sizeInd <= 4U)) { /* expedited transfer */ - SDO->CANtxBuff->data[0] = (uint8_t)(0x43|((4-SDO->sizeInd)<<2)); + SDO->CANtxBuff->data[0] = (uint8_t)(0x43U|((4U-SDO->sizeInd)<<2U)); (void)memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, SDO->sizeInd); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } else { /* data will be transferred with segmented transfer */ - if (SDO->sizeInd > 0) { + if (SDO->sizeInd > 0U) { /* indicate data size, if known */ uint32_t sizeInd = SDO->sizeInd; uint32_t sizeIndSw = CO_SWAP_32(sizeInd); @@ -1360,13 +1360,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* SDO command specifier with toggle bit */ SDO->CANtxBuff->data[0] = SDO->toggle; - SDO->toggle = (SDO->toggle == 0x00) ? 0x10 : 0x00; + SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; /* verify, if this is the last segment */ - if ((count < 7) || (SDO->finished && (count == 7))) { + if ((count < 7U) || (SDO->finished && (count == 7U))) { /* indicate last segment and nnn */ - SDO->CANtxBuff->data[0] |= ((7 - count) << 1) | 0x01; + SDO->CANtxBuff->data[0] |= ((7U - count) << 1U) | 0x01U; SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } @@ -1383,7 +1383,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->sizeTran += count; /* verify if sizeTran is too large or too short if last segment */ - if (SDO->sizeInd > 0) { + if (SDO->sizeInd > 0U) { if (SDO->sizeTran > SDO->sizeInd) { abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 594cd5c0..fc5a6817 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -37,7 +37,7 @@ CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE -#define CO_CONFIG_SDO_SRV_BUFFER_SIZE 32 +#define CO_CONFIG_SDO_SRV_BUFFER_SIZE 32U #endif #ifdef __cplusplus @@ -496,7 +496,7 @@ typedef struct { /** Timeout timer for SDO communication */ uint32_t timeoutTimer; /** Interim data buffer for segmented or block transfer + byte for '\0' */ - uint8_t buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE + 1]; + uint8_t buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE + 1U]; /** Offset of next free data byte available for write in the buffer. */ OD_size_t bufOffsetWr; /** Offset of first data available for read in the buffer */ diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 42dce65e..afee945e 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -39,22 +39,22 @@ static void CO_SYNC_receive(void *object, void *msg) { uint8_t DLC = CO_CANrxMsg_readDLC(msg); bool_t syncReceived = false; - if (SYNC->counterOverflowValue == 0) { - if (DLC == 0) { + if (SYNC->counterOverflowValue == 0U) { + if (DLC == 0U) { syncReceived = true; } else { - SYNC->receiveError = DLC | 0x40; + SYNC->receiveError = DLC | 0x40U; } } else { - if (DLC == 1) { + if (DLC == 1U) { uint8_t *data = CO_CANrxMsg_readData(msg); SYNC->counter = data[0]; syncReceived = true; } else { - SYNC->receiveError = DLC | 0x80; + SYNC->receiveError = DLC | 0x80U; } } @@ -83,7 +83,7 @@ static void CO_SYNC_receive(void *object, void *msg) { static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint32_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -91,7 +91,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, CO_SYNC_t *SYNC = stream->object; uint32_t cobIdSync = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(cobIdSync & 0x7FF); + uint16_t CAN_ID = (uint16_t)(cobIdSync & 0x7FFU); /* verify written value */ #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER @@ -102,7 +102,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, return ODR_INVALID_VALUE; } #else - if (((cobIdSync & 0xFFFFF800) != 0) || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { + if (((cobIdSync & 0xFFFFF800U) != 0U) || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { return ODR_INVALID_VALUE; } #endif @@ -287,8 +287,8 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, } return CO_ERROR_OD_PARAMETERS; } - if (syncCounterOvf == 1) { syncCounterOvf = 2; } - else if (syncCounterOvf > 240) { syncCounterOvf = 240; } + if (syncCounterOvf == 1U) { syncCounterOvf = 2; } + else if (syncCounterOvf > 240U) { syncCounterOvf = 240; } else { /* MISRA C 2004 14.10 */ } #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC @@ -305,10 +305,10 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, /* Configure object variables */ SYNC->em = em; #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER - SYNC->isProducer = (cobIdSync & 0x40000000) != 0; + SYNC->isProducer = (cobIdSync & 0x40000000U) != 0U; #endif #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC - SYNC->CAN_ID = cobIdSync & 0x7FF; + SYNC->CAN_ID = cobIdSync & 0x7FFU; SYNC->CANdevRx = CANdevRx; SYNC->CANdevRxIdx = CANdevRxIdx; #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER @@ -321,7 +321,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, CO_ReturnError_t ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ - cobIdSync & 0x7FF, /* CAN identifier */ + cobIdSync & 0x7FFU, /* CAN identifier */ 0x7FF, /* mask */ 0, /* rtr */ (void*)SYNC, /* object passed to receive function */ @@ -386,9 +386,9 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } uint32_t OD_1006_period = (SYNC->OD_1006_period != NULL) - ? *SYNC->OD_1006_period : 0; + ? *SYNC->OD_1006_period : 0U; - if (OD_1006_period > 0) { + if (OD_1006_period > 0U) { #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER if (SYNC->isProducer) { if (SYNC->timer >= OD_1006_period) { @@ -409,7 +409,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ /* Verify timeout of SYNC */ - if (SYNC->timeoutError == 1) { + if (SYNC->timeoutError == 1U) { /* periodTimeout is 1,5 * OD_1006_period, no overflow */ uint32_t periodTimeout = OD_1006_period + (OD_1006_period >> 1); if (periodTimeout < OD_1006_period) { @@ -417,7 +417,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } if (SYNC->timer > periodTimeout) { - CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, + CO_errorReport(SYNC->em, (uint8_t)CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); SYNC->timeoutError = 2; } @@ -434,7 +434,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } /* if (OD_1006_period > 0) */ /* Synchronous PDOs are allowed only inside time window */ - if ((SYNC->OD_1007_window != NULL) && (*SYNC->OD_1007_window > 0) + if ((SYNC->OD_1007_window != NULL) && (*SYNC->OD_1007_window > 0U) && (SYNC->timer > *SYNC->OD_1007_window) ) { if (!SYNC->syncIsOutsideWindow) { @@ -447,8 +447,8 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } /* verify error from receive function */ - if (SYNC->receiveError != 0) { CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, + if (SYNC->receiveError != 0U) { CO_EMC_SYNC_DATA_LENGTH, SYNC->receiveError); SYNC->receiveError = 0; } @@ -461,8 +461,8 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } if (syncStatus == CO_SYNC_RX_TX) { - if (SYNC->timeoutError == 2) { CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, 0); + if (SYNC->timeoutError == 2U) { } SYNC->timeoutError = 1; } diff --git a/301/CO_TIME.c b/301/CO_TIME.c index fe8da0e4..ee6201ef 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -64,7 +64,7 @@ static void CO_TIME_receive(void *object, void *msg) { static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint32_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -74,14 +74,14 @@ static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, /* verify written value */ uint32_t cobIdTimeStamp = CO_getUint32(buf); - uint16_t CAN_ID = cobIdTimeStamp & 0x7FF; - if (((cobIdTimeStamp & 0x3FFFF800) != 0) || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { + uint16_t CAN_ID = cobIdTimeStamp & 0x7FFU; + if (((cobIdTimeStamp & 0x3FFFF800U) != 0U) || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { return ODR_INVALID_VALUE; } /* update object */ - TIME->isConsumer = (cobIdTimeStamp & 0x80000000L) != 0; - TIME->isProducer = (cobIdTimeStamp & 0x40000000L) != 0; + TIME->isConsumer = (cobIdTimeStamp & 0x80000000UL) != 0U; + TIME->isProducer = (cobIdTimeStamp & 0x40000000UL) != 0U; /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, buf, count, countWritten); @@ -125,9 +125,9 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, #endif /* Configure object variables */ - uint16_t cobId = cobIdTimeStamp & 0x7FF; - TIME->isConsumer = (cobIdTimeStamp & 0x80000000L) != 0; - TIME->isProducer = (cobIdTimeStamp & 0x40000000L) != 0; + uint16_t cobId = cobIdTimeStamp & 0x7FFU; + TIME->isConsumer = (cobIdTimeStamp & 0x80000000UL) != 0U; + TIME->isProducer = (cobIdTimeStamp & 0x40000000UL) != 0U; CO_FLAG_CLEAR(TIME->CANrxNew); /* configure TIME consumer message reception */ @@ -189,7 +189,7 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, if(CO_FLAG_READ(TIME->CANrxNew)) { uint32_t ms_swapped = CO_getUint32(&TIME->timeStamp[0]); uint16_t days_swapped = CO_getUint16(&TIME->timeStamp[4]); - TIME->ms = CO_SWAP_32(ms_swapped) & 0x0FFFFFFF; + TIME->ms = CO_SWAP_32(ms_swapped) & 0x0FFFFFFFU; TIME->days = CO_SWAP_16(days_swapped); TIME->residual_us = 0; timestampReceived = true; @@ -203,14 +203,14 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, /* Update time */ uint32_t ms = 0; - if (!timestampReceived && (timeDifference_us > 0)) { + if (!timestampReceived && (timeDifference_us > 0U)) { uint32_t us = timeDifference_us + TIME->residual_us; - ms = us / 1000; - TIME->residual_us = us % 1000; + ms = us / 1000U; + TIME->residual_us = us % 1000U; TIME->ms += ms; - if (TIME->ms >= ((uint32_t)1000*60*60*24)) { - TIME->ms -= ((uint32_t)1000*60*60*24); - TIME->days += 1; + if (TIME->ms >= ((uint32_t)1000U*60U*60U*24U)) { + TIME->ms -= ((uint32_t)1000U*60U*60U*24U); + TIME->days += 1U; } } diff --git a/301/CO_TIME.h b/301/CO_TIME.h index 9602551f..a97acc70 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -72,7 +72,7 @@ extern "C" { /** Length of the TIME message */ -#define CO_TIME_MSG_LENGTH 6 +#define CO_TIME_MSG_LENGTH 6U /** diff --git a/301/CO_driver.h b/301/CO_driver.h index 99830b10..5f79e44c 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -477,25 +477,25 @@ typedef struct { * in PDO linking phase of the CANopen network configuration. */ typedef enum { - CO_CAN_ID_NMT_SERVICE = 0x000, /**< 0x000, Network management */ - CO_CAN_ID_GFC = 0x001, /**< 0x001, Global fail-safe command */ - CO_CAN_ID_SYNC = 0x080, /**< 0x080, Synchronous message */ - CO_CAN_ID_EMERGENCY = 0x080, /**< 0x080, Emergency messages (+nodeID) */ - CO_CAN_ID_TIME = 0x100, /**< 0x100, Time message */ - CO_CAN_ID_SRDO_1 = 0x0FF, /**< 0x0FF, Default SRDO1 (+2*nodeID) */ - CO_CAN_ID_TPDO_1 = 0x180, /**< 0x180, Default TPDO1 (+nodeID) */ - CO_CAN_ID_RPDO_1 = 0x200, /**< 0x200, Default RPDO1 (+nodeID) */ - CO_CAN_ID_TPDO_2 = 0x280, /**< 0x280, Default TPDO2 (+nodeID) */ - CO_CAN_ID_RPDO_2 = 0x300, /**< 0x300, Default RPDO2 (+nodeID) */ - CO_CAN_ID_TPDO_3 = 0x380, /**< 0x380, Default TPDO3 (+nodeID) */ - CO_CAN_ID_RPDO_3 = 0x400, /**< 0x400, Default RPDO3 (+nodeID) */ - CO_CAN_ID_TPDO_4 = 0x480, /**< 0x480, Default TPDO4 (+nodeID) */ - CO_CAN_ID_RPDO_4 = 0x500, /**< 0x500, Default RPDO5 (+nodeID) */ - CO_CAN_ID_SDO_SRV = 0x580, /**< 0x580, SDO response from server (+nodeID) */ - CO_CAN_ID_SDO_CLI = 0x600, /**< 0x600, SDO request from client (+nodeID) */ - CO_CAN_ID_HEARTBEAT = 0x700, /**< 0x700, Heartbeat message */ - CO_CAN_ID_LSS_SLV = 0x7E4, /**< 0x7E4, LSS response from slave */ - CO_CAN_ID_LSS_MST = 0x7E5 /**< 0x7E5, LSS request from master */ + CO_CAN_ID_NMT_SERVICE = 0x000U, /**< 0x000, Network management */ + CO_CAN_ID_GFC = 0x001U, /**< 0x001, Global fail-safe command */ + CO_CAN_ID_SYNC = 0x080U, /**< 0x080, Synchronous message */ + CO_CAN_ID_EMERGENCY = 0x080U, /**< 0x080, Emergency messages (+nodeID) */ + CO_CAN_ID_TIME = 0x100U, /**< 0x100, Time message */ + CO_CAN_ID_SRDO_1 = 0x0FFU, /**< 0x0FF, Default SRDO1 (+2*nodeID) */ + CO_CAN_ID_TPDO_1 = 0x180U, /**< 0x180, Default TPDO1 (+nodeID) */ + CO_CAN_ID_RPDO_1 = 0x200U, /**< 0x200, Default RPDO1 (+nodeID) */ + CO_CAN_ID_TPDO_2 = 0x280U, /**< 0x280, Default TPDO2 (+nodeID) */ + CO_CAN_ID_RPDO_2 = 0x300U, /**< 0x300, Default RPDO2 (+nodeID) */ + CO_CAN_ID_TPDO_3 = 0x380U, /**< 0x380, Default TPDO3 (+nodeID) */ + CO_CAN_ID_RPDO_3 = 0x400U, /**< 0x400, Default RPDO3 (+nodeID) */ + CO_CAN_ID_TPDO_4 = 0x480U, /**< 0x480, Default TPDO4 (+nodeID) */ + CO_CAN_ID_RPDO_4 = 0x500U, /**< 0x500, Default RPDO5 (+nodeID) */ + CO_CAN_ID_SDO_SRV = 0x580U, /**< 0x580, SDO response from server (+nodeID) */ + CO_CAN_ID_SDO_CLI = 0x600U, /**< 0x600, SDO request from client (+nodeID) */ + CO_CAN_ID_HEARTBEAT = 0x700U, /**< 0x700, Heartbeat message */ + CO_CAN_ID_LSS_SLV = 0x7E4U, /**< 0x7E4, LSS response from slave */ + CO_CAN_ID_LSS_MST = 0x7E5U /**< 0x7E5, LSS request from master */ } CO_Default_CAN_ID_t; @@ -506,12 +506,12 @@ typedef enum { * They shall not be used for SYNC, TIME, EMCY, PDO and SDO. */ #ifndef CO_IS_RESTRICTED_CAN_ID -#define CO_IS_RESTRICTED_CAN_ID(CAN_ID) (((CAN_ID) <= 0x7F) \ - || (((CAN_ID) >= 0x101) && ((CAN_ID) <= 0x180)) \ - || (((CAN_ID) >= 0x581) && ((CAN_ID) <= 0x5FF)) \ - || (((CAN_ID) >= 0x601) && ((CAN_ID) <= 0x67F)) \ - || (((CAN_ID) >= 0x6E0) && ((CAN_ID) <= 0x6FF)) \ - || ((CAN_ID) >= 0x701)) +#define CO_IS_RESTRICTED_CAN_ID(CAN_ID) (((CAN_ID) <= 0x7FU) \ + || (((CAN_ID) >= 0x101U) && ((CAN_ID) <= 0x180U)) \ + || (((CAN_ID) >= 0x581U) && ((CAN_ID) <= 0x5FFU)) \ + || (((CAN_ID) >= 0x601U) && ((CAN_ID) <= 0x67FU)) \ + || (((CAN_ID) >= 0x6E0U) && ((CAN_ID) <= 0x6FFU)) \ + || ((CAN_ID) >= 0x701U)) #endif @@ -524,18 +524,18 @@ typedef enum { * counter is more or equal to 256. */ typedef enum { - CO_CAN_ERRTX_WARNING = 0x0001, /**< 0x0001, CAN transmitter warning */ - CO_CAN_ERRTX_PASSIVE = 0x0002, /**< 0x0002, CAN transmitter passive */ - CO_CAN_ERRTX_BUS_OFF = 0x0004, /**< 0x0004, CAN transmitter bus off */ - CO_CAN_ERRTX_OVERFLOW = 0x0008, /**< 0x0008, CAN transmitter overflow */ + CO_CAN_ERRTX_WARNING = 0x0001U, /**< 0x0001, CAN transmitter warning */ + CO_CAN_ERRTX_PASSIVE = 0x0002U, /**< 0x0002, CAN transmitter passive */ + CO_CAN_ERRTX_BUS_OFF = 0x0004U, /**< 0x0004, CAN transmitter bus off */ + CO_CAN_ERRTX_OVERFLOW = 0x0008U, /**< 0x0008, CAN transmitter overflow */ - CO_CAN_ERRTX_PDO_LATE = 0x0080, /**< 0x0080, TPDO is outside sync window */ + CO_CAN_ERRTX_PDO_LATE = 0x0080U, /**< 0x0080, TPDO is outside sync window */ - CO_CAN_ERRRX_WARNING = 0x0100, /**< 0x0100, CAN receiver warning */ - CO_CAN_ERRRX_PASSIVE = 0x0200, /**< 0x0200, CAN receiver passive */ - CO_CAN_ERRRX_OVERFLOW = 0x0800, /**< 0x0800, CAN receiver overflow */ + CO_CAN_ERRRX_WARNING = 0x0100U, /**< 0x0100, CAN receiver warning */ + CO_CAN_ERRRX_PASSIVE = 0x0200U, /**< 0x0200, CAN receiver passive */ + CO_CAN_ERRRX_OVERFLOW = 0x0800U, /**< 0x0800, CAN receiver overflow */ - CO_CAN_ERR_WARN_PASSIVE = 0x0303/**< 0x0303, combination */ + CO_CAN_ERR_WARN_PASSIVE = 0x0303U/**< 0x0303, combination */ } CO_CAN_ERR_status_t; diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 12cb414c..1cc2b101 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -54,7 +54,7 @@ /******************************************************************************/ void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize) { - if ((fifo == NULL) || (buf == NULL) || (bufSize < 2)) { + if ((fifo == NULL) || (buf == NULL) || (bufSize < 2U)) { return; } @@ -93,12 +93,12 @@ size_t CO_fifo_write(CO_fifo_t *fifo, } bufDest = &fifo->buf[fifo->writePtr]; - for (i = count; i > 0; i--) { - size_t writePtrNext = fifo->writePtr + 1; + for (i = count; i > 0U; i--) { + size_t writePtrNext = fifo->writePtr + 1U; /* is circular buffer full */ if ((writePtrNext == fifo->readPtr) || - ((writePtrNext == fifo->bufSize) && (fifo->readPtr == 0))) { + ((writePtrNext == fifo->bufSize) && (fifo->readPtr == 0U))) { break; } @@ -139,7 +139,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { } bufSrc = &fifo->buf[fifo->readPtr]; - for (i = count; i > 0; ) { + for (i = count; i > 0U; ) { const uint8_t c = *bufSrc; /* is circular buffer empty */ @@ -182,7 +182,7 @@ size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset) { } fifo->altReadPtr = fifo->readPtr; - for (i = offset; i > 0; i--) { + for (i = offset; i > 0U; i--) { /* is circular buffer empty */ if (fifo->altReadPtr == fifo->writePtr) { break; @@ -229,7 +229,7 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count) { const uint8_t *bufSrc; bufSrc = &fifo->buf[fifo->altReadPtr]; - for (i = count; i > 0; i--) { + for (i = count; i > 0U; i--) { const uint8_t c = *bufSrc; /* is there no more data */ @@ -282,12 +282,12 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { commandEnd = (uint8_t *)memchr((const void *)&fifo->buf[0], (int)DELIM_COMMAND, fifo->writePtr); - if ((commandEnd != NULL) || (fifo->readPtr == (fifo->writePtr + 1))) { + if ((commandEnd != NULL) || (fifo->readPtr == (fifo->writePtr + 1U))) { /* command delimiter found or buffer full */ newCommand = true; } } - else if ((fifo->readPtr == 0) && (fifo->writePtr == (fifo->bufSize - 1))) { + else if ((fifo->readPtr == 0U) && (fifo->writePtr == (fifo->bufSize - 1U))) { /* buffer full */ newCommand = true; } @@ -295,7 +295,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { /* Clear buffer if set so */ if (clear) { if (commandEnd != NULL) { - fifo->readPtr = (size_t)(commandEnd - fifo->buf) + 1; + fifo->readPtr = (size_t)(commandEnd - fifo->buf) + 1U; if (fifo->readPtr == fifo->bufSize) { fifo->readPtr = 0; } @@ -348,7 +348,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, bool_t delimCommentFound = false; size_t tokenSize = 0; - if ((fifo != NULL) && (buf != NULL) && (count > 1) && ((err == NULL) || (*err == 0)) + if ((fifo != NULL) && (buf != NULL) && (count > 1U) && ((err == NULL) || (*err == false)) && (fifo->readPtr != fifo->writePtr) ) { bool_t finished = false; @@ -425,7 +425,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, } /* end, if buffer is now empty */ if (ptr == fifo->writePtr) { - if (step == 2) { + if (step == 2U) { fifo->readPtr = ptr; } else { @@ -440,8 +440,8 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, /* set 'err' return value */ if ((err != NULL) && (*err == false)) { if ((tokenSize == count) || ((closed != NULL) && - (((*closed == 1) && (!delimCommandFound || (tokenSize == 0))) || - ((*closed == 0) && (delimCommandFound || (tokenSize == 0)))) + (((*closed == 1) && (!delimCommandFound || (tokenSize == 0U))) || + ((*closed == 0) && (delimCommandFound || (tokenSize == 0U)))) )) { *err = true; } @@ -488,7 +488,7 @@ static const uint8_t base64DecTable[] = { size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; - if ((fifo != NULL) && (count >= 6) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, &n, sizeof(n), NULL); return sprintf(buf, "%"PRIu8, n); } @@ -500,7 +500,7 @@ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; - if ((fifo != NULL) && (count >= 8) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); } @@ -512,7 +512,7 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; - if ((fifo != NULL) && (count >= 12) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 12U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); } @@ -524,7 +524,7 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; - if ((fifo != NULL) && (count >= 20) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); } @@ -536,7 +536,7 @@ size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; - if ((fifo != NULL) && (count >= 6) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%02"PRIX8, n); } @@ -548,7 +548,7 @@ size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; - if ((fifo != NULL) && (count >= 8) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); } @@ -560,7 +560,7 @@ size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; - if ((fifo != NULL) && (count >= 12) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 12U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); } @@ -572,7 +572,7 @@ size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; - if ((fifo != NULL) && (count >= 20) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); } @@ -584,7 +584,7 @@ size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int8_t n=0; - if ((fifo != NULL) && (count >= 6) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId8, n); } @@ -596,7 +596,7 @@ size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int16_t n=0; - if ((fifo != NULL) && (count >= 8) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId16, CO_SWAP_16(n)); } @@ -608,7 +608,7 @@ size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int32_t n=0; - if ((fifo != NULL) && (count >= 13) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 13U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId32, CO_SWAP_32(n)); } @@ -620,7 +620,7 @@ size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int64_t n=0; - if ((fifo != NULL) && (count >= 23) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 23U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId64, CO_SWAP_64(n)); } @@ -632,7 +632,7 @@ size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float32_t n=0; - if ((fifo != NULL) && (count >= 20) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", (double)CO_SWAP_32(n)); } @@ -644,7 +644,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float64_t n=0; - if ((fifo != NULL) && (count >= 30) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if ((fifo != NULL) && (count >= 30U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", (double)CO_SWAP_64(n)); } @@ -658,7 +658,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t len = 0; - if ((fifo != NULL) && (count > 3)) { + if ((fifo != NULL) && (count > 3U)) { /* Very first write is without leading space */ if (!fifo->started) { uint8_t c; @@ -668,7 +668,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } } - while ((len + 3) < count) { + while ((len + 3U) < count) { uint8_t c; if(!CO_fifo_getc(fifo, &c)) { break; @@ -683,14 +683,14 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t len = 0; - if ((fifo != NULL) && (count > 3)) { + if ((fifo != NULL) && (count > 3U)) { /* Start with '"' */ if (!fifo->started) { buf[len++] = '"'; fifo->started = true; } - while ((len + 2) < count) { + while ((len + 2U) < count) { uint8_t c; if(!CO_fifo_getc(fifo, &c)) { if (end) { @@ -698,7 +698,7 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } break; } - else if ((c != 0) && (c != (uint8_t)'\r')) { + else if ((c != 0U) && (c != (uint8_t)'\r')) { /* skip null and CR inside string */ buf[len++] = (char)c; if (c == DELIM_DQUOTE) { @@ -716,7 +716,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t len = 0; - if ((fifo != NULL) && (count >= 4)) { + if ((fifo != NULL) && (count >= 4U)) { uint8_t step; uint16_t word; @@ -731,7 +731,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { word = (uint16_t)fifo->aux; } - while ((len + 3) <= count) { + while ((len + 3U) <= count) { uint8_t c; if(!CO_fifo_getc(fifo, &c)) { @@ -740,12 +740,12 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { /* add padding if necessary */ switch (step) { case 1: - buf[len++] = base64EncTable[(word >> 4) & 0x3F]; + buf[len++] = base64EncTable[(word >> 4) & 0x3FU]; buf[len++] = '='; buf[len++] = '='; break; case 2: - buf[len++] = base64EncTable[(word >> 6) & 0x3F]; + buf[len++] = base64EncTable[(word >> 6) & 0x3FU]; buf[len++] = '='; break; default: @@ -760,14 +760,14 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { switch (step++) { case 0: - buf[len++] = base64EncTable[(word >> 2) & 0x3F]; + buf[len++] = base64EncTable[(word >> 2) & 0x3FU]; break; case 1: - buf[len++] = base64EncTable[(word >> 4) & 0x3F]; + buf[len++] = base64EncTable[(word >> 4) & 0x3FU]; break; default: - buf[len++] = base64EncTable[(word >> 6) & 0x3F]; - buf[len++] = base64EncTable[word & 0x3F]; + buf[len++] = base64EncTable[(word >> 6) & 0x3FU]; + buf[len++] = base64EncTable[word & 0x3FU]; step = 0; break; } @@ -790,7 +790,7 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); @@ -812,7 +812,7 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); @@ -834,7 +834,7 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); @@ -856,7 +856,7 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; uint64_t u64 = strtoull(buf, &sRet, 0); @@ -878,7 +878,7 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); @@ -901,7 +901,7 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); @@ -924,7 +924,7 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); @@ -946,7 +946,7 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; int64_t i64 = strtoll(buf, &sRet, 0); @@ -968,7 +968,7 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; float32_t f32 = strtof(buf, &sRet); @@ -990,7 +990,7 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); CO_fifo_st st = (uint8_t)closed; - if ((nRd == 0) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; float64_t f64 = strtof(buf, &sRet); @@ -1033,18 +1033,18 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else { /* get memorized variables from previous function calls */ step = (uint8_t)(dest->aux >> 8); - firstChar = (uint8_t)(dest->aux & 0xFF); + firstChar = (uint8_t)(dest->aux & 0xFFU); } /* repeat until destination space available and no error and not finished * and source characters available */ - while ((destSpace > 0) && ((st & CO_fifo_st_errMask) == 0) && !finished) { + while ((destSpace > 0U) && ((st & CO_fifo_st_errMask) == 0U) && !finished) { uint8_t c; if (!CO_fifo_getc(src, &c)) { break; } - if (step == 6) { + if (step == 6U) { /* command is inside comment, waiting for command delimiter */ bool_t insideComment = true; if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { @@ -1056,7 +1056,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (isxdigit((int)c) != 0) { /* first or second hex digit */ - if (step == 0) { + if (step == 0U) { firstChar = c; step = 1; } @@ -1080,7 +1080,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } else { /* this is space or delimiter */ - if (step == 1) { + if (step == 1U) { /* write the byte */ uint8_t s[2]; int32_t num; @@ -1143,7 +1143,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* repeat until destination space available and no error and not finished * and source characters available */ - while ((destSpace > 0) && ((st & CO_fifo_st_errMask) == 0) && !finished) { + while ((destSpace > 0U) && ((st & CO_fifo_st_errMask) == 0U) && !finished) { uint8_t c; if (!CO_fifo_getc(src, &c)) { break; @@ -1169,9 +1169,9 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (c == DELIM_DQUOTE) { /* double quote found, this may be end of the string or escaped * double quote (with two double quotes) */ - step += 2; + step += 2U; } - else if ((isgraph((int)c) == 0) && (step == 2)) { + else if ((isgraph((int)c) == 0) && (step == 2U)) { /* end of single word string */ bool_t insideComment = false; if ((c == DELIM_COMMAND) @@ -1201,11 +1201,11 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* escaped double quote, copy the character and continue */ CO_fifo_putc(dest, c); destSpace--; - step -= 2; + step -= 2U; } else { /* previous character was closing double quote */ - if (step == 4) { + if (step == 4U) { /* no opening double quote, syntax error */ st |= CO_fifo_st_errTok; } @@ -1303,20 +1303,20 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else { /* get memorized variables from previous function calls */ step = (uint8_t)(dest->aux >> 24); - dword = dest->aux & 0xFFFFFF; + dword = dest->aux & 0xFFFFFFU; } /* repeat until destination space available and no error and not finished * and source characters available */ - while ((destSpace >= 3) && ((st & CO_fifo_st_errMask) == 0) && !finished) { + while ((destSpace >= 3U) && ((st & CO_fifo_st_errMask) == 0U) && !finished) { uint8_t c; if (!CO_fifo_getc(src, &c)) { break; } - if (step >= 5) { + if (step >= 5U) { /* String token is finished, waiting for command delimiter */ - bool_t insideComment = step > 5; + bool_t insideComment = step > 5U; if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { st |= CO_fifo_st_closed; finished = true; @@ -1333,12 +1333,12 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { continue; } - uint8_t code = base64DecTable[c & 0x7F]; + uint8_t code = base64DecTable[c & 0x7FU]; - if (((c & 0x80) != 0) || ((code & 0x80) != 0)) { + if (((c & 0x80U) != 0U) || ((code & 0x80U) != 0U)) { st |= CO_fifo_st_errTok; } - else if (code >= 64 /* '=' (pad) or DELIM_COMMAND or space */) { + else if (code >= 64U /* '=' (pad) or DELIM_COMMAND or space */) { /* base64 string finished, write remaining bytes */ switch (step) { case 2: @@ -1348,7 +1348,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { case 3: CO_fifo_putc(dest, (uint8_t)(dword >> 10)); CO_fifo_putc(dest, (uint8_t)(dword >> 2)); - destSpace -= 2; + destSpace -= 2U; break; default: /* MISRA C 2004 15.3 */ @@ -1366,11 +1366,11 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } else { dword = (dword << 6) | code; - if (step++ == 3) { - CO_fifo_putc(dest, (uint8_t)((dword >> 16) & 0xFF)); - CO_fifo_putc(dest, (uint8_t)((dword >> 8) & 0xFF)); - CO_fifo_putc(dest, (uint8_t)(dword & 0xFF)); - destSpace -= 3; + if (step++ == 3U) { + CO_fifo_putc(dest, (uint8_t)((dword >> 16) & 0xFFU)); + CO_fifo_putc(dest, (uint8_t)((dword >> 8) & 0xFFU)); + CO_fifo_putc(dest, (uint8_t)(dword & 0xFFU)); + destSpace -= 3U; dword = 0; step = 0; } @@ -1380,7 +1380,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { if (!finished) { st |= CO_fifo_st_partial; /* memorize variables for next iteration */ - dest->aux = ((uint32_t)step << 24) | (dword & 0xFFFFFF); + dest->aux = ((uint32_t)step << 24) | (dword & 0xFFFFFFU); } if (status != NULL) *status = st; diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index c7e4c4d3..d085cdc3 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -64,13 +64,13 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, bool_t tick = false; LEDs->LEDtmr50ms += timeDifference_us; - while (LEDs->LEDtmr50ms >= 50000) { bool_t rdFlickerNext = (LEDs->LEDred & CO_LED_flicker) == 0; + while (LEDs->LEDtmr50ms >= 50000U) { tick = true; - LEDs->LEDtmr50ms -= 50000; + LEDs->LEDtmr50ms -= 50000U; - if (++LEDs->LEDtmr200ms > 3) { + if (++LEDs->LEDtmr200ms > 3U) { /* calculate 2,5Hz blinking and flashing */ LEDs->LEDtmr200ms = 0; rd = gr = 0; diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index 21f02deb..ba092ce3 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -75,19 +75,19 @@ extern "C" { /** Bitfield for combining with red or green led */ typedef enum { - CO_LED_flicker = 0x01, /**< LED flickering 10Hz */ - CO_LED_blink = 0x02, /**< LED blinking 2,5Hz */ - CO_LED_flash_1 = 0x04, /**< LED single flash */ - CO_LED_flash_2 = 0x08, /**< LED double flash */ - CO_LED_flash_3 = 0x10, /**< LED triple flash */ - CO_LED_flash_4 = 0x20, /**< LED quadruple flash */ - CO_LED_CANopen = 0x80 /**< LED CANopen according to CiA 303-3 */ + CO_LED_flicker = 0x01U, /**< LED flickering 10Hz */ + CO_LED_blink = 0x02U, /**< LED blinking 2,5Hz */ + CO_LED_flash_1 = 0x04U, /**< LED single flash */ + CO_LED_flash_2 = 0x08U, /**< LED double flash */ + CO_LED_flash_3 = 0x10U, /**< LED triple flash */ + CO_LED_flash_4 = 0x20U, /**< LED quadruple flash */ + CO_LED_CANopen = 0x80U /**< LED CANopen according to CiA 303-3 */ } CO_LED_BITFIELD_t; /** Get on/off state for green led for specified bitfield */ -#define CO_LED_RED(LEDs, BITFIELD) (((LEDs)->LEDred & BITFIELD) ? 1 : 0) +#define CO_LED_RED(LEDs, BITFIELD) ((((LEDs)->LEDred & BITFIELD) != 0U) ? 1U : 0U) /** Get on/off state for green led for specified bitfield */ -#define CO_LED_GREEN(LEDs, BITFIELD) (((LEDs)->LEDgreen & BITFIELD) ? 1 : 0) +#define CO_LED_GREEN(LEDs, BITFIELD) ((((LEDs)->LEDgreen & BITFIELD) != 0U) ? 1U : 0U) /** diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 088eff6c..760296ef 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -44,7 +44,7 @@ #define CO_SRDO_INVALID (0U) #define CO_SRDO_TX (1U) #define CO_SRDO_RX (2U) -#define CO_SRDO_VALID_MAGIC (0xA5) +#define CO_SRDO_VALID_MAGIC (0xA5U) /* macro for information about SRDO configuration error */ #define ERR_INFO(index, subindex, info) (((uint32_t)(index) << 16) | ((uint32_t)(subindex) << 8) | ((uint32_t)(info))) @@ -147,7 +147,7 @@ OD_not_write_same_value(OD_stream_t *stream, const void *buf, OD_size_t count) { // The conformance test tool does not recognize CANopen Safety and on all object dictionaty tries to read and write the same value OD_size_t countRead = 0; uint8_t bufRead[6] = { 0 }; - if( count > 6 ) { + if( count > 6U ) { return false; } ODR_t returnCode = OD_readOriginal(stream, bufRead, count, &countRead); @@ -166,7 +166,7 @@ OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); /* When reading COB_ID, add Node-Id to the read value, if necessary */ - if ((returnCode == ODR_OK) && ((stream->subIndex == 5U) || (stream->subIndex == 6U)) && (*countRead == 4)) { + if ((returnCode == ODR_OK) && ((stream->subIndex == 5U) || (stream->subIndex == 6U)) && (*countRead == 4U)) { CO_SRDO_t* SRDO = stream->object; uint32_t value = CO_getUint32(buf); @@ -174,7 +174,7 @@ OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, /* If default COB ID is used, then OD entry does not contain $NodeId. Add it here. */ if ((value == defaultCOB_ID) && (SRDO->nodeId <= 64U)) { - value += (uint32_t)SRDO->nodeId * 2; + value += (uint32_t)SRDO->nodeId * 2U; } (void)CO_setUint32(buf, value); @@ -185,7 +185,7 @@ OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, static ODR_t OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { - if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4)) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4U)) { return ODR_DEV_INCOMPAT; } @@ -212,19 +212,19 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t return ODR_INVALID_VALUE; } SRDO->informationDirection = value; - } else if (stream->subIndex == 2) { /* SCT */ + } else if (stream->subIndex == 2U) { /* SCT */ uint16_t value = CO_getUint16(buf); - if (value < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000) + 1)) { + if (value < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000U) + 1U)) { return ODR_INVALID_VALUE; } - } else if (stream->subIndex == 3) { /* SRVT */ + } else if (stream->subIndex == 3U) { /* SRVT */ uint8_t value = CO_getUint8(buf); - if (value == 0) { + if (value == 0U) { return ODR_INVALID_VALUE; } - } else if (stream->subIndex == 4) { /* Transmission_type */ + } else if (stream->subIndex == 4U) { /* Transmission_type */ uint8_t value = CO_getUint8(buf); - if (value != 254) { + if (value != 254U) { return ODR_INVALID_VALUE; } } else if ((stream->subIndex == 5U) || (stream->subIndex == 6U)) { /* COB_ID */ @@ -233,12 +233,12 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t uint16_t defaultCOB_ID = SRDO->defaultCOB_ID + index; /* check value range, the spec does not specify if COB-ID flags are allowed */ - if ((value < 0x101) || (value > 0x180U) || ((value & 1) == index)) { + if ((value < 0x101U) || (value > 0x180U) || ((value & 1U) == index)) { return ODR_INVALID_VALUE; /* Invalid value for parameter (download only). */ } /* if default COB-ID is being written, write defaultCOB_ID without nodeId */ - if ((SRDO->nodeId <= 64U) && (value == (defaultCOB_ID + ((uint32_t)SRDO->nodeId * 2)))) { + if ((SRDO->nodeId <= 64U) && (value == (defaultCOB_ID + ((uint32_t)SRDO->nodeId * 2U)))) { value = defaultCOB_ID; (void)CO_setUint32(bufCopy, value); } @@ -275,7 +275,7 @@ OD_write_SRDO_mappingParam(OD_stream_t* stream, const void* buf, OD_size_t count } /* SRDO must be disabled */ - if (SRDO->informationDirection != 0) { + if (SRDO->informationDirection != 0U) { return ODR_UNSUPP_ACCESS; /* Unsupported access to an object. */ } @@ -283,7 +283,7 @@ OD_write_SRDO_mappingParam(OD_stream_t* stream, const void* buf, OD_size_t count if (stream->subIndex == 0U) { uint8_t value = CO_getUint8(buf); /* only odd numbers are allowed */ - if ((value > CO_SRDO_MAX_MAPPED_ENTRIES) || (value & 1)) { + if ((value > CO_SRDO_MAX_MAPPED_ENTRIES) || ((value & 1U) != 0U)) { return ODR_MAP_LEN; /* Number and length of object to be mapped exceeds SRDO length. */ } SRDO->mappedObjectsCount = value; @@ -378,7 +378,7 @@ CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationV /* Configure SRDOGuard->OD_IO_configurationValid variable. * It will be used for writing 0 to OD variable 13FE,00 */ odRet = OD_getSub(OD_13FE_configurationValid, 0, &SRDOGuard->OD_IO_configurationValid, false); - if ((odRet != ODR_OK) || (SRDOGuard->OD_IO_configurationValid.stream.dataLength != 1)) { + if ((odRet != ODR_OK) || (SRDOGuard->OD_IO_configurationValid.stream.dataLength != 1U)) { if (errInfo != NULL) { *errInfo = (((uint32_t)OD_getIndex(OD_13FE_configurationValid)) << 8) | 1U; } @@ -432,7 +432,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* clear object and configure some object variables */ - if (err == 0) { + if (err == 0U) { (void)memset(SRDO, 0, sizeof(CO_SRDO_t)); SRDO->SRDOGuard = SRDOGuard; @@ -456,89 +456,89 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* Get variables from object Dictionary and verify it's structure. */ - if (err == 0) { + if (err == 0U) { if (OD_get_u8(OD_130x_SRDOCommPar, 0, &cp_highestSubindexSupported, true) != ODR_OK) { - err = ERR_INFO(0x1301 + SRDO_Index, 0, 1); + err = ERR_INFO(0x1301U + SRDO_Index, 0, 1); } else if (OD_get_u8(OD_130x_SRDOCommPar, 1, &informationDirection, true) != ODR_OK) { - err = ERR_INFO(0x1301 + SRDO_Index, 1, 1); + err = ERR_INFO(0x1301U + SRDO_Index, 1, 1); } else if (OD_get_u16(OD_130x_SRDOCommPar, 2, &safetyCycleTime, true) != ODR_OK) { - err = ERR_INFO(0x1301 + SRDO_Index, 2, 1); + err = ERR_INFO(0x1301U + SRDO_Index, 2, 1); } else if (OD_get_u8(OD_130x_SRDOCommPar, 3, &safetyRelatedValidationTime, true) != ODR_OK) { - err = ERR_INFO(0x1301 + SRDO_Index, 3, 1); + err = ERR_INFO(0x1301U + SRDO_Index, 3, 1); } else if (OD_get_u8(OD_130x_SRDOCommPar, 4, &transmissionType, true) != ODR_OK) { - err = ERR_INFO(0x1301 + SRDO_Index, 4, 1); + err = ERR_INFO(0x1301U + SRDO_Index, 4, 1); } else if (OD_get_u32(OD_130x_SRDOCommPar, 5, &COB_ID1_normal, true) != ODR_OK) { - err = ERR_INFO(0x1301 + SRDO_Index, 5, 1); + err = ERR_INFO(0x1301U + SRDO_Index, 5, 1); } else if (OD_get_u32(OD_130x_SRDOCommPar, 6, &COB_ID2_inverted, true) != ODR_OK) { - err = ERR_INFO(0x1301 + SRDO_Index, 6, 1); + err = ERR_INFO(0x1301U + SRDO_Index, 6, 1); } else if (OD_get_u8(OD_13FE_configurationValid, 0, &configurationValid, true) != ODR_OK) { - err = ERR_INFO(0x13FE, 0, 1); + err = ERR_INFO(0x13FEU, 0, 1); } - else if (OD_get_u16(OD_13FF_safetyConfigurationSignature, SRDO_Index + 1, &crcSignatureFromOD, true) != ODR_OK) { - err = ERR_INFO(0x13FF, SRDO_Index + 1, 1); + else if (OD_get_u16(OD_13FF_safetyConfigurationSignature, SRDO_Index + 1U, &crcSignatureFromOD, true) != ODR_OK) { + err = ERR_INFO(0x13FFU, SRDO_Index + 1U, 1); } else if (OD_get_u8(OD_138x_SRDOMapPar, 0, &mappedObjectsCount, true) != ODR_OK) { - err = ERR_INFO(0x1381 + SRDO_Index, 0, 1); + err = ERR_INFO(0x1381U + SRDO_Index, 0, 1); } else { for (uint8_t i = 0; i < mappedObjectsCount; i++) { - if (OD_get_u32(OD_138x_SRDOMapPar, i+1, &mapping[i], true) != ODR_OK) { - err = ERR_INFO(0x1381 + SRDO_Index, i+1, 1); + if (OD_get_u32(OD_138x_SRDOMapPar, i+1U, &mapping[i], true) != ODR_OK) { + err = ERR_INFO(0x1381U + SRDO_Index, i+1U, 1); break; } } } /* if OD contains default COB_IDs, add node-id */ - if ((COB_ID1_normal == defaultCOB_ID) && (COB_ID2_inverted == (defaultCOB_ID + 1)) && (nodeId <= 64U)) { - uint32_t add = (uint32_t)SRDO->nodeId * 2; + if ((COB_ID1_normal == defaultCOB_ID) && (COB_ID2_inverted == (defaultCOB_ID + 1U)) && (nodeId <= 64U)) { + uint32_t add = (uint32_t)SRDO->nodeId * 2U; COB_ID1_normal += add; COB_ID2_inverted += add; } /* If this fails, something is wrong with the Object Dictionary. Device have to be reprogrammed. */ - if (err != 0) { + if (err != 0U) { ret = CO_ERROR_OD_PARAMETERS; } } /* If configurationValid is set and SRDO is valid, continue with further configuration */ - if ((err == 0) && (configurationValid == CO_SRDO_VALID_MAGIC) && (informationDirection != CO_SRDO_INVALID)) { + if ((err == 0U) && (configurationValid == CO_SRDO_VALID_MAGIC) && (informationDirection != CO_SRDO_INVALID)) { configurationInProgress = true; } /* Verify parameters from OD */ - if ((err == 0) && configurationInProgress) { - if (cp_highestSubindexSupported != 6) { - err = ERR_INFO(0x1301 + SRDO_Index, 0, 2); + if ((err == 0U) && configurationInProgress) { + if (cp_highestSubindexSupported != 6U) { + err = ERR_INFO(0x1301U + SRDO_Index, 0, 2); } - else if (informationDirection > 3) { - err = ERR_INFO(0x1301 + SRDO_Index, 1, 2); + else if (informationDirection > 3U) { + err = ERR_INFO(0x1301U + SRDO_Index, 1, 2); } - else if (safetyCycleTime < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000) + 1)) { - err = ERR_INFO(0x1301 + SRDO_Index, 2, 2); + else if (safetyCycleTime < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000U) + 1U)) { + err = ERR_INFO(0x1301U + SRDO_Index, 2, 2); } - else if (safetyRelatedValidationTime < 1) { - err = ERR_INFO(0x1301 + SRDO_Index, 3, 2); + else if (safetyRelatedValidationTime < 1U) { + err = ERR_INFO(0x1301U + SRDO_Index, 3, 2); } - else if (transmissionType != 254) { - err = ERR_INFO(0x1301 + SRDO_Index, 4, 2); + else if (transmissionType != 254U) { + err = ERR_INFO(0x1301U + SRDO_Index, 4, 2); } - else if ((COB_ID1_normal < 0x101) || ((COB_ID1_normal & 1) == 0)) { - err = ERR_INFO(0x1301 + SRDO_Index, 5, 2); + else if ((COB_ID1_normal < 0x101U) || ((COB_ID1_normal & 1U) == 0U)) { + err = ERR_INFO(0x1301U + SRDO_Index, 5, 2); } - else if (((COB_ID1_normal + 1) != COB_ID2_inverted) || (COB_ID2_inverted > 0x180)) { - err = ERR_INFO(0x1301 + SRDO_Index, 6, 2); + else if (((COB_ID1_normal + 1U) != COB_ID2_inverted) || (COB_ID2_inverted > 0x180U)) { + err = ERR_INFO(0x1301U + SRDO_Index, 6, 2); } - else if ((mappedObjectsCount > CO_SRDO_MAX_MAPPED_ENTRIES) || ((mappedObjectsCount & 1) != 0)) { - err = ERR_INFO(0x1381 + SRDO_Index, 0, 2); + else if ((mappedObjectsCount > CO_SRDO_MAX_MAPPED_ENTRIES) || ((mappedObjectsCount & 1U) != 0U)) { + err = ERR_INFO(0x1381U + SRDO_Index, 0, 2); } else { /* MISRA C 2004 14.10 */ @@ -546,7 +546,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* Verify CRC */ - if ((err == 0) && configurationInProgress) { + if ((err == 0U) && configurationInProgress) { uint16_t crcResult = 0x0000; uint16_t tmp_u16; uint32_t tmp_u32; @@ -568,16 +568,16 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } if (crcResult != crcSignatureFromOD) { - err = ERR_INFO(0x13FF, SRDO_Index + 1, 3); + err = ERR_INFO(0x13FFU, SRDO_Index + 1U, 3); } } /* Configure mappings */ - if ((err == 0) && configurationInProgress) { + if ((err == 0U) && configurationInProgress) { size_t srdoDataLength[2] = {0, 0}; for (uint8_t i = 0; i < mappedObjectsCount; i++) { - uint8_t plain_inverted = i % 2; + uint8_t plain_inverted = i % 2U; uint32_t map = mapping[i]; uint16_t index = (uint16_t) (map >> 16); uint8_t subIndex = (uint8_t) (map >> 8); @@ -587,10 +587,10 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* total SRDO length can not be more than CO_SRDO_MAX_SIZE bytes */ if (mappedLength > CO_SRDO_MAX_SIZE) { - err = ERR_INFO(0x1381 + SRDO_Index, i + 1, 4); + err = ERR_INFO(0x1381U + SRDO_Index, i + 1U, 4); } /* is there a reference to the dummy entry */ - else if ((index < 0x20) && (subIndex == 0)) { + else if ((index < 0x20U) && (subIndex == 0U)) { OD_stream_t *stream = &OD_IO->stream; (void)memset(stream, 0, sizeof(OD_stream_t)); stream->dataLength = stream->dataOffset = mappedLength; @@ -603,16 +603,16 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ OD_entry_t *entry = OD_find(OD, index); ODR_t odRet = OD_getSub(entry, subIndex, &OD_IOcopy, false); if (odRet != ODR_OK) { - err = ERR_INFO(0x1381 + SRDO_Index, i + 1, 5); + err = ERR_INFO(0x1381U + SRDO_Index, i + 1U, 5); } else { /* verify access attributes, byte alignment and length */ OD_attr_t testAttribute = (informationDirection == CO_SRDO_RX) ? ODA_RSRDO : ODA_TSRDO; - if (((OD_IOcopy.stream.attribute & testAttribute) == 0) - || ((mappedLengthBits & 0x07) != 0) + if (((OD_IOcopy.stream.attribute & testAttribute) == 0U) + || ((mappedLengthBits & 0x07U) != 0U) || (OD_IOcopy.stream.dataLength < mappedLength) ) { - err = ERR_INFO(0x1381 + SRDO_Index, i + 1, 6); + err = ERR_INFO(0x1381U + SRDO_Index, i + 1U, 6); } /* Copy values and store mappedLength temporary. */ @@ -621,17 +621,17 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ srdoDataLength[plain_inverted] += mappedLength; } } - if (err != 0) { + if (err != 0U) { break; } } /* for (uint8_t i = 0; i < mappedObjectsCount; i++) */ - if (err == 0) { + if (err == 0U) { if (srdoDataLength[0] != srdoDataLength[1]) { - err = ERR_INFO(0x1381 + SRDO_Index, 0, 7); + err = ERR_INFO(0x1381U + SRDO_Index, 0, 7); } - else if ((srdoDataLength[0] == 0) || (srdoDataLength[0] > CO_SRDO_MAX_SIZE)) { - err = ERR_INFO(0x1381 + SRDO_Index, 0, 8); + else if ((srdoDataLength[0] == 0U) || (srdoDataLength[0] > CO_SRDO_MAX_SIZE)) { + err = ERR_INFO(0x1381U + SRDO_Index, 0, 8); } else { SRDO->dataLength = srdoDataLength[0]; @@ -641,7 +641,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* Configure CAN tx buffers */ - if ((err == 0) && configurationInProgress && (informationDirection == CO_SRDO_TX)) { + if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_TX)) { SRDO->CANtxBuff[0] = CO_CANtxBufferInit(CANdevTxNormal, /* CAN device */ CANdevTxIdxNormal, /* index of specific buffer inside CAN module */ @@ -651,7 +651,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ 0); /* synchronous message flag bit */ if (SRDO->CANtxBuff[0] == NULL) { - err = ERR_INFO(0x1301 + SRDO_Index, 5, 10); + err = ERR_INFO(0x1301U + SRDO_Index, 5, 10); } SRDO->CANtxBuff[1] = CO_CANtxBufferInit(CANdevTxInverted, /* CAN device */ @@ -662,12 +662,12 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ 0); /* synchronous message flag bit */ if (SRDO->CANtxBuff[1] == NULL) { - err = ERR_INFO(0x1301 + SRDO_Index, 6, 10); + err = ERR_INFO(0x1301U + SRDO_Index, 6, 10); } } /* Configure CAN rx buffers */ - if ((err == 0) && configurationInProgress && (informationDirection == CO_SRDO_RX)) { + if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_RX)) { CO_ReturnError_t ret; ret = CO_CANrxBufferInit(CANdevRxNormal, /* CAN device */ @@ -679,7 +679,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ CO_SRDO_receive_normal); /* this function will process received message */ if (ret != CO_ERROR_NO) { - err = ERR_INFO(0x1301 + SRDO_Index, 5, 11); + err = ERR_INFO(0x1301U + SRDO_Index, 5, 11); } ret = CO_CANrxBufferInit(CANdevRxInverted, /* CAN device */ @@ -691,12 +691,12 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ CO_SRDO_receive_inverted); /* this function will process received message */ if (ret != CO_ERROR_NO) { - err = ERR_INFO(0x1301 + SRDO_Index, 6, 11); + err = ERR_INFO(0x1301U + SRDO_Index, 6, 11); } } /* Configure remaining variables */ - if (err == 0) { + if (err == 0U) { SRDO->informationDirection = informationDirection; SRDO->cycleTime_us = (uint32_t)safetyCycleTime * 1000U; SRDO->validationTime_us = (uint32_t)safetyRelatedValidationTime * 1000U; @@ -765,7 +765,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* copy mapped data from Object Dictionary into CAN buffers */ for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) { - uint8_t plain_inverted = i % 2; + uint8_t plain_inverted = i % 2U; OD_IO_t *OD_IO = &SRDO->OD_IO[i]; OD_stream_t *stream = &OD_IO->stream; @@ -898,7 +898,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext if (data_ok) { size_t verifyLength[2] = { 0, 0 }; for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) { - uint8_t plain_inverted = i % 2; + uint8_t plain_inverted = i % 2U; OD_IO_t *OD_IO = &SRDO->OD_IO[i]; OD_stream_t *stream = &OD_IO->stream; diff --git a/305/CO_LSS.h b/305/CO_LSS.h index d8e9051b..8212c067 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -183,16 +183,16 @@ typedef enum { * Definition of table_index for /CiA301/ bit timing table */ typedef enum { - CO_LSS_BIT_TIMING_1000 = 0, /**< 1000kbit/s */ - CO_LSS_BIT_TIMING_800 = 1, /**< 800kbit/s */ - CO_LSS_BIT_TIMING_500 = 2, /**< 500kbit/s */ - CO_LSS_BIT_TIMING_250 = 3, /**< 250kbit/s */ - CO_LSS_BIT_TIMING_125 = 4, /**< 125kbit/s */ - /* reserved = 5 */ - CO_LSS_BIT_TIMING_50 = 6, /**< 50kbit/s */ - CO_LSS_BIT_TIMING_20 = 7, /**< 20kbit/s */ - CO_LSS_BIT_TIMING_10 = 8, /**< 10kbit/s */ - CO_LSS_BIT_TIMING_AUTO = 9, /**< Automatic bit rate detection */ + CO_LSS_BIT_TIMING_1000 = 0U, /**< 1000kbit/s */ + CO_LSS_BIT_TIMING_800 = 1U, /**< 800kbit/s */ + CO_LSS_BIT_TIMING_500 = 2U, /**< 500kbit/s */ + CO_LSS_BIT_TIMING_250 = 3U, /**< 250kbit/s */ + CO_LSS_BIT_TIMING_125 = 4U, /**< 125kbit/s */ + /* reserved = 5U */ + CO_LSS_BIT_TIMING_50 = 6U, /**< 50kbit/s */ + CO_LSS_BIT_TIMING_20 = 7U, /**< 20kbit/s */ + CO_LSS_BIT_TIMING_10 = 8U, /**< 10kbit/s */ + CO_LSS_BIT_TIMING_AUTO = 9U, /**< Automatic bit rate detection */ } CO_LSS_bitTimingTable_t; /** @@ -220,7 +220,7 @@ static const uint16_t CO_LSS_bitTimingTableLookup[] = { /** * Macro to check if node id is valid */ -#define CO_LSS_NODE_ID_VALID(nid) (((nid >= 1) && (nid <= 0x7F)) || (nid == CO_LSS_NODE_ID_ASSIGNMENT)) +#define CO_LSS_NODE_ID_VALID(nid) (((nid >= 1U) && (nid <= 0x7FU)) || (nid == CO_LSS_NODE_ID_ASSIGNMENT)) /** * Macro to check if two LSS addresses are equal diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 605592e3..8bd86d9e 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -153,7 +153,7 @@ static void CO_LSSslave_receive(void *object, void *msg) ack = true; LSSslave->fastscanPos = lssNext; - if ((bitCheck == 0) && (lssNext < lssSub)) { + if ((bitCheck == 0U) && (lssNext < lssSub)) { /* complete match, enter configuration state */ LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; } @@ -375,7 +375,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { errorCode = CO_LSS_CFG_BIT_TIMING_OK; errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OK; - if ((tableSelector == 0) && CO_LSS_BIT_TIMING_VALID(tableIndex)) { + if ((tableSelector == 0U) && CO_LSS_BIT_TIMING_VALID(tableIndex)) { uint16_t bit = CO_LSS_bitTimingTableLookup[tableIndex]; bool_t bit_rate_supported = LSSslave->pFunctLSScheckBitRate( LSSslave->functLSScheckBitRateObject, bit); diff --git a/CANopen.c b/CANopen.c index 97d1c152..0396043b 100644 --- a/CANopen.c +++ b/CANopen.c @@ -766,7 +766,7 @@ void CO_delete(CO_t *co) { #endif static CO_EM_t COO_EM; #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) - static CO_EM_fifo_t COO_EM_FIFO[CO_GET_CNT(ARR_1003) + 1]; + static CO_EM_fifo_t COO_EM_FIFO[CO_GET_CNT(ARR_1003) + 1U]; #endif static CO_SDOserver_t COO_SDOserver[OD_CNT_SDO_SRV]; #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE @@ -895,7 +895,7 @@ bool_t CO_isLSSslaveEnabled(CO_t *co) { (void) co; /* may be unused */ bool_t en = false; #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - if (CO_GET_CNT(LSS_SLV) == 1) { en = true; } + if (CO_GET_CNT(LSS_SLV) == 1U) { en = true; } #endif return en; } @@ -931,7 +931,7 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, { CO_ReturnError_t err; - if (co == NULL || CO_GET_CNT(LSS_SLV) != 1) { + if ((co == NULL) || (CO_GET_CNT(LSS_SLV) != 1U)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -969,15 +969,15 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, (void)SDOclientTimeoutTime_ms; (void)SDOclientBlockTransfer; CO_ReturnError_t err; - if (co == NULL - || (CO_GET_CNT(NMT) == 0 && NMT == NULL) - || (CO_GET_CNT(EM) == 0 && em == NULL) + if ((co == NULL) + || ((CO_GET_CNT(NMT) == 0U) && (NMT == NULL)) + || ((CO_GET_CNT(EM) == 0U) && (em == NULL)) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } /* alternatives */ - if (CO_GET_CNT(NMT) == 0) { + if (CO_GET_CNT(NMT) == 0U) { co->NMT = NMT; } if (em == NULL) { @@ -987,18 +987,18 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, /* Verify CANopen Node-ID */ co->nodeIdUnconfigured = false; #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - if (CO_GET_CNT(LSS_SLV) == 1 && nodeId == CO_LSS_NODE_ID_ASSIGNMENT) { + if ((CO_GET_CNT(LSS_SLV) == 1U) && (nodeId == CO_LSS_NODE_ID_ASSIGNMENT)) { co->nodeIdUnconfigured = true; } else #endif - if (nodeId < 1 || nodeId > 127) { + if ((nodeId < 1U) || (nodeId > 127U)) { return CO_ERROR_ILLEGAL_ARGUMENT; } else { /* MISRA C 2004 14.10 */ } #if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE - if (CO_GET_CNT(LEDS) == 1) { + if (CO_GET_CNT(LEDS) == 1U) { err = CO_LEDs_init(co->LEDs); if (err) { return err; } } @@ -1010,13 +1010,13 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } /* Emergency */ - if (CO_GET_CNT(EM) == 1) { + if (CO_GET_CNT(EM) == 1U) { err = CO_EM_init(co->em, co->CANmodule, OD_GET(H1001, OD_H1001_ERR_REG), #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) co->em_fifo, - (CO_GET_CNT(ARR_1003) + 1), + (CO_GET_CNT(ARR_1003) + 1U), #endif #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER OD_GET(H1014, OD_H1014_COBID_EMERGENCY), @@ -1041,7 +1041,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } /* NMT_Heartbeat */ - if (CO_GET_CNT(NMT) == 1) { + if (CO_GET_CNT(NMT) == 1U) { err = CO_NMT_init(co->NMT, OD_GET(H1017, OD_H1017_PRODUCER_HB_TIME), em, @@ -1064,7 +1064,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE - if (CO_GET_CNT(HB_CONS) == 1) { + if (CO_GET_CNT(HB_CONS) == 1U) { err = CO_HBconsumer_init(co->HBcons, em, co->HBconsMonitoredNodes, @@ -1101,7 +1101,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif /* SDOserver */ - if (CO_GET_CNT(SDO_SRV) > 0) { + if (CO_GET_CNT(SDO_SRV) > 0U) { OD_entry_t *SDOsrvPar = OD_GET(H1200, OD_H1200_SDO_SERVER_1_PARAM); for (int16_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { err = CO_SDOserver_init(&co->SDOserver[i], @@ -1137,7 +1137,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE - if (CO_GET_CNT(TIME) == 1) { + if (CO_GET_CNT(TIME) == 1U) { err = CO_TIME_init(co->TIME, OD_GET(H1012, OD_H1012_COBID_TIME), co->CANmodule, @@ -1152,7 +1152,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE - if (CO_GET_CNT(SYNC) == 1) { + if (CO_GET_CNT(SYNC) == 1U) { err = CO_SYNC_init(co->SYNC, em, OD_GET(H1005, OD_H1005_COBID_SYNC), @@ -1244,13 +1244,13 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, if (co == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } - if (nodeId < 1 || nodeId > 127 || co->nodeIdUnconfigured) { + if ((nodeId < 1U) || (nodeId > 127U) || co->nodeIdUnconfigured) { return (co->nodeIdUnconfigured) ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; } #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE - if (CO_GET_CNT(RPDO) > 0) { + if (CO_GET_CNT(RPDO) > 0U) { OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { @@ -1284,7 +1284,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, #endif #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE - if (CO_GET_CNT(TPDO) > 0) { + if (CO_GET_CNT(TPDO) > 0U) { OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { @@ -1332,7 +1332,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, if (co == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } - if (nodeId < 1 || nodeId > 127 || co->nodeIdUnconfigured) { + if ((nodeId < 1U) || (nodeId > 127U) || co->nodeIdUnconfigured) { return (co->nodeIdUnconfigured) ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; } @@ -1354,7 +1354,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, #endif #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE - if (CO_GET_CNT(SRDO) > 0) { + if (CO_GET_CNT(SRDO) > 0U) { CO_ReturnError_t err; err = CO_SRDO_init_start(co->SRDOGuard, OD_GET(H13FE, OD_H13FE_SRDO_VALID), @@ -1382,11 +1382,11 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, co->CANmodule, co->CANmodule, CANdevRxIdx, - CANdevRxIdx + 1, + CANdevRxIdx + 1U, co->CANmodule, co->CANmodule, CANdevTxIdx, - CANdevTxIdx + 1, + CANdevTxIdx + 1U, errInfo); if (err) { return err; } } @@ -1415,7 +1415,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, CO_CANmodule_process(co->CANmodule); #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - if (CO_GET_CNT(LSS_SLV) == 1) { + if (CO_GET_CNT(LSS_SLV) == 1U) { if (CO_LSSslave_process(co->LSSslave)) { reset = CO_RESET_COMM; } @@ -1438,7 +1438,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #define CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS 0 #endif - if (CO_GET_CNT(LEDS) == 1) { + if (CO_GET_CNT(LEDS) == 1U) { CO_LEDs_process(co->LEDs, timeDifference_us, unc ? CO_NMT_INITIALIZING : NMTstate, @@ -1449,7 +1449,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, unc ? false : CO_isError(co->em, CO_EM_SYNC_TIME_OUT), unc ? false : (CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) || CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET)), - CO_getErrorRegister(co->em) != 0, + CO_getErrorRegister(co->em) != 0U, CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS, timerNext_us); } @@ -1461,7 +1461,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, } /* Emergency */ - if (CO_GET_CNT(EM) == 1) { + if (CO_GET_CNT(EM) == 1U) { CO_EM_process(co->em, NMTisPreOrOperational, timeDifference_us, @@ -1469,7 +1469,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, } /* NMT_Heartbeat */ - if (CO_GET_CNT(NMT) == 1) { + if (CO_GET_CNT(NMT) == 1U) { reset = CO_NMT_process(co->NMT, &NMTstate, timeDifference_us, @@ -1487,7 +1487,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, } #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE - if (CO_GET_CNT(HB_CONS) == 1) { + if (CO_GET_CNT(HB_CONS) == 1U) { CO_HBconsumer_process(co->HBcons, NMTisPreOrOperational, timeDifference_us, @@ -1498,7 +1498,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE CO_nodeGuardingSlave_process(co->NGslave, NMTstate, - (co->NMT->HBproducerTime_us > 0), + (co->NMT->HBproducerTime_us > 0U), timeDifference_us, timerNext_us); #endif @@ -1509,7 +1509,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #endif #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE - if (CO_GET_CNT(TIME) == 1) { + if (CO_GET_CNT(TIME) == 1U) { CO_TIME_process(co->TIME, NMTisPreOrOperational, timeDifference_us); } #endif @@ -1535,10 +1535,10 @@ bool_t CO_process_SYNC(CO_t *co, { bool_t syncWas = false; - if (!co->nodeIdUnconfigured && CO_GET_CNT(SYNC) == 1) { + if ((!co->nodeIdUnconfigured) && (CO_GET_CNT(SYNC) == 1U)) { CO_NMT_internalState_t NMTstate = CO_NMT_getInternalState(co->NMT); - bool_t NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL - || NMTstate == CO_NMT_OPERATIONAL); + bool_t NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) + || (NMTstate == CO_NMT_OPERATIONAL)); CO_SYNC_status_t sync_process = CO_SYNC_process(co->SYNC, NMTisPreOrOperational, diff --git a/storage/CO_storage.c b/storage/CO_storage.c index a80131b0..0a00dbaf 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -35,7 +35,7 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* verify arguments */ - if ((stream == NULL) || (stream->subIndex == 0) || (buf == NULL) || (count != 4) + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -43,12 +43,12 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, CO_storage_t *storage = stream->object; - if ((stream->subIndex == 0) || (storage->store == NULL) || !storage->enabled) { + if ((stream->subIndex == 0U) || (storage->store == NULL) || !storage->enabled) { return ODR_READONLY; } uint32_t val = CO_getUint32(buf); - if (val != 0x65766173) { + if (val != 0x65766173U) { return ODR_DATA_TRANSF; } @@ -59,9 +59,9 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; - if ((stream->subIndex == 1) || (entry->subIndexOD == stream->subIndex)) { - if (found == 0) found = 1; - if ((entry->attr & CO_storage_cmd) != 0) { + if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { + if (found == 0U) found = 1; + if ((entry->attr & (uint8_t)CO_storage_cmd) != 0U) { ODR_t code = storage->store(entry, storage->CANmodule); if (code != ODR_OK) returnCode = code; found = 2; @@ -69,8 +69,8 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, } } - if (found != 2) - returnCode = (found == 0) ? ODR_SUB_NOT_EXIST : ODR_READONLY; + if (found != 2U) + returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY; if (returnCode == ODR_OK) *countWritten = sizeof(uint32_t); return returnCode; @@ -86,7 +86,7 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { /* verify arguments */ - if ((stream == NULL) || (stream->subIndex == 0) || (buf == NULL) || (count != 4) + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -94,12 +94,12 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, CO_storage_t *storage = stream->object; - if ((stream->subIndex == 0) || (storage->restore == NULL) || !storage->enabled){ + if ((stream->subIndex == 0U) || (storage->restore == NULL) || !storage->enabled){ return ODR_READONLY; } uint32_t val = CO_getUint32(buf); - if (val != 0x64616F6C) { + if (val != 0x64616F6CU) { return ODR_DATA_TRANSF; } @@ -110,9 +110,9 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; - if ((stream->subIndex == 1) || (entry->subIndexOD == stream->subIndex)) { - if (found == 0) found = 1; - if ((entry->attr & CO_storage_restore) != 0) { + if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { + if (found == 0U) found = 1; + if ((entry->attr & (uint8_t)CO_storage_restore) != 0U) { ODR_t code = storage->restore(entry, storage->CANmodule); if (code != ODR_OK) returnCode = code; found = 2; @@ -120,8 +120,8 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, } } - if (found != 2) - returnCode = (found == 0) ? ODR_SUB_NOT_EXIST : ODR_READONLY; + if (found != 2U) + returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY; if (returnCode == ODR_OK) *countWritten = sizeof(uint32_t); return returnCode; diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 6eacb0b2..9315a7cb 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -117,7 +117,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, bool_t eepromOvf = false; /* verify arguments */ - if ((storage == NULL) || (entries == NULL) || (entriesCount == 0) + if ((storage == NULL) || (entries == NULL) || (entriesCount == 0U) || (storageInitError == NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -159,10 +159,10 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, *storageInitError = 0; for (uint8_t i = 0; i < entriesCount; i++) { CO_storage_entry_t *entry = &entries[i]; - bool_t isAuto = (entry->attr & CO_storage_auto) != 0; + bool_t isAuto = (entry->attr & (uint8_t)CO_storage_auto) != 0U; /* verify arguments */ - if ((entry->addr == NULL) || (entry->len == 0) || (entry->subIndexOD < 2)) { + if ((entry->addr == NULL) || (entry->len == 0U) || (entry->subIndexOD < 2U)) { *storageInitError = i; return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -211,7 +211,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, /* additional info in case of error */ if (dataCorrupt) { uint32_t errorBit = entry->subIndexOD; - if (errorBit > 31) errorBit = 31; + if (errorBit > 31U) errorBit = 31; *storageInitError |= ((uint32_t) 1) << errorBit; ret = CO_ERROR_DATA_CORRUPT; } @@ -233,7 +233,7 @@ void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; - if ((entry->attr & CO_storage_auto) == 0) + if ((entry->attr & (uint8_t)CO_storage_auto) == 0U) continue; if (saveAll) { From 0142f418576c24d0006bc8bdcc9e59c2c25b6623 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 10 Jun 2024 17:59:05 +0200 Subject: [PATCH 266/520] static analysis: an enum value is not an appropriate left operand [MISRA 2012 Rule 10.1, required] --- 301/CO_Emergency.c | 50 +++++++++--------- 301/CO_HBconsumer.c | 10 ++-- 301/CO_NMT_Heartbeat.c | 12 ++--- 301/CO_Node_Guarding.c | 8 +-- 301/CO_ODinterface.c | 6 +-- 301/CO_ODinterface.h | 2 +- 301/CO_PDO.c | 56 ++++++++++----------- 301/CO_SDOserver.c | 10 ++-- 301/CO_SYNC.c | 4 +- 301/CO_fifo.c | 4 +- 303/CO_LEDs.c | 54 ++++++++++---------- 304/CO_SRDO.c | 4 +- 305/CO_LSSslave.c | 8 +-- CANopen.c | 112 ++++++++++++++++++++--------------------- 14 files changed, 170 insertions(+), 170 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 1ad363d7..a09aa2d0 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -137,8 +137,8 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; - COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + em->nodeId; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0U : 0x80000000U; + COB_IDEmergency32 |= (uint32_t)CO_CAN_ID_EMERGENCY + em->nodeId; (void)CO_setUint32(buf, COB_IDEmergency32); *countRead = sizeof(uint32_t); @@ -441,7 +441,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, * to add nodeId of this node to the stored value. */ if (producerCanId == CO_CAN_ID_EMERGENCY) producerCanId += nodeId; #else - uint16_t producerCanId = CO_CAN_ID_EMERGENCY + nodeId; + uint32_t producerCanId = (uint32_t)CO_CAN_ID_EMERGENCY + nodeId; em->producerEnabled = (COB_IDEmergency32 & 0x80000000U) == 0U; em->OD_1014_extension.object = em; @@ -564,33 +564,33 @@ void CO_EM_process(CO_EM_t *em, uint16_t CANerrStChanged = CANerrSt ^ em->CANerrorStatusOld; em->CANerrorStatusOld = CANerrSt; - if (CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) { + if (CANerrStChanged & ((uint16_t)CO_CAN_ERRTX_WARNING | (uint16_t)CO_CAN_ERRRX_WARNING)) { CO_error(em, - (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0, + (CANerrSt & ((uint16_t)CO_CAN_ERRTX_WARNING | (uint16_t)CO_CAN_ERRRX_WARNING)) != 0U, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, 0); } - if (CANerrStChanged & CO_CAN_ERRTX_PASSIVE) { - CO_error(em, (CANerrSt & CO_CAN_ERRTX_PASSIVE) != 0, + if (CANerrStChanged & (uint16_t)CO_CAN_ERRTX_PASSIVE) { + CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRTX_PASSIVE) != 0U, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); } - if (CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) { - CO_error(em, (CANerrSt & CO_CAN_ERRTX_BUS_OFF) != 0, + if (CANerrStChanged & (uint16_t)CO_CAN_ERRTX_BUS_OFF) { + CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRTX_BUS_OFF) != 0U, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, 0); } - if (CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) { - CO_error(em, (CANerrSt & CO_CAN_ERRTX_OVERFLOW) != 0, + if (CANerrStChanged & (uint16_t)CO_CAN_ERRTX_OVERFLOW) { + CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRTX_OVERFLOW) != 0U, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } - if (CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) { - CO_error(em, (CANerrSt & CO_CAN_ERRTX_PDO_LATE) != 0, + if (CANerrStChanged & (uint16_t)CO_CAN_ERRTX_PDO_LATE) { + CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRTX_PDO_LATE) != 0U, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, 0); } - if (CANerrStChanged & CO_CAN_ERRRX_PASSIVE) { - CO_error(em, (CANerrSt & CO_CAN_ERRRX_PASSIVE) != 0, + if (CANerrStChanged & (uint16_t)CO_CAN_ERRRX_PASSIVE) { + CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRRX_PASSIVE) != 0U, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); } - if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) { - CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0, + if (CANerrStChanged & (uint16_t)CO_CAN_ERRRX_OVERFLOW) { + CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRRX_OVERFLOW) != 0U, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } } @@ -598,33 +598,33 @@ void CO_EM_process(CO_EM_t *em, /* calculate Error register */ uint8_t errorRegister = 0U; if (CO_CONFIG_ERR_CONDITION_GENERIC) { - errorRegister |= CO_ERR_REG_GENERIC_ERR; + errorRegister |= (uint8_t)CO_ERR_REG_GENERIC_ERR; } #ifdef CO_CONFIG_ERR_CONDITION_CURRENT if (CO_CONFIG_ERR_CONDITION_CURRENT) { - errorRegister |= CO_ERR_REG_CURRENT; + errorRegister |= (uint8_t)CO_ERR_REG_CURRENT; } #endif #ifdef CO_CONFIG_ERR_CONDITION_VOLTAGE if (CO_CONFIG_ERR_CONDITION_VOLTAGE) { - errorRegister |= CO_ERR_REG_VOLTAGE; + errorRegister |= (uint8_t)CO_ERR_REG_VOLTAGE; } #endif #ifdef CO_CONFIG_ERR_CONDITION_TEMPERATURE if (CO_CONFIG_ERR_CONDITION_TEMPERATURE) { - errorRegister |= CO_ERR_REG_TEMPERATURE; + errorRegister |= (uint8_t)CO_ERR_REG_TEMPERATURE; } #endif if (CO_CONFIG_ERR_CONDITION_COMMUNICATION) { - errorRegister |= CO_ERR_REG_COMMUNICATION; + errorRegister |= (uint8_t)CO_ERR_REG_COMMUNICATION; } #ifdef CO_CONFIG_ERR_CONDITION_DEV_PROFILE if (CO_CONFIG_ERR_CONDITION_DEV_PROFILE) { - errorRegister |= CO_ERR_REG_DEV_PROFILE; + errorRegister |= (uint8_t)CO_ERR_REG_DEV_PROFILE; } #endif if (CO_CONFIG_ERR_CONDITION_MANUFACTURER) { - errorRegister |= CO_ERR_REG_MANUFACTURER; + errorRegister |= (uint8_t)CO_ERR_REG_MANUFACTURER; } *em->errorRegister = errorRegister; @@ -681,7 +681,7 @@ void CO_EM_process(CO_EM_t *em, } else if ((em->fifoOverflow == 2U) && (em->fifoPpPtr == em->fifoWrPtr)) { em->fifoOverflow = 0; - CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); + CO_errorReset(em, (uint8_t)CO_EM_EMERGENCY_BUFFER_FULL, 0); } else { /* MISRA C 2004 14.10 */ } } @@ -719,7 +719,7 @@ void CO_EM_process(CO_EM_t *em, /******************************************************************************/ -void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, +void CO_error(CO_EM_t *em, bool_t setError, const CO_EM_errorStatusBits_t errorBit, uint16_t errorCode, uint32_t infoCode) { if (em == NULL) { return; } diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 275d6ab8..5bb1dc27 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -214,8 +214,8 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, CO_FLAG_CLEAR(monitoredNode->CANrxNew); /* is channel used */ - COB_ID = monitoredNode->nodeId + CO_CAN_ID_HEARTBEAT; if ((monitoredNode->nodeId != 0U) && (monitoredNode->time_us != 0U)) { + COB_ID = monitoredNode->nodeId + (uint16_t)CO_CAN_ID_HEARTBEAT; monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; } else { @@ -388,7 +388,7 @@ void CO_HBconsumer_process( #endif if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) { CO_errorReport(HBcons->em, - CO_EM_HB_CONSUMER_REMOTE_RESET, + (uint8_t)CO_EM_HB_CONSUMER_REMOTE_RESET, CO_EMC_HEARTBEAT, i); } monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; @@ -425,7 +425,7 @@ void CO_HBconsumer_process( monitoredNode->functSignalObjectTimeout); } #endif - CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, + CO_errorReport(HBcons->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, i); monitoredNode->NMTstate = CO_NMT_UNKNOWN; monitoredNode->HBstate = CO_HBconsumer_TIMEOUT; @@ -492,8 +492,8 @@ void CO_HBconsumer_process( /* Clear emergencies when all monitored nodes becomes active. * We only have one emergency index for all monitored nodes! */ if (!HBcons->allMonitoredActive && allMonitoredActiveCurrent) { - CO_errorReset(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, 0); - CO_errorReset(HBcons->em, CO_EM_HB_CONSUMER_REMOTE_RESET, 0); + CO_errorReset(HBcons->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, 0); + CO_errorReset(HBcons->em, (uint8_t)CO_EM_HB_CONSUMER_REMOTE_RESET, 0); } HBcons->allMonitoredActive = allMonitoredActiveCurrent; diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 8424af5f..e8e01073 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -243,7 +243,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, if (NMTstateCpy == CO_NMT_INITIALIZING) { /* NMT slave self starting */ - NMTstateCpy = ((NMT->NMTcontrol & CO_NMT_STARTUP_TO_OPERATIONAL) != 0) + NMTstateCpy = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_STARTUP_TO_OPERATIONAL) != 0U) ? CO_NMT_OPERATIONAL : CO_NMT_PRE_OPERATIONAL; } else { @@ -282,18 +282,18 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, } /* verify NMT transitions based on error register */ - bool_t busOff_HB = ((NMT->NMTcontrol & CO_NMT_ERR_ON_BUSOFF_HB) != 0) + bool_t busOff_HB = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_ON_BUSOFF_HB) != 0U) && (CO_isError(NMT->em, CO_EM_CAN_TX_BUS_OFF) || CO_isError(NMT->em, CO_EM_HEARTBEAT_CONSUMER) || CO_isError(NMT->em, CO_EM_HB_CONSUMER_REMOTE_RESET)); - bool_t errRegMasked = ((NMT->NMTcontrol & CO_NMT_ERR_ON_ERR_REG) != 0) - && ((CO_getErrorRegister(NMT->em) & NMT->NMTcontrol) != 0); + bool_t errRegMasked = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_ON_ERR_REG) != 0U) + && ((CO_getErrorRegister(NMT->em) & (uint8_t)NMT->NMTcontrol) != 0U); if ((NMTstateCpy == CO_NMT_OPERATIONAL) && (busOff_HB || errRegMasked)) { - NMTstateCpy = ((NMT->NMTcontrol & CO_NMT_ERR_TO_STOPPED) != 0) + NMTstateCpy = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_TO_STOPPED) != 0U) ? CO_NMT_STOPPED : CO_NMT_PRE_OPERATIONAL; } - else if (((NMT->NMTcontrol & CO_NMT_ERR_FREE_TO_OPERATIONAL) != 0) + else if ((((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_FREE_TO_OPERATIONAL) != 0U) && (NMTstateCpy == CO_NMT_PRE_OPERATIONAL) && (!busOff_HB && !errRegMasked) ) { NMTstateCpy = CO_NMT_OPERATIONAL; diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 784fae21..77867138 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -229,7 +229,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, if (ngs->lifeTimeTimeout) { /* error bit is shared with HB consumer */ - CO_errorReset(ngs->em, CO_EM_HEARTBEAT_CONSUMER, 0); + CO_errorReset(ngs->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, 0); ngs->lifeTimeTimeout = false; } @@ -252,7 +252,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, ngs->lifeTimeTimeout = true; /* error bit is shared with HB consumer */ - CO_errorReport(ngs->em, CO_EM_HEARTBEAT_CONSUMER, + CO_errorReport(ngs->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, 0); } } @@ -415,12 +415,12 @@ void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, if (!node->responseRecived) { node->monitoringActive = false; /* error bit is shared with HB consumer */ - CO_errorReport(ngm->em, CO_EM_HEARTBEAT_CONSUMER, + CO_errorReport(ngm->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, node->ident & 0x7F); } else if (node->NMTstate != CO_NMT_UNKNOWN) { node->monitoringActive = true; - CO_errorReset(ngm->em, CO_EM_HEARTBEAT_CONSUMER, + CO_errorReset(ngm->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, node->ident & 0x7F); } } diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 824d7ad5..7024a8ba 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -188,7 +188,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, OD_stream_t *stream = &io->stream; /* attribute, dataOrig and dataLength, depends on object type */ - switch (entry->odObjectType & ODT_TYPE_MASK) { + switch (entry->odObjectType & (uint8_t)ODT_TYPE_MASK) { case ODT_VAR: { if (subIndex > 0U) { return ODR_SUB_NOT_EXIST; } CO_PROGMEM OD_obj_var_t *odo = entry->odObject; @@ -212,7 +212,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, stream->attribute = odo->attribute; uint8_t *ptr = odo->dataOrig; stream->dataOrig = (ptr == NULL) ? ptr - : (ptr + (odo->dataElementSizeof * (subIndex - 1))); + : (ptr + (odo->dataElementSizeof * (uint8_t)(subIndex - 1U))); stream->dataLength = odo->dataElementLength; } break; @@ -294,7 +294,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { 0x08000024UL /* No data available */ }; - return ((returnCode < 0) || (returnCode >= ODR_COUNT)) ? + return ((returnCode < ODR_OK) || (returnCode >= ODR_COUNT)) ? abortCodes[ODR_DEV_INCOMPAT] : abortCodes[returnCode]; } diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index f9441c93..c50b087b 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -453,7 +453,7 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { */ static inline bool_t OD_mappable(OD_stream_t *stream) { return (stream != NULL) - ? ((stream->attribute & (ODA_TRPDO | ODA_TRSRDO)) != 0) : false; + ? ((stream->attribute & ((OD_attr_t)ODA_TRPDO | (OD_attr_t)ODA_TRSRDO)) != 0U) : false; } diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 249e8a8b..8a3e3b2d 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -474,10 +474,10 @@ static void CO_PDO_receive(void *object, void *msg) { if (DLC >= PDO->dataLength) { /* indicate errors in PDO length */ if (DLC == PDO->dataLength) { - if (err == CO_RPDO_RX_ACK_ERROR) { err = CO_RPDO_RX_OK; } + if (err == (uint8_t)CO_RPDO_RX_ACK_ERROR) { err = CO_RPDO_RX_OK; } } else { - if (err == CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_LONG; } + if (err == (uint8_t)CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_LONG; } } /* Determine, to which of the two rx buffers copy the message. */ @@ -502,7 +502,7 @@ static void CO_PDO_receive(void *object, void *msg) { } #endif } - else if (err == CO_RPDO_RX_ACK_NO_ERROR) { + else if (err == (uint8_t)CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_SHORT; } else { /* MISRA C 2004 14.10 */ } @@ -588,13 +588,13 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if ((transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240) - && (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) + if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) + && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { return ODR_INVALID_VALUE; } - bool_t synchronous = transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240; + bool_t synchronous = transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240; /* Remove old message from the second buffer. */ if (RPDO->synchronous != synchronous) { CO_FLAG_CLEAR(RPDO->CANrxNew[1]); @@ -692,7 +692,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, if (erroneousMap != 0U) { CO_errorReport(PDO->em, - CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, + (uint8_t)CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, (erroneousMap != 1U) ? erroneousMap : COB_ID); } if (!valid) { @@ -731,7 +731,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, } RPDO->SYNC = SYNC; - RPDO->synchronous = transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240; + RPDO->synchronous = transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240; #endif @@ -795,9 +795,9 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, #endif ) { /* Verify errors in length of received RPDO CAN message */ - if (RPDO->receiveError > CO_RPDO_RX_ACK) { - bool_t setError = RPDO->receiveError != CO_RPDO_RX_OK; - uint16_t code = (RPDO->receiveError == CO_RPDO_RX_SHORT) + if (RPDO->receiveError > (uint8_t)CO_RPDO_RX_ACK) { + bool_t setError = RPDO->receiveError != (uint8_t)CO_RPDO_RX_OK; + uint16_t code = (RPDO->receiveError == (uint8_t)CO_RPDO_RX_SHORT) ? CO_EMC_PDO_LENGTH : CO_EMC_PDO_LENGTH_EXC; CO_error(PDO->em, setError, CO_EM_RPDO_WRONG_LENGTH, code, PDO->dataLength); @@ -888,7 +888,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, if (RPDO->timeoutTime_us > 0U) { if (rpdoReceived) { if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { - CO_errorReset(PDO->em, CO_EM_RPDO_TIME_OUT, + CO_errorReset(PDO->em, (uint8_t)CO_EM_RPDO_TIME_OUT, RPDO->timeoutTimer); } /* enable monitoring */ @@ -900,7 +900,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, RPDO->timeoutTimer += timeDifference_us; if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { - CO_errorReport(PDO->em, CO_EM_RPDO_TIME_OUT, + CO_errorReport(PDO->em, (uint8_t)CO_EM_RPDO_TIME_OUT, CO_EMC_RPDO_TIMEOUT, RPDO->timeoutTimer); } } @@ -995,7 +995,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, CAN_ID, /* CAN identifier */ 0, /* rtr */ PDO->dataLength, /* number of data bytes */ - TPDO->transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240); + TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); /* synchronous message flag */ if (CANtxBuff == NULL) { @@ -1012,13 +1012,13 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - if ((transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240) - && (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) + if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) + && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { return ODR_INVALID_VALUE; } TPDO->CANtxBuff->syncFlag = - transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240; + transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240; TPDO->syncCounter = 255; #else if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { @@ -1123,13 +1123,13 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, odRet = OD_get_u8(OD_18xx_TPDOCommPar, 2, &transmissionType, true); if (odRet != ODR_OK) { if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 2; + *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 2U; } return CO_ERROR_OD_PARAMETERS; } - if ((transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) + if ((transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE - && (transmissionType > CO_PDO_TRANSM_TYPE_SYNC_240) + && (transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) #endif ) { transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; @@ -1156,7 +1156,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, if (erroneousMap != 0U) { CO_errorReport(PDO->em, - CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, + (uint8_t)CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, (erroneousMap != 1U) ? erroneousMap : COB_ID); } if (!valid) { @@ -1174,7 +1174,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, CAN_ID, /* CAN identifier */ 0, /* rtr */ PDO->dataLength, /* number of data bytes */ - TPDO->transmissionType <= CO_PDO_TRANSM_TYPE_SYNC_240); + TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); /* synchronous message flag bit */ if (TPDO->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -1239,8 +1239,8 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { uint8_t *dataTPDO = &TPDO->CANtxBuff->data[0]; #if OD_FLAGS_PDO_SIZE > 0 bool_t eventDriven = - ((TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) - || (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)); + ((TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) + || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)); #endif #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS @@ -1344,8 +1344,8 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, /* check for event timer or application event */ #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || (OD_FLAGS_PDO_SIZE > 0) - if ((TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) - || (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) + if ((TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) + || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { /* event timer */ #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE @@ -1382,7 +1382,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, /* Send PDO by application request or by Event timer */ - if (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { + if (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) : 0U; @@ -1411,7 +1411,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE else if ((TPDO->SYNC != NULL) && syncWas) { /* send synchronous acyclic TPDO */ - if (TPDO->transmissionType == CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { + if (TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { if (TPDO->sendRequest) { CO_TPDOsend(TPDO); } } /* send synchronous cyclic TPDO */ diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 9cc53109..6c29b77e 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -365,15 +365,15 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, return CO_ERROR_ILLEGAL_ARGUMENT; } - CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; - CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; + CanId_ClientToServer = (uint16_t)CO_CAN_ID_SDO_CLI + nodeId; + CanId_ServerToClient = (uint16_t)CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); OD_set_u32(OD_1200_SDOsrvPar, 2, CanId_ServerToClient, true); } - else if ((OD_SDOsrvParIdx > OD_H1200_SDO_SERVER_1_PARAM) - && (OD_SDOsrvParIdx <= (OD_H1200_SDO_SERVER_1_PARAM + 0x7F)) + else if ((OD_SDOsrvParIdx > (uint16_t)OD_H1200_SDO_SERVER_1_PARAM) + && (OD_SDOsrvParIdx <= ((uint16_t)OD_H1200_SDO_SERVER_1_PARAM + 0x7FU)) ) { /* configure additional SDO channel and SDO server parameters for it */ uint8_t maxSubIndex; @@ -896,7 +896,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* strings are allowed to be shorter */ else if ((SDO->sizeInd < sizeInOd) - && ((SDO->OD_IO.stream.attribute & ODA_STR) == 0) + && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) == 0U) ) { abortCode = CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index afee945e..56549fbe 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -447,8 +447,8 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } /* verify error from receive function */ - CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, if (SYNC->receiveError != 0U) { + CO_errorReport(SYNC->em, (uint8_t)CO_EM_SYNC_LENGTH, CO_EMC_SYNC_DATA_LENGTH, SYNC->receiveError); SYNC->receiveError = 0; } @@ -461,8 +461,8 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } if (syncStatus == CO_SYNC_RX_TX) { - CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, 0); if (SYNC->timeoutError == 2U) { + CO_errorReset(SYNC->em, (uint8_t)CO_EM_SYNC_TIME_OUT, 0); } SYNC->timeoutError = 1; } diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 1cc2b101..3d1d2335 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -794,7 +794,7 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if ((sRet != strchr(buf, '\0')) || (u32 > UINT8_MAX)) st |= CO_fifo_st_errVal; + if ((sRet != strchr(buf, '\0')) || (u32 > (uint32_t)UINT8_MAX)) st |= CO_fifo_st_errVal; else { uint8_t num = (uint8_t) u32; nWr = CO_fifo_write(dest, &num, sizeof(num), NULL); @@ -816,7 +816,7 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if ((sRet != strchr(buf, '\0')) || (u32 > UINT16_MAX)) st |= CO_fifo_st_errVal; + if ((sRet != strchr(buf, '\0')) || (u32 > (uint32_t)UINT16_MAX)) st |= CO_fifo_st_errVal; else { uint16_t num = CO_SWAP_16((uint16_t) u32); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index d085cdc3..8cd5be06 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -64,8 +64,8 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, bool_t tick = false; LEDs->LEDtmr50ms += timeDifference_us; - bool_t rdFlickerNext = (LEDs->LEDred & CO_LED_flicker) == 0; while (LEDs->LEDtmr50ms >= 50000U) { + bool_t rdFlickerNext = (LEDs->LEDred & (uint8_t)CO_LED_flicker) == 0U; tick = true; LEDs->LEDtmr50ms -= 50000U; @@ -75,43 +75,43 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, LEDs->LEDtmr200ms = 0; rd = gr = 0; - if ((LEDs->LEDred & CO_LED_blink) == 0) { rd |= CO_LED_blink; } - else { gr |= CO_LED_blink; } + if ((LEDs->LEDred & (uint8_t)CO_LED_blink) == 0U) { rd |= (uint8_t)CO_LED_blink; } + else { gr |= (uint8_t)CO_LED_blink; } switch (++LEDs->LEDtmrflash_1) { - case 1: rd |= CO_LED_flash_1; break; - case 2: gr |= CO_LED_flash_1; break; + case 1: rd |= (uint8_t)CO_LED_flash_1; break; + case 2: gr |= (uint8_t)CO_LED_flash_1; break; case 6: LEDs->LEDtmrflash_1 = 0; break; default: break; } switch (++LEDs->LEDtmrflash_2) { - case 1: case 3: rd |= CO_LED_flash_2; break; - case 2: case 4: gr |= CO_LED_flash_2; break; + case 1: case 3: rd |= (uint8_t)CO_LED_flash_2; break; + case 2: case 4: gr |= (uint8_t)CO_LED_flash_2; break; case 8: LEDs->LEDtmrflash_2 = 0; break; default: break; } switch (++LEDs->LEDtmrflash_3) { - case 1: case 3: case 5: rd |= CO_LED_flash_3; break; - case 2: case 4: case 6: gr |= CO_LED_flash_3; break; + case 1: case 3: case 5: rd |= (uint8_t)CO_LED_flash_3; break; + case 2: case 4: case 6: gr |= (uint8_t)CO_LED_flash_3; break; case 10: LEDs->LEDtmrflash_3 = 0; break; default: break; } switch (++LEDs->LEDtmrflash_4) { - case 1: case 3: case 5: case 7: rd |= CO_LED_flash_4; break; - case 2: case 4: case 6: case 8: gr |= CO_LED_flash_4; break; + case 1: case 3: case 5: case 7: rd |= (uint8_t)CO_LED_flash_4; break; + case 2: case 4: case 6: case 8: gr |= (uint8_t)CO_LED_flash_4; break; case 12: LEDs->LEDtmrflash_4 = 0; break; default: break; } } else { /* clear flicker and CANopen bits, keep others */ - rd = LEDs->LEDred & (0xFF ^ (CO_LED_flicker | CO_LED_CANopen)); - gr = LEDs->LEDgreen & (0xFF ^ (CO_LED_flicker | CO_LED_CANopen)); + rd = LEDs->LEDred & (0xFFU ^ ((uint8_t)CO_LED_flicker | (uint8_t)CO_LED_CANopen)); + gr = LEDs->LEDgreen & (0xFFU ^ ((uint8_t)CO_LED_flicker | (uint8_t)CO_LED_CANopen)); } /* calculate 10Hz flickering */ - if (rdFlickerNext) { rd |= CO_LED_flicker; } - else { gr |= CO_LED_flicker; } + if (rdFlickerNext) { rd |= (uint8_t)CO_LED_flicker; } + else { gr |= (uint8_t)CO_LED_flicker; } } /* while (LEDs->LEDtmr50ms >= 50000) */ @@ -120,24 +120,24 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, /* CANopen red ERROR LED */ if (ErrCANbusOff) { rd_co = 1;} - else if (NMTstate == CO_NMT_INITIALIZING){ rd_co = rd & CO_LED_flicker;} - else if (ErrRpdo) { rd_co = rd & CO_LED_flash_4;} - else if (ErrSync) { rd_co = rd & CO_LED_flash_3;} - else if (ErrHbCons) { rd_co = rd & CO_LED_flash_2;} - else if (ErrCANbusWarn) { rd_co = rd & CO_LED_flash_1;} - else if (ErrOther) { rd_co = rd & CO_LED_blink;} + else if (NMTstate == CO_NMT_INITIALIZING){ rd_co = rd & (uint8_t)CO_LED_flicker;} + else if (ErrRpdo) { rd_co = rd & (uint8_t)CO_LED_flash_4;} + else if (ErrSync) { rd_co = rd & (uint8_t)CO_LED_flash_3;} + else if (ErrHbCons) { rd_co = rd & (uint8_t)CO_LED_flash_2;} + else if (ErrCANbusWarn) { rd_co = rd & (uint8_t)CO_LED_flash_1;} + else if (ErrOther) { rd_co = rd & (uint8_t)CO_LED_blink;} else { rd_co = 0;} /* CANopen green RUN LED */ - if (LSSconfig) {gr_co = gr & CO_LED_flicker;} - else if (firmwareDownload) {gr_co = gr & CO_LED_flash_3;} - else if (NMTstate == CO_NMT_STOPPED) {gr_co = gr & CO_LED_flash_1;} - else if (NMTstate == CO_NMT_PRE_OPERATIONAL){gr_co = gr & CO_LED_blink;} + if (LSSconfig) {gr_co = gr & (uint8_t)CO_LED_flicker;} + else if (firmwareDownload) {gr_co = gr & (uint8_t)CO_LED_flash_3;} + else if (NMTstate == CO_NMT_STOPPED) {gr_co = gr & (uint8_t)CO_LED_flash_1;} + else if (NMTstate == CO_NMT_PRE_OPERATIONAL){gr_co = gr & (uint8_t)CO_LED_blink;} else if (NMTstate == CO_NMT_OPERATIONAL) {gr_co = 1;} else {gr_co = 0;} - if (rd_co != 0) { rd |= CO_LED_CANopen; } - if (gr_co != 0) { gr |= CO_LED_CANopen; } + if (rd_co != 0U) { rd |= (uint8_t)CO_LED_CANopen; } + if (gr_co != 0U) { gr |= (uint8_t)CO_LED_CANopen; } LEDs->LEDred = rd; LEDs->LEDgreen = gr; } /* if (tick) */ diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 760296ef..b0b0bb6d 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -703,7 +703,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } else { if (ret == CO_ERROR_NO) { - CO_errorReport(em, CO_EM_SRDO_CONFIGURATION, CO_EMC_DATA_SET, err); + CO_errorReport(em, (uint8_t)CO_EM_SRDO_CONFIGURATION, CO_EMC_DATA_SET, err); configurationValidUnset(SRDO->SRDOGuard); } } @@ -868,7 +868,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext else { /* CO_SRDO_RX */ /* verify error from receive function */ if (SRDO->rxSrdoShort) { - CO_errorReport(SRDO->em, CO_EM_RPDO_WRONG_LENGTH, CO_EMC_PDO_LENGTH, 0); + CO_errorReport(SRDO->em, (uint8_t)CO_EM_RPDO_WRONG_LENGTH, CO_EMC_PDO_LENGTH, 0); SRDO->internalState = CO_SRDO_state_error_rxShort; } else if (CO_FLAG_READ(SRDO->CANrxNew[SRDO->nextIsNormal ? 0 : 1])) { diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 8bd86d9e..466807bc 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -32,11 +32,11 @@ #include /* 'bit' must be unsigned or additional range check must be added: bit>=CO_LSS_FASTSCAN_BIT0 */ -#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit<=CO_LSS_FASTSCAN_BIT31) || (bit==CO_LSS_FASTSCAN_CONFIRM)) +#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit<=(uint8_t)CO_LSS_FASTSCAN_BIT31) || (bit==(uint8_t)CO_LSS_FASTSCAN_CONFIRM)) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_FASTSCAN_VENDOR_ID */ -#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=CO_LSS_FASTSCAN_SERIAL) +#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=(uint8_t)CO_LSS_FASTSCAN_SERIAL) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_BIT_TIMING_1000 */ -#define CO_LSS_BIT_TIMING_VALID(index) ((index != 5) && (index <= CO_LSS_BIT_TIMING_AUTO)) +#define CO_LSS_BIT_TIMING_VALID(index) ((index != 5U) && (index <= (uint8_t)CO_LSS_BIT_TIMING_AUTO)) /* * Read received message from CAN module. @@ -136,7 +136,7 @@ static void CO_LSSslave_receive(void *object, void *msg) idNumber = CO_SWAP_32(valSw); ack = false; - if (bitCheck == CO_LSS_FASTSCAN_CONFIRM) { + if (bitCheck == (uint8_t)CO_LSS_FASTSCAN_CONFIRM) { /* Confirm, Reset */ ack = true; LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; diff --git a/CANopen.c b/CANopen.c index 0396043b..97387327 100644 --- a/CANopen.c +++ b/CANopen.c @@ -33,8 +33,8 @@ #else #include "OD.h" -#define CO_GET_CO(obj) CO_##obj -#define CO_GET_CNT(obj) OD_CNT_##obj +#define CO_GET_CO(obj) ((uint16_t)(CO_##obj)) +#define CO_GET_CNT(obj) ((uint16_t)(OD_CNT_##obj)) #define OD_GET(entry, index) OD_ENTRY_##entry /* Verify parameters from "OD.h" and calculate necessary values for each object: @@ -272,37 +272,37 @@ /* Indexes of CO_CANrx_t and CO_CANtx_t objects in CO_CANmodule_t and total * number of them. Indexes are sorted in a way, that objects with highest * priority of the CAN identifier are listed first. */ -#define CO_RX_IDX_NMT_SLV 0 -#define CO_RX_IDX_GFC (CO_RX_IDX_NMT_SLV + CO_RX_CNT_NMT_SLV) -#define CO_RX_IDX_SYNC (CO_RX_IDX_GFC + CO_RX_CNT_GFC) -#define CO_RX_IDX_EM_CONS (CO_RX_IDX_SYNC + CO_RX_CNT_SYNC) -#define CO_RX_IDX_TIME (CO_RX_IDX_EM_CONS + CO_RX_CNT_EM_CONS) -#define CO_RX_IDX_SRDO (CO_RX_IDX_TIME + CO_RX_CNT_TIME) -#define CO_RX_IDX_RPDO (CO_RX_IDX_SRDO + CO_RX_CNT_SRDO * 2) -#define CO_RX_IDX_SDO_SRV (CO_RX_IDX_RPDO + CO_RX_CNT_RPDO) -#define CO_RX_IDX_SDO_CLI (CO_RX_IDX_SDO_SRV + CO_RX_CNT_SDO_SRV) -#define CO_RX_IDX_HB_CONS (CO_RX_IDX_SDO_CLI + CO_RX_CNT_SDO_CLI) -#define CO_RX_IDX_NG_SLV (CO_RX_IDX_HB_CONS + CO_RX_CNT_HB_CONS) -#define CO_RX_IDX_NG_MST (CO_RX_IDX_NG_SLV + CO_RX_CNT_NG_SLV) -#define CO_RX_IDX_LSS_SLV (CO_RX_IDX_NG_MST + CO_RX_CNT_NG_MST) -#define CO_RX_IDX_LSS_MST (CO_RX_IDX_LSS_SLV + CO_RX_CNT_LSS_SLV) -#define CO_CNT_ALL_RX_MSGS (CO_RX_IDX_LSS_MST + CO_RX_CNT_LSS_MST) - -#define CO_TX_IDX_NMT_MST 0 -#define CO_TX_IDX_GFC (CO_TX_IDX_NMT_MST + CO_TX_CNT_NMT_MST) -#define CO_TX_IDX_SYNC (CO_TX_IDX_GFC + CO_TX_CNT_GFC) -#define CO_TX_IDX_EM_PROD (CO_TX_IDX_SYNC + CO_TX_CNT_SYNC) -#define CO_TX_IDX_TIME (CO_TX_IDX_EM_PROD + CO_TX_CNT_EM_PROD) -#define CO_TX_IDX_SRDO (CO_TX_IDX_TIME + CO_TX_CNT_TIME) -#define CO_TX_IDX_TPDO (CO_TX_IDX_SRDO + CO_TX_CNT_SRDO * 2) -#define CO_TX_IDX_SDO_SRV (CO_TX_IDX_TPDO + CO_TX_CNT_TPDO) -#define CO_TX_IDX_SDO_CLI (CO_TX_IDX_SDO_SRV + CO_TX_CNT_SDO_SRV) -#define CO_TX_IDX_HB_PROD (CO_TX_IDX_SDO_CLI + CO_TX_CNT_SDO_CLI) -#define CO_TX_IDX_NG_SLV (CO_TX_IDX_HB_PROD + CO_TX_CNT_HB_PROD) -#define CO_TX_IDX_NG_MST (CO_TX_IDX_NG_SLV + CO_TX_CNT_NG_SLV) -#define CO_TX_IDX_LSS_SLV (CO_TX_IDX_NG_MST + CO_TX_CNT_NG_MST) -#define CO_TX_IDX_LSS_MST (CO_TX_IDX_LSS_SLV + CO_TX_CNT_LSS_SLV) -#define CO_CNT_ALL_TX_MSGS (CO_TX_IDX_LSS_MST + CO_TX_CNT_LSS_MST) +#define CO_RX_IDX_NMT_SLV 0U +#define CO_RX_IDX_GFC (CO_RX_IDX_NMT_SLV + (uint16_t)CO_RX_CNT_NMT_SLV) +#define CO_RX_IDX_SYNC (CO_RX_IDX_GFC + (uint16_t)CO_RX_CNT_GFC) +#define CO_RX_IDX_EM_CONS (CO_RX_IDX_SYNC + (uint16_t)CO_RX_CNT_SYNC) +#define CO_RX_IDX_TIME (CO_RX_IDX_EM_CONS + (uint16_t)CO_RX_CNT_EM_CONS) +#define CO_RX_IDX_SRDO (CO_RX_IDX_TIME + (uint16_t)CO_RX_CNT_TIME) +#define CO_RX_IDX_RPDO (CO_RX_IDX_SRDO + ((uint16_t)CO_RX_CNT_SRDO * 2U)) +#define CO_RX_IDX_SDO_SRV (CO_RX_IDX_RPDO + (uint16_t)CO_RX_CNT_RPDO) +#define CO_RX_IDX_SDO_CLI (CO_RX_IDX_SDO_SRV + (uint16_t)CO_RX_CNT_SDO_SRV) +#define CO_RX_IDX_HB_CONS (CO_RX_IDX_SDO_CLI + (uint16_t)CO_RX_CNT_SDO_CLI) +#define CO_RX_IDX_NG_SLV (CO_RX_IDX_HB_CONS + (uint16_t)CO_RX_CNT_HB_CONS) +#define CO_RX_IDX_NG_MST (CO_RX_IDX_NG_SLV + (uint16_t)CO_RX_CNT_NG_SLV) +#define CO_RX_IDX_LSS_SLV (CO_RX_IDX_NG_MST + (uint16_t)CO_RX_CNT_NG_MST) +#define CO_RX_IDX_LSS_MST (CO_RX_IDX_LSS_SLV + (uint16_t)CO_RX_CNT_LSS_SLV) +#define CO_CNT_ALL_RX_MSGS (CO_RX_IDX_LSS_MST + (uint16_t)CO_RX_CNT_LSS_MST) + +#define CO_TX_IDX_NMT_MST 0U +#define CO_TX_IDX_GFC (CO_TX_IDX_NMT_MST + (uint16_t)CO_TX_CNT_NMT_MST) +#define CO_TX_IDX_SYNC (CO_TX_IDX_GFC + (uint16_t)CO_TX_CNT_GFC) +#define CO_TX_IDX_EM_PROD (CO_TX_IDX_SYNC + (uint16_t)CO_TX_CNT_SYNC) +#define CO_TX_IDX_TIME (CO_TX_IDX_EM_PROD + (uint16_t)CO_TX_CNT_EM_PROD) +#define CO_TX_IDX_SRDO (CO_TX_IDX_TIME + (uint16_t)CO_TX_CNT_TIME) +#define CO_TX_IDX_TPDO (CO_TX_IDX_SRDO + ((uint16_t)CO_TX_CNT_SRDO * 2U)) +#define CO_TX_IDX_SDO_SRV (CO_TX_IDX_TPDO + (uint16_t)CO_TX_CNT_TPDO) +#define CO_TX_IDX_SDO_CLI (CO_TX_IDX_SDO_SRV + (uint16_t)CO_TX_CNT_SDO_SRV) +#define CO_TX_IDX_HB_PROD (CO_TX_IDX_SDO_CLI + (uint16_t)CO_TX_CNT_SDO_CLI) +#define CO_TX_IDX_NG_SLV (CO_TX_IDX_HB_PROD + (uint16_t)CO_TX_CNT_HB_PROD) +#define CO_TX_IDX_NG_MST (CO_TX_IDX_NG_SLV + (uint16_t)CO_TX_CNT_NG_SLV) +#define CO_TX_IDX_LSS_SLV (CO_TX_IDX_NG_MST + (uint16_t)CO_TX_CNT_NG_MST) +#define CO_TX_IDX_LSS_MST (CO_TX_IDX_LSS_SLV + (uint16_t)CO_TX_CNT_LSS_SLV) +#define CO_CNT_ALL_TX_MSGS (CO_TX_IDX_LSS_MST + (uint16_t)CO_TX_CNT_LSS_MST) #endif /* #ifdef #else CO_MULTIPLE_OD */ @@ -1058,7 +1058,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif co->CANmodule, CO_GET_CO(TX_IDX_HB_PROD), - CO_CAN_ID_HEARTBEAT + nodeId, + (uint16_t)CO_CAN_ID_HEARTBEAT + nodeId, errInfo); if (err) { return err; } } @@ -1082,7 +1082,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, OD_GET(H100C, OD_H100C_GUARD_TIME), OD_GET(H100D, OD_H100D_LIFETIME_FACTOR), em, - CO_CAN_ID_HEARTBEAT + nodeId, + (uint16_t)CO_CAN_ID_HEARTBEAT + nodeId, co->CANmodule, CO_GET_CO(RX_IDX_NG_SLV), co->CANmodule, @@ -1103,7 +1103,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, /* SDOserver */ if (CO_GET_CNT(SDO_SRV) > 0U) { OD_entry_t *SDOsrvPar = OD_GET(H1200, OD_H1200_SDO_SERVER_1_PARAM); - for (int16_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { + for (uint16_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { err = CO_SDOserver_init(&co->SDOserver[i], od, SDOsrvPar++, @@ -1121,7 +1121,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE if (CO_GET_CNT(SDO_CLI) > 0) { OD_entry_t *SDOcliPar = OD_GET(H1280, OD_H1280_SDO_CLIENT_1_PARAM); - for (int16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { + for (uint16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { err = CO_SDOclient_init(&co->SDOclient[i], od, SDOcliPar++, @@ -1253,12 +1253,12 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, if (CO_GET_CNT(RPDO) > 0U) { OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); - for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { + for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { CO_ReturnError_t err; uint16_t preDefinedCanId = 0; if (i < CO_RPDO_DEFAULT_CANID_COUNT) { #if CO_RPDO_DEFAULT_CANID_COUNT <= 4 - preDefinedCanId = (CO_CAN_ID_RPDO_1 + i * 0x100) + nodeId; + preDefinedCanId = ((uint16_t)CO_CAN_ID_RPDO_1 + (i * 0x100U)) + nodeId; #else uint16_t pdoOffset = i % 4; uint16_t nodeIdOffset = i / 4; @@ -1287,12 +1287,12 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, if (CO_GET_CNT(TPDO) > 0U) { OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); - for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { + for (uint16_t i = 0; i < CO_GET_CNT(TPDO); i++) { CO_ReturnError_t err; uint16_t preDefinedCanId = 0; if (i < CO_TPDO_DEFAULT_CANID_COUNT) { #if CO_TPDO_DEFAULT_CANID_COUNT <= 4 - preDefinedCanId = (CO_CAN_ID_TPDO_1 + i * 0x100) + nodeId; + preDefinedCanId = ((uint16_t)CO_CAN_ID_TPDO_1 + (i * 0x100U)) + nodeId; #else uint16_t pdoOffset = i % 4; uint16_t nodeIdOffset = i / 4; @@ -1364,9 +1364,9 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); OD_entry_t *SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); - for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { - uint16_t CANdevRxIdx = CO_GET_CO(RX_IDX_SRDO) + 2 * i; - uint16_t CANdevTxIdx = CO_GET_CO(TX_IDX_SRDO) + 2 * i; + for (uint16_t i = 0; i < CO_GET_CNT(SRDO); i++) { + uint16_t CANdevRxIdx = CO_GET_CO(RX_IDX_SRDO) + (2U * i); + uint16_t CANdevTxIdx = CO_GET_CO(TX_IDX_SRDO) + (2U * i); err = CO_SRDO_init(&co->SRDO[i], i, @@ -1374,7 +1374,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, od, em, nodeId, - ((i == 0) ? CO_CAN_ID_SRDO_1 : 0), + ((i == 0U) ? (uint16_t)CO_CAN_ID_SRDO_1 : 0U), SRDOcomm++, SRDOmap++, OD_GET(H13FE, OD_H13FE_SRDO_VALID), @@ -1408,8 +1408,8 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, (void) enableGateway; /* may be unused */ CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_NMT_internalState_t NMTstate = CO_NMT_getInternalState(co->NMT); - bool_t NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL - || NMTstate == CO_NMT_OPERATIONAL); + bool_t NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) + || (NMTstate == CO_NMT_OPERATIONAL)); /* CAN module */ CO_CANmodule_process(co->CANmodule); @@ -1427,8 +1427,8 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, uint16_t CANerrorStatus = co->CANmodule->CANerrorStatus; bool_t LSSslave_configuration = false; #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE - if (CO_GET_CNT(LSS_SLV) == 1 - && CO_LSSslave_getState(co->LSSslave) == CO_LSS_STATE_CONFIGURATION + if ((CO_GET_CNT(LSS_SLV) == 1U) + && (CO_LSSslave_getState(co->LSSslave) == CO_LSS_STATE_CONFIGURATION) ) { LSSslave_configuration = true; } @@ -1443,8 +1443,8 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, timeDifference_us, unc ? CO_NMT_INITIALIZING : NMTstate, LSSslave_configuration, - (CANerrorStatus & CO_CAN_ERRTX_BUS_OFF) != 0, - (CANerrorStatus & CO_CAN_ERR_WARN_PASSIVE) != 0, + (CANerrorStatus & (uint16_t)CO_CAN_ERRTX_BUS_OFF) != 0U, + (CANerrorStatus & (uint16_t)CO_CAN_ERR_WARN_PASSIVE) != 0U, 0, /* RPDO event timer timeout */ unc ? false : CO_isError(co->em, CO_EM_SYNC_TIME_OUT), unc ? false : (CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) @@ -1475,8 +1475,8 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, timeDifference_us, timerNext_us); } - NMTisPreOrOperational = (NMTstate == CO_NMT_PRE_OPERATIONAL - || NMTstate == CO_NMT_OPERATIONAL); + NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) + || (NMTstate == CO_NMT_OPERATIONAL)); /* SDOserver */ for (uint8_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { @@ -1580,7 +1580,7 @@ void CO_process_RPDO(CO_t *co, bool_t NMTisOperational = CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; - for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) { + for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { CO_RPDO_process(&co->RPDO[i], #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE timeDifference_us, @@ -1608,7 +1608,7 @@ void CO_process_TPDO(CO_t *co, bool_t NMTisOperational = CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; - for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) { + for (uint16_t i = 0; i < CO_GET_CNT(TPDO); i++) { CO_TPDO_process(&co->TPDO[i], #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE timeDifference_us, @@ -1637,7 +1637,7 @@ CO_SRDO_state_t CO_process_SRDO(CO_t *co, CO_SRDO_state_t lowestState = CO_SRDO_state_deleted; - for (int16_t i = 0; i < CO_GET_CNT(SRDO); i++) { + for (Uint16_t i = 0; i < CO_GET_CNT(SRDO); i++) { CO_SRDO_state_t state = CO_SRDO_process(&co->SRDO[i], timeDifference_us, timerNext_us, From 46dcd052513b61eab55bfaaabb2f1c194c484f16 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 07:39:23 +0200 Subject: [PATCH 267/520] CO_SRDO: static analysis: function 'OD_not_write_same_value' defined without a prototype in scope [MISRA 2012 Rule 8.4, required] --- 304/CO_SRDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index b0b0bb6d..9eca1077 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -142,7 +142,7 @@ OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countR } #ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION -bool_t +static bool_t OD_not_write_same_value(OD_stream_t *stream, const void *buf, OD_size_t count) { // The conformance test tool does not recognize CANopen Safety and on all object dictionaty tries to read and write the same value OD_size_t countRead = 0; From e87959d86c58a9eb25e0f50b2d3fc711558cffb4 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 07:44:43 +0200 Subject: [PATCH 268/520] CO_SRDO: static analysis: ignoring return value of function 'OD_extension_init' [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] ignores the return because it was checked on the function argument --- 304/CO_SRDO.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 9eca1077..1753dd39 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -368,12 +368,12 @@ CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationV SRDOGuard->OD_13FE_extension.object = SRDOGuard; SRDOGuard->OD_13FE_extension.read = OD_readOriginal; SRDOGuard->OD_13FE_extension.write = OD_write_13FE; - OD_extension_init(OD_13FE_configurationValid, &SRDOGuard->OD_13FE_extension); + (void)OD_extension_init(OD_13FE_configurationValid, &SRDOGuard->OD_13FE_extension); SRDOGuard->OD_13FF_extension.object = SRDOGuard; SRDOGuard->OD_13FF_extension.read = OD_readOriginal; SRDOGuard->OD_13FF_extension.write = OD_write_13FF; - OD_extension_init(OD_13FF_safetyConfigurationSignature, &SRDOGuard->OD_13FF_extension); + (void)OD_extension_init(OD_13FF_safetyConfigurationSignature, &SRDOGuard->OD_13FF_extension); /* Configure SRDOGuard->OD_IO_configurationValid variable. * It will be used for writing 0 to OD variable 13FE,00 */ @@ -446,13 +446,13 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ SRDO->OD_communicationParam_ext.object = SRDO; SRDO->OD_communicationParam_ext.read = OD_read_SRDO_communicationParam; SRDO->OD_communicationParam_ext.write = OD_write_SRDO_communicationParam; - OD_extension_init(OD_130x_SRDOCommPar, &SRDO->OD_communicationParam_ext); + (void)OD_extension_init(OD_130x_SRDOCommPar, &SRDO->OD_communicationParam_ext); /* Configure Object dictionary entry at index 0x1381+ */ SRDO->OD_mappingParam_extension.object = SRDO; SRDO->OD_mappingParam_extension.read = OD_readOriginal; SRDO->OD_mappingParam_extension.write = OD_write_SRDO_mappingParam; - OD_extension_init(OD_138x_SRDOMapPar, &SRDO->OD_mappingParam_extension); + (void)OD_extension_init(OD_138x_SRDOMapPar, &SRDO->OD_mappingParam_extension); } /* Get variables from object Dictionary and verify it's structure. */ From ae2f75b7a656d4c421f05240f27facb35639fa87 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 07:48:57 +0200 Subject: [PATCH 269/520] CO_SRDO: static analysis: warning 578: declaration of 'ret' hides a local variable [MISRA 2012 Rule 5.3, required] variable already declared at the beginning of the function --- 304/CO_SRDO.c | 1 - 1 file changed, 1 deletion(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 1753dd39..65d65586 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -668,7 +668,6 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* Configure CAN rx buffers */ if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_RX)) { - CO_ReturnError_t ret; ret = CO_CANrxBufferInit(CANdevRxNormal, /* CAN device */ CANdevRxIdxNormal, /* rx buffer index */ From 70fc66046bd1def69d8d9f4b4a7546a5891b5c9c Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 09:00:18 +0200 Subject: [PATCH 270/520] CO_SRDO: static analysis: no 'else' at end of 'if ... else if' chain [MISRA 2012 Rule 15.7, required] --- 304/CO_SRDO.c | 1 + 1 file changed, 1 insertion(+) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 65d65586..447e0fd6 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -966,6 +966,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext CO_FLAG_CLEAR(SRDO->CANrxNew[1]); } /* inverted message received */ } + else { /* MISRA C 2004 14.10 */ } /* verify timeouts */ if (SRDO->cycleTimer == 0U) { From 9632958e3d0c5c531688fe04df45be146c539ba5 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 09:03:19 +0200 Subject: [PATCH 271/520] CO_SRDO: static analysis: cannot assign 'signed8' to different essential type 'boolean' [MISRA 2012 Rule 10.3, required] --- 304/CO_SRDO.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 447e0fd6..f1cffeeb 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -646,9 +646,9 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ SRDO->CANtxBuff[0] = CO_CANtxBufferInit(CANdevTxNormal, /* CAN device */ CANdevTxIdxNormal, /* index of specific buffer inside CAN module */ COB_ID1_normal, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ SRDO->dataLength, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (SRDO->CANtxBuff[0] == NULL) { err = ERR_INFO(0x1301U + SRDO_Index, 5, 10); @@ -657,9 +657,9 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ SRDO->CANtxBuff[1] = CO_CANtxBufferInit(CANdevTxInverted, /* CAN device */ CANdevTxIdxInverted, /* index of specific buffer inside CAN module */ COB_ID2_inverted, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ SRDO->dataLength, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (SRDO->CANtxBuff[1] == NULL) { err = ERR_INFO(0x1301U + SRDO_Index, 6, 10); @@ -673,7 +673,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ CANdevRxIdxNormal, /* rx buffer index */ COB_ID1_normal, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)SRDO, /* object passed to the receive function */ CO_SRDO_receive_normal); /* this function will process received message */ @@ -685,7 +685,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ CANdevRxIdxInverted, /* rx buffer index */ COB_ID2_inverted, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)SRDO, /* object passed to the receive function */ CO_SRDO_receive_inverted); /* this function will process received message */ From 68daa1f526dc3cc21de668e82c19d903eca07f46 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 09:04:52 +0200 Subject: [PATCH 272/520] CO_SRDO: static analysis: cannot assign 'unsigned32' to narrower essential type 'unsigned16' [MISRA 2012 Rule 10.3, required] --- 304/CO_SRDO.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index f1cffeeb..b05a2694 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -645,7 +645,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ SRDO->CANtxBuff[0] = CO_CANtxBufferInit(CANdevTxNormal, /* CAN device */ CANdevTxIdxNormal, /* index of specific buffer inside CAN module */ - COB_ID1_normal, /* CAN identifier */ + (uint16_t)COB_ID1_normal, /* CAN identifier */ false, /* rtr */ SRDO->dataLength, /* number of data bytes */ false); /* synchronous message flag bit */ @@ -656,7 +656,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ SRDO->CANtxBuff[1] = CO_CANtxBufferInit(CANdevTxInverted, /* CAN device */ CANdevTxIdxInverted, /* index of specific buffer inside CAN module */ - COB_ID2_inverted, /* CAN identifier */ + (uint16_t)COB_ID2_inverted, /* CAN identifier */ false, /* rtr */ SRDO->dataLength, /* number of data bytes */ false); /* synchronous message flag bit */ @@ -671,7 +671,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ ret = CO_CANrxBufferInit(CANdevRxNormal, /* CAN device */ CANdevRxIdxNormal, /* rx buffer index */ - COB_ID1_normal, /* CAN identifier */ + (uint16_t)COB_ID1_normal, /* CAN identifier */ 0x7FF, /* mask */ false, /* rtr */ (void*)SRDO, /* object passed to the receive function */ @@ -683,7 +683,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ ret = CO_CANrxBufferInit(CANdevRxInverted, /* CAN device */ CANdevRxIdxInverted, /* rx buffer index */ - COB_ID2_inverted, /* CAN identifier */ + (uint16_t)COB_ID2_inverted, /* CAN identifier */ 0x7FF, /* mask */ false, /* rtr */ (void*)SRDO, /* object passed to the receive function */ From fa774c75fa46f03facf4690d86ca993050034d19 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 09:07:21 +0200 Subject: [PATCH 273/520] CO_SRDO: static analysis: variables are potentially uninitialized [MISRA 2012 Rule 9.1, mandatory] --- 304/CO_SRDO.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index b05a2694..cb1e92b6 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -411,16 +411,16 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ bool_t configurationInProgress = false; /* variables will be retrieved from Object Dictionary */ - uint8_t cp_highestSubindexSupported; - uint8_t informationDirection; - uint16_t safetyCycleTime; - uint8_t safetyRelatedValidationTime; - uint8_t transmissionType; - uint32_t COB_ID1_normal; - uint32_t COB_ID2_inverted; - uint8_t configurationValid; - uint16_t crcSignatureFromOD; - uint8_t mappedObjectsCount; + uint8_t cp_highestSubindexSupported = 0; + uint8_t informationDirection = 0; + uint16_t safetyCycleTime = 0; + uint8_t safetyRelatedValidationTime = 0; + uint8_t transmissionType = 0; + uint32_t COB_ID1_normal = 0; + uint32_t COB_ID2_inverted = 0; + uint8_t configurationValid = 0; + uint16_t crcSignatureFromOD = 0; + uint8_t mappedObjectsCount = 0; uint32_t mapping[CO_SRDO_MAX_MAPPED_ENTRIES]; /* verify arguments */ From c4c4f98e2c5368319277143d86bd91ea127292d8 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 09:10:15 +0200 Subject: [PATCH 274/520] CO_SRDO: static analysis result of assignment operator used in right operand to '=' operator [MISRA 2012 Rule 13.4, advisory] --- 304/CO_SRDO.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index cb1e92b6..d6186550 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -105,7 +105,8 @@ configurationValidUnset(CO_SRDOGuard_t* SRDOGuard) { uint8_t val = CO_SRDO_INVALID; OD_size_t dummy; - SRDOGuard->configurationValid = SRDOGuard->_configurationValid = false; + SRDOGuard->configurationValid = false; + SRDOGuard->_configurationValid = false; OD_IO->write(&OD_IO->stream, &val, sizeof(val), &dummy); } @@ -593,7 +594,8 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ else if ((index < 0x20U) && (subIndex == 0U)) { OD_stream_t *stream = &OD_IO->stream; (void)memset(stream, 0, sizeof(OD_stream_t)); - stream->dataLength = stream->dataOffset = mappedLength; + stream->dataLength = mappedLength; + stream->dataOffset = mappedLength; OD_IO->read = OD_read_dummy; OD_IO->write = OD_write_dummy; } From 5a31668c3ea24e9b75dd3349e453dfc15bccaa4e Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 09:12:42 +0200 Subject: [PATCH 275/520] CO_SRDO: static analysis: loss of precision (assignment) from 32 bits to 8 bits when: SRDO->dataLength = srdoDataLength[0]; --- 304/CO_SRDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index d6186550..95a3c8d3 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -575,7 +575,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* Configure mappings */ if ((err == 0U) && configurationInProgress) { - size_t srdoDataLength[2] = {0, 0}; + CO_SRDO_size_t srdoDataLength[2] = {0, 0}; for (uint8_t i = 0; i < mappedObjectsCount; i++) { uint8_t plain_inverted = i % 2U; From 88e437b525200db93af09339611fc9ead52bcabb Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 09:14:58 +0200 Subject: [PATCH 276/520] static analysis: minor fix --- CANopen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CANopen.c b/CANopen.c index 97387327..33523b4b 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1637,7 +1637,7 @@ CO_SRDO_state_t CO_process_SRDO(CO_t *co, CO_SRDO_state_t lowestState = CO_SRDO_state_deleted; - for (Uint16_t i = 0; i < CO_GET_CNT(SRDO); i++) { + for (uint16_t i = 0; i < CO_GET_CNT(SRDO); i++) { CO_SRDO_state_t state = CO_SRDO_process(&co->SRDO[i], timeDifference_us, timerNext_us, From 59e0c3b07b10f51f2c6109400889502f942cf04c Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 09:21:47 +0200 Subject: [PATCH 277/520] CO_SRDO: static analysis: the name '_configurationValid' matches a pattern reserved to the compiler [MISRA 2012 Rule 21.2, required] --- 304/CO_SRDO.c | 4 ++-- 304/CO_SRDO.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 95a3c8d3..0df39590 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -106,7 +106,7 @@ configurationValidUnset(CO_SRDOGuard_t* SRDOGuard) { OD_size_t dummy; SRDOGuard->configurationValid = false; - SRDOGuard->_configurationValid = false; + SRDOGuard->privateConfigValid = false; OD_IO->write(&OD_IO->stream, &val, sizeof(val), &dummy); } @@ -393,7 +393,7 @@ CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationV if (configurationValid == CO_SRDO_VALID_MAGIC) { /* Private variable, erroneous SRDO initialization will clear this. */ - SRDOGuard->_configurationValid = true; + SRDOGuard->privateConfigValid = true; } return CO_ERROR_NO; diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index e23c4847..a1bde1c9 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -127,7 +127,7 @@ typedef struct { * finish of all @CO_SRDO_init() functions. Cleared on configuration change. */ bool_t configurationValid; /** Private helper variable set on the start of SRDO configuration */ - bool_t _configurationValid; + bool_t privateConfigValid; /** Object for input / output on the OD variable 13FE:00. Configuration * of any of the the SRDO parameters will write 0 to that variable. */ OD_IO_t OD_IO_configurationValid; @@ -218,7 +218,7 @@ CO_ReturnError_t CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13 * @param SRDOGuard This object will be finalized. */ static inline void CO_SRDO_init_end(CO_SRDOGuard_t* SRDOGuard) { - SRDOGuard->configurationValid = SRDOGuard->_configurationValid; + SRDOGuard->configurationValid = SRDOGuard->privateConfigValid; } /** From e58c5de97683a77dabd77131f879af5e44d90355 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 14:43:05 +0200 Subject: [PATCH 278/520] CO_GFC: static analysis: ignoring return value of function 'OD_extension_init' [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] ignores the return because it was checked on the function argument --- 304/CO_GFC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_GFC.c b/304/CO_GFC.c index 191268ec..c57f055f 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -96,7 +96,7 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC GFC->OD_gfcParam_ext.object = GFC; GFC->OD_gfcParam_ext.read = OD_readOriginal; GFC->OD_gfcParam_ext.write = OD_write_1300; - OD_extension_init(OD_1300_gfcParameter, &GFC->OD_gfcParam_ext); + (void)OD_extension_init(OD_1300_gfcParameter, &GFC->OD_gfcParam_ext); #if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER GFC->CANdevTx = GFC_CANdevTx; From 3533d4498a3d6265ca58674d6cf7a562fbc1d080 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 14:45:15 +0200 Subject: [PATCH 279/520] CO_GFC: static analysis: add 'U' of unsigned [MISRA 2012 Rule 10.4, required] --- 304/CO_GFC.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/304/CO_GFC.c b/304/CO_GFC.c index c57f055f..9913c4a9 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -42,11 +42,11 @@ OD_write_1300(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* CO_GFC_t* GFC = stream->object; uint8_t value = CO_getUint8(buf); - if (value > 1) { + if (value > 1U) { return ODR_INVALID_VALUE; } - GFC->valid = (value == 1); + GFC->valid = (value == 1U); /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, buf, count, countWritten); @@ -60,7 +60,7 @@ CO_GFC_receive(void* object, void* msg) { GFC = (CO_GFC_t*)object; /* this is the correct pointer type of the first argument */ - if (GFC->valid && (DLC == 0)) { + if (GFC->valid && (DLC == 0U)) { /* Callback signals Global Failsafe Command */ if (GFC->pFunctSignalSafe != NULL) { @@ -90,7 +90,7 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC if (OD_get_u8(OD_1300_gfcParameter, 0, &valid, true) != ODR_OK) { return CO_ERROR_OD_PARAMETERS; } - GFC->valid = (valid == 1); + GFC->valid = (valid == 1U); /* Configure Object dictionary entry at index 0x1300+ */ GFC->OD_gfcParam_ext.object = GFC; From 7cabf33d355aabc1ee9153e1fe809811a3e0ac90 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 14:48:50 +0200 Subject: [PATCH 280/520] CO_GFC: static analysis: Added parentheses for dependency on operator precedence [MISRA 2012 Rule 12.1, advisory] --- 304/CO_GFC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_GFC.c b/304/CO_GFC.c index 9913c4a9..149b9a2c 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -82,7 +82,7 @@ CO_GFC_initCallbackEnterSafeState(CO_GFC_t* GFC, void* object, void (*pFunctSign CO_ReturnError_t CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC_CANdevRx, uint16_t GFC_rxIdx, uint16_t CANidRxGFC, CO_CANmodule_t* GFC_CANdevTx, uint16_t GFC_txIdx, uint16_t CANidTxGFC) { - if (GFC == NULL || OD_1300_gfcParameter == NULL || GFC_CANdevRx == NULL || GFC_CANdevTx == NULL) { + if ((GFC == NULL) || (OD_1300_gfcParameter == NULL) || (GFC_CANdevRx == NULL) || (GFC_CANdevTx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } From bfa773da0566db3216a44a22223cbf273c8395e2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 14:49:48 +0200 Subject: [PATCH 281/520] CO_GFC: static analysis: cannot assign 'signed8' to different essential type 'boolean' [MISRA 2012 Rule 10.3, required] --- 304/CO_GFC.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/304/CO_GFC.c b/304/CO_GFC.c index 149b9a2c..f8e5b2ae 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -103,9 +103,9 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC GFC->CANtxBuff = CO_CANtxBufferInit(GFC->CANdevTx, /* CAN device */ GFC_txIdx, /* index of specific buffer inside CAN module */ CANidTxGFC, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 0, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (GFC->CANtxBuff == NULL) { return CO_ERROR_TX_UNCONFIGURED; @@ -122,7 +122,7 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC GFC_rxIdx, /* rx buffer index */ CANidRxGFC, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)GFC, /* object passed to receive function */ CO_GFC_receive); /* this function will process received message */ if (r != CO_ERROR_NO) { From 7399d31447593b51ac2898f9634c55d664b18af2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Tue, 11 Jun 2024 15:09:49 +0200 Subject: [PATCH 282/520] static analysis: ignoring return value of function 'OD_extension_init' [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] ignores the return because it was checked on the function argument --- 301/CO_PDO.c | 8 ++++---- 301/CO_SYNC.c | 4 ++-- 301/CO_TIME.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 8a3e3b2d..4b7dac00 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -756,8 +756,8 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, PDO->OD_mappingParam_extension.object = RPDO; PDO->OD_mappingParam_extension.read = OD_readOriginal; PDO->OD_mappingParam_extension.write = OD_write_PDO_mapping; - OD_extension_init(OD_14xx_RPDOCommPar, &PDO->OD_communicationParam_ext); - OD_extension_init(OD_16xx_RPDOMapPar, &PDO->OD_mappingParam_extension); + (void)OD_extension_init(OD_14xx_RPDOCommPar, &PDO->OD_communicationParam_ext); + (void)OD_extension_init(OD_16xx_RPDOMapPar, &PDO->OD_mappingParam_extension); #endif return CO_ERROR_NO; @@ -1216,8 +1216,8 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, PDO->OD_mappingParam_extension.object = TPDO; PDO->OD_mappingParam_extension.read = OD_readOriginal; PDO->OD_mappingParam_extension.write = OD_write_PDO_mapping; - OD_extension_init(OD_18xx_TPDOCommPar, &PDO->OD_communicationParam_ext); - OD_extension_init(OD_1Axx_TPDOMapPar, &PDO->OD_mappingParam_extension); + (void)OD_extension_init(OD_18xx_TPDOCommPar, &PDO->OD_communicationParam_ext); + (void)OD_extension_init(OD_1Axx_TPDOMapPar, &PDO->OD_mappingParam_extension); #endif return CO_ERROR_NO; diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 56549fbe..3b77cd41 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -243,7 +243,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, SYNC->OD_1005_extension.object = SYNC; SYNC->OD_1005_extension.read = OD_readOriginal; SYNC->OD_1005_extension.write = OD_write_1005; - OD_extension_init(OD_1005_cobIdSync, &SYNC->OD_1005_extension); + (void)OD_extension_init(OD_1005_cobIdSync, &SYNC->OD_1005_extension); #endif /* get and verify "Communication cycle period" from OD */ @@ -296,7 +296,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, SYNC->OD_1019_extension.object = SYNC; SYNC->OD_1019_extension.read = OD_readOriginal; SYNC->OD_1019_extension.write = OD_write_1019; - OD_extension_init(OD_1019_syncCounterOvf, &SYNC->OD_1019_extension); + (void)OD_extension_init(OD_1019_syncCounterOvf, &SYNC->OD_1019_extension); #endif #endif } diff --git a/301/CO_TIME.c b/301/CO_TIME.c index ee6201ef..c8530342 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -121,7 +121,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, TIME->OD_1012_extension.object = TIME; TIME->OD_1012_extension.read = OD_readOriginal; TIME->OD_1012_extension.write = OD_write_1012; - OD_extension_init(OD_1012_cobIdTimeStamp, &TIME->OD_1012_extension); + (void)OD_extension_init(OD_1012_cobIdTimeStamp, &TIME->OD_1012_extension); #endif /* Configure object variables */ From d4e7214f4d81c470f8a653012c50f2936da50693 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 09:09:12 +0200 Subject: [PATCH 283/520] static analysis: conditional of #if does not evaluate to 0 or 1 [MISRA 2012 Rule 20.8, required] --- 301/CO_Emergency.c | 72 ++++----- 301/CO_Emergency.h | 36 ++--- 301/CO_HBconsumer.c | 42 ++--- 301/CO_HBconsumer.h | 24 +-- 301/CO_NMT_Heartbeat.c | 18 +-- 301/CO_NMT_Heartbeat.h | 12 +- 301/CO_Node_Guarding.c | 8 +- 301/CO_Node_Guarding.h | 4 +- 301/CO_PDO.c | 98 ++++++------ 301/CO_PDO.h | 32 ++-- 301/CO_SDOclient.c | 94 ++++++------ 301/CO_SDOclient.h | 16 +- 301/CO_SDOserver.c | 76 ++++----- 301/CO_SDOserver.h | 10 +- 301/CO_SYNC.c | 42 ++--- 301/CO_SYNC.h | 14 +- 301/CO_TIME.c | 18 +-- 301/CO_TIME.h | 14 +- 301/CO_fifo.c | 20 +-- 301/CO_fifo.h | 14 +- 301/crc16-ccitt.c | 4 +- 301/crc16-ccitt.h | 2 +- 303/CO_LEDs.c | 4 +- 303/CO_LEDs.h | 2 +- 304/CO_GFC.c | 10 +- 304/CO_GFC.h | 10 +- 304/CO_SRDO.c | 16 +- 304/CO_SRDO.h | 6 +- 305/CO_LSS.h | 2 +- 305/CO_LSSmaster.c | 8 +- 305/CO_LSSmaster.h | 6 +- 305/CO_LSSslave.c | 8 +- 305/CO_LSSslave.h | 6 +- 309/CO_gateway_ascii.c | 82 +++++----- 309/CO_gateway_ascii.h | 26 ++-- CANopen.c | 306 ++++++++++++++++++------------------- CANopen.h | 42 ++--- storage/CO_storage.c | 2 +- storage/CO_storage.h | 2 +- storage/CO_storageEeprom.c | 2 +- storage/CO_storageEeprom.h | 2 +- 41 files changed, 606 insertions(+), 606 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index a09aa2d0..cafbc6a3 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -48,8 +48,8 @@ * to process to process to process full * ******************************************************************************/ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 /* * Custom functions for read/write OD object "COB-ID EMCY" * @@ -146,7 +146,7 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE */ - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 /* * Custom function for writing OD object "Inhibit time EMCY" * @@ -243,7 +243,7 @@ static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0 /* * Custom functions for read/write OD object _OD_statusBits_, optional * @@ -308,7 +308,7 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 /* * Read received message from CAN module. * @@ -345,24 +345,24 @@ static void CO_EM_receive(void *object, void *msg) { CO_ReturnError_t CO_EM_init(CO_EM_t *em, CO_CANmodule_t *CANdevTx, const OD_entry_t *OD_1001_errReg, -#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 CO_EM_fifo_t *fifo, uint8_t fifoSize, #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 OD_entry_t *OD_1014_cobIdEm, uint16_t CANdevTxIdx, - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 OD_entry_t *OD_1015_InhTime, #endif #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 OD_entry_t *OD_1003_preDefErr, #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0 OD_entry_t *OD_statusBits, #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, #endif @@ -374,17 +374,17 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* verify arguments */ if ((em == NULL) || (OD_1001_errReg == NULL) -#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 || ((fifo == NULL) && (fifoSize >= 2U)) #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 || (OD_1014_cobIdEm == NULL) || (CANdevTx == NULL) || (nodeId < 1U) || (nodeId > 127U) #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 || OD_1003_preDefErr == NULL #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 || CANdevRx == NULL #endif ) { @@ -405,11 +405,11 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, } *em->errorRegister = 0; -#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 em->fifo = fifo; em->fifoSize = fifoSize; #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 /* get initial and verify "COB-ID EMCY" from Object Dictionary */ uint32_t COB_IDEmergency32; ODR_t odRet; @@ -420,7 +420,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, if (odRet != ODR_OK) { return CO_ERROR_OD_PARAMETERS; } } - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0 && producerCanId != 0; @@ -469,7 +469,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, return CO_ERROR_ILLEGAL_ARGUMENT; } - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 /* get and verify optional "Inhibit time EMCY" from Object Dictionary */ em->inhibitEmTime_us = 0; em->inhibitEmTimer = 0; @@ -487,7 +487,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 /* If OD entry available, make access to em->preDefErr */ em->OD_1003_extension.object = em; em->OD_1003_extension.read = OD_read_1003; @@ -496,7 +496,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0 /* If OD entry available, make access to em->errorStatusBits */ em->OD_statusBits_extension.object = em; em->OD_statusBits_extension.read = OD_read_statusBits; @@ -505,7 +505,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 em->pFunctSignalRx = NULL; /* configure SDO server CAN reception */ ret = CO_CANrxBufferInit( @@ -523,7 +523,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /******************************************************************************/ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 void CO_EM_initCallbackRx(CO_EM_t *em, void (*pFunctSignalRx)(const uint16_t ident, const uint16_t errorCode, @@ -537,7 +537,7 @@ void CO_EM_initCallbackRx(CO_EM_t *em, } #endif -#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 void CO_EM_initCallbackPre(CO_EM_t *em, void *object, void (*pFunctSignal)(void *object)) @@ -633,11 +633,11 @@ void CO_EM_process(CO_EM_t *em, } /* post-process Emergency message in fifo buffer. */ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 if (em->fifoSize >= 2U) { uint8_t fifoPpPtr = em->fifoPpPtr; - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 if (em->inhibitEmTimer < em->inhibitEmTime_us) { em->inhibitEmTimer += timeDifference_us; } @@ -657,7 +657,7 @@ void CO_EM_process(CO_EM_t *em, sizeof(em->CANtxBuff->data)); CO_CANsend(em->CANdevTx, em->CANtxBuff); - #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 /* report also own emergency messages */ if (em->pFunctSignalRx != NULL) { uint32_t errMsg = em->fifo[fifoPpPtr].msg; @@ -685,8 +685,8 @@ void CO_EM_process(CO_EM_t *em, } else { /* MISRA C 2004 14.10 */ } } - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT - #if (CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 + #if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL && em->inhibitEmTimer < em->inhibitEmTime_us) { @@ -699,7 +699,7 @@ void CO_EM_process(CO_EM_t *em, #endif #endif } -#elif (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY +#elif ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 if (em->fifoSize >= 2) { uint8_t fifoPpPtr = em->fifoPpPtr; while (fifoPpPtr != em->fifoWrPtr) { @@ -752,10 +752,10 @@ void CO_error(CO_EM_t *em, bool_t setError, const CO_EM_errorStatusBits_t errorB errorCode = CO_EMC_NO_ERROR; } -#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 /* prepare emergency message. Error register will be added in post-process*/ uint32_t errMsg = ((uint32_t)errorBit << 24) | CO_SWAP_16(errorCode); - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 uint32_t infoCodeSwapped = CO_SWAP_32(infoCode); #endif #endif @@ -765,7 +765,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const CO_EM_errorStatusBits_t errorB if (setError) { *errorStatusBits |= bitmask; } else { *errorStatusBits &= ~bitmask; } -#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 if (em->fifoSize >= 2) { uint8_t fifoWrPtr = em->fifoWrPtr; uint8_t fifoWrPtrNext = fifoWrPtr + 1; @@ -778,7 +778,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const CO_EM_errorStatusBits_t errorB } else { em->fifo[fifoWrPtr].msg = errMsg; - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 em->fifo[fifoWrPtr].info = infoCodeSwapped; #endif em->fifoWrPtr = fifoWrPtrNext; @@ -789,8 +789,8 @@ void CO_error(CO_EM_t *em, bool_t setError, const CO_EM_errorStatusBits_t errorB CO_UNLOCK_EMCY(em->CANdevTx); -#if (CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER +#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 /* Optional signal to RTOS, which can resume task, which handles * CO_EM_process */ if (em->pFunctSignalPre != NULL && em->producerEnabled) { diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 35a0e9ab..7fb05169 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -360,14 +360,14 @@ typedef enum { -#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) \ || defined CO_DOXYGEN /** * Fifo buffer for emergency producer and error history */ typedef struct { uint32_t msg; -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN uint32_t info; #endif } CO_EM_fifo_t; @@ -387,7 +387,7 @@ typedef struct { /** From CO_EM_init() */ CO_CANmodule_t *CANdevTx; -#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) \ || defined CO_DOXYGEN /** Internal circular FIFO buffer for storing pre-processed emergency * messages. Messages are added by @ref CO_error() function. All messages @@ -411,7 +411,7 @@ typedef struct { uint8_t fifoCount; #endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN /** True, if emergency producer is enabled, from Object dictionary */ bool_t producerEnabled; /** Copy of CANopen node ID, from CO_EM_init() */ @@ -420,13 +420,13 @@ typedef struct { CO_CANtx_t *CANtxBuff; /** Extension for OD object */ OD_extension_t OD_1014_extension; - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) || defined CO_DOXYGEN + #if (((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0) || defined CO_DOXYGEN /** COB ID of emergency message, from Object dictionary */ uint16_t producerCanId; /** From CO_EM_init() */ uint16_t CANdevTxIdx; #endif - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) || defined CO_DOXYGEN + #if (((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0) || defined CO_DOXYGEN /** Inhibit time for emergency message, from Object dictionary */ uint32_t inhibitEmTime_us; /**< Internal timer for inhibit time */ @@ -436,17 +436,17 @@ typedef struct { #endif #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0) || defined CO_DOXYGEN /** Extension for OD object */ OD_extension_t OD_1003_extension; #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0) || defined CO_DOXYGEN /** Extension for OD object */ OD_extension_t OD_statusBits_extension; #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN /** From CO_EM_initCallbackRx() or NULL */ void (*pFunctSignalRx)(const uint16_t ident, const uint16_t errorCode, @@ -455,7 +455,7 @@ typedef struct { const uint32_t infoCode); #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_EM_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void *object); /** From CO_EM_initCallbackPre() or NULL */ @@ -501,25 +501,25 @@ typedef struct { CO_ReturnError_t CO_EM_init(CO_EM_t *em, CO_CANmodule_t *CANdevTx, const OD_entry_t *OD_1001_errReg, -#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) \ || defined CO_DOXYGEN CO_EM_fifo_t *fifo, uint8_t fifoSize, #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN OD_entry_t *OD_1014_cobIdEm, uint16_t CANdevTxIdx, - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) || defined CO_DOXYGEN + #if (((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0) || defined CO_DOXYGEN OD_entry_t *OD_1015_InhTime, #endif #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0) || defined CO_DOXYGEN OD_entry_t *OD_1003_preDefErr, #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0) || defined CO_DOXYGEN OD_entry_t *OD_statusBits, #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, #endif @@ -527,7 +527,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint32_t *errInfo); -#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize Emergency callback function. * @@ -548,7 +548,7 @@ void CO_EM_initCallbackPre(CO_EM_t *em, #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN /** * Initialize Emergency received callback function. * diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 5bb1dc27..ed95e13b 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -25,11 +25,11 @@ #include "301/CO_HBconsumer.h" -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 /* Verify HB consumer configuration *******************************************/ -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ - && (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + && (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) #error CO_CONFIG_HB_CONS_CALLBACK_CHANGE and CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously! #endif @@ -49,7 +49,7 @@ static void CO_HBcons_receive(void *object, void *msg) { /* copy data and set 'new message' flag. */ HBconsNode->NMTstate = (CO_NMT_internalState_t)data[0]; CO_FLAG_SET(HBconsNode->CANrxNew); -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles HBcons. */ if (HBconsNode->pFunctSignalPre != NULL) { HBconsNode->pFunctSignalPre(HBconsNode->functSignalObjectPre); @@ -77,7 +77,7 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, uint16_t consumerTime_ms); -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "Consumer heartbeat time" * @@ -161,7 +161,7 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, } /* configure extension for OD */ -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 HBcons->OD_1016_extension.object = HBcons; HBcons->OD_1016_extension.read = OD_readOriginal; HBcons->OD_1016_extension.write = OD_write_1016; @@ -207,8 +207,8 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, monitoredNode->nodeId = nodeId; monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; monitoredNode->NMTstate = CO_NMT_UNKNOWN; -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ - || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -237,7 +237,7 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, } -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /******************************************************************************/ void CO_HBconsumer_initCallbackPre( CO_HBconsumer_t *HBcons, @@ -255,7 +255,7 @@ void CO_HBconsumer_initCallbackPre( #endif -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0 /******************************************************************************/ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, @@ -276,7 +276,7 @@ void CO_HBconsumer_initCallbackNmtChanged( #endif -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 /******************************************************************************/ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, @@ -379,7 +379,7 @@ void CO_HBconsumer_process( if (CO_FLAG_READ(monitoredNode->CANrxNew)) { if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) { /* bootup message*/ -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 if (monitoredNode->pFunctSignalRemoteReset != NULL) { monitoredNode->pFunctSignalRemoteReset( monitoredNode->nodeId, i, @@ -396,7 +396,7 @@ void CO_HBconsumer_process( } else { /* heartbeat message */ -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE && monitoredNode->pFunctSignalHbStarted != NULL) { monitoredNode->pFunctSignalHbStarted( @@ -418,7 +418,7 @@ void CO_HBconsumer_process( if (monitoredNode->timeoutTimer >= monitoredNode->time_us) { /* timeout expired */ -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 if (monitoredNode->pFunctSignalTimeout!=NULL) { monitoredNode->pFunctSignalTimeout( monitoredNode->nodeId, i, @@ -431,7 +431,7 @@ void CO_HBconsumer_process( monitoredNode->HBstate = CO_HBconsumer_TIMEOUT; } -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* Calculate timerNext_us for next timeout checking. */ uint32_t diff = monitoredNode->time_us @@ -449,11 +449,11 @@ void CO_HBconsumer_process( if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { allMonitoredOperationalCurrent = false; } -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ - || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) /* Verify, if NMT state of monitored node changed */ if(monitoredNode->NMTstate != monitoredNode->NMTstatePrev) { -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0 if (HBcons->pFunctSignalNmtChanged != NULL) { HBcons->pFunctSignalNmtChanged( monitoredNode->nodeId, i, monitoredNode->NMTstate, @@ -475,8 +475,8 @@ void CO_HBconsumer_process( for(uint8_t i=0; inumberOfMonitoredNodes; i++) { CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[i]; monitoredNode->NMTstate = CO_NMT_UNKNOWN; -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \ - || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -502,7 +502,7 @@ void CO_HBconsumer_process( } -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT) != 0 /******************************************************************************/ int8_t CO_HBconsumer_getIdxByNodeId( CO_HBconsumer_t *HBcons, diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 1ee1346a..29e942bc 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -39,7 +39,7 @@ CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -91,19 +91,19 @@ typedef struct { uint32_t time_us; /** Indication if new Heartbeat message received from the CAN bus */ volatile void *CANrxNew; -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_HBconsumer_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void *object); /** From CO_HBconsumer_initCallbackPre() or NULL */ void *functSignalObjectPre; #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) \ - || ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) \ +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) \ || defined CO_DOXYGEN /** Previous value of the remote node (Heartbeat payload) */ CO_NMT_internalState_t NMTstatePrev; #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, @@ -156,11 +156,11 @@ typedef struct { CO_CANmodule_t *CANdevRx; /** From CO_HBconsumer_init() */ uint16_t CANdevRxIdxStart; -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** Extension for OD object */ OD_extension_t OD_1016_extension; #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, @@ -201,7 +201,7 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, uint32_t *errInfo); -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer callback function. * @@ -219,8 +219,8 @@ void CO_HBconsumer_initCallbackPre( void (*pFunctSignal)(void *object)); #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) \ - || ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) \ +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) \ || defined CO_DOXYGEN /** * Initialize Heartbeat consumer NMT changed callback function. @@ -244,7 +244,7 @@ void CO_HBconsumer_initCallbackNmtChanged( void *object)); #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer started callback function. * @@ -317,7 +317,7 @@ void CO_HBconsumer_process( uint32_t *timerNext_us); -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT) != 0) || defined CO_DOXYGEN /** * Get the heartbeat producer object index by node ID * diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index e8e01073..20f722f1 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -44,7 +44,7 @@ static void CO_NMT_receive(void *object, void *msg) { if ((DLC == 2U) && ((nodeId == 0U) || (nodeId == NMT->nodeId))) { NMT->internalCommand = command; -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles NMT. */ if (NMT->pFunctSignalPre != NULL) { NMT->pFunctSignalPre(NMT->functSignalObjectPre); @@ -89,7 +89,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, CO_CANmodule_t *NMT_CANdevRx, uint16_t NMT_rxIdx, uint16_t CANidRxNMT, -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 CO_CANmodule_t *NMT_CANdevTx, uint16_t NMT_txIdx, uint16_t CANidTxNMT, @@ -104,7 +104,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, /* verify arguments */ if ((NMT == NULL) || (OD_1017_ProducerHbTime == NULL) || (em == NULL) || (NMT_CANdevRx == NULL) || (HB_CANdevTx == NULL) -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 || (NMT_CANdevTx == NULL) #endif ) { @@ -157,7 +157,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, return ret; } -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 /* configure NMT CAN transmission */ NMT->NMT_CANdevTx = NMT_CANdevTx; NMT->NMT_TXbuff = CO_CANtxBufferInit( @@ -189,7 +189,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, } -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 void CO_NMT_initCallbackPre(CO_NMT_t *NMT, void *object, void (*pFunctSignal)(void *object)) @@ -202,7 +202,7 @@ void CO_NMT_initCallbackPre(CO_NMT_t *NMT, #endif -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0 /******************************************************************************/ void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, void (*pFunctNMT)(CO_NMT_internalState_t state)) @@ -300,7 +300,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, } else { /* MISRA C 2004 14.10 */ } -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0 /* Notify operating state change */ if (NMT->operatingStatePrev != NMTstateCpy || NNTinit) { if (NMT->pFunctNMT != NULL) { @@ -309,7 +309,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, } #endif -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate, when next Heartbeat needs to be send */ if (NMT->HBproducerTime_us != 0 && timerNext_us != NULL) { if (NMT->operatingStatePrev != NMTstateCpy) { @@ -328,7 +328,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, } -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 /******************************************************************************/ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, CO_NMT_command_t command, diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index ddee475b..eb33ea7b 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -181,7 +181,7 @@ typedef struct { OD_extension_t OD_1017_extension; /** From CO_NMT_init() */ CO_EM_t *em; -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0) || defined CO_DOXYGEN /** From CO_NMT_init() */ CO_CANmodule_t *NMT_CANdevTx; /** CAN transmit buffer for NMT master message */ @@ -191,13 +191,13 @@ typedef struct { CO_CANmodule_t *HB_CANdevTx; /** CAN transmit buffer for heartbeat message */ CO_CANtx_t *HB_TXbuff; -#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_NMT_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void *object); /** From CO_NMT_initCallbackPre() or NULL */ void *functSignalObjectPre; #endif -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN /** From CO_NMT_initCallbackChanged() or NULL */ void (*pFunctNMT)(CO_NMT_internalState_t state); #endif @@ -242,7 +242,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, CO_CANmodule_t *NMT_CANdevRx, uint16_t NMT_rxIdx, uint16_t CANidRxNMT, -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0) || defined CO_DOXYGEN CO_CANmodule_t *NMT_CANdevTx, uint16_t NMT_txIdx, uint16_t CANidTxNMT, @@ -253,7 +253,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, uint32_t *errInfo); -#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize NMT callback function after message preprocessed. * @@ -272,7 +272,7 @@ void CO_NMT_initCallbackPre(CO_NMT_t *NMT, #endif -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN /** * Initialize NMT callback function. * diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 77867138..dfe02457 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -25,7 +25,7 @@ #include "301/CO_Node_Guarding.h" -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 /* * Read received message from CAN module. @@ -240,7 +240,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, else if (ngs->lifeTimer > 0U) { if (timeDifference_us < ngs->lifeTimer) { ngs->lifeTimer -= timeDifference_us; -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate, when timeout expires */ if (timerNext_us != NULL && *timerNext_us > ngs->lifeTimer) { *timerNext_us = ngs->lifeTimer; @@ -265,7 +265,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 /* * Read received message from CAN module. * @@ -402,7 +402,7 @@ void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, if (node->guardTime_us > 0 && node->ident > CO_CAN_ID_HEARTBEAT) { if (timeDifference_us < node->guardTimer) { node->guardTimer -= timeDifference_us; -#if (CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate, when timeout expires */ if (timerNext_us != NULL && *timerNext_us > node->guardTimer) { *timerNext_us = node->guardTimer; diff --git a/301/CO_Node_Guarding.h b/301/CO_Node_Guarding.h index 6cf17355..08b2b55f 100644 --- a/301/CO_Node_Guarding.h +++ b/301/CO_Node_Guarding.h @@ -39,7 +39,7 @@ #define CO_CONFIG_NODE_GUARDING_MASTER_COUNT 0x7F #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -186,7 +186,7 @@ static inline bool_t CO_nodeGuardingSlave_isTimeout(CO_nodeGuardingSlave_t *ngs) -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0) || defined CO_DOXYGEN #if CO_CONFIG_NODE_GUARDING_MASTER_COUNT < 1 || CO_CONFIG_NODE_GUARDING_MASTER_COUNT > 127 #error CO_CONFIG_NODE_GUARDING_MASTER_COUNT value is wrong! diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 4b7dac00..9ba00f51 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -27,15 +27,15 @@ #include "301/CO_PDO.h" -#if (CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE) +#if ((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) != 0 -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 #error Dynamic PDO mapping is not possible without CO_CONFIG_PDO_OD_IO_ACCESS #endif #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 /* * Custom function for write dummy OD object. Will be used only from RPDO. * @@ -222,7 +222,7 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, return CO_ERROR_NO; } -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "PDO mapping parameter" * @@ -404,7 +404,7 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, #endif /* ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 */ -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for reading OD object "PDO communication parameter" * @@ -441,7 +441,7 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, /******************************************************************************* * R P D O ******************************************************************************/ -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 /* * States for RPDO->receiveError indicates received RPDOs with wrong length. */ @@ -482,7 +482,7 @@ static void CO_PDO_receive(void *object, void *msg) { /* Determine, to which of the two rx buffers copy the message. */ uint8_t bufNo = 0; -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if (RPDO->synchronous && (RPDO->SYNC != NULL) && RPDO->SYNC->CANrxToggle ) { @@ -494,7 +494,7 @@ static void CO_PDO_receive(void *object, void *msg) { (void)memcpy(RPDO->CANrxData[bufNo], data,sizeof(RPDO->CANrxData[bufNo])); CO_FLAG_SET(RPDO->CANrxNew[bufNo]); -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles * the RPDO. */ if (RPDO->pFunctSignalPre != NULL) { @@ -512,7 +512,7 @@ static void CO_PDO_receive(void *object, void *msg) { } -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "RPDO communication parameter" * @@ -574,7 +574,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, else { PDO->valid = false; CO_FLAG_CLEAR(RPDO->CANrxNew[0]); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 CO_FLAG_CLEAR(RPDO->CANrxNew[1]); #endif if (ret != CO_ERROR_NO) { @@ -587,7 +587,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { @@ -609,7 +609,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, break; } -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 case 5: { /* event-timer */ uint32_t eventTime = CO_getUint16(buf); RPDO->timeoutTime_us = eventTime * 1000U; @@ -632,7 +632,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, OD_t *OD, CO_EM_t *em, -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 CO_SYNC_t *SYNC, #endif uint16_t preDefinedCanId, @@ -720,7 +720,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, /* Configure communication parameter - transmission type */ -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 uint8_t transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; odRet = OD_get_u8(OD_14xx_RPDOCommPar, 2, &transmissionType, true); if (odRet != ODR_OK) { @@ -736,7 +736,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, /* Configure communication parameter - event-timer (optional) */ -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 uint16_t eventTime = 0; odRet = OD_get_u16(OD_14xx_RPDOCommPar, 5, &eventTime, true); RPDO->timeoutTime_us = (uint32_t)eventTime * 1000U; @@ -744,7 +744,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, /* Configure OD extensions */ -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 PDO->isRPDO = true; PDO->OD = OD; PDO->CANdevIdx = CANdevRxIdx; @@ -764,7 +764,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, } -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, void *object, void (*pFunctSignalPre)(void *object)) @@ -779,7 +779,7 @@ void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, /******************************************************************************/ void CO_RPDO_process(CO_RPDO_t *RPDO, -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 uint32_t timeDifference_us, uint32_t *timerNext_us, #endif @@ -790,7 +790,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, CO_PDO_common_t *PDO = &RPDO->PDO_common; if (PDO->valid && NMTisOperational -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 && (syncWas || !RPDO->synchronous) #endif ) { @@ -807,7 +807,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* Determine, which of the two rx buffers contains relevant message. */ uint8_t bufNo = 0; -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if (RPDO->synchronous && (RPDO->SYNC != NULL) && !RPDO->SYNC->CANrxToggle) { bufNo = 1; @@ -824,7 +824,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, * by receive thread, then copy the latest data again. */ CO_FLAG_CLEAR(RPDO->CANrxNew[bufNo]); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { OD_IO_t *OD_IO = &PDO->OD_IO[i]; @@ -884,7 +884,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* verify RPDO timeout */ (void) rpdoReceived; -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 if (RPDO->timeoutTime_us > 0U) { if (rpdoReceived) { if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { @@ -905,7 +905,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, } } else { /* MISRA C 2004 14.10 */ } - #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT + #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL && RPDO->timeoutTimer < RPDO->timeoutTime_us ) { @@ -920,17 +920,17 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, } /* if (PDO->valid && NMTisOperational) */ else { /* not valid and operational, clear CAN receive flags and timeoutTimer*/ -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if (!PDO->valid || !NMTisOperational) { CO_FLAG_CLEAR(RPDO->CANrxNew[0]); CO_FLAG_CLEAR(RPDO->CANrxNew[1]); - #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 RPDO->timeoutTimer = 0; #endif } #else CO_FLAG_CLEAR(RPDO->CANrxNew[0]); - #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE + #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 RPDO->timeoutTimer = 0; #endif #endif @@ -942,8 +942,8 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /******************************************************************************* * T P D O ******************************************************************************/ -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "TPDO communication parameter" * @@ -1011,7 +1011,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { @@ -1027,13 +1027,13 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, #endif TPDO->transmissionType = transmissionType; TPDO->sendRequest = true; -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->inhibitTimer = TPDO->eventTimer = 0; #endif break; } -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 case 3: { /* inhibit time */ if (PDO->valid) { return ODR_INVALID_VALUE; @@ -1052,7 +1052,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, } #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 case 6: { /* SYNC start value */ uint8_t syncStartValue = CO_getUint8(buf); @@ -1078,7 +1078,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, OD_t *OD, CO_EM_t *em, -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 CO_SYNC_t *SYNC, #endif uint16_t preDefinedCanId, @@ -1128,7 +1128,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, return CO_ERROR_OD_PARAMETERS; } if ((transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 && (transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) #endif ) { @@ -1184,7 +1184,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, /* Configure communication parameter - inhibit time and event-timer (opt) */ -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 uint16_t inhibitTime = 0; uint16_t eventTime = 0; odRet = OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); @@ -1195,7 +1195,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, /* Configure communication parameter - SYNC start value (optional) */ -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncStartValue = 0; odRet = OD_get_u8(OD_18xx_TPDOCommPar, 6, &TPDO->syncStartValue, true); TPDO->SYNC = SYNC; @@ -1204,7 +1204,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, /* Configure OD extensions */ -#if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 PDO->isRPDO = false; PDO->OD = OD; PDO->CANdevIdx = CANdevTxIdx; @@ -1243,7 +1243,7 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)); #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { OD_IO_t *OD_IO = &PDO->OD_IO[i]; OD_stream_t *stream = &OD_IO->stream; @@ -1317,7 +1317,7 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { #endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ TPDO->sendRequest = false; -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->eventTimer = TPDO->eventTime_us; TPDO->inhibitTimer = TPDO->inhibitTime_us; #endif @@ -1327,7 +1327,7 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { /******************************************************************************/ void CO_TPDO_process(CO_TPDO_t *TPDO, -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN uint32_t timeDifference_us, uint32_t *timerNext_us, #endif @@ -1335,7 +1335,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, bool_t syncWas) { CO_PDO_common_t *PDO = &TPDO->PDO_common; -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE)) != 0 (void) timerNext_us; #endif (void) syncWas; @@ -1343,19 +1343,19 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, if (PDO->valid && NMTisOperational) { /* check for event timer or application event */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || (OD_FLAGS_PDO_SIZE > 0) +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || (OD_FLAGS_PDO_SIZE > 0) if ((TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) ) { /* event timer */ - #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE + #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 if (TPDO->eventTime_us != 0U) { TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) ? (TPDO->eventTimer - timeDifference_us) : 0U; if (TPDO->eventTimer == 0U) { TPDO->sendRequest = true; } - #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT + #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL && *timerNext_us > TPDO->eventTimer) { /* Schedule for next event time */ *timerNext_us = TPDO->eventTimer; @@ -1383,7 +1383,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, /* Send PDO by application request or by Event timer */ if (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) : 0U; @@ -1392,7 +1392,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, CO_TPDOsend(TPDO); } - #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT + #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (TPDO->sendRequest && timerNext_us != NULL && *timerNext_us > TPDO->inhibitTimer ) { @@ -1408,7 +1408,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, } /* if (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) */ /* Synchronous PDOs */ -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 else if ((TPDO->SYNC != NULL) && syncWas) { /* send synchronous acyclic TPDO */ if (TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { @@ -1452,10 +1452,10 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, else { /* Not operational or valid, reset triggers */ TPDO->sendRequest = true; -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->inhibitTimer = TPDO->eventTimer = 0; #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncCounter = 255; #endif } diff --git a/301/CO_PDO.h b/301/CO_PDO.h index ee8dca32..4290885e 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -43,7 +43,7 @@ CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#if ((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -197,7 +197,7 @@ typedef struct { CO_PDO_size_t dataLength; /** Number of mapped objects in PDO */ uint8_t mappedObjectsCount; -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0) || defined CO_DOXYGEN /** Object dictionary interface for all mapped entries. OD_IO.dataOffset has * special usage with PDO. It stores information about mappedLength of * the variable. mappedLength can be less or equal to the OD_IO.dataLength. @@ -219,7 +219,7 @@ typedef struct { uint8_t flagPDObitmask[CO_PDO_MAX_SIZE]; #endif #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** True for RPDO, false for TPDO */ bool_t isRPDO; /** From CO_xPDO_init() */ @@ -241,11 +241,11 @@ typedef struct { /******************************************************************************* * R P D O ******************************************************************************/ -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN /** * Number of buffers for received CAN message for RPDO */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN #define CO_RPDO_CAN_BUFFERS_COUNT 2 #else #define CO_RPDO_CAN_BUFFERS_COUNT 1 @@ -264,20 +264,20 @@ typedef struct { uint8_t CANrxData[CO_RPDO_CAN_BUFFERS_COUNT][CO_PDO_MAX_SIZE]; /** Indication of RPDO length errors, use with CO_PDO_receiveErrors_t */ uint8_t receiveError; -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN /** From CO_RPDO_init() */ CO_SYNC_t *SYNC; /** True if transmissionType <= 240 */ bool_t synchronous; #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN /** Maximum timeout time between received PDOs in microseconds. Configurable * by OD variable RPDO communication parameter, event-timer. */ uint32_t timeoutTime_us; /** Timeout timer variable in microseconds */ uint32_t timeoutTimer; #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_RPDO_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void *object); /** From CO_RPDO_initCallbackPre() or NULL */ @@ -312,7 +312,7 @@ typedef struct { CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, OD_t *OD, CO_EM_t *em, -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN CO_SYNC_t *SYNC, #endif uint16_t preDefinedCanId, @@ -323,7 +323,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, uint32_t *errInfo); -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize RPDO callback function. * @@ -357,7 +357,7 @@ void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, * transmitted. */ void CO_RPDO_process(CO_RPDO_t *RPDO, -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN uint32_t timeDifference_us, uint32_t *timerNext_us, #endif @@ -369,7 +369,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /******************************************************************************* * T P D O ******************************************************************************/ -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN /** * TPDO object. */ @@ -383,7 +383,7 @@ typedef struct { /** If this flag is set and TPDO is event driven (transmission type is 0, * 254 or 255), then PDO will be sent by CO_TPDO_process(). */ bool_t sendRequest; -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN /** From CO_TPDO_init() */ CO_SYNC_t *SYNC; /** Copy of the variable from object dictionary */ @@ -391,7 +391,7 @@ typedef struct { /** SYNC counter used for PDO sending */ uint8_t syncCounter; #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN /** Inhibit time from object dictionary translated to microseconds */ uint32_t inhibitTime_us; /** Event time from object dictionary translated to microseconds */ @@ -430,7 +430,7 @@ typedef struct { CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, OD_t *OD, CO_EM_t *em, -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN CO_SYNC_t *SYNC, #endif uint16_t preDefinedCanId, @@ -469,7 +469,7 @@ static inline void CO_TPDOsendRequest(CO_TPDO_t *TPDO) { * transmitted. */ void CO_TPDO_process(CO_TPDO_t *TPDO, -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN uint32_t timeDifference_us, uint32_t *timerNext_us, #endif diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 8b2e6849..2f980afe 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -26,23 +26,23 @@ #include "301/CO_SDOclient.h" -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 /* verify configuration */ #if CO_CONFIG_SDO_CLI_BUFFER_SIZE < 7 #error CO_CONFIG_SDO_CLI_BUFFER_SIZE must be set to 7 or more. #endif -#if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) == 0 #error CO_CONFIG_FIFO_ENABLE must be enabled. #endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK - #if !((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 + #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 #error CO_CONFIG_SDO_CLI_SEGMENTED must be enabled. #endif - #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) + #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) == 0 #error CO_CONFIG_FIFO_ALT_READ must be enabled. #endif - #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) + #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) == 0 #error CO_CONFIG_FIFO_CRC16_CCITT must be enabled. #endif #endif @@ -70,7 +70,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { if ((SDO_C->state != CO_SDO_ST_IDLE) && (DLC == 8U) && (!CO_FLAG_READ(SDO_C->CANrxNew) || (data[0] == 0x80U)) ) { -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 if ((data[0] == 0x80U) /* abort from server */ || ((SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) && (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP)) @@ -79,7 +79,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { /* copy data and set 'new message' flag */ (void)memcpy((void *)&SDO_C->CANrxData[0], (const void *)&data[0], 8); CO_FLAG_SET(SDO_C->CANrxNew); -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles * SDO client processing. */ if (SDO_C->pFunctSignal != NULL) { @@ -87,7 +87,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { } #endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 } else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { /* block upload, copy data directly */ @@ -153,7 +153,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { * barrier here with CO_FLAG_CLEAR() call. */ CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->state = state; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles * SDO client processing. */ if (SDO_C->pFunctSignal != NULL) { @@ -167,7 +167,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object _SDO client parameter_ * @@ -267,7 +267,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, } /* Configure object variables */ -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 SDO_C->OD = OD; SDO_C->nodeId = nodeId; #endif @@ -275,7 +275,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, SDO_C->CANdevRxIdx = CANdevRxIdx; SDO_C->CANdevTx = CANdevTx; SDO_C->CANdevTxIdx = CANdevTxIdx; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 SDO_C->pFunctSignal = NULL; SDO_C->functSignalObject = NULL; #endif @@ -299,7 +299,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, return CO_ERROR_OD_PARAMETERS; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SDO_C->OD_1280_extension.object = SDO_C; SDO_C->OD_1280_extension.read = OD_readOriginal; SDO_C->OD_1280_extension.write = OD_write_1280; @@ -328,7 +328,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /******************************************************************************/ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, void *object, @@ -341,7 +341,7 @@ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, } #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) && defined CO_BIG_ENDIAN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0) && defined CO_BIG_ENDIAN static inline void reverseBytes(void *start, OD_size_t size) { uint8_t *lo = (uint8_t *)start; uint8_t *hi = (uint8_t *)start + size - 1; @@ -371,7 +371,7 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->nodeIDOfTheSDOServer = nodeIDOfTheSDOServer; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* proceed only, if parameters change */ if ((COB_IDClientToServer == SDO_C->COB_IDClientToServer) && (COB_IDServerToClient == SDO_C->COB_IDServerToClient) @@ -451,7 +451,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, SDO_C->timeoutTimer = 0; CO_fifo_reset(&SDO_C->bufFifo); -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ if ((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U) @@ -462,7 +462,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, } else #endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 if (blockEnable && ((sizeIndicated == 0U) || (sizeIndicated > CO_CONFIG_SDO_CLI_PST)) ) { @@ -485,7 +485,7 @@ void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, { if (SDO_C != NULL) { SDO_C->sizeInd = sizeIndicated; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ) && (sizeIndicated > 0U) && (sizeIndicated <= CO_CONFIG_SDO_CLI_PST) ) { @@ -530,7 +530,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else if (SDO_C->state == CO_SDO_ST_IDLE) { ret = CO_SDO_RT_ok_communicationEnd; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 /* Transfer data locally **************************************************/ else if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) && !abort) { /* search object dictionary in first pass */ @@ -661,7 +661,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (ret != CO_SDO_RT_waitingLocalTransfer) { SDO_C->state = CO_SDO_ST_IDLE; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Inform OS to call this function again without delay. */ else if (timerNext_us != NULL) { *timerNext_us = 0; @@ -699,7 +699,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 if (SDO_C->finished) { /* expedited transfer */ SDO_C->state = CO_SDO_ST_IDLE; @@ -723,7 +723,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { if ((SDO_C->CANrxData[0] & 0xEFU) == 0x20U) { /* verify and alternate toggle bit */ @@ -752,7 +752,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { if ((SDO_C->CANrxData[0] & 0xFBU) == 0xA0U) { /* verify index and subindex */ @@ -862,7 +862,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, abortCode = CO_SDO_AB_TIMEOUT; SDO_C->state = CO_SDO_ST_ABORT; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; @@ -917,7 +917,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->finished = true; } else { -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 /* segmented transfer, indicate data size */ if (SDO_C->sizeInd > 0U) { uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); @@ -939,7 +939,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { /* fill data bytes */ count = CO_fifo_read(&SDO_C->bufFifo, @@ -977,7 +977,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { SDO_C->CANtxBuff->data[0] = 0xC4; SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; @@ -1034,7 +1034,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else if (SDO_C->block_seqno >= SDO_C->block_blksize) { SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else { /* Inform OS to call this function again without delay. */ if (timerNext_us != NULL) { @@ -1081,7 +1081,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { ret = CO_SDO_RT_blockDownldInProgress; } @@ -1122,11 +1122,11 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, CO_fifo_reset(&SDO_C->bufFifo); SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000U; SDO_C->timeoutTimer = 0; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 SDO_C->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700U; #endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ if (((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U)) @@ -1137,7 +1137,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, } else #endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 if (blockEnable) { SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ; } @@ -1174,7 +1174,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, else if (SDO_C->state == CO_SDO_ST_IDLE) { ret = CO_SDO_RT_ok_communicationEnd; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) /* Transfer data locally **************************************************/ else if ((SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) && !abort) { /* search object dictionary in first pass */ @@ -1276,7 +1276,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ) { SDO_C->state = CO_SDO_ST_IDLE; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Inform OS to call this function again without delay. */ else if (timerNext_us != NULL) { *timerNext_us = 0; @@ -1330,7 +1330,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ret = CO_SDO_RT_ok_communicationEnd; } else { -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 /* segmented transfer, is size indicated? */ if (SDO_C->CANrxData[0] & 0x01U) { uint32_t size; @@ -1352,7 +1352,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { if ((SDO_C->CANrxData[0] & 0xE0U) == 0x00U) { size_t count, countWr; @@ -1414,7 +1414,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { if ((SDO_C->CANrxData[0] & 0xF9U) == 0xC0U) { uint16_t index; @@ -1570,7 +1570,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } SDO_C->state = CO_SDO_ST_ABORT; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; @@ -1580,7 +1580,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 /* Timeout for sub-block reception */ if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { if (SDO_C->block_timeoutTimer < SDO_C->block_SDOtimeoutTime_us) { @@ -1592,7 +1592,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; CO_FLAG_CLEAR(SDO_C->CANrxNew); } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO_C->block_SDOtimeoutTime_us - @@ -1612,7 +1612,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* Transmit CAN data ******************************************************/ if (ret == CO_SDO_RT_waitingResponse) { -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 size_t count; #endif (void)memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); @@ -1631,7 +1631,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { /* verify, if there is enough space in data buffer */ if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7U) { @@ -1648,7 +1648,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { SDO_C->CANtxBuff->data[0] = 0xA4; SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; @@ -1729,7 +1729,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, CO_DEBUG_SDO_CLIENT(msg); } #endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Inform OS to call this function again without delay. */ if (timerNext_us != NULL) { *timerNext_us = 0; @@ -1792,7 +1792,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { ret = CO_SDO_RT_blockUploadInProgress; } diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 794ac0ac..8e56fed9 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -37,14 +37,14 @@ #define CO_CONFIG_SDO_CLI (0) #endif #ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE - #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK + #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 #else #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 #endif #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -174,7 +174,7 @@ CO_SDO_abortCode_t write_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, * SDO client object */ typedef struct { -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0) || defined CO_DOXYGEN /** From CO_SDOclient_init() */ OD_t *OD; /** From CO_SDOclient_init() */ @@ -192,7 +192,7 @@ typedef struct { uint16_t CANdevTxIdx; /** CAN transmit buffer inside CANdevTx for CAN tx message */ CO_CANtx_t *CANtxBuff; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** Copy of CANopen COB_ID Client -> Server, meaning of the specific bits: - Bit 0...10: 11-bit CAN identifier. - Bit 11..30: reserved, must be 0. @@ -234,17 +234,17 @@ typedef struct { volatile void *CANrxNew; /** 8 data bytes of the received message */ uint8_t CANrxData[8]; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_SDOclient_initCallbackPre() or NULL */ void (*pFunctSignal)(void *object); /** From CO_SDOclient_initCallbackPre() or NULL */ void *functSignalObject; #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0) || defined CO_DOXYGEN /** Toggle bit toggled in each segment in segmented transfer */ uint8_t toggle; #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0) || defined CO_DOXYGEN /** Timeout time for SDO sub-block upload, half of #SDOtimeoutTime_us */ uint32_t block_SDOtimeoutTime_us; /** Timeout timer for SDO sub-block upload */ @@ -297,7 +297,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, uint32_t *errInfo); -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize SDOclient callback function. * diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 6c29b77e..3074ec93 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -29,16 +29,16 @@ #include "301/crc16-ccitt.h" /* verify configuration */ -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 20 #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 20. #endif #endif -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK - #if !((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 + #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) == 0 #error CO_CONFIG_SDO_SRV_SEGMENTED must be enabled. #endif - #if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) + #if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) == 0 #error CO_CONFIG_CRC16_ENABLE must be enabled. #endif #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 900 @@ -67,7 +67,7 @@ static void CO_SDO_receive(void *object, void *msg) { else if (CO_FLAG_READ(SDO->CANrxNew)) { /* ignore message if previous message was not processed yet */ } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 else if (SDO->state == CO_SDO_ST_UPLOAD_BLK_END_CRSP && data[0]==0xA1) { /* SDO block download successfully transferred, just make idle */ SDO->state = CO_SDO_ST_IDLE; @@ -132,7 +132,7 @@ static void CO_SDO_receive(void *object, void *msg) { * CO_FLAG_CLEAR() call. */ CO_FLAG_CLEAR(SDO->CANrxNew); SDO->state = state; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which * handles SDO server processing. */ if (SDO->pFunctSignalPre != NULL) { @@ -151,7 +151,7 @@ static void CO_SDO_receive(void *object, void *msg) { * CO_SDOserver_process() */ (void)memcpy(SDO->CANrxData, data, DLC); CO_FLAG_SET(SDO->CANrxNew); -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles * SDO server processing. */ if (SDO->pFunctSignalPre != NULL) { @@ -171,7 +171,7 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, uint32_t COB_IDClientToServer, uint32_t COB_IDServerToClient) { -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* proceed only, if parameters change */ if ((COB_IDClientToServer == SDO->COB_IDClientToServer) && (COB_IDServerToClient == SDO->COB_IDServerToClient) @@ -225,7 +225,7 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object _SDO server parameter_, additional * channels @@ -332,15 +332,15 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, /* Configure object variables */ SDO->OD = OD; SDO->nodeId = nodeId; -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) +#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED)) != 0 SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000U; #endif -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700; #endif SDO->state = CO_SDO_ST_IDLE; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 SDO->pFunctSignalPre = NULL; SDO->functSignalObjectPre = NULL; #endif @@ -399,7 +399,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CanId_ServerToClient = ((COB_IDServerToClient32 & 0x80000000U) == 0U) ? (uint16_t)(COB_IDServerToClient32 & 0x7FFU) : 0U; - #if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC + #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SDO->OD_1200_extension.object = SDO; SDO->OD_1200_extension.read = OD_readOriginal; SDO->OD_1200_extension.write = OD_write_1201_additional; @@ -418,7 +418,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CO_FLAG_CLEAR(SDO->CANrxNew); /* store the parameters and configure CANrx and CANtx */ -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SDO->CANdevRx = CANdevRx; SDO->CANdevRxIdx = CANdevRxIdx; SDO->CANdevTxIdx = CANdevTxIdx; @@ -437,7 +437,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /******************************************************************************/ void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, void *object, @@ -464,7 +464,7 @@ static inline void reverseBytes(void *start, OD_size_t size) { #endif -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /** Helper function for writing data to Object dictionary. Function swaps data * if necessary, calcualtes (and verifies CRC) writes data to OD and verifies * data lengths. @@ -539,7 +539,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, } } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* calculate crc on current data */ if (SDO->block_crcEnabled && crcOperation > 0) { SDO->block_crc = crc16_ccitt(SDO->buf, bufOffsetWrOrig, SDO->block_crc); @@ -671,7 +671,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, } #endif -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* update the crc */ if (calculateCrc && SDO->block_crcEnabled) { SDO->block_crc = crc16_ccitt(bufShifted, countRd, SDO->block_crc); @@ -724,7 +724,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, upload = true; SDO->state = CO_SDO_ST_UPLOAD_INITIATE_REQ; } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 else if ((SDO->CANrxData[0] & 0xF9) == 0xC0) { SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ; } @@ -772,7 +772,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /* load data from object dictionary, if upload and no error */ if (upload && (abortCode == CO_SDO_AB_NONE)) { SDO->bufOffsetRd = SDO->bufOffsetWr = 0; @@ -872,13 +872,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } else { SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 SDO->finished = true; #endif } } else { -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /* segmented transfer, is size indicated? */ if (SDO->CANrxData[0] & 0x01U) { uint32_t size; @@ -918,7 +918,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { if ((SDO->CANrxData[0] & 0xE0U) == 0x00U) { SDO->finished = (SDO->CANrxData[0] & 0x01U) != 0U; @@ -970,7 +970,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { if ((SDO->CANrxData[0] & 0xEFU) == 0x60U) { /* verify and alternate toggle bit */ @@ -990,7 +990,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { SDO->block_crcEnabled = (SDO->CANrxData[0] & 0x04) != 0; @@ -1168,7 +1168,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } } /* switch (SDO->state) */ } /* if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) */ -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 SDO->timeoutTimer = 0; #endif timeDifference_us = 0; @@ -1177,7 +1177,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, else { /* MISRA C 2004 14.10 */ } /* Timeout timers and transmit bufferFull flag ****************************/ -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 if (ret == CO_SDO_RT_waitingResponse) { if (SDO->timeoutTimer < SDO->SDOtimeoutTime_us) { SDO->timeoutTimer += timeDifference_us; @@ -1186,7 +1186,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_TIMEOUT; SDO->state = CO_SDO_ST_ABORT; } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO->SDOtimeoutTime_us - SDO->timeoutTimer; @@ -1196,7 +1196,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } #endif -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* Timeout for sub-block transmission */ if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { if (SDO->block_timeoutTimer < SDO->block_SDOtimeoutTime_us) { @@ -1208,7 +1208,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; CO_FLAG_CLEAR(SDO->CANrxNew); } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO->block_SDOtimeoutTime_us - @@ -1240,11 +1240,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[3] = SDO->subIndex; /* reset timeout timer and send message */ -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 SDO->timeoutTimer = 0; #endif CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 if (SDO->finished) { SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; @@ -1263,7 +1263,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { SDO->CANtxBuff->data[0] = 0x20U | SDO->toggle; SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; @@ -1283,7 +1283,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #endif case CO_SDO_ST_UPLOAD_INITIATE_RSP: { -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /* data were already loaded from OD variable */ if ((SDO->sizeInd > 0U) && (SDO->sizeInd <= 4U)) { /* expedited transfer */ @@ -1351,7 +1351,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { /* refill the data buffer if necessary */ if (!readFromOd(SDO, &abortCode, 7, false)) { @@ -1406,7 +1406,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { SDO->CANtxBuff->data[0] = 0xA4; SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; @@ -1564,7 +1564,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, ) { SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else { /* Inform OS to call this function again without delay. */ if (timerNext_us != NULL) { @@ -1611,7 +1611,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; } -#if (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { ret = CO_SDO_RT_blockDownldInProgress; } diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index fc5a6817..29d6b51b 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -463,7 +463,7 @@ typedef struct { volatile void *CANrxNew; /** 8 data bytes of the received message */ uint8_t CANrxData[8]; -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** From CO_SDOserver_init() */ CO_CANmodule_t *CANdevRx; /** From CO_SDOserver_init() */ @@ -480,7 +480,7 @@ typedef struct { /** Extension for OD object */ OD_extension_t OD_1200_extension; #endif -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0) || defined CO_DOXYGEN /** Size of data, which will be transferred. It is optionally indicated by * client in case of download or by server in case of upload. */ OD_size_t sizeInd; @@ -502,7 +502,7 @@ typedef struct { /** Offset of first data available for read in the buffer */ OD_size_t bufOffsetRd; #endif -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0) || defined CO_DOXYGEN /** Timeout time for SDO sub-block download, half of #SDOtimeoutTime_us */ uint32_t block_SDOtimeoutTime_us; /** Timeout timer for SDO sub-block download */ @@ -518,7 +518,7 @@ typedef struct { /** Calculated CRC checksum */ uint16_t block_crc; #endif -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_SDOserver_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void *object); /** From CO_SDOserver_initCallbackPre() or NULL */ @@ -561,7 +561,7 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, uint32_t *errInfo); -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize SDOrx callback function. * diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 3b77cd41..6841dba8 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -25,7 +25,7 @@ #include "301/CO_SYNC.h" -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 /* * Read received message from CAN module. @@ -64,7 +64,7 @@ static void CO_SYNC_receive(void *object, void *msg) { CO_FLAG_SET(SYNC->CANrxNew); -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles SYNC.*/ if (SYNC->pFunctSignalPre != NULL) { SYNC->pFunctSignalPre(SYNC->functSignalObjectPre); @@ -74,7 +74,7 @@ static void CO_SYNC_receive(void *object, void *msg) { } -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "COB-ID sync message" * @@ -94,7 +94,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, uint16_t CAN_ID = (uint16_t)(cobIdSync & 0x7FFU); /* verify written value */ -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 bool_t isProducer = (cobIdSync & 0x40000000) != 0; if ((cobIdSync & 0xBFFFF800) != 0 || CO_IS_RESTRICTED_CAN_ID(CAN_ID) || (SYNC->isProducer && isProducer && CAN_ID != SYNC->CAN_ID) @@ -122,7 +122,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, return ODR_DEV_INCOMPAT; } -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->CANtxBuff = CO_CANtxBufferInit( SYNC->CANdevTx, /* CAN device */ SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ @@ -140,7 +140,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, SYNC->CAN_ID = CAN_ID; } -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->isProducer = isProducer; if (isProducer) { SYNC->counter = 0; @@ -152,7 +152,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, return OD_writeOriginal(stream, buf, count, countWritten); } -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 /* * Custom function for writing OD object "Synchronous counter overflow value" * @@ -210,7 +210,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, OD_entry_t *OD_1019_syncCounterOvf, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, #endif @@ -220,7 +220,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, /* verify arguments */ if ((SYNC == NULL) || (em == NULL) || (OD_1005_cobIdSync == NULL) -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 || (OD_1006_commCyclePeriod == NULL) || (CANdevTx == NULL) #endif || (CANdevRx == NULL) @@ -239,7 +239,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1005_cobIdSync); } return CO_ERROR_OD_PARAMETERS; } -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SYNC->OD_1005_extension.object = SYNC; SYNC->OD_1005_extension.read = OD_readOriginal; SYNC->OD_1005_extension.write = OD_write_1005; @@ -249,7 +249,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, /* get and verify "Communication cycle period" from OD */ SYNC->OD_1006_period = OD_getPtr(OD_1006_commCyclePeriod, 0, sizeof(uint32_t), NULL); -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 if (SYNC->OD_1006_period == NULL) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1006_commCyclePeriod); @@ -291,8 +291,8 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, else if (syncCounterOvf > 240U) { syncCounterOvf = 240; } else { /* MISRA C 2004 14.10 */ } -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->OD_1019_extension.object = SYNC; SYNC->OD_1019_extension.read = OD_readOriginal; SYNC->OD_1019_extension.write = OD_write_1019; @@ -304,14 +304,14 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, /* Configure object variables */ SYNC->em = em; -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->isProducer = (cobIdSync & 0x40000000U) != 0U; #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SYNC->CAN_ID = cobIdSync & 0x7FFU; SYNC->CANdevRx = CANdevRx; SYNC->CANdevRxIdx = CANdevRxIdx; - #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->CANdevTx = CANdevTx; SYNC->CANdevTxIdx = CANdevTxIdx; #endif @@ -330,7 +330,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, return ret; } -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->CANtxBuff = CO_CANtxBufferInit( CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ @@ -348,7 +348,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, } -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /******************************************************************************/ void CO_SYNC_initCallbackPre( CO_SYNC_t *SYNC, @@ -389,13 +389,13 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, ? *SYNC->OD_1006_period : 0U; if (OD_1006_period > 0U) { -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 if (SYNC->isProducer) { if (SYNC->timer >= OD_1006_period) { syncStatus = CO_SYNC_RX_TX; CO_SYNCsend(SYNC); } - #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT + #if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate when next SYNC needs to be sent */ if (timerNext_us != NULL) { uint32_t diff = OD_1006_period - SYNC->timer; @@ -421,7 +421,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, CO_EMC_COMMUNICATION, SYNC->timer); SYNC->timeoutError = 2; } -#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { uint32_t diff = periodTimeout - SYNC->timer; if (*timerNext_us > diff) { diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index d78bd86b..ac5a464b 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -40,7 +40,7 @@ CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -106,7 +106,7 @@ typedef struct { /** Pointer to variable in OD, "Synchronous window length" in microseconds*/ uint32_t *OD_1007_window; -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN /** True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ variable from Object dictionary (index 0x1005). */ bool_t isProducer; @@ -124,7 +124,7 @@ typedef struct { /** CAN ID of the SYNC message. Calculated from _COB ID SYNC Message_ variable from Object dictionary (index 0x1005). */ uint16_t CAN_ID; - #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) || defined CO_DOXYGEN + #if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN /** From CO_SYNC_init() */ CO_CANmodule_t *CANdevTx; /** From CO_SYNC_init() */ @@ -134,7 +134,7 @@ typedef struct { #endif #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_SYNC_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void *object); /** From CO_SYNC_initCallbackPre() or NULL */ @@ -185,14 +185,14 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, OD_entry_t *OD_1019_syncCounterOvf, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, #endif uint32_t *errInfo); -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize SYNC callback function. * @@ -210,7 +210,7 @@ void CO_SYNC_initCallbackPre(CO_SYNC_t *SYNC, #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN /** * Send SYNC message. * diff --git a/301/CO_TIME.c b/301/CO_TIME.c index c8530342..55029d02 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -27,7 +27,7 @@ #include "301/CO_TIME.h" -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 /* * Read received message from CAN module. @@ -45,7 +45,7 @@ static void CO_TIME_receive(void *object, void *msg) { (void)memcpy(TIME->timeStamp, data, sizeof(TIME->timeStamp)); CO_FLAG_SET(TIME->CANrxNew); -#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles TIME.*/ if (TIME->pFunctSignalPre != NULL) { TIME->pFunctSignalPre(TIME->functSignalObjectPre); @@ -55,7 +55,7 @@ static void CO_TIME_receive(void *object, void *msg) { } -#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "COB-ID time stamp" * @@ -93,7 +93,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, OD_entry_t *OD_1012_cobIdTimeStamp, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, #endif @@ -101,7 +101,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, { /* verify arguments */ if ((TIME == NULL) || (OD_1012_cobIdTimeStamp == NULL) || (CANdevRx == NULL) -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 || CANdevTx == NULL #endif ) { @@ -117,7 +117,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1012_cobIdTimeStamp); } return CO_ERROR_OD_PARAMETERS; } -#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC +#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 TIME->OD_1012_extension.object = TIME; TIME->OD_1012_extension.read = OD_readOriginal; TIME->OD_1012_extension.write = OD_write_1012; @@ -145,7 +145,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, } } -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 /* configure TIME producer message transmission */ TIME->CANdevTx = CANdevTx; TIME->CANtxBuff = CO_CANtxBufferInit( @@ -165,7 +165,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, } -#if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 void CO_TIME_initCallbackPre(CO_TIME_t *TIME, void *object, void (*pFunctSignalPre)(void *object)) @@ -214,7 +214,7 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, } } -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 if (NMTisPreOrOperational && TIME->isProducer && TIME->producerInterval_ms > 0 ) { diff --git a/301/CO_TIME.h b/301/CO_TIME.h index a97acc70..a0c94a77 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -38,7 +38,7 @@ CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -95,7 +95,7 @@ typedef struct { bool_t isProducer; /** Variable indicates, if new TIME message received from CAN bus */ volatile void *CANrxNew; -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN /** Interval for time producer in milli seconds */ uint32_t producerInterval_ms; /** Sync producer timer */ @@ -105,13 +105,13 @@ typedef struct { /** CAN transmit buffer */ CO_CANtx_t *CANtxBuff; #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_TIME_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void *object); /** From CO_TIME_initCallbackPre() or NULL */ void *functSignalObjectPre; #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** Extension for OD object */ OD_extension_t OD_1012_extension; #endif @@ -138,14 +138,14 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, OD_entry_t *OD_1012_cobIdTimeStamp, CO_CANmodule_t *CANdevRx, uint16_t CANdevRxIdx, -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN CO_CANmodule_t *CANdevTx, uint16_t CANdevTxIdx, #endif uint32_t *errInfo); -#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize TIME callback function. * @@ -182,7 +182,7 @@ static inline void CO_TIME_set(CO_TIME_t *TIME, TIME->residual_us = 0; TIME->ms = ms; TIME->days = days; -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 TIME->producerTimer_ms = TIME->producerInterval_ms =producerInterval_ms; #endif } diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 3d1d2335..2771e691 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -25,14 +25,14 @@ #include "301/CO_fifo.h" -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) != 0 #include #include #include #include "crc16-ccitt.h" -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 #include #include @@ -45,8 +45,8 @@ #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ /* verify configuration */ -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT - #if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) != 0 + #if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) == 0 #error CO_CONFIG_CRC16_ENABLE must be enabled. #endif #endif @@ -104,7 +104,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, *bufDest = *buf; -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) != 0 if (crc != NULL) { crc16_ccitt_single(crc, *buf); } @@ -159,7 +159,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { } i--; -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 /* is delimiter? */ if ((eof != NULL) && (c == DELIM_COMMAND)) { *eof = true; @@ -172,7 +172,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { } -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) != 0 /******************************************************************************/ size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset) { size_t i; @@ -209,7 +209,7 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { else { const uint8_t *bufSrc = &fifo->buf[fifo->readPtr]; while (fifo->readPtr != fifo->altReadPtr) { -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) != 0 crc16_ccitt_single(crc, *bufSrc); #endif /* increment variable */ @@ -254,7 +254,7 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count) { #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ */ -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 /******************************************************************************/ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { bool_t newCommand = false; @@ -465,7 +465,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0 /******************************************************************************/ /* Tables for mime-base64 encoding, as specified in RFC 2045, (without CR-LF, * but one long string). Base64 is used for encoding binary data into easy diff --git a/301/CO_fifo.h b/301/CO_fifo.h index b6f657e7..7b817709 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -33,7 +33,7 @@ #define CO_CONFIG_FIFO (0) #endif -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -68,11 +68,11 @@ typedef struct { size_t writePtr; /** Location in the buffer, which will be next read. */ size_t readPtr; -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) != 0) || defined CO_DOXYGEN /** Location in the buffer, which will be next read. */ size_t altReadPtr; #endif -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0) || defined CO_DOXYGEN /** helper variable, set to false in CO_fifo_reset(), used in some * functions. */ bool_t started; @@ -103,7 +103,7 @@ static inline void CO_fifo_reset(CO_fifo_t *fifo) { if (fifo != NULL) { fifo->readPtr = 0; fifo->writePtr = 0; -#if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0 fifo->started = false; #endif } @@ -267,7 +267,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof); -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) != 0) || defined CO_DOXYGEN /** * Initializes alternate read with #CO_fifo_altRead * @@ -326,7 +326,7 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count); #endif /* #if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ */ -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0) || defined CO_DOXYGEN /** * Search command inside FIFO * @@ -416,7 +416,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0) || defined CO_DOXYGEN /** * Read uint8_t variable from fifo and output as ascii string. * diff --git a/301/crc16-ccitt.c b/301/crc16-ccitt.c index 682f6396..432af134 100644 --- a/301/crc16-ccitt.c +++ b/301/crc16-ccitt.c @@ -25,8 +25,8 @@ #include "301/crc16-ccitt.h" -#if (CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE -#if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_EXTERNAL) +#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) != 0 +#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_EXTERNAL) == 0 /* * CRC table calculated by the following algorithm: diff --git a/301/crc16-ccitt.h b/301/crc16-ccitt.h index 8fe3070f..a61601d8 100644 --- a/301/crc16-ccitt.h +++ b/301/crc16-ccitt.h @@ -34,7 +34,7 @@ #define CO_CONFIG_CRC16 (0) #endif -#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 8cd5be06..9b24f320 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -25,7 +25,7 @@ #include "303/CO_LEDs.h" -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 /******************************************************************************/ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { @@ -142,7 +142,7 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, LEDs->LEDgreen = gr; } /* if (tick) */ -#if (CO_CONFIG_LEDS) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_LEDS) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL) { uint32_t diff = 50000 - LEDs->LEDtmr50ms; if (*timerNext_us > diff) { diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index ba092ce3..ffc8a6dc 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -35,7 +35,7 @@ CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { diff --git a/304/CO_GFC.c b/304/CO_GFC.c index f8e5b2ae..6b2ac520 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -26,7 +26,7 @@ #include "304/CO_GFC.h" -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 /* * Custom function for reading or writing OD object. @@ -52,7 +52,7 @@ OD_write_1300(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* return OD_writeOriginal(stream, buf, count, countWritten); } -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0 static void CO_GFC_receive(void* object, void* msg) { CO_GFC_t* GFC; @@ -98,7 +98,7 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC GFC->OD_gfcParam_ext.write = OD_write_1300; (void)OD_extension_init(OD_1300_gfcParameter, &GFC->OD_gfcParam_ext); -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0 GFC->CANdevTx = GFC_CANdevTx; GFC->CANtxBuff = CO_CANtxBufferInit(GFC->CANdevTx, /* CAN device */ GFC_txIdx, /* index of specific buffer inside CAN module */ @@ -115,7 +115,7 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC (void)CANidTxGFC; /* unused */ #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0 GFC->functSignalObjectSafe = NULL; GFC->pFunctSignalSafe = NULL; const CO_ReturnError_t r = CO_CANrxBufferInit(GFC_CANdevRx, /* CAN device */ @@ -136,7 +136,7 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC return CO_ERROR_NO; } -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0 CO_ReturnError_t CO_GFCsend(CO_GFC_t* GFC) { if (GFC->valid) { diff --git a/304/CO_GFC.h b/304/CO_GFC.h index 677f22ee..f5bdba51 100644 --- a/304/CO_GFC.h +++ b/304/CO_GFC.h @@ -35,7 +35,7 @@ #define CO_CONFIG_GFC (0) #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -60,11 +60,11 @@ extern "C" { typedef struct { bool_t valid; /**< From OD parameter 1300 */ OD_extension_t OD_gfcParam_ext; /**< Extension for OD object */ -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0) || defined CO_DOXYGEN CO_CANmodule_t* CANdevTx; /**< From CO_GFC_init() */ CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0) || defined CO_DOXYGEN /** From CO_GFC_initCallbackEnterSafeState() or NULL */ void (*pFunctSignalSafe)(void* object); /** From CO_GFC_initCallbackEnterSafeState() or NULL */ @@ -93,7 +93,7 @@ CO_ReturnError_t CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC_CANdevRx, uint16_t GFC_rxIdx, uint16_t CANidRxGFC, CO_CANmodule_t* GFC_CANdevTx, uint16_t GFC_txIdx, uint16_t CANidTxGFC); -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0) || defined CO_DOXYGEN /** * Initialize GFC callback function. * @@ -108,7 +108,7 @@ CO_ReturnError_t CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, void CO_GFC_initCallbackEnterSafeState(CO_GFC_t* GFC, void* object, void (*pFunctSignalSafe)(void* object)); #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0) || defined CO_DOXYGEN /** * Send GFC message. * diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 0df39590..7c53c5a6 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -27,12 +27,12 @@ #include "304/CO_SRDO.h" -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 #include "301/crc16-ccitt.h" /* verify configuration */ -#if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) +#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) == 0 #error CO_CONFIG_CRC16_ENABLE must be enabled. #endif @@ -60,7 +60,7 @@ CO_SRDO_receive_normal(void* object, void* msg) { (void)memcpy(SRDO->CANrxData[0], data, sizeof(SRDO->CANrxData[0])); CO_FLAG_SET(SRDO->CANrxNew[0]); -#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles SRDO. */ if (SRDO->pFunctSignalPre != NULL) { SRDO->pFunctSignalPre(SRDO->functSignalObjectPre); @@ -84,7 +84,7 @@ CO_SRDO_receive_inverted(void* object, void* msg) { (void)memcpy(SRDO->CANrxData[1], data, sizeof(SRDO->CANrxData[1])); CO_FLAG_SET(SRDO->CANrxNew[1]); -#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles SRDO. */ if (SRDO->pFunctSignalPre != NULL) { SRDO->pFunctSignalPre(SRDO->functSignalObjectPre); @@ -341,7 +341,7 @@ OD_write_13FF(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* return OD_writeOriginal(stream, buf, count, countWritten); } -#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 void CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalPre)(void* object)) { if (SRDO != NULL) { @@ -828,7 +828,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } else { bool_t data_ok = true; -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX) != 0 /* check data before sending (optional) */ for (uint8_t i = 0; i < SRDO->dataLength; i++) { if ((uint8_t)(~SRDO->CANtxBuff[0]->data[i]) != SRDO->CANtxBuff[1]->data[i]) { @@ -858,7 +858,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } SRDO->nextIsNormal = !SRDO->nextIsNormal; } -#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL) { if (*timerNext_us > SRDO->cycleTimer) { *timerNext_us = SRDO->cycleTimer; /* Schedule for the next message timer */ @@ -980,7 +980,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext else { /* MISRA C 2004 14.10 */ } -#if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT +#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL) { if (*timerNext_us > SRDO->cycleTimer) { *timerNext_us = SRDO->cycleTimer; /* Schedule for the next message timer */ diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index a1bde1c9..36c755b0 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -39,7 +39,7 @@ #define CO_CONFIG_SRDO_MINIMUM_DELAY 0U #endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -185,7 +185,7 @@ typedef struct { OD_extension_t OD_communicationParam_ext; /** Extension for OD object */ OD_extension_t OD_mappingParam_extension; -#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_SRDO_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void* object); /** From CO_SRDO_initCallbackPre() or NULL */ @@ -259,7 +259,7 @@ CO_ReturnError_t CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_ CO_CANmodule_t* CANdevTxNormal, CO_CANmodule_t* CANdevTxInverted, uint16_t CANdevTxIdxNormal, uint16_t CANdevTxIdxInverted, uint32_t* errInfo); -#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize SRDO callback function. * diff --git a/305/CO_LSS.h b/305/CO_LSS.h index 8212c067..1b4dc933 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -35,7 +35,7 @@ CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) #endif -#if ((CO_CONFIG_LSS) & (CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER)) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & (CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER)) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 7331b974..098a2f0f 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -26,7 +26,7 @@ #include "305/CO_LSSmaster.h" -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 #include @@ -91,7 +91,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) CO_FLAG_SET(LSSmaster->CANrxNew); -#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles further processing. */ if(LSSmaster->pFunctSignal != NULL) { LSSmaster->pFunctSignal(LSSmaster->functSignalObject); @@ -147,7 +147,7 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); (void)memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); -#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 LSSmaster->pFunctSignal = NULL; LSSmaster->functSignalObject = NULL; #endif @@ -191,7 +191,7 @@ void CO_LSSmaster_changeTimeout( } -#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /******************************************************************************/ void CO_LSSmaster_initCallbackPre( CO_LSSmaster_t *LSSmaster, diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 09578800..f3af0a54 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -29,7 +29,7 @@ #include "305/CO_LSS.h" -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -117,7 +117,7 @@ typedef struct{ volatile void *CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */ uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN void (*pFunctSignal)(void *object); /**< From CO_LSSmaster_initCallbackPre() or NULL */ void *functSignalObject;/**< Pointer to object */ #endif @@ -185,7 +185,7 @@ void CO_LSSmaster_changeTimeout( uint16_t timeout_ms); -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize LSSmasterRx callback function. * diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 466807bc..385fb2f5 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -27,7 +27,7 @@ #include "305/CO_LSSslave.h" -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 #include @@ -161,7 +161,7 @@ static void CO_LSSslave_receive(void *object, void *msg) } else { /* MISRA C 2004 14.10 */ } if (ack) { -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND) != 0 LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; (void)memset(&LSSslave->TXbuff->data[1], 0, sizeof(LSSslave->TXbuff->data) - 1); @@ -187,7 +187,7 @@ static void CO_LSSslave_receive(void *object, void *msg) if (request_LSSslave_process) { CO_FLAG_SET(LSSslave->sendResponse); -#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, * which handles further processing. */ if (LSSslave->pFunctSignalPre != NULL) { @@ -265,7 +265,7 @@ CO_ReturnError_t CO_LSSslave_init( } -#if (CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE +#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /******************************************************************************/ void CO_LSSslave_initCallbackPre( CO_LSSslave_t *LSSslave, diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index cb3da5d0..09bc669a 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -30,7 +30,7 @@ #include "305/CO_LSS.h" -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -102,7 +102,7 @@ typedef struct{ CO_LSS_cs_t service; /**< Service, which will have to be processed by mainline processing function */ uint8_t CANdata[8]; /**< Received CAN data, which will be processed by mainline processing function */ -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN void (*pFunctSignalPre)(void *object); /**< From CO_LSSslave_initCallbackPre() or NULL */ void *functSignalObjectPre;/**< Pointer to object */ #endif @@ -194,7 +194,7 @@ static inline CO_LSS_state_t CO_LSSslave_getState(CO_LSSslave_t *LSSslave) { } -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize LSSslaveRx callback function. * diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index ee4e5c54..45bc4fce 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -26,7 +26,7 @@ #include "309/CO_gateway_ascii.h" -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 #include #include @@ -35,32 +35,32 @@ #include /* verify configuration */ -#if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) == 0 #error CO_CONFIG_FIFO_ENABLE must be enabled. #endif -#if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) +#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) == 0 #error CO_CONFIG_FIFO_ASCII_COMMANDS must be enabled. #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO - #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 + #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) == 0 #error CO_CONFIG_FIFO_ASCII_DATATYPES must be enabled. #endif #endif /******************************************************************************/ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN CO_SDOclient_t* SDO_C, uint16_t SDOclientTimeoutTime_ms, bool_t SDOclientBlockTransfer, #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN CO_NMT_t *NMT, #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN CO_LSSmaster_t *LSSmaster, #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN CO_LEDs_t *LEDs, #endif uint8_t dummy) @@ -68,16 +68,16 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, (void)dummy; /* verify arguments */ if (gtwa == NULL -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 || SDO_C == NULL || SDOclientTimeoutTime_ms == 0 #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 || NMT == NULL #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 || LSSmaster == NULL #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 || LEDs == NULL #endif ) { @@ -88,18 +88,18 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, (void)memset(gtwa, 0, sizeof(CO_GTWA_t)); /* initialize variables */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 gtwa->SDO_C = SDO_C; gtwa->SDOtimeoutTime = SDOclientTimeoutTime_ms; gtwa->SDOblockTransferEnable = SDOclientBlockTransfer; #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 gtwa->NMT = NMT; #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 gtwa->LSSmaster = LSSmaster; #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 gtwa->LEDs = LEDs; #endif gtwa->net_default = -1; @@ -111,7 +111,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, >wa->commBuf[0], CO_CONFIG_GTWA_COMM_BUF_SIZE + 1); -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 CO_fifo_init(>wa->logFifo, >wa->logBuf[0], CO_CONFIG_GTWA_LOG_BUF_SIZE + 1); @@ -137,7 +137,7 @@ void CO_GTWA_initRead(CO_GTWA_t* gtwa, /******************************************************************************/ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { if ((gtwa != NULL) && (message != NULL)) { const char *c; @@ -153,7 +153,7 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { /******************************************************************************* * HELPER FUNCTIONS ******************************************************************************/ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 /* help strings ("\n" is used between string, "\r\n" closes the response.) */ static const char CO_GTWA_helpString[] = "\nCommand strings start with '\"[\"\"]\"' followed by:\n" \ @@ -224,7 +224,7 @@ static const char CO_GTWA_helpStringLss[] = "* : 0=fastscan, 1=ignore, 2=match value in next parameter\r\n"; #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 #define CO_GTWA_LED_PRINTOUTS_SIZE 5 static const char *CO_GTWA_LED_PRINTOUTS[CO_GTWA_LED_PRINTOUTS_SIZE] = { " CANopen status LEDs: R G \r", @@ -266,7 +266,7 @@ static bool_t checkNetNode(CO_GTWA_t *gtwa, eCode = CO_GTWA_respErrorUnsupportedNode; e = true; } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET) != 0 else if (net == -1) { eCode = CO_GTWA_respErrorNoDefaultNetSet; e = true; @@ -291,7 +291,7 @@ static bool_t checkNetNode(CO_GTWA_t *gtwa, static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, CO_GTWA_respErrorCode_t *errCode) { -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET) != 0 bool_t e = false; CO_GTWA_respErrorCode_t eCode; @@ -321,7 +321,7 @@ static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 /* data types for SDO read or write */ static const CO_GTWA_dataType_t dataTypes[] = { {"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */ @@ -401,7 +401,7 @@ static bool_t respBufTransfer(CO_GTWA_t *gtwa) { } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC) != 0 #ifndef CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS #define CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS typedef struct { @@ -438,7 +438,7 @@ static const errorDescs_t errorDescs[] = { {505, "LSS command failed because of media error."}, {600, "Running out of memory."} }; -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 static const errorDescs_t errorDescsSDO[] = { {0x00000000, "No abort."}, {0x05030000, "Toggle bit not altered."}, @@ -496,7 +496,7 @@ static void responseWithError(CO_GTWA_t *gtwa, respBufTransfer(gtwa); } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 static void responseWithErrorSDO(CO_GTWA_t *gtwa, CO_SDO_abortCode_t abortCode, bool_t postponed) @@ -537,7 +537,7 @@ static inline void responseWithError(CO_GTWA_t *gtwa, respBufTransfer(gtwa); } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, CO_SDO_abortCode_t abortCode, bool_t postponed) @@ -574,7 +574,7 @@ static inline void responseWithEmpty(CO_GTWA_t *gtwa) { } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 static void responseLSS(CO_GTWA_t *gtwa, CO_LSSmaster_return_t lss_ret) { if (lss_ret == CO_LSSmaster_OK) { responseWithOK(gtwa); @@ -804,7 +804,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->node_default = value; responseWithOK(gtwa); } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 /* 'set sdo_timeout ' */ else if (strcmp(tok, "sdo_timeout") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); @@ -853,7 +853,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 /* Upload SDO command - 'r[ead] ' */ else if ((strcmp(tok, "r") == 0) || (strcmp(tok, "read") == 0)) { uint16_t idx; @@ -1011,7 +1011,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 /* NMT start node - 'start' */ else if (strcmp(tok, "start") == 0) { CO_ReturnError_t ret; @@ -1121,7 +1121,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 /* Switch state global command - 'lss_switch_glob <0|1>' */ else if (strcmp(tok, "lss_switch_glob") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); @@ -1463,7 +1463,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 /* Print message log */ else if (strcmp(tok, "log") == 0) { if (closed == 0) { @@ -1474,7 +1474,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 /* Print help */ else if (strcmp(tok, "help") == 0) { if (closed == 1) { @@ -1504,7 +1504,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 /* Print status led diodes */ else if (strcmp(tok, "led") == 0) { if (closed == 0) { @@ -1548,7 +1548,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, return; /* skip timerNext_us calculation */ } -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 /* SDO upload state */ case CO_GTWA_ST_READ: { CO_SDO_abortCode_t abortCode; @@ -1708,7 +1708,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 case CO_GTWA_ST_LSS_SWITCH_GLOB: { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster, @@ -1985,7 +1985,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* CO_GTWA_ST_LSS_ALLNODES */ #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 /* print message log */ case CO_GTWA_ST_LOG: { do { @@ -2003,7 +2003,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 /* Print help string (in multiple segments if necessary) */ case CO_GTWA_ST_HELP: { size_t lenBuf = CO_GTWA_RESP_BUF_SIZE; @@ -2030,7 +2030,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 /* print CANopen status LED diodes */ case CO_GTWA_ST_LED: { uint8_t i; diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 832107b2..c7f77a3d 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -39,7 +39,7 @@ #define CO_CONFIG_GTW (0) #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -263,7 +263,7 @@ typedef enum { } CO_GTWA_state_t; -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN /* * CANopen Gateway-ascii data types structure */ @@ -343,7 +343,7 @@ typedef struct { CO_GTWA_state_t state; /** Timeout timer for the current state */ uint32_t stateTimeoutTmr; -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN /** SDO client object from CO_GTWA_init() */ CO_SDOclient_t *SDO_C; /** Timeout time for SDO transfer in milliseconds, if no response */ @@ -357,11 +357,11 @@ typedef struct { /** Data type of variable in current SDO communication */ const CO_GTWA_dataType_t *SDOdataType; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN /** NMT object from CO_GTWA_init() */ CO_NMT_t *NMT; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN /** LSSmaster object from CO_GTWA_init() */ CO_LSSmaster_t *LSSmaster; /** 128 bit number, uniquely identifying each node */ @@ -383,18 +383,18 @@ typedef struct { /** LSS allnodes timeout parameter */ uint16_t lssTimeout_ms; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0) || defined CO_DOXYGEN /** Message log buffer of usable size @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */ uint8_t logBuf[CO_CONFIG_GTWA_LOG_BUF_SIZE + 1]; /** CO_fifo_t object for message log (not pointer) */ CO_fifo_t logFifo; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0) || defined CO_DOXYGEN /** Offset, when printing help text */ const char *helpString; size_t helpStringOffset; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN /** CO_LEDs_t object for CANopen status LEDs imitation from CO_GTWA_init()*/ CO_LEDs_t *LEDs; uint8_t ledStringPreviousIndex; @@ -417,18 +417,18 @@ typedef struct { * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT */ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN CO_SDOclient_t* SDO_C, uint16_t SDOclientTimeoutTime_ms, bool_t SDOclientBlockTransfer, #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN CO_NMT_t *NMT, #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN CO_LSSmaster_t *LSSmaster, #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN CO_LEDs_t *LEDs, #endif uint8_t dummy); @@ -491,7 +491,7 @@ static inline size_t CO_GTWA_write(CO_GTWA_t* gtwa, } -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0) || defined CO_DOXYGEN /** * Print message log string into fifo buffer * diff --git a/CANopen.c b/CANopen.c index 33523b4b..9ecbd940 100644 --- a/CANopen.c +++ b/CANopen.c @@ -48,7 +48,7 @@ #error OD_CNT_NMT from OD.h not correct! #endif #define CO_RX_CNT_NMT_SLV OD_CNT_NMT -#if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER +#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 #define CO_TX_CNT_NMT_MST 1 #else #define CO_TX_CNT_NMT_MST 0 @@ -63,7 +63,7 @@ #elif OD_CNT_HB_CONS < 0 || OD_CNT_HB_CONS > 1 #error OD_CNT_HB_CONS from OD.h not correct! #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) && OD_CNT_HB_CONS == 1 +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0) && OD_CNT_HB_CONS == 1 #if OD_CNT_ARR_1016 < 1 || OD_CNT_ARR_1016 > 127 #error OD_CNT_ARR_1016 is not defined in Object Dictionary or value is wrong! #endif @@ -72,14 +72,14 @@ #define CO_RX_CNT_HB_CONS 0 #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 #define CO_RX_CNT_NG_SLV 1 #define CO_TX_CNT_NG_SLV 1 #else #define CO_RX_CNT_NG_SLV 0 #define CO_TX_CNT_NG_SLV 0 #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 #define CO_RX_CNT_NG_MST 1 #define CO_TX_CNT_NG_MST 1 #else @@ -96,7 +96,7 @@ #ifndef OD_CNT_ARR_1003 #define OD_CNT_ARR_1003 8 #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 #if OD_CNT_EM_PROD == 1 #define CO_TX_CNT_EM_PROD OD_CNT_EM_PROD #else @@ -108,7 +108,7 @@ #else #define CO_TX_CNT_EM_PROD 0 #endif -#if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 #define CO_RX_CNT_EM_CONS 1 #else #define CO_RX_CNT_EM_CONS 0 @@ -123,7 +123,7 @@ #define CO_RX_CNT_SDO_SRV OD_CNT_SDO_SRV #define CO_TX_CNT_SDO_SRV OD_CNT_SDO_SRV -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 #if !defined OD_CNT_SDO_CLI #define OD_CNT_SDO_CLI 0 #define OD_ENTRY_H1280 NULL @@ -137,7 +137,7 @@ #define CO_TX_CNT_SDO_CLI 0 #endif -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 #if !defined OD_CNT_TIME #define OD_CNT_TIME 0 #define OD_ENTRY_H1012 NULL @@ -145,7 +145,7 @@ #error OD_CNT_TIME from OD.h not correct! #endif #define CO_RX_CNT_TIME OD_CNT_TIME - #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER + #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 #define CO_TX_CNT_TIME OD_CNT_TIME #else #define CO_TX_CNT_TIME 0 @@ -155,7 +155,7 @@ #define CO_TX_CNT_TIME 0 #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 #if !defined OD_CNT_SYNC #define OD_CNT_SYNC 0 #define OD_ENTRY_H1005 NULL @@ -164,7 +164,7 @@ #error OD_CNT_SYNC from OD.h not correct! #endif #define CO_RX_CNT_SYNC OD_CNT_SYNC - #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 #define CO_TX_CNT_SYNC OD_CNT_SYNC #else #define CO_TX_CNT_SYNC 0 @@ -180,7 +180,7 @@ #define CO_TX_CNT_SYNC 0 #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 #if !defined OD_CNT_RPDO #define OD_CNT_RPDO 0 #define OD_ENTRY_H1400 NULL @@ -193,7 +193,7 @@ #define CO_RX_CNT_RPDO 0 #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 #if !defined OD_CNT_TPDO #define OD_CNT_TPDO 0 #define OD_ENTRY_H1800 NULL @@ -206,11 +206,11 @@ #define CO_TX_CNT_TPDO 0 #endif -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 #define OD_CNT_LEDS 1 #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 #if !defined OD_CNT_GFC #define OD_CNT_GFC 0 #define OD_ENTRY_H1300 NULL @@ -224,7 +224,7 @@ #define CO_TX_CNT_GFC 0 #endif -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 #if !defined OD_CNT_SRDO #define OD_CNT_SRDO 0 #define OD_ENTRY_H1301 NULL @@ -241,7 +241,7 @@ #define CO_TX_CNT_SRDO 0 #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 #define OD_CNT_LSS_SLV 1 #else #define OD_CNT_LSS_SLV 0 @@ -249,7 +249,7 @@ #define CO_RX_CNT_LSS_SLV OD_CNT_LSS_SLV #define CO_TX_CNT_LSS_SLV OD_CNT_LSS_SLV -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 #define OD_CNT_LSS_MST 1 #else #define OD_CNT_LSS_MST 0 @@ -257,7 +257,7 @@ #define CO_RX_CNT_LSS_MST OD_CNT_LSS_MST #define CO_TX_CNT_LSS_MST OD_CNT_LSS_MST -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 #define OD_CNT_GTWA 1 #endif @@ -388,13 +388,13 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { if (CO_GET_CNT(NMT) == 1) { CO_alloc_break_on_fail(co->NMT, CO_GET_CNT(NMT), sizeof(*co->NMT)); ON_MULTI_OD(RX_CNT_NMT_SLV = 1); - #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER + #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 ON_MULTI_OD(TX_CNT_NMT_MST = 1); #endif ON_MULTI_OD(TX_CNT_HB_PROD = 1); } -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_HB_CONS = 0); if (CO_GET_CNT(HB_CONS) == 1) { uint8_t countOfMonitoredNodes = CO_GET_CNT(ARR_1016); @@ -405,10 +405,10 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #endif /* Node guarding */ -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 CO_alloc_break_on_fail(co->NGslave, 1, sizeof(*co->NGslave)); #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 CO_alloc_break_on_fail(co->NGmaster, 1, sizeof(*co->NGmaster)); #endif @@ -417,13 +417,13 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t TX_CNT_EM_PROD = 0); if (CO_GET_CNT(EM) == 1) { CO_alloc_break_on_fail(co->em, CO_GET_CNT(EM), sizeof(*co->em)); - #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 ON_MULTI_OD(RX_CNT_EM_CONS = 1); #endif - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 ON_MULTI_OD(TX_CNT_EM_PROD = 1); #endif - #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 uint8_t fifoSize = CO_GET_CNT(ARR_1003) + 1; if (fifoSize >= 2) { CO_alloc_break_on_fail(co->em_fifo, fifoSize, sizeof(*co->em_fifo)); @@ -440,7 +440,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(TX_CNT_SDO_SRV = config->CNT_SDO_SRV); } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SDO_CLI = 0); ON_MULTI_OD(uint8_t TX_CNT_SDO_CLI = 0); if (CO_GET_CNT(SDO_CLI) > 0) { @@ -450,31 +450,31 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_TIME = 0); ON_MULTI_OD(uint8_t TX_CNT_TIME = 0); if (CO_GET_CNT(TIME) == 1) { CO_alloc_break_on_fail(co->TIME, CO_GET_CNT(TIME), sizeof(*co->TIME)); ON_MULTI_OD(RX_CNT_TIME = 1); - #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER + #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 ON_MULTI_OD(TX_CNT_TIME = 1); #endif } #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SYNC = 0); ON_MULTI_OD(uint8_t TX_CNT_SYNC = 0); if (CO_GET_CNT(SYNC) == 1) { CO_alloc_break_on_fail(co->SYNC, CO_GET_CNT(SYNC), sizeof(*co->SYNC)); ON_MULTI_OD(RX_CNT_SYNC = 1); - #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER + #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 ON_MULTI_OD(TX_CNT_SYNC = 1); #endif } #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 ON_MULTI_OD(uint16_t RX_CNT_RPDO = 0); if (CO_GET_CNT(RPDO) > 0) { CO_alloc_break_on_fail(co->RPDO, CO_GET_CNT(RPDO), sizeof(*co->RPDO)); @@ -482,7 +482,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 ON_MULTI_OD(uint16_t TX_CNT_TPDO = 0); if (CO_GET_CNT(TPDO) > 0) { CO_alloc_break_on_fail(co->TPDO, CO_GET_CNT(TPDO), sizeof(*co->TPDO)); @@ -490,13 +490,13 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 if (CO_GET_CNT(LEDS) == 1) { CO_alloc_break_on_fail(co->LEDs, CO_GET_CNT(LEDS), sizeof(*co->LEDs)); } #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_GFC = 0); ON_MULTI_OD(uint8_t TX_CNT_GFC = 0); if (CO_GET_CNT(GFC) == 1) { @@ -506,7 +506,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SRDO = 0); ON_MULTI_OD(uint8_t TX_CNT_SRDO = 0); if (CO_GET_CNT(SRDO) > 0) { @@ -517,7 +517,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 ON_MULTI_OD(uint8_t RX_CNT_LSS_SLV = 0); ON_MULTI_OD(uint8_t TX_CNT_LSS_SLV = 0); if (CO_GET_CNT(LSS_SLV) == 1) { @@ -527,7 +527,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 ON_MULTI_OD(uint8_t RX_CNT_LSS_MST = 0); ON_MULTI_OD(uint8_t TX_CNT_LSS_MST = 0); if (CO_GET_CNT(LSS_MST) == 1) { @@ -537,7 +537,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 if (CO_GET_CNT(GTWA) == 1) { CO_alloc_break_on_fail(co->gtwa, CO_GET_CNT(GTWA), sizeof(*co->gtwa)); } @@ -555,76 +555,76 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { * highest priority of the CAN identifier are listed first. */ int16_t idxRx = 0; co->RX_IDX_NMT_SLV = idxRx; idxRx += RX_CNT_NMT_SLV; -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 co->RX_IDX_GFC = idxRx; idxRx += RX_CNT_GFC; #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 co->RX_IDX_SYNC = idxRx; idxRx += RX_CNT_SYNC; #endif co->RX_IDX_EM_CONS = idxRx; idxRx += RX_CNT_EM_CONS; -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 co->RX_IDX_TIME = idxRx; idxRx += RX_CNT_TIME; #endif -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 co->RX_IDX_SRDO = idxRx; idxRx += RX_CNT_SRDO * 2; #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 co->RX_IDX_RPDO = idxRx; idxRx += RX_CNT_RPDO; #endif co->RX_IDX_SDO_SRV = idxRx; idxRx += RX_CNT_SDO_SRV; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 co->RX_IDX_SDO_CLI = idxRx; idxRx += RX_CNT_SDO_CLI; #endif -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 co->RX_IDX_HB_CONS = idxRx; idxRx += RX_CNT_HB_CONS; #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 co->RX_IDX_NG_SLV = idxRx; idxRx += 1; #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 co->RX_IDX_NG_MST = idxRx; idxRx += 1; #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 co->RX_IDX_LSS_SLV = idxRx; idxRx += RX_CNT_LSS_SLV; #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 co->RX_IDX_LSS_MST = idxRx; idxRx += RX_CNT_LSS_MST; #endif co->CNT_ALL_RX_MSGS = idxRx; int16_t idxTx = 0; co->TX_IDX_NMT_MST = idxTx; idxTx += TX_CNT_NMT_MST; -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 co->TX_IDX_GFC = idxTx; idxTx += TX_CNT_GFC; #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 co->TX_IDX_SYNC = idxTx; idxTx += TX_CNT_SYNC; #endif co->TX_IDX_EM_PROD = idxTx; idxTx += TX_CNT_EM_PROD; -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 co->TX_IDX_TIME = idxTx; idxTx += TX_CNT_TIME; #endif -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 co->TX_IDX_SRDO = idxTx; idxTx += TX_CNT_SRDO * 2; #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 co->TX_IDX_TPDO = idxTx; idxTx += TX_CNT_TPDO; #endif co->TX_IDX_SDO_SRV = idxTx; idxTx += TX_CNT_SDO_SRV; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 co->TX_IDX_SDO_CLI = idxTx; idxTx += TX_CNT_SDO_CLI; #endif co->TX_IDX_HB_PROD = idxTx; idxTx += TX_CNT_HB_PROD; -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 co->TX_IDX_NG_SLV = idxTx; idxTx += 1; #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 co->TX_IDX_NG_MST = idxTx; idxTx += 1; #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 co->TX_IDX_LSS_SLV = idxTx; idxTx += TX_CNT_LSS_SLV; #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 co->TX_IDX_LSS_MST = idxTx; idxTx += TX_CNT_LSS_MST; #endif co->CNT_ALL_TX_MSGS = idxTx; @@ -669,48 +669,48 @@ void CO_delete(CO_t *co) { CO_free(co->trace); #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 CO_free(co->gtwa); #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 CO_free(co->LSSmaster); #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 CO_free(co->LSSslave); #endif -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 CO_free(co->SRDO); CO_free(co->SRDOGuard); #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 CO_free(co->GFC); #endif -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 CO_free(co->LEDs); #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 CO_free(co->TPDO); #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 CO_free(co->RPDO); #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 CO_free(co->SYNC); #endif -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 CO_free(co->TIME); #endif -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 free(co->SDOclient); #endif @@ -719,18 +719,18 @@ void CO_delete(CO_t *co) { /* Emergency */ CO_free(co->em); -#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 CO_free(co->em_fifo); #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 CO_free(co->NGslave); #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 CO_free(co->NGmaster); #endif -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0) CO_free(co->HBconsMonitoredNodes); CO_free(co->HBcons); #endif @@ -754,56 +754,56 @@ void CO_delete(CO_t *co) { static CO_CANrx_t COO_CANmodule_rxArray[CO_CNT_ALL_RX_MSGS]; static CO_CANtx_t COO_CANmodule_txArray[CO_CNT_ALL_TX_MSGS]; static CO_NMT_t COO_NMT; -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 static CO_HBconsumer_t COO_HBcons; static CO_HBconsNode_t COO_HBconsMonitoredNodes[OD_CNT_ARR_1016]; #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 static CO_nodeGuardingSlave_t COO_NGslave; #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 static CO_nodeGuardingMaster_t COO_NGmaster; #endif static CO_EM_t COO_EM; -#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 static CO_EM_fifo_t COO_EM_FIFO[CO_GET_CNT(ARR_1003) + 1U]; #endif static CO_SDOserver_t COO_SDOserver[OD_CNT_SDO_SRV]; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 static CO_SDOclient_t COO_SDOclient[OD_CNT_SDO_CLI]; #endif -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 static CO_TIME_t COO_TIME; #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 static CO_SYNC_t COO_SYNC; #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 static CO_RPDO_t COO_RPDO[OD_CNT_RPDO]; #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 static CO_TPDO_t COO_TPDO[OD_CNT_TPDO]; #endif -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 static CO_LEDs_t COO_LEDs; #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 static CO_GFC_t COO_GFC; #endif -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 static CO_SRDOGuard_t COO_SRDOGuard; static CO_SRDO_t COO_SRDO[OD_CNT_SRDO]; #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 static CO_LSSslave_t COO_LSSslave; #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 static CO_LSSmaster_t COO_LSSmaster; #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 static CO_GTWA_t COO_gtwa; #endif -#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE +#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) != 0 #ifndef CO_TRACE_BUFFER_SIZE_FIXED #define CO_TRACE_BUFFER_SIZE_FIXED 100 #endif @@ -822,56 +822,56 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { co->CANtx = &COO_CANmodule_txArray[0]; co->NMT = &COO_NMT; -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 co->HBcons = &COO_HBcons; co->HBconsMonitoredNodes = &COO_HBconsMonitoredNodes[0]; #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 co->NGslave = &COO_NGslave; #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 co->NGmaster = &COO_NGmaster; #endif co->em = &COO_EM; -#if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 co->em_fifo = &COO_EM_FIFO[0]; #endif co->SDOserver = &COO_SDOserver[0]; -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 co->SDOclient = &COO_SDOclient[0]; #endif -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 co->TIME = &COO_TIME; #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 co->SYNC = &COO_SYNC; #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 co->RPDO = &COO_RPDO[0]; #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 co->TPDO = &COO_TPDO[0]; #endif -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 co->LEDs = &COO_LEDs; #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 co->GFC = &COO_GFC; #endif -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 co->SRDOGuard = &COO_SRDOGuard; co->SRDO = &COO_SRDO[0]; #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 co->LSSslave = &COO_LSSslave; #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 co->LSSmaster = &COO_LSSmaster; #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 co->gtwa = &COO_gtwa; #endif -#if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE +#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) != 0 co->trace = &COO_trace[0]; co->traceTimeBuffers = &COO_traceTimeBuffers[0][0]; co->traceValueBuffers = &COO_traceValueBuffers[0][0]; @@ -894,7 +894,7 @@ void CO_delete(CO_t *co) { bool_t CO_isLSSslaveEnabled(CO_t *co) { (void) co; /* may be unused */ bool_t en = false; -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 if (CO_GET_CNT(LSS_SLV) == 1U) { en = true; } #endif return en; @@ -923,7 +923,7 @@ CO_ReturnError_t CO_CANinit(CO_t *co, void *CANptr, uint16_t bitRate) { /******************************************************************************/ -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 CO_ReturnError_t CO_LSSinit(CO_t *co, CO_LSS_address_t *lssAddress, uint8_t *pendingNodeID, @@ -986,7 +986,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, /* Verify CANopen Node-ID */ co->nodeIdUnconfigured = false; -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 if ((CO_GET_CNT(LSS_SLV) == 1U) && (nodeId == CO_LSS_NODE_ID_ASSIGNMENT)) { co->nodeIdUnconfigured = true; } @@ -997,7 +997,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } else { /* MISRA C 2004 14.10 */ } -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 if (CO_GET_CNT(LEDS) == 1U) { err = CO_LEDs_init(co->LEDs); if (err) { return err; } @@ -1014,24 +1014,24 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, err = CO_EM_init(co->em, co->CANmodule, OD_GET(H1001, OD_H1001_ERR_REG), - #if (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) + #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 co->em_fifo, (CO_GET_CNT(ARR_1003) + 1U), #endif - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 OD_GET(H1014, OD_H1014_COBID_EMERGENCY), CO_GET_CO(TX_IDX_EM_PROD), - #if (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 OD_GET(H1015, OD_H1015_INHIBIT_TIME_EMCY), #endif #endif - #if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 OD_GET(H1003, OD_H1003_PREDEF_ERR_FIELD), #endif - #if (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0 OD_statusBits, #endif - #if (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 co->CANmodule, CO_GET_CO(RX_IDX_EM_CONS), #endif @@ -1051,7 +1051,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(RX_IDX_NMT_SLV), CO_CAN_ID_NMT_SERVICE, - #if (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER + #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 co->CANmodule, CO_GET_CO(TX_IDX_NMT_MST), CO_CAN_ID_NMT_SERVICE, @@ -1063,7 +1063,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, if (err) { return err; } } -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 if (CO_GET_CNT(HB_CONS) == 1U) { err = CO_HBconsumer_init(co->HBcons, em, @@ -1077,7 +1077,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 err = CO_nodeGuardingSlave_init(co->NGslave, OD_GET(H100C, OD_H100C_GUARD_TIME), OD_GET(H100D, OD_H100D_LIFETIME_FACTOR), @@ -1090,7 +1090,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, errInfo); if (err) { return err; } #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 err = CO_nodeGuardingMaster_init(co->NGmaster, em, co->CANmodule, @@ -1118,7 +1118,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } } -#if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 if (CO_GET_CNT(SDO_CLI) > 0) { OD_entry_t *SDOcliPar = OD_GET(H1280, OD_H1280_SDO_CLIENT_1_PARAM); for (uint16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { @@ -1136,13 +1136,13 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #endif -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 if (CO_GET_CNT(TIME) == 1U) { err = CO_TIME_init(co->TIME, OD_GET(H1012, OD_H1012_COBID_TIME), co->CANmodule, CO_GET_CO(RX_IDX_TIME), -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 co->CANmodule, CO_GET_CO(TX_IDX_TIME), #endif @@ -1151,7 +1151,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #endif -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 if (CO_GET_CNT(SYNC) == 1U) { err = CO_SYNC_init(co->SYNC, em, @@ -1161,7 +1161,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, OD_GET(H1019, OD_H1019_SYNC_CNT_OVERFLOW), co->CANmodule, CO_GET_CO(RX_IDX_SYNC), -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 co->CANmodule, CO_GET_CO(TX_IDX_SYNC), #endif @@ -1170,7 +1170,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #endif -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 if (CO_GET_CNT(LSS_MST) == 1) { err = CO_LSSmaster_init(co->LSSmaster, CO_LSSmaster_DEFAULT_TIMEOUT, @@ -1184,21 +1184,21 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 if (CO_GET_CNT(GTWA) == 1) { err = CO_GTWA_init(co->gtwa, - #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO + #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 &co->SDOclient[0], SDOclientTimeoutTime_ms, SDOclientBlockTransfer, #endif - #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT + #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 co->NMT, #endif - #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS + #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 co->LSSmaster, #endif - #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS + #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 co->LEDs, #endif 0); @@ -1249,7 +1249,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; } -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 if (CO_GET_CNT(RPDO) > 0U) { OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); @@ -1269,7 +1269,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, err = CO_RPDO_init(&co->RPDO[i], od, em, - #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 co->SYNC, #endif preDefinedCanId, @@ -1283,7 +1283,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, } #endif -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 if (CO_GET_CNT(TPDO) > 0U) { OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); @@ -1303,7 +1303,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, err = CO_TPDO_init(&co->TPDO[i], od, em, - #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE + #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 co->SYNC, #endif preDefinedCanId, @@ -1322,7 +1322,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, /******************************************************************************/ -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) +#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, CO_EM_t *em, OD_t *od, @@ -1338,7 +1338,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, } -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 if (CO_GET_CNT(GFC) == 1) { CO_ReturnError_t err; err = CO_GFC_init(co->GFC, @@ -1353,7 +1353,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, } #endif -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 if (CO_GET_CNT(SRDO) > 0U) { CO_ReturnError_t err; err = CO_SRDO_init_start(co->SRDOGuard, @@ -1414,7 +1414,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, /* CAN module */ CO_CANmodule_process(co->CANmodule); -#if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE +#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) if (CO_GET_CNT(LSS_SLV) == 1U) { if (CO_LSSslave_process(co->LSSslave)) { reset = CO_RESET_COMM; @@ -1422,11 +1422,11 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, } #endif -#if (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 bool_t unc = co->nodeIdUnconfigured; uint16_t CANerrorStatus = co->CANmodule->CANerrorStatus; bool_t LSSslave_configuration = false; - #if (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE + #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 if ((CO_GET_CNT(LSS_SLV) == 1U) && (CO_LSSslave_getState(co->LSSslave) == CO_LSS_STATE_CONFIGURATION) ) { @@ -1486,7 +1486,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, timerNext_us); } -#if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 if (CO_GET_CNT(HB_CONS) == 1U) { CO_HBconsumer_process(co->HBcons, NMTisPreOrOperational, @@ -1495,26 +1495,26 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, } #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 CO_nodeGuardingSlave_process(co->NGslave, NMTstate, (co->NMT->HBproducerTime_us > 0U), timeDifference_us, timerNext_us); #endif -#if (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE +#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 CO_nodeGuardingMaster_process(co->NGmaster, timeDifference_us, timerNext_us); #endif -#if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE +#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 if (CO_GET_CNT(TIME) == 1U) { CO_TIME_process(co->TIME, NMTisPreOrOperational, timeDifference_us); } #endif -#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 if (CO_GET_CNT(GTWA) == 1) { CO_GTWA_process(co->gtwa, enableGateway, @@ -1528,7 +1528,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, /******************************************************************************/ -#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE +#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 bool_t CO_process_SYNC(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) @@ -1566,7 +1566,7 @@ bool_t CO_process_SYNC(CO_t *co, /******************************************************************************/ -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 void CO_process_RPDO(CO_t *co, bool_t syncWas, uint32_t timeDifference_us, @@ -1582,7 +1582,7 @@ void CO_process_RPDO(CO_t *co, for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { CO_RPDO_process(&co->RPDO[i], -#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 timeDifference_us, timerNext_us, #endif @@ -1594,7 +1594,7 @@ void CO_process_RPDO(CO_t *co, /******************************************************************************/ -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 void CO_process_TPDO(CO_t *co, bool_t syncWas, uint32_t timeDifference_us, @@ -1610,7 +1610,7 @@ void CO_process_TPDO(CO_t *co, for (uint16_t i = 0; i < CO_GET_CNT(TPDO); i++) { CO_TPDO_process(&co->TPDO[i], -#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 timeDifference_us, timerNext_us, #endif @@ -1622,7 +1622,7 @@ void CO_process_TPDO(CO_t *co, /******************************************************************************/ -#if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE +#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 CO_SRDO_state_t CO_process_SRDO(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) diff --git a/CANopen.h b/CANopen.h index 5930b79b..5018ac3d 100644 --- a/CANopen.h +++ b/CANopen.h @@ -300,7 +300,7 @@ typedef struct { uint16_t TX_IDX_NMT_MST; /**< Start index in CANtx. */ uint16_t TX_IDX_HB_PROD; /**< Start index in CANtx. */ #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0) || defined CO_DOXYGEN /** Heartbeat consumer object, initialised by @ref CO_HBconsumer_init() */ CO_HBconsumer_t *HBcons; /** Object for monitored nodes, initialised by @ref CO_HBconsumer_init() */ @@ -309,7 +309,7 @@ typedef struct { uint16_t RX_IDX_HB_CONS; /**< Start index in CANrx. */ #endif #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0) || defined CO_DOXYGEN /** Node guarding slave object, initialised by @ref CO_nodeGuardingSlave_init() */ CO_nodeGuardingSlave_t *NGslave; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -317,7 +317,7 @@ typedef struct { uint16_t TX_IDX_NG_SLV; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0) || defined CO_DOXYGEN /** Node guarding master object, initialised by @ref CO_nodeGuardingMaster_init() */ CO_nodeGuardingMaster_t *NGmaster; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -331,7 +331,7 @@ typedef struct { uint16_t RX_IDX_EM_CONS; /**< Start index in CANrx. */ uint16_t TX_IDX_EM_PROD; /**< Start index in CANtx. */ #endif -#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) \ +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) \ || defined CO_DOXYGEN /** FIFO for emergency object, initialised by @ref CO_EM_init() */ CO_EM_fifo_t *em_fifo; @@ -342,7 +342,7 @@ typedef struct { uint16_t RX_IDX_SDO_SRV; /**< Start index in CANrx. */ uint16_t TX_IDX_SDO_SRV; /**< Start index in CANtx. */ #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN /** SDO client objects, initialised by @ref CO_SDOclient_init() */ CO_SDOclient_t *SDOclient; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -350,7 +350,7 @@ typedef struct { uint16_t TX_IDX_SDO_CLI; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN /** TIME object, initialised by @ref CO_TIME_init() */ CO_TIME_t *TIME; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -358,7 +358,7 @@ typedef struct { uint16_t TX_IDX_TIME; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN /** SYNC object, initialised by @ref CO_SYNC_init() */ CO_SYNC_t *SYNC; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -366,25 +366,25 @@ typedef struct { uint16_t TX_IDX_SYNC; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN /** RPDO objects, initialised by @ref CO_RPDO_init() */ CO_RPDO_t *RPDO; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_RPDO; /**< Start index in CANrx. */ #endif #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN /** TPDO objects, initialised by @ref CO_TPDO_init() */ CO_TPDO_t *TPDO; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t TX_IDX_TPDO; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN /** LEDs object, initialised by @ref CO_LEDs_init() */ CO_LEDs_t *LEDs; #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0) || defined CO_DOXYGEN /** GFC object, initialised by @ref CO_GFC_init() */ CO_GFC_t *GFC; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -392,7 +392,7 @@ typedef struct { uint16_t TX_IDX_GFC; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN /** SRDO guard object, initialised by @ref CO_SRDO_init_start(), single * SRDOGuard object is included inside all SRDO objects */ CO_SRDOGuard_t *SRDOGuard; @@ -403,7 +403,7 @@ typedef struct { uint16_t TX_IDX_SRDO; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN /** LSS slave object, initialised by @ref CO_LSSslave_init(). */ CO_LSSslave_t *LSSslave; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -411,7 +411,7 @@ typedef struct { uint16_t TX_IDX_LSS_SLV; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0) || defined CO_DOXYGEN /** LSS master object, initialised by @ref CO_LSSmaster_init(). */ CO_LSSmaster_t *LSSmaster; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -419,7 +419,7 @@ typedef struct { uint16_t TX_IDX_LSS_MST; /**< Start index in CANtx. */ #endif #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0) || defined CO_DOXYGEN /** Gateway-ascii object, initialised by @ref CO_GTWA_init(). */ CO_GTWA_t *gtwa; #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN @@ -486,7 +486,7 @@ bool_t CO_isLSSslaveEnabled(CO_t *co); CO_ReturnError_t CO_CANinit(CO_t *co, void *CANptr, uint16_t bitRate); -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN /** * Initialize CANopen LSS slave * @@ -596,7 +596,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, * * @return CO_ERROR_NO in case of success. */ -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) || ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) +#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, CO_EM_t *em, OD_t *od, @@ -633,7 +633,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, uint32_t *timerNext_us); -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN /** * Process CANopen SYNC objects. * @@ -654,7 +654,7 @@ bool_t CO_process_SYNC(CO_t *co, #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN /** * Process CANopen RPDO objects. * @@ -676,7 +676,7 @@ void CO_process_RPDO(CO_t *co, #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN /** * Process CANopen TPDO objects. * @@ -698,7 +698,7 @@ void CO_process_TPDO(CO_t *co, #endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN /** * Process CANopen SRDO objects. * diff --git a/storage/CO_storage.c b/storage/CO_storage.c index 0a00dbaf..bc897c7d 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -24,7 +24,7 @@ #include "storage/CO_storage.h" -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 /* * Custom function for writing OD object "Store parameters" diff --git a/storage/CO_storage.h b/storage/CO_storage.h index f338e9d5..35e00b06 100644 --- a/storage/CO_storage.h +++ b/storage/CO_storage.h @@ -34,7 +34,7 @@ #define CO_CONFIG_STORAGE (CO_CONFIG_STORAGE_ENABLE) #endif -#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 9315a7cb..3a49eba5 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -26,7 +26,7 @@ #include "storage/CO_eeprom.h" #include "301/crc16-ccitt.h" -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 /* * Function for writing data on "Store parameters" command - OD object 1010 diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h index dc8b180a..06490e60 100644 --- a/storage/CO_storageEeprom.h +++ b/storage/CO_storageEeprom.h @@ -28,7 +28,7 @@ #include "storage/CO_storage.h" -#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN +#if (((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { From fbe4d307d9f3afdc9e24320cf8989f31aa04c644 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 09:41:35 +0200 Subject: [PATCH 284/520] static analysis: argument is not compatible with other argument in call to function 'memmove' --- 301/CO_driver.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/301/CO_driver.h b/301/CO_driver.h index 5f79e44c..abce95e5 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -737,15 +737,15 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule); * @return Value */ static inline uint8_t CO_getUint8(const void *buf) { - uint8_t value; (void)memmove(&value, buf, sizeof(value)); return value; + uint8_t value; (void)memmove((void *)&value, buf, sizeof(value)); return value; } /** Get uint16_t value from memory buffer, see @ref CO_getUint8 */ static inline uint16_t CO_getUint16(const void *buf) { - uint16_t value; (void)memmove(&value, buf, sizeof(value)); return value; + uint16_t value; (void)memmove((void *)&value, buf, sizeof(value)); return value; } /** Get uint32_t value from memory buffer, see @ref CO_getUint8 */ static inline uint32_t CO_getUint32(const void *buf) { - uint32_t value; (void)memmove(&value, buf, sizeof(value)); return value; + uint32_t value; (void)memmove((void *)&value, buf, sizeof(value)); return value; } /** @@ -757,15 +757,15 @@ static inline uint32_t CO_getUint32(const void *buf) { * @return number of bytes written. */ static inline uint8_t CO_setUint8(void *buf, uint8_t value) { - (void)memmove(buf, &value, sizeof(value)); return sizeof(value); + (void)memmove(buf, (const void *)&value, sizeof(value)); return sizeof(value); } /** Write uint16_t value into memory buffer, see @ref CO_setUint8 */ static inline uint8_t CO_setUint16(void *buf, uint16_t value) { - (void)memmove(buf, &value, sizeof(value)); return sizeof(value); + (void)memmove(buf, (const void *)&value, sizeof(value)); return sizeof(value); } /** Write uint32_t value into memory buffer, see @ref CO_setUint8 */ static inline uint8_t CO_setUint32(void *buf, uint32_t value) { - (void)memmove(buf, &value, sizeof(value)); return sizeof(value); + (void)memmove(buf, (const void *)&value, sizeof(value)); return sizeof(value); } /** @} */ /* CO_driver */ From e720f497d1f35dca57909e61748c27bbb5055619 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 09:43:41 +0200 Subject: [PATCH 285/520] static analisys: cannot assign 'unsigned32' to narrower essential type 'unsigned8' [MISRA 2012 Rule 10.3, required] --- 301/CO_driver.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_driver.h b/301/CO_driver.h index abce95e5..6c344810 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -757,15 +757,15 @@ static inline uint32_t CO_getUint32(const void *buf) { * @return number of bytes written. */ static inline uint8_t CO_setUint8(void *buf, uint8_t value) { - (void)memmove(buf, (const void *)&value, sizeof(value)); return sizeof(value); + (void)memmove(buf, (const void *)&value, sizeof(value)); return (uint8_t)(sizeof(value)); } /** Write uint16_t value into memory buffer, see @ref CO_setUint8 */ static inline uint8_t CO_setUint16(void *buf, uint16_t value) { - (void)memmove(buf, (const void *)&value, sizeof(value)); return sizeof(value); + (void)memmove(buf, (const void *)&value, sizeof(value)); return (uint8_t)(sizeof(value)); } /** Write uint32_t value into memory buffer, see @ref CO_setUint8 */ static inline uint8_t CO_setUint32(void *buf, uint32_t value) { - (void)memmove(buf, (const void *)&value, sizeof(value)); return sizeof(value); + (void)memmove(buf, (const void *)&value, sizeof(value)); return (uint8_t)(sizeof(value)); } /** @} */ /* CO_driver */ From b2de7f4cbe0b12f434f38a7ef149dcd67d5fbd9c Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 09:46:34 +0200 Subject: [PATCH 286/520] static analysis: integer null pointer constant is not the NULL macro [MISRA 2012 Rule 11.9, required] --- 301/CO_ODinterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index c50b087b..d09db10a 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -486,7 +486,7 @@ static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) { return &entry->extension->flagsPDO[0]; } #endif - return 0; + return NULL; } From 9e8ceb4dfa953a6068d046b61a7370a350d177b2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 10:13:45 +0200 Subject: [PATCH 287/520] static analysis: ignoring return value of functions [MISRA 2012 Directive 4.7, required] --- 301/CO_Emergency.c | 2 +- 301/CO_NMT_Heartbeat.c | 2 +- 301/CO_Node_Guarding.c | 4 ++-- 301/CO_PDO.c | 10 +++++----- 301/CO_SDOclient.c | 26 +++++++++++++------------- 301/CO_SDOserver.c | 30 +++++++++++++++--------------- 301/CO_TIME.c | 2 +- 305/CO_LSSmaster.c | 24 ++++++++++++------------ 305/CO_LSSslave.c | 4 ++-- CANopen.c | 4 ++-- 10 files changed, 54 insertions(+), 54 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index cafbc6a3..d4b26179 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -655,7 +655,7 @@ void CO_EM_process(CO_EM_t *em, /* send emergency message */ (void)memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr].msg, sizeof(em->CANtxBuff->data)); - CO_CANsend(em->CANdevTx, em->CANtxBuff); + (void)CO_CANsend(em->CANdevTx, em->CANtxBuff); #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 /* report also own emergency messages */ diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 20f722f1..8c9d135e 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -239,7 +239,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, || (NMTstateCpy != NMT->operatingStatePrev)) )) { NMT->HB_TXbuff->data[0] = (uint8_t) NMTstateCpy; - CO_CANsend(NMT->HB_CANdevTx, NMT->HB_TXbuff); + (void)CO_CANsend(NMT->HB_CANdevTx, NMT->HB_TXbuff); if (NMTstateCpy == CO_NMT_INITIALIZING) { /* NMT slave self starting */ diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index dfe02457..ea19cfea 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -225,7 +225,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, else { ngs->toggle = true; } - CO_CANsend(ngs->CANdevTx, ngs->CANtxBuff); + (void)CO_CANsend(ngs->CANdevTx, ngs->CANtxBuff); if (ngs->lifeTimeTimeout) { /* error bit is shared with HB consumer */ @@ -436,7 +436,7 @@ void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, node->ident, true, 1, 0); #endif - CO_CANsend(ngm->CANdevTx, ngm->CANtxBuff); + (void)CO_CANsend(ngm->CANdevTx, ngm->CANtxBuff); node->CANtxWasBusy = false; node->responseRecived = false; node->guardTimer = node->guardTime_us; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 9ba00f51..af7a586e 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -1389,7 +1389,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, /* send TPDO */ if (TPDO->sendRequest && (TPDO->inhibitTimer == 0U)) { - CO_TPDOsend(TPDO); + (void)CO_TPDOsend(TPDO); } #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 @@ -1402,7 +1402,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, #endif #else if (TPDO->sendRequest) { - CO_TPDOsend(TPDO); + (void)CO_TPDOsend(TPDO); } #endif } /* if (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) */ @@ -1412,7 +1412,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, else if ((TPDO->SYNC != NULL) && syncWas) { /* send synchronous acyclic TPDO */ if (TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { - if (TPDO->sendRequest) { CO_TPDOsend(TPDO); } + if (TPDO->sendRequest) { (void)CO_TPDOsend(TPDO); } } /* send synchronous cyclic TPDO */ else { @@ -1434,13 +1434,13 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, if (TPDO->syncCounter == 254U) { if (TPDO->SYNC->counter == TPDO->syncStartValue) { TPDO->syncCounter = TPDO->transmissionType; - CO_TPDOsend(TPDO); + (void)CO_TPDOsend(TPDO); } } /* Send TPDO after every N-th Sync */ else if (--TPDO->syncCounter == 0U) { TPDO->syncCounter = TPDO->transmissionType; - CO_TPDOsend(TPDO); + (void)CO_TPDOsend(TPDO); } else { /* MISRA C 2004 14.10 */ } } diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 2f980afe..6769d358 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -934,7 +934,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; break; } @@ -971,7 +971,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; break; } @@ -993,7 +993,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; break; } @@ -1044,7 +1044,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, #endif /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); break; } @@ -1055,7 +1055,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; break; } @@ -1077,7 +1077,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; (void)memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; } @@ -1626,7 +1626,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; break; } @@ -1642,7 +1642,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; break; } @@ -1671,7 +1671,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* reset timeout timer and send message */ SDO_C->timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; break; } @@ -1688,7 +1688,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, * barrier here with CO_FLAG_CLEAR() call. */ SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; CO_FLAG_CLEAR(SDO_C->CANrxNew); - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); break; } @@ -1749,7 +1749,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* reset block_timeoutTimer, but not SDO_C->timeoutTimer */ SDO_C->block_timeoutTimer = 0; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); #ifdef CO_DEBUG_SDO_CLIENT if (transferShort && !SDO_C->finished) { char msg[80]; @@ -1765,7 +1765,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, case CO_SDO_ST_UPLOAD_BLK_END_CRSP: { SDO_C->CANtxBuff->data[0] = 0xA1; - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; break; @@ -1788,7 +1788,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; (void)memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); - CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 3074ec93..18d8d696 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -260,7 +260,7 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, ) { return ODR_INVALID_VALUE; } - CO_SDOserver_init_canRxTx(SDO, + (void)CO_SDOserver_init_canRxTx(SDO, SDO->CANdevRx, SDO->CANdevRxIdx, SDO->CANdevTxIdx, @@ -282,7 +282,7 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, ) { return ODR_INVALID_VALUE; } - CO_SDOserver_init_canRxTx(SDO, + (void)CO_SDOserver_init_canRxTx(SDO, SDO->CANdevRx, SDO->CANdevRxIdx, SDO->CANdevTxIdx, @@ -369,8 +369,8 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, CanId_ServerToClient = (uint16_t)CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; - OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); - OD_set_u32(OD_1200_SDOsrvPar, 2, CanId_ServerToClient, true); + (void)OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); + (void)OD_set_u32(OD_1200_SDOsrvPar, 2, CanId_ServerToClient, true); } else if ((OD_SDOsrvParIdx > (uint16_t)OD_H1200_SDO_SERVER_1_PARAM) && (OD_SDOsrvParIdx <= ((uint16_t)OD_H1200_SDO_SERVER_1_PARAM + 0x7FU)) @@ -1243,7 +1243,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 SDO->timeoutTimer = 0; #endif - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 if (SDO->finished) { SDO->state = CO_SDO_ST_IDLE; @@ -1270,7 +1270,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* reset timeout timer and send message */ SDO->timeoutTimer = 0; - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); if (SDO->finished) { SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; @@ -1347,7 +1347,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); SDO->CANtxBuff->data[3] = SDO->subIndex; - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); break; } @@ -1401,7 +1401,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* send message */ - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); break; } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ @@ -1435,7 +1435,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, * barrier here with CO_FLAG_CLEAR() call. */ SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; CO_FLAG_CLEAR(SDO->CANrxNew); - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); break; } @@ -1481,7 +1481,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* reset block_timeoutTimer, but not SDO->timeoutTimer */ SDO->block_timeoutTimer = 0; - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); #ifdef CO_DEBUG_SDO_SERVER if (transferShort && !SDO->finished) { char msg[80]; @@ -1497,7 +1497,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { SDO->CANtxBuff->data[0] = 0xA1; - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; break; @@ -1518,7 +1518,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* reset timeout timer and send message */ SDO->timeoutTimer = 0; - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; break; } @@ -1574,7 +1574,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #endif /* reset timeout timer and send message */ SDO->timeoutTimer = 0; - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); break; } @@ -1585,7 +1585,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* reset timeout timer and send message */ SDO->timeoutTimer = 0; - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; break; } @@ -1607,7 +1607,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[3] = SDO->subIndex; (void)memcpy(&SDO->CANtxBuff->data[4], &code, sizeof(code)); - CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; } diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 55029d02..36de8db0 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -225,7 +225,7 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, uint16_t days_swapped = CO_SWAP_16(TIME->days); (void)CO_setUint32(&TIME->CANtxBuff->data[0], ms_swapped); (void)CO_setUint16(&TIME->CANtxBuff->data[4], days_swapped); - CO_CANsend(TIME->CANdevTx, TIME->CANtxBuff); + (void)CO_CANsend(TIME->CANdevTx, TIME->CANtxBuff); } else { TIME->producerTimer_ms += ms; diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 098a2f0f..f9e1125a 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -225,16 +225,16 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( (void)memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_PRODUCT; (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.productCode); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_REV; (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.revisionNumber); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_SERIAL; (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.serialNumber); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; } @@ -246,7 +246,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION; (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ ret = CO_LSSmaster_OK; @@ -339,7 +339,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_WAITING; (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ ret = CO_LSSmaster_OK; @@ -443,7 +443,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( LSSmaster->TXbuff->data[1] = 0; LSSmaster->TXbuff->data[2] = bitTiming; (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; } @@ -488,7 +488,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( LSSmaster->TXbuff->data[0] = CO_LSS_CFG_NODE_ID; LSSmaster->TXbuff->data[1] = nodeId; (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; } @@ -528,7 +528,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_STORE; (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; } @@ -567,7 +567,7 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; (void)CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ ret = CO_LSSmaster_OK; @@ -586,7 +586,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = cs; (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); return CO_LSSmaster_WAIT_SLAVE; } @@ -762,7 +762,7 @@ static void CO_LSSmaster_FsSendMsg( LSSmaster->TXbuff->data[6] = lssSub; LSSmaster->TXbuff->data[7] = lssNext; - CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); } /* diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 385fb2f5..dfcfed38 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -165,7 +165,7 @@ static void CO_LSSslave_receive(void *object, void *msg) LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; (void)memset(&LSSslave->TXbuff->data[1], 0, sizeof(LSSslave->TXbuff->data) - 1); - CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); + (void)CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); #else LSSslave->service = cs; request_LSSslave_process = true; @@ -486,7 +486,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { } if(CANsend) { - CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); + (void)CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); } CO_FLAG_CLEAR(LSSslave->sendResponse); diff --git a/CANopen.c b/CANopen.c index 9ecbd940..cbd7e42a 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1480,7 +1480,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, /* SDOserver */ for (uint8_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { - CO_SDOserver_process(&co->SDOserver[i], + (void)CO_SDOserver_process(&co->SDOserver[i], NMTisPreOrOperational, timeDifference_us, timerNext_us); @@ -1510,7 +1510,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 if (CO_GET_CNT(TIME) == 1U) { - CO_TIME_process(co->TIME, NMTisPreOrOperational, timeDifference_us); + (void)CO_TIME_process(co->TIME, NMTisPreOrOperational, timeDifference_us); } #endif From 6e009c08933d46c38fcde4fd799adb0f2bde59b6 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 10:42:40 +0200 Subject: [PATCH 288/520] static analysis: cannot assign 'signed8' to different essential type 'boolean' [MISRA 2012 Rule 10.3, required] --- 301/CO_Emergency.c | 10 +++++----- 301/CO_HBconsumer.c | 2 +- 301/CO_NMT_Heartbeat.c | 10 +++++----- 301/CO_Node_Guarding.c | 4 ++-- 301/CO_PDO.c | 8 ++++---- 301/CO_SDOclient.c | 6 +++--- 301/CO_SDOserver.c | 6 +++--- 301/CO_SYNC.c | 16 ++++++++-------- 301/CO_TIME.c | 6 +++--- 305/CO_LSSmaster.c | 6 +++--- 305/CO_LSSslave.c | 6 +++--- CANopen.c | 4 ++-- 12 files changed, 42 insertions(+), 42 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index d4b26179..dfd6880c 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -112,9 +112,9 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, em->CANdevTx, /* CAN device */ em->CANdevTxIdx, /* index of specific buffer inside CAN module */ newCanId, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 8U, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ } /* write value to the original location in the Object Dictionary */ @@ -461,9 +461,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ producerCanId, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 8U, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (em->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -513,7 +513,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, CANdevRxIdx, /* rx buffer index */ CO_CAN_ID_EMERGENCY, /* CAN identifier */ 0x780, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)em, /* object passed to receive function */ CO_EM_receive); /* this function will process received message*/ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER */ diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index ed95e13b..e165f2f1 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -229,7 +229,7 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, HBcons->CANdevRxIdxStart + idx, COB_ID, 0x7FF, - 0, + false, (void*)&HBcons->monitoredNodes[idx], CO_HBcons_receive); } diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 8c9d135e..e9ba9662 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -150,7 +150,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, NMT_rxIdx, /* rx buffer index */ CANidRxNMT, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)NMT, /* object passed to receive function */ CO_NMT_receive); /* this function will process received message*/ if (ret != CO_ERROR_NO) { @@ -164,9 +164,9 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, NMT_CANdevTx, /* CAN device */ NMT_txIdx, /* index of specific buffer inside CAN module */ CANidTxNMT, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 2, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (NMT->NMT_TXbuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -178,9 +178,9 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, HB_CANdevTx, /* CAN device */ HB_txIdx, /* index of specific buffer inside CAN module */ CANidTxHB, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 1, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (NMT->HB_TXbuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index ea19cfea..0dc12e75 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -185,9 +185,9 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ CANidNodeGuarding, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 1, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (ngs->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } diff --git a/301/CO_PDO.c b/301/CO_PDO.c index af7a586e..cdb63114 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -563,7 +563,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, PDO->CANdevIdx, /* rx buffer index */ CAN_ID, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)RPDO, /* object passed to receive function */ CO_PDO_receive); /* this function will process rx msg */ @@ -709,7 +709,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, CANdevRxIdx, /* rx buffer index */ CAN_ID, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)RPDO, /* object passed to receive function */ CO_PDO_receive); /* this function will process received message*/ if (ret != CO_ERROR_NO) { @@ -993,7 +993,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, PDO->CANdev, /* CAN device */ PDO->CANdevIdx, /* index of specific buffer inside CAN mod. */ CAN_ID, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ PDO->dataLength, /* number of data bytes */ TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); /* synchronous message flag */ @@ -1172,7 +1172,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ CAN_ID, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ PDO->dataLength, /* number of data bytes */ TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); /* synchronous message flag bit */ diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 6769d358..653d7e7e 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -403,7 +403,7 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, SDO_C->CANdevRxIdx, /* rx buffer index */ CanIdS2C, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)SDO_C, /* object passed to receive function */ CO_SDOclient_receive); /* this function will process rx msg */ @@ -412,9 +412,9 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, SDO_C->CANdevTx, /* CAN device */ SDO_C->CANdevTxIdx, /* index of buffer inside CAN module */ CanIdC2S, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 8, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if ((ret != CO_ERROR_NO) || (SDO_C->CANtxBuff == NULL)) { diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 18d8d696..d734973b 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -203,7 +203,7 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, CANdevRxIdx, /* rx buffer index */ idC2S, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)SDO, /* object passed to receive function */ CO_SDO_receive); /* this function will process rx msg */ @@ -212,9 +212,9 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, SDO->CANdevTx, /* CAN device */ CANdevTxIdx, /* index of buffer inside CAN module */ idS2C, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 8, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (SDO->CANtxBuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 6841dba8..1c74de13 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -114,7 +114,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, SYNC->CANdevRxIdx, /* rx buffer index */ CAN_ID, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)SYNC, /* object passed to receive function */ CO_SYNC_receive); /* this function will process received message*/ @@ -127,9 +127,9 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, SYNC->CANdevTx, /* CAN device */ SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ CAN_ID, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ SYNC->counterOverflowValue != 0 ? 1 : 0, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { SYNC->isProducer = false; @@ -183,9 +183,9 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, SYNC->CANdevTx, /* CAN device */ SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ SYNC->CAN_ID, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ syncCounterOvf != 0 ? 1 : 0, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { SYNC->isProducer = false; @@ -323,7 +323,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, CANdevRxIdx, /* rx buffer index */ cobIdSync & 0x7FFU, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)SYNC, /* object passed to receive function */ CO_SYNC_receive); /* this function will process received message*/ if (ret != CO_ERROR_NO) { @@ -335,9 +335,9 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ cobIdSync & 0x7FF, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ syncCounterOvf != 0 ? 1 : 0, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 36de8db0..0e06213a 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -137,7 +137,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, CANdevRxIdx, /* rx buffer index */ cobId, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)TIME, /* object passed to receive function */ CO_TIME_receive);/*this function will process received message*/ if (ret != CO_ERROR_NO) { @@ -152,9 +152,9 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ cobId, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ CO_TIME_MSG_LENGTH, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (TIME->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index f9e1125a..cdc4dad4 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -158,7 +158,7 @@ CO_ReturnError_t CO_LSSmaster_init( CANdevRxIdx, /* rx buffer index */ CANidLssSlave, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)LSSmaster, /* object passed to receive function */ CO_LSSmaster_receive);/* this function will process received message */ @@ -168,9 +168,9 @@ CO_ReturnError_t CO_LSSmaster_init( CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ CANidLssMaster, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 8, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (LSSmaster->TXbuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index dfcfed38..32fa56c8 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -243,7 +243,7 @@ CO_ReturnError_t CO_LSSslave_init( CANdevRxIdx, /* rx buffer index */ CANidLssMaster, /* CAN identifier */ 0x7FF, /* mask */ - 0, /* rtr */ + false, /* rtr */ (void*)LSSslave, /* object passed to receive function */ CO_LSSslave_receive); /* this function will process received message */ @@ -253,9 +253,9 @@ CO_ReturnError_t CO_LSSslave_init( CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ CANidLssSlave, /* CAN identifier */ - 0, /* rtr */ + false, /* rtr */ 8, /* number of data bytes */ - 0); /* synchronous message flag bit */ + false); /* synchronous message flag bit */ if (LSSslave->TXbuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/CANopen.c b/CANopen.c index cbd7e42a..68f70390 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1435,7 +1435,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #endif /* default macro, can be defined externally */ #ifndef CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS - #define CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS 0 + #define CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS false #endif if (CO_GET_CNT(LEDS) == 1U) { @@ -1445,7 +1445,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, LSSslave_configuration, (CANerrorStatus & (uint16_t)CO_CAN_ERRTX_BUS_OFF) != 0U, (CANerrorStatus & (uint16_t)CO_CAN_ERR_WARN_PASSIVE) != 0U, - 0, /* RPDO event timer timeout */ + false, /* RPDO event timer timeout */ unc ? false : CO_isError(co->em, CO_EM_SYNC_TIME_OUT), unc ? false : (CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) || CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET)), From 7855d35bae445ba76b13c396ad57fabe2387da1a Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 13:41:13 +0200 Subject: [PATCH 289/520] static analysis: refactoring changed enum with define to be able to use bitwise operators --- 301/CO_Emergency.c | 32 ++-- 301/CO_Emergency.h | 345 +++++++++++++++-------------------------- 301/CO_HBconsumer.c | 8 +- 301/CO_Node_Guarding.c | 8 +- 301/CO_PDO.c | 8 +- 301/CO_SYNC.c | 6 +- 301/CO_driver.h | 29 ++-- 304/CO_SRDO.c | 4 +- CANopen.c | 4 +- 9 files changed, 172 insertions(+), 272 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index dfd6880c..8410ba01 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -564,33 +564,33 @@ void CO_EM_process(CO_EM_t *em, uint16_t CANerrStChanged = CANerrSt ^ em->CANerrorStatusOld; em->CANerrorStatusOld = CANerrSt; - if (CANerrStChanged & ((uint16_t)CO_CAN_ERRTX_WARNING | (uint16_t)CO_CAN_ERRRX_WARNING)) { + if (CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) { CO_error(em, - (CANerrSt & ((uint16_t)CO_CAN_ERRTX_WARNING | (uint16_t)CO_CAN_ERRRX_WARNING)) != 0U, + (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0U, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, 0); } - if (CANerrStChanged & (uint16_t)CO_CAN_ERRTX_PASSIVE) { - CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRTX_PASSIVE) != 0U, + if (CANerrStChanged & CO_CAN_ERRTX_PASSIVE) { + CO_error(em, (CANerrSt & CO_CAN_ERRTX_PASSIVE) != 0U, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); } - if (CANerrStChanged & (uint16_t)CO_CAN_ERRTX_BUS_OFF) { - CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRTX_BUS_OFF) != 0U, + if (CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) { + CO_error(em, (CANerrSt & CO_CAN_ERRTX_BUS_OFF) != 0U, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, 0); } - if (CANerrStChanged & (uint16_t)CO_CAN_ERRTX_OVERFLOW) { - CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRTX_OVERFLOW) != 0U, + if (CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) { + CO_error(em, (CANerrSt & CO_CAN_ERRTX_OVERFLOW) != 0U, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } - if (CANerrStChanged & (uint16_t)CO_CAN_ERRTX_PDO_LATE) { - CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRTX_PDO_LATE) != 0U, + if (CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) { + CO_error(em, (CANerrSt & CO_CAN_ERRTX_PDO_LATE) != 0U, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, 0); } - if (CANerrStChanged & (uint16_t)CO_CAN_ERRRX_PASSIVE) { - CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRRX_PASSIVE) != 0U, + if (CANerrStChanged & CO_CAN_ERRRX_PASSIVE) { + CO_error(em, (CANerrSt & CO_CAN_ERRRX_PASSIVE) != 0U, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); } - if (CANerrStChanged & (uint16_t)CO_CAN_ERRRX_OVERFLOW) { - CO_error(em, (CANerrSt & (uint16_t)CO_CAN_ERRRX_OVERFLOW) != 0U, + if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) { + CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0U, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } } @@ -681,7 +681,7 @@ void CO_EM_process(CO_EM_t *em, } else if ((em->fifoOverflow == 2U) && (em->fifoPpPtr == em->fifoWrPtr)) { em->fifoOverflow = 0; - CO_errorReset(em, (uint8_t)CO_EM_EMERGENCY_BUFFER_FULL, 0); + CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); } else { /* MISRA C 2004 14.10 */ } } @@ -719,7 +719,7 @@ void CO_EM_process(CO_EM_t *em, /******************************************************************************/ -void CO_error(CO_EM_t *em, bool_t setError, const CO_EM_errorStatusBits_t errorBit, +void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) { if (em == NULL) { return; } diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 7fb05169..c03e654b 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -103,7 +103,8 @@ extern "C" { /** - * CANopen Error register. + * @defgroup CO_errorRegister_t CANopen Error register + * @{ * * Mandatory for CANopen, resides in object dictionary, index 0x1001. * @@ -114,118 +115,75 @@ extern "C" { * Internal errors may prevent device to stay in NMT Operational state and * changes may switch between the states. See @ref CO_NMT_control_t for details. */ -typedef enum { - CO_ERR_REG_GENERIC_ERR = 0x01U, /**< bit 0, generic error */ - CO_ERR_REG_CURRENT = 0x02U, /**< bit 1, current */ - CO_ERR_REG_VOLTAGE = 0x04U, /**< bit 2, voltage */ - CO_ERR_REG_TEMPERATURE = 0x08U, /**< bit 3, temperature */ - CO_ERR_REG_COMMUNICATION = 0x10U, /**< bit 4, communication error */ - CO_ERR_REG_DEV_PROFILE = 0x20U, /**< bit 5, device profile specific */ - CO_ERR_REG_RESERVED = 0x40U, /**< bit 6, reserved (always 0) */ - CO_ERR_REG_MANUFACTURER = 0x80U /**< bit 7, manufacturer specific */ -} CO_errorRegister_t; +#define CO_ERR_REG_GENERIC_ERR 0x01U /**< bit 0, generic error */ +#define CO_ERR_REG_CURRENT 0x02U /**< bit 1, current */ +#define CO_ERR_REG_VOLTAGE 0x04U /**< bit 2, voltage */ +#define CO_ERR_REG_TEMPERATURE 0x08U /**< bit 3, temperature */ +#define CO_ERR_REG_COMMUNICATION 0x10U /**< bit 4, communication error */ +#define CO_ERR_REG_DEV_PROFILE 0x20U /**< bit 5, device profile specific */ +#define CO_ERR_REG_RESERVED 0x40U /**< bit 6, reserved (always 0) */ +#define CO_ERR_REG_MANUFACTURER 0x80U /**< bit 7, manufacturer specific */ +/** @} */ /* CO_errorRegister_t */ /** - * CANopen Error code + * @defgroup CO_EM_errorCode_t CANopen Error code + * @{ * * Standard error codes according to CiA DS-301 and DS-401. */ -typedef enum { - /** 0x00xx, error Reset or No Error */ - CO_EMC_NO_ERROR = 0x0000U, - /** 0x10xx, Generic Error */ - CO_EMC_GENERIC = 0x1000U, - /** 0x20xx, Current */ - CO_EMC_CURRENT = 0x2000U, - /** 0x21xx, Current, device input side */ - CO_EMC_CURRENT_INPUT = 0x2100U, - /** 0x22xx, Current inside the device */ - CO_EMC_CURRENT_INSIDE = 0x2200U, - /** 0x23xx, Current, device output side */ - CO_EMC_CURRENT_OUTPUT = 0x2300U, - /** 0x30xx, Voltage */ - CO_EMC_VOLTAGE = 0x3000U, - /** 0x31xx, Mains Voltage */ - CO_EMC_VOLTAGE_MAINS = 0x3100U, - /** 0x32xx, Voltage inside the device */ - CO_EMC_VOLTAGE_INSIDE = 0x3200U, - /** 0x33xx, Output Voltage */ - CO_EMC_VOLTAGE_OUTPUT = 0x3300U, - /** 0x40xx, Temperature */ - CO_EMC_TEMPERATURE = 0x4000U, - /** 0x41xx, Ambient Temperature */ - CO_EMC_TEMP_AMBIENT = 0x4100U, - /** 0x42xx, Device Temperature */ - CO_EMC_TEMP_DEVICE = 0x4200U, - /** 0x50xx, Device Hardware */ - CO_EMC_HARDWARE = 0x5000U, - /** 0x60xx, Device Software */ - CO_EMC_SOFTWARE_DEVICE = 0x6000U, - /** 0x61xx, Internal Software */ - CO_EMC_SOFTWARE_INTERNAL = 0x6100U, - /** 0x62xx, User Software */ - CO_EMC_SOFTWARE_USER = 0x6200U, - /** 0x63xx, Data Set */ - CO_EMC_DATA_SET = 0x6300U, - /** 0x70xx, Additional Modules */ - CO_EMC_ADDITIONAL_MODUL = 0x7000U, - /** 0x80xx, Monitoring */ - CO_EMC_MONITORING = 0x8000U, - /** 0x81xx, Communication */ - CO_EMC_COMMUNICATION = 0x8100U, - /** 0x8110, CAN Overrun (Objects lost) */ - CO_EMC_CAN_OVERRUN = 0x8110U, - /** 0x8120, CAN in Error Passive Mode */ - CO_EMC_CAN_PASSIVE = 0x8120U, - /** 0x8130, Life Guard Error or Heartbeat Error */ - CO_EMC_HEARTBEAT = 0x8130U, - /** 0x8140, recovered from bus off */ - CO_EMC_BUS_OFF_RECOVERED = 0x8140U, - /** 0x8150, CAN-ID collision */ - CO_EMC_CAN_ID_COLLISION = 0x8150U, - /** 0x82xx, Protocol Error */ - CO_EMC_PROTOCOL_ERROR = 0x8200U, - /** 0x8210, PDO not processed due to length error */ - CO_EMC_PDO_LENGTH = 0x8210U, - /** 0x8220, PDO length exceeded */ - CO_EMC_PDO_LENGTH_EXC = 0x8220U, - /** 0x8230, DAM MPDO not processed, destination object not available */ - CO_EMC_DAM_MPDO = 0x8230U, - /** 0x8240, Unexpected SYNC data length */ - CO_EMC_SYNC_DATA_LENGTH = 0x8240U, - /** 0x8250, RPDO timeout */ - CO_EMC_RPDO_TIMEOUT = 0x8250U, - /** 0x90xx, External Error */ - CO_EMC_EXTERNAL_ERROR = 0x9000U, - /** 0xF0xx, Additional Functions */ - CO_EMC_ADDITIONAL_FUNC = 0xF000U, - /** 0xFFxx, Device specific */ - CO_EMC_DEVICE_SPECIFIC = 0xFF00U, - - /** 0x2310, DS401, Current at outputs too high (overload) */ - CO_EMC401_OUT_CUR_HI = 0x2310U, - /** 0x2320, DS401, Short circuit at outputs */ - CO_EMC401_OUT_SHORTED = 0x2320U, - /** 0x2330, DS401, Load dump at outputs */ - CO_EMC401_OUT_LOAD_DUMP = 0x2330U, - /** 0x3110, DS401, Input voltage too high */ - CO_EMC401_IN_VOLT_HI = 0x3110U, - /** 0x3120, DS401, Input voltage too low */ - CO_EMC401_IN_VOLT_LOW = 0x3120U, - /** 0x3210, DS401, Internal voltage too high */ - CO_EMC401_INTERN_VOLT_HI = 0x3210U, - /** 0x3220, DS401, Internal voltage too low */ - CO_EMC401_INTERN_VOLT_LO = 0x3220U, - /** 0x3310, DS401, Output voltage too high */ - CO_EMC401_OUT_VOLT_HIGH = 0x3310U, - /** 0x3320, DS401, Output voltage too low */ - CO_EMC401_OUT_VOLT_LOW = 0x3320U, -} CO_EM_errorCode_t; +#define CO_EMC_NO_ERROR 0x0000U /** 0x00xx error Reset or No Error */ +#define CO_EMC_GENERIC 0x1000U /** 0x10xx Generic Error */ +#define CO_EMC_CURRENT 0x2000U /** 0x20xx Current */ +#define CO_EMC_CURRENT_INPUT 0x2100U /** 0x21xx Current device input side */ +#define CO_EMC_CURRENT_INSIDE 0x2200U /** 0x22xx Current inside the device */ +#define CO_EMC_CURRENT_OUTPUT 0x2300U /** 0x23xx Current device output side */ +#define CO_EMC_VOLTAGE 0x3000U /** 0x30xx Voltage */ +#define CO_EMC_VOLTAGE_MAINS 0x3100U /** 0x31xx Mains Voltage */ +#define CO_EMC_VOLTAGE_INSIDE 0x3200U /** 0x32xx Voltage inside the device */ +#define CO_EMC_VOLTAGE_OUTPUT 0x3300U /** 0x33xx Output Voltage */ +#define CO_EMC_TEMPERATURE 0x4000U /** 0x40xx Temperature */ +#define CO_EMC_TEMP_AMBIENT 0x4100U /** 0x41xx Ambient Temperature */ +#define CO_EMC_TEMP_DEVICE 0x4200U /** 0x42xx Device Temperature */ +#define CO_EMC_HARDWARE 0x5000U /** 0x50xx Device Hardware */ +#define CO_EMC_SOFTWARE_DEVICE 0x6000U /** 0x60xx Device Software */ +#define CO_EMC_SOFTWARE_INTERNAL 0x6100U /** 0x61xx Internal Software */ +#define CO_EMC_SOFTWARE_USER 0x6200U /** 0x62xx User Software */ +#define CO_EMC_DATA_SET 0x6300U /** 0x63xx Data Set */ +#define CO_EMC_ADDITIONAL_MODUL 0x7000U /** 0x70xx Additional Modules */ +#define CO_EMC_MONITORING 0x8000U /** 0x80xx Monitoring */ +#define CO_EMC_COMMUNICATION 0x8100U /** 0x81xx Communication */ +#define CO_EMC_CAN_OVERRUN 0x8110U /** 0x8110 CAN Overrun (Objects lost) */ +#define CO_EMC_CAN_PASSIVE 0x8120U /** 0x8120 CAN in Error Passive Mode */ +#define CO_EMC_HEARTBEAT 0x8130U /** 0x8130 Life Guard Error or Heartbeat Error */ +#define CO_EMC_BUS_OFF_RECOVERED 0x8140U /** 0x8140 recovered from bus off */ +#define CO_EMC_CAN_ID_COLLISION 0x8150U /** 0x8150 CAN-ID collision */ +#define CO_EMC_PROTOCOL_ERROR 0x8200U /** 0x82xx Protocol Error */ +#define CO_EMC_PDO_LENGTH 0x8210U /** 0x8210 PDO not processed due to length error */ +#define CO_EMC_PDO_LENGTH_EXC 0x8220U /** 0x8220 PDO length exceeded */ +#define CO_EMC_DAM_MPDO 0x8230U /** 0x8230 DAM MPDO not processed destination object not available */ +#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /** 0x8240 Unexpected SYNC data length */ +#define CO_EMC_RPDO_TIMEOUT 0x8250U /** 0x8250 RPDO timeout */ +#define CO_EMC_EXTERNAL_ERROR 0x9000U /** 0x90xx External Error */ +#define CO_EMC_ADDITIONAL_FUNC 0xF000U /** 0xF0xx Additional Functions */ +#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /** 0xFFxx Device specific */ + +#define CO_EMC401_OUT_CUR_HI 0x2310U /** 0x2310 DS401 Current at outputs too high (overload) */ +#define CO_EMC401_OUT_SHORTED 0x2320U /** 0x2320 DS401 Short circuit at outputs */ +#define CO_EMC401_OUT_LOAD_DUMP 0x2330U /** 0x2330 DS401 Load dump at outputs */ +#define CO_EMC401_IN_VOLT_HI 0x3110U /** 0x3110 DS401 Input voltage too high */ +#define CO_EMC401_IN_VOLT_LOW 0x3120U /** 0x3120 DS401 Input voltage too low */ +#define CO_EMC401_INTERN_VOLT_HI 0x3210U /** 0x3210 DS401 Internal voltage too high */ +#define CO_EMC401_INTERN_VOLT_LO 0x3220U /** 0x3220 DS401 Internal voltage too low */ +#define CO_EMC401_OUT_VOLT_HIGH 0x3310U /** 0x3310 DS401 Output voltage too high */ +#define CO_EMC401_OUT_VOLT_LOW 0x3320U /** 0x3320 DS401 Output voltage too low */ + +/** @} */ /* CO_EM_errorCode_t */ /** - * Error status bits + * @defgroup CO_EM_errorStatusBits_t Error status bits + * @{ * * Bits for internal indication of the error condition. Each error condition is * specified by unique index from 0x00 up to 0xFF. @@ -240,123 +198,68 @@ typedef enum { * uses first 6 bytes. Additional 4 bytes are pre-defined for manufacturer * or device specific error indications, by default. */ -typedef enum { - /** 0x00, Error Reset or No Error */ - CO_EM_NO_ERROR = 0x00U, - /** 0x01, communication, info, CAN bus warning limit reached */ - CO_EM_CAN_BUS_WARNING = 0x01U, - /** 0x02, communication, info, Wrong data length of the received CAN - * message */ - CO_EM_RXMSG_WRONG_LENGTH = 0x02U, - /** 0x03, communication, info, Previous received CAN message wasn't - * processed yet */ - CO_EM_RXMSG_OVERFLOW = 0x03U, - /** 0x04, communication, info, Wrong data length of received PDO */ - CO_EM_RPDO_WRONG_LENGTH = 0x04U, - /** 0x05, communication, info, Previous received PDO wasn't processed yet */ - CO_EM_RPDO_OVERFLOW = 0x05U, - /** 0x06, communication, info, CAN receive bus is passive */ - CO_EM_CAN_RX_BUS_PASSIVE = 0x06U, - /** 0x07, communication, info, CAN transmit bus is passive */ - CO_EM_CAN_TX_BUS_PASSIVE = 0x07U, - /** 0x08, communication, info, Wrong NMT command received */ - CO_EM_NMT_WRONG_COMMAND = 0x08U, - /** 0x09, communication, info, TIME message timeout */ - CO_EM_TIME_TIMEOUT = 0x09U, - /** 0x0A, communication, info, (unused) */ - CO_EM_0A_unused = 0x0AU, - /** 0x0B, communication, info, (unused) */ - CO_EM_0B_unused = 0x0BU, - /** 0x0C, communication, info, (unused) */ - CO_EM_0C_unused = 0x0CU, - /** 0x0D, communication, info, (unused) */ - CO_EM_0D_unused = 0x0DU, - /** 0x0E, communication, info, (unused) */ - CO_EM_0E_unused = 0x0EU, - /** 0x0F, communication, info, (unused) */ - CO_EM_0F_unused = 0x0FU, - - /** 0x10, communication, critical, (unused) */ - CO_EM_10_unused = 0x10U, - /** 0x11, communication, critical, (unused) */ - CO_EM_11_unused = 0x11U, - /** 0x12, communication, critical, CAN transmit bus is off */ - CO_EM_CAN_TX_BUS_OFF = 0x12U, - /** 0x13, communication, critical, CAN module receive buffer has - * overflowed */ - CO_EM_CAN_RXB_OVERFLOW = 0x13U, - /** 0x14, communication, critical, CAN transmit buffer has overflowed */ - CO_EM_CAN_TX_OVERFLOW = 0x14U, - /** 0x15, communication, critical, TPDO is outside SYNC window */ - CO_EM_TPDO_OUTSIDE_WINDOW = 0x15U, - /** 0x16, communication, critical, (unused) */ - CO_EM_16_unused = 0x16U, - /** 0x17, communication, critical, RPDO message timeout */ - CO_EM_RPDO_TIME_OUT = 0x17U, - /** 0x18, communication, critical, SYNC message timeout */ - CO_EM_SYNC_TIME_OUT = 0x18U, - /** 0x19, communication, critical, Unexpected SYNC data length */ - CO_EM_SYNC_LENGTH = 0x19U, - /** 0x1A, communication, critical, Error with PDO mapping */ - CO_EM_PDO_WRONG_MAPPING = 0x1AU, - /** 0x1B, communication, critical, Heartbeat consumer timeout */ - CO_EM_HEARTBEAT_CONSUMER = 0x1BU, - /** 0x1C, communication, critical, Heartbeat consumer detected remote node - * reset */ - CO_EM_HB_CONSUMER_REMOTE_RESET = 0x1CU, - /** 0x1D, communication, critical, Error in SRDO configuration parameters. */ - CO_EM_SRDO_CONFIGURATION = 0x1DU, - /** 0x1E, communication, critical, (unused) */ - CO_EM_1E_unused = 0x1EU, - /** 0x1F, communication, critical, (unused) */ - CO_EM_1F_unused = 0x1FU, - - /** 0x20, generic, info, Emergency buffer is full, Emergency message wasn't - * sent */ - CO_EM_EMERGENCY_BUFFER_FULL = 0x20U, - /** 0x21, generic, info, (unused) */ - CO_EM_21_unused = 0x21U, - /** 0x22, generic, info, Microcontroller has just started */ - CO_EM_MICROCONTROLLER_RESET = 0x22U, - /** 0x23, generic, info, (unused) */ - CO_EM_23_unused = 0x23U, - /** 0x24, generic, info, (unused) */ - CO_EM_24_unused = 0x24U, - /** 0x25, generic, info, (unused) */ - CO_EM_25_unused = 0x25U, - /** 0x26, generic, info, (unused) */ - CO_EM_26_unused = 0x26U, - /** 0x27, generic, info, Automatic store to non-volatile memory failed */ - CO_EM_NON_VOLATILE_AUTO_SAVE = 0x27U, - - /** 0x28, generic, critical, Wrong parameters to CO_errorReport() function*/ - CO_EM_WRONG_ERROR_REPORT = 0x28U, - /** 0x29, generic, critical, Timer task has overflowed */ - CO_EM_ISR_TIMER_OVERFLOW = 0x29U, - /** 0x2A, generic, critical, Unable to allocate memory for objects */ - CO_EM_MEMORY_ALLOCATION_ERROR = 0x2AU, - /** 0x2B, generic, critical, Generic error, test usage */ - CO_EM_GENERIC_ERROR = 0x2BU, - /** 0x2C, generic, critical, Software error */ - CO_EM_GENERIC_SOFTWARE_ERROR = 0x2CU, - /** 0x2D, generic, critical, Object dictionary does not match the software*/ - CO_EM_INCONSISTENT_OBJECT_DICT = 0x2DU, - /** 0x2E, generic, critical, Error in calculation of device parameters */ - CO_EM_CALCULATION_OF_PARAMETERS = 0x2EU, - /** 0x2F, generic, critical, Error with access to non volatile device memory - */ - CO_EM_NON_VOLATILE_MEMORY = 0x2FU, - - /** 0x30+, manufacturer, info or critical, Error status buts, free to use by - * manufacturer. By default bits 0x30..0x3F are set as informational and - * bits 0x40..0x4F are set as critical. Manufacturer critical bits sets the - * error register, as specified by @ref CO_CONFIG_ERR_CONDITION_MANUFACTURER - */ - CO_EM_MANUFACTURER_START = 0x30U, - /** (@ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1), largest value of the - * Error status bit. */ - CO_EM_MANUFACTURER_END = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1 -} CO_EM_errorStatusBits_t; +#define CO_EM_NO_ERROR 0x00U /** 0x00 Error Reset or No Error */ +#define CO_EM_CAN_BUS_WARNING 0x01U /** 0x01 communication info CAN bus warning limit reached */ +#define CO_EM_RXMSG_WRONG_LENGTH 0x02U /** 0x02 communication info Wrong data length of the received CAN message */ +#define CO_EM_RXMSG_OVERFLOW 0x03U /** 0x03 communication info Previous received CAN message wasn't processed yet */ +#define CO_EM_RPDO_WRONG_LENGTH 0x04U /** 0x04 communication info Wrong data length of received PDO */ +#define CO_EM_RPDO_OVERFLOW 0x05U /** 0x05 communication info Previous received PDO wasn't processed yet */ +#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /** 0x06 communication info CAN receive bus is passive */ +#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /** 0x07 communication info CAN transmit bus is passive */ +#define CO_EM_NMT_WRONG_COMMAND 0x08U /** 0x08 communication info Wrong NMT command received */ +#define CO_EM_TIME_TIMEOUT 0x09U /** 0x09 communication info TIME message timeout */ +#define CO_EM_0A_unused 0x0AU /** 0x0A communication info (unused) */ +#define CO_EM_0B_unused 0x0BU /** 0x0B communication info (unused) */ +#define CO_EM_0C_unused 0x0CU /** 0x0C communication info (unused) */ +#define CO_EM_0D_unused 0x0DU /** 0x0D communication info (unused) */ +#define CO_EM_0E_unused 0x0EU /** 0x0E communication info (unused) */ +#define CO_EM_0F_unused 0x0FU /** 0x0F communication info (unused) */ + +#define CO_EM_10_unused 0x10U /** 0x10 communication critical (unused) */ +#define CO_EM_11_unused 0x11U /** 0x11 communication critical (unused) */ +#define CO_EM_CAN_TX_BUS_OFF 0x12U /** 0x12 communication critical CAN transmit bus is off */ +#define CO_EM_CAN_RXB_OVERFLOW 0x13U /** 0x13 communication critical CAN module receive buffer has overflowed */ +#define CO_EM_CAN_TX_OVERFLOW 0x14U /** 0x14 communication critical CAN transmit buffer has overflowed */ +#define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /** 0x15 communication critical TPDO is outside SYNC window */ +#define CO_EM_16_unused 0x16U /** 0x16 communication critical (unused) */ +#define CO_EM_RPDO_TIME_OUT 0x17U /** 0x17 communication critical RPDO message timeout */ +#define CO_EM_SYNC_TIME_OUT 0x18U /** 0x18 communication critical SYNC message timeout */ +#define CO_EM_SYNC_LENGTH 0x19U /** 0x19 communication critical Unexpected SYNC data length */ +#define CO_EM_PDO_WRONG_MAPPING 0x1AU /** 0x1A communication critical Error with PDO mapping */ +#define CO_EM_HEARTBEAT_CONSUMER 0x1BU /** 0x1B communication critical Heartbeat consumer timeout */ +#define CO_EM_HB_CONSUMER_REMOTE_RESET 0x1CU /** 0x1C communication critical Heartbeat consumer detected remote node reset */ +#define CO_EM_SRDO_CONFIGURATION 0x1DU /** 0x1D communication critical Error in SRDO configuration parameters. */ +#define CO_EM_1E_unused 0x1EU /** 0x1E communication critical (unused) */ +#define CO_EM_1F_unused 0x1FU /** 0x1F communication critical (unused) */ + +#define CO_EM_EMERGENCY_BUFFER_FULL 0x20U /** 0x20 generic info Emergency buffer is full Emergency message wasn't sent */ +#define CO_EM_21_unused 0x21U /** 0x21 generic info (unused) */ +#define CO_EM_MICROCONTROLLER_RESET 0x22U /** 0x22 generic info Microcontroller has just started */ +#define CO_EM_23_unused 0x23U /** 0x23 generic info (unused) */ +#define CO_EM_24_unused 0x24U /** 0x24 generic info (unused) */ +#define CO_EM_25_unused 0x25U /** 0x25 generic info (unused) */ +#define CO_EM_26_unused 0x26U /** 0x26 generic info (unused) */ +#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /** 0x27 generic info Automatic store to non-volatile memory failed */ + +#define CO_EM_WRONG_ERROR_REPORT 0x28U /** 0x28 generic critical Wrong parameters to CO_errorReport() function*/ +#define CO_EM_ISR_TIMER_OVERFLOW 0x29U /** 0x29 generic critical Timer task has overflowed */ +#define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /** 0x2A generic critical Unable to allocate memory for objects */ +#define CO_EM_GENERIC_ERROR 0x2BU /** 0x2B generic critical Generic error test usage */ +#define CO_EM_GENERIC_SOFTWARE_ERROR 0x2CU /** 0x2C generic critical Software error */ +#define CO_EM_INCONSISTENT_OBJECT_DICT 0x2DU /** 0x2D generic critical Object dictionary does not match the software*/ +#define CO_EM_CALCULATION_OF_PARAMETERS 0x2EU /** 0x2E generic critical Error in calculation of device parameters */ +#define CO_EM_NON_VOLATILE_MEMORY 0x2FU /** 0x2F generic critical Error with access to non volatile device memory */ + +/** 0x30+ manufacturer info or critical Error status buts free to use by + * manufacturer. By default bits 0x30..0x3F are set as informational and + * bits 0x40..0x4F are set as critical. Manufacturer critical bits sets the + * error register as specified by @ref CO_CONFIG_ERR_CONDITION_MANUFACTURER + */ +#define CO_EM_MANUFACTURER_START 0x30U +/** (@ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1) largest value of the Error status bit. */ +#define CO_EM_MANUFACTURER_END (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1) + +/** @} */ /* CO_EM_errorStatusBits_t */ diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index e165f2f1..61cfd4e9 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -388,7 +388,7 @@ void CO_HBconsumer_process( #endif if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) { CO_errorReport(HBcons->em, - (uint8_t)CO_EM_HB_CONSUMER_REMOTE_RESET, + CO_EM_HB_CONSUMER_REMOTE_RESET, CO_EMC_HEARTBEAT, i); } monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; @@ -425,7 +425,7 @@ void CO_HBconsumer_process( monitoredNode->functSignalObjectTimeout); } #endif - CO_errorReport(HBcons->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, + CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, i); monitoredNode->NMTstate = CO_NMT_UNKNOWN; monitoredNode->HBstate = CO_HBconsumer_TIMEOUT; @@ -492,8 +492,8 @@ void CO_HBconsumer_process( /* Clear emergencies when all monitored nodes becomes active. * We only have one emergency index for all monitored nodes! */ if (!HBcons->allMonitoredActive && allMonitoredActiveCurrent) { - CO_errorReset(HBcons->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, 0); - CO_errorReset(HBcons->em, (uint8_t)CO_EM_HB_CONSUMER_REMOTE_RESET, 0); + CO_errorReset(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, 0); + CO_errorReset(HBcons->em, CO_EM_HB_CONSUMER_REMOTE_RESET, 0); } HBcons->allMonitoredActive = allMonitoredActiveCurrent; diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 0dc12e75..14480412 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -229,7 +229,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, if (ngs->lifeTimeTimeout) { /* error bit is shared with HB consumer */ - CO_errorReset(ngs->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, 0); + CO_errorReset(ngs->em, CO_EM_HEARTBEAT_CONSUMER, 0); ngs->lifeTimeTimeout = false; } @@ -252,7 +252,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, ngs->lifeTimeTimeout = true; /* error bit is shared with HB consumer */ - CO_errorReport(ngs->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, + CO_errorReport(ngs->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, 0); } } @@ -415,12 +415,12 @@ void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, if (!node->responseRecived) { node->monitoringActive = false; /* error bit is shared with HB consumer */ - CO_errorReport(ngm->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, + CO_errorReport(ngm->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, node->ident & 0x7F); } else if (node->NMTstate != CO_NMT_UNKNOWN) { node->monitoringActive = true; - CO_errorReset(ngm->em, (uint8_t)CO_EM_HEARTBEAT_CONSUMER, + CO_errorReset(ngm->em, CO_EM_HEARTBEAT_CONSUMER, node->ident & 0x7F); } } diff --git a/301/CO_PDO.c b/301/CO_PDO.c index cdb63114..52f5bbc1 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -692,7 +692,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, if (erroneousMap != 0U) { CO_errorReport(PDO->em, - (uint8_t)CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, + CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, (erroneousMap != 1U) ? erroneousMap : COB_ID); } if (!valid) { @@ -888,7 +888,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, if (RPDO->timeoutTime_us > 0U) { if (rpdoReceived) { if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { - CO_errorReset(PDO->em, (uint8_t)CO_EM_RPDO_TIME_OUT, + CO_errorReset(PDO->em, CO_EM_RPDO_TIME_OUT, RPDO->timeoutTimer); } /* enable monitoring */ @@ -900,7 +900,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, RPDO->timeoutTimer += timeDifference_us; if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { - CO_errorReport(PDO->em, (uint8_t)CO_EM_RPDO_TIME_OUT, + CO_errorReport(PDO->em, CO_EM_RPDO_TIME_OUT, CO_EMC_RPDO_TIMEOUT, RPDO->timeoutTimer); } } @@ -1156,7 +1156,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, if (erroneousMap != 0U) { CO_errorReport(PDO->em, - (uint8_t)CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, + CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, (erroneousMap != 1U) ? erroneousMap : COB_ID); } if (!valid) { diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 1c74de13..b1da86ca 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -417,7 +417,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, } if (SYNC->timer > periodTimeout) { - CO_errorReport(SYNC->em, (uint8_t)CO_EM_SYNC_TIME_OUT, + CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); SYNC->timeoutError = 2; } @@ -448,7 +448,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, /* verify error from receive function */ if (SYNC->receiveError != 0U) { - CO_errorReport(SYNC->em, (uint8_t)CO_EM_SYNC_LENGTH, + CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, CO_EMC_SYNC_DATA_LENGTH, SYNC->receiveError); SYNC->receiveError = 0; } @@ -462,7 +462,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, if (syncStatus == CO_SYNC_RX_TX) { if (SYNC->timeoutError == 2U) { - CO_errorReset(SYNC->em, (uint8_t)CO_EM_SYNC_TIME_OUT, 0); + CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, 0); } SYNC->timeoutError = 1; } diff --git a/301/CO_driver.h b/301/CO_driver.h index 6c344810..794415f5 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -516,28 +516,25 @@ typedef enum { /** - * CAN error status bitmasks. + * @defgroup CO_CAN_ERR_status_t CAN error status bitmasks + * @{ * * CAN warning level is reached, if CAN transmit or receive error counter is * more or equal to 96. CAN passive level is reached, if counters are more or * equal to 128. Transmitter goes in error state 'bus off' if transmit error * counter is more or equal to 256. */ -typedef enum { - CO_CAN_ERRTX_WARNING = 0x0001U, /**< 0x0001, CAN transmitter warning */ - CO_CAN_ERRTX_PASSIVE = 0x0002U, /**< 0x0002, CAN transmitter passive */ - CO_CAN_ERRTX_BUS_OFF = 0x0004U, /**< 0x0004, CAN transmitter bus off */ - CO_CAN_ERRTX_OVERFLOW = 0x0008U, /**< 0x0008, CAN transmitter overflow */ - - CO_CAN_ERRTX_PDO_LATE = 0x0080U, /**< 0x0080, TPDO is outside sync window */ - - CO_CAN_ERRRX_WARNING = 0x0100U, /**< 0x0100, CAN receiver warning */ - CO_CAN_ERRRX_PASSIVE = 0x0200U, /**< 0x0200, CAN receiver passive */ - CO_CAN_ERRRX_OVERFLOW = 0x0800U, /**< 0x0800, CAN receiver overflow */ - - CO_CAN_ERR_WARN_PASSIVE = 0x0303U/**< 0x0303, combination */ -} CO_CAN_ERR_status_t; - +#define CO_CAN_ERRTX_WARNING 0x0001U /**< 0x0001 CAN transmitter warning */ +#define CO_CAN_ERRTX_PASSIVE 0x0002U /**< 0x0002 CAN transmitter passive */ +#define CO_CAN_ERRTX_BUS_OFF 0x0004U /**< 0x0004 CAN transmitter bus off */ +#define CO_CAN_ERRTX_OVERFLOW 0x0008U /**< 0x0008 CAN transmitter overflow */ +#define CO_CAN_ERRTX_PDO_LATE 0x0080U /**< 0x0080 TPDO is outside sync window */ +#define CO_CAN_ERRRX_WARNING 0x0100U /**< 0x0100 CAN receiver warning */ +#define CO_CAN_ERRRX_PASSIVE 0x0200U /**< 0x0200 CAN receiver passive */ +#define CO_CAN_ERRRX_OVERFLOW 0x0800U /**< 0x0800 CAN receiver overflow */ +#define CO_CAN_ERR_WARN_PASSIVE 0x0303U /**< 0x0303 combination */ + +/** @} */ /* CO_CAN_ERR_status_t */ /** * Return values of some CANopen functions. If function was executed diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 7c53c5a6..f8b4d610 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -704,7 +704,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } else { if (ret == CO_ERROR_NO) { - CO_errorReport(em, (uint8_t)CO_EM_SRDO_CONFIGURATION, CO_EMC_DATA_SET, err); + CO_errorReport(em, CO_EM_SRDO_CONFIGURATION, CO_EMC_DATA_SET, err); configurationValidUnset(SRDO->SRDOGuard); } } @@ -869,7 +869,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext else { /* CO_SRDO_RX */ /* verify error from receive function */ if (SRDO->rxSrdoShort) { - CO_errorReport(SRDO->em, (uint8_t)CO_EM_RPDO_WRONG_LENGTH, CO_EMC_PDO_LENGTH, 0); + CO_errorReport(SRDO->em, CO_EM_RPDO_WRONG_LENGTH, CO_EMC_PDO_LENGTH, 0); SRDO->internalState = CO_SRDO_state_error_rxShort; } else if (CO_FLAG_READ(SRDO->CANrxNew[SRDO->nextIsNormal ? 0 : 1])) { diff --git a/CANopen.c b/CANopen.c index 68f70390..ed3317dc 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1443,8 +1443,8 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, timeDifference_us, unc ? CO_NMT_INITIALIZING : NMTstate, LSSslave_configuration, - (CANerrorStatus & (uint16_t)CO_CAN_ERRTX_BUS_OFF) != 0U, - (CANerrorStatus & (uint16_t)CO_CAN_ERR_WARN_PASSIVE) != 0U, + (CANerrorStatus & CO_CAN_ERRTX_BUS_OFF) != 0U, + (CANerrorStatus & CO_CAN_ERR_WARN_PASSIVE) != 0U, false, /* RPDO event timer timeout */ unc ? false : CO_isError(co->em, CO_EM_SYNC_TIME_OUT), unc ? false : (CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) From 691728f71a145f3e0e014612c873aadd504df208 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 13:57:42 +0200 Subject: [PATCH 290/520] static analysis: essential type of condition of 'if' statement is in not correct [MISRA 2012 Rule 14.4, required] --- 301/CO_Emergency.c | 14 +++++++------- 301/CO_SDOserver.c | 6 +++--- CANopen.c | 24 ++++++++++++------------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 8410ba01..d7f5e5a1 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -564,32 +564,32 @@ void CO_EM_process(CO_EM_t *em, uint16_t CANerrStChanged = CANerrSt ^ em->CANerrorStatusOld; em->CANerrorStatusOld = CANerrSt; - if (CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) { + if ((CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0U) { CO_error(em, (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0U, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, 0); } - if (CANerrStChanged & CO_CAN_ERRTX_PASSIVE) { + if ((CANerrStChanged & CO_CAN_ERRTX_PASSIVE) != 0U) { CO_error(em, (CANerrSt & CO_CAN_ERRTX_PASSIVE) != 0U, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); } - if (CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) { + if ((CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) != 0U) { CO_error(em, (CANerrSt & CO_CAN_ERRTX_BUS_OFF) != 0U, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, 0); } - if (CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) { + if ((CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) != 0U) { CO_error(em, (CANerrSt & CO_CAN_ERRTX_OVERFLOW) != 0U, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } - if (CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) { + if ((CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) != 0U) { CO_error(em, (CANerrSt & CO_CAN_ERRTX_PDO_LATE) != 0U, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, 0); } - if (CANerrStChanged & CO_CAN_ERRRX_PASSIVE) { + if ((CANerrStChanged & CO_CAN_ERRRX_PASSIVE) != 0U) { CO_error(em, (CANerrSt & CO_CAN_ERRRX_PASSIVE) != 0U, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); } - if (CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) { + if ((CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) != 0U) { CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0U, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index d734973b..bde52891 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -809,7 +809,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if ((SDO->state != CO_SDO_ST_IDLE) && (SDO->state != CO_SDO_ST_ABORT)) { switch (SDO->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { - if (SDO->CANrxData[0] & 0x02U) { + if ((SDO->CANrxData[0] & 0x02U) != 0U) { /* Expedited transfer, max 4 bytes of data */ /* Size of OD variable (>0 if indicated) */ @@ -817,7 +817,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Get SDO data size (indicated by SDO client or get from OD) */ OD_size_t dataSizeToWrite = 4; - if (SDO->CANrxData[0] & 0x01U) { + if ((SDO->CANrxData[0] & 0x01U) != 0U) { dataSizeToWrite -= (SDO->CANrxData[0] >> 2) & 0x03U; } else if ((sizeInOd > 0U) && (sizeInOd < 4U)) { @@ -880,7 +880,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, else { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /* segmented transfer, is size indicated? */ - if (SDO->CANrxData[0] & 0x01U) { + if ((SDO->CANrxData[0] & 0x01U) != 0U) { uint32_t size; OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; diff --git a/CANopen.c b/CANopen.c index ed3317dc..ced4f9da 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1000,7 +1000,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 if (CO_GET_CNT(LEDS) == 1U) { err = CO_LEDs_init(co->LEDs); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } #endif @@ -1037,7 +1037,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif nodeId, errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } /* NMT_Heartbeat */ @@ -1060,7 +1060,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(TX_IDX_HB_PROD), (uint16_t)CO_CAN_ID_HEARTBEAT + nodeId, errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 @@ -1073,7 +1073,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(RX_IDX_HB_CONS), errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } #endif @@ -1088,7 +1088,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_NG_SLV), errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } #endif #if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 err = CO_nodeGuardingMaster_init(co->NGmaster, @@ -1114,7 +1114,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_SDO_SRV) + i, errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } } @@ -1147,7 +1147,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(TX_IDX_TIME), #endif errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } #endif @@ -1166,7 +1166,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(TX_IDX_SYNC), #endif errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } #endif @@ -1278,7 +1278,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, co->CANmodule, CO_GET_CO(RX_IDX_RPDO) + i, errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } } #endif @@ -1312,7 +1312,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_TPDO) + i, errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } } #endif @@ -1360,7 +1360,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, OD_GET(H13FE, OD_H13FE_SRDO_VALID), OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); OD_entry_t *SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); @@ -1388,7 +1388,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, CANdevTxIdx, CANdevTxIdx + 1U, errInfo); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } CO_SRDO_init_end(co->SRDOGuard); From 686ab04ee9c1dd2dd7cd1eb9a08dc1342c8bdf12 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 14:26:51 +0200 Subject: [PATCH 291/520] static analysis: enumerator 'CO_CAN_ID_EMERGENCY' reuses the constant value '128' previously used by enumerator 'CO_CAN_ID_SYNC' refactoring changed enum with define --- 301/CO_Emergency.c | 4 ++-- 301/CO_SDOserver.c | 8 ++++---- 301/CO_driver.h | 45 +++++++++++++++++++++++---------------------- CANopen.c | 10 +++++----- 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index d7f5e5a1..d34c867b 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -138,7 +138,7 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0U : 0x80000000U; - COB_IDEmergency32 |= (uint32_t)CO_CAN_ID_EMERGENCY + em->nodeId; + COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + em->nodeId; (void)CO_setUint32(buf, COB_IDEmergency32); *countRead = sizeof(uint32_t); @@ -441,7 +441,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, * to add nodeId of this node to the stored value. */ if (producerCanId == CO_CAN_ID_EMERGENCY) producerCanId += nodeId; #else - uint32_t producerCanId = (uint32_t)CO_CAN_ID_EMERGENCY + nodeId; + uint32_t producerCanId = CO_CAN_ID_EMERGENCY + nodeId; em->producerEnabled = (COB_IDEmergency32 & 0x80000000U) == 0U; em->OD_1014_extension.object = em; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index bde52891..2c4ae11a 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -352,8 +352,8 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, /* configure default SDO channel */ if ((nodeId < 1U) || (nodeId > 127U)) { return CO_ERROR_ILLEGAL_ARGUMENT; } - CanId_ClientToServer = (uint16_t)CO_CAN_ID_SDO_CLI + nodeId; - CanId_ServerToClient = (uint16_t)CO_CAN_ID_SDO_SRV + nodeId; + CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; + CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; } else { @@ -365,8 +365,8 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, return CO_ERROR_ILLEGAL_ARGUMENT; } - CanId_ClientToServer = (uint16_t)CO_CAN_ID_SDO_CLI + nodeId; - CanId_ServerToClient = (uint16_t)CO_CAN_ID_SDO_SRV + nodeId; + CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; + CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; (void)OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); diff --git a/301/CO_driver.h b/301/CO_driver.h index 794415f5..00364be9 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -469,34 +469,35 @@ typedef struct { /** - * Default CANopen identifiers. + * @defgroup CO_Default_CAN_ID_t Default CANopen identifiers + * @{ * * Default CANopen identifiers for CANopen communication objects. Same as * 11-bit addresses of CAN messages. These are default identifiers and * can be changed in CANopen. Especially PDO identifiers are configured * in PDO linking phase of the CANopen network configuration. */ -typedef enum { - CO_CAN_ID_NMT_SERVICE = 0x000U, /**< 0x000, Network management */ - CO_CAN_ID_GFC = 0x001U, /**< 0x001, Global fail-safe command */ - CO_CAN_ID_SYNC = 0x080U, /**< 0x080, Synchronous message */ - CO_CAN_ID_EMERGENCY = 0x080U, /**< 0x080, Emergency messages (+nodeID) */ - CO_CAN_ID_TIME = 0x100U, /**< 0x100, Time message */ - CO_CAN_ID_SRDO_1 = 0x0FFU, /**< 0x0FF, Default SRDO1 (+2*nodeID) */ - CO_CAN_ID_TPDO_1 = 0x180U, /**< 0x180, Default TPDO1 (+nodeID) */ - CO_CAN_ID_RPDO_1 = 0x200U, /**< 0x200, Default RPDO1 (+nodeID) */ - CO_CAN_ID_TPDO_2 = 0x280U, /**< 0x280, Default TPDO2 (+nodeID) */ - CO_CAN_ID_RPDO_2 = 0x300U, /**< 0x300, Default RPDO2 (+nodeID) */ - CO_CAN_ID_TPDO_3 = 0x380U, /**< 0x380, Default TPDO3 (+nodeID) */ - CO_CAN_ID_RPDO_3 = 0x400U, /**< 0x400, Default RPDO3 (+nodeID) */ - CO_CAN_ID_TPDO_4 = 0x480U, /**< 0x480, Default TPDO4 (+nodeID) */ - CO_CAN_ID_RPDO_4 = 0x500U, /**< 0x500, Default RPDO5 (+nodeID) */ - CO_CAN_ID_SDO_SRV = 0x580U, /**< 0x580, SDO response from server (+nodeID) */ - CO_CAN_ID_SDO_CLI = 0x600U, /**< 0x600, SDO request from client (+nodeID) */ - CO_CAN_ID_HEARTBEAT = 0x700U, /**< 0x700, Heartbeat message */ - CO_CAN_ID_LSS_SLV = 0x7E4U, /**< 0x7E4, LSS response from slave */ - CO_CAN_ID_LSS_MST = 0x7E5U /**< 0x7E5, LSS request from master */ -} CO_Default_CAN_ID_t; +#define CO_CAN_ID_NMT_SERVICE 0x000U /**< 0x000 Network management */ +#define CO_CAN_ID_GFC 0x001U /**< 0x001 Global fail-safe command */ +#define CO_CAN_ID_SYNC 0x080U /**< 0x080 Synchronous message */ +#define CO_CAN_ID_EMERGENCY 0x080U /**< 0x080 Emergency messages (+nodeID) */ +#define CO_CAN_ID_TIME 0x100U /**< 0x100 Time message */ +#define CO_CAN_ID_SRDO_1 0x0FFU /**< 0x0FF Default SRDO1 (+2*nodeID) */ +#define CO_CAN_ID_TPDO_1 0x180U /**< 0x180 Default TPDO1 (+nodeID) */ +#define CO_CAN_ID_RPDO_1 0x200U /**< 0x200 Default RPDO1 (+nodeID) */ +#define CO_CAN_ID_TPDO_2 0x280U /**< 0x280 Default TPDO2 (+nodeID) */ +#define CO_CAN_ID_RPDO_2 0x300U /**< 0x300 Default RPDO2 (+nodeID) */ +#define CO_CAN_ID_TPDO_3 0x380U /**< 0x380 Default TPDO3 (+nodeID) */ +#define CO_CAN_ID_RPDO_3 0x400U /**< 0x400 Default RPDO3 (+nodeID) */ +#define CO_CAN_ID_TPDO_4 0x480U /**< 0x480 Default TPDO4 (+nodeID) */ +#define CO_CAN_ID_RPDO_4 0x500U /**< 0x500 Default RPDO5 (+nodeID) */ +#define CO_CAN_ID_SDO_SRV 0x580U /**< 0x580 SDO response from server (+nodeID) */ +#define CO_CAN_ID_SDO_CLI 0x600U /**< 0x600 SDO request from client (+nodeID) */ +#define CO_CAN_ID_HEARTBEAT 0x700U /**< 0x700 Heartbeat message */ +#define CO_CAN_ID_LSS_SLV 0x7E4U /**< 0x7E4 LSS response from slave */ +#define CO_CAN_ID_LSS_MST 0x7E5U /**< 0x7E5 LSS request from master */ + +/** @} */ /* CO_Default_CAN_ID_t */ /** diff --git a/CANopen.c b/CANopen.c index ced4f9da..97ecd8e8 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1058,7 +1058,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif co->CANmodule, CO_GET_CO(TX_IDX_HB_PROD), - (uint16_t)CO_CAN_ID_HEARTBEAT + nodeId, + CO_CAN_ID_HEARTBEAT + nodeId, errInfo); if (err != CO_ERROR_NO) { return err; } } @@ -1082,7 +1082,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, OD_GET(H100C, OD_H100C_GUARD_TIME), OD_GET(H100D, OD_H100D_LIFETIME_FACTOR), em, - (uint16_t)CO_CAN_ID_HEARTBEAT + nodeId, + CO_CAN_ID_HEARTBEAT + nodeId, co->CANmodule, CO_GET_CO(RX_IDX_NG_SLV), co->CANmodule, @@ -1258,7 +1258,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, uint16_t preDefinedCanId = 0; if (i < CO_RPDO_DEFAULT_CANID_COUNT) { #if CO_RPDO_DEFAULT_CANID_COUNT <= 4 - preDefinedCanId = ((uint16_t)CO_CAN_ID_RPDO_1 + (i * 0x100U)) + nodeId; + preDefinedCanId = (CO_CAN_ID_RPDO_1 + (i * 0x100U)) + nodeId; #else uint16_t pdoOffset = i % 4; uint16_t nodeIdOffset = i / 4; @@ -1292,7 +1292,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, uint16_t preDefinedCanId = 0; if (i < CO_TPDO_DEFAULT_CANID_COUNT) { #if CO_TPDO_DEFAULT_CANID_COUNT <= 4 - preDefinedCanId = ((uint16_t)CO_CAN_ID_TPDO_1 + (i * 0x100U)) + nodeId; + preDefinedCanId = (CO_CAN_ID_TPDO_1 + (i * 0x100U)) + nodeId; #else uint16_t pdoOffset = i % 4; uint16_t nodeIdOffset = i / 4; @@ -1374,7 +1374,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, od, em, nodeId, - ((i == 0U) ? (uint16_t)CO_CAN_ID_SRDO_1 : 0U), + ((i == 0U) ? CO_CAN_ID_SRDO_1 : 0U), SRDOcomm++, SRDOmap++, OD_GET(H13FE, OD_H13FE_SRDO_VALID), From cff7a3cf5abf82ec2baf1c09952e8953469228f3 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 14:35:37 +0200 Subject: [PATCH 292/520] static analysis: refactoring changed enum with define to be able to use bitwise operators on user space --- 301/CO_NMT_Heartbeat.c | 2 +- 301/CO_NMT_Heartbeat.h | 53 ++++++++++++++++++++++-------------------- CANopen.c | 2 +- CANopen.h | 2 +- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index e9ba9662..ac5377f5 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -84,7 +84,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, OD_entry_t *OD_1017_ProducerHbTime, CO_EM_t *em, uint8_t nodeId, - CO_NMT_control_t NMTcontrol, + uint16_t NMTcontrol, uint16_t firstHBTime_ms, CO_CANmodule_t *NMT_CANdevRx, uint16_t NMT_rxIdx, diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index eb33ea7b..ec319808 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -125,7 +125,9 @@ typedef enum { /** - * NMT control bitfield for NMT internal state. + * @defgroup CO_NMT_control_t NMT control bitfield for NMT internal state. + * @{ + * * * Variable of this type is passed to @ref CO_NMT_init() function. It * controls behavior of the @ref CO_NMT_internalState_t of the device according @@ -134,28 +136,29 @@ typedef enum { * Internal NMT state is controlled also with external NMT command, * @ref CO_NMT_sendInternalCommand() or @ref CO_NMT_sendCommand() functions. */ -typedef enum { - /** First 8 bits can be used to specify bitmask for the - * @ref CO_errorRegister_t, to get relevant bits for the calculation. */ - CO_NMT_ERR_REG_MASK = 0x00FFU, - /** If bit is set, then device enters NMT operational state after the - * initialization phase, otherwise it enters NMT pre-operational state. */ - CO_NMT_STARTUP_TO_OPERATIONAL = 0x0100U, - /** If bit is set and device is operational, it enters NMT pre-operational - * or stopped state, if CAN bus is off or heartbeat consumer timeout is - * detected. */ - CO_NMT_ERR_ON_BUSOFF_HB = 0x1000U, - /** If bit is set and device is operational, it enters NMT pre-operational - * or stopped state, if masked CANopen error register is different than - * zero. */ - CO_NMT_ERR_ON_ERR_REG = 0x2000U, - /** If bit is set and CO_NMT_ERR_ON_xx condition is met, then device will - * enter NMT stopped state, otherwise it will enter NMT pre-op state. */ - CO_NMT_ERR_TO_STOPPED = 0x4000U, - /** If bit is set and device is pre-operational, it enters NMT operational - * state automatically, if conditions from CO_NMT_ERR_ON_xx are all false.*/ - CO_NMT_ERR_FREE_TO_OPERATIONAL = 0x8000U -} CO_NMT_control_t; + +/** First 8 bits can be used to specify bitmask for the + * @ref CO_errorRegister_t to get relevant bits for the calculation. */ +#define CO_NMT_ERR_REG_MASK 0x00FFU +/** If bit is set then device enters NMT operational state after the + * initialization phase otherwise it enters NMT pre-operational state. */ +#define CO_NMT_STARTUP_TO_OPERATIONAL 0x0100U +/** If bit is set and device is operational it enters NMT pre-operational + * or stopped state if CAN bus is off or heartbeat consumer timeout is + * detected. */ +#define CO_NMT_ERR_ON_BUSOFF_HB 0x1000U +/** If bit is set and device is operational it enters NMT pre-operational + * or stopped state if masked CANopen error register is different than + * zero. */ +#define CO_NMT_ERR_ON_ERR_REG 0x2000U +/** If bit is set and CO_NMT_ERR_ON_xx condition is met then device will + * enter NMT stopped state otherwise it will enter NMT pre-op state. */ +#define CO_NMT_ERR_TO_STOPPED 0x4000U +/** If bit is set and device is pre-operational it enters NMT operational + * state automatically if conditions from CO_NMT_ERR_ON_xx are all false.*/ +#define CO_NMT_ERR_FREE_TO_OPERATIONAL 0x8000U + +/** @} */ /* CO_NMT_control_t */ /** @@ -172,7 +175,7 @@ typedef struct { /** From CO_NMT_init() */ uint8_t nodeId; /** From CO_NMT_init() */ - CO_NMT_control_t NMTcontrol; + uint16_t NMTcontrol; /** Producer heartbeat time, calculated from OD 0x1017 */ uint32_t HBproducerTime_us; /** Internal timer for HB producer */ @@ -237,7 +240,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, OD_entry_t *OD_1017_ProducerHbTime, CO_EM_t *em, uint8_t nodeId, - CO_NMT_control_t NMTcontrol, + uint16_t NMTcontrol, uint16_t firstHBTime_ms, CO_CANmodule_t *NMT_CANdevRx, uint16_t NMT_rxIdx, diff --git a/CANopen.c b/CANopen.c index 97ecd8e8..f54dc9cf 100644 --- a/CANopen.c +++ b/CANopen.c @@ -958,7 +958,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_EM_t *em, OD_t *od, OD_entry_t *OD_statusBits, - CO_NMT_control_t NMTcontrol, + uint16_t NMTcontrol, uint16_t firstHBTime_ms, uint16_t SDOserverTimeoutTime_ms, uint16_t SDOclientTimeoutTime_ms, diff --git a/CANopen.h b/CANopen.h index 5018ac3d..780a1e13 100644 --- a/CANopen.h +++ b/CANopen.h @@ -544,7 +544,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_EM_t *em, OD_t *od, OD_entry_t *OD_statusBits, - CO_NMT_control_t NMTcontrol, + uint16_t NMTcontrol, uint16_t firstHBTime_ms, uint16_t SDOserverTimeoutTime_ms, uint16_t SDOclientTimeoutTime_ms, From 20fa24abf742eda85618fc732fd65e565a22cde4 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 14:57:53 +0200 Subject: [PATCH 293/520] CANopen: static analysis: locals not referenced [MISRA 2012 Rule 2.5, advisory] --- CANopen.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CANopen.c b/CANopen.c index f54dc9cf..8ac8ba64 100644 --- a/CANopen.c +++ b/CANopen.c @@ -90,10 +90,10 @@ #if OD_CNT_EM != 1 #error OD_CNT_EM from OD.h not correct! #endif -#ifndef OD_ENTRY_H1003 + #if (!defined OD_ENTRY_H1003) && (defined CO_MULTIPLE_OD) #define OD_ENTRY_H1003 NULL #endif -#ifndef OD_CNT_ARR_1003 + #if (!defined OD_CNT_ARR_1003) && (defined CO_MULTIPLE_OD) #define OD_CNT_ARR_1003 8 #endif #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 @@ -102,7 +102,7 @@ #else #error wrong OD_CNT_EM_PROD #endif - #ifndef OD_ENTRY_H1015 + #if (!defined OD_ENTRY_H1015) && (defined CO_MULTIPLE_OD) #define OD_ENTRY_H1015 NULL #endif #else @@ -169,10 +169,10 @@ #else #define CO_TX_CNT_SYNC 0 #endif - #ifndef OD_ENTRY_H1007 + #if (!defined OD_ENTRY_H1007) && (defined CO_MULTIPLE_OD) #define OD_ENTRY_H1007 NULL #endif - #ifndef OD_ENTRY_H1019 + #if (!defined OD_ENTRY_H1019) && (defined CO_MULTIPLE_OD) #define OD_ENTRY_H1019 NULL #endif #else From 73a65dbfea4eb2853d580f0f6bc26ec5861947d0 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 14:59:34 +0200 Subject: [PATCH 294/520] Revert "CANopen: static analysis: locals not referenced [MISRA 2012 Rule 2.5, advisory]" This reverts commit 20fa24abf742eda85618fc732fd65e565a22cde4. --- CANopen.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CANopen.c b/CANopen.c index 8ac8ba64..f54dc9cf 100644 --- a/CANopen.c +++ b/CANopen.c @@ -90,10 +90,10 @@ #if OD_CNT_EM != 1 #error OD_CNT_EM from OD.h not correct! #endif - #if (!defined OD_ENTRY_H1003) && (defined CO_MULTIPLE_OD) +#ifndef OD_ENTRY_H1003 #define OD_ENTRY_H1003 NULL #endif - #if (!defined OD_CNT_ARR_1003) && (defined CO_MULTIPLE_OD) +#ifndef OD_CNT_ARR_1003 #define OD_CNT_ARR_1003 8 #endif #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 @@ -102,7 +102,7 @@ #else #error wrong OD_CNT_EM_PROD #endif - #if (!defined OD_ENTRY_H1015) && (defined CO_MULTIPLE_OD) + #ifndef OD_ENTRY_H1015 #define OD_ENTRY_H1015 NULL #endif #else @@ -169,10 +169,10 @@ #else #define CO_TX_CNT_SYNC 0 #endif - #if (!defined OD_ENTRY_H1007) && (defined CO_MULTIPLE_OD) + #ifndef OD_ENTRY_H1007 #define OD_ENTRY_H1007 NULL #endif - #if (!defined OD_ENTRY_H1019) && (defined CO_MULTIPLE_OD) + #ifndef OD_ENTRY_H1019 #define OD_ENTRY_H1019 NULL #endif #else From 8c06bec4c9ab36d535ee14d7ae1dde2a88542c75 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 15:08:54 +0200 Subject: [PATCH 295/520] CANopen: static analysis increment operation combined with other operation with side-effects [MISRA 2012 Rule 13.3, advisory] --- CANopen.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/CANopen.c b/CANopen.c index f54dc9cf..ccdece70 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1106,7 +1106,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, for (uint16_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { err = CO_SDOserver_init(&co->SDOserver[i], od, - SDOsrvPar++, + SDOsrvPar, nodeId, SDOserverTimeoutTime_ms, co->CANmodule, @@ -1115,6 +1115,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(TX_IDX_SDO_SRV) + i, errInfo); if (err != CO_ERROR_NO) { return err; } + SDOsrvPar++; } } @@ -1273,12 +1274,14 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, co->SYNC, #endif preDefinedCanId, - RPDOcomm++, - RPDOmap++, + RPDOcomm, + RPDOmap, co->CANmodule, CO_GET_CO(RX_IDX_RPDO) + i, errInfo); if (err != CO_ERROR_NO) { return err; } + RPDOcomm++; + RPDOmap++; } } #endif @@ -1307,12 +1310,14 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, co->SYNC, #endif preDefinedCanId, - TPDOcomm++, - TPDOmap++, + TPDOcomm, + TPDOmap, co->CANmodule, CO_GET_CO(TX_IDX_TPDO) + i, errInfo); if (err != CO_ERROR_NO) { return err; } + TPDOcomm++; + TPDOmap++; } } #endif @@ -1375,8 +1380,8 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, em, nodeId, ((i == 0U) ? CO_CAN_ID_SRDO_1 : 0U), - SRDOcomm++, - SRDOmap++, + SRDOcomm, + SRDOmap, OD_GET(H13FE, OD_H13FE_SRDO_VALID), OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), co->CANmodule, @@ -1389,6 +1394,8 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, CANdevTxIdx + 1U, errInfo); if (err != CO_ERROR_NO) { return err; } + SRDOcomm++; + SRDOmap++; } CO_SRDO_init_end(co->SRDOGuard); From 704bc17b1ee72a0f2f87f735c52f1f9d305b78a2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 15:15:02 +0200 Subject: [PATCH 296/520] CANopen:static analysis possible loss of precision (assignment) --- CANopen.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CANopen.c b/CANopen.c index ccdece70..46d940cd 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1259,7 +1259,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, uint16_t preDefinedCanId = 0; if (i < CO_RPDO_DEFAULT_CANID_COUNT) { #if CO_RPDO_DEFAULT_CANID_COUNT <= 4 - preDefinedCanId = (CO_CAN_ID_RPDO_1 + (i * 0x100U)) + nodeId; + preDefinedCanId = (uint16_t)((CO_CAN_ID_RPDO_1 + (i * 0x100U)) + nodeId); #else uint16_t pdoOffset = i % 4; uint16_t nodeIdOffset = i / 4; @@ -1295,7 +1295,7 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, uint16_t preDefinedCanId = 0; if (i < CO_TPDO_DEFAULT_CANID_COUNT) { #if CO_TPDO_DEFAULT_CANID_COUNT <= 4 - preDefinedCanId = (CO_CAN_ID_TPDO_1 + (i * 0x100U)) + nodeId; + preDefinedCanId = (uint16_t)((CO_CAN_ID_TPDO_1 + (i * 0x100U)) + nodeId); #else uint16_t pdoOffset = i % 4; uint16_t nodeIdOffset = i / 4; @@ -1369,9 +1369,9 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); OD_entry_t *SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); - for (uint16_t i = 0; i < CO_GET_CNT(SRDO); i++) { - uint16_t CANdevRxIdx = CO_GET_CO(RX_IDX_SRDO) + (2U * i); - uint16_t CANdevTxIdx = CO_GET_CO(TX_IDX_SRDO) + (2U * i); + for (uint8_t i = 0; i < CO_GET_CNT(SRDO); i++) { + uint16_t CANdevRxIdx = (uint16_t)(CO_GET_CO(RX_IDX_SRDO) + (2U * i)); + uint16_t CANdevTxIdx = (uint16_t)(CO_GET_CO(TX_IDX_SRDO) + (2U * i)); err = CO_SRDO_init(&co->SRDO[i], i, From 0f06b1022dcafaf7d3b3cf6c33d2b5bf152a327b Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 16:23:04 +0200 Subject: [PATCH 297/520] CANopen:static analysis: right operand to + is a composite expression of type 'unsigned8' which is smaller than the left operand of type 'unsigned16' [MISRA 2012 Rule 10.7, required] --- CANopen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CANopen.c b/CANopen.c index 46d940cd..561f5b78 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1370,8 +1370,8 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); OD_entry_t *SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); for (uint8_t i = 0; i < CO_GET_CNT(SRDO); i++) { - uint16_t CANdevRxIdx = (uint16_t)(CO_GET_CO(RX_IDX_SRDO) + (2U * i)); - uint16_t CANdevTxIdx = (uint16_t)(CO_GET_CO(TX_IDX_SRDO) + (2U * i)); + uint16_t CANdevRxIdx = (uint16_t)(CO_GET_CO(RX_IDX_SRDO) + ((uint16_t)(i) * 2U)); + uint16_t CANdevTxIdx = (uint16_t)(CO_GET_CO(TX_IDX_SRDO) + ((uint16_t)(i) * 2U)); err = CO_SRDO_init(&co->SRDO[i], i, From 24065d5751809357467f4076074b364411b6f99d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 16:29:47 +0200 Subject: [PATCH 298/520] CANopen: static analysis: cannot assign 'unsigned16' to narrower essential type 'unsigned8' [MISRA 2012 Rule 10.3, required] --- CANopen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CANopen.c b/CANopen.c index 561f5b78..1e8fd9e0 100644 --- a/CANopen.c +++ b/CANopen.c @@ -34,7 +34,7 @@ #else #include "OD.h" #define CO_GET_CO(obj) ((uint16_t)(CO_##obj)) -#define CO_GET_CNT(obj) ((uint16_t)(OD_CNT_##obj)) +#define CO_GET_CNT(obj) (uint8_t)(OD_CNT_##obj) #define OD_GET(entry, index) OD_ENTRY_##entry /* Verify parameters from "OD.h" and calculate necessary values for each object: From 308f32ee8b185da4657f48eff643683df60c5576 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 16:34:56 +0200 Subject: [PATCH 299/520] CANopen: static analysis: both sides have side effects [MISRA 2012 Rule 1.3, required] --- CANopen.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CANopen.c b/CANopen.c index 1e8fd9e0..3e7ce7ce 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1434,10 +1434,10 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, uint16_t CANerrorStatus = co->CANmodule->CANerrorStatus; bool_t LSSslave_configuration = false; #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 - if ((CO_GET_CNT(LSS_SLV) == 1U) - && (CO_LSSslave_getState(co->LSSslave) == CO_LSS_STATE_CONFIGURATION) - ) { - LSSslave_configuration = true; + if (CO_GET_CNT(LSS_SLV) == 1U) { + if (CO_LSSslave_getState(co->LSSslave) == CO_LSS_STATE_CONFIGURATION) { + LSSslave_configuration = true; + } } #endif /* default macro, can be defined externally */ From 4cee088192369edfb87b61e09eee9e3bd90eac3f Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 16:36:20 +0200 Subject: [PATCH 300/520] CANopen: static analysis: named parameter 'OD_statusBits' of 'non-virtual' function 'CO_CANopenInit' not subsequently referenced [MISRA 2012 Rule 2.7, advisory] --- CANopen.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CANopen.c b/CANopen.c index 3e7ce7ce..eceffb82 100644 --- a/CANopen.c +++ b/CANopen.c @@ -968,6 +968,10 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, { (void)SDOclientTimeoutTime_ms; (void)SDOclientBlockTransfer; CO_ReturnError_t err; + + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) == 0 + (void)OD_statusBits; /* may be unused */ + #endif if ((co == NULL) || ((CO_GET_CNT(NMT) == 0U) && (NMT == NULL)) From 926dc628733f4d535f445e0c632bcae74ff1f62b Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 12 Jun 2024 16:43:51 +0200 Subject: [PATCH 301/520] CANopen: static analysis: side effects on right hand of logical operator, '||' [MISRA 2012 Rule 13.5, required] --- CANopen.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CANopen.c b/CANopen.c index eceffb82..d76ede55 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1450,6 +1450,9 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #endif if (CO_GET_CNT(LEDS) == 1U) { + bool_t ErrSync = CO_isError(co->em, CO_EM_SYNC_TIME_OUT); + bool_t ErrHbCons = CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER); + bool_t ErrHbConsRemote = CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET); CO_LEDs_process(co->LEDs, timeDifference_us, unc ? CO_NMT_INITIALIZING : NMTstate, @@ -1457,9 +1460,8 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, (CANerrorStatus & CO_CAN_ERRTX_BUS_OFF) != 0U, (CANerrorStatus & CO_CAN_ERR_WARN_PASSIVE) != 0U, false, /* RPDO event timer timeout */ - unc ? false : CO_isError(co->em, CO_EM_SYNC_TIME_OUT), - unc ? false : (CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER) - || CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET)), + unc ? false : ErrSync, + unc ? false : (ErrHbCons || ErrHbConsRemote), CO_getErrorRegister(co->em) != 0U, CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS, timerNext_us); From cff7a6f9629690835f750e9f48b1d9259a37c6b9 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 10:43:49 +0200 Subject: [PATCH 302/520] CO_Emergency: static analysis: cannot assign a composite expression of type 'unsigned8' to an object of wider type 'unsigned32' [MISRA 2012 Rule 10.6, required] --- 301/CO_Emergency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index d34c867b..b8b7bb98 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -138,7 +138,7 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0U : 0x80000000U; - COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + em->nodeId; + COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + (uint32_t)em->nodeId; (void)CO_setUint32(buf, COB_IDEmergency32); *countRead = sizeof(uint32_t); From 266f77df420a66720bd615471abbae517192076d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 10:45:25 +0200 Subject: [PATCH 303/520] CO_Emergency: static analysis: cannot assign 'unsigned32' to narrower essential type 'unsigned16' [MISRA 2012 Rule 10.3, required] --- 301/CO_Emergency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index b8b7bb98..d16cff75 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -441,7 +441,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, * to add nodeId of this node to the stored value. */ if (producerCanId == CO_CAN_ID_EMERGENCY) producerCanId += nodeId; #else - uint32_t producerCanId = CO_CAN_ID_EMERGENCY + nodeId; + uint16_t producerCanId = CO_CAN_ID_EMERGENCY + (uint16_t)nodeId; em->producerEnabled = (COB_IDEmergency32 & 0x80000000U) == 0U; em->OD_1014_extension.object = em; From be2a4690d6d60f9743ce90fb9007d36895d0e8f4 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 10:56:17 +0200 Subject: [PATCH 304/520] CO_Emergency: static analysis: a signed value is not an appropriate [MISRA 2012 Rule 10.1, required] --- 301/CO_Emergency.c | 26 +++++++++++++------------- 301/CO_Emergency.h | 8 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index d16cff75..43308e98 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -28,9 +28,9 @@ #include "301/CO_Emergency.h" /* verify configuration */ -#if CO_CONFIG_EM_ERR_STATUS_BITS_COUNT < (6*8) \ - || CO_CONFIG_EM_ERR_STATUS_BITS_COUNT > 256 \ - || (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT % 8) != 0 +#if CO_CONFIG_EM_ERR_STATUS_BITS_COUNT < (6U*8U) \ + || CO_CONFIG_EM_ERR_STATUS_BITS_COUNT > 256U \ + || (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT % 8U) != 0 #error CO_CONFIG_EM_ERR_STATUS_BITS_COUNT is not correct #endif @@ -261,7 +261,7 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ - OD_size_t countReadLocal = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; + OD_size_t countReadLocal = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U; if (countReadLocal > count) { countReadLocal = count; } @@ -290,7 +290,7 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ - OD_size_t countWrite = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8; + OD_size_t countWrite = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U; if (countWrite > count) { countWrite = count; } @@ -725,12 +725,12 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, if (em == NULL) { return; } uint8_t index = errorBit >> 3; - uint8_t bitmask = 1 << (errorBit & 0x7); + uint8_t bitmask = 1U << (errorBit & 0x7U); /* if unsupported errorBit, change to 'CO_EM_WRONG_ERROR_REPORT' */ - if (index >= (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8)) { + if (index >= (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U)) { index = CO_EM_WRONG_ERROR_REPORT >> 3; - bitmask = 1 << (CO_EM_WRONG_ERROR_REPORT & 0x7); + bitmask = 1U << (CO_EM_WRONG_ERROR_REPORT & 0x7U); errorCode = CO_EMC_SOFTWARE_INTERNAL; infoCode = errorBit; } @@ -741,12 +741,12 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, /* If error is already set (or unset), return without further actions, * otherwise toggle bit and continue with error indication. */ if (setError) { - if (errorStatusBitMasked != 0) { + if (errorStatusBitMasked != 0U) { return; } } else { - if (errorStatusBitMasked == 0) { + if (errorStatusBitMasked == 0U) { return; } errorCode = CO_EMC_NO_ERROR; @@ -766,9 +766,9 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, else { *errorStatusBits &= ~bitmask; } #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 - if (em->fifoSize >= 2) { + if (em->fifoSize >= 2U) { uint8_t fifoWrPtr = em->fifoWrPtr; - uint8_t fifoWrPtrNext = fifoWrPtr + 1; + uint8_t fifoWrPtrNext = fifoWrPtr + 1U; if (fifoWrPtrNext >= em->fifoSize) { fifoWrPtrNext = 0; } @@ -782,7 +782,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, em->fifo[fifoWrPtr].info = infoCodeSwapped; #endif em->fifoWrPtr = fifoWrPtrNext; - if (em->fifoCount < (em->fifoSize - 1)) { em->fifoCount++; } + if (em->fifoCount < (em->fifoSize - 1U)) { em->fifoCount++; } } } #endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index c03e654b..0b5ce18a 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -37,7 +37,7 @@ CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_EM_ERR_STATUS_BITS_COUNT -#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) +#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10U*8U) #endif #ifndef CO_CONFIG_ERR_CONDITION_GENERIC #define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0U) @@ -257,7 +257,7 @@ extern "C" { */ #define CO_EM_MANUFACTURER_START 0x30U /** (@ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1) largest value of the Error status bit. */ -#define CO_EM_MANUFACTURER_END (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1) +#define CO_EM_MANUFACTURER_END (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1U) /** @} */ /* CO_EM_errorStatusBits_t */ @@ -282,7 +282,7 @@ typedef struct { */ typedef struct { /** Bitfield for the internal indication of the error condition. */ - uint8_t errorStatusBits[CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8]; + uint8_t errorStatusBits[CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U]; /** Pointer to error register in object dictionary at 0x1001,00. */ uint8_t *errorRegister; /** Old CAN error status bitfield */ @@ -546,7 +546,7 @@ static inline bool_t CO_isError(CO_EM_t *em, const uint8_t errorBit) { uint8_t index = errorBit >> 3; uint8_t bitmask = 1 << (errorBit & 0x7); - return (em == NULL || index >= (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8) + return (em == NULL || index >= (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U) || (em->errorStatusBits[index] & bitmask) != 0) ? true : false; } From 9bffb7d789e18d345786e096ab9816d06c0a59f8 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:02:22 +0200 Subject: [PATCH 305/520] CO_Emergency: static analysis: argument 1 of type 'uint8_t [8]' is not compatible with argument 2 of type 'uint32_t *' (aka 'unsigned int *') in call to function 'memcpy' --- 301/CO_Emergency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 43308e98..85d232e0 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -653,7 +653,7 @@ void CO_EM_process(CO_EM_t *em, em->fifo[fifoPpPtr].msg |= (uint32_t) errorRegister << 16; /* send emergency message */ - (void)memcpy(em->CANtxBuff->data, &em->fifo[fifoPpPtr].msg, + (void)memcpy((void *)em->CANtxBuff->data, (void *)&em->fifo[fifoPpPtr].msg, sizeof(em->CANtxBuff->data)); (void)CO_CANsend(em->CANdevTx, em->CANtxBuff); From f48d5058e6a990cb86e04362c3f221ca9087a4f6 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:05:14 +0200 Subject: [PATCH 306/520] CO_Emergency: static analysis: increment/decrement operation combined with other operation with side-effects [MISRA 2012 Rule 13.3, advisory] --- 301/CO_Emergency.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 85d232e0..a5a07936 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -670,7 +670,8 @@ void CO_EM_process(CO_EM_t *em, #endif /* increment pointer */ - em->fifoPpPtr = (++fifoPpPtr < em->fifoSize) ? fifoPpPtr : 0U; + fifoPpPtr++; + em->fifoPpPtr = (fifoPpPtr < em->fifoSize) ? fifoPpPtr : 0U; /* verify message buffer overflow. Clear error condition if all * messages from fifo buffer are processed */ From 061237d4135e1c0b928714f7b4d213311eb4b089 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:12:33 +0200 Subject: [PATCH 307/520] CO_HBconsumer: static analysis: cannot assign variable to narrower essential type [MISRA 2012 Rule 10.3, required] --- 301/CO_HBconsumer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 61cfd4e9..b9261616 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -97,8 +97,8 @@ static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, } uint32_t val = CO_getUint32(buf); - uint8_t nodeId = (val >> 16) & 0xFFU; - uint16_t time = val & 0xFFFFU; + uint8_t nodeId = (uint8_t)((val >> 16) & 0xFFU); + uint16_t time = (uint16_t)(val & 0xFFFFU); CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, stream->subIndex - 1U, nodeId, time); if (ret != CO_ERROR_NO) { @@ -150,8 +150,8 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, return CO_ERROR_OD_PARAMETERS; } - uint8_t nodeId = (val >> 16) & 0xFFU; - uint16_t time = val & 0xFFFFU; + uint8_t nodeId = (uint8_t)((val >> 16) & 0xFFU); + uint16_t time = (uint16_t)(val & 0xFFFFU); CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); if (ret != CO_ERROR_NO) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } @@ -205,7 +205,7 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, CO_HBconsNode_t * monitoredNode = &HBcons->monitoredNodes[idx]; monitoredNode->nodeId = nodeId; - monitoredNode->time_us = (int32_t)consumerTime_ms * 1000; + monitoredNode->time_us = (uint32_t)consumerTime_ms * 1000U; monitoredNode->NMTstate = CO_NMT_UNKNOWN; #if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) From 9c89ecf26e648f3e62d728e1b4badba8a062cbe9 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:15:29 +0200 Subject: [PATCH 308/520] CO_HBconsumer: static analisys: the name 'time' is reserved to the compiler [MISRA 2012 Rule 21.2, required] --- 301/CO_HBconsumer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index b9261616..6da55965 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -98,9 +98,9 @@ static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, uint32_t val = CO_getUint32(buf); uint8_t nodeId = (uint8_t)((val >> 16) & 0xFFU); - uint16_t time = (uint16_t)(val & 0xFFFFU); + uint16_t consumer_time = (uint16_t)(val & 0xFFFFU); CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, stream->subIndex - 1U, - nodeId, time); + nodeId, consumer_time); if (ret != CO_ERROR_NO) { return ODR_PAR_INCOMPAT; } @@ -151,8 +151,8 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, } uint8_t nodeId = (uint8_t)((val >> 16) & 0xFFU); - uint16_t time = (uint16_t)(val & 0xFFFFU); - CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time); + uint16_t consumer_time = (uint16_t)(val & 0xFFFFU); + CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, consumer_time); if (ret != CO_ERROR_NO) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } /* don't break a program, if only value of a parameter is wrong */ From c25fec21764a3e3714fe30ae1e25da859ed1f158 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:22:20 +0200 Subject: [PATCH 309/520] CO_NMT_Heartbeat: static analysis: enum constant 'CO_NMT_NO_COMMAND' not used within default switch --- 301/CO_NMT_Heartbeat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index ac5377f5..7e2bb79d 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -275,6 +275,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, case CO_NMT_RESET_COMMUNICATION: resetCommand = CO_RESET_COMM; break; + case CO_NMT_NO_COMMAND: default: break; } From 1da8f44821a2589183aa793cff0db84bc5fa1247 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:24:14 +0200 Subject: [PATCH 310/520] CO_NMT_Heartbeat: static analysis: cannot assign 'signed32' to different essential type 'unsigned32' [MISRA 2012 Rule 10.3, required] --- 301/CO_NMT_Heartbeat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 7e2bb79d..07c5ef2e 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -120,7 +120,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, NMT->nodeId = nodeId; NMT->NMTcontrol = NMTcontrol; NMT->em = em; - NMT->HBproducerTimer = (int32_t)firstHBTime_ms * 1000; + NMT->HBproducerTimer = (uint32_t)firstHBTime_ms * 1000U; /* get and verify required "Producer heartbeat time" from Object Dict. */ uint16_t HBprodTime_ms; From e11ffc1bc393263e6299bb1345b9f485ad811f2b Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:27:42 +0200 Subject: [PATCH 311/520] CO_NMT_Heartbeat: static analysis: statement or comment should appear in default case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.4, required] --- 301/CO_NMT_Heartbeat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 07c5ef2e..cc5f1104 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -277,6 +277,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, break; case CO_NMT_NO_COMMAND: default: + /* done */ break; } NMT->internalCommand = CO_NMT_NO_COMMAND; From 6eaf6b09f707381543c4ed7e7842284c2f49e575 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:35:09 +0200 Subject: [PATCH 312/520] CO_NMT_Heartbeat: static analysis: both sides have side effects [MISRA 2012 Rule 1.3, required] --- 301/CO_NMT_Heartbeat.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index cc5f1104..6caf3c61 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -284,12 +284,15 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, } /* verify NMT transitions based on error register */ - bool_t busOff_HB = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_ON_BUSOFF_HB) != 0U) - && (CO_isError(NMT->em, CO_EM_CAN_TX_BUS_OFF) - || CO_isError(NMT->em, CO_EM_HEARTBEAT_CONSUMER) - || CO_isError(NMT->em, CO_EM_HB_CONSUMER_REMOTE_RESET)); - bool_t errRegMasked = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_ON_ERR_REG) != 0U) - && ((CO_getErrorRegister(NMT->em) & (uint8_t)NMT->NMTcontrol) != 0U); + bool_t ErrOnBusOffHB = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_ON_BUSOFF_HB) != 0U); + bool_t ErrBusOff = CO_isError(NMT->em, CO_EM_CAN_TX_BUS_OFF); + bool_t ErrHbCons = CO_isError(NMT->em, CO_EM_HEARTBEAT_CONSUMER); + bool_t ErrHbConsRemote = CO_isError(NMT->em, CO_EM_HB_CONSUMER_REMOTE_RESET); + bool_t busOff_HB = ErrOnBusOffHB && (ErrBusOff|| ErrHbCons || ErrHbConsRemote); + + bool_t ErrNMTErrReg = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_ON_ERR_REG) != 0U); + bool_t ErrNMTcontrol =((CO_getErrorRegister(NMT->em) & (uint8_t)NMT->NMTcontrol) != 0U); + bool_t errRegMasked = ErrNMTErrReg && ErrNMTcontrol; if ((NMTstateCpy == CO_NMT_OPERATIONAL) && (busOff_HB || errRegMasked)) { NMTstateCpy = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_TO_STOPPED) != 0U) From 78944be8f24881a3f011ed2922e34bb2202e4335 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:41:03 +0200 Subject: [PATCH 313/520] CO_Node_Guarding: static analysis: no 'else' at end of 'if ... else if' chain [MISRA 2012 Rule 15.7, required] --- 301/CO_Node_Guarding.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 14480412..1f6f2a45 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -256,6 +256,7 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, CO_EMC_HEARTBEAT, 0); } } + else { /* MISRA C 2004 14.10 */ } return; } From 52ad9f575856ec379d906bc504b7693b4281fb2d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:43:26 +0200 Subject: [PATCH 314/520] CO_Node_Guarding: static analysis: body should be a compound statement [MISRA 2012 Rule 15.6, required] --- 301/CO_Node_Guarding.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 1f6f2a45..84d57733 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -133,7 +133,9 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, uint16_t guardTime_ms; ODR_t odRet = OD_get_u16(OD_100C_GuardTime, 0, &guardTime_ms, true); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_100C_GuardTime); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_100C_GuardTime); + } return CO_ERROR_OD_PARAMETERS; } ngs->guardTime_us = (uint32_t)guardTime_ms * 1000U; @@ -143,7 +145,9 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, ngs->OD_100C_extension.write = OD_write_100C; odRet = OD_extension_init(OD_100C_GuardTime, &ngs->OD_100C_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_100C_GuardTime); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_100C_GuardTime); + } return CO_ERROR_OD_PARAMETERS; } @@ -151,7 +155,9 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, uint8_t lifeTimeFactor; odRet = OD_get_u8(OD_100D_LifeTimeFactor, 0, &lifeTimeFactor, true); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_100D_LifeTimeFactor); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_100D_LifeTimeFactor); + } return CO_ERROR_OD_PARAMETERS; } ngs->lifeTimeFactor = lifeTimeFactor; @@ -162,7 +168,9 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, ngs->OD_100D_extension.write = OD_write_100D; odRet = OD_extension_init(OD_100D_LifeTimeFactor, &ngs->OD_100D_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_100D_LifeTimeFactor); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_100D_LifeTimeFactor); + } return CO_ERROR_OD_PARAMETERS; } From d0a4b22963c0a335337e111770ca65262cf53274 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:46:29 +0200 Subject: [PATCH 315/520] CO_ODinterface: static analysis: argument 1 of type 'void *' is not compatible with argument 2 of type 'const uint8_t *' (aka 'const unsigned char *') in call to function 'memcpy' --- 301/CO_ODinterface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 7024a8ba..c21145ae 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -65,7 +65,7 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, } } - (void)memcpy(buf, dataOrig, dataLenToCopy); + (void)memcpy((void *)buf, (const void *)dataOrig, dataLenToCopy); *countRead = dataLenToCopy; return returnCode; @@ -116,7 +116,7 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, return ODR_DATA_LONG; } - (void)memcpy(dataOrig, buf, dataLenToCopy); + (void)memcpy((void *)dataOrig, (const void *)buf, dataLenToCopy); *countWritten = dataLenToCopy; return returnCode; From 808ad99b580ab05e3c863e56c7ef3031d6fe6f37 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:52:05 +0200 Subject: [PATCH 316/520] CO_ODinterface: static analysis: missing unconditional break from final switch case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.3, required] --- 301/CO_ODinterface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index c21145ae..0e571067 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -235,6 +235,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, } default: { return ODR_DEV_INCOMPAT; + break; } } From fd8cf681a337be1e8adc04df2d4574a24f52cff3 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 11:58:04 +0200 Subject: [PATCH 317/520] CO_PDO: static analisys: result of assignment operator used in right operand to '=' operator [MISRA 2012 Rule 13.4, advisory] --- 301/CO_PDO.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 52f5bbc1..b3d3f2d6 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -105,7 +105,8 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, if ((index < 0x20U) && (subIndex == 0U)) { OD_stream_t *stream = &OD_IO->stream; (void)memset(stream, 0, sizeof(OD_stream_t)); - stream->dataLength = stream->dataOffset = mappedLength; + stream->dataLength = mappedLength; + stream->dataOffset = mappedLength; OD_IO->read = OD_read_dummy; OD_IO->write = OD_write_dummy; return ODR_OK; @@ -1028,7 +1029,8 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, TPDO->transmissionType = transmissionType; TPDO->sendRequest = true; #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 - TPDO->inhibitTimer = TPDO->eventTimer = 0; + TPDO->inhibitTimer = 0; + TPDO->eventTimer = 0; #endif break; } @@ -1453,7 +1455,8 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, /* Not operational or valid, reset triggers */ TPDO->sendRequest = true; #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 - TPDO->inhibitTimer = TPDO->eventTimer = 0; + TPDO->inhibitTimer = 0; + TPDO->eventTimer = 0; #endif #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncCounter = 255; From 6f6936c9cc405c854c32cda272381f790859e5ca Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 12:03:21 +0200 Subject: [PATCH 318/520] CO_PDO: static analysis: cannot assign 'enum' to different essential type 'unsigned8' [MISRA 2012 Rule 10.3, required] --- 301/CO_PDO.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index b3d3f2d6..1c75b6d4 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -121,7 +121,7 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, } /* verify access attributes, byte alignment and length */ - OD_attr_t testAttribute = isRPDO ? ODA_RPDO : ODA_TPDO; + OD_attr_t testAttribute = isRPDO ? (OD_attr_t)(ODA_RPDO) : (OD_attr_t)(ODA_TPDO); if (((OD_IOcopy.stream.attribute & testAttribute) == 0U) || ((mappedLengthBits & 0x07U) != 0U) || (OD_IOcopy.stream.dataLength < mappedLength) @@ -475,10 +475,10 @@ static void CO_PDO_receive(void *object, void *msg) { if (DLC >= PDO->dataLength) { /* indicate errors in PDO length */ if (DLC == PDO->dataLength) { - if (err == (uint8_t)CO_RPDO_RX_ACK_ERROR) { err = CO_RPDO_RX_OK; } + if (err == (uint8_t)CO_RPDO_RX_ACK_ERROR) { err = (uint8_t)(CO_RPDO_RX_OK); } } else { - if (err == (uint8_t)CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_LONG; } + if (err == (uint8_t)CO_RPDO_RX_ACK_NO_ERROR) { err = (uint8_t)(CO_RPDO_RX_LONG); } } /* Determine, to which of the two rx buffers copy the message. */ @@ -504,7 +504,7 @@ static void CO_PDO_receive(void *object, void *msg) { #endif } else if (err == (uint8_t)CO_RPDO_RX_ACK_NO_ERROR) { - err = CO_RPDO_RX_SHORT; + err = (uint8_t)(CO_RPDO_RX_SHORT); } else { /* MISRA C 2004 14.10 */ } } @@ -722,7 +722,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, /* Configure communication parameter - transmission type */ #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - uint8_t transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; + uint8_t transmissionType = (uint8_t)(CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO); odRet = OD_get_u8(OD_14xx_RPDOCommPar, 2, &transmissionType, true); if (odRet != ODR_OK) { if (errInfo != NULL) { @@ -803,7 +803,7 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, CO_error(PDO->em, setError, CO_EM_RPDO_WRONG_LENGTH, code, PDO->dataLength); RPDO->receiveError = setError - ? CO_RPDO_RX_ACK_ERROR : CO_RPDO_RX_ACK_NO_ERROR; + ? (uint8_t)(CO_RPDO_RX_ACK_ERROR) : (uint8_t)(CO_RPDO_RX_ACK_NO_ERROR); } /* Determine, which of the two rx buffers contains relevant message. */ @@ -1121,7 +1121,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, /* Configure communication parameter - transmission type */ - uint8_t transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; + uint8_t transmissionType = (uint8_t)(CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO); odRet = OD_get_u8(OD_18xx_TPDOCommPar, 2, &transmissionType, true); if (odRet != ODR_OK) { if (errInfo != NULL) { @@ -1134,7 +1134,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, && (transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) #endif ) { - transmissionType = CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO; + transmissionType = (uint8_t)(CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO); } TPDO->transmissionType = transmissionType; TPDO->sendRequest = true; From fe1709c42a93a06db95365504dea1a845ea46e8e Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 12:05:39 +0200 Subject: [PATCH 319/520] CO_PDO: static analysis: argument 1 of type 'uint8_t [4]' is not compatible with argument 2 of type 'const void *' in call to function 'memcpy' --- 301/CO_PDO.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 1c75b6d4..d7d52c89 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -530,7 +530,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, CO_RPDO_t *RPDO = stream->object; CO_PDO_common_t *PDO = &RPDO->PDO_common; uint8_t bufCopy[4]; - (void)memcpy(bufCopy, buf, count); + (void)memcpy((void *)bufCopy, (const void *)buf, count); switch (stream->subIndex) { case 1: { /* COB-ID used by PDO */ @@ -961,7 +961,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, CO_TPDO_t *TPDO = stream->object; CO_PDO_common_t *PDO = &TPDO->PDO_common; uint8_t bufCopy[4]; - (void)memcpy(bufCopy, buf, count); + (void)memcpy((void *)bufCopy, (const void *)buf, count); switch (stream->subIndex) { case 1: { /* COB-ID used by PDO */ From d9d24ffe82bc42012d1826f45219c5c03ca1225c Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 12:17:28 +0200 Subject: [PATCH 320/520] CO_PDO: static analysis: unsigned integer literal without a 'U' suffix [MISRA 2012 Rule 7.2, required] --- 301/CO_PDO.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index d7d52c89..63ffcdc1 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -429,7 +429,7 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, } /* If PDO is not valid, set bit 31 */ - if (!PDO->valid) { COB_ID |= 0x80000000; } + if (!PDO->valid) { COB_ID |= 0x80000000U; } (void)CO_setUint32(buf, COB_ID); } @@ -553,7 +553,7 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, if ((valid != PDO->valid) || (CAN_ID != PDO->configuredCanId)) { /* if default CAN-ID is written, store to OD without Node-ID */ if (CAN_ID == PDO->preDefinedCanId) { - (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); + (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80U); } if (!valid) { CAN_ID = 0; @@ -984,7 +984,7 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, if ((valid != PDO->valid) || (CAN_ID != PDO->configuredCanId)) { /* if default CAN-ID is written, store to OD without Node-ID */ if (CAN_ID == PDO->preDefinedCanId) { - (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80); + (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80U); } if (!valid) { CAN_ID = 0; From 32c1086ac1fc73ce7972e7378c7df2fb9d1e9e9f Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 12:23:38 +0200 Subject: [PATCH 321/520] CO_PDO: static analysis: last value assigned to 'odRet' not used [MISRA 2012 Rule 2.2, required] --- 301/CO_PDO.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 63ffcdc1..56a9c118 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -740,6 +740,12 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 uint16_t eventTime = 0; odRet = OD_get_u16(OD_14xx_RPDOCommPar, 5, &eventTime, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_14xx_RPDOCommPar)) << 8) | 5U; + } + return CO_ERROR_OD_PARAMETERS; + } RPDO->timeoutTime_us = (uint32_t)eventTime * 1000U; #endif @@ -1190,7 +1196,19 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, uint16_t inhibitTime = 0; uint16_t eventTime = 0; odRet = OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 3U; + } + return CO_ERROR_OD_PARAMETERS; + } odRet = OD_get_u16(OD_18xx_TPDOCommPar, 5, &eventTime, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 5U; + } + return CO_ERROR_OD_PARAMETERS; + } TPDO->inhibitTime_us = (uint32_t)inhibitTime * 100U; TPDO->eventTime_us = (uint32_t)eventTime * 1000U; #endif @@ -1200,6 +1218,12 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncStartValue = 0; odRet = OD_get_u8(OD_18xx_TPDOCommPar, 6, &TPDO->syncStartValue, true); + if (odRet != ODR_OK) { + if (errInfo != NULL) { + *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 6U; + } + return CO_ERROR_OD_PARAMETERS; + } TPDO->SYNC = SYNC; TPDO->syncCounter = 255; #endif From f8d10390bcf6e70e9853a4af67a7ac9f550380dc Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 12:27:50 +0200 Subject: [PATCH 322/520] CO_SDOserver: static analysis: missing unconditional break from final switch case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.3, required] --- 301/CO_SDOserver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 2c4ae11a..fba2e4c5 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -304,6 +304,7 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, default: return ODR_SUB_NOT_EXIST; + break; } /* write value to the original location in the Object Dictionary */ From 460441f972bccd40019a2871d9deb319efad82cb Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 12:29:43 +0200 Subject: [PATCH 323/520] CO_SDOserve: static analysis: increment/decrement operation combined with other operation with side-effects [MISRA 2012 Rule 13.3, advisory] --- 301/CO_SDOserver.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index fba2e4c5..b45c2f31 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -510,10 +510,12 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, && ((sizeInOd == 0U) || (SDO->sizeTran < sizeInOd)) && ((SDO->bufOffsetWr + 2U) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE) ) { - SDO->buf[SDO->bufOffsetWr++] = 0; + SDO->buf[SDO->bufOffsetWr] = 0; + SDO->bufOffsetWr++; SDO->sizeTran++; if ((sizeInOd == 0U) || (SDO->sizeTran < sizeInOd)) { - SDO->buf[SDO->bufOffsetWr++] = 0; + SDO->buf[SDO->bufOffsetWr] = 0; + SDO->bufOffsetWr++; SDO->sizeTran++; } SDO->OD_IO.stream.dataLength = SDO->sizeTran; From b2294a65abcbb3949bc54ee62769707fa15453a2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:09:34 +0200 Subject: [PATCH 324/520] CO_SDOserver: static analysis: argument 1 of type 'uint8_t *' (aka 'unsigned char *') is not compatible with argument 2 of type 'uint32_t *' (aka 'unsigned int *') in call to function 'memcpy' --- 301/CO_SDOserver.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index b45c2f31..3d215881 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -887,7 +887,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, uint32_t size; OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - (void)memcpy(&size, &SDO->CANrxData[4], sizeof(size)); + (void)memcpy((void *)(&size), (const void *)(&SDO->CANrxData[4]), sizeof(size)); SDO->sizeInd = CO_SWAP_32(size); /* Indicated size of SDO matches sizeof OD variable? */ @@ -1291,7 +1291,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if ((SDO->sizeInd > 0U) && (SDO->sizeInd <= 4U)) { /* expedited transfer */ SDO->CANtxBuff->data[0] = (uint8_t)(0x43U|((4U-SDO->sizeInd)<<2U)); - (void)memcpy(&SDO->CANtxBuff->data[4], &SDO->buf, SDO->sizeInd); + (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), (const void *)((&SDO->buf), SDO->sizeInd); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } @@ -1302,8 +1302,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, uint32_t sizeInd = SDO->sizeInd; uint32_t sizeIndSw = CO_SWAP_32(sizeInd); SDO->CANtxBuff->data[0] = 0x41; - (void)memcpy(&SDO->CANtxBuff->data[4], - &sizeIndSw, sizeof(sizeIndSw)); + (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), + (const void *)(&sizeIndSw), sizeof(sizeIndSw)); } else { SDO->CANtxBuff->data[0] = 0x40; @@ -1609,7 +1609,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); SDO->CANtxBuff->data[3] = SDO->subIndex; - (void)memcpy(&SDO->CANtxBuff->data[4], &code, sizeof(code)); + (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), (const void *)(&code), sizeof(code)); (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; From a4fb95e38bc19a6617971a1ae9156f716d728594 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:11:09 +0200 Subject: [PATCH 325/520] CO_SDOserver: static analysis: statement or comment should appear in default case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.4, required] --- 301/CO_SDOserver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 3d215881..669731a6 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1595,6 +1595,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ default: { + /* none */ break; } } /* switch (SDO->state) */ From 404ebca5fbdc4c384343a7bc2ac20b8864a68eab Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:14:00 +0200 Subject: [PATCH 326/520] CO_SDOserver: static analysis: cannot assign a composite expression of type 'unsigned8' to an object of wider type 'unsigned32' [MISRA 2012 Rule 10.6, required] --- 301/CO_SDOserver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 669731a6..6614bd21 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -821,7 +821,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Get SDO data size (indicated by SDO client or get from OD) */ OD_size_t dataSizeToWrite = 4; if ((SDO->CANrxData[0] & 0x01U) != 0U) { - dataSizeToWrite -= (SDO->CANrxData[0] >> 2) & 0x03U; + dataSizeToWrite -= (OD_size_t)((SDO->CANrxData[0] >> 2) & 0x03U); } else if ((sizeInOd > 0U) && (sizeInOd < 4U)) { dataSizeToWrite = sizeInOd; @@ -935,7 +935,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* get data size and write data to the buffer */ - OD_size_t count = 7U - ((SDO->CANrxData[0] >> 1) & 0x07U); + OD_size_t count = (OD_size_t)(7U - ((SDO->CANrxData[0] >> 1) & 0x07U)); (void)memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); SDO->bufOffsetWr += count; SDO->sizeTran += count; From 00f8961f55cea168d4b8324247b0b7b72051b365 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:16:22 +0200 Subject: [PATCH 327/520] CO_SDOserver: static analysis: loss of precision (assignment) from 32 bits to 8 bits --- 301/CO_SDOserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 6614bd21..a098fbf1 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1369,7 +1369,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* verify, if this is the last segment */ if ((count < 7U) || (SDO->finished && (count == 7U))) { /* indicate last segment and nnn */ - SDO->CANtxBuff->data[0] |= ((7U - count) << 1U) | 0x01U; + SDO->CANtxBuff->data[0] |= (uint8_t)(((7U - count) << 1U) | 0x01U); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } From e82c94284659bc8a6ee9c152c5053354ff6a86ec Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:18:02 +0200 Subject: [PATCH 328/520] Fix previous static analysis --- 301/CO_SDOserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index a098fbf1..659df170 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1291,7 +1291,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if ((SDO->sizeInd > 0U) && (SDO->sizeInd <= 4U)) { /* expedited transfer */ SDO->CANtxBuff->data[0] = (uint8_t)(0x43U|((4U-SDO->sizeInd)<<2U)); - (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), (const void *)((&SDO->buf), SDO->sizeInd); + (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), (const void *)(&SDO->buf), SDO->sizeInd); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } From 99b56d10c97f539e9438341e0a0381ba0cc6156d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:21:20 +0200 Subject: [PATCH 329/520] CO_SDOserver: static analysis: unexpected lack of indentation --- 301/CO_SDOserver.c | 568 ++++++++++++++++++++++----------------------- 1 file changed, 284 insertions(+), 284 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 659df170..9f6f7f1c 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -810,366 +810,366 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* (SDO->state == CO_SDO_ST_IDLE) */ if ((SDO->state != CO_SDO_ST_IDLE) && (SDO->state != CO_SDO_ST_ABORT)) { - switch (SDO->state) { - case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { - if ((SDO->CANrxData[0] & 0x02U) != 0U) { - /* Expedited transfer, max 4 bytes of data */ + switch (SDO->state) { + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { + if ((SDO->CANrxData[0] & 0x02U) != 0U) { + /* Expedited transfer, max 4 bytes of data */ - /* Size of OD variable (>0 if indicated) */ - OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + /* Size of OD variable (>0 if indicated) */ + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - /* Get SDO data size (indicated by SDO client or get from OD) */ - OD_size_t dataSizeToWrite = 4; - if ((SDO->CANrxData[0] & 0x01U) != 0U) { - dataSizeToWrite -= (OD_size_t)((SDO->CANrxData[0] >> 2) & 0x03U); - } - else if ((sizeInOd > 0U) && (sizeInOd < 4U)) { - dataSizeToWrite = sizeInOd; - } - else { /* MISRA C 2004 14.10 */ } + /* Get SDO data size (indicated by SDO client or get from OD) */ + OD_size_t dataSizeToWrite = 4; + if ((SDO->CANrxData[0] & 0x01U) != 0U) { + dataSizeToWrite -= (OD_size_t)((SDO->CANrxData[0] >> 2) & 0x03U); + } + else if ((sizeInOd > 0U) && (sizeInOd < 4U)) { + dataSizeToWrite = sizeInOd; + } + else { /* MISRA C 2004 14.10 */ } - /* copy data to the temp buffer, swap data if necessary */ - uint8_t buf[6] = {0}; - (void)memcpy(buf, &SDO->CANrxData[4], dataSizeToWrite); -#ifdef CO_BIG_ENDIAN - if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { - reverseBytes(buf, dataSizeToWrite); - } -#endif + /* copy data to the temp buffer, swap data if necessary */ + uint8_t buf[6] = {0}; + (void)memcpy(buf, &SDO->CANrxData[4], dataSizeToWrite); + #ifdef CO_BIG_ENDIAN + if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { + reverseBytes(buf, dataSizeToWrite); + } + #endif - /* If dataType is string, then size of data downloaded may be - * shorter as size of OD data buffer. If so, add two zero bytes - * to terminate (unicode) string. Shorten also OD data size, - * (temporary, send information about EOF into OD_IO.write) */ - if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) - && ((sizeInOd == 0U) || (dataSizeToWrite < sizeInOd)) - ) { - OD_size_t delta = sizeInOd - dataSizeToWrite; - dataSizeToWrite += (delta == 1U) ? 1U : 2U; - SDO->OD_IO.stream.dataLength = dataSizeToWrite; - } - else if (sizeInOd == 0U) { - SDO->OD_IO.stream.dataLength = dataSizeToWrite; + /* If dataType is string, then size of data downloaded may be + * shorter as size of OD data buffer. If so, add two zero bytes + * to terminate (unicode) string. Shorten also OD data size, + * (temporary, send information about EOF into OD_IO.write) */ + if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) + && ((sizeInOd == 0U) || (dataSizeToWrite < sizeInOd)) + ) { + OD_size_t delta = sizeInOd - dataSizeToWrite; + dataSizeToWrite += (delta == 1U) ? 1U : 2U; + SDO->OD_IO.stream.dataLength = dataSizeToWrite; + } + else if (sizeInOd == 0U) { + SDO->OD_IO.stream.dataLength = dataSizeToWrite; + } + /* Verify if size of data downloaded matches data size in OD. */ + else if (dataSizeToWrite != sizeInOd) { + abortCode = (dataSizeToWrite > sizeInOd) ? + CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + else { /* MISRA C 2004 14.10 */ } + + /* Copy data */ + OD_size_t countWritten = 0; + + CO_LOCK_OD(SDO->CANdevTx); + ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, + dataSizeToWrite, &countWritten); + CO_UNLOCK_OD(SDO->CANdevTx); + + if (odRet != ODR_OK) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; + } + else { + SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; + #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + SDO->finished = true; + #endif + } } - /* Verify if size of data downloaded matches data size in OD. */ - else if (dataSizeToWrite != sizeInOd) { - abortCode = (dataSizeToWrite > sizeInOd) ? - CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + else { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + /* segmented transfer, is size indicated? */ + if ((SDO->CANrxData[0] & 0x01U) != 0U) { + uint32_t size; + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + + (void)memcpy((void *)(&size), (const void *)(&SDO->CANrxData[4]), sizeof(size)); + SDO->sizeInd = CO_SWAP_32(size); + + /* Indicated size of SDO matches sizeof OD variable? */ + if (sizeInOd > 0U) { + if (SDO->sizeInd > sizeInOd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } + /* strings are allowed to be shorter */ + else if ((SDO->sizeInd < sizeInOd) + && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) == 0U) + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + else { /* MISRA C 2004 14.10 */ } + } + } + else { + SDO->sizeInd = 0; + } + SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; + SDO->finished = false; +#else + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; SDO->state = CO_SDO_ST_ABORT; - break; +#endif } - else { /* MISRA C 2004 14.10 */ } + break; + } + +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { + if ((SDO->CANrxData[0] & 0xE0U) == 0x00U) { + SDO->finished = (SDO->CANrxData[0] & 0x01U) != 0U; + + /* verify and alternate toggle bit */ + uint8_t toggle = SDO->CANrxData[0] & 0x10U; + if (toggle != SDO->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO->state = CO_SDO_ST_ABORT; + break; + } - /* Copy data */ - OD_size_t countWritten = 0; + /* get data size and write data to the buffer */ + OD_size_t count = (OD_size_t)(7U - ((SDO->CANrxData[0] >> 1) & 0x07U)); + (void)memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); + SDO->bufOffsetWr += count; + SDO->sizeTran += count; - CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, - dataSizeToWrite, &countWritten); - CO_UNLOCK_OD(SDO->CANdevTx); + /* if data size exceeds variable size, abort */ + if ((SDO->OD_IO.stream.dataLength > 0U) + && (SDO->sizeTran > SDO->OD_IO.stream.dataLength) + ) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } - if (odRet != ODR_OK) { - abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); - SDO->state = CO_SDO_ST_ABORT; - break; + /* if necessary, empty the buffer */ + if (SDO->finished + || ((CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7U+2U)) + ) { + if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) { + break; + } + } + + SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; } else { - SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - SDO->finished = true; -#endif + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; } + break; } - else { +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + + case CO_SDO_ST_UPLOAD_INITIATE_REQ: { + SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; + break; + } + #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - /* segmented transfer, is size indicated? */ - if ((SDO->CANrxData[0] & 0x01U) != 0U) { + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { + if ((SDO->CANrxData[0] & 0xEFU) == 0x60U) { + /* verify and alternate toggle bit */ + uint8_t toggle = SDO->CANrxData[0] & 0x10U; + if (toggle != SDO->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; + } + else { + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; + } + break; + } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { + SDO->block_crcEnabled = (SDO->CANrxData[0] & 0x04) != 0; + + /* is size indicated? */ + if ((SDO->CANrxData[0] & 0x02) != 0) { uint32_t size; OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - (void)memcpy((void *)(&size), (const void *)(&SDO->CANrxData[4]), sizeof(size)); + (void)memcpy(&size, &SDO->CANrxData[4], sizeof(size)); SDO->sizeInd = CO_SWAP_32(size); /* Indicated size of SDO matches sizeof OD variable? */ - if (sizeInOd > 0U) { + if (sizeInOd > 0) { if (SDO->sizeInd > sizeInOd) { abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; break; } /* strings are allowed to be shorter */ - else if ((SDO->sizeInd < sizeInOd) - && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) == 0U) + else if (SDO->sizeInd < sizeInOd + && (SDO->OD_IO.stream.attribute & ODA_STR) == 0 ) { abortCode = CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; break; } - else { /* MISRA C 2004 14.10 */ } - } + } } else { SDO->sizeInd = 0; } - SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; SDO->finished = false; -#else - abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; - SDO->state = CO_SDO_ST_ABORT; -#endif + break; } - break; - } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { - if ((SDO->CANrxData[0] & 0xE0U) == 0x00U) { - SDO->finished = (SDO->CANrxData[0] & 0x01U) != 0U; - - /* verify and alternate toggle bit */ - uint8_t toggle = SDO->CANrxData[0] & 0x10U; - if (toggle != SDO->toggle) { - abortCode = CO_SDO_AB_TOGGLE_BIT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - - /* get data size and write data to the buffer */ - OD_size_t count = (OD_size_t)(7U - ((SDO->CANrxData[0] >> 1) & 0x07U)); - (void)memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); - SDO->bufOffsetWr += count; - SDO->sizeTran += count; - - /* if data size exceeds variable size, abort */ - if ((SDO->OD_IO.stream.dataLength > 0U) - && (SDO->sizeTran > SDO->OD_IO.stream.dataLength) - ) { - abortCode = CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; - } + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { + /* data are copied directly in the receive function */ + break; + } - /* if necessary, empty the buffer */ - if (SDO->finished - || ((CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7U+2U)) - ) { - if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) { + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { + if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { + /* Get number of data bytes in last segment, that do not + * contain data. Then reduce buffer. */ + uint8_t noData = ((SDO->CANrxData[0] >> 2) & 0x07); + if (SDO->bufOffsetWr <= noData) { + /* just in case, should never happen */ + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; break; } - } + SDO->sizeTran -= noData; + SDO->bufOffsetWr -= noData; - SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; - } - break; - } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + uint16_t crcClient = 0; + if (SDO->block_crcEnabled) { + crcClient = ((uint16_t) SDO->CANrxData[2]) << 8; + crcClient |= SDO->CANrxData[1]; + } - case CO_SDO_ST_UPLOAD_INITIATE_REQ: { - SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; - break; - } + if (!validateAndWriteToOD(SDO, &abortCode, 2, crcClient)) + break; -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { - if ((SDO->CANrxData[0] & 0xEFU) == 0x60U) { - /* verify and alternate toggle bit */ - uint8_t toggle = SDO->CANrxData[0] & 0x10U; - if (toggle != SDO->toggle) { - abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; + } + else { + abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; - break; } - SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; + break; } - break; - } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { - SDO->block_crcEnabled = (SDO->CANrxData[0] & 0x04) != 0; - - /* is size indicated? */ - if ((SDO->CANrxData[0] & 0x02) != 0) { - uint32_t size; - OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - (void)memcpy(&size, &SDO->CANrxData[4], sizeof(size)); - SDO->sizeInd = CO_SWAP_32(size); + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { + /* if pst (protocol switch threshold, byte5) is larger than data + * size of OD variable, then switch to segmented transfer */ + if (SDO->sizeInd > 0 && SDO->CANrxData[5] > 0 + && SDO->CANrxData[5] >= SDO->sizeInd) + { + SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; + } + else { + /* data were already loaded from OD variable, verify crc */ + if ((SDO->CANrxData[0] & 0x04) != 0) { + SDO->block_crcEnabled = true; + SDO->block_crc = crc16_ccitt(SDO->buf, SDO->bufOffsetWr, 0); + } + else { + SDO->block_crcEnabled = false; + } - /* Indicated size of SDO matches sizeof OD variable? */ - if (sizeInOd > 0) { - if (SDO->sizeInd > sizeInOd) { - abortCode = CO_SDO_AB_DATA_LONG; + /* get blksize and verify it */ + SDO->block_blksize = SDO->CANrxData[4]; + if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { + abortCode = CO_SDO_AB_BLOCK_SIZE; SDO->state = CO_SDO_ST_ABORT; break; } - /* strings are allowed to be shorter */ - else if (SDO->sizeInd < sizeInOd - && (SDO->OD_IO.stream.attribute & ODA_STR) == 0 - ) { - abortCode = CO_SDO_AB_DATA_SHORT; + + /* verify, if there is enough data */ + if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize*7U){ + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; break; } + SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; } + break; } - else { - SDO->sizeInd = 0; - } - SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; - SDO->finished = false; - break; - } - - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { - /* data are copied directly in the receive function */ - break; - } - - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { - if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { - /* Get number of data bytes in last segment, that do not - * contain data. Then reduce buffer. */ - uint8_t noData = ((SDO->CANrxData[0] >> 2) & 0x07); - if (SDO->bufOffsetWr <= noData) { - /* just in case, should never happen */ - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - SDO->sizeTran -= noData; - SDO->bufOffsetWr -= noData; - - uint16_t crcClient = 0; - if (SDO->block_crcEnabled) { - crcClient = ((uint16_t) SDO->CANrxData[2]) << 8; - crcClient |= SDO->CANrxData[1]; - } - - if (!validateAndWriteToOD(SDO, &abortCode, 2, crcClient)) - break; - - SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; - } - break; - } - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { - /* if pst (protocol switch threshold, byte5) is larger than data - * size of OD variable, then switch to segmented transfer */ - if (SDO->sizeInd > 0 && SDO->CANrxData[5] > 0 - && SDO->CANrxData[5] >= SDO->sizeInd) - { - SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; - } - else { - /* data were already loaded from OD variable, verify crc */ - if ((SDO->CANrxData[0] & 0x04) != 0) { - SDO->block_crcEnabled = true; - SDO->block_crc = crc16_ccitt(SDO->buf, SDO->bufOffsetWr, 0); + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { + if (SDO->CANrxData[0] == 0xA3) { + SDO->block_seqno = 0; + SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; } else { - SDO->block_crcEnabled = false; - } - - /* get blksize and verify it */ - SDO->block_blksize = SDO->CANrxData[4]; - if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { - abortCode = CO_SDO_AB_BLOCK_SIZE; + abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; - break; } - - /* verify, if there is enough data */ - if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize*7U){ - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; - } - break; - } - - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { - if (SDO->CANrxData[0] == 0xA3) { - SDO->block_seqno = 0; - SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; + break; } - break; - } - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { - if (SDO->CANrxData[0] == 0xA2) { - SDO->block_blksize = SDO->CANrxData[2]; - if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { - abortCode = CO_SDO_AB_BLOCK_SIZE; - SDO->state = CO_SDO_ST_ABORT; - break; - } + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { + if (SDO->CANrxData[0] == 0xA2) { + SDO->block_blksize = SDO->CANrxData[2]; + if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { + abortCode = CO_SDO_AB_BLOCK_SIZE; + SDO->state = CO_SDO_ST_ABORT; + break; + } - /* check number of segments */ - if (SDO->CANrxData[1] < SDO->block_seqno) { - /* NOT all segments transferred successfully. - * Re-transmit data after erroneous segment. */ - OD_size_t cntFailed = SDO->block_seqno - SDO->CANrxData[1]; - cntFailed = cntFailed * 7 - SDO->block_noData; - SDO->bufOffsetRd -= cntFailed; - SDO->sizeTran -= cntFailed; - } - else if (SDO->CANrxData[1] > SDO->block_seqno) { - /* something strange from server, break transmission */ - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; - break; - } + /* check number of segments */ + if (SDO->CANrxData[1] < SDO->block_seqno) { + /* NOT all segments transferred successfully. + * Re-transmit data after erroneous segment. */ + OD_size_t cntFailed = SDO->block_seqno - SDO->CANrxData[1]; + cntFailed = cntFailed * 7 - SDO->block_noData; + SDO->bufOffsetRd -= cntFailed; + SDO->sizeTran -= cntFailed; + } + else if (SDO->CANrxData[1] > SDO->block_seqno) { + /* something strange from server, break transmission */ + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; + break; + } - /* refill data buffer if necessary */ - if (!readFromOd(SDO, &abortCode, SDO->block_blksize * 7, true)) - break; + /* refill data buffer if necessary */ + if (!readFromOd(SDO, &abortCode, SDO->block_blksize * 7, true)) + break; - if (SDO->bufOffsetWr == SDO->bufOffsetRd) { - SDO->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; + if (SDO->bufOffsetWr == SDO->bufOffsetRd) { + SDO->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; + } + else { + SDO->block_seqno = 0; + SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + } } else { - SDO->block_seqno = 0; - SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; } + break; } - else { +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ + + default: { + /* unknown message received */ abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; + break; } - break; - } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ - - default: { - /* unknown message received */ - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; - break; - } - } /* switch (SDO->state) */ + } /* switch (SDO->state) */ } /* if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) */ #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 SDO->timeoutTimer = 0; From 64934d7903280a88db2b327e5b377f86b52d0b19 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:44:11 +0200 Subject: [PATCH 330/520] CO_SYNC: static analysis: cannot assign 'unsigned32' to narrower essential type 'unsigned16' [MISRA 2012 Rule 10.3, required] --- 301/CO_SYNC.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index b1da86ca..bb245305 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -308,7 +308,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, SYNC->isProducer = (cobIdSync & 0x40000000U) != 0U; #endif #if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 - SYNC->CAN_ID = cobIdSync & 0x7FFU; + SYNC->CAN_ID = (uint16_t)(cobIdSync & 0x7FFU); SYNC->CANdevRx = CANdevRx; SYNC->CANdevRxIdx = CANdevRxIdx; #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 @@ -321,7 +321,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, CO_ReturnError_t ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ - cobIdSync & 0x7FFU, /* CAN identifier */ + (uint16_t)(cobIdSync & 0x7FFU), /* CAN identifier */ 0x7FF, /* mask */ false, /* rtr */ (void*)SYNC, /* object passed to receive function */ From 860a36c85fb3af07fc68426d445adfe0c911db74 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:46:27 +0200 Subject: [PATCH 331/520] CO_SYNC: static analysis: unsigned integer literal without a 'U' suffix [MISRA 2012 Rule 7.2, required] --- 301/CO_SYNC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index bb245305..21fa7e6e 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -413,7 +413,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, /* periodTimeout is 1,5 * OD_1006_period, no overflow */ uint32_t periodTimeout = OD_1006_period + (OD_1006_period >> 1); if (periodTimeout < OD_1006_period) { - periodTimeout = 0xFFFFFFFF; + periodTimeout = 0xFFFFFFFFU; } if (SYNC->timer > periodTimeout) { From 9c79067c53206128780b946cc3a6c18db02df7f3 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:49:28 +0200 Subject: [PATCH 332/520] CO_TIME: static analysis: cannot assign 'unsigned32' to narrower essential type 'unsigned16' [MISRA 2012 Rule 10.3, required] --- 301/CO_TIME.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 0e06213a..9479d5da 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -74,7 +74,7 @@ static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, /* verify written value */ uint32_t cobIdTimeStamp = CO_getUint32(buf); - uint16_t CAN_ID = cobIdTimeStamp & 0x7FFU; + uint16_t CAN_ID = (uint16_t)(cobIdTimeStamp & 0x7FFU); if (((cobIdTimeStamp & 0x3FFFF800U) != 0U) || CO_IS_RESTRICTED_CAN_ID(CAN_ID)) { return ODR_INVALID_VALUE; } @@ -125,7 +125,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, #endif /* Configure object variables */ - uint16_t cobId = cobIdTimeStamp & 0x7FFU; + uint16_t cobId = (uint16_t)(cobIdTimeStamp & 0x7FFU); TIME->isConsumer = (cobIdTimeStamp & 0x80000000UL) != 0U; TIME->isProducer = (cobIdTimeStamp & 0x40000000UL) != 0U; CO_FLAG_CLEAR(TIME->CANrxNew); @@ -206,7 +206,7 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, if (!timestampReceived && (timeDifference_us > 0U)) { uint32_t us = timeDifference_us + TIME->residual_us; ms = us / 1000U; - TIME->residual_us = us % 1000U; + TIME->residual_us = (uint16_t)(us % 1000U); TIME->ms += ms; if (TIME->ms >= ((uint32_t)1000U*60U*60U*24U)) { TIME->ms -= ((uint32_t)1000U*60U*60U*24U); From bc920558acde982f92b96aba850956eda40e4d6e Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:51:13 +0200 Subject: [PATCH 333/520] CO_TIME: static analysis: unexpected lack of indentation (convert tab to space) --- 301/CO_TIME.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 9479d5da..946eb868 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -131,7 +131,7 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, CO_FLAG_CLEAR(TIME->CANrxNew); /* configure TIME consumer message reception */ - if (TIME->isConsumer) { + if (TIME->isConsumer) { CO_ReturnError_t ret = CO_CANrxBufferInit( CANdevRx, /* CAN device */ CANdevRxIdx, /* rx buffer index */ From 20d7220468771be86f5cfb396fc7bf03c530c875 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:56:00 +0200 Subject: [PATCH 334/520] crc16-ccitt: static analysis: loss of precision (assignment) --- 301/crc16-ccitt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/301/crc16-ccitt.c b/301/crc16-ccitt.c index 432af134..c8ecd498 100644 --- a/301/crc16-ccitt.c +++ b/301/crc16-ccitt.c @@ -84,7 +84,7 @@ static const uint16_t crc16_ccitt_table[256] = { /******************************************************************************/ void crc16_ccitt_single(uint16_t *crc, const uint8_t chr) { uint8_t tmp = (uint8_t)(*crc >> 8U) ^ chr; - *crc = (*crc << 8U) ^ crc16_ccitt_table[tmp]; + *crc = (uint16_t)((*crc << 8U) ^ crc16_ccitt_table[tmp]); } @@ -96,8 +96,8 @@ uint16_t crc16_ccitt(const uint8_t block[], size_t i; for (i = 0U; i < blockLength; i++) { - uint8_t tmp = (uint8_t)(crc >> 8U) ^ block[i]; - crc = (crc << 8U) ^ crc16_ccitt_table[tmp]; + uint8_t tmp = (uint8_t)((uint8_t)(crc >> 8U) ^ block[i]); + crc = (uint16_t)((crc << 8U) ^ crc16_ccitt_table[tmp]); } return crc; } From 3e6f9c79d10fb1fe489ef67ec637c3da3cebccb9 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:57:48 +0200 Subject: [PATCH 335/520] CO_LEDs: static analysis: result of assignment operator used in right operand to '=' operator [MISRA 2012 Rule 13.4, advisory] --- 303/CO_LEDs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 9b24f320..a27616bd 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -73,7 +73,8 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, if (++LEDs->LEDtmr200ms > 3U) { /* calculate 2,5Hz blinking and flashing */ LEDs->LEDtmr200ms = 0; - rd = gr = 0; + rd = 0; + gr = 0; if ((LEDs->LEDred & (uint8_t)CO_LED_blink) == 0U) { rd |= (uint8_t)CO_LED_blink; } else { gr |= (uint8_t)CO_LED_blink; } From c99b8ae07aca65bf357a8e597bc40bfd661a6244 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 13:58:53 +0200 Subject: [PATCH 336/520] CO_LEDs: static analysis: statement or comment should appear in default case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.4, required] --- 303/CO_LEDs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index a27616bd..2b82414e 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -83,25 +83,25 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, case 1: rd |= (uint8_t)CO_LED_flash_1; break; case 2: gr |= (uint8_t)CO_LED_flash_1; break; case 6: LEDs->LEDtmrflash_1 = 0; break; - default: break; + default: /* none */ break; } switch (++LEDs->LEDtmrflash_2) { case 1: case 3: rd |= (uint8_t)CO_LED_flash_2; break; case 2: case 4: gr |= (uint8_t)CO_LED_flash_2; break; case 8: LEDs->LEDtmrflash_2 = 0; break; - default: break; + default: /* none */ break; } switch (++LEDs->LEDtmrflash_3) { case 1: case 3: case 5: rd |= (uint8_t)CO_LED_flash_3; break; case 2: case 4: case 6: gr |= (uint8_t)CO_LED_flash_3; break; case 10: LEDs->LEDtmrflash_3 = 0; break; - default: break; + default: /* none */ break; } switch (++LEDs->LEDtmrflash_4) { case 1: case 3: case 5: case 7: rd |= (uint8_t)CO_LED_flash_4; break; case 2: case 4: case 6: case 8: gr |= (uint8_t)CO_LED_flash_4; break; case 12: LEDs->LEDtmrflash_4 = 0; break; - default: break; + default: /* none */ break; } } else { From 8755f23d79c1a578b4563f71b7d436e5811466f1 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:02:17 +0200 Subject: [PATCH 337/520] CO_SRDO: static analysis: argument of type 'const void *' is not compatible with argument of type in call to function memcmp and memcpy --- 304/CO_SRDO.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index f8b4d610..b510f017 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -155,7 +155,7 @@ OD_not_write_same_value(OD_stream_t *stream, const void *buf, OD_size_t count) { if ( returnCode != ODR_OK ){ return false; } - if ( memcmp(buf,bufRead,count) == 0 ){ + if ( memcmp((const void *)(buf),(const void *)(bufRead),count) == 0 ){ return true; } return false; @@ -199,7 +199,7 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t CO_SRDO_t* SRDO = stream->object; CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; uint8_t bufCopy[4]; - (void)memcpy(bufCopy, buf, count); + (void)memcpy((void *)(bufCopy), (const void *)(buf), count); /* Writing Object Dictionary variable */ if (SRDOGuard->NMTisOperational) { From 3c53895fdefb45bd04d4086de81217e27684b528 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:14:34 +0200 Subject: [PATCH 338/520] CO_SRDO: static analysis: cannot cast to wider essential type [MISRA 2012 Rule 10.8, required] --- 304/CO_SRDO.c | 62 +++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index b510f017..220b60ce 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -171,7 +171,7 @@ OD_read_SRDO_communicationParam(OD_stream_t* stream, void* buf, OD_size_t count, CO_SRDO_t* SRDO = stream->object; uint32_t value = CO_getUint32(buf); - uint16_t defaultCOB_ID = SRDO->defaultCOB_ID + (stream->subIndex - 5U); + uint16_t defaultCOB_ID = SRDO->defaultCOB_ID + ((uint16_t)(stream->subIndex) - 5U); /* If default COB ID is used, then OD entry does not contain $NodeId. Add it here. */ if ((value == defaultCOB_ID) && (SRDO->nodeId <= 64U)) { @@ -230,7 +230,7 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t } } else if ((stream->subIndex == 5U) || (stream->subIndex == 6U)) { /* COB_ID */ uint32_t value = CO_getUint32(buf); - uint16_t index = stream->subIndex - 5U; + uint16_t index = (uint16_t)(stream->subIndex) - 5U; uint16_t defaultCOB_ID = SRDO->defaultCOB_ID + index; /* check value range, the spec does not specify if COB-ID flags are allowed */ @@ -459,39 +459,39 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* Get variables from object Dictionary and verify it's structure. */ if (err == 0U) { if (OD_get_u8(OD_130x_SRDOCommPar, 0, &cp_highestSubindexSupported, true) != ODR_OK) { - err = ERR_INFO(0x1301U + SRDO_Index, 0, 1); + err = ERR_INFO(0x1301UL + SRDO_Index, 0, 1); } else if (OD_get_u8(OD_130x_SRDOCommPar, 1, &informationDirection, true) != ODR_OK) { - err = ERR_INFO(0x1301U + SRDO_Index, 1, 1); + err = ERR_INFO(0x1301UL + SRDO_Index, 1, 1); } else if (OD_get_u16(OD_130x_SRDOCommPar, 2, &safetyCycleTime, true) != ODR_OK) { - err = ERR_INFO(0x1301U + SRDO_Index, 2, 1); + err = ERR_INFO(0x1301UL + SRDO_Index, 2, 1); } else if (OD_get_u8(OD_130x_SRDOCommPar, 3, &safetyRelatedValidationTime, true) != ODR_OK) { - err = ERR_INFO(0x1301U + SRDO_Index, 3, 1); + err = ERR_INFO(0x1301UL + SRDO_Index, 3, 1); } else if (OD_get_u8(OD_130x_SRDOCommPar, 4, &transmissionType, true) != ODR_OK) { - err = ERR_INFO(0x1301U + SRDO_Index, 4, 1); + err = ERR_INFO(0x1301UL + SRDO_Index, 4, 1); } else if (OD_get_u32(OD_130x_SRDOCommPar, 5, &COB_ID1_normal, true) != ODR_OK) { - err = ERR_INFO(0x1301U + SRDO_Index, 5, 1); + err = ERR_INFO(0x1301UL + SRDO_Index, 5, 1); } else if (OD_get_u32(OD_130x_SRDOCommPar, 6, &COB_ID2_inverted, true) != ODR_OK) { - err = ERR_INFO(0x1301U + SRDO_Index, 6, 1); + err = ERR_INFO(0x1301UL + SRDO_Index, 6, 1); } else if (OD_get_u8(OD_13FE_configurationValid, 0, &configurationValid, true) != ODR_OK) { - err = ERR_INFO(0x13FEU, 0, 1); + err = ERR_INFO(0x13FEUL, 0, 1); } else if (OD_get_u16(OD_13FF_safetyConfigurationSignature, SRDO_Index + 1U, &crcSignatureFromOD, true) != ODR_OK) { - err = ERR_INFO(0x13FFU, SRDO_Index + 1U, 1); + err = ERR_INFO(0x13FFUL, SRDO_Index + 1UL, 1); } else if (OD_get_u8(OD_138x_SRDOMapPar, 0, &mappedObjectsCount, true) != ODR_OK) { - err = ERR_INFO(0x1381U + SRDO_Index, 0, 1); + err = ERR_INFO(0x1381UL + SRDO_Index, 0, 1); } else { for (uint8_t i = 0; i < mappedObjectsCount; i++) { if (OD_get_u32(OD_138x_SRDOMapPar, i+1U, &mapping[i], true) != ODR_OK) { - err = ERR_INFO(0x1381U + SRDO_Index, i+1U, 1); + err = ERR_INFO(0x1381UL + SRDO_Index, i+1UL, 1); break; } } @@ -518,28 +518,28 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* Verify parameters from OD */ if ((err == 0U) && configurationInProgress) { if (cp_highestSubindexSupported != 6U) { - err = ERR_INFO(0x1301U + SRDO_Index, 0, 2); + err = ERR_INFO(0x1301UL + SRDO_Index, 0, 2); } else if (informationDirection > 3U) { - err = ERR_INFO(0x1301U + SRDO_Index, 1, 2); + err = ERR_INFO(0x1301UL + SRDO_Index, 1, 2); } else if (safetyCycleTime < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000U) + 1U)) { - err = ERR_INFO(0x1301U + SRDO_Index, 2, 2); + err = ERR_INFO(0x1301UL + SRDO_Index, 2, 2); } else if (safetyRelatedValidationTime < 1U) { - err = ERR_INFO(0x1301U + SRDO_Index, 3, 2); + err = ERR_INFO(0x1301UL + SRDO_Index, 3, 2); } else if (transmissionType != 254U) { - err = ERR_INFO(0x1301U + SRDO_Index, 4, 2); + err = ERR_INFO(0x1301UL + SRDO_Index, 4, 2); } else if ((COB_ID1_normal < 0x101U) || ((COB_ID1_normal & 1U) == 0U)) { - err = ERR_INFO(0x1301U + SRDO_Index, 5, 2); + err = ERR_INFO(0x1301UL + SRDO_Index, 5, 2); } else if (((COB_ID1_normal + 1U) != COB_ID2_inverted) || (COB_ID2_inverted > 0x180U)) { - err = ERR_INFO(0x1301U + SRDO_Index, 6, 2); + err = ERR_INFO(0x1301UL + SRDO_Index, 6, 2); } else if ((mappedObjectsCount > CO_SRDO_MAX_MAPPED_ENTRIES) || ((mappedObjectsCount & 1U) != 0U)) { - err = ERR_INFO(0x1381U + SRDO_Index, 0, 2); + err = ERR_INFO(0x1381UL + SRDO_Index, 0, 2); } else { /* MISRA C 2004 14.10 */ @@ -569,7 +569,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } if (crcResult != crcSignatureFromOD) { - err = ERR_INFO(0x13FFU, SRDO_Index + 1U, 3); + err = ERR_INFO(0x13FFUL, SRDO_Index + 1UL, 3); } } @@ -588,7 +588,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* total SRDO length can not be more than CO_SRDO_MAX_SIZE bytes */ if (mappedLength > CO_SRDO_MAX_SIZE) { - err = ERR_INFO(0x1381U + SRDO_Index, i + 1U, 4); + err = ERR_INFO(0x1381UL + SRDO_Index, i + 1UL, 4); } /* is there a reference to the dummy entry */ else if ((index < 0x20U) && (subIndex == 0U)) { @@ -605,7 +605,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ OD_entry_t *entry = OD_find(OD, index); ODR_t odRet = OD_getSub(entry, subIndex, &OD_IOcopy, false); if (odRet != ODR_OK) { - err = ERR_INFO(0x1381U + SRDO_Index, i + 1U, 5); + err = ERR_INFO(0x1381UL + SRDO_Index, i + 1UL, 5); } else { /* verify access attributes, byte alignment and length */ @@ -614,7 +614,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ || ((mappedLengthBits & 0x07U) != 0U) || (OD_IOcopy.stream.dataLength < mappedLength) ) { - err = ERR_INFO(0x1381U + SRDO_Index, i + 1U, 6); + err = ERR_INFO(0x1381UL + SRDO_Index, i + 1UL, 6); } /* Copy values and store mappedLength temporary. */ @@ -630,10 +630,10 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ if (err == 0U) { if (srdoDataLength[0] != srdoDataLength[1]) { - err = ERR_INFO(0x1381U + SRDO_Index, 0, 7); + err = ERR_INFO(0x1381UL + SRDO_Index, 0, 7); } else if ((srdoDataLength[0] == 0U) || (srdoDataLength[0] > CO_SRDO_MAX_SIZE)) { - err = ERR_INFO(0x1381U + SRDO_Index, 0, 8); + err = ERR_INFO(0x1381UL + SRDO_Index, 0, 8); } else { SRDO->dataLength = srdoDataLength[0]; @@ -653,7 +653,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ false); /* synchronous message flag bit */ if (SRDO->CANtxBuff[0] == NULL) { - err = ERR_INFO(0x1301U + SRDO_Index, 5, 10); + err = ERR_INFO(0x1301UL + SRDO_Index, 5, 10); } SRDO->CANtxBuff[1] = CO_CANtxBufferInit(CANdevTxInverted, /* CAN device */ @@ -664,7 +664,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ false); /* synchronous message flag bit */ if (SRDO->CANtxBuff[1] == NULL) { - err = ERR_INFO(0x1301U + SRDO_Index, 6, 10); + err = ERR_INFO(0x1301UL + SRDO_Index, 6, 10); } } @@ -680,7 +680,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ CO_SRDO_receive_normal); /* this function will process received message */ if (ret != CO_ERROR_NO) { - err = ERR_INFO(0x1301U + SRDO_Index, 5, 11); + err = ERR_INFO(0x1301UL + SRDO_Index, 5, 11); } ret = CO_CANrxBufferInit(CANdevRxInverted, /* CAN device */ @@ -692,7 +692,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ CO_SRDO_receive_inverted); /* this function will process received message */ if (ret != CO_ERROR_NO) { - err = ERR_INFO(0x1301U + SRDO_Index, 6, 11); + err = ERR_INFO(0x1301UL + SRDO_Index, 6, 11); } } From 3b893788414934647e21fb2fda1053bc1e6ebb46 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:18:01 +0200 Subject: [PATCH 339/520] CO_SRDO: static analysis: right operand to == is a composite expression of type 'unsigned16' which is smaller than the left operand of type 'unsigned32' [MISRA 2012 Rule 10.7, required] --- 304/CO_SRDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 220b60ce..41b1f355 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -498,7 +498,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* if OD contains default COB_IDs, add node-id */ - if ((COB_ID1_normal == defaultCOB_ID) && (COB_ID2_inverted == (defaultCOB_ID + 1U)) && (nodeId <= 64U)) { + if ((COB_ID1_normal == defaultCOB_ID) && (COB_ID2_inverted == (uint32_t)(defaultCOB_ID + 1U)) && (nodeId <= 64U)) { uint32_t add = (uint32_t)SRDO->nodeId * 2U; COB_ID1_normal += add; COB_ID2_inverted += add; From 6cf0200afbef5bd6d4b47c1b66b29c93803676ea Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:19:33 +0200 Subject: [PATCH 340/520] CO_SRDO: static analysis: result of assignment operator used in right operand to '=' operator [MISRA 2012 Rule 13.4, advisory] --- 304/CO_SRDO.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 41b1f355..f0969142 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -880,7 +880,8 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } /* inverted message received */ else { - SRDO->cycleTimer = SRDO->validationTimer = SRDO->cycleTime_us; + SRDO->cycleTimer = SRDO->cycleTime_us; + SRDO->validationTimer = SRDO->cycleTime_us; SRDO->nextIsNormal = true; uint8_t *dataSRDO[2] = {&SRDO->CANrxData[0][0], &SRDO->CANrxData[1][0]}; @@ -1010,7 +1011,8 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } } - SRDO->NMTisOperationalPrevious = SRDO->SRDOGuard->NMTisOperational = NMTisOperational; + SRDO->NMTisOperationalPrevious = NMTisOperational; + SRDO->SRDOGuard->NMTisOperational = NMTisOperational; return SRDO->internalState; } From f112105cdec560e9cc790e301bf61f7eb71bbfe6 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:22:14 +0200 Subject: [PATCH 341/520] CO_SRDO: static analysis: cannot cast 'unsigned16' to wider essential type 'unsigned32' [MISRA 2012 Rule 10.8, required] --- 304/CO_SRDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index f0969142..f78a7ade 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -498,7 +498,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* if OD contains default COB_IDs, add node-id */ - if ((COB_ID1_normal == defaultCOB_ID) && (COB_ID2_inverted == (uint32_t)(defaultCOB_ID + 1U)) && (nodeId <= 64U)) { + if ((COB_ID1_normal == defaultCOB_ID) && (COB_ID2_inverted == ((uint32_t)defaultCOB_ID + 1UL)) && (nodeId <= 64U)) { uint32_t add = (uint32_t)SRDO->nodeId * 2U; COB_ID1_normal += add; COB_ID2_inverted += add; From 6f4df2bdeb2b48f8e5518095b4415b709fdade64 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:24:25 +0200 Subject: [PATCH 342/520] CO_SRDO: static analysis: 'subIndex' is typographically ambiguous with respect to 'subindex' when ignoring case [MISRA 2012 Directive 4.5, advisory] --- 304/CO_SRDO.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index f78a7ade..16e270ed 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -562,8 +562,8 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ crcResult = crc16_ccitt((uint8_t *)&tmp_u32, 4, crcResult); crcResult = crc16_ccitt(&mappedObjectsCount, 1, crcResult); for (uint8_t i = 0; i < mappedObjectsCount; i++) { - uint8_t subindex = i + 1U; - crcResult = crc16_ccitt(&subindex, 1, crcResult); + uint8_t crcsubindex = i + 1U; + crcResult = crc16_ccitt(&crcsubindex, 1, crcResult); tmp_u32 = CO_SWAP_32(mapping[i]); crcResult = crc16_ccitt((uint8_t *)&tmp_u32, 4, crcResult); } From 5337877ac7c844cbfb4ee97e217b977c8d27a84c Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:29:24 +0200 Subject: [PATCH 343/520] CO_SRDO: static analysis: cannot assign 'enum (OD_attributes_t)' to different essential type 'unsigned8' [MISRA 2012 Rule 10.3, required] --- 304/CO_SRDO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 16e270ed..c4818957 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -609,7 +609,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } else { /* verify access attributes, byte alignment and length */ - OD_attr_t testAttribute = (informationDirection == CO_SRDO_RX) ? ODA_RSRDO : ODA_TSRDO; + OD_attr_t testAttribute = (informationDirection == CO_SRDO_RX) ? (OD_attr_t)(ODA_RSRDO) : (OD_attr_t)(ODA_TSRDO); if (((OD_IOcopy.stream.attribute & testAttribute) == 0U) || ((mappedLengthBits & 0x07U) != 0U) || (OD_IOcopy.stream.dataLength < mappedLength) From 2d03662a23061bfcec20113c9ae4ce038fb384b2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:37:28 +0200 Subject: [PATCH 344/520] CO_LSSslave: static analysis: statement or comment should appear in default case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.4, required] --- 305/CO_LSSslave.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 32fa56c8..50f8b072 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -76,6 +76,7 @@ static void CO_LSSslave_receive(void *object, void *msg) LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; break; default: + /* none */ break; } } @@ -175,6 +176,7 @@ static void CO_LSSslave_receive(void *object, void *msg) break; } default: { + /* none */ break; } } @@ -481,6 +483,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { break; } default: { + /* none */ break; } } From 08e7903332e38abbd01a1e7794a5784da8b420e1 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:41:34 +0200 Subject: [PATCH 345/520] CO_LSSslave: static analysis argument 1 is not compatible with argument 2 in call to function 'memcpy' --- 305/CO_LSSslave.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 50f8b072..63b95f6f 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -84,25 +84,25 @@ static void CO_LSSslave_receive(void *object, void *msg) switch (cs) { case CO_LSS_SWITCH_STATE_SEL_VENDOR: { uint32_t valSw; - (void)memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); LSSslave->lssSelect.identity.vendorID = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_PRODUCT: { uint32_t valSw; - (void)memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); LSSslave->lssSelect.identity.productCode = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_REV: { uint32_t valSw; - (void)memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); LSSslave->lssSelect.identity.revisionNumber = CO_SWAP_32(valSw); break; } case CO_LSS_SWITCH_STATE_SEL_SERIAL: { uint32_t valSw; - (void)memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); LSSslave->lssSelect.identity.serialNumber = CO_SWAP_32(valSw); if (CO_LSS_ADDRESS_EQUAL(LSSslave->lssAddress, @@ -133,7 +133,7 @@ static void CO_LSSslave_receive(void *object, void *msg) break; } - (void)memcpy(&valSw, &data[1], sizeof(valSw)); + (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); idNumber = CO_SWAP_32(valSw); ack = false; @@ -182,7 +182,7 @@ static void CO_LSSslave_receive(void *object, void *msg) } } else { /* LSSslave->lssState == CO_LSS_STATE_CONFIGURATION */ - (void)memcpy(&LSSslave->CANdata, &data[0], sizeof(LSSslave->CANdata)); + (void)memcpy((void *)(&LSSslave->CANdata), (const void *)(&data[0]), sizeof(LSSslave->CANdata)); LSSslave->service = cs; request_LSSslave_process = true; } @@ -446,28 +446,28 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { case CO_LSS_INQUIRE_VENDOR: { LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.vendorID); - (void)memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); + (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_PRODUCT: { LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.productCode); - (void)memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); + (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_REV: { LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.revisionNumber); - (void)memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); + (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_SERIAL: { LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.serialNumber); - (void)memcpy(&LSSslave->TXbuff->data[1], &valSw, sizeof(valSw)); + (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } From cd1f38971904547ccb30a7c0868a8138630d65c2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:46:02 +0200 Subject: [PATCH 346/520] CO_LSSslave: static analysis: cannot assign 'enum' to different essential type [MISRA 2012 Rule 10.3, required] --- 305/CO_LSSslave.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 63b95f6f..04686840 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -140,7 +140,7 @@ static void CO_LSSslave_receive(void *object, void *msg) if (bitCheck == (uint8_t)CO_LSS_FASTSCAN_CONFIRM) { /* Confirm, Reset */ ack = true; - LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; + LSSslave->fastscanPos = (uint8_t)(CO_LSS_FASTSCAN_VENDOR_ID); (void)memset(&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); } @@ -232,7 +232,7 @@ CO_ReturnError_t CO_LSSslave_init( /* Configure object variables */ (void)memcpy(&LSSslave->lssAddress, lssAddress, sizeof(LSSslave->lssAddress)); LSSslave->lssState = CO_LSS_STATE_WAITING; - LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; + LSSslave->fastscanPos = (uint8_t)(CO_LSS_FASTSCAN_VENDOR_ID); LSSslave->pendingBitRate = pendingBitRate; LSSslave->pendingNodeID = pendingNodeID; @@ -344,23 +344,23 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { break; } case CO_LSS_SWITCH_STATE_SEL_SERIAL: { - LSSslave->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL; + LSSslave->TXbuff->data[0] = (uint8_t)(CO_LSS_SWITCH_STATE_SEL); CANsend = true; break; } case CO_LSS_CFG_NODE_ID: { nid = LSSslave->CANdata[1]; - errorCode = CO_LSS_CFG_NODE_ID_OK; + errorCode = (uint8_t)(CO_LSS_CFG_NODE_ID_OK); if (CO_LSS_NODE_ID_VALID(nid)) { *LSSslave->pendingNodeID = nid; } else { - errorCode = CO_LSS_CFG_NODE_ID_OUT_OF_RANGE; + errorCode = (uint8_t)(CO_LSS_CFG_NODE_ID_OUT_OF_RANGE); } /* send confirmation */ - LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); LSSslave->TXbuff->data[1] = errorCode; /* we do not use spec-error, always 0 */ CANsend = true; @@ -374,8 +374,8 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { tableSelector = LSSslave->CANdata[1]; tableIndex = LSSslave->CANdata[2]; - errorCode = CO_LSS_CFG_BIT_TIMING_OK; - errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OK; + errorCode = (uint8_t)(CO_LSS_CFG_BIT_TIMING_OK); + errorCodeManuf = (uint8_t)(CO_LSS_CFG_BIT_TIMING_OK); if ((tableSelector == 0U) && CO_LSS_BIT_TIMING_VALID(tableIndex)) { uint16_t bit = CO_LSS_bitTimingTableLookup[tableIndex]; @@ -386,17 +386,17 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { *LSSslave->pendingBitRate = bit; } else { - errorCode = CO_LSS_CFG_BIT_TIMING_MANUFACTURER; - errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; + errorCode = (uint8_t)(CO_LSS_CFG_BIT_TIMING_MANUFACTURER); + errorCodeManuf = (uint8_t)(CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE); } } else { /* we currently only support CiA301 bit timing table */ - errorCode = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; + errorCode = (uint8_t)(CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE); } /* send confirmation */ - LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); LSSslave->TXbuff->data[1] = errorCode; LSSslave->TXbuff->data[2] = errorCodeManuf; CANsend = true; @@ -418,11 +418,11 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { break; } case CO_LSS_CFG_STORE: { - errorCode = CO_LSS_CFG_STORE_OK; + errorCode = (uint8_t)(CO_LSS_CFG_STORE_OK); if (LSSslave->pFunctLSScfgStore == NULL) { /* storing is not supported. Reply error */ - errorCode = CO_LSS_CFG_STORE_NOT_SUPPORTED; + errorCode = (uint8_t)(CO_LSS_CFG_STORE_NOT_SUPPORTED); } else { bool_t result; @@ -432,53 +432,53 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { *LSSslave->pendingNodeID, *LSSslave->pendingBitRate); if (!result) { - errorCode = CO_LSS_CFG_STORE_FAILED; + errorCode = (uint8_t)(CO_LSS_CFG_STORE_FAILED); } } /* send confirmation */ - LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); LSSslave->TXbuff->data[1] = errorCode; /* we do not use spec-error, always 0 */ CANsend = true; break; } case CO_LSS_INQUIRE_VENDOR: { - LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); valSw = CO_SWAP_32(LSSslave->lssAddress.identity.vendorID); (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_PRODUCT: { - LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); valSw = CO_SWAP_32(LSSslave->lssAddress.identity.productCode); (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_REV: { - LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); valSw = CO_SWAP_32(LSSslave->lssAddress.identity.revisionNumber); (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_SERIAL: { - LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); valSw = CO_SWAP_32(LSSslave->lssAddress.identity.serialNumber); (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_NODE_ID: { - LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); LSSslave->TXbuff->data[1] = LSSslave->activeNodeID; CANsend = true; break; } case CO_LSS_IDENT_FASTSCAN: { - LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; + LSSslave->TXbuff->data[0] = (uint8_t)(CO_LSS_IDENT_SLAVE); CANsend = true; break; } From f1e68448c1321fa0255d17251c94b482ddf49a75 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:48:23 +0200 Subject: [PATCH 347/520] CO_LSSslave: static analysis: unsigned integer literal without a 'U' suffix [MISRA 2012 Rule 7.2, required] --- 305/CO_LSSslave.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 04686840..c15f6d9a 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -145,7 +145,7 @@ static void CO_LSSslave_receive(void *object, void *msg) sizeof(LSSslave->lssFastscan)); } else if (LSSslave->fastscanPos == lssSub) { - uint32_t mask = 0xFFFFFFFF << bitCheck; + uint32_t mask = 0xFFFFFFFFU << bitCheck; if ((LSSslave->lssAddress.addr[lssSub] & mask) == (idNumber & mask)) From d64f0dcc418d0950f658c15ea9c320be60312846 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:50:32 +0200 Subject: [PATCH 348/520] CO_LSSslave: static analysis: taking address of array --- 305/CO_LSSslave.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index c15f6d9a..00adcaa9 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -182,7 +182,7 @@ static void CO_LSSslave_receive(void *object, void *msg) } } else { /* LSSslave->lssState == CO_LSS_STATE_CONFIGURATION */ - (void)memcpy((void *)(&LSSslave->CANdata), (const void *)(&data[0]), sizeof(LSSslave->CANdata)); + (void)memcpy((void *)(&LSSslave->CANdata[0]), (const void *)(&data[0]), sizeof(LSSslave->CANdata)); LSSslave->service = cs; request_LSSslave_process = true; } From d0718824f2f0eed38fa07c4e7ab5ab0a7bc279a6 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 14:55:36 +0200 Subject: [PATCH 349/520] CO_storage: static analysis: body should be a compound statement [MISRA 2012 Rule 15.6, required] --- storage/CO_storage.c | 30 ++++++++++++++++++++++-------- storage/CO_storageEeprom.c | 7 +++++-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/storage/CO_storage.c b/storage/CO_storage.c index bc897c7d..b8c55385 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -60,19 +60,26 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, CO_storage_entry_t *entry = &storage->entries[i]; if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { - if (found == 0U) found = 1; + if (found == 0U) { + found = 1; + } if ((entry->attr & (uint8_t)CO_storage_cmd) != 0U) { ODR_t code = storage->store(entry, storage->CANmodule); - if (code != ODR_OK) returnCode = code; + if (code != ODR_OK) { + returnCode = code; + } found = 2; } } } - if (found != 2U) + if (found != 2U) { returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY; + } - if (returnCode == ODR_OK) *countWritten = sizeof(uint32_t); + if (returnCode == ODR_OK) { + *countWritten = sizeof(uint32_t); + } return returnCode; } @@ -111,19 +118,26 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, CO_storage_entry_t *entry = &storage->entries[i]; if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { - if (found == 0U) found = 1; + if (found == 0U) { + found = 1; + } if ((entry->attr & (uint8_t)CO_storage_restore) != 0U) { ODR_t code = storage->restore(entry, storage->CANmodule); - if (code != ODR_OK) returnCode = code; + if (code != ODR_OK) { + returnCode = code; + } found = 2; } } } - if (found != 2U) + if (found != 2U) { returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY; + } - if (returnCode == ODR_OK) *countWritten = sizeof(uint32_t); + if (returnCode == ODR_OK) { + *countWritten = sizeof(uint32_t); + } return returnCode; } diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 3a49eba5..ef066bca 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -211,7 +211,9 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, /* additional info in case of error */ if (dataCorrupt) { uint32_t errorBit = entry->subIndexOD; - if (errorBit > 31U) errorBit = 31; + if (errorBit > 31U) { + errorBit = 31; + } *storageInitError |= ((uint32_t) 1) << errorBit; ret = CO_ERROR_DATA_CORRUPT; } @@ -233,8 +235,9 @@ void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { for (uint8_t i = 0; i < storage->entriesCount; i++) { CO_storage_entry_t *entry = &storage->entries[i]; - if ((entry->attr & (uint8_t)CO_storage_auto) == 0U) + if ((entry->attr & (uint8_t)CO_storage_auto) == 0U) { continue; + } if (saveAll) { /* update all bytes */ From 2f8f4395cfa55cdd16273c50f70b37d4c14b982a Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 15:01:19 +0200 Subject: [PATCH 350/520] CO_storage: static analysis: refactoring OD_extension_init with ignore return value because verify arguments at function entry --- storage/CO_storage.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/storage/CO_storage.c b/storage/CO_storage.c index b8c55385..f4068d64 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -154,7 +154,9 @@ CO_ReturnError_t CO_storage_init(CO_storage_t *storage, uint8_t entriesCount) { /* verify arguments */ - if (storage == NULL) { + if ((storage == NULL) || (CANmodule == NULL) || (OD_1010_StoreParameters == NULL) || (OD_1011_RestoreDefaultParameters == NULL) + || (store == NULL) || (restore == NULL) || (entries == NULL) + ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -166,20 +168,16 @@ CO_ReturnError_t CO_storage_init(CO_storage_t *storage, storage->entriesCount = entriesCount; /* configure extensions */ - if (OD_1010_StoreParameters != NULL) { - storage->OD_1010_extension.object = storage; - storage->OD_1010_extension.read = OD_readOriginal; - storage->OD_1010_extension.write = OD_write_1010; - OD_extension_init(OD_1010_StoreParameters, &storage->OD_1010_extension); - } - - if (OD_1011_RestoreDefaultParameters != NULL) { - storage->OD_1011_extension.object = storage; - storage->OD_1011_extension.read = OD_readOriginal; - storage->OD_1011_extension.write = OD_write_1011; - OD_extension_init(OD_1011_RestoreDefaultParameters, - &storage->OD_1011_extension); - } + storage->OD_1010_extension.object = storage; + storage->OD_1010_extension.read = OD_readOriginal; + storage->OD_1010_extension.write = OD_write_1010; + (void)OD_extension_init(OD_1010_StoreParameters, &storage->OD_1010_extension); + + storage->OD_1011_extension.object = storage; + storage->OD_1011_extension.read = OD_readOriginal; + storage->OD_1011_extension.write = OD_write_1011; + (void)OD_extension_init(OD_1011_RestoreDefaultParameters, + &storage->OD_1011_extension); return CO_ERROR_NO; } From 5907aa27cf20a0e58d008528b1e2709f1aaa3e53 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 15:03:54 +0200 Subject: [PATCH 351/520] CO_storageEeprom: static analysis: unsigned integer literal without a 'U' suffix [MISRA 2012 Rule 7.2, required] --- storage/CO_storageEeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index ef066bca..7c2f87f2 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -83,7 +83,7 @@ static ODR_t restoreEeprom(CO_storage_entry_t *entry, bool_t writeOk; /* Write empty signature */ - uint32_t signature = 0xFFFFFFFF; + uint32_t signature = 0xFFFFFFFFU; writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t *)&signature, entry->eepromAddrSignature, @@ -127,7 +127,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, /* Initialize storage hardware */ if (!CO_eeprom_init(storageModule)) { - *storageInitError = 0xFFFFFFFF; + *storageInitError = 0xFFFFFFFFU; return CO_ERROR_DATA_CORRUPT; } From f54f919c1c76023b4e8c81fd8763788d31d61952 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 15:07:55 +0200 Subject: [PATCH 352/520] CO_LSSmaster: static analysis: use of modifier or type 'int' outside of a typedef [MISRA 2012 Directive 4.6, advisory] --- 305/CO_LSSmaster.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index cdc4dad4..64799077 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -961,7 +961,7 @@ static CO_LSS_fastscan_lss_sub_next CO_LSSmaster_FsSearchNext( CO_LSSmaster_t *LSSmaster, const CO_LSSmaster_fastscan_t *fastscan) { - int i; + uint8_t i; /* we search for the next LSS address part to scan for, beginning with the * one after the current one. If there is none remaining, scanning is From f322d42c2c31ef9c242ba02f4017dd8a259bc4e6 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 15:09:30 +0200 Subject: [PATCH 353/520] CO_LSSmaster: static analysis: ignoring return value of function 'CO_LSSmaster_FsScanInitiate' [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] --- 305/CO_LSSmaster.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 64799077..8454e9c2 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -1050,7 +1050,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( (void)memset(&fastscan->found, 0, sizeof(fastscan->found)); /* start scanning procedure by triggering vendor ID scan */ - CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_us, + (void)CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_us, fastscan->scan[CO_LSS_FASTSCAN_VENDOR_ID], CO_LSS_FASTSCAN_VENDOR_ID); ret = CO_LSSmaster_WAIT_SLAVE; From 29673b030482e497569c0ac8d2f76bc338cef678 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 15:13:01 +0200 Subject: [PATCH 354/520] CO_LSSmaster: static analysis: an unsigned value and a signed value cannot be used together as operands [MISRA 2012 Rule 10.4, required] --- 305/CO_LSSmaster.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 8454e9c2..61324005 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -83,7 +83,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */ /* verify message length and message overflow (previous message was not processed yet) */ - if((DLC==8) && !CO_FLAG_READ(LSSmaster->CANrxNew) && + if((DLC==8U) && !CO_FLAG_READ(LSSmaster->CANrxNew) && (LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING)){ /* copy data and set 'new message' flag */ @@ -141,7 +141,7 @@ CO_ReturnError_t CO_LSSmaster_init( return CO_ERROR_ILLEGAL_ARGUMENT; } - LSSmaster->timeout_us = (uint32_t)timeout_ms * 1000; + LSSmaster->timeout_us = (uint32_t)timeout_ms * 1000U; LSSmaster->state = CO_LSSmaster_STATE_WAITING; LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; LSSmaster->timeoutTimer = 0; @@ -186,7 +186,7 @@ void CO_LSSmaster_changeTimeout( uint16_t timeout_ms) { if (LSSmaster != NULL) { - LSSmaster->timeout_us = (uint32_t)timeout_ms * 1000; + LSSmaster->timeout_us = (uint32_t)timeout_ms * 1000U; } } @@ -222,7 +222,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); - (void)memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6); + (void)memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6U); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -245,7 +245,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION; - (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); + (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2U); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -338,7 +338,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; LSSmaster->TXbuff->data[1] = CO_LSS_STATE_WAITING; - (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); + (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2U); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -379,10 +379,10 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( CO_FLAG_CLEAR(LSSmaster->CANrxNew); if (cs == csWait) { - if (errorCode == 0) { + if (errorCode == 0U) { ret = CO_LSSmaster_OK; } - else if (errorCode == 0xff) { + else if (errorCode == 0xFFU) { ret = CO_LSSmaster_OK_MANUFACTURER; } else { @@ -442,7 +442,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( LSSmaster->TXbuff->data[0] = CO_LSS_CFG_BIT_TIMING; LSSmaster->TXbuff->data[1] = 0; LSSmaster->TXbuff->data[2] = bitTiming; - (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); + (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3U); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -487,7 +487,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_NODE_ID; LSSmaster->TXbuff->data[1] = nodeId; - (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2); + (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2U); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -527,7 +527,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_STORE; - (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); + (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1U); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -566,7 +566,7 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; (void)CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); - (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3); + (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3U); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); /* This is non-confirmed service! */ @@ -585,7 +585,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( { CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = cs; - (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1); + (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1U); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); return CO_LSSmaster_WAIT_SLAVE; @@ -966,7 +966,7 @@ static CO_LSS_fastscan_lss_sub_next CO_LSSmaster_FsSearchNext( /* we search for the next LSS address part to scan for, beginning with the * one after the current one. If there is none remaining, scanning is * finished */ - for (i = LSSmaster->fsLssSub + 1; i <= CO_LSS_FASTSCAN_SERIAL; i++) { + for (i = LSSmaster->fsLssSub + 1U; i <= CO_LSS_FASTSCAN_SERIAL; i++) { if (fastscan->scan[i] != CO_LSSmaster_FS_SKIP) { return (CO_LSS_fastscan_lss_sub_next)i; } @@ -1000,7 +1000,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( if (fastscan->scan[i] == CO_LSSmaster_FS_SKIP) { count ++; } - if (count > 2) { + if (count > 2U) { /* Node selection needs the Vendor ID and at least one other value */ return CO_LSSmaster_ILLEGAL_ARGUMENT; } From 5a62e186b9dc09ad6213fdc6e7c16fafe3892162 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 16:04:10 +0200 Subject: [PATCH 355/520] CO_LSSmaster: static analysis: missing unconditional break from final switch case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.3, required] --- 305/CO_LSSmaster.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 61324005..d39067ce 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -428,7 +428,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( case 20: bitTiming = CO_LSS_BIT_TIMING_20; break; case 10: bitTiming = CO_LSS_BIT_TIMING_10; break; case 0: bitTiming = CO_LSS_BIT_TIMING_AUTO; break; - default: return CO_LSSmaster_ILLEGAL_ARGUMENT; + default: return CO_LSSmaster_ILLEGAL_ARGUMENT; break; } /* Initiate config bit */ @@ -812,9 +812,11 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanInitiate( case CO_LSSmaster_FS_MATCH: /* No scanning requested */ return CO_LSSmaster_SCAN_FINISHED; + break; case CO_LSSmaster_FS_SKIP: default: return CO_LSSmaster_SCAN_FAILED; + break; } LSSmaster->fsBitChecked = CO_LSS_FASTSCAN_BIT31; @@ -842,9 +844,11 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( case CO_LSSmaster_FS_MATCH: /* No scanning requested */ return CO_LSSmaster_SCAN_FINISHED; + break; case CO_LSSmaster_FS_SKIP: default: return CO_LSSmaster_SCAN_FAILED; + break; } ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); @@ -905,6 +909,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate( case CO_LSSmaster_FS_SKIP: default: return CO_LSSmaster_SCAN_FAILED; + break; } LSSmaster->fsBitChecked = CO_LSS_FASTSCAN_BIT0; From bad75219859cd9cb5d04698710eb9d4ec7ff9c2f Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 16:07:28 +0200 Subject: [PATCH 356/520] CO_LSSmaster: static analysis: no 'else' at end of 'if ... else if' chain [MISRA 2012 Rule 15.7, required] --- 305/CO_LSSmaster.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index d39067ce..0dae5cb1 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -304,6 +304,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( else if (LSSmaster->command == CO_LSSmaster_COMMAND_SWITCH_STATE) { ret = CO_LSSmaster_switchStateSelectWait(LSSmaster, timeDifference_us); } + else { /* MISRA C 2004 14.10 */ } if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ @@ -453,6 +454,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_BIT_TIMING); } + else { /* MISRA C 2004 14.10 */ } if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ @@ -498,6 +500,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_NODE_ID); } + else { /* MISRA C 2004 14.10 */ } if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ @@ -538,6 +541,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_STORE); } + else { /* MISRA C 2004 14.10 */ } if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { /* finished */ @@ -670,6 +674,8 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_SERIAL, &lssAddress->identity.serialNumber); } + else { /* MISRA C 2004 14.10 */ } + /* Check for next request */ if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || (LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL)) { @@ -698,6 +704,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_SERIAL); } + else { /* MISRA C 2004 14.10 */ } } if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { @@ -736,6 +743,7 @@ CO_LSSmaster_return_t CO_LSSmaster_Inquire( ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, lssInquireCs, value); } + else { /* MISRA C 2004 14.10 */ } if (ret != CO_LSSmaster_WAIT_SLAVE) { LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; From 6ebd39016065e8ed10cfa630dd04167155391101 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 16:10:56 +0200 Subject: [PATCH 357/520] CO_LSSmaster: departure from MISRA switch syntax: missing break or throw from switch-case [MISRA 2012 Rule 16.1, required] refactoring change switch to if condition --- 305/CO_LSSmaster.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 0dae5cb1..13a003e1 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -1028,19 +1028,17 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } /* evaluate LSS state machine */ - switch (LSSmaster->command) { - case CO_LSSmaster_COMMAND_WAITING: - /* start fastscan */ - LSSmaster->command = CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN; + if (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING) { + /* start fastscan */ + LSSmaster->command = CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN; - /* check if any nodes are waiting, if yes fastscan is reset */ - LSSmaster->fsState = CO_LSSmaster_FS_STATE_CHECK; - CO_LSSmaster_FsSendMsg(LSSmaster, 0, CO_LSS_FASTSCAN_CONFIRM, 0, 0); + /* check if any nodes are waiting, if yes fastscan is reset */ + LSSmaster->fsState = CO_LSSmaster_FS_STATE_CHECK; + CO_LSSmaster_FsSendMsg(LSSmaster, 0, CO_LSS_FASTSCAN_CONFIRM, 0, 0); - return CO_LSSmaster_WAIT_SLAVE; - default: - /* continue with evaluating fastscan state machine */ - break; + return CO_LSSmaster_WAIT_SLAVE; + } else { + /* continue with evaluating fastscan state machine */ } /* evaluate fastscan state machine. The state machine is evaluated as following From 22fe7b9bc6f5f33367f5ac0294279e8016c6bc08 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 16:12:13 +0200 Subject: [PATCH 358/520] CO_LSSmaster: static analysis: statement or comment should appear in default case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.4, required] --- 305/CO_LSSmaster.c | 1 + 1 file changed, 1 insertion(+) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 13a003e1..7cdae11e 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -1114,6 +1114,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } break; default: + /* none */ break; } From 79aa3666278a787447a10182b6169619ba2f7bc4 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 16:21:12 +0200 Subject: [PATCH 359/520] CO_LSSmaster: style changed , add space on if condition --- 305/CO_LSSmaster.c | 56 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 7cdae11e..b31c03ec 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -84,7 +84,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) /* verify message length and message overflow (previous message was not processed yet) */ if((DLC==8U) && !CO_FLAG_READ(LSSmaster->CANrxNew) && - (LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING)){ + (LSSmaster->command != CO_LSSmaster_COMMAND_WAITING)){ /* copy data and set 'new message' flag */ (void)memcpy(LSSmaster->CANrxData, data, sizeof(LSSmaster->CANrxData)); @@ -137,7 +137,7 @@ CO_ReturnError_t CO_LSSmaster_init( CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if ((LSSmaster==NULL) || (CANdevRx==NULL) || (CANdevTx==NULL)){ + if ((LSSmaster == NULL) || (CANdevRx == NULL) || (CANdevTx == NULL)){ return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -295,8 +295,8 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( } /* Initiate select */ - if ((LSSmaster->state==CO_LSSmaster_STATE_WAITING) && - (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)){ + if ((LSSmaster->state == CO_LSSmaster_STATE_WAITING) && + (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)){ ret = CO_LSSmaster_switchStateSelectInitiate(LSSmaster, lssAddress); } @@ -306,7 +306,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( } else { /* MISRA C 2004 14.10 */ } - if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { + if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -398,7 +398,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } - if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { + if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -433,8 +433,8 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( } /* Initiate config bit */ - if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE) && - (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)){ + if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) && + (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)){ LSSmaster->command = CO_LSSmaster_COMMAND_CFG_BIT_TIMING; LSSmaster->timeoutTimer = 0; @@ -456,7 +456,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( } else { /* MISRA C 2004 14.10 */ } - if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { + if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -472,16 +472,16 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if ((LSSmaster==NULL) || !CO_LSS_NODE_ID_VALID(nodeId)){ + if ((LSSmaster == NULL) || !CO_LSS_NODE_ID_VALID(nodeId)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* Initiate config node ID */ - if (((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE) || + if (((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || /* Let un-config node ID also be run in global mode for unconfiguring all nodes */ - ((LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL) && + ((LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL) && (nodeId == CO_LSS_NODE_ID_ASSIGNMENT))) && - (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)) { + (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { LSSmaster->command = CO_LSSmaster_COMMAND_CFG_NODE_ID; LSSmaster->timeoutTimer = 0; @@ -502,7 +502,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( } else { /* MISRA C 2004 14.10 */ } - if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { + if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -522,8 +522,8 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( } /* Initiate config store */ - if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE) && - (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)){ + if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) && + (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)){ LSSmaster->command = CO_LSSmaster_COMMAND_CFG_STORE; LSSmaster->timeoutTimer = 0; @@ -543,7 +543,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( } else { /* MISRA C 2004 14.10 */ } - if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { + if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -564,8 +564,8 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( /* for activating bit timing, we need to have all slaves set to config * state. This check makes it a bit harder to shoot ourselves in the foot */ - if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL) && - (LSSmaster->command==CO_LSSmaster_COMMAND_WAITING)){ + if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL) && + (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)){ CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; @@ -634,7 +634,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; CO_LSSmaster_command_t next = CO_LSSmaster_COMMAND_WAITING; - if ((LSSmaster==NULL) || (lssAddress==NULL)){ + if ((LSSmaster == NULL) || (lssAddress == NULL)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } @@ -707,7 +707,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( else { /* MISRA C 2004 14.10 */ } } - if ((ret!=CO_LSSmaster_INVALID_STATE) && (ret!=CO_LSSmaster_WAIT_SLAVE)) { + if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } @@ -724,13 +724,13 @@ CO_LSSmaster_return_t CO_LSSmaster_Inquire( { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if ((LSSmaster==NULL) || (value==NULL)){ + if ((LSSmaster == NULL) || (value == NULL)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* send request */ - if (((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE) || - (LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL)) && + if (((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || + (LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL)) && (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE; @@ -1001,7 +1001,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( CO_LSS_fastscan_lss_sub_next next; /* parameter validation */ - if ((LSSmaster==NULL) || (fastscan==NULL)){ + if ((LSSmaster == NULL) || (fastscan == NULL)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; } if (fastscan->scan[0] == CO_LSSmaster_FS_SKIP) { @@ -1020,9 +1020,9 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } /* state machine validation */ - if ((LSSmaster->state!=CO_LSSmaster_STATE_WAITING) || - ((LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING) && - (LSSmaster->command!=CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN))) { + if ((LSSmaster->state != CO_LSSmaster_STATE_WAITING) || + ((LSSmaster->command != CO_LSSmaster_COMMAND_WAITING) && + (LSSmaster->command != CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN))) { /* state machine not ready, other command is already processed */ return CO_LSSmaster_INVALID_STATE; } From 47461cf08a554ee93eabac459e72f489a17d030a Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 13 Jun 2024 16:30:10 +0200 Subject: [PATCH 360/520] CO_LSSmaster: static analysis: cannot assign 'enum' to different essential type [MISRA 2012 Rule 10.3, required] refactoring convert enum to macro --- 305/CO_LSSmaster.c | 54 ++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index b31c03ec..2ff8714a 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -31,41 +31,43 @@ #include /* + * @defgroup CO_LSSmaster_state_t + * @{ * LSS master slave select state machine. Compared to #CO_LSS_state_t this * has information if we currently have selected one or all slaves. This * allows for some basic error checking. */ -typedef enum { - CO_LSSmaster_STATE_WAITING = 0, - CO_LSSmaster_STATE_CFG_SLECTIVE, - CO_LSSmaster_STATE_CFG_GLOBAL, -} CO_LSSmaster_state_t; +#define CO_LSSmaster_STATE_WAITING 0x00U +#define CO_LSSmaster_STATE_CFG_SLECTIVE 0x01U +#define CO_LSSmaster_STATE_CFG_GLOBAL 0x02U +/** @} */ /* CO_LSSmaster_state_t */ /* - * LSS master slave command state machine + * @defgroup CO_LSSmaster_command_t LSS master slave command state machine + * @{ + * */ -typedef enum { - CO_LSSmaster_COMMAND_WAITING = 0, - CO_LSSmaster_COMMAND_SWITCH_STATE, - CO_LSSmaster_COMMAND_CFG_BIT_TIMING, - CO_LSSmaster_COMMAND_CFG_NODE_ID, - CO_LSSmaster_COMMAND_CFG_STORE, - CO_LSSmaster_COMMAND_INQUIRE_VENDOR, - CO_LSSmaster_COMMAND_INQUIRE_PRODUCT, - CO_LSSmaster_COMMAND_INQUIRE_REV, - CO_LSSmaster_COMMAND_INQUIRE_SERIAL, - CO_LSSmaster_COMMAND_INQUIRE, - CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN, -} CO_LSSmaster_command_t; +#define CO_LSSmaster_COMMAND_WAITING 0x00U +#define CO_LSSmaster_COMMAND_SWITCH_STATE 0x01U +#define CO_LSSmaster_COMMAND_CFG_BIT_TIMING 0x02U +#define CO_LSSmaster_COMMAND_CFG_NODE_ID 0x03U +#define CO_LSSmaster_COMMAND_CFG_STORE 0x04U +#define CO_LSSmaster_COMMAND_INQUIRE_VENDOR 0x05U +#define CO_LSSmaster_COMMAND_INQUIRE_PRODUCT 0x06U +#define CO_LSSmaster_COMMAND_INQUIRE_REV 0x07U +#define CO_LSSmaster_COMMAND_INQUIRE_SERIAL 0x08U +#define CO_LSSmaster_COMMAND_INQUIRE 0x09U +#define CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN 0x0AU +/** @} */ /* CO_LSSmaster_command_t */ /* - * LSS master fastscan state machine + * @defgroup CO_LSSmaster_fs_t LSS master fastscan state machine + * @{ */ -typedef enum { - CO_LSSmaster_FS_STATE_CHECK, - CO_LSSmaster_FS_STATE_SCAN, - CO_LSSmaster_FS_STATE_VERIFY -} CO_LSSmaster_fs_t; +#define CO_LSSmaster_FS_STATE_CHECK 0x00U +#define CO_LSSmaster_FS_STATE_SCAN 0x01U +#define CO_LSSmaster_FS_STATE_VERIFY 0x02U +/** @} */ /* CO_LSSmaster_fs_t */ /* * Read received message from CAN module. @@ -632,7 +634,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSS_address_t *lssAddress) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - CO_LSSmaster_command_t next = CO_LSSmaster_COMMAND_WAITING; + uint8_t next = CO_LSSmaster_COMMAND_WAITING; if ((LSSmaster == NULL) || (lssAddress == NULL)){ return CO_LSSmaster_ILLEGAL_ARGUMENT; From d4b4d29f0b9a346d4b7728bd3f1f11517431482d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 08:12:08 +0200 Subject: [PATCH 361/520] CO_LSSmaster and CO_LSSslave: static analysis: cannot assign 'enum' to different essential type [MISRA 2012 Rule 10.3, required] refactoring convert enum to macro --- 305/CO_LSS.h | 140 ++++++++++++++++++++--------------------- 305/CO_LSSmaster.c | 12 ++-- 305/CO_LSSmaster.h | 2 +- 305/CO_LSSslave.c | 38 +++++------ 305/CO_LSSslave.h | 6 +- 309/CO_gateway_ascii.h | 2 +- 6 files changed, 100 insertions(+), 100 deletions(-) diff --git a/305/CO_LSS.h b/305/CO_LSS.h index 1b4dc933..8a2ae243 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -75,7 +75,8 @@ extern "C" { */ /** - * LSS protocol command specifiers + * @defgroup CO_LSS_cs_t LSS protocol command specifiers + * @{ * * The LSS protocols are executed between the LSS master device and the LSS * slave device(s) to implement the LSS services. Some LSS protocols require @@ -83,73 +84,72 @@ extern "C" { * * As identifying method only "LSS fastscan" is supported. */ -typedef enum { - CO_LSS_SWITCH_STATE_GLOBAL = 0x04U, /**< Switch state global protocol */ - CO_LSS_SWITCH_STATE_SEL_VENDOR = 0x40U, /**< Switch state selective protocol - Vendor ID */ - CO_LSS_SWITCH_STATE_SEL_PRODUCT = 0x41U, /**< Switch state selective protocol - Product code */ - CO_LSS_SWITCH_STATE_SEL_REV = 0x42U, /**< Switch state selective protocol - Revision number */ - CO_LSS_SWITCH_STATE_SEL_SERIAL = 0x43U, /**< Switch state selective protocol - Serial number */ - CO_LSS_SWITCH_STATE_SEL = 0x44U, /**< Switch state selective protocol - Slave response */ - CO_LSS_CFG_NODE_ID = 0x11U, /**< Configure node ID protocol */ - CO_LSS_CFG_BIT_TIMING = 0x13U, /**< Configure bit timing parameter protocol */ - CO_LSS_CFG_ACTIVATE_BIT_TIMING = 0x15U, /**< Activate bit timing parameter protocol */ - CO_LSS_CFG_STORE = 0x17U, /**< Store configuration protocol */ - CO_LSS_IDENT_SLAVE = 0x4FU, /**< LSS Fastscan response */ - CO_LSS_IDENT_FASTSCAN = 0x51U, /**< LSS Fastscan protocol */ - CO_LSS_INQUIRE_VENDOR = 0x5AU, /**< Inquire identity vendor-ID protocol */ - CO_LSS_INQUIRE_PRODUCT = 0x5BU, /**< Inquire identity product-code protocol */ - CO_LSS_INQUIRE_REV = 0x5CU, /**< Inquire identity revision-number protocol */ - CO_LSS_INQUIRE_SERIAL = 0x5DU, /**< Inquire identity serial-number protocol */ - CO_LSS_INQUIRE_NODE_ID = 0x5EU, /**< Inquire node-ID protocol */ -} CO_LSS_cs_t; +#define CO_LSS_SWITCH_STATE_GLOBAL 0x04U /**< Switch state global protocol */ +#define CO_LSS_SWITCH_STATE_SEL_VENDOR 0x40U /**< Switch state selective protocol - Vendor ID */ +#define CO_LSS_SWITCH_STATE_SEL_PRODUCT 0x41U /**< Switch state selective protocol - Product code */ +#define CO_LSS_SWITCH_STATE_SEL_REV 0x42U /**< Switch state selective protocol - Revision number */ +#define CO_LSS_SWITCH_STATE_SEL_SERIAL 0x43U /**< Switch state selective protocol - Serial number */ +#define CO_LSS_SWITCH_STATE_SEL 0x44U /**< Switch state selective protocol - Slave response */ +#define CO_LSS_CFG_NODE_ID 0x11U /**< Configure node ID protocol */ +#define CO_LSS_CFG_BIT_TIMING 0x13U /**< Configure bit timing parameter protocol */ +#define CO_LSS_CFG_ACTIVATE_BIT_TIMING 0x15U /**< Activate bit timing parameter protocol */ +#define CO_LSS_CFG_STORE 0x17U /**< Store configuration protocol */ +#define CO_LSS_IDENT_SLAVE 0x4FU /**< LSS Fastscan response */ +#define CO_LSS_IDENT_FASTSCAN 0x51U /**< LSS Fastscan protocol */ +#define CO_LSS_INQUIRE_VENDOR 0x5AU /**< Inquire identity vendor-ID protocol */ +#define CO_LSS_INQUIRE_PRODUCT 0x5BU /**< Inquire identity product-code protocol */ +#define CO_LSS_INQUIRE_REV 0x5CU /**< Inquire identity revision-number protocol */ +#define CO_LSS_INQUIRE_SERIAL 0x5DU /**< Inquire identity serial-number protocol */ +#define CO_LSS_INQUIRE_NODE_ID 0x5EU /**< Inquire node-ID protocol */ +/** @} */ /* CO_LSS_cs_t */ /** - * Error codes for Configure node ID protocol + * @defgroup CO_LSS_cfgNodeId_t Error codes for Configure node ID protocol + * @{ */ -typedef enum { - CO_LSS_CFG_NODE_ID_OK = 0x00U,/**< Protocol successfully completed */ - CO_LSS_CFG_NODE_ID_OUT_OF_RANGE = 0x01U,/**< NID out of range */ - CO_LSS_CFG_NODE_ID_MANUFACTURER = 0xFFU /**< Manufacturer specific error. No further support */ -} CO_LSS_cfgNodeId_t; +#define CO_LSS_CFG_NODE_ID_OK 0x00U /**< Protocol successfully completed */ +#define CO_LSS_CFG_NODE_ID_OUT_OF_RANGE 0x01U /**< NID out of range */ +#define CO_LSS_CFG_NODE_ID_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ +/** @} */ /* CO_LSS_cfgNodeId_t */ /** - * Error codes for Configure bit timing parameters protocol + * @defgroup CO_LSS_cfgBitTiming_t Error codes for Configure bit timing parameters protocol + * @{ */ -typedef enum { - CO_LSS_CFG_BIT_TIMING_OK = 0x00U,/**< Protocol successfully completed */ - CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE = 0x01U,/**< Bit timing / Bit rate not supported */ - CO_LSS_CFG_BIT_TIMING_MANUFACTURER = 0xFFU /**< Manufacturer specific error. No further support */ -} CO_LSS_cfgBitTiming_t; +#define CO_LSS_CFG_BIT_TIMING_OK 0x00U /**< Protocol successfully completed */ +#define CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE 0x01U /**< Bit timing / Bit rate not supported */ +#define CO_LSS_CFG_BIT_TIMING_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ +/** @} */ /* CO_LSS_cfgBitTiming_t */ /** - * Error codes for Store configuration protocol + * @defgroup CO_LSS_cfgStore_t Error codes for Store configuration protocol + * @{ */ -typedef enum { - CO_LSS_CFG_STORE_OK = 0x00U, /**< Protocol successfully completed */ - CO_LSS_CFG_STORE_NOT_SUPPORTED = 0x01U, /**< Store configuration not supported */ - CO_LSS_CFG_STORE_FAILED = 0x02U, /**< Storage media access error */ - CO_LSS_CFG_STORE_MANUFACTURER = 0xFFU /**< Manufacturer specific error. No further support */ -} CO_LSS_cfgStore_t; +#define CO_LSS_CFG_STORE_OK 0x00U /**< Protocol successfully completed */ +#define CO_LSS_CFG_STORE_NOT_SUPPORTED 0x01U /**< Store configuration not supported */ +#define CO_LSS_CFG_STORE_FAILED 0x02U /**< Storage media access error */ +#define CO_LSS_CFG_STORE_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ +/** @} */ /* CO_LSS_cfgStore_t */ /** - * Fastscan BitCheck. BIT0 means all bits are checked for equality by slave. + * @defgroup CO_LSS_fastscan_bitcheck Fastscan BitCheck. BIT0 means all bits are checked for equality by slave + * @{ */ -typedef enum { - CO_LSS_FASTSCAN_BIT0 = 0x00U, /**< Least significant bit of IDnumbners bit area to be checked */ +#define CO_LSS_FASTSCAN_BIT0 0x00U /**< Least significant bit of IDnumbners bit area to be checked */ /* ... */ - CO_LSS_FASTSCAN_BIT31 = 0x1FU, /**< dito */ - CO_LSS_FASTSCAN_CONFIRM = 0x80U /**< All LSS slaves waiting for scan respond and previous scan is reset */ -} CO_LSS_fastscan_bitcheck; +#define CO_LSS_FASTSCAN_BIT31 0x1FU /**< dito */ +#define CO_LSS_FASTSCAN_CONFIRM 0x80U /**< All LSS slaves waiting for scan respond and previous scan is reset */ +/** @} */ /* CO_LSS_fastscan_bitcheck */ /** - * Fastscan LSSsub, LSSnext + * @defgroup CO_LSS_fastscan_lss_sub_next Fastscan LSSsub, LSSnext + * @{ */ -typedef enum { - CO_LSS_FASTSCAN_VENDOR_ID = 0, /**< Vendor ID */ - CO_LSS_FASTSCAN_PRODUCT = 1, /**< Product code */ - CO_LSS_FASTSCAN_REV = 2, /**< Revision number */ - CO_LSS_FASTSCAN_SERIAL = 3 /**< Serial number */ -} CO_LSS_fastscan_lss_sub_next; +#define CO_LSS_FASTSCAN_VENDOR_ID 0x00U /**< Vendor ID */ +#define CO_LSS_FASTSCAN_PRODUCT 0x01U /**< Product code */ +#define CO_LSS_FASTSCAN_REV 0x02U /**< Revision number */ +#define CO_LSS_FASTSCAN_SERIAL 0x03U /**< Serial number */ +/** @} */ /* CO_LSS_fastscan_lss_sub_next */ /** * The LSS address is a 128 bit number, uniquely identifying each node. It @@ -166,7 +166,8 @@ typedef union { } CO_LSS_address_t; /** - * LSS finite state automaton + * @defgroup CO_LSS_state_t LSS finite state automaton + * @{ * * The LSS FSA shall provide the following states: * - Initial: Pseudo state, indicating the activation of the FSA. @@ -174,26 +175,25 @@ typedef union { * - LSS configuration: In this state variables may be configured in the LSS slave. * - Final: Pseudo state, indicating the deactivation of the FSA. */ -typedef enum { - CO_LSS_STATE_WAITING = 0, /**< LSS FSA waiting for requests*/ - CO_LSS_STATE_CONFIGURATION = 1, /**< LSS FSA waiting for configuration*/ -} CO_LSS_state_t; +#define CO_LSS_STATE_WAITING 0x00U /**< LSS FSA waiting for requests*/ +#define CO_LSS_STATE_CONFIGURATION 0x01U /**< LSS FSA waiting for configuration*/ +/** @} */ /* CO_LSS_state_t */ /** - * Definition of table_index for /CiA301/ bit timing table + * @defgroup CO_LSS_bitTimingTable_t Definition of table_index for /CiA301/ bit timing table + * @{ */ -typedef enum { - CO_LSS_BIT_TIMING_1000 = 0U, /**< 1000kbit/s */ - CO_LSS_BIT_TIMING_800 = 1U, /**< 800kbit/s */ - CO_LSS_BIT_TIMING_500 = 2U, /**< 500kbit/s */ - CO_LSS_BIT_TIMING_250 = 3U, /**< 250kbit/s */ - CO_LSS_BIT_TIMING_125 = 4U, /**< 125kbit/s */ - /* reserved = 5U */ - CO_LSS_BIT_TIMING_50 = 6U, /**< 50kbit/s */ - CO_LSS_BIT_TIMING_20 = 7U, /**< 20kbit/s */ - CO_LSS_BIT_TIMING_10 = 8U, /**< 10kbit/s */ - CO_LSS_BIT_TIMING_AUTO = 9U, /**< Automatic bit rate detection */ -} CO_LSS_bitTimingTable_t; +#define CO_LSS_BIT_TIMING_1000 0U /**< 1000kbit/s */ +#define CO_LSS_BIT_TIMING_800 1U /**< 800kbit/s */ +#define CO_LSS_BIT_TIMING_500 2U /**< 500kbit/s */ +#define CO_LSS_BIT_TIMING_250 3U /**< 250kbit/s */ +#define CO_LSS_BIT_TIMING_125 4U /**< 125kbit/s */ + /* reserved 5U */ +#define CO_LSS_BIT_TIMING_50 6U /**< 50kbit/s */ +#define CO_LSS_BIT_TIMING_20 7U /**< 20kbit/s */ +#define CO_LSS_BIT_TIMING_10 8U /**< 10kbit/s */ +#define CO_LSS_BIT_TIMING_AUTO 9U /**< Automatic bit rate detection */ +/** @} */ /* CO_LSS_bitTimingTable_t */ /** * Lookup table for conversion between bit timing table and numerical diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 2ff8714a..d26bc048 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -721,7 +721,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSSmaster_return_t CO_LSSmaster_Inquire( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, - CO_LSS_cs_t lssInquireCs, + uint8_t lssInquireCs, uint32_t *value) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; @@ -809,7 +809,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanInitiate( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, - CO_LSS_fastscan_lss_sub_next lssSub) + uint8_t lssSub) { (void)timeDifference_us; /* unused */ @@ -904,7 +904,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate( uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, uint32_t idNumberCheck, - CO_LSS_fastscan_lss_sub_next lssNext) + uint8_t lssNext) { (void)timeDifference_us; /* unused */ @@ -972,7 +972,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait( /* * Helper function - check which 32 bit to scan for next, if any */ -static CO_LSS_fastscan_lss_sub_next CO_LSSmaster_FsSearchNext( +static uint8_t CO_LSSmaster_FsSearchNext( CO_LSSmaster_t *LSSmaster, const CO_LSSmaster_fastscan_t *fastscan) { @@ -983,7 +983,7 @@ static CO_LSS_fastscan_lss_sub_next CO_LSSmaster_FsSearchNext( * finished */ for (i = LSSmaster->fsLssSub + 1U; i <= CO_LSS_FASTSCAN_SERIAL; i++) { if (fastscan->scan[i] != CO_LSSmaster_FS_SKIP) { - return (CO_LSS_fastscan_lss_sub_next)i; + return i; } } /* node selection is triggered by switching node state machine back @@ -1000,7 +1000,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( uint8_t i; uint8_t count; CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - CO_LSS_fastscan_lss_sub_next next; + uint8_t next; /* parameter validation */ if ((LSSmaster == NULL) || (fastscan == NULL)){ diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index f3af0a54..653051e7 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -386,7 +386,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSSmaster_return_t CO_LSSmaster_Inquire( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, - CO_LSS_cs_t lssInquireCs, + uint8_t lssInquireCs, uint32_t *value); diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 00adcaa9..0d97db1b 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -32,11 +32,11 @@ #include /* 'bit' must be unsigned or additional range check must be added: bit>=CO_LSS_FASTSCAN_BIT0 */ -#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit<=(uint8_t)CO_LSS_FASTSCAN_BIT31) || (bit==(uint8_t)CO_LSS_FASTSCAN_CONFIRM)) +#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit<=CO_LSS_FASTSCAN_BIT31) || (bit==CO_LSS_FASTSCAN_CONFIRM)) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_FASTSCAN_VENDOR_ID */ -#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=(uint8_t)CO_LSS_FASTSCAN_SERIAL) +#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=CO_LSS_FASTSCAN_SERIAL) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_BIT_TIMING_1000 */ -#define CO_LSS_BIT_TIMING_VALID(index) ((index != 5U) && (index <= (uint8_t)CO_LSS_BIT_TIMING_AUTO)) +#define CO_LSS_BIT_TIMING_VALID(index) ((index != 5U) && (index <= CO_LSS_BIT_TIMING_AUTO)) /* * Read received message from CAN module. @@ -53,7 +53,7 @@ static void CO_LSSslave_receive(void *object, void *msg) if((DLC == 8U) && !CO_FLAG_READ(LSSslave->sendResponse)) { bool_t request_LSSslave_process = false; uint8_t *data = CO_CANrxMsg_readData(msg); - CO_LSS_cs_t cs = (CO_LSS_cs_t) data[0]; + uint8_t cs = data[0]; if (cs == CO_LSS_SWITCH_STATE_GLOBAL) { uint8_t mode = data[1]; @@ -137,10 +137,10 @@ static void CO_LSSslave_receive(void *object, void *msg) idNumber = CO_SWAP_32(valSw); ack = false; - if (bitCheck == (uint8_t)CO_LSS_FASTSCAN_CONFIRM) { + if (bitCheck == CO_LSS_FASTSCAN_CONFIRM) { /* Confirm, Reset */ ack = true; - LSSslave->fastscanPos = (uint8_t)(CO_LSS_FASTSCAN_VENDOR_ID); + LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; (void)memset(&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); } @@ -232,7 +232,7 @@ CO_ReturnError_t CO_LSSslave_init( /* Configure object variables */ (void)memcpy(&LSSslave->lssAddress, lssAddress, sizeof(LSSslave->lssAddress)); LSSslave->lssState = CO_LSS_STATE_WAITING; - LSSslave->fastscanPos = (uint8_t)(CO_LSS_FASTSCAN_VENDOR_ID); + LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; LSSslave->pendingBitRate = pendingBitRate; LSSslave->pendingNodeID = pendingNodeID; @@ -344,19 +344,19 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { break; } case CO_LSS_SWITCH_STATE_SEL_SERIAL: { - LSSslave->TXbuff->data[0] = (uint8_t)(CO_LSS_SWITCH_STATE_SEL); + LSSslave->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL; CANsend = true; break; } case CO_LSS_CFG_NODE_ID: { nid = LSSslave->CANdata[1]; - errorCode = (uint8_t)(CO_LSS_CFG_NODE_ID_OK); + errorCode = CO_LSS_CFG_NODE_ID_OK; if (CO_LSS_NODE_ID_VALID(nid)) { *LSSslave->pendingNodeID = nid; } else { - errorCode = (uint8_t)(CO_LSS_CFG_NODE_ID_OUT_OF_RANGE); + errorCode = CO_LSS_CFG_NODE_ID_OUT_OF_RANGE; } /* send confirmation */ @@ -374,8 +374,8 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { tableSelector = LSSslave->CANdata[1]; tableIndex = LSSslave->CANdata[2]; - errorCode = (uint8_t)(CO_LSS_CFG_BIT_TIMING_OK); - errorCodeManuf = (uint8_t)(CO_LSS_CFG_BIT_TIMING_OK); + errorCode = CO_LSS_CFG_BIT_TIMING_OK; + errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OK; if ((tableSelector == 0U) && CO_LSS_BIT_TIMING_VALID(tableIndex)) { uint16_t bit = CO_LSS_bitTimingTableLookup[tableIndex]; @@ -386,13 +386,13 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { *LSSslave->pendingBitRate = bit; } else { - errorCode = (uint8_t)(CO_LSS_CFG_BIT_TIMING_MANUFACTURER); - errorCodeManuf = (uint8_t)(CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE); + errorCode = CO_LSS_CFG_BIT_TIMING_MANUFACTURER; + errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; } } else { /* we currently only support CiA301 bit timing table */ - errorCode = (uint8_t)(CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE); + errorCode = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; } /* send confirmation */ @@ -418,11 +418,11 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { break; } case CO_LSS_CFG_STORE: { - errorCode = (uint8_t)(CO_LSS_CFG_STORE_OK); + errorCode = CO_LSS_CFG_STORE_OK; if (LSSslave->pFunctLSScfgStore == NULL) { /* storing is not supported. Reply error */ - errorCode = (uint8_t)(CO_LSS_CFG_STORE_NOT_SUPPORTED); + errorCode = CO_LSS_CFG_STORE_NOT_SUPPORTED; } else { bool_t result; @@ -432,7 +432,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { *LSSslave->pendingNodeID, *LSSslave->pendingBitRate); if (!result) { - errorCode = (uint8_t)(CO_LSS_CFG_STORE_FAILED); + errorCode = CO_LSS_CFG_STORE_FAILED; } } @@ -478,7 +478,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { break; } case CO_LSS_IDENT_FASTSCAN: { - LSSslave->TXbuff->data[0] = (uint8_t)(CO_LSS_IDENT_SLAVE); + LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; CANsend = true; break; } diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index 09bc669a..40ce0075 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -88,7 +88,7 @@ extern "C" { */ typedef struct{ CO_LSS_address_t lssAddress; /**< From #CO_LSSslave_init */ - CO_LSS_state_t lssState; /**< #CO_LSS_state_t */ + uint8_t lssState; /**< #CO_LSS_state_t */ CO_LSS_address_t lssSelect; /**< Received LSS Address by select */ CO_LSS_address_t lssFastscan; /**< Received LSS Address by fastscan */ @@ -99,7 +99,7 @@ typedef struct{ uint8_t activeNodeID; /**< Node ID used at the CAN interface */ volatile void *sendResponse; /**< Variable indicates, if LSS response has to be sent by mainline processing function */ - CO_LSS_cs_t service; /**< Service, which will have to be processed by mainline processing function */ + uint8_t service; /**< Service, which will have to be processed by mainline processing function */ uint8_t CANdata[8]; /**< Received CAN data, which will be processed by mainline processing function */ #if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN @@ -189,7 +189,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave); * @param LSSslave This object. * @return #CO_LSS_state_t */ -static inline CO_LSS_state_t CO_LSSslave_getState(CO_LSSslave_t *LSSslave) { +static inline uint8_t CO_LSSslave_getState(CO_LSSslave_t *LSSslave) { return (LSSslave == NULL) ? CO_LSS_STATE_WAITING : LSSslave->lssState; } diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index c7f77a3d..13ecc672 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -371,7 +371,7 @@ typedef struct { /** LSS bitrate parameter */ uint16_t lssBitrate; /** LSS inquire parameter */ - CO_LSS_cs_t lssInquireCs; + uint8_t lssInquireCs; /** LSS fastscan parameter */ CO_LSSmaster_fastscan_t lssFastscan; /** LSS allnodes sub state parameter */ From 6990e11e7f07711918b0bf5eeb10e318fa968c71 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 08:13:08 +0200 Subject: [PATCH 362/520] CO_LSSslave: static analysis: an unsigned value and a signed value cannot be used together as operands to - [MISRA 2012 Rule 10.4, required] --- 305/CO_LSSslave.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 0d97db1b..cec439fc 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -165,7 +165,7 @@ static void CO_LSSslave_receive(void *object, void *msg) #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND) != 0 LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; (void)memset(&LSSslave->TXbuff->data[1], 0, - sizeof(LSSslave->TXbuff->data) - 1); + sizeof(LSSslave->TXbuff->data) - 1U); (void)CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); #else LSSslave->service = cs; From 284ba1a41f92fb7106c2b20314e30243a54c3d56 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 08:20:26 +0200 Subject: [PATCH 363/520] CO_LSSslave: static analysis: remove cast unnecessary --- 305/CO_LSSslave.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index cec439fc..d22e6b2e 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -360,7 +360,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { } /* send confirmation */ - LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); + LSSslave->TXbuff->data[0] = LSSslave->service; LSSslave->TXbuff->data[1] = errorCode; /* we do not use spec-error, always 0 */ CANsend = true; @@ -396,7 +396,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { } /* send confirmation */ - LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); + LSSslave->TXbuff->data[0] = LSSslave->service; LSSslave->TXbuff->data[1] = errorCode; LSSslave->TXbuff->data[2] = errorCodeManuf; CANsend = true; @@ -437,42 +437,42 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { } /* send confirmation */ - LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); + LSSslave->TXbuff->data[0] = LSSslave->service; LSSslave->TXbuff->data[1] = errorCode; /* we do not use spec-error, always 0 */ CANsend = true; break; } case CO_LSS_INQUIRE_VENDOR: { - LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); + LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.vendorID); (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_PRODUCT: { - LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); + LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.productCode); (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_REV: { - LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); + LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.revisionNumber); (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_SERIAL: { - LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); + LSSslave->TXbuff->data[0] = LSSslave->service; valSw = CO_SWAP_32(LSSslave->lssAddress.identity.serialNumber); (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); CANsend = true; break; } case CO_LSS_INQUIRE_NODE_ID: { - LSSslave->TXbuff->data[0] = (uint8_t)(LSSslave->service); + LSSslave->TXbuff->data[0] = LSSslave->service; LSSslave->TXbuff->data[1] = LSSslave->activeNodeID; CANsend = true; break; From 8af3ef3c6b543bf889229062773aa24607ac1fcf Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 08:26:34 +0200 Subject: [PATCH 364/520] CO_SDOserver: static analysis: taking address of array --- 301/CO_SDOserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 9f6f7f1c..2563e3a6 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -1291,7 +1291,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if ((SDO->sizeInd > 0U) && (SDO->sizeInd <= 4U)) { /* expedited transfer */ SDO->CANtxBuff->data[0] = (uint8_t)(0x43U|((4U-SDO->sizeInd)<<2U)); - (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), (const void *)(&SDO->buf), SDO->sizeInd); + (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), (const void *)(&SDO->buf[0]), SDO->sizeInd); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } From 75909f4fa2d6ca178dc5f1064b9547bc740253fa Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 08:29:04 +0200 Subject: [PATCH 365/520] CO_ODinterface: static analysis: implicit conversion of enum 'ODR_t' to integral type 'int' --- 301/CO_ODinterface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 0e571067..651fe526 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -266,7 +266,7 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, /******************************************************************************/ uint32_t OD_getSDOabCode(ODR_t returnCode) { - static const uint32_t abortCodes[ODR_COUNT] = { + static const uint32_t abortCodes[(uint8_t)ODR_COUNT] = { 0x00000000UL, /* No abort */ 0x05040005UL, /* Out of memory */ 0x06010000UL, /* Unsupported access to an object */ From 4cef8205c8f930aef994899d6037ac6adb188622 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 08:43:01 +0200 Subject: [PATCH 366/520] CO_ODinterface: static analysis: fix cast to correct address assignment and 'OD_IO_t::write' is potentially uninitialized [MISRA 2012 Rule 9.1, mandatory] --- 301/CO_ODinterface.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 651fe526..6ae54557 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -306,8 +306,8 @@ ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, { if (val == NULL) { return ODR_DEV_INCOMPAT; } - OD_IO_t io; - OD_stream_t *stream = (OD_stream_t *)&io; + OD_IO_t io = { NULL }; + OD_stream_t *stream = &io.stream; OD_size_t countRd = 0; ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); @@ -321,7 +321,9 @@ ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, OD_size_t len, bool_t odOrig) { - OD_IO_t io; + if (val == NULL) { return ODR_DEV_INCOMPAT; } + + OD_IO_t io = { NULL }; OD_stream_t *stream = &io.stream; OD_size_t countWritten = 0; From 35cefe09c38b53f8a7dbbb8628cb96f37b4fbfb1 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 08:52:07 +0200 Subject: [PATCH 367/520] CO_SDOserver: static analysis: cannot cast 'unsigned8' to wider essential type 'unsigned32' [MISRA 2012 Rule 10.8, required] --- 301/CO_SDOserver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 2563e3a6..e784b5ab 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -821,7 +821,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* Get SDO data size (indicated by SDO client or get from OD) */ OD_size_t dataSizeToWrite = 4; if ((SDO->CANrxData[0] & 0x01U) != 0U) { - dataSizeToWrite -= (OD_size_t)((SDO->CANrxData[0] >> 2) & 0x03U); + dataSizeToWrite -= ((OD_size_t)(SDO->CANrxData[0]) >> 2) & 0x03U; } else if ((sizeInOd > 0U) && (sizeInOd < 4U)) { dataSizeToWrite = sizeInOd; @@ -935,7 +935,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } /* get data size and write data to the buffer */ - OD_size_t count = (OD_size_t)(7U - ((SDO->CANrxData[0] >> 1) & 0x07U)); + OD_size_t count = (OD_size_t)(7U - (((OD_size_t)(SDO->CANrxData[0]) >> 1) & 0x07U)); (void)memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); SDO->bufOffsetWr += count; SDO->sizeTran += count; From ab261455976cce2955922dc8a5bf36bf551bbfd1 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 08:56:03 +0200 Subject: [PATCH 368/520] CO_Emergency: static analysis: side effects on right hand of logical operator, '&&' [MISRA 2012 Rule 13.5, required] because em->CANtxBuff->bufferFull is volatile --- 301/CO_Emergency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index a5a07936..91a3aaf1 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -647,7 +647,7 @@ void CO_EM_process(CO_EM_t *em, ) { em->inhibitEmTimer = 0; #else - if ((fifoPpPtr != em->fifoWrPtr) && (!em->CANtxBuff->bufferFull)) { + if ((!em->CANtxBuff->bufferFull) && (fifoPpPtr != em->fifoWrPtr)) { #endif /* add error register to emergency message */ em->fifo[fifoPpPtr].msg |= (uint32_t) errorRegister << 16; From 06834c1d144a13aee14088aa688635ef65f2604d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 09:02:17 +0200 Subject: [PATCH 369/520] O_SDOserver: static analysis: side effects on right hand of logical operator, '&&' [MISRA 2012 Rule 13.5, required] because SDO->state is volatile --- 301/CO_SDOserver.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index e784b5ab..073d3898 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -704,7 +704,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, bool_t isNew = CO_FLAG_READ(SDO->CANrxNew); - if (SDO->valid && (SDO->state == CO_SDO_ST_IDLE) && !isNew) { + if ((SDO->state == CO_SDO_ST_IDLE) && SDO->valid && !isNew) { /* Idle and nothing new */ ret = CO_SDO_RT_ok_communicationEnd; } @@ -809,7 +809,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ } /* (SDO->state == CO_SDO_ST_IDLE) */ - if ((SDO->state != CO_SDO_ST_IDLE) && (SDO->state != CO_SDO_ST_ABORT)) { + bool isOKstate = (SDO->state != CO_SDO_ST_IDLE); + isOKstate = (SDO->state != CO_SDO_ST_ABORT) && isOKstate; + if (isOKstate) { switch (SDO->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { if ((SDO->CANrxData[0] & 0x02U) != 0U) { From 42cea36f3bdd34fbebc22d33206b3a3273cbd7f8 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 09:12:52 +0200 Subject: [PATCH 370/520] CO_LSSmaster and CO_LSSslave: static analysis: repeated include file 'string.h' --- 305/CO_LSSmaster.c | 3 ++- 305/CO_LSSslave.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index d26bc048..8c6141f3 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -24,11 +24,12 @@ * limitations under the License. */ +#include + #include "305/CO_LSSmaster.h" #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 -#include /* * @defgroup CO_LSSmaster_state_t diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index d22e6b2e..96ec4ccf 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -25,12 +25,12 @@ * limitations under the License. */ +#include + #include "305/CO_LSSslave.h" #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 -#include - /* 'bit' must be unsigned or additional range check must be added: bit>=CO_LSS_FASTSCAN_BIT0 */ #define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit<=CO_LSS_FASTSCAN_BIT31) || (bit==CO_LSS_FASTSCAN_CONFIRM)) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_FASTSCAN_VENDOR_ID */ From cbf3df74e9d21f71375e0dfb30f0b3f30231a6a1 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 09:47:16 +0200 Subject: [PATCH 371/520] CO_SDOserver: static analysis: result of assignment operator used in right operand to '=' operator [MISRA 2012 Rule 13.4, advisory] --- 301/CO_SDOserver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 073d3898..753ce913 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -778,7 +778,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /* load data from object dictionary, if upload and no error */ if (upload && (abortCode == CO_SDO_AB_NONE)) { - SDO->bufOffsetRd = SDO->bufOffsetWr = 0; + SDO->bufOffsetRd = 0; + SDO->bufOffsetWr = 0; SDO->sizeTran = 0; SDO->finished = false; From 29bb7992d2c25d1deda78f4d7cb15fcbcf08e219 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 09:49:21 +0200 Subject: [PATCH 372/520] CO_SDOserver: static analysis: enum constants not used within default switch --- 301/CO_SDOserver.c | 74 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 753ce913..b6ab9bc3 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -924,8 +924,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 if ((SDO->CANrxData[0] & 0xE0U) == 0x00U) { SDO->finished = (SDO->CANrxData[0] & 0x01U) != 0U; @@ -967,17 +967,17 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ break; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ case CO_SDO_ST_UPLOAD_INITIATE_REQ: { SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; break; } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 if ((SDO->CANrxData[0] & 0xEFU) == 0x60U) { /* verify and alternate toggle bit */ uint8_t toggle = SDO->CANrxData[0] & 0x10U; @@ -992,12 +992,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ break; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->block_crcEnabled = (SDO->CANrxData[0] & 0x04) != 0; /* is size indicated? */ @@ -1030,15 +1030,19 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; SDO->finished = false; +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* data are copied directly in the receive function */ +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { /* Get number of data bytes in last segment, that do not * contain data. Then reduce buffer. */ @@ -1067,10 +1071,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* if pst (protocol switch threshold, byte5) is larger than data * size of OD variable, then switch to segmented transfer */ if (SDO->sizeInd > 0 && SDO->CANrxData[5] > 0 @@ -1104,10 +1110,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 if (SDO->CANrxData[0] == 0xA3) { SDO->block_seqno = 0; SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; @@ -1116,11 +1124,13 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 if (SDO->CANrxData[0] == 0xA2) { SDO->block_blksize = SDO->CANrxData[2]; if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { @@ -1162,10 +1172,24 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: default: { /* unknown message received */ abortCode = CO_SDO_AB_CMD; @@ -1269,8 +1293,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 SDO->CANtxBuff->data[0] = 0x20U | SDO->toggle; SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; @@ -1284,9 +1308,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, else { SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; } +#endif break; } -#endif case CO_SDO_ST_UPLOAD_INITIATE_RSP: { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 @@ -1357,8 +1381,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /* refill the data buffer if necessary */ if (!readFromOd(SDO, &abortCode, 7, false)) { break; @@ -1408,12 +1432,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* send message */ (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ break; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xA4; SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); @@ -1442,10 +1466,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; CO_FLAG_CLEAR(SDO->CANrxNew); (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xA2; SDO->CANtxBuff->data[1] = SDO->block_seqno; #ifdef CO_DEBUG_SDO_SERVER @@ -1497,19 +1523,23 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, CO_DEBUG_SDO_SERVER(msg); } #endif +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xA1; (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xC4; SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); @@ -1526,10 +1556,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->timeoutTimer = 0; (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* write header and get current count */ SDO->CANtxBuff->data[0] = ++SDO->block_seqno; OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; @@ -1581,10 +1613,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* reset timeout timer and send message */ SDO->timeoutTimer = 0; (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xC1 | (SDO->block_noData << 2); SDO->CANtxBuff->data[1] = (uint8_t) SDO->block_crc; SDO->CANtxBuff->data[2] = (uint8_t) (SDO->block_crc >> 8); @@ -1593,10 +1627,26 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->timeoutTimer = 0; (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ + + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: default: { /* none */ break; From cac0f78b10246859a301799518fcb6f123a2d6e8 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 10:42:39 +0200 Subject: [PATCH 373/520] CO_LSSslave: static analysis: ANSI/ISO minimum translation limit of 31 'significant characters in an external identifier' exceeded, processing is unaffected --- 305/CO_LSSslave.c | 6 +++--- 305/CO_LSSslave.h | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 96ec4ccf..f29cb391 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -283,7 +283,7 @@ void CO_LSSslave_initCallbackPre( /******************************************************************************/ -void CO_LSSslave_initCheckBitRateCallback( +void CO_LSSslave_initCkBitRateCall( CO_LSSslave_t *LSSslave, void *object, bool_t (*pFunctLSScheckBitRate)(void *object, uint16_t bitRate)) @@ -296,7 +296,7 @@ void CO_LSSslave_initCheckBitRateCallback( /******************************************************************************/ -void CO_LSSslave_initActivateBitRateCallback( +void CO_LSSslave_initActBitRateCall( CO_LSSslave_t *LSSslave, void *object, void (*pFunctLSSactivateBitRate)(void *object, uint16_t delay)) @@ -309,7 +309,7 @@ void CO_LSSslave_initActivateBitRateCallback( /******************************************************************************/ -void CO_LSSslave_initCfgStoreCallback( +void CO_LSSslave_initCfgStoreCall( CO_LSSslave_t *LSSslave, void *object, bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate)) diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index 40ce0075..a6b5e186 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -78,9 +78,9 @@ extern "C" { * also be checked with CO->nodeIdUnconfigured variable. * * Some callback functions may be initialized by application with - * CO_LSSslave_initCheckBitRateCallback(), - * CO_LSSslave_initActivateBitRateCallback() and - * CO_LSSslave_initCfgStoreCallback(). + * CO_LSSslave_initCkBitRateCall(), + * CO_LSSslave_initActBitRateCall() and + * CO_LSSslave_initCfgStoreCall(). */ /** @@ -106,11 +106,11 @@ typedef struct{ void (*pFunctSignalPre)(void *object); /**< From CO_LSSslave_initCallbackPre() or NULL */ void *functSignalObjectPre;/**< Pointer to object */ #endif - bool_t (*pFunctLSScheckBitRate)(void *object, uint16_t bitRate); /**< From CO_LSSslave_initCheckBitRateCallback() or NULL */ + bool_t (*pFunctLSScheckBitRate)(void *object, uint16_t bitRate); /**< From CO_LSSslave_initCkBitRateCall() or NULL */ void *functLSScheckBitRateObject; /** Pointer to object */ - void (*pFunctLSSactivateBitRate)(void *object, uint16_t delay); /**< From CO_LSSslave_initActivateBitRateCallback() or NULL. Delay is in ms */ + void (*pFunctLSSactivateBitRate)(void *object, uint16_t delay); /**< From CO_LSSslave_initActBitRateCall() or NULL. Delay is in ms */ void *functLSSactivateBitRateObject; /** Pointer to object */ - bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate); /**< From CO_LSSslave_initCfgStoreCallback() or NULL */ + bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate); /**< From CO_LSSslave_initCfgStoreCall() or NULL */ void *functLSScfgStoreObject; /** Pointer to object */ CO_CANmodule_t *CANdevTx; /**< From #CO_LSSslave_init() */ @@ -227,7 +227,7 @@ void CO_LSSslave_initCallbackPre( * @param object Pointer to object, which will be passed to pFunctLSScheckBitRate(). Can be NULL * @param pFunctLSScheckBitRate Pointer to the callback function. Not called if NULL. */ -void CO_LSSslave_initCheckBitRateCallback( +void CO_LSSslave_initCkBitRateCall( CO_LSSslave_t *LSSslave, void *object, bool_t (*pFunctLSScheckBitRate)(void *object, uint16_t bitRate)); @@ -246,7 +246,7 @@ void CO_LSSslave_initCheckBitRateCallback( * @param object Pointer to object, which will be passed to pFunctLSSactivateBitRate(). Can be NULL * @param pFunctLSSactivateBitRate Pointer to the callback function. Not called if NULL. */ -void CO_LSSslave_initActivateBitRateCallback( +void CO_LSSslave_initActBitRateCall( CO_LSSslave_t *LSSslave, void *object, void (*pFunctLSSactivateBitRate)(void *object, uint16_t delay)); @@ -265,7 +265,7 @@ void CO_LSSslave_initActivateBitRateCallback( * @param object Pointer to object, which will be passed to pFunctLSScfgStore(). Can be NULL * @param pFunctLSScfgStore Pointer to the callback function. Not called if NULL. */ -void CO_LSSslave_initCfgStoreCallback( +void CO_LSSslave_initCfgStoreCall( CO_LSSslave_t *LSSslave, void *object, bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate)); From 41c9e742f84cb0667aa93914cfb0f34cce5219af Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 10:59:43 +0200 Subject: [PATCH 374/520] CO_Emergency: static analysis: named parameter 'timeDifference_us' of 'non-virtual' function 'CO_EM_process' not subsequently referenced [MISRA 2012 Rule 2.7, advisory] --- 301/CO_Emergency.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 91a3aaf1..26a77b65 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -557,6 +557,10 @@ void CO_EM_process(CO_EM_t *em, uint32_t *timerNext_us) { (void)timerNext_us; /* may be unused */ + + #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) == 0 + (void)timeDifference_us; /* may be unused */ + #endif /* verify errors from driver */ uint16_t CANerrSt = em->CANdevTx->CANerrorStatus; From 8cc4dc1601bdfc1a23fcb782ec03333b55793cac Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 11:03:51 +0200 Subject: [PATCH 375/520] CO_HBconsumer: static analysis: local variable 'data' could be pointer to const [MISRA 2012 Rule 8.13, advisory] --- 301/CO_HBconsumer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 6da55965..4dc970bc 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -43,7 +43,7 @@ static void CO_HBcons_receive(void *object, void *msg) { CO_HBconsNode_t *HBconsNode = object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); if (DLC == 1U) { /* copy data and set 'new message' flag. */ From c41aa14680d80972b0713f8f94628968181b2a80 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 11:09:31 +0200 Subject: [PATCH 376/520] CO_PDO: static analysis: named parameter 'timerNext_us' of 'non-virtual' function 'CO_RPDO_process' not subsequently referenced [MISRA 2012 Rule 2.7, advisory] --- 301/CO_PDO.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 56a9c118..7e8c61c6 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -794,6 +794,8 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas) { (void) syncWas; + (void) timerNext_us; + CO_PDO_common_t *PDO = &RPDO->PDO_common; if (PDO->valid && NMTisOperational From d2770c491755d83f90a32ae0a03ffe1ea9c72177 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 11:15:41 +0200 Subject: [PATCH 377/520] CO_SDOserver: static analysis: named parameter 'calculateCrc' of 'non-virtual' function 'readFromOd' not subsequently referenced [MISRA 2012 Rule 2.7, advisory] --- 301/CO_SDOserver.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index b6ab9bc3..92e14d7d 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -606,6 +606,9 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, OD_size_t countMinimum, bool_t calculateCrc) { +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) == 0 + (void)calculateCrc; /* may be unused */ +#endif OD_size_t countRemain = SDO->bufOffsetWr - SDO->bufOffsetRd; if (!SDO->finished && (countRemain < countMinimum)) { From f9d8bdeff319d714e46e112ff55246735adbf743 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 11:27:22 +0200 Subject: [PATCH 378/520] static analysys: local variable 'data' could be pointer to const [MISRA 2012 Rule 8.13, advisory] refactory CO_CANrxMsg_readData return const --- 301/CO_Emergency.c | 2 +- 301/CO_NMT_Heartbeat.c | 2 +- 301/CO_Node_Guarding.c | 2 +- 301/CO_PDO.c | 2 +- 301/CO_SDOclient.c | 2 +- 301/CO_SDOserver.c | 2 +- 301/CO_SYNC.c | 2 +- 301/CO_TIME.c | 2 +- 301/CO_driver.h | 2 +- 304/CO_SRDO.c | 4 ++-- 305/CO_LSSmaster.c | 2 +- 305/CO_LSSslave.c | 2 +- example/CO_driver_target.h | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 26a77b65..87f2879f 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -324,7 +324,7 @@ static void CO_EM_receive(void *object, void *msg) { /* ignore sync messages (necessary if sync object is not used) */ if (ident != 0x80) { - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); uint16_t errorCode; uint32_t infoCode; diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 6caf3c61..556bb580 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -35,7 +35,7 @@ */ static void CO_NMT_receive(void *object, void *msg) { uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); CO_NMT_command_t command = (CO_NMT_command_t)data[0]; uint8_t nodeId = data[1]; diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 84d57733..6b751ec0 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -289,7 +289,7 @@ static void CO_ngm_receive(void *object, void *msg) { CO_nodeGuardingMaster_t *ngm = (CO_nodeGuardingMaster_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); uint16_t ident = CO_CANrxMsg_readIdent(msg); CO_nodeGuardingMasterNode_t *node = &ngm->nodes[0]; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 7e8c61c6..7caa06c2 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -468,7 +468,7 @@ static void CO_PDO_receive(void *object, void *msg) { CO_RPDO_t *RPDO = object; CO_PDO_common_t *PDO = &RPDO->PDO_common; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); uint8_t err = RPDO->receiveError; if (PDO->valid) { diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 653d7e7e..88355d19 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -63,7 +63,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { CO_SDOclient_t *SDO_C = (CO_SDOclient_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); /* Ignore messages in idle state and messages with wrong length. Ignore * message also if previous message was not processed yet and not abort */ diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 92e14d7d..7a2655ab 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -56,7 +56,7 @@ static void CO_SDO_receive(void *object, void *msg) { CO_SDOserver_t *SDO = (CO_SDOserver_t *)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); /* ignore messages with wrong length */ if (DLC == 8U) { diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 21fa7e6e..005dc708 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -49,7 +49,7 @@ static void CO_SYNC_receive(void *object, void *msg) { } else { if (DLC == 1U) { - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); SYNC->counter = data[0]; syncReceived = true; } diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 946eb868..067a3c77 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -39,7 +39,7 @@ static void CO_TIME_receive(void *object, void *msg) { CO_TIME_t *TIME = object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); if (DLC == CO_TIME_MSG_LENGTH) { (void)memcpy(TIME->timeStamp, data, sizeof(TIME->timeStamp)); diff --git a/301/CO_driver.h b/301/CO_driver.h index 00364be9..5c1337fd 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -245,7 +245,7 @@ static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg) { * @param rxMsg Pointer to received message * @return pointer to data buffer */ -static inline uint8_t *CO_CANrxMsg_readData(void *rxMsg) { +static inline const uint8_t *CO_CANrxMsg_readData(void *rxMsg) { return NULL; } diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index c4818957..27072078 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -53,7 +53,7 @@ static void CO_SRDO_receive_normal(void* object, void* msg) { CO_SRDO_t* SRDO = (CO_SRDO_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t* data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); if ((SRDO->informationDirection == CO_SRDO_RX) && (DLC >= SRDO->dataLength) && !CO_FLAG_READ(SRDO->CANrxNew[1])) { /* copy data into appropriate buffer and set 'new message' flag */ @@ -77,7 +77,7 @@ static void CO_SRDO_receive_inverted(void* object, void* msg) { CO_SRDO_t* SRDO = (CO_SRDO_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t* data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); if ((SRDO->informationDirection == CO_SRDO_RX) && (DLC >= SRDO->dataLength) && CO_FLAG_READ(SRDO->CANrxNew[0])) { /* copy data into appropriate buffer and set 'new message' flag */ diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 8c6141f3..d72225e8 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -81,7 +81,7 @@ static void CO_LSSmaster_receive(void *object, void *msg) { CO_LSSmaster_t *LSSmaster; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */ diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index f29cb391..1afc11ce 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -52,7 +52,7 @@ static void CO_LSSslave_receive(void *object, void *msg) if((DLC == 8U) && !CO_FLAG_READ(LSSslave->sendResponse)) { bool_t request_LSSslave_process = false; - uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t *data = CO_CANrxMsg_readData(msg); uint8_t cs = data[0]; if (cs == CO_LSS_SWITCH_STATE_GLOBAL) { diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index a270beed..c8c32b71 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -62,7 +62,7 @@ typedef double float64_t; /* Access to received CAN message */ #define CO_CANrxMsg_readIdent(msg) ((uint16_t)0) #define CO_CANrxMsg_readDLC(msg) ((uint8_t)0) -#define CO_CANrxMsg_readData(msg) ((uint8_t *)NULL) +#define CO_CANrxMsg_readData(msg) ((const uint8_t *)NULL) /* Received message object */ typedef struct { From 8cccf6f379e4a74d2d1a9b3db025f6d3eb04822d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Fri, 14 Jun 2024 13:46:21 +0200 Subject: [PATCH 379/520] minor fix after static analysis --- 301/CO_PDO.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 7caa06c2..b8e141af 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -794,7 +794,9 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas) { (void) syncWas; +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 (void) timerNext_us; +#endif CO_PDO_common_t *PDO = &RPDO->PDO_common; From f7c7f9c10434fb276340cae85ca59672138257c3 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 24 Jun 2024 17:43:05 +0200 Subject: [PATCH 380/520] Add more static analysis and MISRA.md (cherry picked from commit ad337c3e9c4e879721ec432bc9a5d9a84a53c573) # Conflicts: # CANopen.c --- 301/CO_ODinterface.c | 7 ++- 301/CO_PDO.c | 37 +++++++------ 301/CO_SDOserver.c | 12 ++-- MISRA.md | 128 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 25 deletions(-) create mode 100644 MISRA.md diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 6ae54557..b0682118 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -116,7 +116,12 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, return ODR_DATA_LONG; } - (void)memcpy((void *)dataOrig, (const void *)buf, dataLenToCopy); + if (((dataLenToCopy + stream->dataOffset) <= stream->dataLength) && (dataLenToCopy <= count)) { + (void)memcpy((void *)dataOrig, (const void *)buf, dataLenToCopy); + } + else { + return ODR_DEV_INCOMPAT; + } *countWritten = dataLenToCopy; return returnCode; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index b8e141af..35ad3a6c 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -444,16 +444,17 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, ******************************************************************************/ #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 /* - * States for RPDO->receiveError indicates received RPDOs with wrong length. + * @defgroup CO_PDO_receiveErrors_t States for RPDO->receiveError indicates received RPDOs with wrong length. + * @{ + * */ -typedef enum { - CO_RPDO_RX_ACK_NO_ERROR = 0, /* No error */ - CO_RPDO_RX_ACK_ERROR = 1, /* Error is acknowledged */ - CO_RPDO_RX_ACK = 10, /* Auxiliary value */ - CO_RPDO_RX_OK = 11, /* Correct RPDO received, not acknowledged */ - CO_RPDO_RX_SHORT = 12, /* Too short RPDO received, not acknowledged */ - CO_RPDO_RX_LONG = 13 /* Too long RPDO received, not acknowledged */ -} CO_PDO_receiveErrors_t; +#define CO_RPDO_RX_ACK_NO_ERROR 0U /* No error */ +#define CO_RPDO_RX_ACK_ERROR 1U /* Error is acknowledged */ +#define CO_RPDO_RX_ACK 10U /* Auxiliary value */ +#define CO_RPDO_RX_OK 11U /* Correct RPDO received, not acknowledged */ +#define CO_RPDO_RX_SHORT 12U /* Too short RPDO received, not acknowledged */ +#define CO_RPDO_RX_LONG 13U /* Too long RPDO received, not acknowledged */ +/** @} */ /* CO_PDO_receiveErrors_t */ /* * Read received message from CAN module. @@ -475,10 +476,10 @@ static void CO_PDO_receive(void *object, void *msg) { if (DLC >= PDO->dataLength) { /* indicate errors in PDO length */ if (DLC == PDO->dataLength) { - if (err == (uint8_t)CO_RPDO_RX_ACK_ERROR) { err = (uint8_t)(CO_RPDO_RX_OK); } + if (err == CO_RPDO_RX_ACK_ERROR) { err = CO_RPDO_RX_OK; } } else { - if (err == (uint8_t)CO_RPDO_RX_ACK_NO_ERROR) { err = (uint8_t)(CO_RPDO_RX_LONG); } + if (err == CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_LONG; } } /* Determine, to which of the two rx buffers copy the message. */ @@ -492,7 +493,7 @@ static void CO_PDO_receive(void *object, void *msg) { #endif /* copy data into appropriate buffer and set 'new message' flag */ - (void)memcpy(RPDO->CANrxData[bufNo], data,sizeof(RPDO->CANrxData[bufNo])); + (void)memcpy(RPDO->CANrxData[bufNo], data, CO_PDO_MAX_SIZE); CO_FLAG_SET(RPDO->CANrxNew[bufNo]); #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 @@ -503,8 +504,8 @@ static void CO_PDO_receive(void *object, void *msg) { } #endif } - else if (err == (uint8_t)CO_RPDO_RX_ACK_NO_ERROR) { - err = (uint8_t)(CO_RPDO_RX_SHORT); + else if (err == CO_RPDO_RX_ACK_NO_ERROR) { + err = CO_RPDO_RX_SHORT; } else { /* MISRA C 2004 14.10 */ } } @@ -806,14 +807,14 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, #endif ) { /* Verify errors in length of received RPDO CAN message */ - if (RPDO->receiveError > (uint8_t)CO_RPDO_RX_ACK) { - bool_t setError = RPDO->receiveError != (uint8_t)CO_RPDO_RX_OK; - uint16_t code = (RPDO->receiveError == (uint8_t)CO_RPDO_RX_SHORT) + if (RPDO->receiveError > CO_RPDO_RX_ACK) { + bool_t setError = RPDO->receiveError != CO_RPDO_RX_OK; + uint16_t code = (RPDO->receiveError == CO_RPDO_RX_SHORT) ? CO_EMC_PDO_LENGTH : CO_EMC_PDO_LENGTH_EXC; CO_error(PDO->em, setError, CO_EM_RPDO_WRONG_LENGTH, code, PDO->dataLength); RPDO->receiveError = setError - ? (uint8_t)(CO_RPDO_RX_ACK_ERROR) : (uint8_t)(CO_RPDO_RX_ACK_NO_ERROR); + ? CO_RPDO_RX_ACK_ERROR : CO_RPDO_RX_ACK_NO_ERROR; } /* Determine, which of the two rx buffers contains relevant message. */ diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 7a2655ab..947bf049 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -622,10 +622,9 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* load data from OD variable into the buffer */ OD_size_t countRd = 0; - uint8_t *bufShifted = SDO->buf + countRemain; CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, bufShifted, + ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->buf[countRemain], countRdRequest, &countRd); CO_UNLOCK_OD(SDO->CANdevTx); @@ -636,9 +635,10 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, } /* if data is string, send only data up to null termination */ + OD_size_t lastRd = countRd + countRemain; if ((countRd > 0U) && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U)) { - bufShifted[countRd] = 0; /* (SDO->buf is one byte larger) */ - OD_size_t countStr = (OD_size_t)strlen((char *)bufShifted); + SDO->buf[lastRd] = 0; /* (SDO->buf is one byte larger) */ + OD_size_t countStr = (OD_size_t)strlen((char *)&SDO->buf[countRemain]); if (countStr == 0U) { countStr = 1; }/* zero length is not allowed */ if (countStr < countRd) { /* string terminator found, read is finished, shorten data */ @@ -747,8 +747,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* if no error search object dictionary for new SDO request */ if (abortCode == CO_SDO_AB_NONE) { ODR_t odRet; - SDO->index = (((uint16_t)SDO->CANrxData[2]) << 8) - | SDO->CANrxData[1]; + SDO->index = (uint16_t)((((uint16_t)SDO->CANrxData[2]) << 8) + | SDO->CANrxData[1]); SDO->subIndex = SDO->CANrxData[3]; odRet = OD_getSub(OD_find(SDO->OD, SDO->index), SDO->subIndex, &SDO->OD_IO, false); diff --git a/MISRA.md b/MISRA.md new file mode 100644 index 00000000..073b921b --- /dev/null +++ b/MISRA.md @@ -0,0 +1,128 @@ +# MISRA Compliance + +The CANopenNode files conform to the [MISRA C:2012](https://www.misra.org.uk) +guidelines, with some noted exceptions. Compliance is checked with [PC Lint Plus](https://pclintplus.com/). + + +## Configuration Inhibits Control + +### Inhibits: Excluded the OD.c and OD.h files from the check because there are configuration parameters (not source code execution) +``` +-efile( *, CANopenNode\OD.c ) +-efile( *, CANopenNode\OD.h ) +``` + +### Inhibits: C comment contains '://' sequence +ref.: MISRA C 2012 Rule 3.1 +``` +-efile( 9259, CANopenNode* ) +``` + +### Inhibits: unknown preprocessor directive 'string' in conditionally excluded region +ref.: MISRA C 2012 Rule 20.13 +``` +-efile( 9160, CANopenNode* ) +``` + +### Inhibits: conversion from pointer to void to other pointer type (type) +ref.: MISRA C 2012 Rule 11.5 +``` +-efile( 9079, CANopenNode* ) +``` + +### Inhibits: complete definition of symbol is unnecessary in this translation unit +ref.: MISRA C 2012 Dir 4.8 +``` +-efile( 9045, CANopenNode* ) +``` + +### Inhibits: function parameter symbol modified +ref.: MISRA C 2012 Rule 17.8 +``` +-efile( 9044, CANopenNode* ) +``` + +### Inhibits: cannot cast essential-type value to essential-type type +ref.: MISRA C 2012 Rule 10.5 +``` +-efile( 9030, CANopenNode* ) +``` + +### Inhibits: function-like macro, 'macro', defined +ref.: MISRA C 2012 Dir 4.9 +``` +-efile( 9026, CANopenNode* ) +``` + +### Inhibits: pasting/stringize operator used in definition of object-like/function-like macro 'string' +ref.: MISRA C 2012 Rule 20.10 +``` +-efile( 9024, CANopenNode* ) +``` + +### Inhibits: performing pointer arithmetic via addition/subtraction +ref.: MISRA C 2012 Rule 18.4 +``` +-efile( 9016, CANopenNode* ) +``` + +### Inhibits: local variable symbol could be pointer to const +ref.: MISRA C 2012 Rule 8.13 +``` +-efile( 954, CANopenNode* ) +``` + +### Inhibits: return statement before end of function symbol +ref.: MISRA C 2012 Rule 15.5 +``` +-efile( 904, CANopenNode* ) +``` + +### Inhibits: the left/right operand to operator always evaluates to 0 +ref.: MISRA C 2004 Rule 13.7 +``` +-efile( 845, CANopenNode* ) +``` + +### Inhibits: previous value assigned to symbol not used +``` +-efile( 838, CANopenNode* ) +``` + +### Inhibits: zero given as string argument to operator context +``` +-efile( 835, CANopenNode* ) +``` + +### Inhibits: parameter symbol of function symbol could be pointer to const +ref.: MISRA C 2012 Rule 8.13 +``` +-efile( 818, CANopenNode* ) +``` + +### Inhibits: constant expression evaluates to 0 in 'unary/binary' operation 'operator' +``` +-efile( 778, CANopenNode* ) +``` + +### Inhibits: boolean condition for 'detail' always evaluates to 'detail' +ref.: MISRA C 2012 Rule 2.2 and Rule 14.3 +``` +-efile( 774, CANopenNode* ) +``` + +### Inhibits: local macro 'string' not referenced +ref.: MISRA C 2012 Rule 2.5 +``` +-efile( 750, CANopenNode* ) +``` + + +### Inhibits: constant value used in Boolean context (string) +``` +-efile( 506, CANopenNode* ) +``` + + + + From 5cf08656e19f6649cf4c244bea13ac32db33e312 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 08:50:45 +0200 Subject: [PATCH 381/520] Fix commit 29bb7992d2c25d1deda78f4d7cb15fcbcf08e219 won't respond with abort message, if segmented transfer is not supported --- 301/CO_SDOserver.c | 71 +++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 947bf049..7732a823 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -927,8 +927,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { if ((SDO->CANrxData[0] & 0xE0U) == 0x00U) { SDO->finished = (SDO->CANrxData[0] & 0x01U) != 0U; @@ -970,17 +970,17 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ break; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ case CO_SDO_ST_UPLOAD_INITIATE_REQ: { SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; break; } - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { if ((SDO->CANrxData[0] & 0xEFU) == 0x60U) { /* verify and alternate toggle bit */ uint8_t toggle = SDO->CANrxData[0] & 0x10U; @@ -995,12 +995,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ break; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { SDO->block_crcEnabled = (SDO->CANrxData[0] & 0x04) != 0; /* is size indicated? */ @@ -1033,19 +1033,15 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; SDO->finished = false; -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* data are copied directly in the receive function */ -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { /* Get number of data bytes in last segment, that do not * contain data. Then reduce buffer. */ @@ -1074,12 +1070,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* if pst (protocol switch threshold, byte5) is larger than data * size of OD variable, then switch to segmented transfer */ if (SDO->sizeInd > 0 && SDO->CANrxData[5] > 0 @@ -1113,12 +1107,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 if (SDO->CANrxData[0] == 0xA3) { SDO->block_seqno = 0; SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; @@ -1127,13 +1119,11 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 if (SDO->CANrxData[0] == 0xA2) { SDO->block_blksize = SDO->CANrxData[2]; if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { @@ -1175,9 +1165,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ case CO_SDO_ST_IDLE: case CO_SDO_ST_ABORT: @@ -1193,6 +1183,20 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: case CO_SDO_ST_UPLOAD_BLK_END_SREQ: case CO_SDO_ST_UPLOAD_BLK_END_CRSP: + +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) == 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) == 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ default: { /* unknown message received */ abortCode = CO_SDO_AB_CMD; @@ -1296,8 +1300,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { SDO->CANtxBuff->data[0] = 0x20U | SDO->toggle; SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; @@ -1311,9 +1315,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, else { SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; } -#endif break; } +#endif case CO_SDO_ST_UPLOAD_INITIATE_RSP: { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 @@ -1384,8 +1388,8 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, break; } - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { /* refill the data buffer if necessary */ if (!readFromOd(SDO, &abortCode, 7, false)) { break; @@ -1435,12 +1439,12 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* send message */ (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ break; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { SDO->CANtxBuff->data[0] = 0xA4; SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); @@ -1469,12 +1473,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; CO_FLAG_CLEAR(SDO->CANrxNew); (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xA2; SDO->CANtxBuff->data[1] = SDO->block_seqno; #ifdef CO_DEBUG_SDO_SERVER @@ -1526,23 +1528,19 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, CO_DEBUG_SDO_SERVER(msg); } #endif -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xA1; (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xC4; SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); @@ -1559,12 +1557,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->timeoutTimer = 0; (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* write header and get current count */ SDO->CANtxBuff->data[0] = ++SDO->block_seqno; OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; @@ -1616,12 +1612,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* reset timeout timer and send message */ SDO->timeoutTimer = 0; (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->CANtxBuff->data[0] = 0xC1 | (SDO->block_noData << 2); SDO->CANtxBuff->data[1] = (uint8_t) SDO->block_crc; SDO->CANtxBuff->data[2] = (uint8_t) (SDO->block_crc >> 8); @@ -1630,11 +1624,22 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->timeoutTimer = 0; (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ break; } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ - +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) == 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: +#endif +#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) == 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: +#endif case CO_SDO_ST_IDLE: case CO_SDO_ST_ABORT: case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: From 1e9b6da4f3bba25afede98bc7e90f41184e8d040 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 10:33:50 +0200 Subject: [PATCH 382/520] CO_fifo: static analysis: ignoring return value of functions [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] --- 301/CO_fifo.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 2771e691..87d6d807 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -489,7 +489,7 @@ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, &n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, &n, sizeof(n), NULL); return sprintf(buf, "%"PRIu8, n); } else { @@ -501,7 +501,7 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); } else { @@ -513,7 +513,7 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; if ((fifo != NULL) && (count >= 12U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); } else { @@ -525,7 +525,7 @@ size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); } else { @@ -537,7 +537,7 @@ size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%02"PRIX8, n); } else { @@ -549,7 +549,7 @@ size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); } else { @@ -561,7 +561,7 @@ size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; if ((fifo != NULL) && (count >= 12U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); } else { @@ -573,7 +573,7 @@ size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); } else { @@ -585,7 +585,7 @@ size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int8_t n=0; if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId8, n); } else { @@ -597,7 +597,7 @@ size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int16_t n=0; if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId16, CO_SWAP_16(n)); } else { @@ -609,7 +609,7 @@ size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int32_t n=0; if ((fifo != NULL) && (count >= 13U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId32, CO_SWAP_32(n)); } else { @@ -621,7 +621,7 @@ size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int64_t n=0; if ((fifo != NULL) && (count >= 23U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId64, CO_SWAP_64(n)); } else { @@ -633,7 +633,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float32_t n=0; if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", (double)CO_SWAP_32(n)); } else { @@ -645,7 +645,7 @@ size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float64_t n=0; if ((fifo != NULL) && (count >= 30U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { - CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", (double)CO_SWAP_64(n)); } else { @@ -1066,7 +1066,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { int32_t num; s[0] = firstChar; s[1] = c; s[2] = 0; num = strtol((char *)&s[0], NULL, 16); - CO_fifo_putc(dest, (uint8_t) num); + (void)CO_fifo_putc(dest, (uint8_t) num); destSpace--; step = 0; } @@ -1086,7 +1086,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { int32_t num; s[0] = firstChar; s[1] = 0; num = strtol((char *)&s[0], NULL, 16); - CO_fifo_putc(dest, (uint8_t) num); + (void)CO_fifo_putc(dest, (uint8_t) num); destSpace--; step = 0; } @@ -1158,7 +1158,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else { /* this must be a single word string without '"' */ /* copy the character */ - CO_fifo_putc(dest, c); + (void)CO_fifo_putc(dest, c); destSpace--; step = 2; } @@ -1190,7 +1190,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { } else { /* copy the character */ - CO_fifo_putc(dest, c); + (void)CO_fifo_putc(dest, c); destSpace--; } break; @@ -1199,7 +1199,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { case 4: /* previous was double quote, parsing no quoted word */ if (c == DELIM_DQUOTE) { /* escaped double quote, copy the character and continue */ - CO_fifo_putc(dest, c); + (void)CO_fifo_putc(dest, c); destSpace--; step -= 2U; } @@ -1342,12 +1342,12 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { /* base64 string finished, write remaining bytes */ switch (step) { case 2: - CO_fifo_putc(dest, (uint8_t)(dword >> 4)); + (void)CO_fifo_putc(dest, (uint8_t)(dword >> 4)); destSpace --; break; case 3: - CO_fifo_putc(dest, (uint8_t)(dword >> 10)); - CO_fifo_putc(dest, (uint8_t)(dword >> 2)); + (void)CO_fifo_putc(dest, (uint8_t)(dword >> 10)); + (void)CO_fifo_putc(dest, (uint8_t)(dword >> 2)); destSpace -= 2U; break; default: @@ -1367,9 +1367,9 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { else { dword = (dword << 6) | code; if (step++ == 3U) { - CO_fifo_putc(dest, (uint8_t)((dword >> 16) & 0xFFU)); - CO_fifo_putc(dest, (uint8_t)((dword >> 8) & 0xFFU)); - CO_fifo_putc(dest, (uint8_t)(dword & 0xFFU)); + (void)CO_fifo_putc(dest, (uint8_t)((dword >> 16) & 0xFFU)); + (void)CO_fifo_putc(dest, (uint8_t)((dword >> 8) & 0xFFU)); + (void)CO_fifo_putc(dest, (uint8_t)(dword & 0xFFU)); destSpace -= 3U; dword = 0; step = 0; From 29156e8ed7fba23e0e5c3c189658d718605ba266 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 10:48:52 +0200 Subject: [PATCH 383/520] CO_fifo: static analysis: refactoring changed enum with define to be able to use bitwise operators --- 301/CO_fifo.c | 52 ++++++++++++++++++------------------- 301/CO_fifo.h | 59 ++++++++++++++++++++---------------------- 309/CO_gateway_ascii.c | 4 +-- 309/CO_gateway_ascii.h | 2 +- 4 files changed, 57 insertions(+), 60 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 87d6d807..8340ad66 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -783,13 +783,13 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { /******************************************************************************/ -size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -805,13 +805,13 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -827,13 +827,13 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -849,13 +849,13 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[25]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -871,13 +871,13 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -894,13 +894,13 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -917,13 +917,13 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -939,13 +939,13 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[25]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -961,13 +961,13 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[30]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -983,13 +983,13 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[40]; int8_t closed = -1; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); - CO_fifo_st st = (uint8_t)closed; + uint8_t st = closed; if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; else { char *sRet; @@ -1005,12 +1005,12 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return nWr; } -size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t destSpace, destSpaceStart; bool_t finished = false; uint8_t step; uint8_t firstChar; - CO_fifo_st st = 0; + uint8_t st = 0; if ((dest == NULL) || (src == NULL)) { return 0; @@ -1113,11 +1113,11 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return destSpaceStart - destSpace; } -size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t destSpace, destSpaceStart; bool_t finished = false; uint8_t step; - CO_fifo_st st = 0; + uint8_t st = 0; if ((dest == NULL) || (src == NULL)) { return 0; @@ -1273,14 +1273,14 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { return destSpaceStart - destSpace; } -size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status) { +size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { /* mime-base64 decoding, see description above base64EncTable */ size_t destSpace, destSpaceStart; bool_t finished = false; uint8_t step; uint32_t dword; - CO_fifo_st st = 0; + uint8_t st = 0; if ((dest == NULL) || (src == NULL)) { return 0; diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 7b817709..59375dbb 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -471,64 +471,61 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); /** Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar */ -typedef enum { - /** Bit is set, if command delimiter is reached in src */ - CO_fifo_st_closed = 0x01U, - /** Bit is set, if copy was partial and more data are available. If unset - * and no error, then all data was successfully copied. */ - CO_fifo_st_partial = 0x02U, - /** Bit is set, if no valid token found */ - CO_fifo_st_errTok = 0x10U, - /** Bit is set, if value is not valid or out of limits */ - CO_fifo_st_errVal = 0x20U, - /** Bit is set, if destination buffer is to small */ - CO_fifo_st_errBuf = 0x40U, - /** Bit is set, if internal error */ - CO_fifo_st_errInt = 0x80U, - /** Bitmask for error bits */ - CO_fifo_st_errMask = 0xF0U -} CO_fifo_st; + + +/** + * @defgroup uint8_t Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar + * @{ + */ +#define CO_fifo_st_closed 0x01U /** Bit is set, if command delimiter is reached in src */ +#define CO_fifo_st_partial 0x02U /** Bit is set, if copy was partial and more data are available. If unset and no error, then all data was successfully copied. */ +#define CO_fifo_st_errTok 0x10U /** Bit is set, if no valid token found */ +#define CO_fifo_st_errVal 0x20U /** Bit is set, if value is not valid or out of limits */ +#define CO_fifo_st_errBuf 0x40U /** Bit is set, if destination buffer is to small */ +#define CO_fifo_st_errInt 0x80U /** Bit is set, if internal error */ +#define CO_fifo_st_errMask 0xF0U /** Bitmask for error bits */ +/** @} */ /* uint8_t */ /** * Read ascii string from src fifo and copy as uint8_t variable to dest fifo. * * @param dest destination fifo buffer object. * @param src source fifo buffer object. - * @param [out] status bitfield of the CO_fifo_st type. + * @param [out] status bitfield of the uint8_t type. * * @return Number of bytes written into dest. */ -size_t CO_fifo_cpyTok2U8 (CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2U8 (CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to uint16_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to uint32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to uint64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to int8_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I8 (CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2I8 (CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to int16_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to int32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to int64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to float32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy ascii string to float64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy bytes written as two hex digits into to data. Bytes may be space * separated. See CO_fifo_cpyTok2U8 for parameters. */ -size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Copy visible string to data. A visible string must be enclosed with double * quotes, if it contains space. If a double quote is used within the string, * the quotes are escaped by a second quotes. Input string can not contain * newline characters. See CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); /** Read ascii mime-base64 encoded string from src fifo and copy as binary data * to dest fifo. Encoding is as specified in RFC 2045, without CR-LF, but one * long string in single line. See also CO_fifo_readU82a */ -size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, CO_fifo_st *status); +size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES */ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 45bc4fce..653b5710 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -927,7 +927,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if ((strcmp(tok, "w") == 0) || (strcmp(tok, "write") == 0)) { uint16_t idx; uint8_t subidx; - CO_fifo_st status; + uint8_t status; CO_SDO_return_t SDO_ret; size_t size; bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); @@ -1631,7 +1631,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* copy data to the SDO buffer if previous dataTypeScan was partial */ if (gtwa->SDOdataCopyStatus) { - CO_fifo_st status; + uint8_t status; gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, >wa->commFifo, &status); diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 13ecc672..79b553be 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -286,7 +286,7 @@ typedef struct { * description of parameters see #CO_fifo_cpyTok2U8 */ size_t (*dataTypeScan)(CO_fifo_t *dest, CO_fifo_t *src, - CO_fifo_st *status); + uint8_t *status); } CO_GTWA_dataType_t; #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ From d96ac7719e96f739eed6ba45059aaa0ba2e92378 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 11:00:19 +0200 Subject: [PATCH 384/520] CO_fifo: static analysis: body should be a compound statement [MISRA 2012 Rule 15.6, required] --- 301/CO_fifo.c | 186 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 138 insertions(+), 48 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 8340ad66..2f4f8a12 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -410,7 +410,9 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, } else if (delimCommandFound) { /* command delimiter found, set readPtr behind it. */ - if (++ptr == fifo->bufSize) ptr = 0; + if (++ptr == fifo->bufSize) { + ptr = 0; + } fifo->readPtr = ptr; finished = true; } @@ -790,18 +792,26 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if ((sRet != strchr(buf, '\0')) || (u32 > (uint32_t)UINT8_MAX)) st |= CO_fifo_st_errVal; + if ((sRet != strchr(buf, '\0')) || (u32 > (uint32_t)UINT8_MAX)) { + st |= CO_fifo_st_errVal; + } else { uint8_t num = (uint8_t) u32; nWr = CO_fifo_write(dest, &num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return nWr; } @@ -812,18 +822,26 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if ((sRet != strchr(buf, '\0')) || (u32 > (uint32_t)UINT16_MAX)) st |= CO_fifo_st_errVal; + if ((sRet != strchr(buf, '\0')) || (u32 > (uint32_t)UINT16_MAX)) { + st |= CO_fifo_st_errVal; + } else { uint16_t num = CO_SWAP_16((uint16_t) u32); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return nWr; } @@ -834,18 +852,26 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; + if (sRet != strchr(buf, '\0')) { + st |= CO_fifo_st_errVal; + } else { uint32_t num = CO_SWAP_32(u32); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return nWr; } @@ -856,18 +882,26 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; uint64_t u64 = strtoull(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; + if (sRet != strchr(buf, '\0')) { + st |= CO_fifo_st_errVal; + } else { uint64_t num = CO_SWAP_64(u64); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) { + *status = (uint8_t) st; + } return nWr; } @@ -878,7 +912,9 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); @@ -887,10 +923,14 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } else { int8_t num = (int8_t) i32; nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return nWr; } @@ -901,7 +941,9 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); @@ -910,10 +952,14 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } else { int16_t num = CO_SWAP_16((int16_t) i32); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return nWr; } @@ -924,18 +970,26 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; + if (sRet != strchr(buf, '\0')) { + st |= CO_fifo_st_errVal; + } else { int32_t num = CO_SWAP_32(i32); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return nWr; } @@ -946,18 +1000,26 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; int64_t i64 = strtoll(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; + if (sRet != strchr(buf, '\0')) { + st |= CO_fifo_st_errVal; + } else { int64_t num = CO_SWAP_64(i64); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = (uint8_t) st; + if (status != NULL) { + *status = (uint8_t) st; + } return nWr; } @@ -968,18 +1030,26 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; float32_t f32 = strtof(buf, &sRet); - if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; + if (sRet != strchr(buf, '\0')) { + st |= CO_fifo_st_errVal; + } else { float32_t num = CO_SWAP_32(f32); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return nWr; } @@ -990,18 +1060,26 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; - if ((nRd == 0U) || err) st |= CO_fifo_st_errTok; + if ((nRd == 0U) || err) { + st |= CO_fifo_st_errTok; + } else { char *sRet; float64_t f64 = strtof(buf, &sRet); - if (sRet != strchr(buf, '\0')) st |= CO_fifo_st_errVal; + if (sRet != strchr(buf, '\0')) { + st |= CO_fifo_st_errVal; + } else { float64_t num = CO_SWAP_64(f64); nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); - if (nWr != sizeof(num)) st |= CO_fifo_st_errBuf; + if (nWr != sizeof(num)) { + st |= CO_fifo_st_errBuf; + } } } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return nWr; } @@ -1073,10 +1151,12 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } else if (isgraph((int)c) != 0) { /* printable character, not hex digit */ - if (c == DELIM_COMMENT) /* comment start */ + if (c == DELIM_COMMENT) { /* comment start */ step = 6; - else /* syntax error */ + } + else {/* syntax error */ st |= CO_fifo_st_errTok; + } } else { /* this is space or delimiter */ @@ -1108,7 +1188,9 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { dest->aux = ((uint32_t)step << 8) | firstChar; } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return destSpaceStart - destSpace; } @@ -1241,10 +1323,12 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { step = 6; } else if (isgraph((int)c) != 0) { - if (c == DELIM_COMMENT) /* comment start */ + if (c == DELIM_COMMENT) { /* comment start */ step = 6; - else /* syntax error */ + } + else {/* syntax error */ st |= CO_fifo_st_errTok; + } } break; } @@ -1268,7 +1352,9 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { dest->aux = step; } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return destSpaceStart - destSpace; } @@ -1325,10 +1411,12 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { step = 6; } else if ((isgraph((int)c) != 0) && (c != (uint8_t)'=')) { - if (c == DELIM_COMMENT) /* comment start */ + if (c == DELIM_COMMENT) { /* comment start */ step = 6; - else /* syntax error */ + } + else {/* syntax error */ st |= CO_fifo_st_errTok; + } } continue; } @@ -1383,7 +1471,9 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { dest->aux = ((uint32_t)step << 24) | (dword & 0xFFFFFFU); } - if (status != NULL) *status = st; + if (status != NULL) { + *status = st; + } return destSpaceStart - destSpace; } From 4bef46fb46750cc26c94183469623d034ce6cc84 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 11:43:41 +0200 Subject: [PATCH 385/520] CO_fifo: static analysis: refactoring CO_fifo_readToken for loss of sign --- 301/CO_fifo.c | 28 ++++----- 301/CO_fifo.h | 2 +- 309/CO_gateway_ascii.c | 134 ++++++++++++++++++++--------------------- 3 files changed, 82 insertions(+), 82 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 2f4f8a12..bb476698 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -341,7 +341,7 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { size_t CO_fifo_readToken(CO_fifo_t *fifo, char *buf, size_t count, - int8_t *closed, + uint8_t *closed, bool_t *err) { bool_t delimCommandFound = false; @@ -442,15 +442,15 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, /* set 'err' return value */ if ((err != NULL) && (*err == false)) { if ((tokenSize == count) || ((closed != NULL) && - (((*closed == 1) && (!delimCommandFound || (tokenSize == 0U))) || - ((*closed == 0) && (delimCommandFound || (tokenSize == 0U)))) + (((*closed == 1U) && (!delimCommandFound || (tokenSize == 0U))) || + ((*closed == 0U) && (delimCommandFound || (tokenSize == 0U)))) )) { *err = true; } } /* set 'closed' return value */ if (closed != NULL) { - *closed = delimCommandFound ? 1 : 0; + *closed = delimCommandFound ? 1U : 0U; } /* token was larger then size of the buffer, all was cleaned, return empty*/ @@ -787,7 +787,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { /******************************************************************************/ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -817,7 +817,7 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -847,7 +847,7 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -877,7 +877,7 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[25]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -907,7 +907,7 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -936,7 +936,7 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -965,7 +965,7 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -995,7 +995,7 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[25]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -1025,7 +1025,7 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[30]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); @@ -1055,7 +1055,7 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[40]; - int8_t closed = -1; + uint8_t closed = 0xFFU; bool_t err = 0; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 59375dbb..61a843f0 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -411,7 +411,7 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment); size_t CO_fifo_readToken(CO_fifo_t *fifo, char *buf, size_t count, - int8_t *closed, + uint8_t *closed, bool_t *err); #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 653b5710..16ee6fa4 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -623,7 +623,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, (void)timerNext_us; /* may be unused */ bool_t err = false; /* syntax or other error, true or false, I/O variable */ - int8_t closed; /* indication of command delimiter, I/O variable */ + uint8_t closed; /* indication of command delimiter, I/O variable */ CO_GTWA_respErrorCode_t respErrorCode = CO_GTWA_respErrorNone; if (gtwa == NULL) { @@ -667,16 +667,16 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* parse mandatory token '"[""]"' */ - closed = -1; + closed = 0xFFU; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); /* Break if error in token or token was found, but closed with * command delimiter. */ - if (err || ((n > 0) && (closed != 0))) { + if (err || ((n > 0) && (closed != 0U))) { err = true; break; } /* If empty line or just comment, continue with next command */ - else if ((n == 0) && (closed != 0)) { + else if ((n == 0) && (closed != 0U)) { responseWithEmpty(gtwa); continue; } @@ -692,7 +692,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* parse optional tokens '[[] ]', both numerical. Then * follows mandatory token , which is not numerical. */ for (i = 0; i < 3; i++) { - closed = -1; + closed = 0xFFU; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err || (n == 0)) { @@ -702,7 +702,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } else if (isdigit((int)tok[0]) == 0) { /* found */ break; - } else if (closed != 0) { + } else if (closed != 0U) { /* numerical value must not be closed */ err = true; break; @@ -753,13 +753,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* set command - multiple sub commands */ if (strcmp(tok, "set") == 0) { - if (closed != 0) { + if (closed != 0U) { err = true; break; } /* command 2 */ - closed = -1; + closed = 0xFFU; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err) break; @@ -768,13 +768,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (strcmp(tok, "network") == 0) { uint16_t value; - if (closed != 0) { + if (closed != 0U) { err = true; break; } /* value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, CO_CONFIG_GTW_NET_MIN, @@ -789,13 +789,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t value; - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint8_t)getU32(tok, 1, 127, &err); @@ -810,13 +810,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t value; - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, 1, 0xFFFF, &err); @@ -830,13 +830,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t value; - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, 0, 1, &err); @@ -861,19 +861,19 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_SDO_return_t SDO_ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* index */ - closed = 0; + closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) break; /* subindex */ - closed = -1; + closed = 0xFFU; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); @@ -883,8 +883,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* optional data type */ - if (closed == 0) { - closed = 1; + if (closed == 0U) { + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); convertToLower(tok, sizeof(tok)); @@ -932,26 +932,26 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, size_t size; bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode); - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* index */ - closed = 0; + closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) break; /* subindex */ - closed = 0; + closed = 0U; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); if (err) break; /* data type */ - closed = 0; + closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); convertToLower(tok, sizeof(tok)); @@ -986,14 +986,14 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, >wa->commFifo, &status); /* set to true, if command delimiter was found */ - closed = ((status & CO_fifo_st_closed) == 0) ? 0 : 1; + closed = ((status & CO_fifo_st_closed) == 0) ? 0U : 1U; /* set to true, if data are copied only partially */ gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0; /* is syntax error in command or size is zero or not the last token * in command */ if (((status & CO_fifo_st_errMask) != 0) || (size == 0) - || ((gtwa->SDOdataCopyStatus == false) && (closed != 1)) + || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U)) ) { err = true; break; @@ -1018,7 +1018,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_OPERATIONAL; - if ((closed != 1) || NodeErr) { + if ((closed != 1U) || NodeErr) { err = true; break; } @@ -1040,7 +1040,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_STOPPED; - if ((closed != 1) || NodeErr) { + if ((closed != 1U) || NodeErr) { err = true; break; } @@ -1064,7 +1064,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_PRE_OPERATIONAL; - if ((closed != 1) || NodeErr) { + if ((closed != 1U) || NodeErr) { err = true; break; } @@ -1086,13 +1086,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2; - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* command 2 */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err) break; @@ -1127,13 +1127,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t select; - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* get value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); select = (uint8_t)getU32(tok, 0, 1, &err); if (err) break; @@ -1162,13 +1162,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); CO_LSS_address_t *addr = >wa->lssAddress; - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* get values */ - closed = 0; + closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err); if (err) break; @@ -1181,7 +1181,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, addr->identity.revisionNumber = getU32(tok, 0, 0xFFFFFFFF, &err); if (err) break; - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.serialNumber = getU32(tok, 0, 0xFFFFFFFF, &err); if (err) break; @@ -1193,13 +1193,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(tok, "lss_set_node") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* get value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); gtwa->lssNID = (uint8_t)getU32(tok, 0, 0xFF, &err); if ((gtwa->lssNID > 0x7F) && (gtwa->lssNID < 0xFF)) err = true; @@ -1218,19 +1218,19 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, int maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / sizeof(CO_LSS_bitTimingTableLookup[0])) - 1; - if ((closed != 0)|| NodeErr) { + if ((closed != 0U)|| NodeErr) { err = true; break; } /* First parameter is table selector. We only support the CiA * bit timing table from CiA301 ("0") */ - closed = 0; + closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); (void)getU32(tok, 0, 0, &err); /* get value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); tableIndex = (uint8_t)getU32(tok, 0, maxIndex, &err); if (tableIndex == 5) err = true; @@ -1247,13 +1247,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, uint16_t switchDelay; CO_LSSmaster_return_t ret; - if ((closed != 0) || NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } /* get value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); switchDelay = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) break; @@ -1273,7 +1273,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(tok, "lss_store") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - if ((closed != 1) || NodeErr) { + if ((closed != 1U) || NodeErr) { err = true; break; } @@ -1290,10 +1290,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - if (closed == 0) { + if (closed == 0U) { uint8_t lsssub; /* get value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); lsssub = (uint8_t)getU32(tok, 0, 3, &err); if (err) break; @@ -1316,7 +1316,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(tok, "lss_get_node") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - if ((closed != 1) || NodeErr) { + if ((closed != 1U) || NodeErr) { err = true; break; } @@ -1336,9 +1336,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - if (closed == 0) { + if (closed == 0U) { /* get value */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) break; @@ -1380,9 +1380,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - if (closed == 0) { + if (closed == 0U) { /* get optional token timeout (non standard) */ - closed = -1; + closed = 0xFFU; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) break; @@ -1394,7 +1394,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->lssNodeCount = 0; gtwa->lssSubState = 0; - if (closed == 1) { + if (closed == 1U) { /* No other arguments, as by CiA specification for this command. * Do full scan. */ /* use start node ID 2. Should work in most cases */ @@ -1404,23 +1404,23 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* prepare lssFastscan, all zero */ (void)memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); } - if (closed == 0) { + if (closed == 0U) { /* more arguments follow */ CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); gtwa->lssNID = (uint8_t)getU32(tok, 1, 127, &err); if (err) break; - closed = -1; + closed = 0xFFU; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); gtwa->lssStore = (bool_t)getU32(tok, 0, 1, &err); if (err) break; - if (closed == 1) { + if (closed == 1U) { /* No other arguments, prepare lssFastscan, all zero */ (void)memset(>wa->lssFastscan, 0, sizeof(gtwa->lssFastscan)); } } - if (closed == 0) { + if (closed == 0U) { /* more arguments follow */ CO_LSSmaster_fastscan_t *fs = >wa->lssFastscan; @@ -1452,7 +1452,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, fs->scan[CO_LSS_FASTSCAN_SERIAL] = getU32(tok, 0, 2, &err); if (err) break; - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.serialNumber = getU32(tok,0,0xFFFFFFFF,&err); if (err) break; @@ -1466,7 +1466,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 /* Print message log */ else if (strcmp(tok, "log") == 0) { - if (closed == 0) { + if (closed == 0U) { err = true; break; } @@ -1477,12 +1477,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 /* Print help */ else if (strcmp(tok, "help") == 0) { - if (closed == 1) { + if (closed == 1U) { gtwa->helpString = CO_GTWA_helpString; } else { /* get second token */ - closed = 1; + closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); if (err) break; @@ -1507,7 +1507,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 /* Print status led diodes */ else if (strcmp(tok, "led") == 0) { - if (closed == 0) { + if (closed == 0U) { err = true; break; } @@ -1537,7 +1537,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, responseWithError(gtwa, respErrorCode); /* delete command, if it was only partially read */ - if(closed == 0) { + if(closed == 0U) { CO_fifo_CommSearch(>wa->commFifo, true); } gtwa->state = CO_GTWA_ST_IDLE; @@ -1636,24 +1636,24 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, >wa->commFifo, &status); /* set to true, if command delimiter was found */ - closed = ((status & CO_fifo_st_closed) == 0) ? 0 : 1; + closed = ((status & CO_fifo_st_closed) == 0) ? 0U : 1U; /* set to true, if data are copied only partially */ gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0; /* is syntax error in command or not the last token in command */ if (((status & CO_fifo_st_errMask) != 0) - || ((gtwa->SDOdataCopyStatus == false) && (closed != 1)) + || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U)) ) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; abort = true; /* abort SDO communication */ /* clear the rest of the command, if necessary */ - if (closed != 1) + if (closed != 1U) CO_fifo_CommSearch(>wa->commFifo, true); } if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) { /* Stay in this state, until all data transferred via commFifo * will be purged. */ - if (!CO_fifo_purge(>wa->SDO_C->bufFifo) || closed == 1) { + if (!CO_fifo_purge(>wa->SDO_C->bufFifo) || closed == 1U) { gtwa->state = CO_GTWA_ST_IDLE; } break; From 11771f889c75c6f9d78e69d1fc0ffe22cf451604 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 11:45:23 +0200 Subject: [PATCH 386/520] CO_fifo: fix doxygen documentation comments --- 301/CO_fifo.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 61a843f0..6f68d9be 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -477,13 +477,13 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); * @defgroup uint8_t Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar * @{ */ -#define CO_fifo_st_closed 0x01U /** Bit is set, if command delimiter is reached in src */ -#define CO_fifo_st_partial 0x02U /** Bit is set, if copy was partial and more data are available. If unset and no error, then all data was successfully copied. */ -#define CO_fifo_st_errTok 0x10U /** Bit is set, if no valid token found */ -#define CO_fifo_st_errVal 0x20U /** Bit is set, if value is not valid or out of limits */ -#define CO_fifo_st_errBuf 0x40U /** Bit is set, if destination buffer is to small */ -#define CO_fifo_st_errInt 0x80U /** Bit is set, if internal error */ -#define CO_fifo_st_errMask 0xF0U /** Bitmask for error bits */ +#define CO_fifo_st_closed 0x01U /**< Bit is set, if command delimiter is reached in src */ +#define CO_fifo_st_partial 0x02U /**< Bit is set, if copy was partial and more data are available. If unset and no error, then all data was successfully copied. */ +#define CO_fifo_st_errTok 0x10U /**< Bit is set, if no valid token found */ +#define CO_fifo_st_errVal 0x20U /**< Bit is set, if value is not valid or out of limits */ +#define CO_fifo_st_errBuf 0x40U /**< Bit is set, if destination buffer is to small */ +#define CO_fifo_st_errInt 0x80U /**< Bit is set, if internal error */ +#define CO_fifo_st_errMask 0xF0U /**< Bitmask for error bits */ /** @} */ /* uint8_t */ /** From c643683b24b1404ca624e6214a2ebfc5eda0a944 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 26 Jun 2024 12:15:30 +0200 Subject: [PATCH 387/520] Update CO_ODinterface.c: fix memcpy boundary verification --- 301/CO_ODinterface.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index b0682118..d9cc744c 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -80,6 +80,7 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ + OD_size_t dataLenRemain = dataLenToCopy; /* remaining length of dataOrig buffer */ uint8_t *dataOrig = stream->dataOrig; if (dataOrig == NULL) { @@ -97,6 +98,7 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, } /* reduce for already copied data */ dataLenToCopy -= stream->dataOffset; + dataLenRemain = dataLenToCopy; dataOrig += stream->dataOffset; if (dataLenToCopy > count) { @@ -116,7 +118,8 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, return ODR_DATA_LONG; } - if (((dataLenToCopy + stream->dataOffset) <= stream->dataLength) && (dataLenToCopy <= count)) { + /* additional check for Misra c compliance */ + if ((dataLenToCopy <= dataLenRemain) && (dataLenToCopy <= count)) { (void)memcpy((void *)dataOrig, (const void *)buf, dataLenToCopy); } else { From 3e08dd45d5f8b1b67e194bf41efa7c585e37b7d4 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 26 Jun 2024 12:27:02 +0200 Subject: [PATCH 388/520] Update CO_Emergency.h: fix doxygen documentation comments --- 301/CO_Emergency.h | 192 ++++++++++++++++++++++----------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 0b5ce18a..661fdf63 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -132,51 +132,51 @@ extern "C" { * * Standard error codes according to CiA DS-301 and DS-401. */ -#define CO_EMC_NO_ERROR 0x0000U /** 0x00xx error Reset or No Error */ -#define CO_EMC_GENERIC 0x1000U /** 0x10xx Generic Error */ -#define CO_EMC_CURRENT 0x2000U /** 0x20xx Current */ -#define CO_EMC_CURRENT_INPUT 0x2100U /** 0x21xx Current device input side */ -#define CO_EMC_CURRENT_INSIDE 0x2200U /** 0x22xx Current inside the device */ -#define CO_EMC_CURRENT_OUTPUT 0x2300U /** 0x23xx Current device output side */ -#define CO_EMC_VOLTAGE 0x3000U /** 0x30xx Voltage */ -#define CO_EMC_VOLTAGE_MAINS 0x3100U /** 0x31xx Mains Voltage */ -#define CO_EMC_VOLTAGE_INSIDE 0x3200U /** 0x32xx Voltage inside the device */ -#define CO_EMC_VOLTAGE_OUTPUT 0x3300U /** 0x33xx Output Voltage */ -#define CO_EMC_TEMPERATURE 0x4000U /** 0x40xx Temperature */ -#define CO_EMC_TEMP_AMBIENT 0x4100U /** 0x41xx Ambient Temperature */ -#define CO_EMC_TEMP_DEVICE 0x4200U /** 0x42xx Device Temperature */ -#define CO_EMC_HARDWARE 0x5000U /** 0x50xx Device Hardware */ -#define CO_EMC_SOFTWARE_DEVICE 0x6000U /** 0x60xx Device Software */ -#define CO_EMC_SOFTWARE_INTERNAL 0x6100U /** 0x61xx Internal Software */ -#define CO_EMC_SOFTWARE_USER 0x6200U /** 0x62xx User Software */ -#define CO_EMC_DATA_SET 0x6300U /** 0x63xx Data Set */ -#define CO_EMC_ADDITIONAL_MODUL 0x7000U /** 0x70xx Additional Modules */ -#define CO_EMC_MONITORING 0x8000U /** 0x80xx Monitoring */ -#define CO_EMC_COMMUNICATION 0x8100U /** 0x81xx Communication */ -#define CO_EMC_CAN_OVERRUN 0x8110U /** 0x8110 CAN Overrun (Objects lost) */ -#define CO_EMC_CAN_PASSIVE 0x8120U /** 0x8120 CAN in Error Passive Mode */ -#define CO_EMC_HEARTBEAT 0x8130U /** 0x8130 Life Guard Error or Heartbeat Error */ -#define CO_EMC_BUS_OFF_RECOVERED 0x8140U /** 0x8140 recovered from bus off */ -#define CO_EMC_CAN_ID_COLLISION 0x8150U /** 0x8150 CAN-ID collision */ -#define CO_EMC_PROTOCOL_ERROR 0x8200U /** 0x82xx Protocol Error */ -#define CO_EMC_PDO_LENGTH 0x8210U /** 0x8210 PDO not processed due to length error */ -#define CO_EMC_PDO_LENGTH_EXC 0x8220U /** 0x8220 PDO length exceeded */ -#define CO_EMC_DAM_MPDO 0x8230U /** 0x8230 DAM MPDO not processed destination object not available */ -#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /** 0x8240 Unexpected SYNC data length */ -#define CO_EMC_RPDO_TIMEOUT 0x8250U /** 0x8250 RPDO timeout */ -#define CO_EMC_EXTERNAL_ERROR 0x9000U /** 0x90xx External Error */ -#define CO_EMC_ADDITIONAL_FUNC 0xF000U /** 0xF0xx Additional Functions */ -#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /** 0xFFxx Device specific */ - -#define CO_EMC401_OUT_CUR_HI 0x2310U /** 0x2310 DS401 Current at outputs too high (overload) */ -#define CO_EMC401_OUT_SHORTED 0x2320U /** 0x2320 DS401 Short circuit at outputs */ -#define CO_EMC401_OUT_LOAD_DUMP 0x2330U /** 0x2330 DS401 Load dump at outputs */ -#define CO_EMC401_IN_VOLT_HI 0x3110U /** 0x3110 DS401 Input voltage too high */ -#define CO_EMC401_IN_VOLT_LOW 0x3120U /** 0x3120 DS401 Input voltage too low */ -#define CO_EMC401_INTERN_VOLT_HI 0x3210U /** 0x3210 DS401 Internal voltage too high */ -#define CO_EMC401_INTERN_VOLT_LO 0x3220U /** 0x3220 DS401 Internal voltage too low */ -#define CO_EMC401_OUT_VOLT_HIGH 0x3310U /** 0x3310 DS401 Output voltage too high */ -#define CO_EMC401_OUT_VOLT_LOW 0x3320U /** 0x3320 DS401 Output voltage too low */ +#define CO_EMC_NO_ERROR 0x0000U /**< 0x00xx error Reset or No Error */ +#define CO_EMC_GENERIC 0x1000U /**< 0x10xx Generic Error */ +#define CO_EMC_CURRENT 0x2000U /**< 0x20xx Current */ +#define CO_EMC_CURRENT_INPUT 0x2100U /**< 0x21xx Current device input side */ +#define CO_EMC_CURRENT_INSIDE 0x2200U /**< 0x22xx Current inside the device */ +#define CO_EMC_CURRENT_OUTPUT 0x2300U /**< 0x23xx Current device output side */ +#define CO_EMC_VOLTAGE 0x3000U /**< 0x30xx Voltage */ +#define CO_EMC_VOLTAGE_MAINS 0x3100U /**< 0x31xx Mains Voltage */ +#define CO_EMC_VOLTAGE_INSIDE 0x3200U /**< 0x32xx Voltage inside the device */ +#define CO_EMC_VOLTAGE_OUTPUT 0x3300U /**< 0x33xx Output Voltage */ +#define CO_EMC_TEMPERATURE 0x4000U /**< 0x40xx Temperature */ +#define CO_EMC_TEMP_AMBIENT 0x4100U /**< 0x41xx Ambient Temperature */ +#define CO_EMC_TEMP_DEVICE 0x4200U /**< 0x42xx Device Temperature */ +#define CO_EMC_HARDWARE 0x5000U /**< 0x50xx Device Hardware */ +#define CO_EMC_SOFTWARE_DEVICE 0x6000U /**< 0x60xx Device Software */ +#define CO_EMC_SOFTWARE_INTERNAL 0x6100U /**< 0x61xx Internal Software */ +#define CO_EMC_SOFTWARE_USER 0x6200U /**< 0x62xx User Software */ +#define CO_EMC_DATA_SET 0x6300U /**< 0x63xx Data Set */ +#define CO_EMC_ADDITIONAL_MODUL 0x7000U /**< 0x70xx Additional Modules */ +#define CO_EMC_MONITORING 0x8000U /**< 0x80xx Monitoring */ +#define CO_EMC_COMMUNICATION 0x8100U /**< 0x81xx Communication */ +#define CO_EMC_CAN_OVERRUN 0x8110U /**< 0x8110 CAN Overrun (Objects lost) */ +#define CO_EMC_CAN_PASSIVE 0x8120U /**< 0x8120 CAN in Error Passive Mode */ +#define CO_EMC_HEARTBEAT 0x8130U /**< 0x8130 Life Guard Error or Heartbeat Error */ +#define CO_EMC_BUS_OFF_RECOVERED 0x8140U /**< 0x8140 recovered from bus off */ +#define CO_EMC_CAN_ID_COLLISION 0x8150U /**< 0x8150 CAN-ID collision */ +#define CO_EMC_PROTOCOL_ERROR 0x8200U /**< 0x82xx Protocol Error */ +#define CO_EMC_PDO_LENGTH 0x8210U /**< 0x8210 PDO not processed due to length error */ +#define CO_EMC_PDO_LENGTH_EXC 0x8220U /**< 0x8220 PDO length exceeded */ +#define CO_EMC_DAM_MPDO 0x8230U /**< 0x8230 DAM MPDO not processed destination object not available */ +#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /**< 0x8240 Unexpected SYNC data length */ +#define CO_EMC_RPDO_TIMEOUT 0x8250U /**< 0x8250 RPDO timeout */ +#define CO_EMC_EXTERNAL_ERROR 0x9000U /**< 0x90xx External Error */ +#define CO_EMC_ADDITIONAL_FUNC 0xF000U /**< 0xF0xx Additional Functions */ +#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /**< 0xFFxx Device specific */ + +#define CO_EMC401_OUT_CUR_HI 0x2310U /**< 0x2310 DS401 Current at outputs too high (overload) */ +#define CO_EMC401_OUT_SHORTED 0x2320U /**< 0x2320 DS401 Short circuit at outputs */ +#define CO_EMC401_OUT_LOAD_DUMP 0x2330U /**< 0x2330 DS401 Load dump at outputs */ +#define CO_EMC401_IN_VOLT_HI 0x3110U /**< 0x3110 DS401 Input voltage too high */ +#define CO_EMC401_IN_VOLT_LOW 0x3120U /**< 0x3120 DS401 Input voltage too low */ +#define CO_EMC401_INTERN_VOLT_HI 0x3210U /**< 0x3210 DS401 Internal voltage too high */ +#define CO_EMC401_INTERN_VOLT_LO 0x3220U /**< 0x3220 DS401 Internal voltage too low */ +#define CO_EMC401_OUT_VOLT_HIGH 0x3310U /**< 0x3310 DS401 Output voltage too high */ +#define CO_EMC401_OUT_VOLT_LOW 0x3320U /**< 0x3320 DS401 Output voltage too low */ /** @} */ /* CO_EM_errorCode_t */ @@ -198,57 +198,57 @@ extern "C" { * uses first 6 bytes. Additional 4 bytes are pre-defined for manufacturer * or device specific error indications, by default. */ -#define CO_EM_NO_ERROR 0x00U /** 0x00 Error Reset or No Error */ -#define CO_EM_CAN_BUS_WARNING 0x01U /** 0x01 communication info CAN bus warning limit reached */ -#define CO_EM_RXMSG_WRONG_LENGTH 0x02U /** 0x02 communication info Wrong data length of the received CAN message */ -#define CO_EM_RXMSG_OVERFLOW 0x03U /** 0x03 communication info Previous received CAN message wasn't processed yet */ -#define CO_EM_RPDO_WRONG_LENGTH 0x04U /** 0x04 communication info Wrong data length of received PDO */ -#define CO_EM_RPDO_OVERFLOW 0x05U /** 0x05 communication info Previous received PDO wasn't processed yet */ -#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /** 0x06 communication info CAN receive bus is passive */ -#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /** 0x07 communication info CAN transmit bus is passive */ -#define CO_EM_NMT_WRONG_COMMAND 0x08U /** 0x08 communication info Wrong NMT command received */ -#define CO_EM_TIME_TIMEOUT 0x09U /** 0x09 communication info TIME message timeout */ -#define CO_EM_0A_unused 0x0AU /** 0x0A communication info (unused) */ -#define CO_EM_0B_unused 0x0BU /** 0x0B communication info (unused) */ -#define CO_EM_0C_unused 0x0CU /** 0x0C communication info (unused) */ -#define CO_EM_0D_unused 0x0DU /** 0x0D communication info (unused) */ -#define CO_EM_0E_unused 0x0EU /** 0x0E communication info (unused) */ -#define CO_EM_0F_unused 0x0FU /** 0x0F communication info (unused) */ - -#define CO_EM_10_unused 0x10U /** 0x10 communication critical (unused) */ -#define CO_EM_11_unused 0x11U /** 0x11 communication critical (unused) */ -#define CO_EM_CAN_TX_BUS_OFF 0x12U /** 0x12 communication critical CAN transmit bus is off */ -#define CO_EM_CAN_RXB_OVERFLOW 0x13U /** 0x13 communication critical CAN module receive buffer has overflowed */ -#define CO_EM_CAN_TX_OVERFLOW 0x14U /** 0x14 communication critical CAN transmit buffer has overflowed */ -#define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /** 0x15 communication critical TPDO is outside SYNC window */ -#define CO_EM_16_unused 0x16U /** 0x16 communication critical (unused) */ -#define CO_EM_RPDO_TIME_OUT 0x17U /** 0x17 communication critical RPDO message timeout */ -#define CO_EM_SYNC_TIME_OUT 0x18U /** 0x18 communication critical SYNC message timeout */ -#define CO_EM_SYNC_LENGTH 0x19U /** 0x19 communication critical Unexpected SYNC data length */ -#define CO_EM_PDO_WRONG_MAPPING 0x1AU /** 0x1A communication critical Error with PDO mapping */ -#define CO_EM_HEARTBEAT_CONSUMER 0x1BU /** 0x1B communication critical Heartbeat consumer timeout */ -#define CO_EM_HB_CONSUMER_REMOTE_RESET 0x1CU /** 0x1C communication critical Heartbeat consumer detected remote node reset */ -#define CO_EM_SRDO_CONFIGURATION 0x1DU /** 0x1D communication critical Error in SRDO configuration parameters. */ -#define CO_EM_1E_unused 0x1EU /** 0x1E communication critical (unused) */ -#define CO_EM_1F_unused 0x1FU /** 0x1F communication critical (unused) */ - -#define CO_EM_EMERGENCY_BUFFER_FULL 0x20U /** 0x20 generic info Emergency buffer is full Emergency message wasn't sent */ -#define CO_EM_21_unused 0x21U /** 0x21 generic info (unused) */ -#define CO_EM_MICROCONTROLLER_RESET 0x22U /** 0x22 generic info Microcontroller has just started */ -#define CO_EM_23_unused 0x23U /** 0x23 generic info (unused) */ -#define CO_EM_24_unused 0x24U /** 0x24 generic info (unused) */ -#define CO_EM_25_unused 0x25U /** 0x25 generic info (unused) */ -#define CO_EM_26_unused 0x26U /** 0x26 generic info (unused) */ -#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /** 0x27 generic info Automatic store to non-volatile memory failed */ - -#define CO_EM_WRONG_ERROR_REPORT 0x28U /** 0x28 generic critical Wrong parameters to CO_errorReport() function*/ -#define CO_EM_ISR_TIMER_OVERFLOW 0x29U /** 0x29 generic critical Timer task has overflowed */ -#define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /** 0x2A generic critical Unable to allocate memory for objects */ -#define CO_EM_GENERIC_ERROR 0x2BU /** 0x2B generic critical Generic error test usage */ -#define CO_EM_GENERIC_SOFTWARE_ERROR 0x2CU /** 0x2C generic critical Software error */ -#define CO_EM_INCONSISTENT_OBJECT_DICT 0x2DU /** 0x2D generic critical Object dictionary does not match the software*/ -#define CO_EM_CALCULATION_OF_PARAMETERS 0x2EU /** 0x2E generic critical Error in calculation of device parameters */ -#define CO_EM_NON_VOLATILE_MEMORY 0x2FU /** 0x2F generic critical Error with access to non volatile device memory */ +#define CO_EM_NO_ERROR 0x00U /**< 0x00 Error Reset or No Error */ +#define CO_EM_CAN_BUS_WARNING 0x01U /**< 0x01 communication info CAN bus warning limit reached */ +#define CO_EM_RXMSG_WRONG_LENGTH 0x02U /**< 0x02 communication info Wrong data length of the received CAN message */ +#define CO_EM_RXMSG_OVERFLOW 0x03U /**< 0x03 communication info Previous received CAN message wasn't processed yet */ +#define CO_EM_RPDO_WRONG_LENGTH 0x04U /**< 0x04 communication info Wrong data length of received PDO */ +#define CO_EM_RPDO_OVERFLOW 0x05U /**< 0x05 communication info Previous received PDO wasn't processed yet */ +#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /**< 0x06 communication info CAN receive bus is passive */ +#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /**< 0x07 communication info CAN transmit bus is passive */ +#define CO_EM_NMT_WRONG_COMMAND 0x08U /**< 0x08 communication info Wrong NMT command received */ +#define CO_EM_TIME_TIMEOUT 0x09U /**< 0x09 communication info TIME message timeout */ +#define CO_EM_0A_unused 0x0AU /**< 0x0A communication info (unused) */ +#define CO_EM_0B_unused 0x0BU /**< 0x0B communication info (unused) */ +#define CO_EM_0C_unused 0x0CU /**< 0x0C communication info (unused) */ +#define CO_EM_0D_unused 0x0DU /**< 0x0D communication info (unused) */ +#define CO_EM_0E_unused 0x0EU /**< 0x0E communication info (unused) */ +#define CO_EM_0F_unused 0x0FU /**< 0x0F communication info (unused) */ + +#define CO_EM_10_unused 0x10U /**< 0x10 communication critical (unused) */ +#define CO_EM_11_unused 0x11U /**< 0x11 communication critical (unused) */ +#define CO_EM_CAN_TX_BUS_OFF 0x12U /**< 0x12 communication critical CAN transmit bus is off */ +#define CO_EM_CAN_RXB_OVERFLOW 0x13U /**< 0x13 communication critical CAN module receive buffer has overflowed */ +#define CO_EM_CAN_TX_OVERFLOW 0x14U /**< 0x14 communication critical CAN transmit buffer has overflowed */ +#define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /**< 0x15 communication critical TPDO is outside SYNC window */ +#define CO_EM_16_unused 0x16U /**< 0x16 communication critical (unused) */ +#define CO_EM_RPDO_TIME_OUT 0x17U /**< 0x17 communication critical RPDO message timeout */ +#define CO_EM_SYNC_TIME_OUT 0x18U /**< 0x18 communication critical SYNC message timeout */ +#define CO_EM_SYNC_LENGTH 0x19U /**< 0x19 communication critical Unexpected SYNC data length */ +#define CO_EM_PDO_WRONG_MAPPING 0x1AU /**< 0x1A communication critical Error with PDO mapping */ +#define CO_EM_HEARTBEAT_CONSUMER 0x1BU /**< 0x1B communication critical Heartbeat consumer timeout */ +#define CO_EM_HB_CONSUMER_REMOTE_RESET 0x1CU /**< 0x1C communication critical Heartbeat consumer detected remote node reset */ +#define CO_EM_SRDO_CONFIGURATION 0x1DU /**< 0x1D communication critical Error in SRDO configuration parameters. */ +#define CO_EM_1E_unused 0x1EU /**< 0x1E communication critical (unused) */ +#define CO_EM_1F_unused 0x1FU /**< 0x1F communication critical (unused) */ + +#define CO_EM_EMERGENCY_BUFFER_FULL 0x20U /**< 0x20 generic info Emergency buffer is full Emergency message wasn't sent */ +#define CO_EM_21_unused 0x21U /**< 0x21 generic info (unused) */ +#define CO_EM_MICROCONTROLLER_RESET 0x22U /**< 0x22 generic info Microcontroller has just started */ +#define CO_EM_23_unused 0x23U /**< 0x23 generic info (unused) */ +#define CO_EM_24_unused 0x24U /**< 0x24 generic info (unused) */ +#define CO_EM_25_unused 0x25U /**< 0x25 generic info (unused) */ +#define CO_EM_26_unused 0x26U /**< 0x26 generic info (unused) */ +#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /**< 0x27 generic info Automatic store to non-volatile memory failed */ + +#define CO_EM_WRONG_ERROR_REPORT 0x28U /**< 0x28 generic critical Wrong parameters to CO_errorReport() function*/ +#define CO_EM_ISR_TIMER_OVERFLOW 0x29U /**< 0x29 generic critical Timer task has overflowed */ +#define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /**< 0x2A generic critical Unable to allocate memory for objects */ +#define CO_EM_GENERIC_ERROR 0x2BU /**< 0x2B generic critical Generic error test usage */ +#define CO_EM_GENERIC_SOFTWARE_ERROR 0x2CU /**< 0x2C generic critical Software error */ +#define CO_EM_INCONSISTENT_OBJECT_DICT 0x2DU /**< 0x2D generic critical Object dictionary does not match the software*/ +#define CO_EM_CALCULATION_OF_PARAMETERS 0x2EU /**< 0x2E generic critical Error in calculation of device parameters */ +#define CO_EM_NON_VOLATILE_MEMORY 0x2FU /**< 0x2F generic critical Error with access to non volatile device memory */ /** 0x30+ manufacturer info or critical Error status buts free to use by * manufacturer. By default bits 0x30..0x3F are set as informational and From 7850623700fe17114a7fe3b773e0b4f4faed079e Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 26 Jun 2024 12:40:17 +0200 Subject: [PATCH 389/520] Update CO_PDO.c: make eventTime, inhibitTime and syncStartValue optional in object dictionary. --- 301/CO_PDO.c | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 35ad3a6c..7e34ebab 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -740,13 +740,7 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, /* Configure communication parameter - event-timer (optional) */ #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 uint16_t eventTime = 0; - odRet = OD_get_u16(OD_14xx_RPDOCommPar, 5, &eventTime, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_14xx_RPDOCommPar)) << 8) | 5U; - } - return CO_ERROR_OD_PARAMETERS; - } + (void)OD_get_u16(OD_14xx_RPDOCommPar, 5, &eventTime, true); RPDO->timeoutTime_us = (uint32_t)eventTime * 1000U; #endif @@ -1200,20 +1194,8 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 uint16_t inhibitTime = 0; uint16_t eventTime = 0; - odRet = OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 3U; - } - return CO_ERROR_OD_PARAMETERS; - } - odRet = OD_get_u16(OD_18xx_TPDOCommPar, 5, &eventTime, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 5U; - } - return CO_ERROR_OD_PARAMETERS; - } + (void)OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); + (void)OD_get_u16(OD_18xx_TPDOCommPar, 5, &eventTime, true); TPDO->inhibitTime_us = (uint32_t)inhibitTime * 100U; TPDO->eventTime_us = (uint32_t)eventTime * 1000U; #endif @@ -1222,13 +1204,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, /* Configure communication parameter - SYNC start value (optional) */ #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncStartValue = 0; - odRet = OD_get_u8(OD_18xx_TPDOCommPar, 6, &TPDO->syncStartValue, true); - if (odRet != ODR_OK) { - if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_18xx_TPDOCommPar)) << 8) | 6U; - } - return CO_ERROR_OD_PARAMETERS; - } + (void)OD_get_u8(OD_18xx_TPDOCommPar, 6, &TPDO->syncStartValue, true); TPDO->SYNC = SYNC; TPDO->syncCounter = 255; #endif From c46bb96292c9ada7b0e940adc1ebd4164e13e96f Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 12:14:51 +0200 Subject: [PATCH 390/520] CO_fifo: static analysis: side effects on right hand of logical operator, '&&' [MISRA 2012 Rule 13.5, required] (cherry picked from commit bd20c9d7dcf935bc81fb70d0a82df14f9c4442d5) --- 301/CO_fifo.c | 84 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index bb476698..76c15c6b 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -490,7 +490,11 @@ static const uint8_t base64DecTable[] = { size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; - if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { (void)CO_fifo_read(fifo, &n, sizeof(n), NULL); return sprintf(buf, "%"PRIu8, n); } @@ -502,7 +506,11 @@ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; - if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); } @@ -514,7 +522,11 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; - if ((fifo != NULL) && (count >= 12U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 12U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); } @@ -526,7 +538,11 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; - if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); } @@ -538,7 +554,11 @@ size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t n=0; - if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%02"PRIX8, n); } @@ -550,7 +570,11 @@ size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint16_t n=0; - if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); } @@ -562,7 +586,11 @@ size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint32_t n=0; - if ((fifo != NULL) && (count >= 12U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 12U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); } @@ -574,7 +602,11 @@ size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint64_t n=0; - if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); } @@ -586,7 +618,11 @@ size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int8_t n=0; - if ((fifo != NULL) && (count >= 6U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId8, n); } @@ -598,7 +634,11 @@ size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int16_t n=0; - if ((fifo != NULL) && (count >= 8U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId16, CO_SWAP_16(n)); } @@ -610,7 +650,11 @@ size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int32_t n=0; - if ((fifo != NULL) && (count >= 13U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 13U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId32, CO_SWAP_32(n)); } @@ -622,7 +666,11 @@ size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { int64_t n=0; - if ((fifo != NULL) && (count >= 23U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 23U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%"PRId64, CO_SWAP_64(n)); } @@ -634,7 +682,11 @@ size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float32_t n=0; - if ((fifo != NULL) && (count >= 20U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", (double)CO_SWAP_32(n)); } @@ -646,7 +698,11 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { float64_t n=0; - if ((fifo != NULL) && (count >= 30U) && (CO_fifo_getOccupied(fifo) == sizeof(n))) { + if(fifo == NULL) { + return 0; + } + + if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 30U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); return sprintf(buf, "%g", (double)CO_SWAP_64(n)); } From 376d86a5a435c6422c953a16aa63d746b1e16226 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 12:18:04 +0200 Subject: [PATCH 391/520] CO_fifo: static analysis: side effects on right hand of logical operator, '||' [MISRA 2012 Rule 13.5, required] (cherry picked from commit ea89548ebae934dc3acbcfd6fea15107389f8fd7) --- 301/CO_fifo.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 76c15c6b..91d687bb 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -1181,7 +1181,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { if (step == 6U) { /* command is inside comment, waiting for command delimiter */ bool_t insideComment = true; - if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; } @@ -1227,7 +1227,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { step = 0; } bool_t insideComment = false; - if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { + if (CO_fifo_trimSpaces(src, &insideComment) ||(c == DELIM_COMMAND)) { /* newline found, finish */ st |= CO_fifo_st_closed; finished = true; @@ -1312,9 +1312,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else if ((isgraph((int)c) == 0) && (step == 2U)) { /* end of single word string */ bool_t insideComment = false; - if ((c == DELIM_COMMAND) - || CO_fifo_trimSpaces(src, &insideComment) - ) { + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; } @@ -1351,9 +1349,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { if (isgraph((int)c) == 0) { /* end of quoted string */ bool_t insideComment = false; - if ((c == DELIM_COMMAND) - || CO_fifo_trimSpaces(src, &insideComment) - ) { + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; } @@ -1371,7 +1367,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { case 5: { /* String token is finished, waiting for command delimiter */ bool_t insideComment = false; - if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; } @@ -1390,7 +1386,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } case 6: { /* String token is finished, waiting for command delimiter */ bool_t insideComment = true; - if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; } @@ -1459,7 +1455,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { if (step >= 5U) { /* String token is finished, waiting for command delimiter */ bool_t insideComment = step > 5U; - if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; } @@ -1500,7 +1496,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } bool_t insideComment = false; - if ((c == DELIM_COMMAND) || CO_fifo_trimSpaces(src, &insideComment)) { + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; } From f6535def56216dfa0836a20b2b23ce37864e9316 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 13:11:21 +0200 Subject: [PATCH 392/520] CO_fifo: static analysis: increment/decrement operation combined with other operation with side-effects [MISRA 2012 Rule 13.3, advisory] --- 301/CO_fifo.c | 51 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 91d687bb..ce7352b2 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -147,7 +147,8 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { break; } - *(buf++) = c; + *buf = c; + buf++; /* increment variables */ if (++fifo->readPtr == fifo->bufSize) { @@ -237,7 +238,8 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count) { break; } - *(buf++) = c; + *buf = c; + buf++; /* increment variables */ if (++fifo->altReadPtr == fifo->bufSize) { @@ -362,7 +364,8 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, if (*c == DELIM_COMMENT) { delimCommentFound = true; } else { - buf[tokenSize++] = (char)*c; + buf[tokenSize] = (char)*c; + tokenSize++; step++; } } @@ -375,7 +378,8 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, if (*c == DELIM_COMMENT) { delimCommentFound = true; } else if (tokenSize < count) { - buf[tokenSize++] = (char)*c; + buf[tokenSize] = (char)*c; + tokenSize++; } } else { @@ -744,7 +748,8 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((fifo != NULL) && (count > 3U)) { /* Start with '"' */ if (!fifo->started) { - buf[len++] = '"'; + buf[len] = '"'; + len++; fifo->started = true; } @@ -752,15 +757,18 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { uint8_t c; if(!CO_fifo_getc(fifo, &c)) { if (end) { - buf[len++] = '"'; + buf[len] = '"'; + len++; } break; } else if ((c != 0U) && (c != (uint8_t)'\r')) { /* skip null and CR inside string */ - buf[len++] = (char)c; + buf[len] = (char)c; + len++; if (c == DELIM_DQUOTE) { - buf[len++] = '"'; + buf[len] = '"'; + len++; } } } @@ -798,13 +806,18 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { /* add padding if necessary */ switch (step) { case 1: - buf[len++] = base64EncTable[(word >> 4) & 0x3FU]; - buf[len++] = '='; - buf[len++] = '='; + buf[len] = base64EncTable[(word >> 4) & 0x3FU]; + len++; + buf[len] = '='; + len++; + buf[len] = '='; + len++; break; case 2: - buf[len++] = base64EncTable[(word >> 6) & 0x3FU]; - buf[len++] = '='; + buf[len] = base64EncTable[(word >> 6) & 0x3FU]; + len++; + buf[len] = '='; + len++; break; default: /* MISRA C 2004 15.3 */ @@ -818,14 +831,18 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { switch (step++) { case 0: - buf[len++] = base64EncTable[(word >> 2) & 0x3FU]; + buf[len] = base64EncTable[(word >> 2) & 0x3FU]; + len++; break; case 1: - buf[len++] = base64EncTable[(word >> 4) & 0x3FU]; + buf[len] = base64EncTable[(word >> 4) & 0x3FU]; + len++; break; default: - buf[len++] = base64EncTable[(word >> 6) & 0x3FU]; - buf[len++] = base64EncTable[word & 0x3FU]; + buf[len] = base64EncTable[(word >> 6) & 0x3FU]; + len++; + buf[len] = base64EncTable[word & 0x3FU]; + len++; step = 0; break; } From a5004f46495c7f60236e58116b845c93ea410755 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 13:14:11 +0200 Subject: [PATCH 393/520] CO_fifo: static analysis: result of assignment operator used in right operand to '=' operator [MISRA 2012 Rule 13.4, advisory] --- 301/CO_fifo.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index ce7352b2..d0a9af31 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -1168,7 +1168,8 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } /* get free space of the dest fifo */ - destSpaceStart = destSpace = CO_fifo_getSpace(dest); + destSpaceStart = CO_fifo_getSpace(dest); + destSpace = destSpaceStart; /* is this the first write into dest? */ if (!dest->started) { @@ -1279,7 +1280,8 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } /* get free space of the dest fifo */ - destSpaceStart = destSpace = CO_fifo_getSpace(dest); + destSpaceStart = CO_fifo_getSpace(dest); + destSpace = destSpaceStart; /* is this the first write into dest? */ if (!dest->started) { @@ -1442,7 +1444,8 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } /* get free space of the dest fifo */ - destSpaceStart = destSpace = CO_fifo_getSpace(dest); + destSpaceStart = CO_fifo_getSpace(dest); + destSpace = destSpaceStart; /* is this the first write into dest? */ if (!dest->started) { From 8c36f03fc6549a14513bd8d4d11f947c3511d87d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 13:35:26 +0200 Subject: [PATCH 394/520] CO_fifo: static analysis: cannot assign value to different essential type [MISRA 2012 Rule 10.3, required] --- 301/CO_fifo.c | 88 +++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index d0a9af31..c1a00857 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -264,7 +264,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { uint8_t *commandEnd; if ((fifo == NULL) || (fifo->readPtr == fifo->writePtr)) { - return 0; + return false; } /* search delimiter until writePtr or until end of buffer */ @@ -500,7 +500,7 @@ size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { (void)CO_fifo_read(fifo, &n, sizeof(n), NULL); - return sprintf(buf, "%"PRIu8, n); + return (size_t)sprintf(buf, "%"PRIu8, n); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -516,7 +516,7 @@ size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); + return (size_t)sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -532,7 +532,7 @@ size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 12U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); + return (size_t)sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -548,7 +548,7 @@ size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); + return (size_t)sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -564,7 +564,7 @@ size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "0x%02"PRIX8, n); + return (size_t)sprintf(buf, "0x%02"PRIX8, n); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -580,7 +580,7 @@ size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); + return (size_t)sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -596,7 +596,7 @@ size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 12U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); + return (size_t)sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -612,7 +612,7 @@ size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); + return (size_t)sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -628,7 +628,7 @@ size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%"PRId8, n); + return (size_t)sprintf(buf, "%"PRId8, n); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -644,7 +644,7 @@ size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%"PRId16, CO_SWAP_16(n)); + return (size_t)sprintf(buf, "%"PRId16, CO_SWAP_16(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -660,7 +660,7 @@ size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 13U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%"PRId32, CO_SWAP_32(n)); + return (size_t)sprintf(buf, "%"PRId32, CO_SWAP_32(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -676,7 +676,7 @@ size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 23U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%"PRId64, CO_SWAP_64(n)); + return (size_t)sprintf(buf, "%"PRId64, CO_SWAP_64(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -684,7 +684,7 @@ size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - float32_t n=0; + float32_t n=(float32_t)0; if(fifo == NULL) { return 0; @@ -692,7 +692,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%g", (double)CO_SWAP_32(n)); + return (size_t)sprintf(buf, "%g", (double)CO_SWAP_32(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -700,7 +700,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - float64_t n=0; + float64_t n=(float64_t)0; if(fifo == NULL) { return 0; @@ -708,7 +708,7 @@ size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 30U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return sprintf(buf, "%g", (double)CO_SWAP_64(n)); + return (size_t)sprintf(buf, "%g", (double)CO_SWAP_64(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -725,7 +725,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if (!fifo->started) { uint8_t c; if(CO_fifo_getc(fifo, &c)) { - len = sprintf(&buf[0], "%02"PRIX8, c); + len = (size_t)sprintf(&buf[0], "%02"PRIX8, c); fifo->started = true; } } @@ -735,7 +735,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if(!CO_fifo_getc(fifo, &c)) { break; } - len += sprintf(&buf[len], " %02"PRIX8, c); + len += (size_t)sprintf(&buf[len], " %02"PRIX8, c); } } @@ -861,7 +861,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -871,7 +871,7 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if ((sRet != strchr(buf, '\0')) || (u32 > (uint32_t)UINT8_MAX)) { + if ((sRet != strchr(buf, (int)('\0'))) || (u32 > (uint32_t)UINT8_MAX)) { st |= CO_fifo_st_errVal; } else { @@ -891,7 +891,7 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -901,7 +901,7 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if ((sRet != strchr(buf, '\0')) || (u32 > (uint32_t)UINT16_MAX)) { + if ((sRet != strchr(buf, (int)('\0'))) || (u32 > (uint32_t)UINT16_MAX)) { st |= CO_fifo_st_errVal; } else { @@ -921,7 +921,7 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -931,7 +931,7 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) { + if (sRet != strchr(buf, (int)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -951,7 +951,7 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[25]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -961,7 +961,7 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; uint64_t u64 = strtoull(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) { + if (sRet != strchr(buf, (int)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -981,7 +981,7 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -991,7 +991,7 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if ((sRet != strchr(buf, '\0')) || (i32 < INT8_MIN) || (i32 > INT8_MAX)) { + if ((sRet != strchr(buf, (int)('\0'))) || (i32 < INT8_MIN) || (i32 > INT8_MAX)) { st |= CO_fifo_st_errVal; } else { int8_t num = (int8_t) i32; @@ -1010,7 +1010,7 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -1020,7 +1020,7 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if ((sRet != strchr(buf, '\0')) || (i32 < INT16_MIN) || (i32 > INT16_MAX)) { + if ((sRet != strchr(buf, (int)('\0'))) || (i32 < INT16_MIN) || (i32 > INT16_MAX)) { st |= CO_fifo_st_errVal; } else { int16_t num = CO_SWAP_16((int16_t) i32); @@ -1039,7 +1039,7 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -1049,7 +1049,7 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) { + if (sRet != strchr(buf, (int)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1069,7 +1069,7 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[25]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -1079,7 +1079,7 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; int64_t i64 = strtoll(buf, &sRet, 0); - if (sRet != strchr(buf, '\0')) { + if (sRet != strchr(buf, (int)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1099,7 +1099,7 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[30]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -1109,7 +1109,7 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; float32_t f32 = strtof(buf, &sRet); - if (sRet != strchr(buf, '\0')) { + if (sRet != strchr(buf, (int)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1129,7 +1129,7 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[40]; uint8_t closed = 0xFFU; - bool_t err = 0; + bool_t err = false; size_t nWr = 0; size_t nRd = CO_fifo_readToken(src, buf, sizeof(buf), &closed, &err); uint8_t st = closed; @@ -1139,7 +1139,7 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; float64_t f64 = strtof(buf, &sRet); - if (sRet != strchr(buf, '\0')) { + if (sRet != strchr(buf, (int)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1206,7 +1206,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { continue; } - if (isxdigit((int)c) != 0) { + if ((int)(isxdigit((int)c)) != (int)(0)) { /* first or second hex digit */ if (step == 0U) { firstChar = c; @@ -1223,7 +1223,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { step = 0; } } - else if (isgraph((int)c) != 0) { + else if ((int)(isgraph((int)c)) != (int)(0)) { /* printable character, not hex digit */ if (c == DELIM_COMMENT) { /* comment start */ step = 6; @@ -1336,7 +1336,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { finished = true; } else { - step = insideComment ? 6 : 5; + step = insideComment ? 6U : 5U; } } else if (c == DELIM_COMMAND) { @@ -1373,7 +1373,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { finished = true; } else { - step = insideComment ? 6 : 5; + step = insideComment ? 6U : 5U; } } else { @@ -1521,7 +1521,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { finished = true; } else { - step = insideComment ? 6 : 5; + step = insideComment ? 6U : 5U; } } else { From 36f7481778ffa6561a4ba8da5df36a752a362f64 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 13:38:38 +0200 Subject: [PATCH 395/520] CO_fifo: static analysis: no 'else' at end of 'if ... else if' chain [MISRA 2012 Rule 15.7, required] --- 301/CO_fifo.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index c1a00857..ea6eb8bc 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -293,6 +293,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { /* buffer full */ newCommand = true; } + else { /* MISRA C 2004 14.10 */ } /* Clear buffer if set so */ if (clear) { @@ -325,6 +326,8 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { else if ((isgraph((int)c) != 0) && !(*insideComment)) { break; } + else { /* MISRA C 2004 14.10 */ } + if (++fifo->readPtr == fifo->bufSize) { fifo->readPtr = 0; } @@ -372,6 +375,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, else if (*c == DELIM_COMMAND) { delimCommandFound = true; } + else { /* MISRA C 2004 14.10 */ } break; case 1: /* search for end of the token */ if (isgraph((int)*c) != 0) { @@ -381,6 +385,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, buf[tokenSize] = (char)*c; tokenSize++; } + else { /* MISRA C 2004 14.10 */ } } else { if (*c == DELIM_COMMAND) { @@ -401,6 +406,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, else if (*c == DELIM_COMMAND) { delimCommandFound = true; } + else { /* MISRA C 2004 14.10 */ } break; default: /* MISRA C 2004 15.3 */ @@ -440,6 +446,7 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, finished = true; } } + else { /* MISRA C 2004 14.10 */ } } while (!finished); } @@ -771,6 +778,7 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { len++; } } + else { /* MISRA C 2004 14.10 */ } } } @@ -1253,6 +1261,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else if (insideComment) { step = 6; } + else { /* MISRA C 2004 14.10 */ } } } /* while ... */ @@ -1401,6 +1410,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { st |= CO_fifo_st_errTok; } } + else { /* MISRA C 2004 14.10 */ } break; } case 6: { /* String token is finished, waiting for command delimiter */ @@ -1490,6 +1500,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { st |= CO_fifo_st_errTok; } } + else { /* MISRA C 2004 14.10 */ } continue; } From 5749014c168d1b0b6e683ac0b45e399ebc185e67 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 15:36:31 +0200 Subject: [PATCH 396/520] CO_fifo: static analysis: pointer subtraction [MISRA 2012 Rule 18.2, required] --- 301/CO_fifo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index ea6eb8bc..a4f70912 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -298,7 +298,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { /* Clear buffer if set so */ if (clear) { if (commandEnd != NULL) { - fifo->readPtr = (size_t)(commandEnd - fifo->buf) + 1U; + fifo->readPtr = ((size_t)commandEnd - (size_t)fifo->buf) + 1U; if (fifo->readPtr == fifo->bufSize) { fifo->readPtr = 0; } From 4a8c750cbfcde08d409ed6f08ef1c5032d37c1b9 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 15:38:36 +0200 Subject: [PATCH 397/520] CO_fifo: static analysis: repeated include file 'string.h' --- 301/CO_fifo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index a4f70912..770ecf7f 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -23,11 +23,12 @@ * limitations under the License. */ +#include + #include "301/CO_fifo.h" #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) != 0 -#include #include #include #include "crc16-ccitt.h" From 40917a870e2f15d8165c28abc08eb911dec3ee0e Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:06:09 +0200 Subject: [PATCH 398/520] CO_SDOclient: static analysis: no 'else' at end of 'if ... else if' chain [MISRA 2012 Rule 15.7, required] --- 301/CO_SDOclient.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 88355d19..865920be 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -137,15 +137,16 @@ static void CO_SDOclient_receive(void *object, void *msg) { CO_DEBUG_SDO_CLIENT(msg); #endif } -#ifdef CO_DEBUG_SDO_CLIENT else { + /* MISRA C 2004 14.10 */ +#ifdef CO_DEBUG_SDO_CLIENT char msg[80]; sprintf(msg, "sub-block, rx ignored: sequno=%02X, expected=%02X", seqno, SDO_C->block_seqno + 1); CO_DEBUG_SDO_CLIENT(msg); - } #endif + } /* Is exit from sub-block receive state? */ if (state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { @@ -162,6 +163,8 @@ static void CO_SDOclient_receive(void *object, void *msg) { #endif } } + else { /* MISRA C 2004 14.10 */ } + #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ } } @@ -556,6 +559,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; } + else { /* MISRA C 2004 14.10 */ } } /* write data, in several passes if necessary */ if (SDO_C->OD_IO.write != NULL) { @@ -618,7 +622,10 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; } + else { /* MISRA C 2004 14.10 */ } } + else { /* MISRA C 2004 14.10 */ } + if (abortCode == CO_SDO_AB_NONE) { OD_size_t countWritten = 0; @@ -666,6 +673,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else if (timerNext_us != NULL) { *timerNext_us = 0; } + else { /* MISRA C 2004 14.10 */ } #endif } #endif /* CO_CONFIG_SDO_CLI_LOCAL */ @@ -803,6 +811,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_ABORT; break; } + else { /* MISRA C 2004 14.10 */ } /* confirm successfully transmitted data */ CO_fifo_altFinish(&SDO_C->bufFifo, &SDO_C->block_crc); @@ -852,6 +861,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; } + else { /* MISRA C 2004 14.10 */ } /* Timeout timers and transmit bufferFull flag ****************************/ if (ret == CO_SDO_RT_waitingResponse) { @@ -870,6 +880,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, *timerNext_us = diff; } } + else { /* MISRA C 2004 14.10 */ } #endif if (SDO_C->CANtxBuff->bufferFull) { ret = CO_SDO_RT_transmittBufferFull; @@ -1085,6 +1096,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { ret = CO_SDO_RT_blockDownldInProgress; } + else { /* MISRA C 2004 14.10 */ } #endif } @@ -1200,6 +1212,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; } + else { /* MISRA C 2004 14.10 */ } } size_t countFifo = CO_fifo_getSpace(&SDO_C->bufFifo); @@ -1270,6 +1283,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } } } + else { /* MISRA C 2004 14.10 */ } if ((ret != CO_SDO_RT_uploadDataBufferFull) && (ret != CO_SDO_RT_waitingLocalTransfer) @@ -1281,6 +1295,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, else if (timerNext_us != NULL) { *timerNext_us = 0; } + else { /* MISRA C 2004 14.10 */ } #endif } #endif /* CO_CONFIG_SDO_CLI_LOCAL */ @@ -1553,6 +1568,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; } + else { /* MISRA C 2004 14.10 */ } /* Timeout timers and transmit bufferFull flag ****************************/ if (ret == CO_SDO_RT_waitingResponse) { @@ -1578,6 +1594,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, *timerNext_us = diff; } } + else { /* MISRA C 2004 14.10 */ } #endif #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 @@ -1601,6 +1618,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, *timerNext_us = diff; } } + else { /* MISRA C 2004 14.10 */ } #endif } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ @@ -1665,6 +1683,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_ABORT; break; } + else { /* MISRA C 2004 14.10 */ } SDO_C->block_blksize = (uint8_t)count; SDO_C->CANtxBuff->data[4] = SDO_C->block_blksize; SDO_C->CANtxBuff->data[5] = CO_CONFIG_SDO_CLI_PST; @@ -1737,6 +1756,8 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, #endif break; } + else { /* MISRA C 2004 14.10 */ } + SDO_C->block_blksize = (uint8_t)count; SDO_C->block_seqno = 0; /* Block segments will be received in different thread. Make @@ -1796,6 +1817,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { ret = CO_SDO_RT_blockUploadInProgress; } + else { /* MISRA C 2004 14.10 */ } #endif } From 022e1e0d7508f6352dca77b239eaf761727a7a62 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:20:11 +0200 Subject: [PATCH 399/520] CO_SDOclient: static analysis: enum constant case not used within default switch --- 301/CO_SDOclient.c | 115 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 865920be..4fb59738 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -845,7 +845,34 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ - +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: +#endif +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: +#endif + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: default: { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; @@ -1071,7 +1098,34 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ - +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: +#endif +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: +#endif + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: default: { break; } @@ -1553,6 +1607,34 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: +#endif +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: +#endif + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: default: { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; @@ -1792,7 +1874,34 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ - +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: +#endif +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: +#endif + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: default: { break; } From 41e637cb4235619847d466c8a9211406ae525118 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:22:45 +0200 Subject: [PATCH 400/520] CO_SDOclient: static analysis: ignoring return value of function 'CO_SDOclient_setup' [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] --- 301/CO_SDOclient.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 4fb59738..649a2df6 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -114,7 +114,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { else { /* Copy data. There is always enough space in fifo buffer, * because block_blksize was calculated before */ - CO_fifo_write(&SDO_C->bufFifo, + (void)CO_fifo_write(&SDO_C->bufFifo, &data[1], 7, &SDO_C->block_crc); SDO_C->sizeTran += 7U; @@ -203,7 +203,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, ) { return ODR_INVALID_VALUE; } - CO_SDOclient_setup(SDO_C, + (void)CO_SDOclient_setup(SDO_C, COB_ID, SDO_C->COB_IDServerToClient, SDO_C->nodeIDOfTheSDOServer); @@ -223,7 +223,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, ) { return ODR_INVALID_VALUE; } - CO_SDOclient_setup(SDO_C, + (void)CO_SDOclient_setup(SDO_C, SDO_C->COB_IDClientToServer, COB_ID, SDO_C->nodeIDOfTheSDOServer); @@ -566,7 +566,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo); uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 2]; - CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); + (void)CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); SDO_C->sizeTran += count; /* error: no data */ @@ -780,7 +780,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if ((SDO_C->block_blksize < 1U) || (SDO_C->block_blksize > 127U)) SDO_C->block_blksize = 127; SDO_C->block_seqno = 0; - CO_fifo_altBegin(&SDO_C->bufFifo, 0); + (void)CO_fifo_altBegin(&SDO_C->bufFifo, 0); SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; } else { @@ -801,7 +801,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, - SDO_C->CANrxData[1]; cntFailed = (cntFailed * 7U) - SDO_C->block_noData; SDO_C->sizeTran -= cntFailed; - CO_fifo_altBegin(&SDO_C->bufFifo, + (void)CO_fifo_altBegin(&SDO_C->bufFifo, (size_t)SDO_C->CANrxData[1] * 7U); SDO_C->finished = false; } @@ -821,7 +821,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } else { SDO_C->block_blksize = SDO_C->CANrxData[2]; SDO_C->block_seqno = 0; - CO_fifo_altBegin(&SDO_C->bufFifo, 0); + (void)CO_fifo_altBegin(&SDO_C->bufFifo, 0); SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; } } @@ -949,7 +949,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* copy data */ - CO_fifo_read(&SDO_C->bufFifo, + (void)CO_fifo_read(&SDO_C->bufFifo, &SDO_C->CANtxBuff->data[4], count, NULL); SDO_C->sizeTran = count; SDO_C->finished = true; @@ -1312,7 +1312,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } } - CO_fifo_write(&SDO_C->bufFifo, buf, countRd, NULL); + (void)CO_fifo_write(&SDO_C->bufFifo, buf, countRd, NULL); SDO_C->sizeTran += countRd; /* verify if size of data uploaded is too large */ @@ -1391,7 +1391,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, count -= (SDO_C->CANrxData[0] >> 2) & 0x03U; } /* copy data, indicate size and finish */ - CO_fifo_write(&SDO_C->bufFifo, + (void)CO_fifo_write(&SDO_C->bufFifo, &SDO_C->CANrxData[4], count, NULL); SDO_C->sizeTran = count; @@ -1535,7 +1535,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, count -= (SDO_C->CANrxData[0] >> 2) & 0x03U; } /* copy data, indicate size and finish */ - CO_fifo_write(&SDO_C->bufFifo, + (void)CO_fifo_write(&SDO_C->bufFifo, &SDO_C->CANrxData[4], count, NULL); SDO_C->sizeTran = count; @@ -1570,7 +1570,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* Get number of data bytes in last segment, that do not * contain data. Then copy remaining data into fifo */ uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07U); - CO_fifo_write(&SDO_C->bufFifo, + (void)CO_fifo_write(&SDO_C->bufFifo, &SDO_C->block_dataUploadLast[0], 7U - noData, &SDO_C->block_crc); From 340ba3f84e88df567396e3ab9d6d2ae10d259729 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:25:01 +0200 Subject: [PATCH 401/520] CO_SDOclient: static analysis: departure from MISRA switch syntax: missing break or throw from switch-case [MISRA 2012 Rule 16.1, required] --- 301/CO_SDOclient.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 649a2df6..b8691bf3 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -189,6 +189,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, switch (stream->subIndex) { case 0: /* Highest sub-index supported */ return ODR_READONLY; + break; case 1: { /* COB-ID client -> server */ uint32_t COB_ID = CO_getUint32(buf); @@ -241,6 +242,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, default: return ODR_SUB_NOT_EXIST; + break; } /* write value to the original location in the Object Dictionary */ From d8811edba35b93926b8c24a2c1445705964e4281 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:27:08 +0200 Subject: [PATCH 402/520] CO_SDOclient: static analysis: increment/decrement operation combined with other operation with side-effects [MISRA 2012 Rule 13.3, advisory] --- 301/CO_SDOclient.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index b8691bf3..8a1e4f3c 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -606,10 +606,12 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0) && ((sizeInOd == 0U) || (SDO_C->sizeTran < sizeInOd)) ) { - buf[count++] = 0; + buf[count] = 0; + count++; SDO_C->sizeTran++; if ((sizeInOd == 0U) || (sizeInOd > SDO_C->sizeTran)) { - buf[count++] = 0; + buf[count] = 0; + count++; SDO_C->sizeTran++; } SDO_C->OD_IO.stream.dataLength = (OD_size_t)SDO_C->sizeTran; @@ -1043,7 +1045,8 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* wait until data are refilled */ break; } - SDO_C->CANtxBuff->data[0] = ++SDO_C->block_seqno; + SDO_C->block_seqno++; + SDO_C->CANtxBuff->data[0] = SDO_C->block_seqno; /* get up to 7 data bytes */ count = CO_fifo_altRead(&SDO_C->bufFifo, From be69c270c35f8fd787956cff52cd9659aeaa73e1 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:34:07 +0200 Subject: [PATCH 403/520] CO_SDOclient: static analysis: the name 'abort' is reserved to the compiler [MISRA 2012 Rule 21.2, required] --- 301/CO_SDOclient.c | 16 ++++++++-------- 301/CO_SDOclient.h | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 8a1e4f3c..932ee559 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -517,7 +517,7 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, /******************************************************************************/ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, - bool_t abort, + bool_t send_abort, bool_t bufferPartial, CO_SDO_abortCode_t *SDOabortCode, size_t *sizeTransferred, @@ -537,7 +537,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 /* Transfer data locally **************************************************/ - else if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) && !abort) { + else if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) && !send_abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.write == NULL) { ODR_t odRet; @@ -691,7 +691,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; } - else if (abort) { + else if (send_abort) { abortCode = (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; @@ -887,7 +887,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, timeDifference_us = 0; CO_FLAG_CLEAR(SDO_C->CANrxNew); } - else if (abort) { + else if (send_abort) { abortCode = (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; @@ -1227,7 +1227,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, /******************************************************************************/ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, - bool_t abort, + bool_t send_abort, CO_SDO_abortCode_t *SDOabortCode, size_t *sizeIndicated, size_t *sizeTransferred, @@ -1247,7 +1247,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) /* Transfer data locally **************************************************/ - else if ((SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) && !abort) { + else if ((SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) && !send_abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.read == NULL) { ODR_t odRet; @@ -1368,7 +1368,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; } - else if (abort) { + else if (send_abort) { abortCode = (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; @@ -1650,7 +1650,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, timeDifference_us = 0; CO_FLAG_CLEAR(SDO_C->CANrxNew); } - else if (abort) { + else if (send_abort) { abortCode = (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 8e56fed9..e2c44970 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -427,7 +427,7 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, * @param SDO_C This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. - * @param abort If true, SDO client will send abort message from SDOabortCode + * @param send_abort If true, SDO client will send abort message from SDOabortCode * and transmission will be aborted. * @param bufferPartial True indicates, not all data were copied to internal * buffer yet. Buffer will be refilled later with #CO_SDOclientDownloadBufWrite. @@ -443,7 +443,7 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, */ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, - bool_t abort, + bool_t send_abort, bool_t bufferPartial, CO_SDO_abortCode_t *SDOabortCode, size_t *sizeTransferred, @@ -488,7 +488,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, * @param SDO_C This object. * @param timeDifference_us Time difference from previous function call in * [microseconds]. - * @param abort If true, SDO client will send abort message from SDOabortCode + * @param send_abort If true, SDO client will send abort message from SDOabortCode * and reception will be aborted. * @param [out] SDOabortCode In case of error in communication, SDO abort code * contains reason of error. Ignored if NULL. @@ -504,7 +504,7 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, */ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, - bool_t abort, + bool_t send_abort, CO_SDO_abortCode_t *SDOabortCode, size_t *sizeIndicated, size_t *sizeTransferred, From 56466169cb54585866697207a322711de5ebad72 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:35:59 +0200 Subject: [PATCH 404/520] CO_SDOclient: static analysis: conditional of #if does not evaluate to 0 or 1 [MISRA 2012 Rule 20.8, required] --- 301/CO_SDOclient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 932ee559..9208a338 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -1245,7 +1245,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, else if (SDO_C->state == CO_SDO_ST_IDLE) { ret = CO_SDO_RT_ok_communicationEnd; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 /* Transfer data locally **************************************************/ else if ((SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) && !send_abort) { /* search object dictionary in first pass */ From c41d5b7cadd821ac514f1a5181a6094aa3cc1e08 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:38:28 +0200 Subject: [PATCH 405/520] CO_SDOclient: static analysis: statement or comment should appear in default case [MISRA 2012 Rule 16.1, required], [MISRA 2012 Rule 16.4, required] --- 301/CO_SDOclient.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 9208a338..3a7fbb7c 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -1132,6 +1132,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, case CO_SDO_ST_UPLOAD_BLK_END_SREQ: case CO_SDO_ST_UPLOAD_BLK_END_CRSP: default: { + /* none */ break; } } @@ -1908,6 +1909,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: case CO_SDO_ST_UPLOAD_BLK_END_SREQ: default: { + /* none */ break; } } From 7d1da22c828ef92a2761b17d0e2bd4d3e61ddee7 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:42:19 +0200 Subject: [PATCH 406/520] CO_SDOclient: static analysis: essential type of condition of 'if' statement is 'unsigned8' but should be boolean [MISRA 2012 Rule 14.4, required] --- 301/CO_SDOclient.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 3a7fbb7c..e545aa10 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -1389,11 +1389,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } - if (SDO_C->CANrxData[0] & 0x02U) { + if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { /* Expedited transfer */ size_t count = 4; /* is size indicated? */ - if (SDO_C->CANrxData[0] & 0x01U) { + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { count -= (SDO_C->CANrxData[0] >> 2) & 0x03U; } /* copy data, indicate size and finish */ @@ -1407,7 +1407,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, else { #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 /* segmented transfer, is size indicated? */ - if (SDO_C->CANrxData[0] & 0x01U) { + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { uint32_t size; (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); @@ -1465,7 +1465,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* If no more segments to be upload, finish */ - if (SDO_C->CANrxData[0] & 0x01U) { + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { /* verify size of data uploaded */ if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd) @@ -1501,7 +1501,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else { SDO_C->block_crcEnabled = false; } - if (SDO_C->CANrxData[0] & 0x02U) { + if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { uint32_t size; (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); @@ -1533,11 +1533,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, break; } - if (SDO_C->CANrxData[0] & 0x02U) { + if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { /* Expedited transfer */ size_t count = 4; /* is size indicated? */ - if (SDO_C->CANrxData[0] & 0x01U) { + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { count -= (SDO_C->CANrxData[0] >> 2) & 0x03U; } /* copy data, indicate size and finish */ @@ -1550,7 +1550,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else { /* segmented transfer, is size indicated? */ - if (SDO_C->CANrxData[0] & 0x01U) { + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { uint32_t size; (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); From 900633ad93c7623c8c3b738f0d702bf615d121f6 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 16:43:50 +0200 Subject: [PATCH 407/520] CO_SDOclient: static analysis: cannot assign 'signed8' to different essential type 'unsigned8' [MISRA 2012 Rule 10.3, required] --- 301/CO_SDOclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index e545aa10..6a123364 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -745,7 +745,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_ABORT; break; } - SDO_C->toggle = (toggle == 0x00U) ? 0x10 : 0x00; + SDO_C->toggle = (toggle == 0x00U) ? 0x10U : 0x00U; /* is end of transfer? */ if (SDO_C->finished) { @@ -1439,7 +1439,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_ABORT; break; } - SDO_C->toggle = (toggle == 0x00U) ? 0x10 : 0x00; + SDO_C->toggle = (toggle == 0x00U) ? 0x10U : 0x00U; /* get data size and write data to the buffer */ count = 7U - ((SDO_C->CANrxData[0] >> 1) & 0x07U); From 10816afe534e25dd1de80c2270c1bf771fb7dd41 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 17:00:22 +0200 Subject: [PATCH 408/520] CO_SDOclient: static analysis: right operand to +=/-= is a composite expression of type 'unsigned8' which is smaller than the left operand of type 'unsigned32' [MISRA 2012 Rule 10.7, required] --- 301/CO_SDOclient.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 6a123364..323c9c94 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -1394,7 +1394,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, size_t count = 4; /* is size indicated? */ if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { - count -= (SDO_C->CANrxData[0] >> 2) & 0x03U; + count -= (((size_t)SDO_C->CANrxData[0]) >> 2) & 0x03U; } /* copy data, indicate size and finish */ (void)CO_fifo_write(&SDO_C->bufFifo, @@ -1538,7 +1538,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, size_t count = 4; /* is size indicated? */ if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { - count -= (SDO_C->CANrxData[0] >> 2) & 0x03U; + count -= ((size_t)(SDO_C->CANrxData[0]) >> 2) & 0x03U; } /* copy data, indicate size and finish */ (void)CO_fifo_write(&SDO_C->bufFifo, @@ -1578,9 +1578,9 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07U); (void)CO_fifo_write(&SDO_C->bufFifo, &SDO_C->block_dataUploadLast[0], - 7U - noData, + (size_t)(7U) - noData, &SDO_C->block_crc); - SDO_C->sizeTran += 7U - noData; + SDO_C->sizeTran += (size_t)(7U) - noData; /* verify length */ if ((SDO_C->sizeInd > 0U) From 2a6b78172d870c80ebcb5e56b843f9e43fdfffc5 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 17:08:38 +0200 Subject: [PATCH 409/520] CO_SDOclient: static analysis: cannot assign a composite expression of type 'unsigned8' to an object of wider type 'unsigned32' [MISRA 2012 Rule 10.6, required] --- 301/CO_SDOclient.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 323c9c94..adeae407 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -801,8 +801,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->CANrxData[1] < SDO_C->block_seqno) { /* NOT all segments transferred successfully. * Re-transmit data after erroneous segment. */ - size_t cntFailed = SDO_C->block_seqno - - SDO_C->CANrxData[1]; + size_t cntFailed = (size_t)(SDO_C->block_seqno) - (size_t)(SDO_C->CANrxData[1]); cntFailed = (cntFailed * 7U) - SDO_C->block_noData; SDO_C->sizeTran -= cntFailed; (void)CO_fifo_altBegin(&SDO_C->bufFifo, @@ -1442,7 +1441,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->toggle = (toggle == 0x00U) ? 0x10U : 0x00U; /* get data size and write data to the buffer */ - count = 7U - ((SDO_C->CANrxData[0] >> 1) & 0x07U); + count = (size_t)(7U) - (((size_t)(SDO_C->CANrxData[0]) >> 1) & 0x07U); countWr = CO_fifo_write(&SDO_C->bufFifo, &SDO_C->CANrxData[1], count, NULL); From 53f3c58540e3988e7a7704e951a96f35a1f49830 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 17:19:05 +0200 Subject: [PATCH 410/520] CO_SDOclient: static analysis: body should be a compound statement [MISRA 2012 Rule 15.6, required] --- 301/CO_SDOclient.c | 458 +++++++++++++++++++++++---------------------- 1 file changed, 230 insertions(+), 228 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index adeae407..35289ddd 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -1373,277 +1373,279 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; } - else switch (SDO_C->state) { - case CO_SDO_ST_UPLOAD_INITIATE_RSP: { - if ((SDO_C->CANrxData[0] & 0xF0U) == 0x40U) { - /* verify index and subindex */ - uint16_t index; - uint8_t subindex; - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; - index |= SDO_C->CANrxData[1]; - subindex = SDO_C->CANrxData[3]; - if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { - abortCode = CO_SDO_AB_PRAM_INCOMPAT; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } + else { + switch (SDO_C->state) { + case CO_SDO_ST_UPLOAD_INITIATE_RSP: { + if ((SDO_C->CANrxData[0] & 0xF0U) == 0x40U) { + /* verify index and subindex */ + uint16_t index; + uint8_t subindex; + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { - /* Expedited transfer */ - size_t count = 4; - /* is size indicated? */ - if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { - count -= (((size_t)SDO_C->CANrxData[0]) >> 2) & 0x03U; + if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { + /* Expedited transfer */ + size_t count = 4; + /* is size indicated? */ + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { + count -= (((size_t)SDO_C->CANrxData[0]) >> 2) & 0x03U; + } + /* copy data, indicate size and finish */ + (void)CO_fifo_write(&SDO_C->bufFifo, + &SDO_C->CANrxData[4], + count, NULL); + SDO_C->sizeTran = count; + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; } - /* copy data, indicate size and finish */ - (void)CO_fifo_write(&SDO_C->bufFifo, - &SDO_C->CANrxData[4], - count, NULL); - SDO_C->sizeTran = count; - SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; - } - else { + else { #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 - /* segmented transfer, is size indicated? */ - if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { - uint32_t size; - (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); - SDO_C->sizeInd = CO_SWAP_32(size); - } - SDO_C->toggle = 0x00; - SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; + /* segmented transfer, is size indicated? */ + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { + uint32_t size; + (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + SDO_C->sizeInd = CO_SWAP_32(size); + } + SDO_C->toggle = 0x00; + SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; #else - abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; - SDO_C->state = CO_SDO_ST_ABORT; + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; + SDO_C->state = CO_SDO_ST_ABORT; #endif + } } - } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; - } - break; - } - -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { - if ((SDO_C->CANrxData[0] & 0xE0U) == 0x00U) { - size_t count, countWr; - - /* verify and alternate toggle bit */ - uint8_t toggle = SDO_C->CANrxData[0] & 0x10U; - if (toggle != SDO_C->toggle) { - abortCode = CO_SDO_AB_TOGGLE_BIT; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } - SDO_C->toggle = (toggle == 0x00U) ? 0x10U : 0x00U; - - /* get data size and write data to the buffer */ - count = (size_t)(7U) - (((size_t)(SDO_C->CANrxData[0]) >> 1) & 0x07U); - countWr = CO_fifo_write(&SDO_C->bufFifo, - &SDO_C->CANrxData[1], - count, NULL); - SDO_C->sizeTran += countWr; - - /* verify, if there was not enough space in fifo buffer */ - if (countWr != count) { - abortCode = CO_SDO_AB_OUT_OF_MEM; + else { + abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; - break; } + break; + } - /* verify if size of data uploaded is too large */ - if ((SDO_C->sizeInd > 0U) - && (SDO_C->sizeTran > SDO_C->sizeInd) - ) { - abortCode = CO_SDO_AB_DATA_LONG; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } +#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { + if ((SDO_C->CANrxData[0] & 0xE0U) == 0x00U) { + size_t count, countWr; + + /* verify and alternate toggle bit */ + uint8_t toggle = SDO_C->CANrxData[0] & 0x10U; + if (toggle != SDO_C->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + SDO_C->toggle = (toggle == 0x00U) ? 0x10U : 0x00U; + + /* get data size and write data to the buffer */ + count = (size_t)(7U) - (((size_t)(SDO_C->CANrxData[0]) >> 1) & 0x07U); + countWr = CO_fifo_write(&SDO_C->bufFifo, + &SDO_C->CANrxData[1], + count, NULL); + SDO_C->sizeTran += countWr; + + /* verify, if there was not enough space in fifo buffer */ + if (countWr != count) { + abortCode = CO_SDO_AB_OUT_OF_MEM; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - /* If no more segments to be upload, finish */ - if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { - /* verify size of data uploaded */ + /* verify if size of data uploaded is too large */ if ((SDO_C->sizeInd > 0U) - && (SDO_C->sizeTran < SDO_C->sizeInd) + && (SDO_C->sizeTran > SDO_C->sizeInd) ) { - abortCode = CO_SDO_AB_DATA_SHORT; + abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; - } else { - SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; + break; + } + + /* If no more segments to be upload, finish */ + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { + /* verify size of data uploaded */ + if ((SDO_C->sizeInd > 0U) + && (SDO_C->sizeTran < SDO_C->sizeInd) + ) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO_C->state = CO_SDO_ST_ABORT; + } else { + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } + } + else { + SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; } } else { - SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } + break; } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; - } - break; - } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { - if ((SDO_C->CANrxData[0] & 0xF9U) == 0xC0U) { - uint16_t index; - uint8_t subindex; - - /* get server CRC support info and data size */ - if ((SDO_C->CANrxData[0] & 0x04U) != 0U) { - SDO_C->block_crcEnabled = true; - } else { - SDO_C->block_crcEnabled = false; - } - if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { - uint32_t size; - (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); - SDO_C->sizeInd = CO_SWAP_32(size); - } + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { + if ((SDO_C->CANrxData[0] & 0xF9U) == 0xC0U) { + uint16_t index; + uint8_t subindex; + + /* get server CRC support info and data size */ + if ((SDO_C->CANrxData[0] & 0x04U) != 0U) { + SDO_C->block_crcEnabled = true; + } else { + SDO_C->block_crcEnabled = false; + } + if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { + uint32_t size; + (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + SDO_C->sizeInd = CO_SWAP_32(size); + } - /* verify index and subindex */ - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; - index |= SDO_C->CANrxData[1]; - subindex = SDO_C->CANrxData[3]; - if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { - abortCode = CO_SDO_AB_PRAM_INCOMPAT; - SDO_C->state = CO_SDO_ST_ABORT; - } - else { - SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; - } - } - /* switch to regular transfer, CO_SDO_ST_UPLOAD_INITIATE_RSP */ - else if ((SDO_C->CANrxData[0] & 0xF0U) == 0x40U) { - /* verify index and subindex */ - uint16_t index; - uint8_t subindex; - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; - index |= SDO_C->CANrxData[1]; - subindex = SDO_C->CANrxData[3]; - if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { - abortCode = CO_SDO_AB_PRAM_INCOMPAT; - SDO_C->state = CO_SDO_ST_ABORT; - break; + /* verify index and subindex */ + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + } + else { + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; + } } + /* switch to regular transfer, CO_SDO_ST_UPLOAD_INITIATE_RSP */ + else if ((SDO_C->CANrxData[0] & 0xF0U) == 0x40U) { + /* verify index and subindex */ + uint16_t index; + uint8_t subindex; + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { - /* Expedited transfer */ - size_t count = 4; - /* is size indicated? */ - if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { - count -= ((size_t)(SDO_C->CANrxData[0]) >> 2) & 0x03U; + if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { + /* Expedited transfer */ + size_t count = 4; + /* is size indicated? */ + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { + count -= ((size_t)(SDO_C->CANrxData[0]) >> 2) & 0x03U; + } + /* copy data, indicate size and finish */ + (void)CO_fifo_write(&SDO_C->bufFifo, + &SDO_C->CANrxData[4], + count, NULL); + SDO_C->sizeTran = count; + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } + else { + /* segmented transfer, is size indicated? */ + if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { + uint32_t size; + (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + SDO_C->sizeInd = CO_SWAP_32(size); + } + SDO_C->toggle = 0x00; + SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; } - /* copy data, indicate size and finish */ - (void)CO_fifo_write(&SDO_C->bufFifo, - &SDO_C->CANrxData[4], - count, NULL); - SDO_C->sizeTran = count; - SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; } else { - /* segmented transfer, is size indicated? */ - if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { - uint32_t size; - (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); - SDO_C->sizeInd = CO_SWAP_32(size); - } - SDO_C->toggle = 0x00; - SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } + break; } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; - } - break; - } - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: { - /* data are copied directly in the receive function */ - break; - } + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: { + /* data are copied directly in the receive function */ + break; + } - case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { - if ((SDO_C->CANrxData[0] & 0xE3U) == 0xC1U) { - /* Get number of data bytes in last segment, that do not - * contain data. Then copy remaining data into fifo */ - uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07U); - (void)CO_fifo_write(&SDO_C->bufFifo, - &SDO_C->block_dataUploadLast[0], - (size_t)(7U) - noData, - &SDO_C->block_crc); - SDO_C->sizeTran += (size_t)(7U) - noData; - - /* verify length */ - if ((SDO_C->sizeInd > 0U) - && (SDO_C->sizeTran != SDO_C->sizeInd) - ) { - abortCode = (SDO_C->sizeTran > SDO_C->sizeInd) ? - CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { + if ((SDO_C->CANrxData[0] & 0xE3U) == 0xC1U) { + /* Get number of data bytes in last segment, that do not + * contain data. Then copy remaining data into fifo */ + uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07U); + (void)CO_fifo_write(&SDO_C->bufFifo, + &SDO_C->block_dataUploadLast[0], + (size_t)(7U) - noData, + &SDO_C->block_crc); + SDO_C->sizeTran += (size_t)(7U) - noData; - /* verify CRC */ - if (SDO_C->block_crcEnabled) { - uint16_t crcServer; - crcServer = ((uint16_t) SDO_C->CANrxData[2]) << 8; - crcServer |= SDO_C->CANrxData[1]; - if (crcServer != SDO_C->block_crc) { - abortCode = CO_SDO_AB_CRC; + /* verify length */ + if ((SDO_C->sizeInd > 0U) + && (SDO_C->sizeTran != SDO_C->sizeInd) + ) { + abortCode = (SDO_C->sizeTran > SDO_C->sizeInd) ? + CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; break; } + + /* verify CRC */ + if (SDO_C->block_crcEnabled) { + uint16_t crcServer; + crcServer = ((uint16_t) SDO_C->CANrxData[2]) << 8; + crcServer |= SDO_C->CANrxData[1]; + if (crcServer != SDO_C->block_crc) { + abortCode = CO_SDO_AB_CRC; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + } + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; } - SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; + } + break; } - break; - } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: #endif #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 - case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: - case CO_SDO_ST_UPLOAD_BLK_END_SREQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: #endif - case CO_SDO_ST_IDLE: - case CO_SDO_ST_ABORT: - case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: - case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_UPLOAD_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: - case CO_SDO_ST_UPLOAD_BLK_END_CRSP: - default: { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; - break; + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: + default: { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } } } SDO_C->timeoutTimer = 0; From 86eb9bfad3277bd846d6ea8beea56b6564577f7f Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 17:24:43 +0200 Subject: [PATCH 411/520] CO_SDOclient: static analysis: an unsigned value and an enum value cannot be used together [MISRA 2012 Rule 10.4, required] --- 301/CO_SDOclient.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 35289ddd..e57257e1 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -49,7 +49,7 @@ /* default 'protocol switch threshold' size for block transfer */ #ifndef CO_CONFIG_SDO_CLI_PST -#define CO_CONFIG_SDO_CLI_PST 21 +#define CO_CONFIG_SDO_CLI_PST 21U #endif @@ -264,8 +264,8 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, { /* verify arguments */ if ((SDO_C == NULL) || (OD_1280_SDOcliPar == NULL) - || (OD_getIndex(OD_1280_SDOcliPar) < OD_H1280_SDO_CLIENT_1_PARAM) - || (OD_getIndex(OD_1280_SDOcliPar) > (OD_H1280_SDO_CLIENT_1_PARAM + 0x7FU)) + || (OD_getIndex(OD_1280_SDOcliPar) < (uint16_t)(OD_H1280_SDO_CLIENT_1_PARAM)) + || (OD_getIndex(OD_1280_SDOcliPar) > ((uint16_t)(OD_H1280_SDO_CLIENT_1_PARAM) + 0x7FU)) || (CANdevRx==NULL) || (CANdevTx==NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -469,7 +469,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, #endif #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 if (blockEnable && ((sizeIndicated == 0U) || - (sizeIndicated > CO_CONFIG_SDO_CLI_PST)) + (sizeIndicated > (size_t)(CO_CONFIG_SDO_CLI_PST))) ) { SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ; } @@ -492,7 +492,7 @@ void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, SDO_C->sizeInd = sizeIndicated; #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ) - && (sizeIndicated > 0U) && (sizeIndicated <= CO_CONFIG_SDO_CLI_PST) + && (sizeIndicated > 0U) && (sizeIndicated <= (size_t)(CO_CONFIG_SDO_CLI_PST)) ) { SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; } @@ -549,11 +549,11 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithClientAbort; } - else if ((SDO_C->OD_IO.stream.attribute & ODA_SDO_RW) == 0) { + else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_RW) == 0U) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; ret = CO_SDO_RT_endedWithClientAbort; } - else if ((SDO_C->OD_IO.stream.attribute & ODA_SDO_W) == 0) { + else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_W) == 0U) { abortCode = CO_SDO_AB_READONLY; ret = CO_SDO_RT_endedWithClientAbort; } @@ -603,7 +603,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, * shorter than size of OD data buffer. If so, add two zero * bytes to terminate (unicode) string. Shorten also OD data * size, (temporary, send info about EOF into OD_IO.write) */ - if (((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0) + if (((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) && ((sizeInOd == 0U) || (SDO_C->sizeTran < sizeInOd)) ) { buf[count] = 0; @@ -1259,11 +1259,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithClientAbort; } - else if ((SDO_C->OD_IO.stream.attribute & ODA_SDO_RW) == 0) { + else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_RW) == 0U) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; ret = CO_SDO_RT_endedWithClientAbort; } - else if ((SDO_C->OD_IO.stream.attribute & ODA_SDO_R) == 0) { + else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_R) == 0U) { abortCode = CO_SDO_AB_WRITEONLY; ret = CO_SDO_RT_endedWithClientAbort; } @@ -1303,7 +1303,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, else { /* if data is string, send only data up to null termination */ if ((countRd > 0U) - && ((SDO_C->OD_IO.stream.attribute & ODA_STR) != 0) + && ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) ) { buf[countRd] = 0; /* (buf is one byte larger) */ OD_size_t countStr = (OD_size_t)strlen((char *)buf); From 6b41e85e3d0c4ad581587dea938a2c7fa105b323 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 17:36:19 +0200 Subject: [PATCH 412/520] CO_SDOclient: static analysis: body should be a compound statement [MISRA 2012 Rule 15.6, required] --- 301/CO_SDOclient.c | 313 +++++++++++++++++++++++---------------------- 1 file changed, 161 insertions(+), 152 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index e57257e1..efcffa34 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -300,7 +300,9 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, if ((odRet0 != ODR_OK) || (maxSubIndex != 3U) || (odRet1 != ODR_OK) || (odRet2 != ODR_OK) || (odRet3 != ODR_OK) ) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1280_SDOcliPar); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1280_SDOcliPar); + } return CO_ERROR_OD_PARAMETERS; } @@ -311,7 +313,9 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, ODR_t odRetE = OD_extension_init(OD_1280_SDOcliPar, &SDO_C->OD_1280_extension); if (odRetE != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1280_SDOcliPar); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1280_SDOcliPar); + } return CO_ERROR_OD_PARAMETERS; } @@ -696,190 +700,193 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; } - else switch (SDO_C->state) { - case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { - if (SDO_C->CANrxData[0] == 0x60U) { - /* verify index and subindex */ - uint16_t index; - uint8_t subindex; - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; - index |= SDO_C->CANrxData[1]; - subindex = SDO_C->CANrxData[3]; - if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { - abortCode = CO_SDO_AB_PRAM_INCOMPAT; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } + else { + switch (SDO_C->state) { + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { + if (SDO_C->CANrxData[0] == 0x60U) { + /* verify index and subindex */ + uint16_t index; + uint8_t subindex; + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 - if (SDO_C->finished) { + if (SDO_C->finished) { + /* expedited transfer */ + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } + else { + /* segmented transfer - prepare the first segment */ + SDO_C->toggle = 0x00; + SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; + } +#else /* expedited transfer */ SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; +#endif } else { - /* segmented transfer - prepare the first segment */ - SDO_C->toggle = 0x00; - SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } -#else - /* expedited transfer */ - SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; -#endif - } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; + break; } - break; - } #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { - if ((SDO_C->CANrxData[0] & 0xEFU) == 0x20U) { - /* verify and alternate toggle bit */ - uint8_t toggle = SDO_C->CANrxData[0] & 0x10U; - if (toggle != SDO_C->toggle) { - abortCode = CO_SDO_AB_TOGGLE_BIT; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } - SDO_C->toggle = (toggle == 0x00U) ? 0x10U : 0x00U; + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { + if ((SDO_C->CANrxData[0] & 0xEFU) == 0x20U) { + /* verify and alternate toggle bit */ + uint8_t toggle = SDO_C->CANrxData[0] & 0x10U; + if (toggle != SDO_C->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + SDO_C->toggle = (toggle == 0x00U) ? 0x10U : 0x00U; - /* is end of transfer? */ - if (SDO_C->finished) { - SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; + /* is end of transfer? */ + if (SDO_C->finished) { + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } + else { + SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; + } } else { - SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; } + break; } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; - } - break; - } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { - if ((SDO_C->CANrxData[0] & 0xFBU) == 0xA0U) { - /* verify index and subindex */ - uint16_t index; - uint8_t subindex; - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; - index |= SDO_C->CANrxData[1]; - subindex = SDO_C->CANrxData[3]; - if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { - abortCode = CO_SDO_AB_PRAM_INCOMPAT; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } - - SDO_C->block_crc = 0; - SDO_C->block_blksize = SDO_C->CANrxData[4]; - if ((SDO_C->block_blksize < 1U) || (SDO_C->block_blksize > 127U)) - SDO_C->block_blksize = 127; - SDO_C->block_seqno = 0; - (void)CO_fifo_altBegin(&SDO_C->bufFifo, 0); - SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; - } - break; - } + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { + if ((SDO_C->CANrxData[0] & 0xFBU) == 0xA0U) { + /* verify index and subindex */ + uint16_t index; + uint8_t subindex; + index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index |= SDO_C->CANrxData[1]; + subindex = SDO_C->CANrxData[3]; + if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { + abortCode = CO_SDO_AB_PRAM_INCOMPAT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { - if (SDO_C->CANrxData[0] == 0xA2U) { - /* check number of segments */ - if (SDO_C->CANrxData[1] < SDO_C->block_seqno) { - /* NOT all segments transferred successfully. - * Re-transmit data after erroneous segment. */ - size_t cntFailed = (size_t)(SDO_C->block_seqno) - (size_t)(SDO_C->CANrxData[1]); - cntFailed = (cntFailed * 7U) - SDO_C->block_noData; - SDO_C->sizeTran -= cntFailed; - (void)CO_fifo_altBegin(&SDO_C->bufFifo, - (size_t)SDO_C->CANrxData[1] * 7U); - SDO_C->finished = false; + SDO_C->block_crc = 0; + SDO_C->block_blksize = SDO_C->CANrxData[4]; + if ((SDO_C->block_blksize < 1U) || (SDO_C->block_blksize > 127U)) { + SDO_C->block_blksize = 127; + } + SDO_C->block_seqno = 0; + (void)CO_fifo_altBegin(&SDO_C->bufFifo, 0); + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; } - else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) { - /* something strange from server, break transmission */ + else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; - break; } - else { /* MISRA C 2004 14.10 */ } + break; + } + + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { + if (SDO_C->CANrxData[0] == 0xA2U) { + /* check number of segments */ + if (SDO_C->CANrxData[1] < SDO_C->block_seqno) { + /* NOT all segments transferred successfully. + * Re-transmit data after erroneous segment. */ + size_t cntFailed = (size_t)(SDO_C->block_seqno) - (size_t)(SDO_C->CANrxData[1]); + cntFailed = (cntFailed * 7U) - SDO_C->block_noData; + SDO_C->sizeTran -= cntFailed; + (void)CO_fifo_altBegin(&SDO_C->bufFifo, + (size_t)SDO_C->CANrxData[1] * 7U); + SDO_C->finished = false; + } + else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) { + /* something strange from server, break transmission */ + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + else { /* MISRA C 2004 14.10 */ } - /* confirm successfully transmitted data */ - CO_fifo_altFinish(&SDO_C->bufFifo, &SDO_C->block_crc); + /* confirm successfully transmitted data */ + CO_fifo_altFinish(&SDO_C->bufFifo, &SDO_C->block_crc); - if (SDO_C->finished) { - SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_REQ; - } else { - SDO_C->block_blksize = SDO_C->CANrxData[2]; - SDO_C->block_seqno = 0; - (void)CO_fifo_altBegin(&SDO_C->bufFifo, 0); - SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; + if (SDO_C->finished) { + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_REQ; + } else { + SDO_C->block_blksize = SDO_C->CANrxData[2]; + SDO_C->block_seqno = 0; + (void)CO_fifo_altBegin(&SDO_C->bufFifo, 0); + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; + } } + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; + } + break; } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; - } - break; - } - case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { - if (SDO_C->CANrxData[0] == 0xA1U) { - /* SDO block download successfully transferred */ - SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { + if (SDO_C->CANrxData[0] == 0xA1U) { + /* SDO block download successfully transferred */ + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } + else { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; + } + break; } - break; - } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: #endif #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: #endif - case CO_SDO_ST_IDLE: - case CO_SDO_ST_ABORT: - case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: - case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_UPLOAD_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: - case CO_SDO_ST_UPLOAD_BLK_END_SREQ: - case CO_SDO_ST_UPLOAD_BLK_END_CRSP: - default: { - abortCode = CO_SDO_AB_CMD; - SDO_C->state = CO_SDO_ST_ABORT; - break; + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: + default: { + abortCode = CO_SDO_AB_CMD; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } } } SDO_C->timeoutTimer = 0; @@ -1307,7 +1314,9 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, ) { buf[countRd] = 0; /* (buf is one byte larger) */ OD_size_t countStr = (OD_size_t)strlen((char *)buf); - if (countStr == 0U) countStr = 1; /* no zero length */ + if (countStr == 0U) { + countStr = 1; /* no zero length */ + } if (countStr < countRd) { /* string terminator found, finish read, shorten data */ countRd = countStr; From b1cba9661b0f20fd3898dae9e2ec6b8272e72c56 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 17:53:02 +0200 Subject: [PATCH 413/520] CO_SDOclient: static analysis: side effects on right hand of logical operator, '||'/'&&' [MISRA 2012 Rule 13.5, required] --- 301/CO_SDOclient.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index efcffa34..e89cf82b 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -71,9 +71,10 @@ static void CO_SDOclient_receive(void *object, void *msg) { && (!CO_FLAG_READ(SDO_C->CANrxNew) || (data[0] == 0x80U)) ) { #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 + bool_t state_not_upload_blk_sublock_sreq = (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ); + bool_t state_not_upload_blk_sublock_crsp = (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP); if ((data[0] == 0x80U) /* abort from server */ - || ((SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) - && (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP)) + || (state_not_upload_blk_sublock_sreq && state_not_upload_blk_sublock_crsp) ) { #endif /* copy data and set 'new message' flag */ @@ -262,10 +263,12 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, uint16_t CANdevTxIdx, uint32_t *errInfo) { + bool_t index_SDOcliPar_min = (OD_getIndex(OD_1280_SDOcliPar) < (uint16_t)(OD_H1280_SDO_CLIENT_1_PARAM)); + bool_t index_SDOcliPar_max = (OD_getIndex(OD_1280_SDOcliPar) > ((uint16_t)(OD_H1280_SDO_CLIENT_1_PARAM) + 0x7FU)); + /* verify arguments */ if ((SDO_C == NULL) || (OD_1280_SDOcliPar == NULL) - || (OD_getIndex(OD_1280_SDOcliPar) < (uint16_t)(OD_H1280_SDO_CLIENT_1_PARAM)) - || (OD_getIndex(OD_1280_SDOcliPar) > ((uint16_t)(OD_H1280_SDO_CLIENT_1_PARAM) + 0x7FU)) + || index_SDOcliPar_min || index_SDOcliPar_max || (CANdevRx==NULL) || (CANdevTx==NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -1674,9 +1677,9 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->timeoutTimer += timeDifference_us; } if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) { - if ((SDO_C->state == CO_SDO_ST_UPLOAD_SEGMENT_REQ) || - (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP) - ) { + bool_t state_upload_seg_req = (SDO_C->state == CO_SDO_ST_UPLOAD_SEGMENT_REQ); + bool_t state_upload_blk_sublock_crsp = (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP); + if (state_upload_seg_req || state_upload_blk_sublock_crsp) { /* application didn't empty buffer */ abortCode = CO_SDO_AB_GENERAL; } else { From ad14eb5b18e15cde88ee589ce4cb55a167018fcf Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 17:58:18 +0200 Subject: [PATCH 414/520] CO_SDOclient: static analysis: argument 1 is not compatible with argument 2 in call to function 'memcpy' --- 301/CO_SDOclient.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index e89cf82b..169d6b97 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -693,7 +693,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80U) { uint32_t code; - (void)memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); + (void)memcpy((void *)(&code), (const void *)(&SDO_C->CANrxData[4]), sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; @@ -973,7 +973,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->sizeInd > 0U) { uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); SDO_C->CANtxBuff->data[0] |= 0x01U; - (void)memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); + (void)memcpy((void *)(&SDO_C->CANtxBuff->data[4]), (const void *)(&size), sizeof(size)); } #else SDO_C->state = CO_SDO_ST_IDLE; @@ -1039,7 +1039,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->sizeInd > 0U) { uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); SDO_C->CANtxBuff->data[0] |= 0x02U; - (void)memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size)); + (void)memcpy((void *)(&SDO_C->CANtxBuff->data[4]), (const void *)(&size), sizeof(size)); } /* reset timeout timer and send message */ @@ -1156,7 +1156,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - (void)memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); + (void)memcpy((void *)(&SDO_C->CANtxBuff->data[4]), (const void *)(&code), sizeof(code)); (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; @@ -1375,7 +1375,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80U) { uint32_t code; - (void)memcpy(&code, &SDO_C->CANrxData[4], sizeof(code)); + (void)memcpy((void *)(&code), (const void *)(&SDO_C->CANrxData[4]), sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; @@ -1421,7 +1421,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* segmented transfer, is size indicated? */ if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { uint32_t size; - (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + (void)memcpy((void *)(&size), (void *)(&SDO_C->CANrxData[4]), sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } SDO_C->toggle = 0x00; @@ -1515,7 +1515,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { uint32_t size; - (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + (void)memcpy((void *)(&size), (const void *)(&SDO_C->CANrxData[4]), sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } @@ -1564,7 +1564,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* segmented transfer, is size indicated? */ if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { uint32_t size; - (void)memcpy(&size, &SDO_C->CANrxData[4], sizeof(size)); + (void)memcpy((void *)(&size), (const void *)(&SDO_C->CANrxData[4]), sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } SDO_C->toggle = 0x00; @@ -1937,7 +1937,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - (void)memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code)); + (void)memcpy((void *)(&SDO_C->CANtxBuff->data[4]), (const void *)(&code), sizeof(code)); (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; From 646e367ae1748357b00ede5e28924ee76ddb6634 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Wed, 26 Jun 2024 18:01:47 +0200 Subject: [PATCH 415/520] CO_SDOclient: static anaylsis: loss of precision (assignment) from 32 bits to 8 bits --- 301/CO_SDOclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 169d6b97..463d7ef5 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -958,7 +958,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } if (SDO_C->sizeInd > 0U) { - SDO_C->CANtxBuff->data[0] |= 0x01U | ((4U - count) << 2); + SDO_C->CANtxBuff->data[0] |= (uint8_t)(0x01U | ((4U - count) << 2)); } /* copy data */ @@ -1101,7 +1101,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { - SDO_C->CANtxBuff->data[0] = 0xC1U | (SDO_C->block_noData << 2); + SDO_C->CANtxBuff->data[0] = (uint8_t)(0xC1U | (SDO_C->block_noData << 2)); SDO_C->CANtxBuff->data[1] = (uint8_t) SDO_C->block_crc; SDO_C->CANtxBuff->data[2] = (uint8_t) (SDO_C->block_crc >> 8); From b39334d9c3c3c3bd628eee48abc93621d5644014 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 08:55:44 +0200 Subject: [PATCH 416/520] CO_SDOclient: static analysis: potential out of bounds pointer access [MISRA 2012 Rule 18.1, required] --- 301/CO_SDOclient.c | 12 ++++++------ 301/CO_SDOclient.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 463d7ef5..834cd107 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -29,7 +29,7 @@ #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 /* verify configuration */ -#if CO_CONFIG_SDO_CLI_BUFFER_SIZE < 7 +#if CO_CONFIG_SDO_CLI_BUFFER_SIZE < 7U #error CO_CONFIG_SDO_CLI_BUFFER_SIZE must be set to 7 or more. #endif #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) == 0 @@ -290,7 +290,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, /* prepare circular fifo buffer */ CO_fifo_init(&SDO_C->bufFifo, SDO_C->buf, - CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1); + CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U); /* Get parameters from Object Dictionary (initial values) */ uint8_t maxSubIndex, nodeIDOfTheSDOServer; @@ -573,13 +573,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* write data, in several passes if necessary */ if (SDO_C->OD_IO.write != NULL) { size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo); - uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 2]; + uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 2U]; (void)CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); SDO_C->sizeTran += count; /* error: no data */ - if (count == 0U) { + if ((count == 0U) || (count > CO_CONFIG_SDO_CLI_BUFFER_SIZE)){ abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; } @@ -1298,7 +1298,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, OD_size_t countBuf = ((countData > 0U) && (countData <= countFifo)) ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; - uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; + uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U]; /* load data from OD variable into the buffer */ CO_LOCK_OD(SDO_C->CANdevTx); @@ -1312,7 +1312,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } else { /* if data is string, send only data up to null termination */ - if ((countRd > 0U) + if ((countRd > 0U) && (countRd <= CO_CONFIG_SDO_CLI_BUFFER_SIZE) && ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) ) { buf[countRd] = 0; /* (buf is one byte larger) */ diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index e2c44970..8062b97a 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -38,9 +38,9 @@ #endif #ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000 + #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000U #else - #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32 + #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32U #endif #endif @@ -228,7 +228,7 @@ typedef struct { CO_fifo_t bufFifo; /** Data buffer of usable size @ref CO_CONFIG_SDO_CLI_BUFFER_SIZE, used * inside bufFifo. Must be one byte larger for fifo usage. */ - uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1]; + uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U]; /** Indicates, if new SDO message received from CAN bus. It is not cleared, * until received message is completely processed. */ volatile void *CANrxNew; From d7b77c7dd61bbbd8dabf159caf05a1b34bcf356b Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 08:59:56 +0200 Subject: [PATCH 417/520] CO_gateway_ascii: static analysis: no 'else' at end of 'if ... else if' chain [MISRA 2012 Rule 15.7, required] --- 309/CO_gateway_ascii.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 16ee6fa4..96307385 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -680,6 +680,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, responseWithEmpty(gtwa); continue; } + else { /* MISRA C 2004 14.10 */ } + if ((tok[0] != '[') || (tok[strlen(tok)-1] != ']')) { err = true; break; @@ -707,6 +709,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, err = true; break; } + else { /* MISRA C 2004 14.10 */ } ui[i] = getU32(tok, 0, 0xFFFFFFFF, &err); if (err) break; @@ -1617,6 +1620,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } while ((gtwa->respHold == false) && (fifoRemain > 0)); } + else { /* MISRA C 2004 14.10 */ } break; } @@ -1703,6 +1707,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, responseWithOK(gtwa); gtwa->state = CO_GTWA_ST_IDLE; } + else { /* MISRA C 2004 14.10 */ } } break; } From ebf549db2b7e63d9347713aa5b231cebef981306 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 09:09:21 +0200 Subject: [PATCH 418/520] CO_gateway_ascii: static analysis: switch case lacks unconditional break or throw [MISRA 2012 Rule 16.3, required] --- 309/CO_gateway_ascii.c | 1 + 1 file changed, 1 insertion(+) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 96307385..51dbec68 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -1549,6 +1549,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else switch (gtwa->state) { case CO_GTWA_ST_IDLE: { return; /* skip timerNext_us calculation */ + break; } #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 From df350cc1340e3bcb10e7c2d57d9309e812c60b0b Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 09:18:21 +0200 Subject: [PATCH 419/520] CO_gateway_ascii: static analysis: body should be a compound statement [MISRA 2012 Rule 15.6, required] --- 309/CO_gateway_ascii.c | 166 ++++++++++++++++++++++++++++++----------- 1 file changed, 124 insertions(+), 42 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 51dbec68..9035eef1 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -688,7 +688,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } tok[strlen(tok)-1] = '\0'; gtwa->sequence = getU32(tok + 1, 0, 0xFFFFFFFF, &err); - if (err) break; + if (err) { + break; + } /* parse optional tokens '[[] ]', both numerical. Then @@ -712,9 +714,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else { /* MISRA C 2004 14.10 */ } ui[i] = getU32(tok, 0, 0xFFFFFFFF, &err); - if (err) break; + if (err) { + break; + } + } + if (err) { + break; } - if (err) break; switch(i) { case 0: /* only (pointed by token) */ @@ -749,7 +755,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* MISRA C 2004 15.3 */ break; } - if (err) break; + if (err) { + break; + } /* command is case insensitive */ convertToLower(tok, sizeof(tok)); @@ -764,7 +772,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* command 2 */ closed = 0xFFU; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - if (err) break; + if (err) { + break; + } convertToLower(tok, sizeof(tok)); /* 'set network ' */ @@ -782,7 +792,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, &closed, &err); value = (uint16_t)getU32(tok, CO_CONFIG_GTW_NET_MIN, CO_CONFIG_GTW_NET_MAX, &err); - if (err) break; + if (err) { + break; + } gtwa->net_default = value; responseWithOK(gtwa); @@ -802,7 +814,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint8_t)getU32(tok, 1, 127, &err); - if (err) break; + if (err) { + break; + } gtwa->node_default = value; responseWithOK(gtwa); @@ -823,7 +837,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, 1, 0xFFFF, &err); - if (err) break; + if (err) { + break; + } gtwa->SDOtimeoutTime = value; responseWithOK(gtwa); @@ -843,7 +859,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, 0, 1, &err); - if (err) break; + if (err) { + break; + } gtwa->SDOblockTransferEnable = (value==1) ? true : false; responseWithOK(gtwa); @@ -873,7 +891,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err); - if (err) break; + if (err) { + break; + } /* subindex */ closed = 0xFFU; @@ -892,7 +912,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, &closed, &err); convertToLower(tok, sizeof(tok)); gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err); - if (err) break; + if (err) { + break; + } } else { gtwa->SDOdataType = &dataTypes[0]; /* use generic data type */ @@ -944,14 +966,18 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err); - if (err) break; + if (err) { + break; + } /* subindex */ closed = 0U; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); - if (err) break; + if (err) { + break; + } /* data type */ closed = 0U; @@ -959,7 +985,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, &closed, &err); convertToLower(tok, sizeof(tok)); gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err); - if (err) break; + if (err) { + break; + } /* setup client */ SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, @@ -1097,7 +1125,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* command 2 */ closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - if (err) break; + if (err) { + break; + } convertToLower(tok, sizeof(tok)); if (strcmp(tok, "node") == 0) { @@ -1139,7 +1169,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); select = (uint8_t)getU32(tok, 0, 1, &err); - if (err) break; + if (err) { + break; + } if (select == 0) { /* send non-confirmed message */ @@ -1174,20 +1206,28 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err); - if (err) break; + if (err) { + break; + } CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.productCode = getU32(tok, 0, 0xFFFFFFFF, &err); - if (err) break; + if (err) { + break; + } CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.revisionNumber = getU32(tok, 0, 0xFFFFFFFF, &err); - if (err) break; + if (err) { + break; + } closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.serialNumber = getU32(tok, 0, 0xFFFFFFFF, &err); - if (err) break; + if (err) { + break; + } /* continue with state machine */ gtwa->state = CO_GTWA_ST_LSS_SWITCH_SEL; @@ -1205,8 +1245,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); gtwa->lssNID = (uint8_t)getU32(tok, 0, 0xFF, &err); - if ((gtwa->lssNID > 0x7F) && (gtwa->lssNID < 0xFF)) err = true; - if (err) break; + if ((gtwa->lssNID > 0x7F) && (gtwa->lssNID < 0xFF)) { + err = true; + } + if (err) { + break; + } /* continue with state machine */ gtwa->state = CO_GTWA_ST_LSS_SET_NODE; @@ -1236,8 +1280,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); tableIndex = (uint8_t)getU32(tok, 0, maxIndex, &err); - if (tableIndex == 5) err = true; - if (err) break; + if (tableIndex == 5) { + err = true; + } + if (err) { + break; + } gtwa->lssBitrate = CO_LSS_bitTimingTableLookup[tableIndex]; /* continue with state machine */ @@ -1259,7 +1307,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); switchDelay = (uint16_t)getU32(tok, 0, 0xFFFF, &err); - if (err) break; + if (err) { + break; + } /* send non-confirmed message */ ret = CO_LSSmaster_ActivateBit(gtwa->LSSmaster, switchDelay); @@ -1299,7 +1349,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); lsssub = (uint8_t)getU32(tok, 0, 3, &err); - if (err) break; + if (err) { + break; + } switch (lsssub) { case 0: gtwa->lssInquireCs = CO_LSS_INQUIRE_VENDOR; break; case 1: gtwa->lssInquireCs = CO_LSS_INQUIRE_PRODUCT; break; @@ -1344,7 +1396,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); - if (err) break; + if (err) { + break; + } } /* If timeout not specified, use 100ms. Should work in most cases */ @@ -1388,7 +1442,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 0xFFU; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); - if (err) break; + if (err) { + break; + } } /* If timeout not specified, use 100ms. Should work in most cases */ @@ -1411,12 +1467,16 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* more arguments follow */ CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); gtwa->lssNID = (uint8_t)getU32(tok, 1, 127, &err); - if (err) break; + if (err) { + break; + } closed = 0xFFU; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); gtwa->lssStore = (bool_t)getU32(tok, 0, 1, &err); - if (err) break; + if (err) { + break; + } if (closed == 1U) { /* No other arguments, prepare lssFastscan, all zero */ @@ -1429,36 +1489,52 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_VENDOR_ID] = getU32(tok, 0, 2, &err); - if (err) break; + if (err) { + break; + } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err); - if (err) break; + if (err) { + break; + } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_PRODUCT] = getU32(tok, 0, 2, &err); - if (err) break; + if (err) { + break; + } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.productCode = getU32(tok,0,0xFFFFFFFF, &err); - if (err) break; + if (err) { + break; + } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_REV] = getU32(tok, 0, 2, &err); - if (err) break; + if (err) { + break; + } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.revisionNumber=getU32(tok,0,0xFFFFFFFF,&err); - if (err) break; + if (err) { + break; + } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_SERIAL] = getU32(tok, 0, 2, &err); - if (err) break; + if (err) { + break; + } closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.serialNumber = getU32(tok,0,0xFFFFFFFF,&err); - if (err) break; + if (err) { + break; + } } /* continue with state machine */ @@ -1487,7 +1563,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* get second token */ closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - if (err) break; + if (err) { + break; + } convertToLower(tok, sizeof(tok)); if (strcmp(tok, "datatype") == 0) { @@ -1546,7 +1624,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_IDLE; } - else switch (gtwa->state) { + else { + switch (gtwa->state) { case CO_GTWA_ST_IDLE: { return; /* skip timerNext_us calculation */ break; @@ -1652,8 +1731,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, abortCode = CO_SDO_AB_DEVICE_INCOMPAT; abort = true; /* abort SDO communication */ /* clear the rest of the command, if necessary */ - if (closed != 1U) + if (closed != 1U) { CO_fifo_CommSearch(>wa->commFifo, true); + } } if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) { /* Stay in this state, until all data transferred via commFifo @@ -2049,8 +2129,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, i = (CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2) + CO_LED_GREEN(gtwa->LEDs, CO_LED_CANopen); } - if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1)) + if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1)) { i = CO_GTWA_LED_PRINTOUTS_SIZE - 1; + } if (i != gtwa->ledStringPreviousIndex) { gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, @@ -2070,6 +2151,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } } /* switch (gtwa->state) */ + } /* execute next CANopen processing immediately, if idle and more commands * available */ From e0bd857df85eca8c51b561739e089e71cf7bac6a Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 09:22:02 +0200 Subject: [PATCH 420/520] CO_gateway_ascii: static analysis: dependence placed on operator [MISRA 2012 Rule 12.1, advisory] --- 309/CO_gateway_ascii.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 9035eef1..c818fcf8 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -67,18 +67,18 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, { (void)dummy; /* verify arguments */ - if (gtwa == NULL + if ((gtwa == NULL) #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 - || SDO_C == NULL || SDOclientTimeoutTime_ms == 0 + || (SDO_C == NULL) || (SDOclientTimeoutTime_ms == 0) #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 - || NMT == NULL + || (NMT == NULL) #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 - || LSSmaster == NULL + || (LSSmaster == NULL) #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 - || LEDs == NULL + || (LEDs == NULL) #endif ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -272,7 +272,7 @@ static bool_t checkNetNode(CO_GTWA_t *gtwa, e = true; } /* not implemented */ - else if (net < CO_CONFIG_GTW_NET_MIN || net > CO_CONFIG_GTW_NET_MAX) { + else if ((net < CO_CONFIG_GTW_NET_MIN) || (net > CO_CONFIG_GTW_NET_MAX)) { eCode = CO_GTWA_respErrorUnsupportedNet; e = true; } @@ -300,7 +300,7 @@ static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, e = true; } /* not implemented */ - else if (net < CO_CONFIG_GTW_NET_MIN || net > CO_CONFIG_GTW_NET_MAX) { + else if ((net < CO_CONFIG_GTW_NET_MIN) || (net > CO_CONFIG_GTW_NET_MAX)) { eCode = CO_GTWA_respErrorUnsupportedNet; e = true; } @@ -582,7 +582,7 @@ static void responseLSS(CO_GTWA_t *gtwa, CO_LSSmaster_return_t lss_ret) { else { CO_GTWA_respErrorCode_t respErrorCode; - if (lss_ret==CO_LSSmaster_TIMEOUT || lss_ret==CO_LSSmaster_SCAN_NOACK) { + if ((lss_ret==CO_LSSmaster_TIMEOUT) || (lss_ret==CO_LSSmaster_SCAN_NOACK)) { respErrorCode = CO_GTWA_respErrorTimeOut; } else if (lss_ret == CO_LSSmaster_OK_MANUFACTURER) { @@ -1738,7 +1738,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) { /* Stay in this state, until all data transferred via commFifo * will be purged. */ - if (!CO_fifo_purge(>wa->SDO_C->bufFifo) || closed == 1U) { + if (!CO_fifo_purge(>wa->SDO_C->bufFifo) || (closed == 1U)) { gtwa->state = CO_GTWA_ST_IDLE; } break; @@ -1748,8 +1748,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * SDO buffer, to continue communication. Otherwise wait and check for * timeout */ if (gtwa->SDOdataCopyStatus - && CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < - (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7) + && (CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < + (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7)) ) { if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; @@ -1926,7 +1926,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, timeDifference_us, >wa->lssFastscan); if (ret != CO_LSSmaster_WAIT_SLAVE) { - if (ret == CO_LSSmaster_OK || ret == CO_LSSmaster_SCAN_FINISHED) { + if ((ret == CO_LSSmaster_OK) || (ret == CO_LSSmaster_SCAN_FINISHED)) { gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ @@ -1957,7 +1957,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_LSSmaster_changeTimeout(gtwa->LSSmaster, CO_LSSmaster_DEFAULT_TIMEOUT); - if (ret == CO_LSSmaster_OK || ret == CO_LSSmaster_SCAN_NOACK) { + if ((ret == CO_LSSmaster_OK) || (ret == CO_LSSmaster_SCAN_NOACK)) { /* no (more) nodes found, send report sum and finish */ gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, From 03fc8257f66e137b93f615e3cb4bf6bd8e4a49d9 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 09:24:38 +0200 Subject: [PATCH 421/520] CO_gateway_asci: staatic analysis: the name 'abort' is reserved to the compiler [MISRA 2012 Rule 21.2, required] --- 309/CO_gateway_ascii.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index c818fcf8..20db1218 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -1709,7 +1709,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, case CO_GTWA_ST_WRITE_ABORTED: { CO_SDO_abortCode_t abortCode; size_t sizeTransferred; - bool_t abort = false; + bool_t abort_comm = false; bool_t hold = false; CO_SDO_return_t ret; @@ -1729,7 +1729,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U)) ) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - abort = true; /* abort SDO communication */ + abort_comm = true; /* abort SDO communication */ /* clear the rest of the command, if necessary */ if (closed != 1U) { CO_fifo_CommSearch(>wa->commFifo, true); @@ -1753,20 +1753,20 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, ) { if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - abort = true; + abort_comm = true; } else { gtwa->stateTimeoutTmr += timeDifference_us; hold = true; } } - if (!hold || abort) { + if (!hold || abort_comm) { /* if OS has CANtx queue, speedup block transfer */ int loop = 0; do { ret = CO_SDOclientDownload(gtwa->SDO_C, timeDifference_us, - abort, + abort_comm, gtwa->SDOdataCopyStatus, &abortCode, &sizeTransferred, From 732634d049c8426d410f2b6bf2730308a7419553 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 09:27:09 +0200 Subject: [PATCH 422/520] CO_gateway_ascii: static analysis: unsigned integer literal without a 'U' suffix [MISRA 2012 Rule 7.2, required] --- 309/CO_gateway_ascii.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 20db1218..df238739 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -687,7 +687,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } tok[strlen(tok)-1] = '\0'; - gtwa->sequence = getU32(tok + 1, 0, 0xFFFFFFFF, &err); + gtwa->sequence = getU32(tok + 1, 0, 0xFFFFFFFFU, &err); if (err) { break; } @@ -713,7 +713,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } else { /* MISRA C 2004 14.10 */ } - ui[i] = getU32(tok, 0, 0xFFFFFFFF, &err); + ui[i] = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } @@ -1205,26 +1205,26 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* get values */ closed = 0U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - addr->identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err); + addr->identity.vendorID = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - addr->identity.productCode = getU32(tok, 0, 0xFFFFFFFF, &err); + addr->identity.productCode = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - addr->identity.revisionNumber = getU32(tok, 0, 0xFFFFFFFF, &err); + addr->identity.revisionNumber = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - addr->identity.serialNumber = getU32(tok, 0, 0xFFFFFFFF, &err); + addr->identity.serialNumber = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } @@ -1494,7 +1494,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->match.identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err); + fs->match.identity.vendorID = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } @@ -1506,7 +1506,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->match.identity.productCode = getU32(tok,0,0xFFFFFFFF, &err); + fs->match.identity.productCode = getU32(tok,0,0xFFFFFFFFU, &err); if (err) { break; } @@ -1518,7 +1518,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->match.identity.revisionNumber=getU32(tok,0,0xFFFFFFFF,&err); + fs->match.identity.revisionNumber=getU32(tok,0,0xFFFFFFFFU,&err); if (err) { break; } @@ -1531,7 +1531,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->match.identity.serialNumber = getU32(tok,0,0xFFFFFFFF,&err); + fs->match.identity.serialNumber = getU32(tok,0,0xFFFFFFFFU,&err); if (err) { break; } From 49c90c50f6a7a8b510c2ce14305e51dd79b8bca0 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 09:40:39 +0200 Subject: [PATCH 423/520] CO_gateway_ascii: static analysis: cannot assign type to different essential type [MISRA 2012 Rule 10.3, required] --- 309/CO_gateway_ascii.c | 64 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index df238739..4097b6af 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -243,7 +243,7 @@ static inline uint32_t getU32(char *token, uint32_t min, char *sRet; uint32_t num = strtoul(token, &sRet, 0); - if ((sRet != strchr(token, '\0')) || (num < min) || (num > max)) { + if ((sRet != strchr(token, (int)'\0')) || (num < min) || (num > max)) { *err = true; } @@ -350,8 +350,8 @@ static const CO_GTWA_dataType_t dataTypes[] = { /* get data type from token */ static const CO_GTWA_dataType_t *CO_GTWA_getDataType(char *token, bool_t *err) { if ((token != NULL) && (*err == false)) { - int i; - int len = sizeof(dataTypes) / sizeof(CO_GTWA_dataType_t); + uint32_t i; + uint32_t len = sizeof(dataTypes) / sizeof(CO_GTWA_dataType_t); for (i = 0; i < len; i++) { const CO_GTWA_dataType_t *dt = &dataTypes[i]; @@ -479,8 +479,8 @@ static const errorDescs_t errorDescsSDO[] = { static void responseWithError(CO_GTWA_t *gtwa, CO_GTWA_respErrorCode_t respErrorCode) { - int i; - int len = sizeof(errorDescs) / sizeof(errorDescs_t); + uint32_t i; + uint32_t len = sizeof(errorDescs) / sizeof(errorDescs_t); const char *desc = "-"; for (i = 0; i < len; i++) { @@ -490,7 +490,7 @@ static void responseWithError(CO_GTWA_t *gtwa, } } - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] ERROR:%d #%s\r\n", gtwa->sequence, respErrorCode, desc); respBufTransfer(gtwa); @@ -501,8 +501,8 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, CO_SDO_abortCode_t abortCode, bool_t postponed) { - int i; - int len = sizeof(errorDescsSDO) / sizeof(errorDescs_t); + uint32_t i; + uint32_t len = sizeof(errorDescsSDO) / sizeof(errorDescs_t); const char *desc = "-"; for (i = 0; i < len; i++) { @@ -513,12 +513,12 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, } if (!postponed) { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] ERROR:0x%08X #%s\r\n", gtwa->sequence, abortCode, desc); } else { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "\n...ERROR:0x%08X #%s\r\n", abortCode, desc); } @@ -531,7 +531,7 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, static inline void responseWithError(CO_GTWA_t *gtwa, CO_GTWA_respErrorCode_t respErrorCode) { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] ERROR:%d\r\n", gtwa->sequence, respErrorCode); respBufTransfer(gtwa); @@ -543,12 +543,12 @@ static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, bool_t postponed) { if (!postponed) { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] ERROR:0x%08X\r\n", gtwa->sequence, abortCode); } else { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "\n...ERROR:0x%08X\r\n", abortCode); } @@ -560,7 +560,7 @@ static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, static inline void responseWithOK(CO_GTWA_t *gtwa) { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] OK\r\n", gtwa->sequence); respBufTransfer(gtwa); @@ -568,7 +568,7 @@ static inline void responseWithOK(CO_GTWA_t *gtwa) { static inline void responseWithEmpty(CO_GTWA_t *gtwa) { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "\r\n"); respBufTransfer(gtwa); } @@ -796,7 +796,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - gtwa->net_default = value; + gtwa->net_default = (int32_t)value; responseWithOK(gtwa); } /* 'set node ' */ @@ -818,7 +818,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - gtwa->node_default = value; + gtwa->node_default = (int16_t)value; responseWithOK(gtwa); } #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 @@ -1262,7 +1262,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (strcmp(tok, "lss_conf_bitrate") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t tableIndex; - int maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / + uint32_t maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / sizeof(CO_LSS_bitTimingTableLookup[0])) - 1; if ((closed != 0U)|| NodeErr) { @@ -1448,7 +1448,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* If timeout not specified, use 100ms. Should work in most cases */ - gtwa->lssTimeout_ms = (timeout_ms == 0) ? 100 : timeout_ms; + gtwa->lssTimeout_ms = (timeout_ms == 0U) ? 100U : timeout_ms; CO_LSSmaster_changeTimeout(gtwa->LSSmaster, gtwa->lssTimeout_ms); gtwa->lssNodeCount = 0; gtwa->lssSubState = 0; @@ -1488,7 +1488,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_LSSmaster_fastscan_t *fs = >wa->lssFastscan; CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->scan[CO_LSS_FASTSCAN_VENDOR_ID] = getU32(tok, 0, 2, &err); + fs->scan[CO_LSS_FASTSCAN_VENDOR_ID] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } @@ -1500,7 +1500,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->scan[CO_LSS_FASTSCAN_PRODUCT] = getU32(tok, 0, 2, &err); + fs->scan[CO_LSS_FASTSCAN_PRODUCT] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } @@ -1512,7 +1512,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->scan[CO_LSS_FASTSCAN_REV] = getU32(tok, 0, 2, &err); + fs->scan[CO_LSS_FASTSCAN_REV] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } @@ -1524,7 +1524,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->scan[CO_LSS_FASTSCAN_SERIAL] = getU32(tok, 0, 2, &err); + fs->scan[CO_LSS_FASTSCAN_SERIAL] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } @@ -1658,7 +1658,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* write response head first */ if (!gtwa->SDOdataCopyStatus) { - gtwa->respBufCount = snprintf(gtwa->respBuf, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE - 2, "[%"PRId32"] ", gtwa->sequence); @@ -1877,12 +1877,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (ret == CO_LSSmaster_OK) { if (gtwa->lssInquireCs == CO_LSS_INQUIRE_NODE_ID) { gtwa->respBufCount = - snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%02"PRIX32"\r\n", gtwa->sequence, value & 0xFF); } else { gtwa->respBufCount = - snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%08"PRIX32"\r\n", gtwa->sequence, value); } @@ -1903,7 +1903,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (ret != CO_LSSmaster_WAIT_SLAVE) { if (ret == CO_LSSmaster_OK) { gtwa->respBufCount = - snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", gtwa->sequence, @@ -1928,7 +1928,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (ret != CO_LSSmaster_WAIT_SLAVE) { if ((ret == CO_LSSmaster_OK) || (ret == CO_LSSmaster_SCAN_FINISHED)) { gtwa->respBufCount = - snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", gtwa->sequence, @@ -1960,7 +1960,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if ((ret == CO_LSSmaster_OK) || (ret == CO_LSSmaster_SCAN_NOACK)) { /* no (more) nodes found, send report sum and finish */ gtwa->respBufCount = - snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "# Found %d nodes, search finished.\n" \ "[%"PRId32"] OK\r\n", gtwa->lssNodeCount, @@ -2055,7 +2055,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* send report */ gtwa->respBufCount = - snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "# Node-ID %d assigned to: 0x%08"PRIX32" 0x%08" \ PRIX32" 0x%08"PRIX32" 0x%08"PRIX32"\n%s", lssNidAssigned, @@ -2126,7 +2126,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, i = 4; } else { - i = (CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2) + + i = (CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2U) + CO_LED_GREEN(gtwa->LEDs, CO_LED_CANopen); } if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1)) { @@ -2134,7 +2134,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } if (i != gtwa->ledStringPreviousIndex) { - gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "%s", CO_GTWA_LED_PRINTOUTS[i]); respBufTransfer(gtwa); gtwa->ledStringPreviousIndex = i; From b73f3c1cf2502ac315cc845c006ab428e3ab397a Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 09:42:45 +0200 Subject: [PATCH 424/520] CO_gateway_ascii: static analysis: cannot assign a composite expression of type 'unsigned16' to an object of wider type 'unsigned32' [MISRA 2012 Rule 10.6, required] --- 309/CO_gateway_ascii.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 4097b6af..6e546f3a 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -922,8 +922,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* setup client */ SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, - CO_CAN_ID_SDO_CLI + gtwa->node, - CO_CAN_ID_SDO_SRV + gtwa->node, + (uint32_t)CO_CAN_ID_SDO_CLI + gtwa->node, + (uint32_t)CO_CAN_ID_SDO_SRV + gtwa->node, gtwa->node); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; @@ -991,8 +991,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* setup client */ SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, - CO_CAN_ID_SDO_CLI + gtwa->node, - CO_CAN_ID_SDO_SRV + gtwa->node, + (uint32_t)CO_CAN_ID_SDO_CLI + gtwa->node, + (uint32_t)CO_CAN_ID_SDO_SRV + gtwa->node, gtwa->node); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; From 4db6676aebd4c6b654f3bb72064a954fed1f3b25 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 09:45:18 +0200 Subject: [PATCH 425/520] CO_gateway_ascii: static analysis: initializing 'char *' with an expression of type 'const char [x]' discards qualifiers --- 309/CO_gateway_ascii.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 6e546f3a..cc4fa55d 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -324,26 +324,26 @@ static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 /* data types for SDO read or write */ static const CO_GTWA_dataType_t dataTypes[] = { - {"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */ - {"b", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* BOOLEAN */ - {"i8", 1, CO_fifo_readI82a, CO_fifo_cpyTok2I8}, /* INTEGER8 */ - {"i16", 2, CO_fifo_readI162a, CO_fifo_cpyTok2I16}, /* INTEGER16 */ - {"i32", 4, CO_fifo_readI322a, CO_fifo_cpyTok2I32}, /* INTEGER32 */ - {"i64", 8, CO_fifo_readI642a, CO_fifo_cpyTok2I64}, /* INTEGER64 */ - {"u8", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ - {"u16", 2, CO_fifo_readU162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ - {"u32", 4, CO_fifo_readU322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ - {"u64", 8, CO_fifo_readU642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ - {"x8", 1, CO_fifo_readX82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ - {"x16", 2, CO_fifo_readX162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ - {"x32", 4, CO_fifo_readX322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ - {"x64", 8, CO_fifo_readX642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ - {"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */ - {"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */ - {"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}, /* VISIBLE_STRING */ - {"os", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* OCTET_STRING base64*/ - {"us", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64},/* UNICODE_STRING base64*/ - {"d", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64} /* DOMAIN - base64 */ + {(char *)"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */ + {(char *)"b", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* BOOLEAN */ + {(char *)"i8", 1, CO_fifo_readI82a, CO_fifo_cpyTok2I8}, /* INTEGER8 */ + {(char *)"i16", 2, CO_fifo_readI162a, CO_fifo_cpyTok2I16}, /* INTEGER16 */ + {(char *)"i32", 4, CO_fifo_readI322a, CO_fifo_cpyTok2I32}, /* INTEGER32 */ + {(char *)"i64", 8, CO_fifo_readI642a, CO_fifo_cpyTok2I64}, /* INTEGER64 */ + {(char *)"u8", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ + {(char *)"u16", 2, CO_fifo_readU162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ + {(char *)"u32", 4, CO_fifo_readU322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ + {(char *)"u64", 8, CO_fifo_readU642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ + {(char *)"x8", 1, CO_fifo_readX82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ + {(char *)"x16", 2, CO_fifo_readX162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ + {(char *)"x32", 4, CO_fifo_readX322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ + {(char *)"x64", 8, CO_fifo_readX642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ + {(char *)"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */ + {(char *)"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */ + {(char *)"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}, /* VISIBLE_STRING */ + {(char *)"os", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* OCTET_STRING base64*/ + {(char *)"us", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64},/* UNICODE_STRING base64*/ + {(char *)"d", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64} /* DOMAIN - base64 */ }; From 8c798fbf20ca5f63dfd0bda289dc91392dcbbd5a Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 10:08:52 +0200 Subject: [PATCH 426/520] CO_gateway_ascii: static analysis: an value cannot be used together as operands [MISRA 2012 Rule 10.4, required] --- 303/CO_LEDs.c | 52 +++++++++++----------- 303/CO_LEDs.h | 24 ++++++----- 309/CO_gateway_ascii.c | 98 +++++++++++++++++++++--------------------- 309/CO_gateway_ascii.h | 4 +- 4 files changed, 91 insertions(+), 87 deletions(-) diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 2b82414e..56c67751 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -76,43 +76,43 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, rd = 0; gr = 0; - if ((LEDs->LEDred & (uint8_t)CO_LED_blink) == 0U) { rd |= (uint8_t)CO_LED_blink; } - else { gr |= (uint8_t)CO_LED_blink; } + if ((LEDs->LEDred & CO_LED_blink) == 0U) { rd |= CO_LED_blink; } + else { gr |= CO_LED_blink; } switch (++LEDs->LEDtmrflash_1) { - case 1: rd |= (uint8_t)CO_LED_flash_1; break; - case 2: gr |= (uint8_t)CO_LED_flash_1; break; + case 1: rd |= CO_LED_flash_1; break; + case 2: gr |= CO_LED_flash_1; break; case 6: LEDs->LEDtmrflash_1 = 0; break; default: /* none */ break; } switch (++LEDs->LEDtmrflash_2) { - case 1: case 3: rd |= (uint8_t)CO_LED_flash_2; break; - case 2: case 4: gr |= (uint8_t)CO_LED_flash_2; break; + case 1: case 3: rd |= CO_LED_flash_2; break; + case 2: case 4: gr |= CO_LED_flash_2; break; case 8: LEDs->LEDtmrflash_2 = 0; break; default: /* none */ break; } switch (++LEDs->LEDtmrflash_3) { - case 1: case 3: case 5: rd |= (uint8_t)CO_LED_flash_3; break; - case 2: case 4: case 6: gr |= (uint8_t)CO_LED_flash_3; break; + case 1: case 3: case 5: rd |= CO_LED_flash_3; break; + case 2: case 4: case 6: gr |= CO_LED_flash_3; break; case 10: LEDs->LEDtmrflash_3 = 0; break; default: /* none */ break; } switch (++LEDs->LEDtmrflash_4) { - case 1: case 3: case 5: case 7: rd |= (uint8_t)CO_LED_flash_4; break; - case 2: case 4: case 6: case 8: gr |= (uint8_t)CO_LED_flash_4; break; + case 1: case 3: case 5: case 7: rd |= CO_LED_flash_4; break; + case 2: case 4: case 6: case 8: gr |= CO_LED_flash_4; break; case 12: LEDs->LEDtmrflash_4 = 0; break; default: /* none */ break; } } else { /* clear flicker and CANopen bits, keep others */ - rd = LEDs->LEDred & (0xFFU ^ ((uint8_t)CO_LED_flicker | (uint8_t)CO_LED_CANopen)); - gr = LEDs->LEDgreen & (0xFFU ^ ((uint8_t)CO_LED_flicker | (uint8_t)CO_LED_CANopen)); + rd = LEDs->LEDred & (0xFFU ^ (CO_LED_flicker | CO_LED_CANopen)); + gr = LEDs->LEDgreen & (0xFFU ^ (CO_LED_flicker | CO_LED_CANopen)); } /* calculate 10Hz flickering */ - if (rdFlickerNext) { rd |= (uint8_t)CO_LED_flicker; } - else { gr |= (uint8_t)CO_LED_flicker; } + if (rdFlickerNext) { rd |= CO_LED_flicker; } + else { gr |= CO_LED_flicker; } } /* while (LEDs->LEDtmr50ms >= 50000) */ @@ -121,24 +121,24 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, /* CANopen red ERROR LED */ if (ErrCANbusOff) { rd_co = 1;} - else if (NMTstate == CO_NMT_INITIALIZING){ rd_co = rd & (uint8_t)CO_LED_flicker;} - else if (ErrRpdo) { rd_co = rd & (uint8_t)CO_LED_flash_4;} - else if (ErrSync) { rd_co = rd & (uint8_t)CO_LED_flash_3;} - else if (ErrHbCons) { rd_co = rd & (uint8_t)CO_LED_flash_2;} - else if (ErrCANbusWarn) { rd_co = rd & (uint8_t)CO_LED_flash_1;} - else if (ErrOther) { rd_co = rd & (uint8_t)CO_LED_blink;} + else if (NMTstate == CO_NMT_INITIALIZING){ rd_co = rd & CO_LED_flicker;} + else if (ErrRpdo) { rd_co = rd & CO_LED_flash_4;} + else if (ErrSync) { rd_co = rd & CO_LED_flash_3;} + else if (ErrHbCons) { rd_co = rd & CO_LED_flash_2;} + else if (ErrCANbusWarn) { rd_co = rd & CO_LED_flash_1;} + else if (ErrOther) { rd_co = rd & CO_LED_blink;} else { rd_co = 0;} /* CANopen green RUN LED */ - if (LSSconfig) {gr_co = gr & (uint8_t)CO_LED_flicker;} - else if (firmwareDownload) {gr_co = gr & (uint8_t)CO_LED_flash_3;} - else if (NMTstate == CO_NMT_STOPPED) {gr_co = gr & (uint8_t)CO_LED_flash_1;} - else if (NMTstate == CO_NMT_PRE_OPERATIONAL){gr_co = gr & (uint8_t)CO_LED_blink;} + if (LSSconfig) {gr_co = gr & CO_LED_flicker;} + else if (firmwareDownload) {gr_co = gr & CO_LED_flash_3;} + else if (NMTstate == CO_NMT_STOPPED) {gr_co = gr & CO_LED_flash_1;} + else if (NMTstate == CO_NMT_PRE_OPERATIONAL){gr_co = gr & CO_LED_blink;} else if (NMTstate == CO_NMT_OPERATIONAL) {gr_co = 1;} else {gr_co = 0;} - if (rd_co != 0U) { rd |= (uint8_t)CO_LED_CANopen; } - if (gr_co != 0U) { gr |= (uint8_t)CO_LED_CANopen; } + if (rd_co != 0U) { rd |= CO_LED_CANopen; } + if (gr_co != 0U) { gr |= CO_LED_CANopen; } LEDs->LEDred = rd; LEDs->LEDgreen = gr; } /* if (tick) */ diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index ffc8a6dc..185e8a56 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -73,16 +73,20 @@ extern "C" { * available for implementing custom leds. */ -/** Bitfield for combining with red or green led */ -typedef enum { - CO_LED_flicker = 0x01U, /**< LED flickering 10Hz */ - CO_LED_blink = 0x02U, /**< LED blinking 2,5Hz */ - CO_LED_flash_1 = 0x04U, /**< LED single flash */ - CO_LED_flash_2 = 0x08U, /**< LED double flash */ - CO_LED_flash_3 = 0x10U, /**< LED triple flash */ - CO_LED_flash_4 = 0x20U, /**< LED quadruple flash */ - CO_LED_CANopen = 0x80U /**< LED CANopen according to CiA 303-3 */ -} CO_LED_BITFIELD_t; +/** + * @defgroup CO_LED_BITFIELD_t Bitfield for combining with red or green led + * @{ + * + */ +#define CO_LED_flicker 0x01U /**< LED flickering 10Hz */ +#define CO_LED_blink 0x02U /**< LED blinking 2,5Hz */ +#define CO_LED_flash_1 0x04U /**< LED single flash */ +#define CO_LED_flash_2 0x08U /**< LED double flash */ +#define CO_LED_flash_3 0x10U /**< LED triple flash */ +#define CO_LED_flash_4 0x20U /**< LED quadruple flash */ +#define CO_LED_CANopen 0x80U /**< LED CANopen according to CiA 303-3 */ + +/** @} */ /* CO_LED_BITFIELD_t */ /** Get on/off state for green led for specified bitfield */ #define CO_LED_RED(LEDs, BITFIELD) ((((LEDs)->LEDred & BITFIELD) != 0U) ? 1U : 0U) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index cc4fa55d..721e3ff9 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -69,7 +69,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, /* verify arguments */ if ((gtwa == NULL) #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 - || (SDO_C == NULL) || (SDOclientTimeoutTime_ms == 0) + || (SDO_C == NULL) || (SDOclientTimeoutTime_ms == 0U) #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 || (NMT == NULL) @@ -142,7 +142,7 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { if ((gtwa != NULL) && (message != NULL)) { const char *c; - for (c = &message[0]; *c != 0; c++) { + for (c = &message[0]; *c != '\0'; c++) { CO_fifo_putc_ov(>wa->logFifo, (const uint8_t)*c); } } @@ -225,7 +225,7 @@ static const char CO_GTWA_helpStringLss[] = #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 -#define CO_GTWA_LED_PRINTOUTS_SIZE 5 +#define CO_GTWA_LED_PRINTOUTS_SIZE 5U static const char *CO_GTWA_LED_PRINTOUTS[CO_GTWA_LED_PRINTOUTS_SIZE] = { " CANopen status LEDs: R G \r", " CANopen status LEDs: R G* \r", @@ -262,7 +262,7 @@ static bool_t checkNetNode(CO_GTWA_t *gtwa, eCode = CO_GTWA_respErrorNoDefaultNodeSet; e = true; } - else if ((node < NodeMin) || (node > 127)) { + else if ((node < (int16_t)NodeMin) || (node > (int16_t)127)) { eCode = CO_GTWA_respErrorUnsupportedNode; e = true; } @@ -397,7 +397,7 @@ static bool_t respBufTransfer(CO_GTWA_t *gtwa) { gtwa->respHold = false; } } - return connectionOK != 0; + return connectionOK != 0U; } @@ -602,7 +602,7 @@ static inline void convertToLower(char *token, size_t maxCount) { char *c = &token[0]; for (i = 0; i < maxCount; i++) { - if (*c == 0) { + if (*c == '\0') { break; } else { *c = (char)tolower((int)*c); @@ -671,22 +671,22 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); /* Break if error in token or token was found, but closed with * command delimiter. */ - if (err || ((n > 0) && (closed != 0U))) { + if (err || ((n > 0U) && (closed != 0U))) { err = true; break; } /* If empty line or just comment, continue with next command */ - else if ((n == 0) && (closed != 0U)) { + else if ((n == 0U) && (closed != 0U)) { responseWithEmpty(gtwa); continue; } else { /* MISRA C 2004 14.10 */ } - if ((tok[0] != '[') || (tok[strlen(tok)-1] != ']')) { + if ((tok[0] != '[') || (tok[strlen(tok)-1U] != ']')) { err = true; break; } - tok[strlen(tok)-1] = '\0'; + tok[strlen(tok)-1U] = '\0'; gtwa->sequence = getU32(tok + 1, 0, 0xFFFFFFFFU, &err); if (err) { break; @@ -699,11 +699,11 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 0xFFU; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - if (err || (n == 0)) { + if (err || (n == 0U)) { /* empty token, break on error */ err = true; break; - } else if (isdigit((int)tok[0]) == 0) { + } else if ((int)isdigit((int)tok[0]) == (int)0) { /* found */ break; } else if (closed != 0U) { @@ -726,7 +726,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, case 0: /* only (pointed by token) */ break; case 1: /* and tokens */ - if (ui[0] > 127) { + if (ui[0] > 127U) { err = true; respErrorCode = CO_GTWA_respErrorUnsupportedNode; } @@ -735,11 +735,11 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } break; case 2: /* , and tokens */ - if (ui[0] > 0xFFFF) { + if (ui[0] > 0xFFFFU) { err = true; respErrorCode = CO_GTWA_respErrorUnsupportedNet; } - else if (ui[1] > 127) { + else if (ui[1] > 127U) { err = true; respErrorCode = CO_GTWA_respErrorUnsupportedNode; } @@ -863,7 +863,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - gtwa->SDOblockTransferEnable = (value==1) ? true : false; + gtwa->SDOblockTransferEnable = (value==1U) ? true : false; responseWithOK(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ @@ -900,7 +900,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); - if (err || (n == 0)) { + if (err || (n == 0U)) { err = true; break; } @@ -1017,13 +1017,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, >wa->commFifo, &status); /* set to true, if command delimiter was found */ - closed = ((status & CO_fifo_st_closed) == 0) ? 0U : 1U; + closed = ((status & CO_fifo_st_closed) == 0U) ? 0U : 1U; /* set to true, if data are copied only partially */ - gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0; + gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0U; /* is syntax error in command or size is zero or not the last token * in command */ - if (((status & CO_fifo_st_errMask) != 0) || (size == 0) + if (((status & CO_fifo_st_errMask) != 0U) || (size == 0U) || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U)) ) { err = true; @@ -1031,7 +1031,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* if data size was not known before and is known now, update SDO */ - if ((gtwa->SDOdataType->length == 0) && !gtwa->SDOdataCopyStatus) { + if ((gtwa->SDOdataType->length == 0U) && !gtwa->SDOdataCopyStatus) { CO_SDOclientDownloadInitiateSize(gtwa->SDO_C, size); } @@ -1173,7 +1173,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - if (select == 0) { + if (select == 0U) { /* send non-confirmed message */ CO_LSSmaster_return_t ret; ret = CO_LSSmaster_switchStateDeselect(gtwa->LSSmaster); @@ -1245,7 +1245,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); gtwa->lssNID = (uint8_t)getU32(tok, 0, 0xFF, &err); - if ((gtwa->lssNID > 0x7F) && (gtwa->lssNID < 0xFF)) { + if ((gtwa->lssNID > 0x7FU) && (gtwa->lssNID < 0xFFU)) { err = true; } if (err) { @@ -1263,7 +1263,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t tableIndex; uint32_t maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / - sizeof(CO_LSS_bitTimingTableLookup[0])) - 1; + sizeof(CO_LSS_bitTimingTableLookup[0])) - 1U; if ((closed != 0U)|| NodeErr) { err = true; @@ -1280,7 +1280,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, closed = 1U; CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); tableIndex = (uint8_t)getU32(tok, 0, maxIndex, &err); - if (tableIndex == 5) { + if (tableIndex == 5U) { err = true; } if (err) { @@ -1402,7 +1402,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* If timeout not specified, use 100ms. Should work in most cases */ - if (timeout_ms == 0) { + if (timeout_ms == 0U) { timeout_ms = 100; } CO_LSSmaster_changeTimeout(gtwa->LSSmaster, timeout_ms); @@ -1646,7 +1646,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, &sizeTransferred, timerNext_us); - if (ret < 0) { + if (ret < CO_SDO_RT_ok_communicationEnd) { responseWithErrorSDO(gtwa, abortCode, gtwa->SDOdataCopyStatus); gtwa->state = CO_GTWA_ST_IDLE; } @@ -1659,7 +1659,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* write response head first */ if (!gtwa->SDOdataCopyStatus) { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, - CO_GTWA_RESP_BUF_SIZE - 2, + CO_GTWA_RESP_BUF_SIZE - 2U, "[%"PRId32"] ", gtwa->sequence); gtwa->SDOdataCopyStatus = true; @@ -1673,14 +1673,14 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->respBufCount += gtwa->SDOdataType->dataTypePrint( >wa->SDO_C->bufFifo, >wa->respBuf[gtwa->respBufCount], - CO_GTWA_RESP_BUF_SIZE - 2 - gtwa->respBufCount, + CO_GTWA_RESP_BUF_SIZE - 2U - gtwa->respBufCount, ret == CO_SDO_RT_ok_communicationEnd); fifoRemain = CO_fifo_getOccupied(>wa->SDO_C->bufFifo); /* end of communication, print newline and enter idle state */ - if ((ret == CO_SDO_RT_ok_communicationEnd) && (fifoRemain == 0)) { + if ((ret == CO_SDO_RT_ok_communicationEnd) && (fifoRemain == 0U)) { gtwa->respBufCount += - sprintf(>wa->respBuf[gtwa->respBufCount], "\r\n"); + (size_t)sprintf(>wa->respBuf[gtwa->respBufCount], "\r\n"); gtwa->state = CO_GTWA_ST_IDLE; } @@ -1698,7 +1698,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_IDLE; break; } - } while ((gtwa->respHold == false) && (fifoRemain > 0)); + } while ((gtwa->respHold == false) && (fifoRemain > 0U)); } else { /* MISRA C 2004 14.10 */ } break; @@ -1720,12 +1720,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, >wa->commFifo, &status); /* set to true, if command delimiter was found */ - closed = ((status & CO_fifo_st_closed) == 0) ? 0U : 1U; + closed = ((status & CO_fifo_st_closed) == 0U) ? 0U : 1U; /* set to true, if data are copied only partially */ - gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0; + gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0U; /* is syntax error in command or not the last token in command */ - if (((status & CO_fifo_st_errMask) != 0) + if (((status & CO_fifo_st_errMask) != 0U) || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U)) ) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; @@ -1749,7 +1749,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * timeout */ if (gtwa->SDOdataCopyStatus && (CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < - (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7)) + (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7U)) ) { if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; @@ -1762,7 +1762,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } if (!hold || abort_comm) { /* if OS has CANtx queue, speedup block transfer */ - int loop = 0; + uint32_t loop = 0; do { ret = CO_SDOclientDownload(gtwa->SDO_C, timeDifference_us, @@ -1777,7 +1777,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } while (ret == CO_SDO_RT_blockDownldInProgress); /* send response in case of error or finish */ - if (ret < 0) { + if (ret < CO_SDO_RT_ok_communicationEnd) { responseWithErrorSDO(gtwa, abortCode, false); /* purge remaining data if necessary */ gtwa->state = gtwa->SDOdataCopyStatus @@ -1879,7 +1879,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%02"PRIX32"\r\n", - gtwa->sequence, value & 0xFF); + gtwa->sequence, value & 0xFFU); } else { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, @@ -1949,7 +1949,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } case CO_GTWA_ST_LSS_ALLNODES: { CO_LSSmaster_return_t ret; - if (gtwa->lssSubState == 0) { /* _lss_fastscan */ + if (gtwa->lssSubState == 0U) { /* _lss_fastscan */ ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, timeDifference_us, >wa->lssFastscan); @@ -1979,14 +1979,14 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } } - if (gtwa->lssSubState == 1) { /* lss_set_node */ + if (gtwa->lssSubState == 1U) { /* lss_set_node */ ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster, timeDifference_us, gtwa->lssNID); if (ret != CO_LSSmaster_WAIT_SLAVE) { if (ret == CO_LSSmaster_OK) { /* next sub-step */ - gtwa->lssSubState += gtwa->lssStore ? 1 : 2; + gtwa->lssSubState += gtwa->lssStore ? 1U : 2U; } else { /* error occurred */ @@ -2001,7 +2001,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } } - if (gtwa->lssSubState == 2) { /* lss_store */ + if (gtwa->lssSubState == 2U) { /* lss_store */ ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, timeDifference_us); if (ret != CO_LSSmaster_WAIT_SLAVE) { @@ -2023,7 +2023,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } } - if (gtwa->lssSubState >= 3) { /* lss_switch_glob 0 */ + if (gtwa->lssSubState >= 3U) { /* lss_switch_glob 0 */ /* send non-confirmed message */ ret = CO_LSSmaster_switchStateDeselect(gtwa->LSSmaster); if (ret != CO_LSSmaster_OK) { @@ -2036,11 +2036,11 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, uint8_t lssNidAssigned = gtwa->lssNID; const char msg2Fmt[] = "# Not all nodes scanned!\n" \ "[%"PRId32"] OK\r\n"; - char msg2[sizeof(msg2Fmt)+10] = {0}; + char msg2[sizeof(msg2Fmt)+10U] = {0}; /* increment variables, check end-of-nodeId */ gtwa->lssNodeCount++; - if (gtwa->lssNID < 127) { + if (gtwa->lssNID < 127U) { /* repeat cycle with next node-id */ gtwa->lssNID++; CO_LSSmaster_changeTimeout(gtwa->LSSmaster, @@ -2080,7 +2080,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, CO_GTWA_RESP_BUF_SIZE, NULL); respBufTransfer(gtwa); - if (CO_fifo_getOccupied(>wa->logFifo) == 0) { + if (CO_fifo_getOccupied(>wa->logFifo) == 0U) { gtwa->state = CO_GTWA_ST_IDLE; break; } @@ -2129,8 +2129,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, i = (CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2U) + CO_LED_GREEN(gtwa->LEDs, CO_LED_CANopen); } - if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1)) { - i = CO_GTWA_LED_PRINTOUTS_SIZE - 1; + if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1U)) { + i = CO_GTWA_LED_PRINTOUTS_SIZE - 1U; } if (i != gtwa->ledStringPreviousIndex) { diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 79b553be..290f9c6a 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -149,13 +149,13 @@ lss_allnodes [ [ \\ /** Size of response string buffer. This is intermediate buffer. If there is * larger amount of data to transfer, then multiple transfers will occur. */ #ifndef CO_GTWA_RESP_BUF_SIZE -#define CO_GTWA_RESP_BUF_SIZE 200 +#define CO_GTWA_RESP_BUF_SIZE 200U #endif /** Timeout time in microseconds for some internal states. */ #ifndef CO_GTWA_STATE_TIMEOUT_TIME_US -#define CO_GTWA_STATE_TIMEOUT_TIME_US 1200000 +#define CO_GTWA_STATE_TIMEOUT_TIME_US 1200000U #endif From 3a414a3b171c454e9bda6587813cd7c22840898e Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 10:11:06 +0200 Subject: [PATCH 427/520] CO_gateway_ascii: static analysis: use of modifier or type 'int' outside of a typedef [MISRA 2012 Directive 4.6, advisory] --- 309/CO_gateway_ascii.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 721e3ff9..70ea3000 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -661,7 +661,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, char tok[20]; size_t n; uint32_t ui[3]; - int i; + int32_t i; int32_t net = gtwa->net_default; int16_t node = gtwa->node_default; From 646eac142bd9f943af31827c52afde091797df6c Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 10:16:31 +0200 Subject: [PATCH 428/520] CO_gateway_ascii: static analysis: ignoring return value of functions [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] --- 309/CO_gateway_ascii.c | 102 ++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 70ea3000..721930f9 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -493,7 +493,7 @@ static void responseWithError(CO_GTWA_t *gtwa, gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] ERROR:%d #%s\r\n", gtwa->sequence, respErrorCode, desc); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 @@ -523,7 +523,7 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, abortCode, desc); } - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ @@ -534,7 +534,7 @@ static inline void responseWithError(CO_GTWA_t *gtwa, gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] ERROR:%d\r\n", gtwa->sequence, respErrorCode); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 @@ -553,7 +553,7 @@ static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, abortCode); } - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */ @@ -563,14 +563,14 @@ static inline void responseWithOK(CO_GTWA_t *gtwa) { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] OK\r\n", gtwa->sequence); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } static inline void responseWithEmpty(CO_GTWA_t *gtwa) { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "\r\n"); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } @@ -641,7 +641,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (gtwa->respHold) { timeDifference_us += gtwa->timeDifference_us_cumulative; - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); if (gtwa->respHold) { gtwa->timeDifference_us_cumulative = timeDifference_us; return; @@ -771,7 +771,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* command 2 */ closed = 0xFFU; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err) { break; } @@ -788,7 +788,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, CO_CONFIG_GTW_NET_MIN, CO_CONFIG_GTW_NET_MAX, &err); @@ -811,7 +811,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint8_t)getU32(tok, 1, 127, &err); if (err) { @@ -834,7 +834,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, 1, 0xFFFF, &err); if (err) { @@ -856,7 +856,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, 0, 1, &err); if (err) { @@ -889,7 +889,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* index */ closed = 0U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) { break; @@ -908,7 +908,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* optional data type */ if (closed == 0U) { closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); convertToLower(tok, sizeof(tok)); gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err); @@ -964,7 +964,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* index */ closed = 0U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) { break; @@ -981,7 +981,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* data type */ closed = 0U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); convertToLower(tok, sizeof(tok)); gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err); @@ -1124,7 +1124,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* command 2 */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err) { break; } @@ -1167,7 +1167,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* get value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); select = (uint8_t)getU32(tok, 0, 1, &err); if (err) { break; @@ -1204,26 +1204,26 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* get values */ closed = 0U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.vendorID = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.productCode = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.revisionNumber = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); addr->identity.serialNumber = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; @@ -1243,7 +1243,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* get value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); gtwa->lssNID = (uint8_t)getU32(tok, 0, 0xFF, &err); if ((gtwa->lssNID > 0x7FU) && (gtwa->lssNID < 0xFFU)) { err = true; @@ -1273,12 +1273,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* First parameter is table selector. We only support the CiA * bit timing table from CiA301 ("0") */ closed = 0U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); (void)getU32(tok, 0, 0, &err); /* get value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); tableIndex = (uint8_t)getU32(tok, 0, maxIndex, &err); if (tableIndex == 5U) { err = true; @@ -1305,7 +1305,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* get value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); switchDelay = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) { break; @@ -1347,7 +1347,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, uint8_t lsssub; /* get value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); lsssub = (uint8_t)getU32(tok, 0, 3, &err); if (err) { break; @@ -1394,7 +1394,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (closed == 0U) { /* get value */ closed = 1U; - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) { break; @@ -1440,7 +1440,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (closed == 0U) { /* get optional token timeout (non standard) */ closed = 0xFFU; - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) { break; @@ -1465,14 +1465,14 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } if (closed == 0U) { /* more arguments follow */ - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); gtwa->lssNID = (uint8_t)getU32(tok, 1, 127, &err); if (err) { break; } closed = 0xFFU; - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); gtwa->lssStore = (bool_t)getU32(tok, 0, 1, &err); if (err) { break; @@ -1487,50 +1487,50 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* more arguments follow */ CO_LSSmaster_fastscan_t *fs = >wa->lssFastscan; - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_VENDOR_ID] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.vendorID = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_PRODUCT] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.productCode = getU32(tok,0,0xFFFFFFFFU, &err); if (err) { break; } - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_REV] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.revisionNumber=getU32(tok,0,0xFFFFFFFFU,&err); if (err) { break; } - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->scan[CO_LSS_FASTSCAN_SERIAL] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } closed = 1U; - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); fs->match.identity.serialNumber = getU32(tok,0,0xFFFFFFFFU,&err); if (err) { break; @@ -1562,7 +1562,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else { /* get second token */ closed = 1U; - CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); if (err) { break; } @@ -1619,7 +1619,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* delete command, if it was only partially read */ if(closed == 0U) { - CO_fifo_CommSearch(>wa->commFifo, true); + (void)CO_fifo_CommSearch(>wa->commFifo, true); } gtwa->state = CO_GTWA_ST_IDLE; } @@ -1688,7 +1688,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (respBufTransfer(gtwa) == false) { /* broken communication, send SDO abort and force finish. */ abortCode = CO_SDO_AB_DATA_TRANSF; - CO_SDOclientUpload(gtwa->SDO_C, + (void)CO_SDOclientUpload(gtwa->SDO_C, 0, true, &abortCode, @@ -1732,7 +1732,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, abort_comm = true; /* abort SDO communication */ /* clear the rest of the command, if necessary */ if (closed != 1U) { - CO_fifo_CommSearch(>wa->commFifo, true); + (void)CO_fifo_CommSearch(>wa->commFifo, true); } } if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) { @@ -1886,7 +1886,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, "[%"PRId32"] 0x%08"PRIX32"\r\n", gtwa->sequence, value); } - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } else { responseLSS(gtwa, ret); @@ -1911,7 +1911,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->lssAddress.identity.productCode, gtwa->lssAddress.identity.revisionNumber, gtwa->lssAddress.identity.serialNumber); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } else { responseLSS(gtwa, ret); @@ -1936,7 +1936,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->lssFastscan.found.identity.productCode, gtwa->lssFastscan.found.identity.revisionNumber, gtwa->lssFastscan.found.identity.serialNumber); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } else { responseLSS(gtwa, ret); @@ -1965,7 +1965,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, "[%"PRId32"] OK\r\n", gtwa->lssNodeCount, gtwa->sequence); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); gtwa->state = CO_GTWA_ST_IDLE; } else if (ret == CO_LSSmaster_SCAN_FINISHED) { @@ -2064,7 +2064,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->lssFastscan.found.identity.revisionNumber, gtwa->lssFastscan.found.identity.serialNumber, msg2); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); } } break; @@ -2078,7 +2078,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->respBufCount = CO_fifo_read(>wa->logFifo, (uint8_t *)gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, NULL); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); if (CO_fifo_getOccupied(>wa->logFifo) == 0U) { gtwa->state = CO_GTWA_ST_IDLE; @@ -2105,7 +2105,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->respBufCount = lenCopied; gtwa->helpStringOffset += lenCopied; - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); if (gtwa->helpStringOffset == lenHelp) { gtwa->state = CO_GTWA_ST_IDLE; @@ -2136,7 +2136,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (i != gtwa->ledStringPreviousIndex) { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "%s", CO_GTWA_LED_PRINTOUTS[i]); - respBufTransfer(gtwa); + (void)respBufTransfer(gtwa); gtwa->ledStringPreviousIndex = i; } break; From b02b7424f0e8aa5108b252f5b8c58b8867be76a1 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 10:17:29 +0200 Subject: [PATCH 429/520] CANopenNode\309\CO_gateway_ascii.c(32,0): warning 537: repeated include file 'string.h' --- 309/CO_gateway_ascii.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 721930f9..2b409d27 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -24,12 +24,13 @@ * limitations under the License. */ +#include + #include "309/CO_gateway_ascii.h" #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 #include -#include #include #include #include From 0c70d4010548d855ede70fd8cbec73597a7ca06d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 10:20:16 +0200 Subject: [PATCH 430/520] CO_gateway_ascii: static analysis: operator '-' followed by operator '-' could be confusing without parentheses --- 309/CO_gateway_ascii.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 2b409d27..7f515005 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -1674,7 +1674,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->respBufCount += gtwa->SDOdataType->dataTypePrint( >wa->SDO_C->bufFifo, >wa->respBuf[gtwa->respBufCount], - CO_GTWA_RESP_BUF_SIZE - 2U - gtwa->respBufCount, + (CO_GTWA_RESP_BUF_SIZE - 2U) - gtwa->respBufCount, ret == CO_SDO_RT_ok_communicationEnd); fifoRemain = CO_fifo_getOccupied(>wa->SDO_C->bufFifo); From c5160499f82a30c524856109f95b998cb751c334 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 10:57:24 +0200 Subject: [PATCH 431/520] CO_gateway_ascii: static analysis: both sides have side effects [MISRA 2012 Rule 1.3, required] --- 309/CO_gateway_ascii.c | 83 +++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 7f515005..c1263e3c 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -763,8 +763,43 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* command is case insensitive */ convertToLower(tok, sizeof(tok)); + bool_t tok_is_set = strcmp(tok, "set") == 0; +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 + bool_t tok_is_read = strcmp(tok, "r") == 0; + tok_is_read = (strcmp(tok, "read") == 0) || tok_is_read; + bool_t tok_is_write = strcmp(tok, "w") == 0; + tok_is_write = (strcmp(tok, "write") == 0) || tok_is_write; +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 + bool_t tok_is_start = strcmp(tok, "start") == 0; + bool_t tok_is_stop = strcmp(tok, "stop") == 0; + bool_t tok_is_preop = strcmp(tok, "preop") == 0; + tok_is_preop = (strcmp(tok, "preoperational") == 0) || tok_is_preop; + bool_t tok_is_reset = strcmp(tok, "reset") == 0; +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 + bool_t tok_is_lss_switch_glob = strcmp(tok, "lss_switch_glob") == 0; + bool_t tok_is_lss_switch_sel = strcmp(tok, "lss_switch_sel") == 0; + bool_t tok_is_lss_set_node = strcmp(tok, "lss_set_node") == 0; + bool_t tok_is_lss_conf_bitrate = strcmp(tok, "lss_conf_bitrate") == 0; + bool_t tok_is_lss_activate_bitrate = strcmp(tok, "lss_activate_bitrate") == 0; + bool_t tok_is_lss_store = strcmp(tok, "lss_store") == 0; + bool_t tok_is_lss_inquire_addr= strcmp(tok, "lss_inquire_addr") == 0; + bool_t tok_is_lss_get_node = strcmp(tok, "lss_get_node") == 0; + bool_t tok_is__lss_fastscan = strcmp(tok, "_lss_fastscan") == 0; + bool_t tok_is_lss_allnodes = strcmp(tok, "lss_allnodes") == 0; +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 + bool_t tok_is_log = strcmp(tok, "log") == 0; +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 + bool_t tok_is_help = strcmp(tok, "help") == 0; +#endif +#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 + bool_t tok_is_led = strcmp(tok, "led") == 0; +#endif /* set command - multiple sub commands */ - if (strcmp(tok, "set") == 0) { + if (tok_is_set) { if (closed != 0U) { err = true; break; @@ -877,7 +912,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 /* Upload SDO command - 'r[ead] ' */ - else if ((strcmp(tok, "r") == 0) || (strcmp(tok, "read") == 0)) { + else if (tok_is_read) { uint16_t idx; uint8_t subidx; CO_SDO_return_t SDO_ret; @@ -950,7 +985,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* Download SDO comm. - w[rite] */ - else if ((strcmp(tok, "w") == 0) || (strcmp(tok, "write") == 0)) { + else if (tok_is_write) { uint16_t idx; uint8_t subidx; uint8_t status; @@ -1045,7 +1080,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 /* NMT start node - 'start' */ - else if (strcmp(tok, "start") == 0) { + else if (tok_is_start) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_OPERATIONAL; @@ -1067,7 +1102,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* NMT stop node - 'stop' */ - else if (strcmp(tok, "stop") == 0) { + else if (tok_is_stop) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_STOPPED; @@ -1089,9 +1124,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* NMT Set node to pre-operational - 'preop[erational]' */ - else if ((strcmp(tok, "preop") == 0) || - (strcmp(tok, "preoperational") == 0) - ) { + else if (tok_is_preop) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2 = CO_NMT_ENTER_PRE_OPERATIONAL; @@ -1113,7 +1146,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* NMT reset (node or communication) - 'reset '*/ - else if (strcmp(tok, "reset") == 0) { + else if (tok_is_reset) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); CO_NMT_command_t command2; @@ -1133,9 +1166,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, convertToLower(tok, sizeof(tok)); if (strcmp(tok, "node") == 0) { command2 = CO_NMT_RESET_NODE; - } else if ((strcmp(tok, "comm") == 0) || - (strcmp(tok, "communication") == 0) - ) { + } else if (strcmp(tok, "comm") == 0) { + command2 = CO_NMT_RESET_COMMUNICATION; + } else if (strcmp(tok, "communication") == 0) { command2 = CO_NMT_RESET_COMMUNICATION; } else { err = true; @@ -1157,7 +1190,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 /* Switch state global command - 'lss_switch_glob <0|1>' */ - else if (strcmp(tok, "lss_switch_glob") == 0) { + else if (tok_is_lss_switch_glob) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t select; @@ -1194,7 +1227,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* Switch state selective command - * 'lss_switch_sel ' */ - else if (strcmp(tok, "lss_switch_sel") == 0) { + else if (tok_is_lss_switch_sel) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); CO_LSS_address_t *addr = >wa->lssAddress; @@ -1234,7 +1267,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_LSS_SWITCH_SEL; } /* LSS configure node-ID command - 'lss_set_node ' */ - else if (strcmp(tok, "lss_set_node") == 0) { + else if (tok_is_lss_set_node) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); if ((closed != 0U) || NodeErr) { @@ -1260,7 +1293,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * 'lss_conf_bitrate ' * table_index: 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s, * 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto */ - else if (strcmp(tok, "lss_conf_bitrate") == 0) { + else if (tok_is_lss_conf_bitrate) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t tableIndex; uint32_t maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / @@ -1294,7 +1327,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* LSS activate new bit-rate command - * 'lss_activate_bitrate ' */ - else if (strcmp(tok, "lss_activate_bitrate") == 0) { + else if (tok_is_lss_activate_bitrate) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t switchDelay; CO_LSSmaster_return_t ret; @@ -1324,7 +1357,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } /* LSS store configuration command - 'lss_store' */ - else if (strcmp(tok, "lss_store") == 0) { + else if (tok_is_lss_store) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); if ((closed != 1U) || NodeErr) { @@ -1336,7 +1369,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->state = CO_GTWA_ST_LSS_STORE; } /* Inquire LSS address command - 'lss_inquire_addr []' */ - else if (strcmp(tok, "lss_inquire_addr") == 0) { + else if (tok_is_lss_inquire_addr) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); if (NodeErr) { @@ -1369,7 +1402,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } /* LSS inquire node-ID command - 'lss_get_node'*/ - else if (strcmp(tok, "lss_get_node") == 0) { + else if (tok_is_lss_get_node) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); if ((closed != 1U) || NodeErr) { @@ -1383,7 +1416,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* LSS identify fastscan. This is a manufacturer specific command as * the one in DSP309 is quite useless - '_lss_fastscan []'*/ - else if (strcmp(tok, "_lss_fastscan") == 0) { + else if (tok_is__lss_fastscan) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t timeout_ms = 0; @@ -1418,7 +1451,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * [ [ * * ]]' */ - else if (strcmp(tok, "lss_allnodes") == 0) { + else if (tok_is_lss_allnodes) { /* Request node enumeration by LSS identify fastscan. * This initiates node enumeration by the means of LSS fastscan * mechanism. When this function is finished: @@ -1545,7 +1578,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 /* Print message log */ - else if (strcmp(tok, "log") == 0) { + else if (tok_is_log) { if (closed == 0U) { err = true; break; @@ -1556,7 +1589,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 /* Print help */ - else if (strcmp(tok, "help") == 0) { + else if (tok_is_help) { if (closed == 1U) { gtwa->helpString = CO_GTWA_helpString; } @@ -1588,7 +1621,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 /* Print status led diodes */ - else if (strcmp(tok, "led") == 0) { + else if (tok_is_led) { if (closed == 0U) { err = true; break; From 6440f8b6b67426f990083ed037af05f2b54cf7f3 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 11:03:40 +0200 Subject: [PATCH 432/520] CO_gateway_ascii: static analysis: side effects on right hand of logical operator [MISRA 2012 Rule 13.5, required] --- 309/CO_gateway_ascii.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index c1263e3c..27423ef9 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -656,8 +656,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * COMMAND PARSER ***************************************************************************/ /* if idle, search for new command, skip comments or empty lines */ - while ((gtwa->state == CO_GTWA_ST_IDLE) - && CO_fifo_CommSearch(>wa->commFifo, false) + while (CO_fifo_CommSearch(>wa->commFifo, false) && + (gtwa->state == CO_GTWA_ST_IDLE) ) { char tok[20]; size_t n; @@ -683,7 +683,11 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } else { /* MISRA C 2004 14.10 */ } - if ((tok[0] != '[') || (tok[strlen(tok)-1U] != ']')) { + if (tok[0] != '[') { + err = true; + break; + } + if (tok[strlen(tok)-1U] != ']') { err = true; break; } @@ -1781,17 +1785,16 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* If not all data were transferred, make sure, there is enough data in * SDO buffer, to continue communication. Otherwise wait and check for * timeout */ - if (gtwa->SDOdataCopyStatus - && (CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < - (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7U)) - ) { - if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - abort_comm = true; - } - else { - gtwa->stateTimeoutTmr += timeDifference_us; - hold = true; + if (gtwa->SDOdataCopyStatus) { + if( CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7U)) { + if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + abort_comm = true; + } + else { + gtwa->stateTimeoutTmr += timeDifference_us; + hold = true; + } } } if (!hold || abort_comm) { @@ -2189,10 +2192,10 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* execute next CANopen processing immediately, if idle and more commands * available */ - if ((timerNext_us != NULL) && (gtwa->state == CO_GTWA_ST_IDLE) - && CO_fifo_CommSearch(>wa->commFifo, false) - ) { - *timerNext_us = 0; + if ((timerNext_us != NULL) && (gtwa->state == CO_GTWA_ST_IDLE)) { + if(CO_fifo_CommSearch(>wa->commFifo, false)) { + *timerNext_us = 0; + } } } From 2e703328d8fd90f48eaf62987cc87b5bd73afac3 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 11:23:27 +0200 Subject: [PATCH 433/520] CO_NMT_Heartbeat: static analysis: other minor change --- 301/CO_NMT_Heartbeat.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 556bb580..ed96a53f 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -307,7 +307,7 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0 /* Notify operating state change */ - if (NMT->operatingStatePrev != NMTstateCpy || NNTinit) { + if ((NMT->operatingStatePrev != NMTstateCpy) || NNTinit) { if (NMT->pFunctNMT != NULL) { NMT->pFunctNMT(NMTstateCpy); } @@ -316,13 +316,14 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, #if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate, when next Heartbeat needs to be send */ - if (NMT->HBproducerTime_us != 0 && timerNext_us != NULL) { + if ((NMT->HBproducerTime_us != 0U) && (timerNext_us != NULL)) { if (NMT->operatingStatePrev != NMTstateCpy) { *timerNext_us = 0; } else if (*timerNext_us > NMT->HBproducerTimer) { *timerNext_us = NMT->HBproducerTimer; } + else { /* MISRA C 2004 14.10 */ } } #endif @@ -345,12 +346,12 @@ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, } /* Apply NMT command also to this node, if set so. */ - if (nodeID == 0 || nodeID == NMT->nodeId) { + if ((nodeID == 0U) || (nodeID == NMT->nodeId)) { NMT->internalCommand = command; } /* Send NMT master message. */ - NMT->NMT_TXbuff->data[0] = command; + NMT->NMT_TXbuff->data[0] = (uint8_t)command; NMT->NMT_TXbuff->data[1] = nodeID; return CO_CANsend(NMT->NMT_CANdevTx, NMT->NMT_TXbuff); } From 071f6d7935c5c2d14f63b6c2b4dddd37a7295b25 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:06:07 +0200 Subject: [PATCH 434/520] CO_Emergency: static analysis: dependence placed on operator precedence [MISRA 2012 Rule 12.1, advisory] --- 301/CO_Emergency.c | 68 +++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 87f2879f..827a9fa3 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -58,16 +58,16 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count < sizeof(uint32_t) || countRead == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count < sizeof(uint32_t)) || (countRead == NULL) ) { return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - uint16_t canId = em->producerCanId == CO_CAN_ID_EMERGENCY ? - CO_CAN_ID_EMERGENCY + em->nodeId : em->producerCanId; + uint16_t canId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? + (CO_CAN_ID_EMERGENCY + em->nodeId) : em->producerCanId; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; COB_IDEmergency32 |= canId; (void)CO_setUint32(buf, COB_IDEmergency32); @@ -80,8 +80,8 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint32_t) || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count != sizeof(uint32_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -91,11 +91,11 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, /* Verify written value. COB ID must not change, if emergency is enabled */ uint32_t COB_IDEmergency32 = CO_getUint32(buf); uint16_t newCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); - uint16_t curCanId = em->producerCanId == CO_CAN_ID_EMERGENCY ? - CO_CAN_ID_EMERGENCY + em->nodeId : em->producerCanId; - bool_t newEnabled = (COB_IDEmergency32 & 0x80000000) == 0 && newCanId != 0; - if ((COB_IDEmergency32 & 0x7FFFF800)!=0 || CO_IS_RESTRICTED_CAN_ID(newCanId) - || (em->producerEnabled && newEnabled && newCanId != curCanId) + uint16_t curCanId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? + (CO_CAN_ID_EMERGENCY + em->nodeId) : em->producerCanId; + bool_t newEnabled = ((COB_IDEmergency32 & 0x80000000) == 0) && (newCanId != 0); + if (((COB_IDEmergency32 & 0x7FFFF800)!=0) || CO_IS_RESTRICTED_CAN_ID(newCanId) + || ((em->producerEnabled && newEnabled) && (newCanId != curCanId)) ) { return ODR_INVALID_VALUE; } @@ -103,7 +103,7 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, /* store values. If default CAN-ID is used, then store only value of * CO_CAN_ID_EMERGENCY without node id. */ em->producerEnabled = newEnabled; - em->producerCanId = newCanId == (CO_CAN_ID_EMERGENCY + em->nodeId) ? + em->producerCanId = (newCanId == (CO_CAN_ID_EMERGENCY + em->nodeId)) ? CO_CAN_ID_EMERGENCY : newCanId; /* configure emergency message CAN transmission */ @@ -155,8 +155,8 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint16_t) || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count != sizeof(uint16_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -182,8 +182,8 @@ static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if (stream == NULL || buf == NULL || countRead == NULL - || (count < 4 && stream->subIndex > 0) || count < 1 + if ((stream == NULL) || (buf == NULL) || (countRead == NULL) + || ((count < 4) && (stream->subIndex > 0)) || (count < 1) ) { return ODR_DEV_INCOMPAT; } @@ -223,8 +223,8 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL || count != 1 - || countWritten == NULL) + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) || (count != 1) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } @@ -252,8 +252,8 @@ static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if (stream == NULL || stream->subIndex != 0 - || buf == NULL || countRead == NULL) + if ((stream == NULL) || (stream->subIndex != 0) + || (buf == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } @@ -265,7 +265,7 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, if (countReadLocal > count) { countReadLocal = count; } - if (stream->dataLength != 0 && countReadLocal > stream->dataLength) { + if ((stream->dataLength != 0) && (countReadLocal > stream->dataLength)) { countReadLocal = stream->dataLength; } else { @@ -281,8 +281,8 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 - || buf == NULL || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) + || (buf == NULL) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -294,7 +294,7 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, if (countWrite > count) { countWrite = count; } - if (stream->dataLength != 0 && countWrite > stream->dataLength) { + if ((stream->dataLength != 0) && (countWrite > stream->dataLength)) { countWrite = stream->dataLength; } else { @@ -319,7 +319,7 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, static void CO_EM_receive(void *object, void *msg) { CO_EM_t *em = (CO_EM_t*)object; - if (em != NULL && em->pFunctSignalRx != NULL) { + if ((em != NULL) && (em->pFunctSignalRx != NULL)) { uint16_t ident = CO_CANrxMsg_readIdent(msg); /* ignore sync messages (necessary if sync object is not used) */ @@ -382,10 +382,10 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, || (nodeId < 1U) || (nodeId > 127U) #endif #if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 - || OD_1003_preDefErr == NULL + || (OD_1003_preDefErr == NULL) #endif #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 - || CANdevRx == NULL + || (CANdevRx == NULL) #endif ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -422,8 +422,8 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); - em->producerEnabled = (COB_IDEmergency32 & 0x80000000) == 0 - && producerCanId != 0; + em->producerEnabled = ((COB_IDEmergency32 & 0x80000000) == 0) + && (producerCanId != 0); em->OD_1014_extension.object = em; em->OD_1014_extension.read = OD_read_1014; @@ -646,8 +646,8 @@ void CO_EM_process(CO_EM_t *em, em->inhibitEmTimer += timeDifference_us; } - if (fifoPpPtr != em->fifoWrPtr && !em->CANtxBuff->bufferFull - && em->inhibitEmTimer >= em->inhibitEmTime_us + if ((fifoPpPtr != em->fifoWrPtr) && !em->CANtxBuff->bufferFull + && (em->inhibitEmTimer >= em->inhibitEmTime_us) ) { em->inhibitEmTimer = 0; #else @@ -692,8 +692,8 @@ void CO_EM_process(CO_EM_t *em, } #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 #if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - else if (timerNext_us != NULL - && em->inhibitEmTimer < em->inhibitEmTime_us) + else if ((timerNext_us != NULL) + && (em->inhibitEmTimer < em->inhibitEmTime_us)) { /* check again after inhibit time elapsed */ uint32_t diff = em->inhibitEmTime_us - em->inhibitEmTimer; @@ -798,7 +798,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 /* Optional signal to RTOS, which can resume task, which handles * CO_EM_process */ - if (em->pFunctSignalPre != NULL && em->producerEnabled) { + if ((em->pFunctSignalPre != NULL) && em->producerEnabled) { em->pFunctSignalPre(em->functSignalObjectPre); } #endif From d76aeb178f72cc1cfe0abde79794aa7a862df5c4 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:07:42 +0200 Subject: [PATCH 435/520] CO_Emergency: static analysis: unsigned integer literal without a 'U' suffix [MISRA 2012 Rule 7.2, required] --- 301/CO_Emergency.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 827a9fa3..d823d6f6 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -68,7 +68,7 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, uint16_t canId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? (CO_CAN_ID_EMERGENCY + em->nodeId) : em->producerCanId; - uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000; + uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000U; COB_IDEmergency32 |= canId; (void)CO_setUint32(buf, COB_IDEmergency32); @@ -93,7 +93,7 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, uint16_t newCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); uint16_t curCanId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? (CO_CAN_ID_EMERGENCY + em->nodeId) : em->producerCanId; - bool_t newEnabled = ((COB_IDEmergency32 & 0x80000000) == 0) && (newCanId != 0); + bool_t newEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0) && (newCanId != 0); if (((COB_IDEmergency32 & 0x7FFFF800)!=0) || CO_IS_RESTRICTED_CAN_ID(newCanId) || ((em->producerEnabled && newEnabled) && (newCanId != curCanId)) ) { @@ -422,7 +422,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); - em->producerEnabled = ((COB_IDEmergency32 & 0x80000000) == 0) + em->producerEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0) && (producerCanId != 0); em->OD_1014_extension.object = em; From ca968aa160725e3576a4540434d175658f5fef6e Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:08:42 +0200 Subject: [PATCH 436/520] CO_Emergency: static analysis: conditional of #if does not evaluate to 0 or 1 [MISRA 2012 Rule 20.8, required] --- 301/CO_Emergency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index d823d6f6..c79ffea5 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -173,7 +173,7 @@ static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ -#if (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY +#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 /* * Custom functions for read/write OD object _OD_statusBits_, optional * From 7bf5065e41e816d7292eb95b8a5e225e54ae6950 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:11:19 +0200 Subject: [PATCH 437/520] CO_Emergency: static analysis: no 'else' at end of 'if ... else if' chain [MISRA 2012 Rule 15.7, required] --- 301/CO_Emergency.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index c79ffea5..3867d436 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -701,6 +701,7 @@ void CO_EM_process(CO_EM_t *em, *timerNext_us = diff; } } + else { /* MISRA C 2004 14.10 */ } #endif #endif } From ce405b1e2785378bf641ef040e5933cbf90ad598 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:12:57 +0200 Subject: [PATCH 438/520] CO_Emergency: static analysis: body should be a compound statement [MISRA 2012 Rule 15.6, required] --- 301/CO_Emergency.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 3867d436..4eaf5c3d 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -430,7 +430,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1014_extension.write = OD_write_1014; odRet = OD_extension_init(OD_1014_cobIdEm, &em->OD_1014_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) *errInfo = OD_getIndex(OD_1014_cobIdEm); + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1014_cobIdEm); + } return CO_ERROR_OD_PARAMETERS; } /* following two variables are used inside OD_read_1014 and OD_write_1014 */ @@ -439,7 +441,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* if default producerCanId is used, then value of CO_CAN_ID_EMERGENCY * (0x80) is stored into non-volatile memory. In that case it is necessary * to add nodeId of this node to the stored value. */ - if (producerCanId == CO_CAN_ID_EMERGENCY) producerCanId += nodeId; + if (producerCanId == CO_CAN_ID_EMERGENCY) { + producerCanId += nodeId; + } #else uint16_t producerCanId = CO_CAN_ID_EMERGENCY + (uint16_t)nodeId; em->producerEnabled = (COB_IDEmergency32 & 0x80000000U) == 0U; From 42c39a2b51417a898d80b1703b9dd4005c4a4dc4 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:19:07 +0200 Subject: [PATCH 439/520] CO_Emergency: static analysis: an unsigned value and a signed value cannot be used together as operands [MISRA 2012 Rule 10.4, required] --- 301/CO_Emergency.c | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 4eaf5c3d..36637870 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -58,7 +58,7 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count < sizeof(uint32_t)) || (countRead == NULL) ) { return ODR_DEV_INCOMPAT; @@ -68,7 +68,7 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, uint16_t canId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? (CO_CAN_ID_EMERGENCY + em->nodeId) : em->producerCanId; - uint32_t COB_IDEmergency32 = em->producerEnabled ? 0 : 0x80000000U; + uint32_t COB_IDEmergency32 = em->producerEnabled ? 0U : 0x80000000U; COB_IDEmergency32 |= canId; (void)CO_setUint32(buf, COB_IDEmergency32); @@ -80,7 +80,7 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint32_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -90,11 +90,11 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, /* Verify written value. COB ID must not change, if emergency is enabled */ uint32_t COB_IDEmergency32 = CO_getUint32(buf); - uint16_t newCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); + uint16_t newCanId = (uint16_t)(COB_IDEmergency32 & 0x7FFU); uint16_t curCanId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? (CO_CAN_ID_EMERGENCY + em->nodeId) : em->producerCanId; - bool_t newEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0) && (newCanId != 0); - if (((COB_IDEmergency32 & 0x7FFFF800)!=0) || CO_IS_RESTRICTED_CAN_ID(newCanId) + bool_t newEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0U) && (newCanId != 0U); + if (((COB_IDEmergency32 & 0x7FFFF800U)!=0U) || CO_IS_RESTRICTED_CAN_ID(newCanId) || ((em->producerEnabled && newEnabled) && (newCanId != curCanId)) ) { return ODR_INVALID_VALUE; @@ -155,7 +155,7 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint16_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -164,7 +164,7 @@ static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, CO_EM_t *em = (CO_EM_t *)stream->object; /* update object */ - em->inhibitEmTime_us = (uint32_t)CO_getUint16(buf) * 100; + em->inhibitEmTime_us = (uint32_t)CO_getUint16(buf) * 100U; em->inhibitEmTimer = 0; /* write value to the original location in the Object Dictionary */ @@ -183,17 +183,17 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { if ((stream == NULL) || (buf == NULL) || (countRead == NULL) - || ((count < 4) && (stream->subIndex > 0)) || (count < 1) + || ((count < 4U) && (stream->subIndex > 0U)) || (count < 1U) ) { return ODR_DEV_INCOMPAT; } CO_EM_t *em = (CO_EM_t *)stream->object; - if (em->fifoSize < 2) { + if (em->fifoSize < 2U) { return ODR_DEV_INCOMPAT; } - if (stream->subIndex == 0) { + if (stream->subIndex == 0U) { (void)CO_setUint8(buf, em->fifoCount); *countRead = sizeof(uint8_t); @@ -202,11 +202,11 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, else if (stream->subIndex <= em->fifoCount) { /* newest error is reported on subIndex 1 and is stored just behind * fifoWrPtr. Get correct index in FIFO buffer. */ - int16_t index = (int16_t)em->fifoWrPtr - stream->subIndex; + int16_t index = (int16_t)em->fifoWrPtr - (int16_t)stream->subIndex; if (index < 0) { - index += em->fifoSize; + index += (int16_t)em->fifoSize; } - else if (index >= (em->fifoSize)) { + else if (index >= (int16_t)(em->fifoSize)) { return ODR_DEV_INCOMPAT; } else { /* MISRA C 2004 14.10 */ } @@ -223,13 +223,13 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) || (count != 1) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != 1U) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - if (CO_getUint8(buf) != 0) { + if (CO_getUint8(buf) != 0U) { return ODR_INVALID_VALUE; } @@ -252,7 +252,7 @@ static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { - if ((stream == NULL) || (stream->subIndex != 0) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; @@ -265,7 +265,7 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, if (countReadLocal > count) { countReadLocal = count; } - if ((stream->dataLength != 0) && (countReadLocal > stream->dataLength)) { + if ((stream->dataLength != 0U) && (countReadLocal > stream->dataLength)) { countReadLocal = stream->dataLength; } else { @@ -281,7 +281,7 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -294,7 +294,7 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, if (countWrite > count) { countWrite = count; } - if ((stream->dataLength != 0) && (countWrite > stream->dataLength)) { + if ((stream->dataLength != 0U) && (countWrite > stream->dataLength)) { countWrite = stream->dataLength; } else { @@ -323,7 +323,7 @@ static void CO_EM_receive(void *object, void *msg) { uint16_t ident = CO_CANrxMsg_readIdent(msg); /* ignore sync messages (necessary if sync object is not used) */ - if (ident != 0x80) { + if (ident != 0x80U) { const uint8_t *data = CO_CANrxMsg_readData(msg); uint16_t errorCode; uint32_t infoCode; @@ -421,9 +421,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, } #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 - uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FF); - em->producerEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0) - && (producerCanId != 0); + uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FFU); + em->producerEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0U) + && (producerCanId != 0U); em->OD_1014_extension.object = em; em->OD_1014_extension.read = OD_read_1014; @@ -480,7 +480,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, uint16_t inhibitTime_100us; odRet = OD_get_u16(OD_1015_InhTime, 0, &inhibitTime_100us, true); if (odRet == ODR_OK) { - em->inhibitEmTime_us = (uint32_t)inhibitTime_100us * 100; + em->inhibitEmTime_us = (uint32_t)inhibitTime_100us * 100U; em->OD_1015_extension.object = em; em->OD_1015_extension.read = OD_readOriginal; From 58606174a285de1c96e213d08bb8a2c0c71f9c50 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:21:24 +0200 Subject: [PATCH 440/520] CO_Emergency: static analysis: side effects on right hand of logical operator, '&&' [MISRA 2012 Rule 13.5, required] --- 301/CO_Emergency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 36637870..6abb81eb 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -650,7 +650,7 @@ void CO_EM_process(CO_EM_t *em, em->inhibitEmTimer += timeDifference_us; } - if ((fifoPpPtr != em->fifoWrPtr) && !em->CANtxBuff->bufferFull + if (!em->CANtxBuff->bufferFull && (fifoPpPtr != em->fifoWrPtr) && (em->inhibitEmTimer >= em->inhibitEmTime_us) ) { em->inhibitEmTimer = 0; From d9d9044221db3db510a0389ce42ee694b91a75c3 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:22:43 +0200 Subject: [PATCH 441/520] CO_Emergency: static analysis: right operand to == is a composite expression of type 'unsigned8' which is smaller than the left operand of type 'unsigned16' [MISRA 2012 Rule 10.7, required] --- 301/CO_Emergency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 6abb81eb..26bb2b4a 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -103,7 +103,7 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, /* store values. If default CAN-ID is used, then store only value of * CO_CAN_ID_EMERGENCY without node id. */ em->producerEnabled = newEnabled; - em->producerCanId = (newCanId == (CO_CAN_ID_EMERGENCY + em->nodeId)) ? + em->producerCanId = (newCanId == ((uint16_t)CO_CAN_ID_EMERGENCY + em->nodeId)) ? CO_CAN_ID_EMERGENCY : newCanId; /* configure emergency message CAN transmission */ From a501f961d4aa27b68b5550c22da3ea04aeaac3c9 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:24:20 +0200 Subject: [PATCH 442/520] CO_Emergency: ignoring return value of functions [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] --- 301/CO_Emergency.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 26bb2b4a..29e256c8 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -485,7 +485,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1015_extension.object = em; em->OD_1015_extension.read = OD_readOriginal; em->OD_1015_extension.write = OD_write_1015; - OD_extension_init(OD_1015_InhTime, &em->OD_1015_extension); + (void)OD_extension_init(OD_1015_InhTime, &em->OD_1015_extension); } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ @@ -496,7 +496,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1003_extension.object = em; em->OD_1003_extension.read = OD_read_1003; em->OD_1003_extension.write = OD_write_1003; - OD_extension_init(OD_1003_preDefErr, &em->OD_1003_extension); + (void)OD_extension_init(OD_1003_preDefErr, &em->OD_1003_extension); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ @@ -505,7 +505,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_statusBits_extension.object = em; em->OD_statusBits_extension.read = OD_read_statusBits; em->OD_statusBits_extension.write = OD_write_statusBits; - OD_extension_init(OD_statusBits, &em->OD_statusBits_extension); + (void)OD_extension_init(OD_statusBits, &em->OD_statusBits_extension); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ From baa9e4e2b244334b0f9e6904e4baefd732c548dd Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:27:01 +0200 Subject: [PATCH 443/520] CO_Emergency: static analysis: argument 1 of type 'void *' is not compatible with argument 2 of type 'uint8_t *' (aka 'unsigned char *') in call to function 'memcpy' --- 301/CO_Emergency.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 29e256c8..1ffe96a2 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -272,7 +272,7 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, stream->dataLength = countReadLocal; } - (void)memcpy (buf, &em->errorStatusBits[0], countReadLocal); + (void)memcpy ((void *)(buf), (const void *)(&em->errorStatusBits[0]), countReadLocal); *countRead = countReadLocal; return ODR_OK; @@ -301,7 +301,7 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, stream->dataLength = countWrite; } - (void)memcpy (&em->errorStatusBits[0], buf, countWrite); + (void)memcpy ((void *)(&em->errorStatusBits[0]), (const void *)(buf), countWrite); *countWritten = countWrite; return ODR_OK; @@ -328,8 +328,8 @@ static void CO_EM_receive(void *object, void *msg) { uint16_t errorCode; uint32_t infoCode; - (void)memcpy(&errorCode, &data[0], sizeof(errorCode)); - (void)memcpy(&infoCode, &data[4], sizeof(infoCode)); + (void)memcpy((void *)(&errorCode), (const void *)(&data[0]), sizeof(errorCode)); + (void)memcpy((void *)(&infoCode), (const void *)(&data[4]), sizeof(infoCode)); em->pFunctSignalRx(ident, CO_SWAP_16(errorCode), data[2], From f684b34a0385a2cfbdb9c1d7dc2ca339c2504665 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:51:06 +0200 Subject: [PATCH 444/520] CO_SYNC: static analysis: no 'else' at end of 'if ... else if' chain [MISRA 2012 Rule 15.7, required] --- 301/CO_SYNC.c | 1 + 1 file changed, 1 insertion(+) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 005dc708..df6b02ff 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -428,6 +428,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, *timerNext_us = diff; } } + else { /* MISRA C 2004 14.10 */ } #endif } else { /* MISRA C 2004 14.10 */ } From d6b3163311b2c0f2db30d8b7128eb172fdf73fe0 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:53:30 +0200 Subject: [PATCH 445/520] CO_SYNC: static analysis: dependence placed on operator precedence [MISRA 2012 Rule 12.1, advisory] --- 301/CO_SYNC.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index df6b02ff..9ef2bcad 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -96,8 +96,8 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, /* verify written value */ #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 bool_t isProducer = (cobIdSync & 0x40000000) != 0; - if ((cobIdSync & 0xBFFFF800) != 0 || CO_IS_RESTRICTED_CAN_ID(CAN_ID) - || (SYNC->isProducer && isProducer && CAN_ID != SYNC->CAN_ID) + if (((cobIdSync & 0xBFFFF800) != 0) || CO_IS_RESTRICTED_CAN_ID(CAN_ID) + || (SYNC->isProducer && isProducer && (CAN_ID != SYNC->CAN_ID)) ) { return ODR_INVALID_VALUE; } @@ -128,7 +128,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ CAN_ID, /* CAN identifier */ false, /* rtr */ - SYNC->counterOverflowValue != 0 ? 1 : 0, /* number of data bytes */ + (SYNC->counterOverflowValue != 0) ? 1 : 0, /* number of data bytes */ false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { @@ -161,8 +161,8 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if (stream == NULL || stream->subIndex != 0 || buf == NULL - || count != sizeof(uint8_t) || countWritten == NULL + if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + || (count != sizeof(uint8_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; } @@ -171,7 +171,7 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, uint8_t syncCounterOvf = CO_getUint8(buf); /* verify written value */ - if (syncCounterOvf == 1 || syncCounterOvf > 240) { + if ((syncCounterOvf == 1) || (syncCounterOvf > 240)) { return ODR_INVALID_VALUE; } if (*SYNC->OD_1006_period != 0) { @@ -184,7 +184,7 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ SYNC->CAN_ID, /* CAN identifier */ false, /* rtr */ - syncCounterOvf != 0 ? 1 : 0, /* number of data bytes */ + (syncCounterOvf != 0) ? 1 : 0, /* number of data bytes */ false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { @@ -336,7 +336,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, CANdevTxIdx, /* index of specific buffer inside CAN module */ cobIdSync & 0x7FF, /* CAN identifier */ false, /* rtr */ - syncCounterOvf != 0 ? 1 : 0, /* number of data bytes */ + (syncCounterOvf != 0) ? 1 : 0, /* number of data bytes */ false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { From 995fed609dbeeaf8081b5b0f23a2c9e534e5dd97 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:58:02 +0200 Subject: [PATCH 446/520] CO_SYNC: static analysis: an unsigned value and a signed value cannot be used together [MISRA 2012 Rule 10.4, required] --- 301/CO_SYNC.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 9ef2bcad..615bebe7 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -95,8 +95,8 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, /* verify written value */ #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 - bool_t isProducer = (cobIdSync & 0x40000000) != 0; - if (((cobIdSync & 0xBFFFF800) != 0) || CO_IS_RESTRICTED_CAN_ID(CAN_ID) + bool_t isProducer = (cobIdSync & 0x40000000U) != 0U; + if (((cobIdSync & 0xBFFFF800U) != 0U) || CO_IS_RESTRICTED_CAN_ID(CAN_ID) || (SYNC->isProducer && isProducer && (CAN_ID != SYNC->CAN_ID)) ) { return ODR_INVALID_VALUE; @@ -128,7 +128,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ CAN_ID, /* CAN identifier */ false, /* rtr */ - (SYNC->counterOverflowValue != 0) ? 1 : 0, /* number of data bytes */ + (SYNC->counterOverflowValue != 0U) ? 1U : 0U, /* number of data bytes */ false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { @@ -161,7 +161,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { - if ((stream == NULL) || (stream->subIndex != 0) || (buf == NULL) + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint8_t)) || (countWritten == NULL) ) { return ODR_DEV_INCOMPAT; @@ -171,10 +171,10 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, uint8_t syncCounterOvf = CO_getUint8(buf); /* verify written value */ - if ((syncCounterOvf == 1) || (syncCounterOvf > 240)) { + if ((syncCounterOvf == 1U) || (syncCounterOvf > 240U)) { return ODR_INVALID_VALUE; } - if (*SYNC->OD_1006_period != 0) { + if (*SYNC->OD_1006_period != 0U) { return ODR_DATA_DEV_STATE; } @@ -184,7 +184,7 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ SYNC->CAN_ID, /* CAN identifier */ false, /* rtr */ - (syncCounterOvf != 0) ? 1 : 0, /* number of data bytes */ + (syncCounterOvf != 0U) ? 1U : 0U, /* number of data bytes */ false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { @@ -334,9 +334,9 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, SYNC->CANtxBuff = CO_CANtxBufferInit( CANdevTx, /* CAN device */ CANdevTxIdx, /* index of specific buffer inside CAN module */ - cobIdSync & 0x7FF, /* CAN identifier */ + (uint16_t)(cobIdSync & 0x7FFU), /* CAN identifier */ false, /* rtr */ - (syncCounterOvf != 0) ? 1 : 0, /* number of data bytes */ + (syncCounterOvf != 0U) ? 1U : 0U, /* number of data bytes */ false); /* synchronous message flag bit */ if (SYNC->CANtxBuff == NULL) { From 4ae66f9839ae1eeb8b583fef899e52f708941df6 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 12:58:54 +0200 Subject: [PATCH 447/520] CO_SYNC: static analysis: ignoring return value of function 'CO_SYNCsend' [MISRA 2012 Directive 4.7, required], [MISRA 2012 Rule 17.7, required] --- 301/CO_SYNC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 615bebe7..b2a78879 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -393,7 +393,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, if (SYNC->isProducer) { if (SYNC->timer >= OD_1006_period) { syncStatus = CO_SYNC_RX_TX; - CO_SYNCsend(SYNC); + (void)CO_SYNCsend(SYNC); } #if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate when next SYNC needs to be sent */ From f6a4718428f96c5a599ad41e466c394a30b5982a Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 13:05:00 +0200 Subject: [PATCH 448/520] CANopen: static analysis: an unsigned value and a signed value cannot be used together as operands to > [MISRA 2012 Rule 10.4, required] --- CANopen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CANopen.c b/CANopen.c index d76ede55..e5806e3c 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1124,7 +1124,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, } #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 - if (CO_GET_CNT(SDO_CLI) > 0) { + if (CO_GET_CNT(SDO_CLI) > 0U) { OD_entry_t *SDOcliPar = OD_GET(H1280, OD_H1280_SDO_CLIENT_1_PARAM); for (uint16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { err = CO_SDOclient_init(&co->SDOclient[i], From ff3299918ed17aa88ccd0142c450663e214410bd Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 13:06:39 +0200 Subject: [PATCH 449/520] CANopen: static analysis: increment/decrement operation combined with other operation with side-effects [MISRA 2012 Rule 13.3, advisory] --- CANopen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CANopen.c b/CANopen.c index e5806e3c..61b0856e 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1129,13 +1129,14 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, for (uint16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { err = CO_SDOclient_init(&co->SDOclient[i], od, - SDOcliPar++, + SDOcliPar, nodeId, co->CANmodule, CO_GET_CO(RX_IDX_SDO_CLI) + i, co->CANmodule, CO_GET_CO(TX_IDX_SDO_CLI) + i, errInfo); + SDOcliPar++; if (err) { return err; } } } From d4c69b2ca472e92d7bf2378aadc1f7c0b5491eba Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 13:07:55 +0200 Subject: [PATCH 450/520] CANopen: staatic analysis: an unsigned value and a signed value cannot be used together as operands to == [MISRA 2012 Rule 10.4, required] --- CANopen.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CANopen.c b/CANopen.c index 61b0856e..8aa64552 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1177,7 +1177,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 - if (CO_GET_CNT(LSS_MST) == 1) { + if (CO_GET_CNT(LSS_MST) == 1U) { err = CO_LSSmaster_init(co->LSSmaster, CO_LSSmaster_DEFAULT_TIMEOUT, co->CANmodule, @@ -1191,7 +1191,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 - if (CO_GET_CNT(GTWA) == 1) { + if (CO_GET_CNT(GTWA) == 1U) { err = CO_GTWA_init(co->gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 &co->SDOclient[0], @@ -1529,7 +1529,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 - if (CO_GET_CNT(GTWA) == 1) { + if (CO_GET_CNT(GTWA) == 1U) { CO_GTWA_process(co->gtwa, enableGateway, timeDifference_us, From 823dcb3427f0c93fb5b375fccbba47f3c6350389 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 13:09:48 +0200 Subject: [PATCH 451/520] CANopen: static analysis: essential type of condition of 'if' statement is 'enum (CO_ReturnError_t)' but should be boolean [MISRA 2012 Rule 14.4, required] --- CANopen.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CANopen.c b/CANopen.c index 8aa64552..8f545aa0 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1137,7 +1137,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, CO_GET_CO(TX_IDX_SDO_CLI) + i, errInfo); SDOcliPar++; - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } } #endif @@ -1186,7 +1186,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->CANmodule, CO_GET_CO(TX_IDX_LSS_MST), CO_CAN_ID_LSS_MST); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } #endif @@ -1208,7 +1208,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, co->LEDs, #endif 0); - if (err) { return err; } + if (err != CO_ERROR_NO) { return err; } } #endif From 6fef978b697b3c75f13622414741e3f5fd1d7c19 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 13:21:43 +0200 Subject: [PATCH 452/520] CO_PDO: static analysis: dependence placed on operator precedence [MISRA 2012 Rule 12.1, advisory] --- 301/CO_PDO.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 7e34ebab..8b4dbc19 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -912,8 +912,8 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, } else { /* MISRA C 2004 14.10 */ } #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - if (timerNext_us != NULL - && RPDO->timeoutTimer < RPDO->timeoutTime_us + if ((timerNext_us != NULL) + && (RPDO->timeoutTimer < RPDO->timeoutTime_us) ) { uint32_t diff = RPDO->timeoutTime_us - RPDO->timeoutTimer; if (*timerNext_us > diff) { @@ -1363,7 +1363,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, TPDO->sendRequest = true; } #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - if (timerNext_us != NULL && *timerNext_us > TPDO->eventTimer) { + if ((timerNext_us != NULL) && (*timerNext_us > TPDO->eventTimer)) { /* Schedule for next event time */ *timerNext_us = TPDO->eventTimer; } @@ -1401,7 +1401,7 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (TPDO->sendRequest - && timerNext_us != NULL && *timerNext_us > TPDO->inhibitTimer + && (timerNext_us != NULL) && (*timerNext_us > TPDO->inhibitTimer) ) { /* Schedule for just beyond inhibit window */ *timerNext_us = TPDO->inhibitTimer; From 1c4a5f6877a301f5afce2e71269cb48dfb32e538 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 13:31:08 +0200 Subject: [PATCH 453/520] CO_fifo: static analysis: multiple loop exits [MISRA 2012 Rule 15.4, advisory] --- 301/CO_fifo.c | 61 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 770ecf7f..0a94b1b0 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -131,6 +131,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { size_t i; const uint8_t *bufSrc; + bool_t alive_cycle = true; if (eof != NULL) { *eof = false; @@ -140,34 +141,35 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { } bufSrc = &fifo->buf[fifo->readPtr]; - for (i = count; i > 0U; ) { + for (i = count; (i > 0U) && alive_cycle; ) { const uint8_t c = *bufSrc; /* is circular buffer empty */ if (fifo->readPtr == fifo->writePtr) { - break; - } - - *buf = c; - buf++; - - /* increment variables */ - if (++fifo->readPtr == fifo->bufSize) { - fifo->readPtr = 0; - bufSrc = &fifo->buf[0]; + alive_cycle = false; } else { - bufSrc++; - } - i--; + *buf = c; + buf++; + + /* increment variables */ + if (++fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + bufSrc = &fifo->buf[0]; + } + else { + bufSrc++; + } + i--; #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 - /* is delimiter? */ - if ((eof != NULL) && (c == DELIM_COMMAND)) { - *eof = true; - break; - } + /* is delimiter? */ + if ((eof != NULL) && (c == DELIM_COMMAND)) { + *eof = true; + alive_cycle = false; + } #endif + } } return count - i; @@ -316,26 +318,29 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { /******************************************************************************/ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { bool_t delimCommandFound = false; + bool_t alive_cycle = true; if ((fifo != NULL) && (insideComment != NULL)) { - while (fifo->readPtr != fifo->writePtr) { + while ((fifo->readPtr != fifo->writePtr) && alive_cycle) { uint8_t c = fifo->buf[fifo->readPtr]; if (c == DELIM_COMMENT) { *insideComment = true; } else if ((isgraph((int)c) != 0) && !(*insideComment)) { - break; + alive_cycle = false; } else { /* MISRA C 2004 14.10 */ } - if (++fifo->readPtr == fifo->bufSize) { - fifo->readPtr = 0; - } - if (c == DELIM_COMMAND) { - delimCommandFound = true; - *insideComment = false; - break; + if( alive_cycle ) { + if (++fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + } + if (c == DELIM_COMMAND) { + delimCommandFound = true; + *insideComment = false; + alive_cycle = false; + } } } } From 2e4b8890adf6f93df2d818ad2618f55d13a6e60d Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 14:06:14 +0200 Subject: [PATCH 454/520] CO_storageEeprom: static analysis: declaration of 'i' hides a local variable (multiple declaration) [MISRA 2012 Rule 5.3, required] --- storage/CO_storageEeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 7c2f87f2..73381df4 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -232,8 +232,8 @@ void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { } /* loop through entries */ - for (uint8_t i = 0; i < storage->entriesCount; i++) { - CO_storage_entry_t *entry = &storage->entries[i]; + for (uint8_t n = 0; n < storage->entriesCount; n++) { + CO_storage_entry_t *entry = &storage->entries[n]; if ((entry->attr & (uint8_t)CO_storage_auto) == 0U) { continue; From d35a5b68348c8046ed09c8e0d0ccdbf4123fb60f Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 14:07:26 +0200 Subject: [PATCH 455/520] CO_storageEeprom: static analysis: dependence placed on operator precedence [MISRA 2012 Rule 12.1, advisory] --- storage/CO_storageEeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 73381df4..1b6a5765 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -45,7 +45,7 @@ static ODR_t storeEeprom(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { /* Verify, if data in eeprom are equal */ uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, entry->eepromAddr, entry->len); - if (entry->crc != crc_read || !writeOk) { + if ((entry->crc != crc_read) || !writeOk) { return ODR_HW; } @@ -168,7 +168,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, } /* calculate addresses inside eeprom */ - entry->eepromAddrSignature = signaturesAddress + sizeof(uint32_t) * i; + entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, From b17182d96203305a914cf6382f8ed149b0a9bc5e Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 14:21:22 +0200 Subject: [PATCH 456/520] CANopen: static analysis: an unsigned value and a signed value cannot be used together as operands [MISRA 2012 Rule 10.4, required] --- CANopen.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/CANopen.c b/CANopen.c index 8f545aa0..5170067d 100644 --- a/CANopen.c +++ b/CANopen.c @@ -375,7 +375,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #endif /* CANopen object */ - CO_alloc_break_on_fail(co, 1, sizeof(*co)); + CO_alloc_break_on_fail(co, 1U, sizeof(*co)); #ifdef CO_MULTIPLE_OD co->config = config; @@ -385,7 +385,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t RX_CNT_NMT_SLV = 0); ON_MULTI_OD(uint8_t TX_CNT_NMT_MST = 0); ON_MULTI_OD(uint8_t TX_CNT_HB_PROD = 0); - if (CO_GET_CNT(NMT) == 1) { + if (CO_GET_CNT(NMT) == 1U) { CO_alloc_break_on_fail(co->NMT, CO_GET_CNT(NMT), sizeof(*co->NMT)); ON_MULTI_OD(RX_CNT_NMT_SLV = 1); #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 @@ -396,7 +396,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_HB_CONS = 0); - if (CO_GET_CNT(HB_CONS) == 1) { + if (CO_GET_CNT(HB_CONS) == 1U) { uint8_t countOfMonitoredNodes = CO_GET_CNT(ARR_1016); CO_alloc_break_on_fail(co->HBcons, CO_GET_CNT(HB_CONS), sizeof(*co->HBcons)); CO_alloc_break_on_fail(co->HBconsMonitoredNodes, countOfMonitoredNodes, sizeof(*co->HBconsMonitoredNodes)); @@ -415,7 +415,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { /* Emergency */ ON_MULTI_OD(uint8_t RX_CNT_EM_CONS = 0); ON_MULTI_OD(uint8_t TX_CNT_EM_PROD = 0); - if (CO_GET_CNT(EM) == 1) { + if (CO_GET_CNT(EM) == 1U) { CO_alloc_break_on_fail(co->em, CO_GET_CNT(EM), sizeof(*co->em)); #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 ON_MULTI_OD(RX_CNT_EM_CONS = 1); @@ -424,8 +424,8 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(TX_CNT_EM_PROD = 1); #endif #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 - uint8_t fifoSize = CO_GET_CNT(ARR_1003) + 1; - if (fifoSize >= 2) { + uint8_t fifoSize = CO_GET_CNT(ARR_1003) + 1U; + if (fifoSize >= 2U) { CO_alloc_break_on_fail(co->em_fifo, fifoSize, sizeof(*co->em_fifo)); } #endif @@ -434,7 +434,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { /* SDOserver */ ON_MULTI_OD(uint8_t RX_CNT_SDO_SRV = 0); ON_MULTI_OD(uint8_t TX_CNT_SDO_SRV = 0); - if (CO_GET_CNT(SDO_SRV) > 0) { + if (CO_GET_CNT(SDO_SRV) > 0U) { CO_alloc_break_on_fail(co->SDOserver, CO_GET_CNT(SDO_SRV), sizeof(*co->SDOserver)); ON_MULTI_OD(RX_CNT_SDO_SRV = config->CNT_SDO_SRV); ON_MULTI_OD(TX_CNT_SDO_SRV = config->CNT_SDO_SRV); @@ -443,7 +443,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SDO_CLI = 0); ON_MULTI_OD(uint8_t TX_CNT_SDO_CLI = 0); - if (CO_GET_CNT(SDO_CLI) > 0) { + if (CO_GET_CNT(SDO_CLI) > 0U) { CO_alloc_break_on_fail(co->SDOclient, CO_GET_CNT(SDO_CLI), sizeof(*co->SDOclient)); ON_MULTI_OD(RX_CNT_SDO_CLI = config->CNT_SDO_CLI); ON_MULTI_OD(TX_CNT_SDO_CLI = config->CNT_SDO_CLI); @@ -453,7 +453,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_TIME = 0); ON_MULTI_OD(uint8_t TX_CNT_TIME = 0); - if (CO_GET_CNT(TIME) == 1) { + if (CO_GET_CNT(TIME) == 1U) { CO_alloc_break_on_fail(co->TIME, CO_GET_CNT(TIME), sizeof(*co->TIME)); ON_MULTI_OD(RX_CNT_TIME = 1); #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 @@ -465,7 +465,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SYNC = 0); ON_MULTI_OD(uint8_t TX_CNT_SYNC = 0); - if (CO_GET_CNT(SYNC) == 1) { + if (CO_GET_CNT(SYNC) == 1U) { CO_alloc_break_on_fail(co->SYNC, CO_GET_CNT(SYNC), sizeof(*co->SYNC)); ON_MULTI_OD(RX_CNT_SYNC = 1); #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 @@ -476,7 +476,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 ON_MULTI_OD(uint16_t RX_CNT_RPDO = 0); - if (CO_GET_CNT(RPDO) > 0) { + if (CO_GET_CNT(RPDO) > 0U) { CO_alloc_break_on_fail(co->RPDO, CO_GET_CNT(RPDO), sizeof(*co->RPDO)); ON_MULTI_OD(RX_CNT_RPDO = config->CNT_RPDO); } @@ -484,14 +484,14 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 ON_MULTI_OD(uint16_t TX_CNT_TPDO = 0); - if (CO_GET_CNT(TPDO) > 0) { + if (CO_GET_CNT(TPDO) > 0U) { CO_alloc_break_on_fail(co->TPDO, CO_GET_CNT(TPDO), sizeof(*co->TPDO)); ON_MULTI_OD(TX_CNT_TPDO = config->CNT_TPDO); } #endif #if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 - if (CO_GET_CNT(LEDS) == 1) { + if (CO_GET_CNT(LEDS) == 1U) { CO_alloc_break_on_fail(co->LEDs, CO_GET_CNT(LEDS), sizeof(*co->LEDs)); } #endif @@ -509,8 +509,8 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SRDO = 0); ON_MULTI_OD(uint8_t TX_CNT_SRDO = 0); - if (CO_GET_CNT(SRDO) > 0) { - CO_alloc_break_on_fail(co->SRDOGuard, 1, sizeof(*co->SRDOGuard)); + if (CO_GET_CNT(SRDO) > 0U) { + CO_alloc_break_on_fail(co->SRDOGuard, 1U, sizeof(*co->SRDOGuard)); CO_alloc_break_on_fail(co->SRDO, CO_GET_CNT(SRDO), sizeof(*co->SRDO)); ON_MULTI_OD(RX_CNT_SRDO = config->CNT_SRDO * 2); ON_MULTI_OD(TX_CNT_SRDO = config->CNT_SRDO * 2); @@ -520,7 +520,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 ON_MULTI_OD(uint8_t RX_CNT_LSS_SLV = 0); ON_MULTI_OD(uint8_t TX_CNT_LSS_SLV = 0); - if (CO_GET_CNT(LSS_SLV) == 1) { + if (CO_GET_CNT(LSS_SLV) == 1U) { CO_alloc_break_on_fail(co->LSSslave, CO_GET_CNT(LSS_SLV), sizeof(*co->LSSslave)); ON_MULTI_OD(RX_CNT_LSS_SLV = 1); ON_MULTI_OD(TX_CNT_LSS_SLV = 1); @@ -530,7 +530,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 ON_MULTI_OD(uint8_t RX_CNT_LSS_MST = 0); ON_MULTI_OD(uint8_t TX_CNT_LSS_MST = 0); - if (CO_GET_CNT(LSS_MST) == 1) { + if (CO_GET_CNT(LSS_MST) == 1U) { CO_alloc_break_on_fail(co->LSSmaster, CO_GET_CNT(LSS_MST), sizeof(*co->LSSmaster)); ON_MULTI_OD(RX_CNT_LSS_MST = 1); ON_MULTI_OD(TX_CNT_LSS_MST = 1); @@ -538,7 +538,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #endif #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 - if (CO_GET_CNT(GTWA) == 1) { + if (CO_GET_CNT(GTWA) == 1U) { CO_alloc_break_on_fail(co->gtwa, CO_GET_CNT(GTWA), sizeof(*co->gtwa)); } #endif @@ -631,7 +631,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #endif /* #ifdef CO_MULTIPLE_OD */ /* CANmodule */ - CO_alloc_break_on_fail(co->CANmodule, 1, sizeof(*co->CANmodule)); + CO_alloc_break_on_fail(co->CANmodule, 1U, sizeof(*co->CANmodule)); /* CAN RX blocks */ CO_alloc_break_on_fail(co->CANrx, CO_GET_CO(CNT_ALL_RX_MSGS), sizeof(*co->CANrx)); From dad273b656e1da8258faca83872f091e910ecc40 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 14:26:09 +0200 Subject: [PATCH 457/520] CANopen: static analysis: expected end of line in preprocessor expression --- CANopen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CANopen.c b/CANopen.c index 5170067d..07e0a964 100644 --- a/CANopen.c +++ b/CANopen.c @@ -496,7 +496,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 +#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_GFC = 0); ON_MULTI_OD(uint8_t TX_CNT_GFC = 0); if (CO_GET_CNT(GFC) == 1) { @@ -730,7 +730,7 @@ void CO_delete(CO_t *co) { CO_free(co->NGmaster); #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0) +#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 CO_free(co->HBconsMonitoredNodes); CO_free(co->HBcons); #endif From 5a2f24bc4b1bf51c7f37be0b2e6fe8edc3c2c413 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 14:49:37 +0200 Subject: [PATCH 458/520] static analysis: ANSI/ISO minimum translation limit of 31 'significant characters in an external identifier' exceeded, processing is unaffected --- 301/CO_SDOclient.c | 2 +- 301/CO_SDOclient.h | 2 +- 305/CO_LSSmaster.c | 4 ++-- 305/CO_LSSmaster.h | 4 ++-- 309/CO_gateway_ascii.c | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 834cd107..88b93562 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -492,7 +492,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, } -void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, +void CO_SDOclientDownloadInitSize(CO_SDOclient_t *SDO_C, size_t sizeIndicated) { if (SDO_C != NULL) { diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 8062b97a..90eb633d 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -385,7 +385,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, * @param SDO_C This object. * @param sizeIndicated Same as in CO_SDOclientDownloadInitiate(). */ -void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C, +void CO_SDOclientDownloadInitSize(CO_SDOclient_t *SDO_C, size_t sizeIndicated); diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index d72225e8..77b499d0 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -286,7 +286,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( } /******************************************************************************/ -CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( +CO_LSSmaster_return_t CO_LSSmaster_swStateSelect( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, CO_LSS_address_t *lssAddress) @@ -323,7 +323,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( /******************************************************************************/ -CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( +CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect( CO_LSSmaster_t *LSSmaster) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 653051e7..69bd0a21 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -222,7 +222,7 @@ void CO_LSSmaster_initCallbackPre( * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ -CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( +CO_LSSmaster_return_t CO_LSSmaster_swStateSelect( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, CO_LSS_address_t *lssAddress); @@ -240,7 +240,7 @@ CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect( * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_OK */ -CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect( +CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect( CO_LSSmaster_t *LSSmaster); diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 27423ef9..56aec3c7 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -1072,7 +1072,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* if data size was not known before and is known now, update SDO */ if ((gtwa->SDOdataType->length == 0U) && !gtwa->SDOdataCopyStatus) { - CO_SDOclientDownloadInitiateSize(gtwa->SDO_C, size); + CO_SDOclientDownloadInitSize(gtwa->SDO_C, size); } /* continue with state machine */ @@ -1214,7 +1214,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (select == 0U) { /* send non-confirmed message */ CO_LSSmaster_return_t ret; - ret = CO_LSSmaster_switchStateDeselect(gtwa->LSSmaster); + ret = CO_LSSmaster_swStateDeselect(gtwa->LSSmaster); if (ret == CO_LSSmaster_OK) { responseWithOK(gtwa); } @@ -1834,7 +1834,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 case CO_GTWA_ST_LSS_SWITCH_GLOB: { CO_LSSmaster_return_t ret; - ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster, + ret = CO_LSSmaster_swStateSelect(gtwa->LSSmaster, timeDifference_us, NULL); if (ret != CO_LSSmaster_WAIT_SLAVE) { @@ -1845,7 +1845,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } case CO_GTWA_ST_LSS_SWITCH_SEL: { CO_LSSmaster_return_t ret; - ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster, + ret = CO_LSSmaster_swStateSelect(gtwa->LSSmaster, timeDifference_us, >wa->lssAddress); if (ret != CO_LSSmaster_WAIT_SLAVE) { @@ -2062,7 +2062,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } if (gtwa->lssSubState >= 3U) { /* lss_switch_glob 0 */ /* send non-confirmed message */ - ret = CO_LSSmaster_switchStateDeselect(gtwa->LSSmaster); + ret = CO_LSSmaster_swStateDeselect(gtwa->LSSmaster); if (ret != CO_LSSmaster_OK) { /* error occurred */ responseLSS(gtwa, ret); From 3e5140886198f205c4cd3b0c792869e6d10db1ea Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 14:53:17 +0200 Subject: [PATCH 459/520] static analysis: Add exception 9059, C comment contains C++ comment --- MISRA.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/MISRA.md b/MISRA.md index 073b921b..7b1a50f8 100644 --- a/MISRA.md +++ b/MISRA.md @@ -30,6 +30,12 @@ ref.: MISRA C 2012 Rule 11.5 -efile( 9079, CANopenNode* ) ``` +### Inhibits: C comment contains C++ comment +ref.: MISRA C 2012 Rule 3.1 +``` +-efile( 9059, CANopenNode* ) +``` + ### Inhibits: complete definition of symbol is unnecessary in this translation unit ref.: MISRA C 2012 Dir 4.8 ``` @@ -117,12 +123,7 @@ ref.: MISRA C 2012 Rule 2.5 -efile( 750, CANopenNode* ) ``` - ### Inhibits: constant value used in Boolean context (string) ``` -efile( 506, CANopenNode* ) ``` - - - - From 36f01f3893a352746b52d045323189be88cb7db1 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 16:27:09 +0200 Subject: [PATCH 460/520] CO_gateway_ascii: static analysis: format specifies is nominally inconsistent with argument --- 309/CO_gateway_ascii.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 56aec3c7..964f68a4 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -244,7 +244,7 @@ static inline uint32_t getU32(char *token, uint32_t min, char *sRet; uint32_t num = strtoul(token, &sRet, 0); - if ((sRet != strchr(token, (int)'\0')) || (num < min) || (num > max)) { + if ((sRet != strchr(token, (int32_t)'\0')) || (num < min) || (num > max)) { *err = true; } @@ -493,7 +493,7 @@ static void responseWithError(CO_GTWA_t *gtwa, gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] ERROR:%d #%s\r\n", - gtwa->sequence, respErrorCode, desc); + (int32_t)gtwa->sequence, (int32_t)respErrorCode, desc); (void)respBufTransfer(gtwa); } @@ -516,12 +516,12 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, if (!postponed) { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] ERROR:0x%08X #%s\r\n", - gtwa->sequence, abortCode, desc); + (int32_t)gtwa->sequence, (uint32_t)abortCode, desc); } else { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "\n...ERROR:0x%08X #%s\r\n", - abortCode, desc); + (uint32_t)abortCode, desc); } (void)respBufTransfer(gtwa); @@ -563,7 +563,7 @@ static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, static inline void responseWithOK(CO_GTWA_t *gtwa) { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] OK\r\n", - gtwa->sequence); + (int32_t)gtwa->sequence); (void)respBufTransfer(gtwa); } @@ -606,7 +606,7 @@ static inline void convertToLower(char *token, size_t maxCount) { if (*c == '\0') { break; } else { - *c = (char)tolower((int)*c); + *c = (char)tolower((int32_t)*c); } c++; } @@ -708,7 +708,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* empty token, break on error */ err = true; break; - } else if ((int)isdigit((int)tok[0]) == (int)0) { + } else if ((int32_t)isdigit((int)tok[0]) == 0) { /* found */ break; } else if (closed != 0U) { @@ -1699,7 +1699,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE - 2U, "[%"PRId32"] ", - gtwa->sequence); + (int32_t)gtwa->sequence); gtwa->SDOdataCopyStatus = true; } @@ -1916,12 +1916,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%02"PRIX32"\r\n", - gtwa->sequence, value & 0xFFU); + (int32_t)gtwa->sequence, value & 0xFFU); } else { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%08"PRIX32"\r\n", - gtwa->sequence, value); + (int32_t)gtwa->sequence, value); } (void)respBufTransfer(gtwa); } @@ -1943,7 +1943,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", - gtwa->sequence, + (int32_t)gtwa->sequence, gtwa->lssAddress.identity.vendorID, gtwa->lssAddress.identity.productCode, gtwa->lssAddress.identity.revisionNumber, @@ -1968,7 +1968,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", - gtwa->sequence, + (int32_t)gtwa->sequence, gtwa->lssFastscan.found.identity.vendorID, gtwa->lssFastscan.found.identity.productCode, gtwa->lssFastscan.found.identity.revisionNumber, @@ -2001,7 +2001,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, "# Found %d nodes, search finished.\n" \ "[%"PRId32"] OK\r\n", gtwa->lssNodeCount, - gtwa->sequence); + (int32_t)gtwa->sequence); (void)respBufTransfer(gtwa); gtwa->state = CO_GTWA_ST_IDLE; } @@ -2086,7 +2086,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } else { /* If we can't assign more node IDs, quit scanning */ - sprintf(msg2, msg2Fmt, gtwa->sequence); + sprintf(msg2, msg2Fmt, (int32_t)gtwa->sequence); gtwa->state = CO_GTWA_ST_IDLE; } From 86a5064e2fd888f22a1540e9b8b3cd0f72ce8964 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 16:43:00 +0200 Subject: [PATCH 461/520] CO_fifo: static analisys: use of modifier or type outside of a typedef [MISRA 2012 Directive 4.6, advisory] --- 301/CO_fifo.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 0a94b1b0..87b28e6a 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -277,7 +277,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { count = fifo->bufSize - fifo->readPtr; } commandEnd = (uint8_t *)memchr((const void *)&fifo->buf[fifo->readPtr], - (int)DELIM_COMMAND, + (int32_t)DELIM_COMMAND, count); if (commandEnd != NULL) { newCommand = true; @@ -285,7 +285,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { else if (fifo->readPtr > fifo->writePtr) { /* not found, search in the beginning of the circular buffer */ commandEnd = (uint8_t *)memchr((const void *)&fifo->buf[0], - (int)DELIM_COMMAND, + (int32_t)DELIM_COMMAND, fifo->writePtr); if ((commandEnd != NULL) || (fifo->readPtr == (fifo->writePtr + 1U))) { /* command delimiter found or buffer full */ @@ -705,7 +705,7 @@ size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%g", (double)CO_SWAP_32(n)); + return (size_t)sprintf(buf, "%g", (float32_t)CO_SWAP_32(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -721,7 +721,7 @@ size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 30U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%g", (double)CO_SWAP_64(n)); + return (size_t)sprintf(buf, "%g", (float64_t)CO_SWAP_64(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -885,7 +885,7 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if ((sRet != strchr(buf, (int)('\0'))) || (u32 > (uint32_t)UINT8_MAX)) { + if ((sRet != strchr(buf, (int32_t)('\0'))) || (u32 > (uint32_t)UINT8_MAX)) { st |= CO_fifo_st_errVal; } else { @@ -915,7 +915,7 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if ((sRet != strchr(buf, (int)('\0'))) || (u32 > (uint32_t)UINT16_MAX)) { + if ((sRet != strchr(buf, (int32_t)('\0'))) || (u32 > (uint32_t)UINT16_MAX)) { st |= CO_fifo_st_errVal; } else { @@ -945,7 +945,7 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; uint32_t u32 = strtoul(buf, &sRet, 0); - if (sRet != strchr(buf, (int)('\0'))) { + if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -975,7 +975,7 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; uint64_t u64 = strtoull(buf, &sRet, 0); - if (sRet != strchr(buf, (int)('\0'))) { + if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1005,7 +1005,7 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if ((sRet != strchr(buf, (int)('\0'))) || (i32 < INT8_MIN) || (i32 > INT8_MAX)) { + if ((sRet != strchr(buf, (int32_t)('\0'))) || (i32 < INT8_MIN) || (i32 > INT8_MAX)) { st |= CO_fifo_st_errVal; } else { int8_t num = (int8_t) i32; @@ -1034,7 +1034,7 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if ((sRet != strchr(buf, (int)('\0'))) || (i32 < INT16_MIN) || (i32 > INT16_MAX)) { + if ((sRet != strchr(buf, (int32_t)('\0'))) || (i32 < INT16_MIN) || (i32 > INT16_MAX)) { st |= CO_fifo_st_errVal; } else { int16_t num = CO_SWAP_16((int16_t) i32); @@ -1063,7 +1063,7 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; int32_t i32 = strtol(buf, &sRet, 0); - if (sRet != strchr(buf, (int)('\0'))) { + if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1093,7 +1093,7 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; int64_t i64 = strtoll(buf, &sRet, 0); - if (sRet != strchr(buf, (int)('\0'))) { + if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1123,7 +1123,7 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; float32_t f32 = strtof(buf, &sRet); - if (sRet != strchr(buf, (int)('\0'))) { + if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1153,7 +1153,7 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { else { char *sRet; float64_t f64 = strtof(buf, &sRet); - if (sRet != strchr(buf, (int)('\0'))) { + if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; } else { @@ -1220,7 +1220,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { continue; } - if ((int)(isxdigit((int)c)) != (int)(0)) { + if ((int32_t)(isxdigit((int32_t)c)) != 0) { /* first or second hex digit */ if (step == 0U) { firstChar = c; @@ -1237,7 +1237,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { step = 0; } } - else if ((int)(isgraph((int)c)) != (int)(0)) { + else if ((int32_t)(isgraph((int32_t)c)) != 0) { /* printable character, not hex digit */ if (c == DELIM_COMMENT) { /* comment start */ step = 6; From 675d11a33d4fafb6db7d0441aa389731617805eb Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 16:54:42 +0200 Subject: [PATCH 462/520] CO_fifo: static analysis: format '%02X' specifies type 'unsigned int' which is nominally inconsistent with argument no. 3 of promoted type 'int' --- 301/CO_fifo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 87b28e6a..ffbb1bbe 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -577,7 +577,7 @@ size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "0x%02"PRIX8, n); + return (size_t)sprintf(buf, "0x%02"PRIX8, (uint32_t)n); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -593,7 +593,7 @@ size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "0x%04"PRIX16, CO_SWAP_16(n)); + return (size_t)sprintf(buf, "0x%04"PRIX16, (uint32_t)CO_SWAP_16(n)); } else { return CO_fifo_readHex2a(fifo, buf, count, end); @@ -738,7 +738,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if (!fifo->started) { uint8_t c; if(CO_fifo_getc(fifo, &c)) { - len = (size_t)sprintf(&buf[0], "%02"PRIX8, c); + len = (size_t)sprintf(&buf[0], "%02"PRIX8, (uint32_t)c); fifo->started = true; } } @@ -748,7 +748,7 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { if(!CO_fifo_getc(fifo, &c)) { break; } - len += (size_t)sprintf(&buf[len], " %02"PRIX8, c); + len += (size_t)sprintf(&buf[len], " %02"PRIX8, (uint32_t)c); } } From b0ae30aeba2d2438844e21572f38c688303cc5a2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 17:06:26 +0200 Subject: [PATCH 463/520] static analysis: Excluded the CO_gateway_ascii and CO_fifo --- MISRA.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MISRA.md b/MISRA.md index 7b1a50f8..8896be21 100644 --- a/MISRA.md +++ b/MISRA.md @@ -12,6 +12,14 @@ guidelines, with some noted exceptions. Compliance is checked with [PC Lint Plus -efile( *, CANopenNode\OD.h ) ``` +### Inhibits: Excluded the CO_gateway_ascii and CO_fifo (currently static analysis not completed) +``` +-efile( *, CANopenNode\309\CO_gateway_ascii.c ) +-efile( *, CANopenNode\309\CO_gateway_ascii.h ) +-efile( *, CANopenNode\301\CO_fifo.c ) +-efile( *, CANopenNode\301\CO_fifo.h ) +``` + ### Inhibits: C comment contains '://' sequence ref.: MISRA C 2012 Rule 3.1 ``` From 4a59d6eb0e35e62d258ab66ecac9ec6808afd88b Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 27 Jun 2024 17:16:28 +0200 Subject: [PATCH 464/520] static analysis: add recommendation use CO_USE_GLOBALS --- MISRA.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MISRA.md b/MISRA.md index 8896be21..38c9cb68 100644 --- a/MISRA.md +++ b/MISRA.md @@ -3,6 +3,9 @@ The CANopenNode files conform to the [MISRA C:2012](https://www.misra.org.uk) guidelines, with some noted exceptions. Compliance is checked with [PC Lint Plus](https://pclintplus.com/). +A recommendation for MISRA: memory allocation and deallocation functions should not be used. +You must define the macro CO_USE_GLOBALS in your driver configuration. + ## Configuration Inhibits Control From 586c81937dd0c3f4c521c2e9ac79b2fc6366bc2d Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 27 Jun 2024 17:24:55 +0200 Subject: [PATCH 465/520] Update CO_storageEeprom.c Change to fixed sized array --- storage/CO_storageEeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 1b6a5765..34819dbd 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -118,7 +118,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, /* verify arguments */ if ((storage == NULL) || (entries == NULL) || (entriesCount == 0U) - || (storageInitError == NULL) + || (entriesCount > CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT) || (storageInitError == NULL) ) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -145,7 +145,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, } /* Read entry signatures from the eeprom */ - uint32_t signatures[entriesCount]; + uint32_t signatures[CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT]; size_t signaturesAddress = CO_eeprom_getAddr(storageModule, false, sizeof(signatures), From f36345dbab053cf6ce6e51ac46eab65579421b53 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 27 Jun 2024 17:25:48 +0200 Subject: [PATCH 466/520] CO_storageEeprom.h: Change to fixed sized array --- storage/CO_storageEeprom.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h index 06490e60..35b9d11e 100644 --- a/storage/CO_storageEeprom.h +++ b/storage/CO_storageEeprom.h @@ -28,6 +28,10 @@ #include "storage/CO_storage.h" +#ifndef CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT +#define CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT 5 +#endif + #if (((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus @@ -91,7 +95,8 @@ extern "C" { * @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default * parameters". Entry is optional, may be NULL. * @param entries Pointer to array of storage entries, see @ref CO_storage_init. - * @param entriesCount Count of storage entries + * @param entriesCount Count of storage entries, must not be larger than + * CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT. * @param [out] storageInitError If function returns CO_ERROR_DATA_CORRUPT, * then this variable contains a bit mask from subIndexOD values, where data * was not properly initialized. If other error, then this variable contains From 94022f51f0169ffb97ccc6a0d5a935c971c174b2 Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 1 Jul 2024 08:53:03 +0200 Subject: [PATCH 467/520] CO_storageEeprom: static analysis: an unsigned value and a signed value cannot be used together [MISRA 2012 Rule 10.4, required] --- storage/CO_storageEeprom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h index 35b9d11e..62d5897b 100644 --- a/storage/CO_storageEeprom.h +++ b/storage/CO_storageEeprom.h @@ -29,7 +29,7 @@ #include "storage/CO_storage.h" #ifndef CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT -#define CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT 5 +#define CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT 5U #endif #if (((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN From 240dd588fc0eef9d7a551b0e4d7c854f959d4ced Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Mon, 1 Jul 2024 11:40:44 +0200 Subject: [PATCH 468/520] Fix timing message, cycleTimer is only managed by the normal message to avoid mail loop losses --- 304/CO_SRDO.c | 17 +++++++++++------ 304/CO_SRDO.h | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 27072078..26a0c03a 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -743,6 +743,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext if (NMTisOperational && (SRDO->informationDirection != CO_SRDO_INVALID) && SRDO->SRDOGuard->configurationValid && (SRDO->internalState >= CO_SRDO_state_unknown)) { SRDO->cycleTimer = (SRDO->cycleTimer > timeDifference_us) ? (SRDO->cycleTimer - timeDifference_us) : 0U; + SRDO->invertedDelay = (SRDO->invertedDelay > timeDifference_us) ? (SRDO->invertedDelay - timeDifference_us) : 0U; SRDO->validationTimer = (SRDO->validationTimer > timeDifference_us) ? (SRDO->validationTimer - timeDifference_us) : 0U; /* Detect transition to NMT operational */ @@ -759,8 +760,8 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext SRDO->internalState = CO_SRDO_state_error_internal; /* should not happen */ } else if (SRDO->informationDirection == CO_SRDO_TX) { - if (SRDO->cycleTimer == 0U) { - if (SRDO->nextIsNormal) { + if (SRDO->nextIsNormal) { + if (SRDO->cycleTimer == 0U) { uint8_t *dataSRDO[2] = {&SRDO->CANtxBuff[0]->data[0], &SRDO->CANtxBuff[1]->data[0]}; size_t verifyLength[2] = { 0, 0 }; @@ -840,7 +841,9 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext #endif if (data_ok) { if (CO_CANsend(SRDO->CANdevTx[0], SRDO->CANtxBuff[0]) == CO_ERROR_NO) { - SRDO->cycleTimer = CO_CONFIG_SRDO_MINIMUM_DELAY; + SRDO->cycleTimer = SRDO->cycleTime_us; /* cycleTime_us is verified, result can't be <0 */ + SRDO->invertedDelay = CO_CONFIG_SRDO_MINIMUM_DELAY; + SRDO->nextIsNormal = false; SRDO->internalState = CO_SRDO_state_communicationEstablished; } else { @@ -848,16 +851,18 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } } } - } else { + } + } else { + if (SRDO->invertedDelay == 0U) { if (CO_CANsend(SRDO->CANdevTx[1], SRDO->CANtxBuff[1]) == CO_ERROR_NO) { - SRDO->cycleTimer = SRDO->cycleTime_us - CO_CONFIG_SRDO_MINIMUM_DELAY; /* cycleTime_us is verified, result can't be <0 */ + SRDO->nextIsNormal = true; } else { SRDO->internalState = CO_SRDO_state_error_txFail; } } - SRDO->nextIsNormal = !SRDO->nextIsNormal; } + #if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL) { if (*timerNext_us > SRDO->cycleTimer) { diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 36c755b0..9abe851d 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -158,6 +158,8 @@ typedef struct { uint32_t validationTime_us; /** cycle timer variable in microseconds */ uint32_t cycleTimer; + /** inverted delay timer variable in microseconds */ + uint32_t invertedDelay; /** validation timer variable in microseconds */ uint32_t validationTimer; /** Data length of the received SRDO message. Calculated from mapping */ From 28d3c1f372bb2275115b1b00da4d0322d27a86bb Mon Sep 17 00:00:00 2001 From: temi54c1l8 Date: Thu, 4 Jul 2024 09:55:39 +0200 Subject: [PATCH 469/520] Fix SRDO problem with PCL Codesys on configuration runtime without reset --- 304/CO_SRDO.c | 178 +++++++++++++++++++++++++++++--------------------- 304/CO_SRDO.h | 42 ++++++------ CANopen.c | 26 ++++++-- 3 files changed, 146 insertions(+), 100 deletions(-) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 26a0c03a..081542e0 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -106,7 +106,6 @@ configurationValidUnset(CO_SRDOGuard_t* SRDOGuard) { OD_size_t dummy; SRDOGuard->configurationValid = false; - SRDOGuard->privateConfigValid = false; OD_IO->write(&OD_IO->stream, &val, sizeof(val), &dummy); } @@ -316,6 +315,13 @@ OD_write_13FE(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* /* Data cannot be transferred or stored to the application because of the present device state. */ return ODR_DATA_DEV_STATE; } + + uint8_t configurationValid = CO_getUint8(buf); + if( configurationValid == CO_SRDO_VALID_MAGIC ) { + SRDOGuard->configurationValid = true; + } else { + SRDOGuard->configurationValid = false; + } /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, buf, count, countWritten); @@ -352,7 +358,7 @@ CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalPre)(v #endif CO_ReturnError_t -CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, +CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo) { ODR_t odRet; uint8_t configurationValid; @@ -364,6 +370,9 @@ CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationV /* clear object */ (void)memset(SRDOGuard, 0, sizeof(CO_SRDOGuard_t)); + + SRDOGuard->OD_13FE_entry = OD_13FE_configurationValid; + SRDOGuard->OD_13FF_entry = OD_13FF_safetyConfigurationSignature; /* Configure Object dictionary extensions */ SRDOGuard->OD_13FE_extension.object = SRDOGuard; @@ -385,28 +394,22 @@ CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationV } return CO_ERROR_OD_PARAMETERS; } - + if (OD_get_u8(OD_13FE_configurationValid, 0, &configurationValid, true) != ODR_OK) { *errInfo = (((uint32_t)OD_getIndex(OD_13FE_configurationValid)) << 8) | 1U; return CO_ERROR_OD_PARAMETERS; } - - if (configurationValid == CO_SRDO_VALID_MAGIC) { - /* Private variable, erroneous SRDO initialization will clear this. */ - SRDOGuard->privateConfigValid = true; + if( configurationValid == CO_SRDO_VALID_MAGIC ) { + SRDOGuard->configurationValid = true; + } else { + SRDOGuard->configurationValid = false; } return CO_ERROR_NO; } CO_ReturnError_t -CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_t* OD, CO_EM_t* em, uint8_t nodeId, - uint16_t defaultCOB_ID, OD_entry_t* OD_130x_SRDOCommPar, OD_entry_t* OD_138x_SRDOMapPar, - OD_entry_t* OD_13FE_configurationValid, OD_entry_t* OD_13FF_safetyConfigurationSignature, - CO_CANmodule_t* CANdevRxNormal, CO_CANmodule_t* CANdevRxInverted, uint16_t CANdevRxIdxNormal, - uint16_t CANdevRxIdxInverted, CO_CANmodule_t* CANdevTxNormal, CO_CANmodule_t* CANdevTxInverted, - uint16_t CANdevTxIdxNormal, uint16_t CANdevTxIdxInverted, uint32_t* errInfo) { - +CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, uint32_t* errInfo) { CO_ReturnError_t ret = CO_ERROR_NO; uint32_t err = 0; bool_t configurationInProgress = false; @@ -424,73 +427,41 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ uint8_t mappedObjectsCount = 0; uint32_t mapping[CO_SRDO_MAX_MAPPED_ENTRIES]; - /* verify arguments */ - if ((SRDO == NULL) || (SRDOGuard == NULL) || (OD == NULL) || (em == NULL) || (OD_130x_SRDOCommPar == NULL) - || (OD_138x_SRDOMapPar == NULL) || (OD_13FE_configurationValid == NULL) || (OD_13FF_safetyConfigurationSignature == NULL) - || (CANdevRxNormal == NULL) || (CANdevRxInverted == NULL) || (CANdevTxNormal == NULL) || (CANdevTxInverted == NULL)) { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - err = 1; - } - - /* clear object and configure some object variables */ - if (err == 0U) { - (void)memset(SRDO, 0, sizeof(CO_SRDO_t)); - - SRDO->SRDOGuard = SRDOGuard; - SRDO->em = em; - SRDO->defaultCOB_ID = defaultCOB_ID; - SRDO->nodeId = nodeId; - SRDO->CANdevTx[0] = CANdevTxNormal; - SRDO->CANdevTx[1] = CANdevTxInverted; - - /* Configure Object dictionary entry at index 0x1301+ */ - SRDO->OD_communicationParam_ext.object = SRDO; - SRDO->OD_communicationParam_ext.read = OD_read_SRDO_communicationParam; - SRDO->OD_communicationParam_ext.write = OD_write_SRDO_communicationParam; - (void)OD_extension_init(OD_130x_SRDOCommPar, &SRDO->OD_communicationParam_ext); - - /* Configure Object dictionary entry at index 0x1381+ */ - SRDO->OD_mappingParam_extension.object = SRDO; - SRDO->OD_mappingParam_extension.read = OD_readOriginal; - SRDO->OD_mappingParam_extension.write = OD_write_SRDO_mappingParam; - (void)OD_extension_init(OD_138x_SRDOMapPar, &SRDO->OD_mappingParam_extension); - } - /* Get variables from object Dictionary and verify it's structure. */ if (err == 0U) { - if (OD_get_u8(OD_130x_SRDOCommPar, 0, &cp_highestSubindexSupported, true) != ODR_OK) { + if (OD_get_u8(SRDOGuard->OD_13FE_entry, 0, &configurationValid, true) != ODR_OK) { + err = ERR_INFO(0x13FEUL, 0, 1); + } + else if (OD_get_u16(SRDOGuard->OD_13FF_entry, SRDO_Index + 1U, &crcSignatureFromOD, true) != ODR_OK) { + err = ERR_INFO(0x13FFUL, SRDO_Index + 1UL, 1); + } + else if (OD_get_u8(SRDO->OD_communicationParam_entry, 0, &cp_highestSubindexSupported, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 0, 1); } - else if (OD_get_u8(OD_130x_SRDOCommPar, 1, &informationDirection, true) != ODR_OK) { + else if (OD_get_u8(SRDO->OD_communicationParam_entry, 1, &informationDirection, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 1, 1); } - else if (OD_get_u16(OD_130x_SRDOCommPar, 2, &safetyCycleTime, true) != ODR_OK) { + else if (OD_get_u16(SRDO->OD_communicationParam_entry, 2, &safetyCycleTime, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 2, 1); } - else if (OD_get_u8(OD_130x_SRDOCommPar, 3, &safetyRelatedValidationTime, true) != ODR_OK) { + else if (OD_get_u8(SRDO->OD_communicationParam_entry, 3, &safetyRelatedValidationTime, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 3, 1); } - else if (OD_get_u8(OD_130x_SRDOCommPar, 4, &transmissionType, true) != ODR_OK) { + else if (OD_get_u8(SRDO->OD_communicationParam_entry, 4, &transmissionType, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 4, 1); } - else if (OD_get_u32(OD_130x_SRDOCommPar, 5, &COB_ID1_normal, true) != ODR_OK) { + else if (OD_get_u32(SRDO->OD_communicationParam_entry, 5, &COB_ID1_normal, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 5, 1); } - else if (OD_get_u32(OD_130x_SRDOCommPar, 6, &COB_ID2_inverted, true) != ODR_OK) { + else if (OD_get_u32(SRDO->OD_communicationParam_entry, 6, &COB_ID2_inverted, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 6, 1); } - else if (OD_get_u8(OD_13FE_configurationValid, 0, &configurationValid, true) != ODR_OK) { - err = ERR_INFO(0x13FEUL, 0, 1); - } - else if (OD_get_u16(OD_13FF_safetyConfigurationSignature, SRDO_Index + 1U, &crcSignatureFromOD, true) != ODR_OK) { - err = ERR_INFO(0x13FFUL, SRDO_Index + 1UL, 1); - } - else if (OD_get_u8(OD_138x_SRDOMapPar, 0, &mappedObjectsCount, true) != ODR_OK) { + else if (OD_get_u8(SRDO->OD_mappingParam_entry, 0, &mappedObjectsCount, true) != ODR_OK) { err = ERR_INFO(0x1381UL + SRDO_Index, 0, 1); } else { for (uint8_t i = 0; i < mappedObjectsCount; i++) { - if (OD_get_u32(OD_138x_SRDOMapPar, i+1U, &mapping[i], true) != ODR_OK) { + if (OD_get_u32(SRDO->OD_mappingParam_entry, i+1U, &mapping[i], true) != ODR_OK) { err = ERR_INFO(0x1381UL + SRDO_Index, i+1UL, 1); break; } @@ -498,7 +469,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } /* if OD contains default COB_IDs, add node-id */ - if ((COB_ID1_normal == defaultCOB_ID) && (COB_ID2_inverted == ((uint32_t)defaultCOB_ID + 1UL)) && (nodeId <= 64U)) { + if ((COB_ID1_normal == SRDO->defaultCOB_ID) && (COB_ID2_inverted == ((uint32_t)SRDO->defaultCOB_ID + 1UL)) && (SRDO->nodeId <= 64U)) { uint32_t add = (uint32_t)SRDO->nodeId * 2U; COB_ID1_normal += add; COB_ID2_inverted += add; @@ -602,7 +573,7 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* find entry in the Object Dictionary */ else { OD_IO_t OD_IOcopy; - OD_entry_t *entry = OD_find(OD, index); + OD_entry_t *entry = OD_find(SRDO->OD, index); ODR_t odRet = OD_getSub(entry, subIndex, &OD_IOcopy, false); if (odRet != ODR_OK) { err = ERR_INFO(0x1381UL + SRDO_Index, i + 1UL, 5); @@ -644,9 +615,9 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* Configure CAN tx buffers */ if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_TX)) { - - SRDO->CANtxBuff[0] = CO_CANtxBufferInit(CANdevTxNormal, /* CAN device */ - CANdevTxIdxNormal, /* index of specific buffer inside CAN module */ + /* Normal Configuration */ + SRDO->CANtxBuff[0] = CO_CANtxBufferInit(SRDO->CANdevTx[0], /* CAN device */ + SRDO->CANdevTxIdx[0], /* index of specific buffer inside CAN module */ (uint16_t)COB_ID1_normal, /* CAN identifier */ false, /* rtr */ SRDO->dataLength, /* number of data bytes */ @@ -656,8 +627,9 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ err = ERR_INFO(0x1301UL + SRDO_Index, 5, 10); } - SRDO->CANtxBuff[1] = CO_CANtxBufferInit(CANdevTxInverted, /* CAN device */ - CANdevTxIdxInverted, /* index of specific buffer inside CAN module */ + /* Inverted Configuration */ + SRDO->CANtxBuff[1] = CO_CANtxBufferInit(SRDO->CANdevTx[1], /* CAN device */ + SRDO->CANdevTxIdx[1], /* index of specific buffer inside CAN module */ (uint16_t)COB_ID2_inverted, /* CAN identifier */ false, /* rtr */ SRDO->dataLength, /* number of data bytes */ @@ -670,9 +642,9 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ /* Configure CAN rx buffers */ if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_RX)) { - - ret = CO_CANrxBufferInit(CANdevRxNormal, /* CAN device */ - CANdevRxIdxNormal, /* rx buffer index */ + /* Normal Configuration */ + ret = CO_CANrxBufferInit(SRDO->CANdevRx[0], /* CAN device */ + SRDO->CANdevRxIdx[0], /* rx buffer index */ (uint16_t)COB_ID1_normal, /* CAN identifier */ 0x7FF, /* mask */ false, /* rtr */ @@ -683,8 +655,9 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ err = ERR_INFO(0x1301UL + SRDO_Index, 5, 11); } - ret = CO_CANrxBufferInit(CANdevRxInverted, /* CAN device */ - CANdevRxIdxInverted, /* rx buffer index */ + /* Inverted Configuration */ + ret = CO_CANrxBufferInit(SRDO->CANdevRx[1], /* CAN device */ + SRDO->CANdevRxIdx[1], /* rx buffer index */ (uint16_t)COB_ID2_inverted, /* CAN identifier */ 0x7FF, /* mask */ false, /* rtr */ @@ -704,11 +677,12 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ } else { if (ret == CO_ERROR_NO) { - CO_errorReport(em, CO_EM_SRDO_CONFIGURATION, CO_EMC_DATA_SET, err); + CO_errorReport(SRDO->em, CO_EM_SRDO_CONFIGURATION, CO_EMC_DATA_SET, err); configurationValidUnset(SRDO->SRDOGuard); } } + if (errInfo != NULL) { *errInfo = err; } @@ -716,6 +690,62 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ return ret; } +CO_ReturnError_t +CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_t* OD, CO_EM_t* em, uint8_t nodeId, + uint16_t defaultCOB_ID, OD_entry_t* OD_130x_SRDOCommPar, OD_entry_t* OD_138x_SRDOMapPar, + CO_CANmodule_t* CANdevRxNormal, CO_CANmodule_t* CANdevRxInverted, uint16_t CANdevRxIdxNormal, + uint16_t CANdevRxIdxInverted, CO_CANmodule_t* CANdevTxNormal, CO_CANmodule_t* CANdevTxInverted, + uint16_t CANdevTxIdxNormal, uint16_t CANdevTxIdxInverted, uint32_t* errInfo) { + + CO_ReturnError_t ret = CO_ERROR_NO; + + /* verify arguments */ + if ((SRDO == NULL) || (SRDOGuard == NULL) || (OD == NULL) || (em == NULL) + || (OD_130x_SRDOCommPar == NULL) || (OD_138x_SRDOMapPar == NULL) + || (CANdevRxNormal == NULL) || (CANdevRxInverted == NULL) + || (CANdevTxNormal == NULL) || (CANdevTxInverted == NULL)) { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + /* clear object and configure some object variables */ + else { + (void)memset(SRDO, 0, sizeof(CO_SRDO_t)); + + SRDO->SRDOGuard = SRDOGuard; + SRDO->OD = OD; + SRDO->em = em; + SRDO->defaultCOB_ID = defaultCOB_ID; + SRDO->nodeId = nodeId; + SRDO->CANdevTx[0] = CANdevTxNormal; + SRDO->CANdevTx[1] = CANdevTxInverted; + SRDO->CANdevRx[0] = CANdevRxNormal; + SRDO->CANdevRx[1] = CANdevRxInverted; + + SRDO->CANdevTxIdx[0] = CANdevTxIdxNormal; + SRDO->CANdevTxIdx[1] = CANdevTxIdxInverted; + SRDO->CANdevRxIdx[0] = CANdevRxIdxNormal; + SRDO->CANdevRxIdx[1] = CANdevRxIdxInverted; + + SRDO->OD_communicationParam_entry = OD_130x_SRDOCommPar; + SRDO->OD_mappingParam_entry = OD_138x_SRDOMapPar; + + /* Configure Object dictionary entry at index 0x1301+ */ + SRDO->OD_communicationParam_ext.object = SRDO; + SRDO->OD_communicationParam_ext.read = OD_read_SRDO_communicationParam; + SRDO->OD_communicationParam_ext.write = OD_write_SRDO_communicationParam; + (void)OD_extension_init(OD_130x_SRDOCommPar, &SRDO->OD_communicationParam_ext); + + /* Configure Object dictionary entry at index 0x1381+ */ + SRDO->OD_mappingParam_extension.object = SRDO; + SRDO->OD_mappingParam_extension.read = OD_readOriginal; + SRDO->OD_mappingParam_extension.write = OD_write_SRDO_mappingParam; + (void)OD_extension_init(OD_138x_SRDOMapPar, &SRDO->OD_mappingParam_extension); + + ret = CO_SRDO_config(SRDO, SRDO_Index, SRDOGuard, errInfo); + } + + return ret; +} + CO_ReturnError_t CO_SRDO_requestSend(CO_SRDO_t* SRDO) { CO_ReturnError_t ret; diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 9abe851d..b44ec65e 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -126,11 +126,13 @@ typedef struct { /** True if all SRDO objects are properly configured. Set after successful * finish of all @CO_SRDO_init() functions. Cleared on configuration change. */ bool_t configurationValid; - /** Private helper variable set on the start of SRDO configuration */ - bool_t privateConfigValid; /** Object for input / output on the OD variable 13FE:00. Configuration * of any of the the SRDO parameters will write 0 to that variable. */ OD_IO_t OD_IO_configurationValid; + + OD_entry_t* OD_13FE_entry; + OD_entry_t* OD_13FF_entry; + /** Extension for OD object */ OD_extension_t OD_13FE_extension; /** Extension for OD object */ @@ -141,11 +143,15 @@ typedef struct { * SRDO object. */ typedef struct { - CO_SRDOGuard_t* SRDOGuard; /**< From CO_SRDO_init() */ - CO_EM_t* em; /**< From CO_SRDO_init() */ - uint16_t defaultCOB_ID; /**< From CO_SRDO_init() */ - uint8_t nodeId; /**< From CO_SRDO_init() */ - CO_CANmodule_t* CANdevTx[2];/**< From CO_SRDO_init() */ + CO_SRDOGuard_t* SRDOGuard; /**< From CO_SRDO_init() */ + OD_t *OD; /**< From CO_SRDO_init() */ + CO_EM_t* em; /**< From CO_SRDO_init() */ + uint16_t defaultCOB_ID; /**< From CO_SRDO_init() */ + uint8_t nodeId; /**< From CO_SRDO_init() */ + CO_CANmodule_t* CANdevTx[2]; /**< From CO_SRDO_init() */ + uint16_t CANdevTxIdx[2]; /**< From CO_SRDO_init() */ + CO_CANmodule_t* CANdevRx[2]; /**< From CO_SRDO_init() */ + uint16_t CANdevRxIdx[2]; /**< From CO_SRDO_init() */ /** Internal state of this SRDO. */ CO_SRDO_state_t internalState; /** Copy of variable, internal usage. */ @@ -183,6 +189,10 @@ typedef struct { uint8_t CANrxData[2][CO_SRDO_MAX_SIZE]; /** If true, next processed SRDO message is normal (not inverted) */ bool_t nextIsNormal; + + OD_entry_t* OD_communicationParam_entry;/**< From CO_SRDO_init() */ + OD_entry_t* OD_mappingParam_entry;/**< From CO_SRDO_init() */ + /** Extension for OD object */ OD_extension_t OD_communicationParam_ext; /** Extension for OD object */ @@ -209,19 +219,9 @@ typedef struct { * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_SRDO_init_start(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, +CO_ReturnError_t CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo); -/** - * Finalize SRDOGuard object. - * - * Function must be called in the communication reset section after @CO_SRDO_init functions. - * - * @param SRDOGuard This object will be finalized. - */ -static inline void CO_SRDO_init_end(CO_SRDOGuard_t* SRDOGuard) { - SRDOGuard->configurationValid = SRDOGuard->privateConfigValid; -} /** * Initialize SRDO object. @@ -255,8 +255,7 @@ static inline void CO_SRDO_init_end(CO_SRDOGuard_t* SRDOGuard) { */ CO_ReturnError_t CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_t* OD, CO_EM_t* em, uint8_t nodeId, uint16_t defaultCOB_ID, OD_entry_t* OD_130x_SRDOCommPar, - OD_entry_t* OD_138x_SRDOMapPar, OD_entry_t* OD_13FE_configurationValid, - OD_entry_t* OD_13FF_safetyConfigurationSignature, CO_CANmodule_t* CANdevRxNormal, + OD_entry_t* OD_138x_SRDOMapPar, CO_CANmodule_t* CANdevRxNormal, CO_CANmodule_t* CANdevRxInverted, uint16_t CANdevRxIdxNormal, uint16_t CANdevRxIdxInverted, CO_CANmodule_t* CANdevTxNormal, CO_CANmodule_t* CANdevTxInverted, uint16_t CANdevTxIdxNormal, uint16_t CANdevTxIdxInverted, uint32_t* errInfo); @@ -288,6 +287,9 @@ void CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalP */ CO_ReturnError_t CO_SRDO_requestSend(CO_SRDO_t* SRDO); + +CO_ReturnError_t CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, uint32_t* errInfo); + /** * Process transmitting/receiving individual SRDO message. * diff --git a/CANopen.c b/CANopen.c index 07e0a964..d085df04 100644 --- a/CANopen.c +++ b/CANopen.c @@ -723,6 +723,7 @@ void CO_delete(CO_t *co) { CO_free(co->em_fifo); #endif + #if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 CO_free(co->NGslave); #endif @@ -1366,7 +1367,7 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, #if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 if (CO_GET_CNT(SRDO) > 0U) { CO_ReturnError_t err; - err = CO_SRDO_init_start(co->SRDOGuard, + err = CO_SRDOGuard_init(co->SRDOGuard, OD_GET(H13FE, OD_H13FE_SRDO_VALID), OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), errInfo); @@ -1387,8 +1388,6 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, ((i == 0U) ? CO_CAN_ID_SRDO_1 : 0U), SRDOcomm, SRDOmap, - OD_GET(H13FE, OD_H13FE_SRDO_VALID), - OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), co->CANmodule, co->CANmodule, CANdevRxIdx, @@ -1402,8 +1401,6 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, SRDOcomm++; SRDOmap++; } - - CO_SRDO_init_end(co->SRDOGuard); } #endif @@ -1641,6 +1638,10 @@ CO_SRDO_state_t CO_process_SRDO(CO_t *co, uint32_t timeDifference_us, uint32_t *timerNext_us) { + static bool_t NMTisOperationalPrevius = false; + uint8_t i; + CO_ReturnError_t err; + if (co->nodeIdUnconfigured) { return CO_SRDO_state_unknown; } @@ -1649,9 +1650,22 @@ CO_SRDO_state_t CO_process_SRDO(CO_t *co, CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; + if( NMTisOperationalPrevius != NMTisOperational ) { + NMTisOperationalPrevius = NMTisOperational; + if( NMTisOperational ) { + for (i = 0; i < CO_GET_CNT(SRDO); i++) { + err = CO_SRDO_config( &co->SRDO[i], + i, + co->SRDOGuard, NULL ); + + if (err != CO_ERROR_NO) { return CO_SRDO_state_error_internal; } + } + } + } + CO_SRDO_state_t lowestState = CO_SRDO_state_deleted; - for (uint16_t i = 0; i < CO_GET_CNT(SRDO); i++) { + for (i = 0; i < CO_GET_CNT(SRDO); i++) { CO_SRDO_state_t state = CO_SRDO_process(&co->SRDO[i], timeDifference_us, timerNext_us, From 7db21c1f91b7a280687dc1097443bd6037df2368 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 5 Jul 2024 11:14:37 +0200 Subject: [PATCH 470/520] CO_SDO_server.c fix missing "bufShifted" --- 301/CO_SDOserver.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 7732a823..599f13a4 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -667,7 +667,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { if (SDO->finished) { /* int16_t .. uint64_t */ - reverseBytes(bufShifted, countRd); + reverseBytes(&SDO->buf[countRemain], countRd); } else { *abortCode = CO_SDO_AB_PRAM_INCOMPAT; @@ -680,7 +680,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 /* update the crc */ if (calculateCrc && SDO->block_crcEnabled) { - SDO->block_crc = crc16_ccitt(bufShifted, countRd, SDO->block_crc); + SDO->block_crc = crc16_ccitt(&SDO->buf[countRemain], countRd, SDO->block_crc); } #endif @@ -1183,9 +1183,9 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: case CO_SDO_ST_UPLOAD_BLK_END_SREQ: case CO_SDO_ST_UPLOAD_BLK_END_CRSP: - + #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) == 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: case CO_SDO_ST_UPLOAD_SEGMENT_REQ: #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) == 0 From fcd89f87deb61ed02171c01ad3aea40f24945fec Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 5 Jul 2024 18:38:01 +0200 Subject: [PATCH 471/520] Remove comments from arguments in CO_CANrxBufferInit and CO_CANtxBufferInit --- 301/CO_Emergency.c | 38 ++++++++++++------------- 301/CO_NMT_Heartbeat.c | 38 ++++++++++++------------- 301/CO_Node_Guarding.c | 52 +++++++++++++++++----------------- 301/CO_PDO.c | 51 +++++++++++++++++---------------- 301/CO_SDOclient.c | 26 ++++++++--------- 301/CO_SDOserver.c | 26 ++++++++--------- 301/CO_SYNC.c | 64 +++++++++++++++++++++--------------------- 301/CO_TIME.c | 26 ++++++++--------- 304/CO_GFC.c | 26 ++++++++--------- 304/CO_SRDO.c | 52 +++++++++++++++++----------------- 305/CO_LSSmaster.c | 26 ++++++++--------- 305/CO_LSSslave.c | 26 ++++++++--------- 12 files changed, 225 insertions(+), 226 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 1ffe96a2..7a96fe4e 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -109,12 +109,12 @@ static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, /* configure emergency message CAN transmission */ if (newEnabled) { em->CANtxBuff = CO_CANtxBufferInit( - em->CANdevTx, /* CAN device */ - em->CANdevTxIdx, /* index of specific buffer inside CAN module */ - newCanId, /* CAN identifier */ - false, /* rtr */ - 8U, /* number of data bytes */ - false); /* synchronous message flag bit */ + em->CANdevTx, + em->CANdevTxIdx, + newCanId, + false, + 8U, + false); } /* write value to the original location in the Object Dictionary */ @@ -462,12 +462,12 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->nodeId = nodeId; em->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - producerCanId, /* CAN identifier */ - false, /* rtr */ - 8U, /* number of data bytes */ - false); /* synchronous message flag bit */ + CANdevTx, + CANdevTxIdx, + producerCanId, + false, + 8U, + false); if (em->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -513,13 +513,13 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->pFunctSignalRx = NULL; /* configure SDO server CAN reception */ ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - CO_CAN_ID_EMERGENCY, /* CAN identifier */ - 0x780, /* mask */ - false, /* rtr */ - (void*)em, /* object passed to receive function */ - CO_EM_receive); /* this function will process received message*/ + CANdevRx, + CANdevRxIdx, + CO_CAN_ID_EMERGENCY, + 0x780, + false, + (void*)em, + CO_EM_receive); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER */ return ret; diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index ed96a53f..0872f328 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -146,13 +146,13 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, /* configure NMT CAN reception */ ret = CO_CANrxBufferInit( - NMT_CANdevRx, /* CAN device */ - NMT_rxIdx, /* rx buffer index */ - CANidRxNMT, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)NMT, /* object passed to receive function */ - CO_NMT_receive); /* this function will process received message*/ + NMT_CANdevRx, + NMT_rxIdx, + CANidRxNMT, + 0x7FF, + false, + (void*)NMT, + CO_NMT_receive); if (ret != CO_ERROR_NO) { return ret; } @@ -161,12 +161,12 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, /* configure NMT CAN transmission */ NMT->NMT_CANdevTx = NMT_CANdevTx; NMT->NMT_TXbuff = CO_CANtxBufferInit( - NMT_CANdevTx, /* CAN device */ - NMT_txIdx, /* index of specific buffer inside CAN module */ - CANidTxNMT, /* CAN identifier */ - false, /* rtr */ - 2, /* number of data bytes */ - false); /* synchronous message flag bit */ + NMT_CANdevTx, + NMT_txIdx, + CANidTxNMT, + false, + 2, + false); if (NMT->NMT_TXbuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -175,12 +175,12 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, /* configure HB CAN transmission */ NMT->HB_CANdevTx = HB_CANdevTx; NMT->HB_TXbuff = CO_CANtxBufferInit( - HB_CANdevTx, /* CAN device */ - HB_txIdx, /* index of specific buffer inside CAN module */ - CANidTxHB, /* CAN identifier */ - false, /* rtr */ - 1, /* number of data bytes */ - false); /* synchronous message flag bit */ + HB_CANdevTx, + HB_txIdx, + CANidTxHB, + false, + 1, + false); if (NMT->HB_TXbuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 6b751ec0..ac260bc4 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -176,13 +176,13 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, /* configure CAN reception */ ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - CANidNodeGuarding, /* CAN identifier */ - 0x7FF, /* mask */ - true, /* rtr */ - (void*)ngs, /* object passed to receive function */ - CO_ngs_receive); /* this function will process received message*/ + CANdevRx, + CANdevRxIdx, + CANidNodeGuarding, + 0x7FF, + true, + (void*)ngs, + CO_ngs_receive); if (ret != CO_ERROR_NO) { return ret; } @@ -190,12 +190,12 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, /* configure CAN transmission */ ngs->CANdevTx = CANdevTx; ngs->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - CANidNodeGuarding, /* CAN identifier */ - false, /* rtr */ - 1, /* number of data bytes */ - false); /* synchronous message flag bit */ + CANdevTx, + CANdevTxIdx, + CANidNodeGuarding, + false, + 1, + false); if (ngs->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -334,13 +334,13 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, /* configure CAN reception. One buffer will receive all messages * from CAN-id 0x700 to 0x7FF. */ ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - CO_CAN_ID_HEARTBEAT,/* CAN identifier = 0x700 */ - 0x780, /* mask - accept any combination of lower 7 bits*/ - false, /* rtr */ - (void*)ngm, /* object passed to receive function */ - CO_ngm_receive); /* this function will process received message*/ + CANdevRx, + CANdevRxIdx, + CO_CAN_ID_HEARTBEAT, + 0x780, + false, + (void*)ngm, + CO_ngm_receive); if (ret != CO_ERROR_NO) { return ret; } @@ -349,12 +349,12 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, ngm->CANdevTx = CANdevTx; ngm->CANdevTxIdx = CANdevTxIdx; ngm->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - CO_CAN_ID_HEARTBEAT,/* CAN identifier - will be changed later.*/ - true, /* rtr */ - 1, /* number of data bytes (rtr indication only) */ - 0); /* synchronous message flag bit */ + CANdevTx, + CANdevTxIdx, + CO_CAN_ID_HEARTBEAT, + true, + 1, + 0); if (ngm->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 8b4dbc19..14c1b735 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -561,13 +561,13 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, } CO_ReturnError_t ret = CO_CANrxBufferInit( - PDO->CANdev, /* CAN device */ - PDO->CANdevIdx, /* rx buffer index */ - CAN_ID, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)RPDO, /* object passed to receive function */ - CO_PDO_receive); /* this function will process rx msg */ + PDO->CANdev, + PDO->CANdevIdx, + CAN_ID, + 0x7FF, + false, + (void*)RPDO, + CO_PDO_receive); if (valid && (ret == CO_ERROR_NO)) { PDO->valid = true; @@ -707,13 +707,13 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, } ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - CAN_ID, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)RPDO, /* object passed to receive function */ - CO_PDO_receive); /* this function will process received message*/ + CANdevRx, + CANdevRxIdx, + CAN_ID, + 0x7FF, + false, + (void*)RPDO, + CO_PDO_receive); if (ret != CO_ERROR_NO) { return ret; } @@ -996,13 +996,12 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, } CO_CANtx_t *CANtxBuff = CO_CANtxBufferInit( - PDO->CANdev, /* CAN device */ - PDO->CANdevIdx, /* index of specific buffer inside CAN mod. */ - CAN_ID, /* CAN identifier */ - false, /* rtr */ - PDO->dataLength, /* number of data bytes */ + PDO->CANdev, + PDO->CANdevIdx, + CAN_ID, + false, + PDO->dataLength, TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); - /* synchronous message flag */ if (CANtxBuff == NULL) { return ODR_DEV_INCOMPAT; @@ -1176,13 +1175,13 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, } TPDO->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - CAN_ID, /* CAN identifier */ - false, /* rtr */ - PDO->dataLength, /* number of data bytes */ + CANdevTx, + CANdevTxIdx, + CAN_ID, + false, + PDO->dataLength, TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); - /* synchronous message flag bit */ + if (TPDO->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 88b93562..bc71c0fb 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -411,22 +411,22 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, /* configure SDO client CAN reception */ CO_ReturnError_t ret = CO_CANrxBufferInit( - SDO_C->CANdevRx, /* CAN device */ - SDO_C->CANdevRxIdx, /* rx buffer index */ - CanIdS2C, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)SDO_C, /* object passed to receive function */ - CO_SDOclient_receive); /* this function will process rx msg */ + SDO_C->CANdevRx, + SDO_C->CANdevRxIdx, + CanIdS2C, + 0x7FF, + false, + (void*)SDO_C, + CO_SDOclient_receive); /* configure SDO client CAN transmission */ SDO_C->CANtxBuff = CO_CANtxBufferInit( - SDO_C->CANdevTx, /* CAN device */ - SDO_C->CANdevTxIdx, /* index of buffer inside CAN module */ - CanIdC2S, /* CAN identifier */ - false, /* rtr */ - 8, /* number of data bytes */ - false); /* synchronous message flag bit */ + SDO_C->CANdevTx, + SDO_C->CANdevTxIdx, + CanIdC2S, + false, + 8, + false); if ((ret != CO_ERROR_NO) || (SDO_C->CANtxBuff == NULL)) { diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 599f13a4..2d6de334 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -199,22 +199,22 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, /* configure SDO server CAN reception */ CO_ReturnError_t ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - idC2S, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)SDO, /* object passed to receive function */ - CO_SDO_receive); /* this function will process rx msg */ + CANdevRx, + CANdevRxIdx, + idC2S, + 0x7FF, + false, + (void*)SDO, + CO_SDO_receive); /* configure SDO server CAN transmission */ SDO->CANtxBuff = CO_CANtxBufferInit( - SDO->CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of buffer inside CAN module */ - idS2C, /* CAN identifier */ - false, /* rtr */ - 8, /* number of data bytes */ - false); /* synchronous message flag bit */ + SDO->CANdevTx, + CANdevTxIdx, + idS2C, + false, + 8, + false); if (SDO->CANtxBuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index b2a78879..9bc3fce7 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -110,13 +110,13 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, /* Configure CAN receive and transmit buffers */ if (CAN_ID != SYNC->CAN_ID) { CO_ReturnError_t CANret = CO_CANrxBufferInit( - SYNC->CANdevRx, /* CAN device */ - SYNC->CANdevRxIdx, /* rx buffer index */ - CAN_ID, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)SYNC, /* object passed to receive function */ - CO_SYNC_receive); /* this function will process received message*/ + SYNC->CANdevRx, + SYNC->CANdevRxIdx, + CAN_ID, + 0x7FF, + false, + (void*)SYNC, + CO_SYNC_receive); if (CANret != CO_ERROR_NO) { return ODR_DEV_INCOMPAT; @@ -124,12 +124,12 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->CANtxBuff = CO_CANtxBufferInit( - SYNC->CANdevTx, /* CAN device */ - SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ - CAN_ID, /* CAN identifier */ - false, /* rtr */ - (SYNC->counterOverflowValue != 0U) ? 1U : 0U, /* number of data bytes */ - false); /* synchronous message flag bit */ + SYNC->CANdevTx, + SYNC->CANdevTxIdx, + CAN_ID, + false, + (SYNC->counterOverflowValue != 0U) ? 1U : 0U, + false); if (SYNC->CANtxBuff == NULL) { SYNC->isProducer = false; @@ -180,12 +180,12 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, /* Configure CAN transmit buffer */ SYNC->CANtxBuff = CO_CANtxBufferInit( - SYNC->CANdevTx, /* CAN device */ - SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */ - SYNC->CAN_ID, /* CAN identifier */ - false, /* rtr */ - (syncCounterOvf != 0U) ? 1U : 0U, /* number of data bytes */ - false); /* synchronous message flag bit */ + SYNC->CANdevTx, + SYNC->CANdevTxIdx, + SYNC->CAN_ID, + false, + (syncCounterOvf != 0U) ? 1U : 0U, + false); if (SYNC->CANtxBuff == NULL) { SYNC->isProducer = false; @@ -319,25 +319,25 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, /* configure SYNC CAN reception and transmission */ CO_ReturnError_t ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - (uint16_t)(cobIdSync & 0x7FFU), /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)SYNC, /* object passed to receive function */ - CO_SYNC_receive); /* this function will process received message*/ + CANdevRx, + CANdevRxIdx, + (uint16_t)(cobIdSync & 0x7FFU), + 0x7FF, + false, + (void*)SYNC, + CO_SYNC_receive); if (ret != CO_ERROR_NO) { return ret; } #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - (uint16_t)(cobIdSync & 0x7FFU), /* CAN identifier */ - false, /* rtr */ - (syncCounterOvf != 0U) ? 1U : 0U, /* number of data bytes */ - false); /* synchronous message flag bit */ + CANdevTx, + CANdevTxIdx, + (uint16_t)(cobIdSync & 0x7FFU), + false, + (syncCounterOvf != 0U) ? 1U : 0U, + false); if (SYNC->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 067a3c77..809b9628 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -133,13 +133,13 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, /* configure TIME consumer message reception */ if (TIME->isConsumer) { CO_ReturnError_t ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - cobId, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)TIME, /* object passed to receive function */ - CO_TIME_receive);/*this function will process received message*/ + CANdevRx, + CANdevRxIdx, + cobId, + 0x7FF, + false, + (void*)TIME, + CO_TIME_receive); if (ret != CO_ERROR_NO) { return ret; } @@ -149,12 +149,12 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, /* configure TIME producer message transmission */ TIME->CANdevTx = CANdevTx; TIME->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - cobId, /* CAN identifier */ - false, /* rtr */ - CO_TIME_MSG_LENGTH, /* number of data bytes */ - false); /* synchronous message flag bit */ + CANdevTx, + CANdevTxIdx, + cobId, + false, + CO_TIME_MSG_LENGTH, + false); if (TIME->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/304/CO_GFC.c b/304/CO_GFC.c index 6b2ac520..d5792862 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -100,12 +100,12 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC #if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0 GFC->CANdevTx = GFC_CANdevTx; - GFC->CANtxBuff = CO_CANtxBufferInit(GFC->CANdevTx, /* CAN device */ - GFC_txIdx, /* index of specific buffer inside CAN module */ - CANidTxGFC, /* CAN identifier */ - false, /* rtr */ - 0, /* number of data bytes */ - false); /* synchronous message flag bit */ + GFC->CANtxBuff = CO_CANtxBufferInit(GFC->CANdevTx, + GFC_txIdx, + CANidTxGFC, + false, + 0, + false); if (GFC->CANtxBuff == NULL) { return CO_ERROR_TX_UNCONFIGURED; @@ -118,13 +118,13 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC #if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0 GFC->functSignalObjectSafe = NULL; GFC->pFunctSignalSafe = NULL; - const CO_ReturnError_t r = CO_CANrxBufferInit(GFC_CANdevRx, /* CAN device */ - GFC_rxIdx, /* rx buffer index */ - CANidRxGFC, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)GFC, /* object passed to receive function */ - CO_GFC_receive); /* this function will process received message */ + const CO_ReturnError_t r = CO_CANrxBufferInit(GFC_CANdevRx, + GFC_rxIdx, + CANidRxGFC, + 0x7FF, + false, + (void*)GFC, + CO_GFC_receive); if (r != CO_ERROR_NO) { return r; } diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 081542e0..48e642f2 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -616,24 +616,24 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, /* Configure CAN tx buffers */ if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_TX)) { /* Normal Configuration */ - SRDO->CANtxBuff[0] = CO_CANtxBufferInit(SRDO->CANdevTx[0], /* CAN device */ - SRDO->CANdevTxIdx[0], /* index of specific buffer inside CAN module */ - (uint16_t)COB_ID1_normal, /* CAN identifier */ - false, /* rtr */ - SRDO->dataLength, /* number of data bytes */ - false); /* synchronous message flag bit */ + SRDO->CANtxBuff[0] = CO_CANtxBufferInit(SRDO->CANdevTx[0], + SRDO->CANdevTxIdx[0], + (uint16_t)COB_ID1_normal, + false, + SRDO->dataLength, + false); if (SRDO->CANtxBuff[0] == NULL) { err = ERR_INFO(0x1301UL + SRDO_Index, 5, 10); } /* Inverted Configuration */ - SRDO->CANtxBuff[1] = CO_CANtxBufferInit(SRDO->CANdevTx[1], /* CAN device */ - SRDO->CANdevTxIdx[1], /* index of specific buffer inside CAN module */ - (uint16_t)COB_ID2_inverted, /* CAN identifier */ - false, /* rtr */ - SRDO->dataLength, /* number of data bytes */ - false); /* synchronous message flag bit */ + SRDO->CANtxBuff[1] = CO_CANtxBufferInit(SRDO->CANdevTx[1], + SRDO->CANdevTxIdx[1], + (uint16_t)COB_ID2_inverted, + false, + SRDO->dataLength, + false); if (SRDO->CANtxBuff[1] == NULL) { err = ERR_INFO(0x1301UL + SRDO_Index, 6, 10); @@ -643,26 +643,26 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, /* Configure CAN rx buffers */ if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_RX)) { /* Normal Configuration */ - ret = CO_CANrxBufferInit(SRDO->CANdevRx[0], /* CAN device */ - SRDO->CANdevRxIdx[0], /* rx buffer index */ - (uint16_t)COB_ID1_normal, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)SRDO, /* object passed to the receive function */ - CO_SRDO_receive_normal); /* this function will process received message */ + ret = CO_CANrxBufferInit(SRDO->CANdevRx[0], + SRDO->CANdevRxIdx[0], + (uint16_t)COB_ID1_normal, + 0x7FF, + false, + (void*)SRDO, + CO_SRDO_receive_normal); if (ret != CO_ERROR_NO) { err = ERR_INFO(0x1301UL + SRDO_Index, 5, 11); } /* Inverted Configuration */ - ret = CO_CANrxBufferInit(SRDO->CANdevRx[1], /* CAN device */ - SRDO->CANdevRxIdx[1], /* rx buffer index */ - (uint16_t)COB_ID2_inverted, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)SRDO, /* object passed to the receive function */ - CO_SRDO_receive_inverted); /* this function will process received message */ + ret = CO_CANrxBufferInit(SRDO->CANdevRx[1], + SRDO->CANdevRxIdx[1], + (uint16_t)COB_ID2_inverted, + 0x7FF, + false, + (void*)SRDO, + CO_SRDO_receive_inverted); if (ret != CO_ERROR_NO) { err = ERR_INFO(0x1301UL + SRDO_Index, 6, 11); diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 77b499d0..9693916e 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -157,23 +157,23 @@ CO_ReturnError_t CO_LSSmaster_init( /* configure LSS CAN Slave response message reception */ ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - CANidLssSlave, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)LSSmaster, /* object passed to receive function */ - CO_LSSmaster_receive);/* this function will process received message */ + CANdevRx, + CANdevRxIdx, + CANidLssSlave, + 0x7FF, + false, + (void*)LSSmaster, + CO_LSSmaster_receive); /* configure LSS CAN Master message transmission */ LSSmaster->CANdevTx = CANdevTx; LSSmaster->TXbuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - CANidLssMaster, /* CAN identifier */ - false, /* rtr */ - 8, /* number of data bytes */ - false); /* synchronous message flag bit */ + CANdevTx, + CANdevTxIdx, + CANidLssMaster, + false, + 8, + false); if (LSSmaster->TXbuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 1afc11ce..b3396d25 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -241,23 +241,23 @@ CO_ReturnError_t CO_LSSslave_init( /* configure LSS CAN Master message reception */ ret = CO_CANrxBufferInit( - CANdevRx, /* CAN device */ - CANdevRxIdx, /* rx buffer index */ - CANidLssMaster, /* CAN identifier */ - 0x7FF, /* mask */ - false, /* rtr */ - (void*)LSSslave, /* object passed to receive function */ - CO_LSSslave_receive); /* this function will process received message */ + CANdevRx, + CANdevRxIdx, + CANidLssMaster, + 0x7FF, + false, + (void*)LSSslave, + CO_LSSslave_receive); /* configure LSS CAN Slave response message transmission */ LSSslave->CANdevTx = CANdevTx; LSSslave->TXbuff = CO_CANtxBufferInit( - CANdevTx, /* CAN device */ - CANdevTxIdx, /* index of specific buffer inside CAN module */ - CANidLssSlave, /* CAN identifier */ - false, /* rtr */ - 8, /* number of data bytes */ - false); /* synchronous message flag bit */ + CANdevTx, + CANdevTxIdx, + CANidLssSlave, + false, + 8, + false); if (LSSslave->TXbuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; From f064eeaa4060290665c20eab9040ec4ff1c732af Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 6 Jul 2024 13:03:00 +0200 Subject: [PATCH 472/520] Format the license information in files. --- 301/CO_Emergency.c | 17 ++++++----------- 301/CO_Emergency.h | 17 ++++++----------- 301/CO_HBconsumer.c | 17 ++++++----------- 301/CO_HBconsumer.h | 17 ++++++----------- 301/CO_NMT_Heartbeat.c | 17 ++++++----------- 301/CO_NMT_Heartbeat.h | 17 ++++++----------- 301/CO_Node_Guarding.c | 17 ++++++----------- 301/CO_Node_Guarding.h | 17 ++++++----------- 301/CO_ODinterface.c | 17 ++++++----------- 301/CO_ODinterface.h | 17 ++++++----------- 301/CO_PDO.c | 17 ++++++----------- 301/CO_PDO.h | 17 ++++++----------- 301/CO_SDOclient.c | 17 ++++++----------- 301/CO_SDOclient.h | 17 ++++++----------- 301/CO_SDOserver.c | 17 ++++++----------- 301/CO_SDOserver.h | 17 ++++++----------- 301/CO_SYNC.c | 17 ++++++----------- 301/CO_SYNC.h | 17 ++++++----------- 301/CO_TIME.c | 17 ++++++----------- 301/CO_TIME.h | 17 ++++++----------- 301/CO_config.h | 17 ++++++----------- 301/CO_driver.h | 17 ++++++----------- 301/CO_fifo.c | 17 ++++++----------- 301/CO_fifo.h | 17 ++++++----------- 301/crc16-ccitt.c | 17 ++++++----------- 301/crc16-ccitt.h | 17 ++++++----------- 303/CO_LEDs.c | 17 ++++++----------- 303/CO_LEDs.h | 17 ++++++----------- 304/CO_GFC.c | 17 ++++++----------- 304/CO_GFC.h | 17 ++++++----------- 304/CO_SRDO.c | 17 ++++++----------- 304/CO_SRDO.h | 17 ++++++----------- 305/CO_LSS.h | 17 ++++++----------- 305/CO_LSSmaster.c | 17 ++++++----------- 305/CO_LSSmaster.h | 17 ++++++----------- 305/CO_LSSslave.c | 17 ++++++----------- 305/CO_LSSslave.h | 17 ++++++----------- 309/CO_gateway_ascii.c | 17 ++++++----------- 309/CO_gateway_ascii.h | 17 ++++++----------- CANopen.c | 17 ++++++----------- CANopen.h | 17 ++++++----------- example/CO_driver_blank.c | 17 ++++++----------- example/CO_driver_target.h | 17 ++++++----------- example/CO_storageBlank.c | 17 ++++++----------- example/CO_storageBlank.h | 17 ++++++----------- example/main_blank.c | 17 ++++++----------- extra/CO_trace.c | 17 ++++++----------- extra/CO_trace.h | 17 ++++++----------- storage/CO_eeprom.h | 17 ++++++----------- storage/CO_storage.c | 17 ++++++----------- storage/CO_storage.h | 17 ++++++----------- storage/CO_storageEeprom.c | 17 ++++++----------- storage/CO_storageEeprom.h | 17 ++++++----------- 53 files changed, 318 insertions(+), 583 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 7a96fe4e..4826f925 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 661fdf63..9fec9041 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_EMERGENCY_H diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 4dc970bc..64f9c064 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "301/CO_HBconsumer.h" diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 29e942bc..38232f51 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_HB_CONS_H diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 0872f328..4e238064 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "301/CO_NMT_Heartbeat.h" diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index ec319808..0bd39370 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_NMT_HEARTBEAT_H diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index ac260bc4..942ca46f 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2023 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "301/CO_Node_Guarding.h" diff --git a/301/CO_Node_Guarding.h b/301/CO_Node_Guarding.h index 08b2b55f..35596f27 100644 --- a/301/CO_Node_Guarding.h +++ b/301/CO_Node_Guarding.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2023 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_NODE_GUARDING_H diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index d9cc744c..464c530c 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -5,21 +5,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index d09db10a..b7d3b868 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_OD_INTERFACE_H diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 14c1b735..b4bd7b25 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 4290885e..ff738458 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_PDO_H diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index bc71c0fb..7acbd6be 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -7,21 +7,16 @@ * @author Matej Severkar * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "301/CO_SDOclient.h" diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 90eb633d..f4cac5c7 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -7,21 +7,16 @@ * @author Matej Severkar * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_SDO_CLIENT_H diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 2d6de334..9b2a0a0d 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 29d6b51b..ed786091 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_SDO_SERVER_H diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 9bc3fce7..171ad998 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "301/CO_SYNC.h" diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index ac5a464b..8c2038a2 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_SYNC_H diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 809b9628..fe847d69 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -6,21 +6,16 @@ * @author Julien PEYREGNE * @copyright 2019 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/301/CO_TIME.h b/301/CO_TIME.h index a0c94a77..b57bc552 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -6,21 +6,16 @@ * @author Julien PEYREGNE * @copyright 2019 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_TIME_H diff --git a/301/CO_config.h b/301/CO_config.h index a5e8f893..89e77305 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ diff --git a/301/CO_driver.h b/301/CO_driver.h index 5c1337fd..d5885054 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_DRIVER_H diff --git a/301/CO_fifo.c b/301/CO_fifo.c index ffbb1bbe..56e3453f 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 6f68d9be..671699b0 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_FIFO_H diff --git a/301/crc16-ccitt.c b/301/crc16-ccitt.c index c8ecd498..66d50f3d 100644 --- a/301/crc16-ccitt.c +++ b/301/crc16-ccitt.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2012 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "301/crc16-ccitt.h" diff --git a/301/crc16-ccitt.h b/301/crc16-ccitt.h index a61601d8..22569039 100644 --- a/301/crc16-ccitt.h +++ b/301/crc16-ccitt.h @@ -7,21 +7,16 @@ * @author Janez Paternoster * @copyright 2012 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CRC16_CCITT_H diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 56c67751..445ea018 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "303/CO_LEDs.h" diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index 185e8a56..caa2fb23 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_LEDS_H diff --git a/304/CO_GFC.c b/304/CO_GFC.c index d5792862..8618c0c8 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -7,21 +7,16 @@ * @copyright 2020 Robert Grüning * @copyright 2024 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "304/CO_GFC.h" diff --git a/304/CO_GFC.h b/304/CO_GFC.h index f5bdba51..121946d1 100644 --- a/304/CO_GFC.h +++ b/304/CO_GFC.h @@ -7,21 +7,16 @@ * @copyright 2020 Robert Grüning * @copyright 2024 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_GFC_H diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 48e642f2..a6074fb6 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -8,21 +8,16 @@ * @copyright 2024 temi54c1l8@github * @copyright 2024 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "304/CO_SRDO.h" diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index b44ec65e..9625e22f 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -8,21 +8,16 @@ * @copyright 2024 temi54c1l8@github * @copyright 2024 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_SRDO_H diff --git a/305/CO_LSS.h b/305/CO_LSS.h index 8a2ae243..02736399 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -7,21 +7,16 @@ * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_LSS_H diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 9693916e..a8159570 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -7,21 +7,16 @@ * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 69bd0a21..437ea97d 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -7,21 +7,16 @@ * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_LSSmaster_H diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index b3396d25..ba14cf5d 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -8,21 +8,16 @@ * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index a6b5e186..e56ba443 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -8,21 +8,16 @@ * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH * * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_LSSslave_H diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 964f68a4..ed1b8b11 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -7,21 +7,16 @@ * @author Martin Wagner * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 290f9c6a..6e26260e 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -7,21 +7,16 @@ * @author Martin Wagner * @copyright 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_GATEWAY_ASCII_H diff --git a/CANopen.c b/CANopen.c index d085df04..a954af58 100644 --- a/CANopen.c +++ b/CANopen.c @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2010 - 2023 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "CANopen.h" diff --git a/CANopen.h b/CANopen.h index 780a1e13..ecbbd432 100644 --- a/CANopen.h +++ b/CANopen.h @@ -7,21 +7,16 @@ * @author Uwe Kindler * @copyright 2010 - 2023 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index e0ef6391..11fa35af 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -8,21 +8,16 @@ * @author Janez Paternoster * @copyright 2004 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index c8c32b71..d560f729 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -5,21 +5,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ diff --git a/example/CO_storageBlank.c b/example/CO_storageBlank.c index 16f92253..cf63f41c 100644 --- a/example/CO_storageBlank.c +++ b/example/CO_storageBlank.c @@ -5,21 +5,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "CO_storageBlank.h" diff --git a/example/CO_storageBlank.h b/example/CO_storageBlank.h index 5e562c6a..2e1525df 100644 --- a/example/CO_storageBlank.h +++ b/example/CO_storageBlank.h @@ -5,21 +5,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_STORAGE_BLANK_H diff --git a/example/main_blank.c b/example/main_blank.c index cb54eb01..4ec0583a 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -7,21 +7,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ diff --git a/extra/CO_trace.c b/extra/CO_trace.c index 3902f8f9..b5bb2e43 100644 --- a/extra/CO_trace.c +++ b/extra/CO_trace.c @@ -5,21 +5,16 @@ * @author Janez Paternoster * @copyright 2016 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "extra/CO_trace.h" diff --git a/extra/CO_trace.h b/extra/CO_trace.h index a2e5ae5f..370e85c1 100644 --- a/extra/CO_trace.h +++ b/extra/CO_trace.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2016 - 2020 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_TRACE_H diff --git a/storage/CO_eeprom.h b/storage/CO_eeprom.h index 94d1b306..c37c9a57 100644 --- a/storage/CO_eeprom.h +++ b/storage/CO_eeprom.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_EEPROM_H diff --git a/storage/CO_storage.c b/storage/CO_storage.c index f4068d64..eb9fd57f 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -5,21 +5,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "storage/CO_storage.h" diff --git a/storage/CO_storage.h b/storage/CO_storage.h index 35e00b06..ddfdfd30 100644 --- a/storage/CO_storage.h +++ b/storage/CO_storage.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_STORAGE_H diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 34819dbd..e635e8d2 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -5,21 +5,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #include "storage/CO_storageEeprom.h" diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h index 62d5897b..44cda6e7 100644 --- a/storage/CO_storageEeprom.h +++ b/storage/CO_storageEeprom.h @@ -6,21 +6,16 @@ * @author Janez Paternoster * @copyright 2021 Janez Paternoster * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . + * This file is part of , a CANopen Stack. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_STORAGE_EEPROM_H From 2857d749be7b2d7c13c625fee0d804a4eb91d9d3 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 6 Jul 2024 13:05:43 +0200 Subject: [PATCH 473/520] .clang-format: do not SortIncludes --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 33bb7d7f..3a8fd1e5 100644 --- a/.clang-format +++ b/.clang-format @@ -16,7 +16,7 @@ AlignConsecutiveBitFields: AlignConsecutiveDeclarations: None AlignEscapedNewlines: Right AlignOperands: Align -SortIncludes: true +SortIncludes: false InsertBraces: true # Control statements must have curly brackets AlignTrailingComments: true AllowAllArgumentsOnNextLine: true From 0d016a00198835b58d3fa9e5b60bf90ec7ebcfc3 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 6 Jul 2024 18:53:40 +0200 Subject: [PATCH 474/520] Remove /*********...*/ comment delimiters. --- 301/CO_Emergency.c | 4 ---- 301/CO_HBconsumer.c | 12 ------------ 301/CO_NMT_Heartbeat.c | 4 ---- 301/CO_Node_Guarding.c | 5 ----- 301/CO_ODinterface.c | 6 ------ 301/CO_PDO.c | 4 ---- 301/CO_SDOclient.c | 8 -------- 301/CO_SDOserver.c | 3 --- 301/CO_SYNC.c | 3 --- 301/CO_fifo.c | 8 -------- 301/crc16-ccitt.c | 2 -- 303/CO_LEDs.c | 2 -- 305/CO_LSSmaster.c | 12 ------------ 305/CO_LSSslave.c | 6 ------ 309/CO_gateway_ascii.c | 3 --- example/CO_driver_blank.c | 10 ---------- extra/CO_trace.c | 2 -- storage/CO_storageEeprom.c | 2 -- 18 files changed, 96 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 4826f925..e2f2d3b8 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -336,7 +336,6 @@ static void CO_EM_receive(void *object, void *msg) { #endif -/******************************************************************************/ CO_ReturnError_t CO_EM_init(CO_EM_t *em, CO_CANmodule_t *CANdevTx, const OD_entry_t *OD_1001_errReg, @@ -521,7 +520,6 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, } -/******************************************************************************/ #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 void CO_EM_initCallbackRx(CO_EM_t *em, void (*pFunctSignalRx)(const uint16_t ident, @@ -549,7 +547,6 @@ void CO_EM_initCallbackPre(CO_EM_t *em, #endif -/******************************************************************************/ void CO_EM_process(CO_EM_t *em, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, @@ -723,7 +720,6 @@ void CO_EM_process(CO_EM_t *em, } -/******************************************************************************/ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) { diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 64f9c064..b422c7da 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -106,7 +106,6 @@ static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, #endif -/******************************************************************************/ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, CO_EM_t *em, CO_HBconsNode_t *monitoredNodes, @@ -171,7 +170,6 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, } -/******************************************************************************/ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, uint8_t idx, uint8_t nodeId, @@ -233,7 +231,6 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -/******************************************************************************/ void CO_HBconsumer_initCallbackPre( CO_HBconsumer_t *HBcons, void *object, @@ -251,7 +248,6 @@ void CO_HBconsumer_initCallbackPre( #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0 -/******************************************************************************/ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, uint8_t idx, @@ -272,7 +268,6 @@ void CO_HBconsumer_initCallbackNmtChanged( #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 -/******************************************************************************/ void CO_HBconsumer_initCallbackNmtChanged( CO_HBconsumer_t *HBcons, uint8_t idx, @@ -291,7 +286,6 @@ void CO_HBconsumer_initCallbackNmtChanged( } -/******************************************************************************/ void CO_HBconsumer_initCallbackHeartbeatStarted( CO_HBconsumer_t *HBcons, uint8_t idx, @@ -310,7 +304,6 @@ void CO_HBconsumer_initCallbackHeartbeatStarted( } -/******************************************************************************/ void CO_HBconsumer_initCallbackTimeout( CO_HBconsumer_t *HBcons, uint8_t idx, @@ -329,7 +322,6 @@ void CO_HBconsumer_initCallbackTimeout( } -/******************************************************************************/ void CO_HBconsumer_initCallbackRemoteReset( CO_HBconsumer_t *HBcons, uint8_t idx, @@ -349,7 +341,6 @@ void CO_HBconsumer_initCallbackRemoteReset( #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI */ -/******************************************************************************/ void CO_HBconsumer_process( CO_HBconsumer_t *HBcons, bool_t NMTisPreOrOperational, @@ -498,7 +489,6 @@ void CO_HBconsumer_process( #if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT) != 0 -/******************************************************************************/ int8_t CO_HBconsumer_getIdxByNodeId( CO_HBconsumer_t *HBcons, uint8_t nodeId) @@ -523,7 +513,6 @@ int8_t CO_HBconsumer_getIdxByNodeId( } -/******************************************************************************/ CO_HBconsumer_state_t CO_HBconsumer_getState( CO_HBconsumer_t *HBcons, uint8_t idx) @@ -538,7 +527,6 @@ CO_HBconsumer_state_t CO_HBconsumer_getState( return monitoredNode->HBstate; } -/******************************************************************************/ int8_t CO_HBconsumer_getNmtState( CO_HBconsumer_t *HBcons, uint8_t idx, diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 4e238064..0c95dc6e 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -74,7 +74,6 @@ static ODR_t OD_write_1017(OD_stream_t *stream, const void *buf, } -/******************************************************************************/ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, OD_entry_t *OD_1017_ProducerHbTime, CO_EM_t *em, @@ -198,7 +197,6 @@ void CO_NMT_initCallbackPre(CO_NMT_t *NMT, #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0 -/******************************************************************************/ void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, void (*pFunctNMT)(CO_NMT_internalState_t state)) { @@ -212,7 +210,6 @@ void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, #endif -/******************************************************************************/ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, CO_NMT_internalState_t *NMTstate, uint32_t timeDifference_us, @@ -330,7 +327,6 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 -/******************************************************************************/ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, CO_NMT_command_t command, uint8_t nodeID) diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 942ca46f..a7506d4d 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -97,7 +97,6 @@ static ODR_t OD_write_100D(OD_stream_t *stream, const void *buf, } -/******************************************************************************/ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, OD_entry_t *OD_100C_GuardTime, OD_entry_t *OD_100D_LifeTimeFactor, @@ -199,7 +198,6 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, } -/******************************************************************************/ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, CO_NMT_internalState_t NMTstate, bool_t slaveDisable, @@ -305,7 +303,6 @@ static void CO_ngm_receive(void *object, void *msg) { } -/******************************************************************************/ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, CO_EM_t *em, CO_CANmodule_t *CANdevRx, @@ -358,7 +355,6 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, } -/******************************************************************************/ CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t *ngm, uint8_t index, uint8_t nodeId, @@ -392,7 +388,6 @@ CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t *ngm, } -/******************************************************************************/ void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, uint32_t timeDifference_us, uint32_t *timerNext_us) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 464c530c..3dca47a4 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -22,7 +22,6 @@ #include "301/CO_ODinterface.h" -/******************************************************************************/ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) { @@ -66,7 +65,6 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, return returnCode; } -/******************************************************************************/ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) { @@ -142,7 +140,6 @@ static ODR_t OD_writeDisabled(OD_stream_t *stream, const void *buf, } -/******************************************************************************/ OD_entry_t *OD_find(OD_t *od, uint16_t index) { if ((od == NULL) || (od->size == 0U)) { return NULL; @@ -181,7 +178,6 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index) { return NULL; /* entry does not exist in OD */ } -/******************************************************************************/ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, OD_IO_t *io, bool_t odOrig) { @@ -267,7 +263,6 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, return ODR_OK; } -/******************************************************************************/ uint32_t OD_getSDOabCode(ODR_t returnCode) { static const uint32_t abortCodes[(uint8_t)ODR_COUNT] = { 0x00000000UL, /* No abort */ @@ -303,7 +298,6 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { } -/******************************************************************************/ ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, void *val, OD_size_t len, bool_t odOrig) { diff --git a/301/CO_PDO.c b/301/CO_PDO.c index b4bd7b25..18c5dfb4 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -625,7 +625,6 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, #endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ -/******************************************************************************/ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, OD_t *OD, CO_EM_t *em, @@ -774,7 +773,6 @@ void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, #endif -/******************************************************************************/ void CO_RPDO_process(CO_RPDO_t *RPDO, #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 uint32_t timeDifference_us, @@ -1075,7 +1073,6 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, #endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ -/******************************************************************************/ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, OD_t *OD, CO_EM_t *em, @@ -1326,7 +1323,6 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { } -/******************************************************************************/ void CO_TPDO_process(CO_TPDO_t *TPDO, #if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN uint32_t timeDifference_us, diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 7acbd6be..d5022a13 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -247,7 +247,6 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC */ -/******************************************************************************/ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, OD_t *OD, OD_entry_t *OD_1280_SDOcliPar, @@ -336,7 +335,6 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -/******************************************************************************/ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, void *object, void (*pFunctSignal)(void *object)) @@ -362,7 +360,6 @@ static inline void reverseBytes(void *start, OD_size_t size) { #endif -/******************************************************************************/ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, uint32_t COB_IDClientToServer, uint32_t COB_IDServerToClient, @@ -503,7 +500,6 @@ void CO_SDOclientDownloadInitSize(CO_SDOclient_t *SDO_C, } -/******************************************************************************/ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, const uint8_t *buf, size_t count) @@ -516,7 +512,6 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, } -/******************************************************************************/ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, bool_t send_abort, @@ -1229,7 +1224,6 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, } -/******************************************************************************/ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, uint32_t timeDifference_us, bool_t send_abort, @@ -1959,7 +1953,6 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } -/******************************************************************************/ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, uint8_t *buf, size_t count) @@ -1972,7 +1965,6 @@ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, } -/******************************************************************************/ void CO_SDOclientClose(CO_SDOclient_t *SDO_C) { if (SDO_C != NULL) { SDO_C->state = CO_SDO_ST_IDLE; diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 9b2a0a0d..9948ff78 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -308,7 +308,6 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC */ -/******************************************************************************/ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, OD_t *OD, OD_entry_t *OD_1200_SDOsrvPar, @@ -434,7 +433,6 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -/******************************************************************************/ void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, void *object, void (*pFunctSignalPre)(void *object)) @@ -685,7 +683,6 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, #endif -/******************************************************************************/ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 171ad998..a1aebdec 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -196,7 +196,6 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC */ -/******************************************************************************/ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, CO_EM_t *em, OD_entry_t *OD_1005_cobIdSync, @@ -344,7 +343,6 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, #if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -/******************************************************************************/ void CO_SYNC_initCallbackPre( CO_SYNC_t *SYNC, void *object, @@ -358,7 +356,6 @@ void CO_SYNC_initCallbackPre( #endif -/******************************************************************************/ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 56e3453f..21b52151 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -47,7 +47,6 @@ #endif #endif -/******************************************************************************/ void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize) { if ((fifo == NULL) || (buf == NULL) || (bufSize < 2U)) { @@ -122,7 +121,6 @@ size_t CO_fifo_write(CO_fifo_t *fifo, } -/******************************************************************************/ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { size_t i; const uint8_t *bufSrc; @@ -172,7 +170,6 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) != 0 -/******************************************************************************/ size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset) { size_t i; @@ -255,7 +252,6 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count) { #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 -/******************************************************************************/ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { bool_t newCommand = false; size_t count; @@ -310,7 +306,6 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { } -/******************************************************************************/ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { bool_t delimCommandFound = false; bool_t alive_cycle = true; @@ -343,7 +338,6 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { } -/******************************************************************************/ size_t CO_fifo_readToken(CO_fifo_t *fifo, char *buf, size_t count, @@ -480,7 +474,6 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0 -/******************************************************************************/ /* Tables for mime-base64 encoding, as specified in RFC 2045, (without CR-LF, * but one long string). Base64 is used for encoding binary data into easy * transferable printable characters. In general, each three bytes of binary @@ -866,7 +859,6 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { } -/******************************************************************************/ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { char buf[15]; uint8_t closed = 0xFFU; diff --git a/301/crc16-ccitt.c b/301/crc16-ccitt.c index 66d50f3d..778e1eba 100644 --- a/301/crc16-ccitt.c +++ b/301/crc16-ccitt.c @@ -76,14 +76,12 @@ static const uint16_t crc16_ccitt_table[256] = { }; -/******************************************************************************/ void crc16_ccitt_single(uint16_t *crc, const uint8_t chr) { uint8_t tmp = (uint8_t)(*crc >> 8U) ^ chr; *crc = (uint16_t)((*crc << 8U) ^ crc16_ccitt_table[tmp]); } -/******************************************************************************/ uint16_t crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 445ea018..e23f5ecb 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -22,7 +22,6 @@ #if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 -/******************************************************************************/ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { CO_ReturnError_t ret = CO_ERROR_NO; @@ -38,7 +37,6 @@ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { } -/******************************************************************************/ void CO_LEDs_process(CO_LEDs_t *LEDs, uint32_t timeDifference_us, CO_NMT_internalState_t NMTstate, diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index a8159570..7336b9ba 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -121,7 +121,6 @@ static inline CO_LSSmaster_return_t CO_LSSmaster_check_timeout( } -/******************************************************************************/ CO_ReturnError_t CO_LSSmaster_init( CO_LSSmaster_t *LSSmaster, uint16_t timeout_ms, @@ -178,7 +177,6 @@ CO_ReturnError_t CO_LSSmaster_init( } -/******************************************************************************/ void CO_LSSmaster_changeTimeout( CO_LSSmaster_t *LSSmaster, uint16_t timeout_ms) @@ -190,7 +188,6 @@ void CO_LSSmaster_changeTimeout( #if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -/******************************************************************************/ void CO_LSSmaster_initCallbackPre( CO_LSSmaster_t *LSSmaster, void *object, @@ -280,7 +277,6 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( return ret; } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_swStateSelect( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, @@ -317,7 +313,6 @@ CO_LSSmaster_return_t CO_LSSmaster_swStateSelect( } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect( CO_LSSmaster_t *LSSmaster) { @@ -404,7 +399,6 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, @@ -462,7 +456,6 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, @@ -508,7 +501,6 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_configureStore( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us) @@ -549,7 +541,6 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( CO_LSSmaster_t *LSSmaster, uint16_t switchDelay_ms) @@ -623,7 +614,6 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait( return ret; } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, @@ -713,7 +703,6 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_Inquire( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, @@ -987,7 +976,6 @@ static uint8_t CO_LSSmaster_FsSearchNext( return CO_LSS_FASTSCAN_VENDOR_ID; } -/******************************************************************************/ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( CO_LSSmaster_t *LSSmaster, uint32_t timeDifference_us, diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index ba14cf5d..e39b9e40 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -196,7 +196,6 @@ static void CO_LSSslave_receive(void *object, void *msg) } -/******************************************************************************/ CO_ReturnError_t CO_LSSslave_init( CO_LSSslave_t *LSSslave, CO_LSS_address_t *lssAddress, @@ -263,7 +262,6 @@ CO_ReturnError_t CO_LSSslave_init( #if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -/******************************************************************************/ void CO_LSSslave_initCallbackPre( CO_LSSslave_t *LSSslave, void *object, @@ -277,7 +275,6 @@ void CO_LSSslave_initCallbackPre( #endif -/******************************************************************************/ void CO_LSSslave_initCkBitRateCall( CO_LSSslave_t *LSSslave, void *object, @@ -290,7 +287,6 @@ void CO_LSSslave_initCkBitRateCall( } -/******************************************************************************/ void CO_LSSslave_initActBitRateCall( CO_LSSslave_t *LSSslave, void *object, @@ -303,7 +299,6 @@ void CO_LSSslave_initActBitRateCall( } -/******************************************************************************/ void CO_LSSslave_initCfgStoreCall( CO_LSSslave_t *LSSslave, void *object, @@ -316,7 +311,6 @@ void CO_LSSslave_initCfgStoreCall( } -/******************************************************************************/ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { bool_t resetCommunication = false; diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index ed1b8b11..6071c671 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -43,7 +43,6 @@ #endif #endif -/******************************************************************************/ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, #if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN CO_SDOclient_t* SDO_C, @@ -117,7 +116,6 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, } -/******************************************************************************/ void CO_GTWA_initRead(CO_GTWA_t* gtwa, size_t (*readCallback)(void *object, const char *buf, @@ -132,7 +130,6 @@ void CO_GTWA_initRead(CO_GTWA_t* gtwa, } -/******************************************************************************/ #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { if ((gtwa != NULL) && (message != NULL)) { diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index 11fa35af..dfa46e68 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -24,13 +24,11 @@ #include "301/CO_driver.h" -/******************************************************************************/ void CO_CANsetConfigurationMode(void *CANptr){ /* Put CAN module in configuration mode */ } -/******************************************************************************/ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ /* Put CAN module in normal mode */ @@ -38,7 +36,6 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ } -/******************************************************************************/ CO_ReturnError_t CO_CANmodule_init( CO_CANmodule_t *CANmodule, void *CANptr, @@ -107,7 +104,6 @@ CO_ReturnError_t CO_CANmodule_init( } -/******************************************************************************/ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) { if (CANmodule != NULL) { /* turn off the module */ @@ -115,7 +111,6 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) { } -/******************************************************************************/ CO_ReturnError_t CO_CANrxBufferInit( CO_CANmodule_t *CANmodule, uint16_t index, @@ -155,7 +150,6 @@ CO_ReturnError_t CO_CANrxBufferInit( } -/******************************************************************************/ CO_CANtx_t *CO_CANtxBufferInit( CO_CANmodule_t *CANmodule, uint16_t index, @@ -184,7 +178,6 @@ CO_CANtx_t *CO_CANtxBufferInit( } -/******************************************************************************/ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ CO_ReturnError_t err = CO_ERROR_NO; @@ -214,7 +207,6 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ } -/******************************************************************************/ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ uint32_t tpdoDeleted = 0U; @@ -250,7 +242,6 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ } -/******************************************************************************/ /* Get error counters from the module. If necessary, function may use * different way to determine errors. */ static uint16_t rxErrors=0, txErrors=0, overflow=0; @@ -305,7 +296,6 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { } -/******************************************************************************/ typedef struct { uint32_t ident; uint8_t DLC; diff --git a/extra/CO_trace.c b/extra/CO_trace.c index b5bb2e43..e7a6a243 100644 --- a/extra/CO_trace.c +++ b/extra/CO_trace.c @@ -394,7 +394,6 @@ static CO_SDO_abortCode_t CO_ODF_trace(CO_ODF_arg_t *ODF_arg) { } -/******************************************************************************/ void CO_trace_init( CO_trace_t *trace, CO_SDO_t *SDO, @@ -451,7 +450,6 @@ void CO_trace_init( } -/******************************************************************************/ void CO_trace_process(CO_trace_t *trace, uint32_t timestamp) { if(trace->enabled) { diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index e635e8d2..a82efa09 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -98,7 +98,6 @@ static ODR_t restoreEeprom(CO_storage_entry_t *entry, } -/******************************************************************************/ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, void *storageModule, @@ -219,7 +218,6 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, } -/******************************************************************************/ void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { /* verify arguments */ if ((storage == NULL) || !storage->enabled) { From 95c1705e76e22a820a943ab5a9f4ea60b130cac2 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 6 Jul 2024 19:57:06 +0200 Subject: [PATCH 475/520] Format the .c files using clang-format v15. --- 301/CO_Emergency.c | 445 ++++------ 301/CO_HBconsumer.c | 337 +++----- 301/CO_NMT_Heartbeat.c | 190 ++--- 301/CO_Node_Guarding.c | 204 ++--- 301/CO_ODinterface.c | 230 ++--- 301/CO_PDO.c | 895 +++++++++---------- 301/CO_SDOclient.c | 1289 ++++++++++++---------------- 301/CO_SDOserver.c | 1653 ++++++++++++++++-------------------- 301/CO_SYNC.c | 257 +++--- 301/CO_TIME.c | 106 +-- 301/CO_fifo.c | 871 +++++++++---------- 301/crc16-ccitt.c | 68 +- 303/CO_LEDs.c | 120 ++- 304/CO_GFC.c | 29 +- 304/CO_SRDO.c | 328 +++---- 305/CO_LSSmaster.c | 613 ++++++------- 305/CO_LSSslave.c | 549 ++++++------ 309/CO_gateway_ascii.c | 1617 ++++++++++++++++------------------- CANopen.c | 1530 +++++++++++++++------------------ example/CO_driver_blank.c | 192 ++--- example/CO_storageBlank.c | 39 +- example/main_blank.c | 145 ++-- storage/CO_storage.c | 57 +- storage/CO_storageEeprom.c | 115 +-- 24 files changed, 5146 insertions(+), 6733 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index e2f2d3b8..53d25f29 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -23,10 +23,9 @@ #include "301/CO_Emergency.h" /* verify configuration */ -#if CO_CONFIG_EM_ERR_STATUS_BITS_COUNT < (6U*8U) \ - || CO_CONFIG_EM_ERR_STATUS_BITS_COUNT > 256U \ +#if CO_CONFIG_EM_ERR_STATUS_BITS_COUNT < (6U * 8U) || CO_CONFIG_EM_ERR_STATUS_BITS_COUNT > 256U \ || (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT % 8U) != 0 - #error CO_CONFIG_EM_ERR_STATUS_BITS_COUNT is not correct +#error CO_CONFIG_EM_ERR_STATUS_BITS_COUNT is not correct #endif /* fifo buffer example for fifoSize = 7 (actual capacity = 6) * @@ -43,94 +42,79 @@ * to process to process to process full * ******************************************************************************/ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 /* * Custom functions for read/write OD object "COB-ID EMCY" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_read_1014(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count < sizeof(uint32_t)) || (countRead == NULL) - ) { +static ODR_t +OD_read_1014(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count < sizeof(uint32_t)) + || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } - CO_EM_t *em = (CO_EM_t *)stream->object; + CO_EM_t* em = (CO_EM_t*)stream->object; - uint16_t canId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? - (CO_CAN_ID_EMERGENCY + em->nodeId) : em->producerCanId; + uint16_t canId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? (CO_CAN_ID_EMERGENCY + em->nodeId) + : em->producerCanId; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0U : 0x80000000U; COB_IDEmergency32 |= canId; (void)CO_setUint32(buf, COB_IDEmergency32); - *countRead = sizeof(uint32_t); return ODR_OK; } -static ODR_t OD_write_1014(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count != sizeof(uint32_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_1014(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint32_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_EM_t *em = (CO_EM_t *)stream->object; + CO_EM_t* em = (CO_EM_t*)stream->object; /* Verify written value. COB ID must not change, if emergency is enabled */ uint32_t COB_IDEmergency32 = CO_getUint32(buf); uint16_t newCanId = (uint16_t)(COB_IDEmergency32 & 0x7FFU); - uint16_t curCanId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? - (CO_CAN_ID_EMERGENCY + em->nodeId) : em->producerCanId; + uint16_t curCanId = (em->producerCanId == CO_CAN_ID_EMERGENCY) ? (CO_CAN_ID_EMERGENCY + em->nodeId) + : em->producerCanId; bool_t newEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0U) && (newCanId != 0U); - if (((COB_IDEmergency32 & 0x7FFFF800U)!=0U) || CO_IS_RESTRICTED_CAN_ID(newCanId) - || ((em->producerEnabled && newEnabled) && (newCanId != curCanId)) - ) { + if (((COB_IDEmergency32 & 0x7FFFF800U) != 0U) || CO_IS_RESTRICTED_CAN_ID(newCanId) + || ((em->producerEnabled && newEnabled) && (newCanId != curCanId))) { return ODR_INVALID_VALUE; } /* store values. If default CAN-ID is used, then store only value of * CO_CAN_ID_EMERGENCY without node id. */ em->producerEnabled = newEnabled; - em->producerCanId = (newCanId == ((uint16_t)CO_CAN_ID_EMERGENCY + em->nodeId)) ? - CO_CAN_ID_EMERGENCY : newCanId; + em->producerCanId = (newCanId == ((uint16_t)CO_CAN_ID_EMERGENCY + em->nodeId)) ? CO_CAN_ID_EMERGENCY : newCanId; /* configure emergency message CAN transmission */ if (newEnabled) { - em->CANtxBuff = CO_CANtxBufferInit( - em->CANdevTx, - em->CANdevTxIdx, - newCanId, - false, - 8U, - false); + em->CANtxBuff = CO_CANtxBufferInit(em->CANdevTx, em->CANdevTxIdx, newCanId, false, 8U, false); } /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, buf, count, countWritten); } - #else +#else /* * Custom functions for read/write OD object "COB-ID EMCY" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count < sizeof(uint32_t)) || (countRead == NULL) - ) { +static ODR_t +OD_read_1014_default(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count < sizeof(uint32_t)) + || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } - CO_EM_t *em = (CO_EM_t *)stream->object; + CO_EM_t* em = (CO_EM_t*)stream->object; uint32_t COB_IDEmergency32 = em->producerEnabled ? 0U : 0x80000000U; COB_IDEmergency32 |= CO_CAN_ID_EMERGENCY + (uint32_t)em->nodeId; @@ -139,24 +123,22 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf, *countRead = sizeof(uint32_t); return ODR_OK; } - #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE */ +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE */ - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0 /* * Custom function for writing OD object "Inhibit time EMCY" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count != sizeof(uint16_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_1015(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint16_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_EM_t *em = (CO_EM_t *)stream->object; + CO_EM_t* em = (CO_EM_t*)stream->object; /* update object */ em->inhibitEmTime_us = (uint32_t)CO_getUint16(buf) * 100U; @@ -165,25 +147,23 @@ static ODR_t OD_write_1015(OD_stream_t *stream, const void *buf, /* write value to the original location in the Object Dictionary */ return OD_writeOriginal(stream, buf, count, countWritten); } - #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0 /* * Custom functions for read/write OD object _OD_statusBits_, optional * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ - if ((stream == NULL) || (buf == NULL) || (countRead == NULL) - || ((count < 4U) && (stream->subIndex > 0U)) || (count < 1U) - ) { +static ODR_t +OD_read_1003(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + if ((stream == NULL) || (buf == NULL) || (countRead == NULL) || ((count < 4U) && (stream->subIndex > 0U)) + || (count < 1U)) { return ODR_DEV_INCOMPAT; } - CO_EM_t *em = (CO_EM_t *)stream->object; + CO_EM_t* em = (CO_EM_t*)stream->object; if (em->fifoSize < 2U) { return ODR_DEV_INCOMPAT; @@ -193,34 +173,28 @@ static ODR_t OD_read_1003(OD_stream_t *stream, void *buf, *countRead = sizeof(uint8_t); return ODR_OK; - } - else if (stream->subIndex <= em->fifoCount) { + } else if (stream->subIndex <= em->fifoCount) { /* newest error is reported on subIndex 1 and is stored just behind * fifoWrPtr. Get correct index in FIFO buffer. */ int16_t index = (int16_t)em->fifoWrPtr - (int16_t)stream->subIndex; if (index < 0) { index += (int16_t)em->fifoSize; - } - else if (index >= (int16_t)(em->fifoSize)) { + } else if (index >= (int16_t)(em->fifoSize)) { return ODR_DEV_INCOMPAT; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } (void)CO_setUint32(buf, em->fifo[index].msg); *countRead = sizeof(uint32_t); return ODR_OK; - } - else { + } else { return ODR_NO_DATA; } } -static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != 1U) - || (countWritten == NULL)) - { +static ODR_t +OD_write_1003(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != 1U) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } @@ -228,7 +202,7 @@ static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, return ODR_INVALID_VALUE; } - CO_EM_t *em = (CO_EM_t *)stream->object; + CO_EM_t* em = (CO_EM_t*)stream->object; /* clear error history */ em->fifoCount = 0; @@ -238,22 +212,19 @@ static ODR_t OD_write_1003(OD_stream_t *stream, const void *buf, } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0 /* * Custom functions for read/write OD object _OD_statusBits_, optional * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ - if ((stream == NULL) || (stream->subIndex != 0U) - || (buf == NULL) || (countRead == NULL)) - { +static ODR_t +OD_read_statusBits(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } - CO_EM_t *em = (CO_EM_t *)stream->object; + CO_EM_t* em = (CO_EM_t*)stream->object; /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ OD_size_t countReadLocal = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U; @@ -262,27 +233,23 @@ static ODR_t OD_read_statusBits(OD_stream_t *stream, void *buf, } if ((stream->dataLength != 0U) && (countReadLocal > stream->dataLength)) { countReadLocal = stream->dataLength; - } - else { + } else { stream->dataLength = countReadLocal; } - (void)memcpy ((void *)(buf), (const void *)(&em->errorStatusBits[0]), countReadLocal); + (void)memcpy((void*)(buf), (const void*)(&em->errorStatusBits[0]), countReadLocal); *countRead = countReadLocal; return ODR_OK; } -static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) - || (buf == NULL) || (countWritten == NULL) - ) { +static ODR_t +OD_write_statusBits(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_EM_t *em = (CO_EM_t *)stream->object; + CO_EM_t* em = (CO_EM_t*)stream->object; /* get MAX(errorStatusBitsSize, bufSize, ODsizeIndication) */ OD_size_t countWrite = CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U; @@ -291,19 +258,18 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, } if ((stream->dataLength != 0U) && (countWrite > stream->dataLength)) { countWrite = stream->dataLength; - } - else { + } else { stream->dataLength = countWrite; } - (void)memcpy ((void *)(&em->errorStatusBits[0]), (const void *)(buf), countWrite); + (void)memcpy((void*)(&em->errorStatusBits[0]), (const void*)(buf), countWrite); *countWritten = countWrite; return ODR_OK; } #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 /* * Read received message from CAN module. * @@ -311,59 +277,49 @@ static ODR_t OD_write_statusBits(OD_stream_t *stream, const void *buf, * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_EM_receive(void *object, void *msg) { - CO_EM_t *em = (CO_EM_t*)object; +static void +CO_EM_receive(void* object, void* msg) { + CO_EM_t* em = (CO_EM_t*)object; if ((em != NULL) && (em->pFunctSignalRx != NULL)) { uint16_t ident = CO_CANrxMsg_readIdent(msg); /* ignore sync messages (necessary if sync object is not used) */ if (ident != 0x80U) { - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); uint16_t errorCode; uint32_t infoCode; - (void)memcpy((void *)(&errorCode), (const void *)(&data[0]), sizeof(errorCode)); - (void)memcpy((void *)(&infoCode), (const void *)(&data[4]), sizeof(infoCode)); - em->pFunctSignalRx(ident, - CO_SWAP_16(errorCode), - data[2], - data[3], - CO_SWAP_32(infoCode)); + (void)memcpy((void*)(&errorCode), (const void*)(&data[0]), sizeof(errorCode)); + (void)memcpy((void*)(&infoCode), (const void*)(&data[4]), sizeof(infoCode)); + em->pFunctSignalRx(ident, CO_SWAP_16(errorCode), data[2], data[3], CO_SWAP_32(infoCode)); } } } #endif - -CO_ReturnError_t CO_EM_init(CO_EM_t *em, - CO_CANmodule_t *CANdevTx, - const OD_entry_t *OD_1001_errReg, +CO_ReturnError_t +CO_EM_init(CO_EM_t* em, CO_CANmodule_t* CANdevTx, const OD_entry_t* OD_1001_errReg, #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 - CO_EM_fifo_t *fifo, - uint8_t fifoSize, + CO_EM_fifo_t* fifo, uint8_t fifoSize, +#endif +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 + OD_entry_t* OD_1014_cobIdEm, uint16_t CANdevTxIdx, +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0 + OD_entry_t* OD_1015_InhTime, #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 - OD_entry_t *OD_1014_cobIdEm, - uint16_t CANdevTxIdx, - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 - OD_entry_t *OD_1015_InhTime, - #endif #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 - OD_entry_t *OD_1003_preDefErr, +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0 + OD_entry_t* OD_1003_preDefErr, #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0 - OD_entry_t *OD_statusBits, +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0 + OD_entry_t* OD_statusBits, #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 + CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, #endif - const uint8_t nodeId, - uint32_t *errInfo) -{ - (void) nodeId; /* may be unused */ + const uint8_t nodeId, uint32_t* errInfo) { + (void)nodeId; /* may be unused */ CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ @@ -371,15 +327,14 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 || ((fifo == NULL) && (fifoSize >= 2U)) #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 - || (OD_1014_cobIdEm == NULL) || (CANdevTx == NULL) - || (nodeId < 1U) || (nodeId > 127U) +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 + || (OD_1014_cobIdEm == NULL) || (CANdevTx == NULL) || (nodeId < 1U) || (nodeId > 127U) #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 - || (OD_1003_preDefErr == NULL) +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0 + || (OD_1003_preDefErr == NULL) #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 - || (CANdevRx == NULL) +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 + || (CANdevRx == NULL) #endif ) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -394,7 +349,9 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, /* get and verify "Error register" from Object Dictionary */ em->errorRegister = OD_getPtr(OD_1001_errReg, 0, sizeof(uint8_t), NULL); if (em->errorRegister == NULL) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1001_errReg); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1001_errReg); + } return CO_ERROR_OD_PARAMETERS; } *em->errorRegister = 0; @@ -403,21 +360,24 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->fifo = fifo; em->fifoSize = fifoSize; #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 /* get initial and verify "COB-ID EMCY" from Object Dictionary */ uint32_t COB_IDEmergency32; ODR_t odRet; odRet = OD_get_u32(OD_1014_cobIdEm, 0, &COB_IDEmergency32, true); if ((odRet != ODR_OK) || ((COB_IDEmergency32 & 0x7FFFF800U) != 0U)) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1014_cobIdEm); } - /* don't break a program, if only value of a parameter is wrong */ - if (odRet != ODR_OK) { return CO_ERROR_OD_PARAMETERS; } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1014_cobIdEm); + } + /* don't break a program, if only value of a parameter is wrong */ + if (odRet != ODR_OK) { + return CO_ERROR_OD_PARAMETERS; + } } - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_CONFIGURABLE) != 0 uint16_t producerCanId = (uint16_t)(COB_IDEmergency32 & 0x7FFU); - em->producerEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0U) - && (producerCanId != 0U); + em->producerEnabled = ((COB_IDEmergency32 & 0x80000000U) == 0U) && (producerCanId != 0U); em->OD_1014_extension.object = em; em->OD_1014_extension.read = OD_read_1014; @@ -438,7 +398,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, if (producerCanId == CO_CAN_ID_EMERGENCY) { producerCanId += nodeId; } - #else +#else uint16_t producerCanId = CO_CAN_ID_EMERGENCY + (uint16_t)nodeId; em->producerEnabled = (COB_IDEmergency32 & 0x80000000U) == 0U; @@ -447,27 +407,23 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1014_extension.write = OD_writeOriginal; odRet = OD_extension_init(OD_1014_cobIdEm, &em->OD_1014_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1014_cobIdEm); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1014_cobIdEm); + } return CO_ERROR_OD_PARAMETERS; } - #endif +#endif /* configure parameters and emergency message CAN transmission */ em->nodeId = nodeId; - em->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, - CANdevTxIdx, - producerCanId, - false, - 8U, - false); + em->CANtxBuff = CO_CANtxBufferInit(CANdevTx, CANdevTxIdx, producerCanId, false, 8U, false); if (em->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0 /* get and verify optional "Inhibit time EMCY" from Object Dictionary */ em->inhibitEmTime_us = 0; em->inhibitEmTimer = 0; @@ -481,11 +437,10 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, em->OD_1015_extension.write = OD_write_1015; (void)OD_extension_init(OD_1015_InhTime, &em->OD_1015_extension); } - #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ +#endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT */ #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ - -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0 /* If OD entry available, make access to em->preDefErr */ em->OD_1003_extension.object = em; em->OD_1003_extension.read = OD_read_1003; @@ -493,8 +448,7 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, (void)OD_extension_init(OD_1003_preDefErr, &em->OD_1003_extension); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY */ - -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0 /* If OD entry available, make access to em->errorStatusBits */ em->OD_statusBits_extension.object = em; em->OD_statusBits_extension.read = OD_read_statusBits; @@ -502,43 +456,29 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, (void)OD_extension_init(OD_statusBits, &em->OD_statusBits_extension); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS */ - -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 em->pFunctSignalRx = NULL; /* configure SDO server CAN reception */ - ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - CO_CAN_ID_EMERGENCY, - 0x780, - false, - (void*)em, - CO_EM_receive); + ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, CO_CAN_ID_EMERGENCY, 0x780, false, (void*)em, CO_EM_receive); #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER */ return ret; } - -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 -void CO_EM_initCallbackRx(CO_EM_t *em, - void (*pFunctSignalRx)(const uint16_t ident, - const uint16_t errorCode, - const uint8_t errorRegister, - const uint8_t errorBit, - const uint32_t infoCode)) -{ +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 +void +CO_EM_initCallbackRx(CO_EM_t* em, + void (*pFunctSignalRx)(const uint16_t ident, const uint16_t errorCode, const uint8_t errorRegister, + const uint8_t errorBit, const uint32_t infoCode)) { if (em != NULL) { em->pFunctSignalRx = pFunctSignalRx; } } #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_EM_initCallbackPre(CO_EM_t *em, - void *object, - void (*pFunctSignal)(void *object)) -{ +#if ((CO_CONFIG_EM)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_EM_initCallbackPre(CO_EM_t* em, void* object, void (*pFunctSignal)(void* object)) { if (em != NULL) { em->functSignalObjectPre = object; em->pFunctSignalPre = pFunctSignal; @@ -546,17 +486,13 @@ void CO_EM_initCallbackPre(CO_EM_t *em, } #endif - -void CO_EM_process(CO_EM_t *em, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +void +CO_EM_process(CO_EM_t* em, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ - - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) == 0 + +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) == 0 (void)timeDifference_us; /* may be unused */ - #endif +#endif /* verify errors from driver */ uint16_t CANerrSt = em->CANdevTx->CANerrorStatus; @@ -565,33 +501,26 @@ void CO_EM_process(CO_EM_t *em, em->CANerrorStatusOld = CANerrSt; if ((CANerrStChanged & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0U) { - CO_error(em, - (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0U, - CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, 0); + CO_error(em, (CANerrSt & (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING)) != 0U, CO_EM_CAN_BUS_WARNING, + CO_EMC_NO_ERROR, 0); } if ((CANerrStChanged & CO_CAN_ERRTX_PASSIVE) != 0U) { - CO_error(em, (CANerrSt & CO_CAN_ERRTX_PASSIVE) != 0U, - CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); + CO_error(em, (CANerrSt & CO_CAN_ERRTX_PASSIVE) != 0U, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); } if ((CANerrStChanged & CO_CAN_ERRTX_BUS_OFF) != 0U) { - CO_error(em, (CANerrSt & CO_CAN_ERRTX_BUS_OFF) != 0U, - CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, 0); + CO_error(em, (CANerrSt & CO_CAN_ERRTX_BUS_OFF) != 0U, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, 0); } if ((CANerrStChanged & CO_CAN_ERRTX_OVERFLOW) != 0U) { - CO_error(em, (CANerrSt & CO_CAN_ERRTX_OVERFLOW) != 0U, - CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); + CO_error(em, (CANerrSt & CO_CAN_ERRTX_OVERFLOW) != 0U, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } if ((CANerrStChanged & CO_CAN_ERRTX_PDO_LATE) != 0U) { - CO_error(em, (CANerrSt & CO_CAN_ERRTX_PDO_LATE) != 0U, - CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, 0); + CO_error(em, (CANerrSt & CO_CAN_ERRTX_PDO_LATE) != 0U, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, 0); } if ((CANerrStChanged & CO_CAN_ERRRX_PASSIVE) != 0U) { - CO_error(em, (CANerrSt & CO_CAN_ERRRX_PASSIVE) != 0U, - CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); + CO_error(em, (CANerrSt & CO_CAN_ERRRX_PASSIVE) != 0U, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, 0); } if ((CANerrStChanged & CO_CAN_ERRRX_OVERFLOW) != 0U) { - CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0U, - CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); + CO_error(em, (CANerrSt & CO_CAN_ERRRX_OVERFLOW) != 0U, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, 0); } } @@ -633,41 +562,36 @@ void CO_EM_process(CO_EM_t *em, } /* post-process Emergency message in fifo buffer. */ -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 if (em->fifoSize >= 2U) { uint8_t fifoPpPtr = em->fifoPpPtr; - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0 if (em->inhibitEmTimer < em->inhibitEmTime_us) { em->inhibitEmTimer += timeDifference_us; } - if (!em->CANtxBuff->bufferFull && (fifoPpPtr != em->fifoWrPtr) - && (em->inhibitEmTimer >= em->inhibitEmTime_us) - ) { + if (!em->CANtxBuff->bufferFull && (fifoPpPtr != em->fifoWrPtr) + && (em->inhibitEmTimer >= em->inhibitEmTime_us)) { em->inhibitEmTimer = 0; - #else +#else if ((!em->CANtxBuff->bufferFull) && (fifoPpPtr != em->fifoWrPtr)) { - #endif +#endif /* add error register to emergency message */ - em->fifo[fifoPpPtr].msg |= (uint32_t) errorRegister << 16; + em->fifo[fifoPpPtr].msg |= (uint32_t)errorRegister << 16; /* send emergency message */ - (void)memcpy((void *)em->CANtxBuff->data, (void *)&em->fifo[fifoPpPtr].msg, - sizeof(em->CANtxBuff->data)); + (void)memcpy((void*)em->CANtxBuff->data, (void*)&em->fifo[fifoPpPtr].msg, sizeof(em->CANtxBuff->data)); (void)CO_CANsend(em->CANdevTx, em->CANtxBuff); - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 /* report also own emergency messages */ if (em->pFunctSignalRx != NULL) { uint32_t errMsg = em->fifo[fifoPpPtr].msg; - em->pFunctSignalRx(0, - CO_SWAP_16((uint16_t) errMsg), - errorRegister, - (uint8_t) (errMsg >> 24), + em->pFunctSignalRx(0, CO_SWAP_16((uint16_t)errMsg), errorRegister, (uint8_t)(errMsg >> 24), CO_SWAP_32(em->fifo[fifoPpPtr].info)); } - #endif +#endif /* increment pointer */ fifoPpPtr++; @@ -677,36 +601,32 @@ void CO_EM_process(CO_EM_t *em, * messages from fifo buffer are processed */ if (em->fifoOverflow == 1U) { em->fifoOverflow = 2; - CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, - CO_EMC_GENERIC, 0); - } - else if ((em->fifoOverflow == 2U) && (em->fifoPpPtr == em->fifoWrPtr)) { + CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, CO_EMC_GENERIC, 0); + } else if ((em->fifoOverflow == 2U) && (em->fifoPpPtr == em->fifoWrPtr)) { em->fifoOverflow = 0; CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0); + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 - #if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - else if ((timerNext_us != NULL) - && (em->inhibitEmTimer < em->inhibitEmTime_us)) - { +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_FLAG_TIMERNEXT) != 0 + else if ((timerNext_us != NULL) && (em->inhibitEmTimer < em->inhibitEmTime_us)) { /* check again after inhibit time elapsed */ uint32_t diff = em->inhibitEmTime_us - em->inhibitEmTimer; if (*timerNext_us > diff) { *timerNext_us = diff; } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } - #endif - #endif +#endif +#endif } -#elif ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 +#elif ((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0 if (em->fifoSize >= 2) { uint8_t fifoPpPtr = em->fifoPpPtr; while (fifoPpPtr != em->fifoWrPtr) { /* add error register to emergency message and increment pointers */ - em->fifo[fifoPpPtr].msg |= (uint32_t) errorRegister << 16; + em->fifo[fifoPpPtr].msg |= (uint32_t)errorRegister << 16; if (++fifoPpPtr >= em->fifoSize) { fifoPpPtr = 0; @@ -719,11 +639,11 @@ void CO_EM_process(CO_EM_t *em, return; } - -void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, - uint16_t errorCode, uint32_t infoCode) -{ - if (em == NULL) { return; } +void +CO_error(CO_EM_t* em, bool_t setError, const uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) { + if (em == NULL) { + return; + } uint8_t index = errorBit >> 3; uint8_t bitmask = 1U << (errorBit & 0x7U); @@ -736,7 +656,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, infoCode = errorBit; } - uint8_t *errorStatusBits = &em->errorStatusBits[index]; + uint8_t* errorStatusBits = &em->errorStatusBits[index]; uint8_t errorStatusBitMasked = *errorStatusBits & bitmask; /* If error is already set (or unset), return without further actions, @@ -745,8 +665,7 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, if (errorStatusBitMasked != 0U) { return; } - } - else { + } else { if (errorStatusBitMasked == 0U) { return; } @@ -756,15 +675,18 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 /* prepare emergency message. Error register will be added in post-process*/ uint32_t errMsg = ((uint32_t)errorBit << 24) | CO_SWAP_16(errorCode); - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 uint32_t infoCodeSwapped = CO_SWAP_32(infoCode); - #endif +#endif #endif /* safely write data, and increment pointers */ CO_LOCK_EMCY(em->CANdevTx); - if (setError) { *errorStatusBits |= bitmask; } - else { *errorStatusBits &= ~bitmask; } + if (setError) { + *errorStatusBits |= bitmask; + } else { + *errorStatusBits &= ~bitmask; + } #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 if (em->fifoSize >= 2U) { @@ -776,27 +698,28 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, if (fifoWrPtrNext == em->fifoPpPtr) { em->fifoOverflow = 1; - } - else { + } else { em->fifo[fifoWrPtr].msg = errMsg; - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 em->fifo[fifoWrPtr].info = infoCodeSwapped; - #endif +#endif em->fifoWrPtr = fifoWrPtrNext; - if (em->fifoCount < (em->fifoSize - 1U)) { em->fifoCount++; } + if (em->fifoCount < (em->fifoSize - 1U)) { + em->fifoCount++; + } } } #endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ CO_UNLOCK_EMCY(em->CANdevTx); -#if ((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 /* Optional signal to RTOS, which can resume task, which handles * CO_EM_process */ if ((em->pFunctSignalPre != NULL) && em->producerEnabled) { em->pFunctSignalPre(em->functSignalObjectPre); } - #endif +#endif #endif } diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index b422c7da..ae249325 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -20,11 +20,11 @@ #include "301/CO_HBconsumer.h" -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 /* Verify HB consumer configuration *******************************************/ -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ - && (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + && (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) #error CO_CONFIG_HB_CONS_CALLBACK_CHANGE and CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously! #endif @@ -35,16 +35,17 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_HBcons_receive(void *object, void *msg) { - CO_HBconsNode_t *HBconsNode = object; +static void +CO_HBcons_receive(void* object, void* msg) { + CO_HBconsNode_t* HBconsNode = object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); if (DLC == 1U) { /* copy data and set 'new message' flag. */ HBconsNode->NMTstate = (CO_NMT_internalState_t)data[0]; CO_FLAG_SET(HBconsNode->CANrxNew); -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles HBcons. */ if (HBconsNode->pFunctSignalPre != NULL) { HBconsNode->pFunctSignalPre(HBconsNode->functSignalObjectPre); @@ -53,7 +54,6 @@ static void CO_HBcons_receive(void *object, void *msg) { } } - /* * Initialize one Heartbeat consumer entry * @@ -66,36 +66,29 @@ static void CO_HBcons_receive(void *object, void *msg) { * @param consumerTime_ms in milliseconds. see OD 0x1016 description * @return */ -static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, - uint8_t idx, - uint8_t nodeId, +static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t* HBcons, uint8_t idx, uint8_t nodeId, uint16_t consumerTime_ms); - -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "Consumer heartbeat time" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - CO_HBconsumer_t *HBcons = stream->object; - - if ((stream == NULL) || (buf == NULL) - || (stream->subIndex < 1U) - || (stream->subIndex > HBcons->numberOfMonitoredNodes) - || (count != sizeof(uint32_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_1016(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + CO_HBconsumer_t* HBcons = stream->object; + + if ((stream == NULL) || (buf == NULL) || (stream->subIndex < 1U) + || (stream->subIndex > HBcons->numberOfMonitoredNodes) || (count != sizeof(uint32_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } uint32_t val = CO_getUint32(buf); uint8_t nodeId = (uint8_t)((val >> 16) & 0xFFU); uint16_t consumer_time = (uint16_t)(val & 0xFFFFU); - CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, stream->subIndex - 1U, - nodeId, consumer_time); + CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, stream->subIndex - 1U, nodeId, consumer_time); if (ret != CO_ERROR_NO) { return ODR_PAR_INCOMPAT; } @@ -105,22 +98,14 @@ static ODR_t OD_write_1016(OD_stream_t *stream, const void *buf, } #endif - -CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, - CO_EM_t *em, - CO_HBconsNode_t *monitoredNodes, - uint8_t monitoredNodesCount, - OD_entry_t *OD_1016_HBcons, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdxStart, - uint32_t *errInfo) -{ +CO_ReturnError_t +CO_HBconsumer_init(CO_HBconsumer_t* HBcons, CO_EM_t* em, CO_HBconsNode_t* monitoredNodes, uint8_t monitoredNodesCount, + OD_entry_t* OD_1016_HBcons, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdxStart, uint32_t* errInfo) { ODR_t odRet; /* verify arguments */ - if ((HBcons == NULL) || (em == NULL) || (monitoredNodes == NULL) - || (OD_1016_HBcons == NULL) || (CANdevRx == NULL) - ) { + if ((HBcons == NULL) || (em == NULL) || (monitoredNodes == NULL) || (OD_1016_HBcons == NULL) + || (CANdevRx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -132,15 +117,17 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, HBcons->CANdevRxIdxStart = CANdevRxIdxStart; /* get actual number of monitored nodes */ - HBcons->numberOfMonitoredNodes = - ((OD_1016_HBcons->subEntriesCount-1U) < monitoredNodesCount) ? - (OD_1016_HBcons->subEntriesCount-1U) : monitoredNodesCount; + HBcons->numberOfMonitoredNodes = ((OD_1016_HBcons->subEntriesCount - 1U) < monitoredNodesCount) + ? (OD_1016_HBcons->subEntriesCount - 1U) + : monitoredNodesCount; for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { uint32_t val; odRet = OD_get_u32(OD_1016_HBcons, i + 1U, &val, true); if (odRet != ODR_OK) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1016_HBcons); + } return CO_ERROR_OD_PARAMETERS; } @@ -148,20 +135,26 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, uint16_t consumer_time = (uint16_t)(val & 0xFFFFU); CO_ReturnError_t ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, consumer_time); if (ret != CO_ERROR_NO) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1016_HBcons); + } /* don't break a program, if only value of a parameter is wrong */ - if (ret != CO_ERROR_OD_PARAMETERS) { return ret; } + if (ret != CO_ERROR_OD_PARAMETERS) { + return ret; + } } } /* configure extension for OD */ -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 HBcons->OD_1016_extension.object = HBcons; HBcons->OD_1016_extension.read = OD_readOriginal; HBcons->OD_1016_extension.write = OD_write_1016; odRet = OD_extension_init(OD_1016_HBcons, &HBcons->OD_1016_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1016_HBcons); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1016_HBcons); + } return CO_ERROR_OD_PARAMETERS; } #endif @@ -169,12 +162,8 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, return CO_ERROR_NO; } - -static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, - uint8_t idx, - uint8_t nodeId, - uint16_t consumerTime_ms) -{ +static CO_ReturnError_t +CO_HBconsumer_initEntry(CO_HBconsumer_t* HBcons, uint8_t idx, uint8_t nodeId, uint16_t consumerTime_ms) { CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ @@ -183,10 +172,10 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, } /* verify for duplicate entries */ - if((consumerTime_ms != 0U) && (nodeId != 0U)) { + if ((consumerTime_ms != 0U) && (nodeId != 0U)) { for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { CO_HBconsNode_t node = HBcons->monitoredNodes[i]; - if((idx != i) && (node.time_us != 0U) && (node.nodeId == nodeId)) { + if ((idx != i) && (node.time_us != 0U) && (node.nodeId == nodeId)) { ret = CO_ERROR_OD_PARAMETERS; } } @@ -196,12 +185,12 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, if (ret == CO_ERROR_NO) { uint16_t COB_ID; - CO_HBconsNode_t * monitoredNode = &HBcons->monitoredNodes[idx]; + CO_HBconsNode_t* monitoredNode = &HBcons->monitoredNodes[idx]; monitoredNode->nodeId = nodeId; monitoredNode->time_us = (uint32_t)consumerTime_ms * 1000U; monitoredNode->NMTstate = CO_NMT_UNKNOWN; -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ - || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -210,35 +199,25 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t *HBcons, if ((monitoredNode->nodeId != 0U) && (monitoredNode->time_us != 0U)) { COB_ID = monitoredNode->nodeId + (uint16_t)CO_CAN_ID_HEARTBEAT; monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; - } - else { + } else { COB_ID = 0; monitoredNode->time_us = 0; monitoredNode->HBstate = CO_HBconsumer_UNCONFIGURED; } /* configure Heartbeat consumer (or disable) CAN reception */ - ret = CO_CANrxBufferInit(HBcons->CANdevRx, - HBcons->CANdevRxIdxStart + idx, - COB_ID, - 0x7FF, - false, - (void*)&HBcons->monitoredNodes[idx], - CO_HBcons_receive); + ret = CO_CANrxBufferInit(HBcons->CANdevRx, HBcons->CANdevRxIdxStart + idx, COB_ID, 0x7FF, false, + (void*)&HBcons->monitoredNodes[idx], CO_HBcons_receive); } return ret; } - -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_HBconsumer_initCallbackPre( - CO_HBconsumer_t *HBcons, - void *object, - void (*pFunctSignal)(void *object)) -{ +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_HBconsumer_initCallbackPre(CO_HBconsumer_t* HBcons, void* object, void (*pFunctSignal)(void* object)) { if (HBcons != NULL) { uint8_t i; - for(i=0; inumberOfMonitoredNodes; i++) { + for (i = 0; i < HBcons->numberOfMonitoredNodes; i++) { HBcons->monitoredNodes[i].pFunctSignalPre = pFunctSignal; HBcons->monitoredNodes[i].functSignalObjectPre = object; } @@ -246,18 +225,13 @@ void CO_HBconsumer_initCallbackPre( } #endif - -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0 -void CO_HBconsumer_initCallbackNmtChanged( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t NMTstate, - void *object)) -{ - (void) idx; - if (HBcons==NULL) { +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0 +void +CO_HBconsumer_initCallbackNmtChanged(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t NMTstate, + void* object)) { + (void)idx; + if (HBcons == NULL) { return; } @@ -266,35 +240,26 @@ void CO_HBconsumer_initCallbackNmtChanged( } #endif - -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 -void CO_HBconsumer_initCallbackNmtChanged( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t NMTstate, - void *object)) -{ - if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 +void +CO_HBconsumer_initCallbackNmtChanged(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t NMTstate, + void* object)) { + if (HBcons == NULL || idx >= HBcons->numberOfMonitoredNodes) { return; } - CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[idx]; + CO_HBconsNode_t* const monitoredNode = &HBcons->monitoredNodes[idx]; monitoredNode->pFunctSignalNmtChanged = pFunctSignal; monitoredNode->pFunctSignalObjectNmtChanged = object; } +void +CO_HBconsumer_initCallbackHeartbeatStarted(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void* object)) { + CO_HBconsNode_t* monitoredNode; -void CO_HBconsumer_initCallbackHeartbeatStarted( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)) -{ - CO_HBconsNode_t *monitoredNode; - - if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { + if (HBcons == NULL || idx >= HBcons->numberOfMonitoredNodes) { return; } @@ -303,16 +268,12 @@ void CO_HBconsumer_initCallbackHeartbeatStarted( monitoredNode->functSignalObjectHbStarted = object; } +void +CO_HBconsumer_initCallbackTimeout(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void* object)) { + CO_HBconsNode_t* monitoredNode; -void CO_HBconsumer_initCallbackTimeout( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)) -{ - CO_HBconsNode_t *monitoredNode; - - if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { + if (HBcons == NULL || idx >= HBcons->numberOfMonitoredNodes) { return; } @@ -321,16 +282,12 @@ void CO_HBconsumer_initCallbackTimeout( monitoredNode->functSignalObjectTimeout = object; } +void +CO_HBconsumer_initCallbackRemoteReset(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void* object)) { + CO_HBconsNode_t* monitoredNode; -void CO_HBconsumer_initCallbackRemoteReset( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)) -{ - CO_HBconsNode_t *monitoredNode; - - if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { + if (HBcons == NULL || idx >= HBcons->numberOfMonitoredNodes) { return; } @@ -340,22 +297,18 @@ void CO_HBconsumer_initCallbackRemoteReset( } #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI */ - -void CO_HBconsumer_process( - CO_HBconsumer_t *HBcons, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +void +CO_HBconsumer_process(CO_HBconsumer_t* HBcons, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, + uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ bool_t allMonitoredActiveCurrent = true; bool_t allMonitoredOperationalCurrent = true; if (NMTisPreOrOperational && HBcons->NMTisPreOrOperationalPrev) { - for (uint8_t i=0; inumberOfMonitoredNodes; i++) { + for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { uint32_t timeDifference_us_copy = timeDifference_us; - CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[i]; + CO_HBconsNode_t* const monitoredNode = &HBcons->monitoredNodes[i]; if (monitoredNode->HBstate == CO_HBconsumer_UNCONFIGURED) { /* continue, if node is not monitored */ @@ -365,29 +318,24 @@ void CO_HBconsumer_process( if (CO_FLAG_READ(monitoredNode->CANrxNew)) { if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) { /* bootup message*/ -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 if (monitoredNode->pFunctSignalRemoteReset != NULL) { - monitoredNode->pFunctSignalRemoteReset( - monitoredNode->nodeId, i, - monitoredNode->functSignalObjectRemoteReset); + monitoredNode->pFunctSignalRemoteReset(monitoredNode->nodeId, i, + monitoredNode->functSignalObjectRemoteReset); } #endif if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) { - CO_errorReport(HBcons->em, - CO_EM_HB_CONSUMER_REMOTE_RESET, - CO_EMC_HEARTBEAT, i); + CO_errorReport(HBcons->em, CO_EM_HB_CONSUMER_REMOTE_RESET, CO_EMC_HEARTBEAT, i); } monitoredNode->HBstate = CO_HBconsumer_UNKNOWN; - } - else { + } else { /* heartbeat message */ -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 - if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE && - monitoredNode->pFunctSignalHbStarted != NULL) { - monitoredNode->pFunctSignalHbStarted( - monitoredNode->nodeId, i, - monitoredNode->functSignalObjectHbStarted); +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 + if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE + && monitoredNode->pFunctSignalHbStarted != NULL) { + monitoredNode->pFunctSignalHbStarted(monitoredNode->nodeId, i, + monitoredNode->functSignalObjectHbStarted); } #endif monitoredNode->HBstate = CO_HBconsumer_ACTIVE; @@ -404,24 +352,21 @@ void CO_HBconsumer_process( if (monitoredNode->timeoutTimer >= monitoredNode->time_us) { /* timeout expired */ -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 - if (monitoredNode->pFunctSignalTimeout!=NULL) { - monitoredNode->pFunctSignalTimeout( - monitoredNode->nodeId, i, - monitoredNode->functSignalObjectTimeout); +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 + if (monitoredNode->pFunctSignalTimeout != NULL) { + monitoredNode->pFunctSignalTimeout(monitoredNode->nodeId, i, + monitoredNode->functSignalObjectTimeout); } #endif - CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, - CO_EMC_HEARTBEAT, i); + CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, i); monitoredNode->NMTstate = CO_NMT_UNKNOWN; monitoredNode->HBstate = CO_HBconsumer_TIMEOUT; } -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* Calculate timerNext_us for next timeout checking. */ - uint32_t diff = monitoredNode->time_us - - monitoredNode->timeoutTimer; + uint32_t diff = monitoredNode->time_us - monitoredNode->timeoutTimer; if (*timerNext_us > diff) { *timerNext_us = diff; } @@ -429,40 +374,37 @@ void CO_HBconsumer_process( #endif } - if(monitoredNode->HBstate != CO_HBconsumer_ACTIVE) { + if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE) { allMonitoredActiveCurrent = false; } if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) { allMonitoredOperationalCurrent = false; } -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ - || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) /* Verify, if NMT state of monitored node changed */ - if(monitoredNode->NMTstate != monitoredNode->NMTstatePrev) { -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0 + if (monitoredNode->NMTstate != monitoredNode->NMTstatePrev) { +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0 if (HBcons->pFunctSignalNmtChanged != NULL) { - HBcons->pFunctSignalNmtChanged( - monitoredNode->nodeId, i, monitoredNode->NMTstate, - HBcons->pFunctSignalObjectNmtChanged); + HBcons->pFunctSignalNmtChanged(monitoredNode->nodeId, i, monitoredNode->NMTstate, + HBcons->pFunctSignalObjectNmtChanged); #else if (monitoredNode->pFunctSignalNmtChanged != NULL) { - monitoredNode->pFunctSignalNmtChanged( - monitoredNode->nodeId, i, monitoredNode->NMTstate, - monitoredNode->pFunctSignalObjectNmtChanged); + monitoredNode->pFunctSignalNmtChanged(monitoredNode->nodeId, i, monitoredNode->NMTstate, + monitoredNode->pFunctSignalObjectNmtChanged); #endif } monitoredNode->NMTstatePrev = monitoredNode->NMTstate; } #endif } - } - else if (NMTisPreOrOperational || HBcons->NMTisPreOrOperationalPrev) { + } else if (NMTisPreOrOperational || HBcons->NMTisPreOrOperationalPrev) { /* (pre)operational state changed, clear variables */ - for(uint8_t i=0; inumberOfMonitoredNodes; i++) { - CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[i]; + for (uint8_t i = 0; i < HBcons->numberOfMonitoredNodes; i++) { + CO_HBconsNode_t* const monitoredNode = &HBcons->monitoredNodes[i]; monitoredNode->NMTstate = CO_NMT_UNKNOWN; -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ - || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN; #endif CO_FLAG_CLEAR(monitoredNode->CANrxNew); @@ -472,8 +414,8 @@ void CO_HBconsumer_process( } allMonitoredActiveCurrent = false; allMonitoredOperationalCurrent = false; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } /* Clear emergencies when all monitored nodes becomes active. * We only have one emergency index for all monitored nodes! */ @@ -487,14 +429,11 @@ void CO_HBconsumer_process( HBcons->NMTisPreOrOperationalPrev = NMTisPreOrOperational; } - -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT) != 0 -int8_t CO_HBconsumer_getIdxByNodeId( - CO_HBconsumer_t *HBcons, - uint8_t nodeId) -{ +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_QUERY_FUNCT) != 0 +int8_t +CO_HBconsumer_getIdxByNodeId(CO_HBconsumer_t* HBcons, uint8_t nodeId) { uint8_t i; - CO_HBconsNode_t *monitoredNode; + CO_HBconsNode_t* monitoredNode; if (HBcons == NULL) { return -1; @@ -502,24 +441,21 @@ int8_t CO_HBconsumer_getIdxByNodeId( /* linear search for the node */ monitoredNode = &HBcons->monitoredNodes[0]; - for(i=0; inumberOfMonitoredNodes; i++){ + for (i = 0; i < HBcons->numberOfMonitoredNodes; i++) { if (monitoredNode->nodeId == nodeId) { return i; } - monitoredNode ++; + monitoredNode++; } /* not found */ return -1; } +CO_HBconsumer_state_t +CO_HBconsumer_getState(CO_HBconsumer_t* HBcons, uint8_t idx) { + CO_HBconsNode_t* monitoredNode; -CO_HBconsumer_state_t CO_HBconsumer_getState( - CO_HBconsumer_t *HBcons, - uint8_t idx) -{ - CO_HBconsNode_t *monitoredNode; - - if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) { + if (HBcons == NULL || idx >= HBcons->numberOfMonitoredNodes) { return CO_HBconsumer_UNCONFIGURED; } @@ -527,14 +463,11 @@ CO_HBconsumer_state_t CO_HBconsumer_getState( return monitoredNode->HBstate; } -int8_t CO_HBconsumer_getNmtState( - CO_HBconsumer_t *HBcons, - uint8_t idx, - CO_NMT_internalState_t *nmtState) -{ - CO_HBconsNode_t *monitoredNode; +int8_t +CO_HBconsumer_getNmtState(CO_HBconsumer_t* HBcons, uint8_t idx, CO_NMT_internalState_t* nmtState) { + CO_HBconsNode_t* monitoredNode; - if (HBcons==NULL || nmtState==NULL || idx>=HBcons->numberOfMonitoredNodes) { + if (HBcons == NULL || nmtState == NULL || idx >= HBcons->numberOfMonitoredNodes) { return -1; } *nmtState = CO_NMT_INITIALIZING; @@ -542,8 +475,8 @@ int8_t CO_HBconsumer_getNmtState( monitoredNode = &HBcons->monitoredNodes[idx]; if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) { - *nmtState = monitoredNode->NMTstate; - return 0; + *nmtState = monitoredNode->NMTstate; + return 0; } return -1; } diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index 0c95dc6e..b95cf368 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -20,7 +20,6 @@ #include "301/CO_NMT_Heartbeat.h" - /* * Read received message from CAN module. * @@ -28,18 +27,19 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_NMT_receive(void *object, void *msg) { +static void +CO_NMT_receive(void* object, void* msg) { uint8_t DLC = CO_CANrxMsg_readDLC(msg); - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); CO_NMT_command_t command = (CO_NMT_command_t)data[0]; uint8_t nodeId = data[1]; - CO_NMT_t *NMT = (CO_NMT_t*)object; + CO_NMT_t* NMT = (CO_NMT_t*)object; if ((DLC == 2U) && ((nodeId == 0U) || (nodeId == NMT->nodeId))) { NMT->internalCommand = command; -#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_NMT)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles NMT. */ if (NMT->pFunctSignalPre != NULL) { NMT->pFunctSignalPre(NMT->functSignalObjectPre); @@ -48,22 +48,19 @@ static void CO_NMT_receive(void *object, void *msg) { } } - /* * Custom function for writing OD object "Producer heartbeat time" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1017(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count != sizeof(uint16_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_1017(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint16_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_NMT_t *NMT = (CO_NMT_t *)stream->object; + CO_NMT_t* NMT = (CO_NMT_t*)stream->object; /* update object, send Heartbeat immediately */ NMT->HBproducerTime_us = (uint32_t)CO_getUint16(buf) * 1000U; @@ -73,32 +70,19 @@ static ODR_t OD_write_1017(OD_stream_t *stream, const void *buf, return OD_writeOriginal(stream, buf, count, countWritten); } - -CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, - OD_entry_t *OD_1017_ProducerHbTime, - CO_EM_t *em, - uint8_t nodeId, - uint16_t NMTcontrol, - uint16_t firstHBTime_ms, - CO_CANmodule_t *NMT_CANdevRx, - uint16_t NMT_rxIdx, - uint16_t CANidRxNMT, -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 - CO_CANmodule_t *NMT_CANdevTx, - uint16_t NMT_txIdx, - uint16_t CANidTxNMT, +CO_ReturnError_t +CO_NMT_init(CO_NMT_t* NMT, OD_entry_t* OD_1017_ProducerHbTime, CO_EM_t* em, uint8_t nodeId, uint16_t NMTcontrol, + uint16_t firstHBTime_ms, CO_CANmodule_t* NMT_CANdevRx, uint16_t NMT_rxIdx, uint16_t CANidRxNMT, +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0 + CO_CANmodule_t* NMT_CANdevTx, uint16_t NMT_txIdx, uint16_t CANidTxNMT, #endif - CO_CANmodule_t *HB_CANdevTx, - uint16_t HB_txIdx, - uint16_t CANidTxHB, - uint32_t *errInfo) -{ + CO_CANmodule_t* HB_CANdevTx, uint16_t HB_txIdx, uint16_t CANidTxHB, uint32_t* errInfo) { CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if ((NMT == NULL) || (OD_1017_ProducerHbTime == NULL) || (em == NULL) - || (NMT_CANdevRx == NULL) || (HB_CANdevTx == NULL) -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 + if ((NMT == NULL) || (OD_1017_ProducerHbTime == NULL) || (em == NULL) || (NMT_CANdevRx == NULL) + || (HB_CANdevTx == NULL) +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0 || (NMT_CANdevTx == NULL) #endif ) { @@ -120,7 +104,9 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, uint16_t HBprodTime_ms; ODR_t odRet = OD_get_u16(OD_1017_ProducerHbTime, 0, &HBprodTime_ms, true); if (odRet != ODR_OK) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1017_ProducerHbTime); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1017_ProducerHbTime); + } return CO_ERROR_OD_PARAMETERS; } NMT->HBproducerTime_us = (uint32_t)HBprodTime_ms * 1000U; @@ -130,7 +116,9 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, NMT->OD_1017_extension.write = OD_write_1017; odRet = OD_extension_init(OD_1017_ProducerHbTime, &NMT->OD_1017_extension); if (odRet != ODR_OK) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1017_ProducerHbTime); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1017_ProducerHbTime); + } return CO_ERROR_OD_PARAMETERS; } @@ -139,28 +127,15 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, } /* configure NMT CAN reception */ - ret = CO_CANrxBufferInit( - NMT_CANdevRx, - NMT_rxIdx, - CANidRxNMT, - 0x7FF, - false, - (void*)NMT, - CO_NMT_receive); + ret = CO_CANrxBufferInit(NMT_CANdevRx, NMT_rxIdx, CANidRxNMT, 0x7FF, false, (void*)NMT, CO_NMT_receive); if (ret != CO_ERROR_NO) { return ret; } -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0 /* configure NMT CAN transmission */ NMT->NMT_CANdevTx = NMT_CANdevTx; - NMT->NMT_TXbuff = CO_CANtxBufferInit( - NMT_CANdevTx, - NMT_txIdx, - CANidTxNMT, - false, - 2, - false); + NMT->NMT_TXbuff = CO_CANtxBufferInit(NMT_CANdevTx, NMT_txIdx, CANidTxNMT, false, 2, false); if (NMT->NMT_TXbuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -168,13 +143,7 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, /* configure HB CAN transmission */ NMT->HB_CANdevTx = HB_CANdevTx; - NMT->HB_TXbuff = CO_CANtxBufferInit( - HB_CANdevTx, - HB_txIdx, - CANidTxHB, - false, - 1, - false); + NMT->HB_TXbuff = CO_CANtxBufferInit(HB_CANdevTx, HB_txIdx, CANidTxHB, false, 1, false); if (NMT->HB_TXbuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -182,12 +151,9 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, return ret; } - -#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_NMT_initCallbackPre(CO_NMT_t *NMT, - void *object, - void (*pFunctSignal)(void *object)) -{ +#if ((CO_CONFIG_NMT)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_NMT_initCallbackPre(CO_NMT_t* NMT, void* object, void (*pFunctSignal)(void* object)) { if (NMT != NULL) { NMT->pFunctSignalPre = pFunctSignal; NMT->functSignalObjectPre = object; @@ -195,11 +161,9 @@ void CO_NMT_initCallbackPre(CO_NMT_t *NMT, } #endif - -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0 -void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, - void (*pFunctNMT)(CO_NMT_internalState_t state)) -{ +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_CALLBACK_CHANGE) != 0 +void +CO_NMT_initCallbackChanged(CO_NMT_t* NMT, void (*pFunctNMT)(CO_NMT_internalState_t state)) { if (NMT != NULL) { NMT->pFunctNMT = pFunctNMT; if (NMT->pFunctNMT != NULL) { @@ -209,36 +173,30 @@ void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, } #endif - -CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, - CO_NMT_internalState_t *NMTstate, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +CO_NMT_reset_cmd_t +CO_NMT_process(CO_NMT_t* NMT, CO_NMT_internalState_t* NMTstate, uint32_t timeDifference_us, uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ CO_NMT_internalState_t NMTstateCpy = NMT->operatingState; CO_NMT_reset_cmd_t resetCommand = CO_RESET_NOT; bool_t NNTinit = NMTstateCpy == CO_NMT_INITIALIZING; - NMT->HBproducerTimer = (NMT->HBproducerTimer > timeDifference_us ) - ? (NMT->HBproducerTimer - timeDifference_us) : 0U; + NMT->HBproducerTimer = (NMT->HBproducerTimer > timeDifference_us) ? (NMT->HBproducerTimer - timeDifference_us) : 0U; /* Send heartbeat producer message if: * - First start, send bootup message or * - HB producer enabled and: Timer expired or NMT->operatingState changed*/ - if (NNTinit || ((NMT->HBproducerTime_us != 0U) - && ((NMT->HBproducerTimer == 0U) - || (NMTstateCpy != NMT->operatingStatePrev)) - )) { - NMT->HB_TXbuff->data[0] = (uint8_t) NMTstateCpy; + if (NNTinit + || ((NMT->HBproducerTime_us != 0U) + && ((NMT->HBproducerTimer == 0U) || (NMTstateCpy != NMT->operatingStatePrev)))) { + NMT->HB_TXbuff->data[0] = (uint8_t)NMTstateCpy; (void)CO_CANsend(NMT->HB_CANdevTx, NMT->HB_TXbuff); if (NMTstateCpy == CO_NMT_INITIALIZING) { /* NMT slave self starting */ NMTstateCpy = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_STARTUP_TO_OPERATIONAL) != 0U) - ? CO_NMT_OPERATIONAL : CO_NMT_PRE_OPERATIONAL; - } - else { + ? CO_NMT_OPERATIONAL + : CO_NMT_PRE_OPERATIONAL; + } else { /* Start timer from the beginning. If OS is slow, time sliding may * occur. However, heartbeat is not for synchronization, it is for * health report. In case of initializing, timer is set in the @@ -252,21 +210,11 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, * CO_NMT_sendCommand() */ if (NMT->internalCommand != CO_NMT_NO_COMMAND) { switch (NMT->internalCommand) { - case CO_NMT_ENTER_OPERATIONAL: - NMTstateCpy = CO_NMT_OPERATIONAL; - break; - case CO_NMT_ENTER_STOPPED: - NMTstateCpy = CO_NMT_STOPPED; - break; - case CO_NMT_ENTER_PRE_OPERATIONAL: - NMTstateCpy = CO_NMT_PRE_OPERATIONAL; - break; - case CO_NMT_RESET_NODE: - resetCommand = CO_RESET_APP; - break; - case CO_NMT_RESET_COMMUNICATION: - resetCommand = CO_RESET_COMM; - break; + case CO_NMT_ENTER_OPERATIONAL: NMTstateCpy = CO_NMT_OPERATIONAL; break; + case CO_NMT_ENTER_STOPPED: NMTstateCpy = CO_NMT_STOPPED; break; + case CO_NMT_ENTER_PRE_OPERATIONAL: NMTstateCpy = CO_NMT_PRE_OPERATIONAL; break; + case CO_NMT_RESET_NODE: resetCommand = CO_RESET_APP; break; + case CO_NMT_RESET_COMMUNICATION: resetCommand = CO_RESET_COMM; break; case CO_NMT_NO_COMMAND: default: /* done */ @@ -280,24 +228,22 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, bool_t ErrBusOff = CO_isError(NMT->em, CO_EM_CAN_TX_BUS_OFF); bool_t ErrHbCons = CO_isError(NMT->em, CO_EM_HEARTBEAT_CONSUMER); bool_t ErrHbConsRemote = CO_isError(NMT->em, CO_EM_HB_CONSUMER_REMOTE_RESET); - bool_t busOff_HB = ErrOnBusOffHB && (ErrBusOff|| ErrHbCons || ErrHbConsRemote); + bool_t busOff_HB = ErrOnBusOffHB && (ErrBusOff || ErrHbCons || ErrHbConsRemote); bool_t ErrNMTErrReg = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_ON_ERR_REG) != 0U); - bool_t ErrNMTcontrol =((CO_getErrorRegister(NMT->em) & (uint8_t)NMT->NMTcontrol) != 0U); + bool_t ErrNMTcontrol = ((CO_getErrorRegister(NMT->em) & (uint8_t)NMT->NMTcontrol) != 0U); bool_t errRegMasked = ErrNMTErrReg && ErrNMTcontrol; if ((NMTstateCpy == CO_NMT_OPERATIONAL) && (busOff_HB || errRegMasked)) { - NMTstateCpy = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_TO_STOPPED) != 0U) - ? CO_NMT_STOPPED : CO_NMT_PRE_OPERATIONAL; - } - else if ((((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_FREE_TO_OPERATIONAL) != 0U) - && (NMTstateCpy == CO_NMT_PRE_OPERATIONAL) && (!busOff_HB && !errRegMasked) - ) { + NMTstateCpy = (((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_TO_STOPPED) != 0U) ? CO_NMT_STOPPED + : CO_NMT_PRE_OPERATIONAL; + } else if ((((uint16_t)NMT->NMTcontrol & (uint16_t)CO_NMT_ERR_FREE_TO_OPERATIONAL) != 0U) + && (NMTstateCpy == CO_NMT_PRE_OPERATIONAL) && (!busOff_HB && !errRegMasked)) { NMTstateCpy = CO_NMT_OPERATIONAL; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0 +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_CALLBACK_CHANGE) != 0 /* Notify operating state change */ if ((NMT->operatingStatePrev != NMTstateCpy) || NNTinit) { if (NMT->pFunctNMT != NULL) { @@ -306,31 +252,29 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, } #endif -#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_NMT)&CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate, when next Heartbeat needs to be send */ if ((NMT->HBproducerTime_us != 0U) && (timerNext_us != NULL)) { if (NMT->operatingStatePrev != NMTstateCpy) { *timerNext_us = 0; - } - else if (*timerNext_us > NMT->HBproducerTimer) { + } else if (*timerNext_us > NMT->HBproducerTimer) { *timerNext_us = NMT->HBproducerTimer; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } #endif NMT->operatingState = NMTstateCpy; - if (NMTstate != NULL) { *NMTstate = NMTstateCpy; } + if (NMTstate != NULL) { + *NMTstate = NMTstateCpy; + } return resetCommand; } - -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 -CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, - CO_NMT_command_t command, - uint8_t nodeID) -{ +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0 +CO_ReturnError_t +CO_NMT_sendCommand(CO_NMT_t* NMT, CO_NMT_command_t command, uint8_t nodeID) { /* verify arguments */ if (NMT == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index a7506d4d..8be43dec 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -20,7 +20,7 @@ #include "301/CO_Node_Guarding.h" -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 /* * Read received message from CAN module. @@ -29,29 +29,27 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_ngs_receive(void *object, void *msg) { - (void) msg; - CO_nodeGuardingSlave_t *ngs = (CO_nodeGuardingSlave_t*)object; +static void +CO_ngs_receive(void* object, void* msg) { + (void)msg; + CO_nodeGuardingSlave_t* ngs = (CO_nodeGuardingSlave_t*)object; CO_FLAG_SET(ngs->CANrxNew); } - /* * Custom function for writing OD object "Guard time" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_100C(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count != sizeof(uint16_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_100C(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint16_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_nodeGuardingSlave_t *ngs = (CO_nodeGuardingSlave_t *)stream->object; + CO_nodeGuardingSlave_t* ngs = (CO_nodeGuardingSlave_t*)stream->object; /* update objects */ ngs->guardTime_us = (uint32_t)CO_getUint16(buf) * 1000U; @@ -66,22 +64,19 @@ static ODR_t OD_write_100C(OD_stream_t *stream, const void *buf, return OD_writeOriginal(stream, buf, count, countWritten); } - /* * Custom function for writing OD object "Life time factor" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_100D(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count != sizeof(uint8_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_100D(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint8_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_nodeGuardingSlave_t *ngs = (CO_nodeGuardingSlave_t *)stream->object; + CO_nodeGuardingSlave_t* ngs = (CO_nodeGuardingSlave_t*)stream->object; /* update objects */ ngs->lifeTimeFactor = (uint8_t)CO_getUint8(buf); @@ -96,24 +91,16 @@ static ODR_t OD_write_100D(OD_stream_t *stream, const void *buf, return OD_writeOriginal(stream, buf, count, countWritten); } - -CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, - OD_entry_t *OD_100C_GuardTime, - OD_entry_t *OD_100D_LifeTimeFactor, - CO_EM_t *em, - uint16_t CANidNodeGuarding, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint32_t *errInfo) -{ +CO_ReturnError_t +CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t* ngs, OD_entry_t* OD_100C_GuardTime, + OD_entry_t* OD_100D_LifeTimeFactor, CO_EM_t* em, uint16_t CANidNodeGuarding, + CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t* CANdevTx, + uint16_t CANdevTxIdx, uint32_t* errInfo) { CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if ((ngs == NULL) || (em == NULL) || (CANdevRx == NULL) || (CANdevTx == NULL) - || (OD_100C_GuardTime == NULL) || (OD_100D_LifeTimeFactor == NULL) - ) { + if ((ngs == NULL) || (em == NULL) || (CANdevRx == NULL) || (CANdevTx == NULL) || (OD_100C_GuardTime == NULL) + || (OD_100D_LifeTimeFactor == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -169,27 +156,14 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, } /* configure CAN reception */ - ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - CANidNodeGuarding, - 0x7FF, - true, - (void*)ngs, - CO_ngs_receive); + ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, CANidNodeGuarding, 0x7FF, true, (void*)ngs, CO_ngs_receive); if (ret != CO_ERROR_NO) { return ret; } /* configure CAN transmission */ ngs->CANdevTx = CANdevTx; - ngs->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, - CANdevTxIdx, - CANidNodeGuarding, - false, - 1, - false); + ngs->CANtxBuff = CO_CANtxBufferInit(CANdevTx, CANdevTxIdx, CANidNodeGuarding, false, 1, false); if (ngs->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -197,13 +171,9 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, return ret; } - -void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, - CO_NMT_internalState_t NMTstate, - bool_t slaveDisable, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +void +CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t* ngs, CO_NMT_internalState_t NMTstate, bool_t slaveDisable, + uint32_t timeDifference_us, uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ if (slaveDisable) { @@ -218,12 +188,11 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, ngs->lifeTimer = ngs->lifeTime_us; /* send response */ - ngs->CANtxBuff->data[0] = (uint8_t) NMTstate; + ngs->CANtxBuff->data[0] = (uint8_t)NMTstate; if (ngs->toggle) { ngs->CANtxBuff->data[0] |= 0x80U; ngs->toggle = false; - } - else { + } else { ngs->toggle = true; } (void)CO_CANsend(ngs->CANdevTx, ngs->CANtxBuff); @@ -241,33 +210,28 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, else if (ngs->lifeTimer > 0U) { if (timeDifference_us < ngs->lifeTimer) { ngs->lifeTimer -= timeDifference_us; -#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_NMT)&CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate, when timeout expires */ if (timerNext_us != NULL && *timerNext_us > ngs->lifeTimer) { *timerNext_us = ngs->lifeTimer; } #endif - } - else { + } else { ngs->lifeTimer = 0; ngs->lifeTimeTimeout = true; /* error bit is shared with HB consumer */ - CO_errorReport(ngs->em, CO_EM_HEARTBEAT_CONSUMER, - CO_EMC_HEARTBEAT, 0); + CO_errorReport(ngs->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, 0); } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } return; } #endif /* (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE */ - - - -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 /* * Read received message from CAN module. * @@ -278,16 +242,17 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, * Function receives messages from CAN identifier from 0x700 to 0x7FF. It * searches matching node->ident from nodes array. */ -static void CO_ngm_receive(void *object, void *msg) { - CO_nodeGuardingMaster_t *ngm = (CO_nodeGuardingMaster_t*)object; +static void +CO_ngm_receive(void* object, void* msg) { + CO_nodeGuardingMaster_t* ngm = (CO_nodeGuardingMaster_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); uint16_t ident = CO_CANrxMsg_readIdent(msg); - CO_nodeGuardingMasterNode_t *node = &ngm->nodes[0]; + CO_nodeGuardingMasterNode_t* node = &ngm->nodes[0]; if (DLC == 1) { - for (uint8_t i=0; iident) { uint8_t toggle = data[0] & 0x80; if (toggle == node->toggle) { @@ -297,19 +262,14 @@ static void CO_ngm_receive(void *object, void *msg) { } break; } - node ++; + node++; } } } - -CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, - CO_EM_t *em, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx) -{ +CO_ReturnError_t +CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t* ngm, CO_EM_t* em, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx) { CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ @@ -325,14 +285,7 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, /* configure CAN reception. One buffer will receive all messages * from CAN-id 0x700 to 0x7FF. */ - ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - CO_CAN_ID_HEARTBEAT, - 0x780, - false, - (void*)ngm, - CO_ngm_receive); + ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, CO_CAN_ID_HEARTBEAT, 0x780, false, (void*)ngm, CO_ngm_receive); if (ret != CO_ERROR_NO) { return ret; } @@ -340,13 +293,7 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, /* configure CAN transmission */ ngm->CANdevTx = CANdevTx; ngm->CANdevTxIdx = CANdevTxIdx; - ngm->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, - CANdevTxIdx, - CO_CAN_ID_HEARTBEAT, - true, - 1, - 0); + ngm->CANtxBuff = CO_CANtxBufferInit(CANdevTx, CANdevTxIdx, CO_CAN_ID_HEARTBEAT, true, 1, 0); if (ngm->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -354,19 +301,13 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, return ret; } - -CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t *ngm, - uint8_t index, - uint8_t nodeId, - uint16_t guardTime_ms) -{ - if (ngm == NULL || index >= CO_CONFIG_NODE_GUARDING_MASTER_COUNT - || nodeId < 1 || nodeId > 0x7F - ) { +CO_ReturnError_t +CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t* ngm, uint8_t index, uint8_t nodeId, uint16_t guardTime_ms) { + if (ngm == NULL || index >= CO_CONFIG_NODE_GUARDING_MASTER_COUNT || nodeId < 1 || nodeId > 0x7F) { return CO_ERROR_ILLEGAL_ARGUMENT; } - CO_nodeGuardingMasterNode_t *node = &ngm->nodes[index]; + CO_nodeGuardingMasterNode_t* node = &ngm->nodes[index]; node->guardTime_us = (uint32_t)guardTime_ms * 1000; node->guardTimer = 0; @@ -378,62 +319,48 @@ CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t *ngm, node->monitoringActive = false; #if CO_CONFIG_NODE_GUARDING_MASTER_COUNT == 1 - ngm->CANtxBuff = CO_CANtxBufferInit(ngm->CANdevTx, - ngm->CANdevTxIdx, - node->ident, - true, 1, 0); + ngm->CANtxBuff = CO_CANtxBufferInit(ngm->CANdevTx, ngm->CANdevTxIdx, node->ident, true, 1, 0); #endif - return CO_ERROR_NO; + return CO_ERROR_NO; } - -void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +void +CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t* ngm, uint32_t timeDifference_us, uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ bool_t allMonitoredActiveCurrent = true; bool_t allMonitoredOperationalCurrent = true; - CO_nodeGuardingMasterNode_t *node = &ngm->nodes[0]; + CO_nodeGuardingMasterNode_t* node = &ngm->nodes[0]; - for (uint8_t i=0; iguardTime_us > 0 && node->ident > CO_CAN_ID_HEARTBEAT) { if (timeDifference_us < node->guardTimer) { node->guardTimer -= timeDifference_us; -#if ((CO_CONFIG_NMT) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_NMT)&CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate, when timeout expires */ if (timerNext_us != NULL && *timerNext_us > node->guardTimer) { *timerNext_us = node->guardTimer; } #endif - } - else { + } else { /* it is time to send new rtr, but first verify last response */ if (!node->CANtxWasBusy) { if (!node->responseRecived) { node->monitoringActive = false; /* error bit is shared with HB consumer */ - CO_errorReport(ngm->em, CO_EM_HEARTBEAT_CONSUMER, - CO_EMC_HEARTBEAT, node->ident & 0x7F); - } - else if (node->NMTstate != CO_NMT_UNKNOWN) { + CO_errorReport(ngm->em, CO_EM_HEARTBEAT_CONSUMER, CO_EMC_HEARTBEAT, node->ident & 0x7F); + } else if (node->NMTstate != CO_NMT_UNKNOWN) { node->monitoringActive = true; - CO_errorReset(ngm->em, CO_EM_HEARTBEAT_CONSUMER, - node->ident & 0x7F); + CO_errorReset(ngm->em, CO_EM_HEARTBEAT_CONSUMER, node->ident & 0x7F); } } if (ngm->CANtxBuff->bufferFull) { node->guardTimer = 0; node->CANtxWasBusy = true; - } - else { + } else { #if CO_CONFIG_NODE_GUARDING_MASTER_COUNT > 1 - ngm->CANtxBuff = CO_CANtxBufferInit(ngm->CANdevTx, - ngm->CANdevTxIdx, - node->ident, - true, 1, 0); + ngm->CANtxBuff = CO_CANtxBufferInit(ngm->CANdevTx, ngm->CANdevTxIdx, node->ident, true, 1, 0); #endif (void)CO_CANsend(ngm->CANdevTx, ngm->CANtxBuff); node->CANtxWasBusy = false; @@ -447,15 +374,14 @@ void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, if (node->NMTstate != CO_NMT_OPERATIONAL) { allMonitoredOperationalCurrent = false; } - } - else { + } else { allMonitoredActiveCurrent = false; allMonitoredOperationalCurrent = false; } } } /* if node enabled */ - node ++; + node++; } /* for */ ngm->allMonitoredActive = allMonitoredActiveCurrent; diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 3dca47a4..fcba2a83 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -21,16 +21,14 @@ #define OD_DEFINITION #include "301/CO_ODinterface.h" - -ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ +ODR_t +OD_readOriginal(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { if ((stream == NULL) || (buf == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ - const uint8_t *dataOrig = stream->dataOrig; + const uint8_t* dataOrig = stream->dataOrig; if (dataOrig == NULL) { return ODR_SUB_NOT_EXIST; @@ -53,28 +51,26 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, dataLenToCopy = count; stream->dataOffset += dataLenToCopy; returnCode = ODR_PARTIAL; - } - else { + } else { stream->dataOffset = 0; /* copy finished, reset offset */ } } - (void)memcpy((void *)buf, (const void *)dataOrig, dataLenToCopy); + (void)memcpy((void*)buf, (const void*)dataOrig, dataLenToCopy); *countRead = dataLenToCopy; return returnCode; } -ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ +ODR_t +OD_writeOriginal(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } OD_size_t dataLenToCopy = stream->dataLength; /* length of OD variable */ OD_size_t dataLenRemain = dataLenToCopy; /* remaining length of dataOrig buffer */ - uint8_t *dataOrig = stream->dataOrig; + uint8_t* dataOrig = stream->dataOrig; if (dataOrig == NULL) { return ODR_SUB_NOT_EXIST; @@ -100,8 +96,7 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, dataLenToCopy = count; stream->dataOffset += dataLenToCopy; returnCode = ODR_PARTIAL; - } - else { + } else { stream->dataOffset = 0; /* copy finished, reset offset */ } } @@ -113,9 +108,8 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, /* additional check for Misra c compliance */ if ((dataLenToCopy <= dataLenRemain) && (dataLenToCopy <= count)) { - (void)memcpy((void *)dataOrig, (const void *)buf, dataLenToCopy); - } - else { + (void)memcpy((void*)dataOrig, (const void*)buf, dataLenToCopy); + } else { return ODR_DEV_INCOMPAT; } @@ -124,23 +118,27 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, } /* Read value from variable from Object Dictionary disabled, see OD_IO_t*/ -static ODR_t OD_readDisabled(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ - (void) stream; (void) buf; (void) count; (void) countRead; +static ODR_t +OD_readDisabled(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + (void)stream; + (void)buf; + (void)count; + (void)countRead; return ODR_UNSUPP_ACCESS; } /* Write value to variable from Object Dictionary disabled, see OD_IO_t */ -static ODR_t OD_writeDisabled(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - (void) stream; (void) buf; (void) count; (void) countWritten; +static ODR_t +OD_writeDisabled(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + (void)stream; + (void)buf; + (void)count; + (void)countWritten; return ODR_UNSUPP_ACCESS; } - -OD_entry_t *OD_find(OD_t *od, uint16_t index) { +OD_entry_t* +OD_find(OD_t* od, uint16_t index) { if ((od == NULL) || (od->size == 0U)) { return NULL; } @@ -162,8 +160,7 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index) { if (index < entry->index) { max = (cur > 0U) ? (cur - 1U) : cur; - } - else { + } else { min = cur + 1U; } } @@ -175,67 +172,73 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index) { } } - return NULL; /* entry does not exist in OD */ + return NULL; /* entry does not exist in OD */ } -ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, - OD_IO_t *io, bool_t odOrig) -{ - if ((entry == NULL) || (entry->odObject == NULL)) { return ODR_IDX_NOT_EXIST; } - if (io == NULL) { return ODR_DEV_INCOMPAT; } +ODR_t +OD_getSub(const OD_entry_t* entry, uint8_t subIndex, OD_IO_t* io, bool_t odOrig) { + if ((entry == NULL) || (entry->odObject == NULL)) { + return ODR_IDX_NOT_EXIST; + } + if (io == NULL) { + return ODR_DEV_INCOMPAT; + } - OD_stream_t *stream = &io->stream; + OD_stream_t* stream = &io->stream; /* attribute, dataOrig and dataLength, depends on object type */ switch (entry->odObjectType & (uint8_t)ODT_TYPE_MASK) { - case ODT_VAR: { - if (subIndex > 0U) { return ODR_SUB_NOT_EXIST; } - CO_PROGMEM OD_obj_var_t *odo = entry->odObject; - + case ODT_VAR: { + if (subIndex > 0U) { + return ODR_SUB_NOT_EXIST; + } + CO_PROGMEM OD_obj_var_t* odo = entry->odObject; - stream->attribute = odo->attribute; - stream->dataOrig = odo->dataOrig; - stream->dataLength = odo->dataLength; - break; - } - case ODT_ARR: { - if (subIndex >= entry->subEntriesCount) { return ODR_SUB_NOT_EXIST; } - CO_PROGMEM OD_obj_array_t *odo = entry->odObject; - - if (subIndex == 0U) { - stream->attribute = odo->attribute0; - stream->dataOrig = odo->dataOrig0; - stream->dataLength = 1; - } - else { stream->attribute = odo->attribute; - uint8_t *ptr = odo->dataOrig; - stream->dataOrig = (ptr == NULL) ? ptr - : (ptr + (odo->dataElementSizeof * (uint8_t)(subIndex - 1U))); - stream->dataLength = odo->dataElementLength; + stream->dataOrig = odo->dataOrig; + stream->dataLength = odo->dataLength; + break; } - break; - } - case ODT_REC: { - CO_PROGMEM OD_obj_record_t *odoArr = entry->odObject; - CO_PROGMEM OD_obj_record_t *odo = NULL; - for (uint8_t i = 0; i < entry->subEntriesCount; i++) { - if (odoArr[i].subIndex == subIndex) { - odo = &odoArr[i]; - break; + case ODT_ARR: { + if (subIndex >= entry->subEntriesCount) { + return ODR_SUB_NOT_EXIST; + } + CO_PROGMEM OD_obj_array_t* odo = entry->odObject; + + if (subIndex == 0U) { + stream->attribute = odo->attribute0; + stream->dataOrig = odo->dataOrig0; + stream->dataLength = 1; + } else { + stream->attribute = odo->attribute; + uint8_t* ptr = odo->dataOrig; + stream->dataOrig = (ptr == NULL) ? ptr : (ptr + (odo->dataElementSizeof * (uint8_t)(subIndex - 1U))); + stream->dataLength = odo->dataElementLength; } + break; } - if (odo == NULL) { return ODR_SUB_NOT_EXIST; } + case ODT_REC: { + CO_PROGMEM OD_obj_record_t* odoArr = entry->odObject; + CO_PROGMEM OD_obj_record_t* odo = NULL; + for (uint8_t i = 0; i < entry->subEntriesCount; i++) { + if (odoArr[i].subIndex == subIndex) { + odo = &odoArr[i]; + break; + } + } + if (odo == NULL) { + return ODR_SUB_NOT_EXIST; + } - stream->attribute = odo->attribute; - stream->dataOrig = odo->dataOrig; - stream->dataLength = odo->dataLength; - break; - } - default: { - return ODR_DEV_INCOMPAT; - break; - } + stream->attribute = odo->attribute; + stream->dataOrig = odo->dataOrig; + stream->dataLength = odo->dataLength; + break; + } + default: { + return ODR_DEV_INCOMPAT; + break; + } } /* Access data from the original OD location */ @@ -246,10 +249,8 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, } /* Access data from extension specified by application */ else { - io->read = (entry->extension->read != NULL) ? - entry->extension->read : OD_readDisabled; - io->write = (entry->extension->write != NULL) ? - entry->extension->write : OD_writeDisabled; + io->read = (entry->extension->read != NULL) ? entry->extension->read : OD_readDisabled; + io->write = (entry->extension->write != NULL) ? entry->extension->write : OD_writeDisabled; stream->object = entry->extension->object; } @@ -263,7 +264,8 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, return ODR_OK; } -uint32_t OD_getSDOabCode(ODR_t returnCode) { +uint32_t +OD_getSDOabCode(ODR_t returnCode) { static const uint32_t abortCodes[(uint8_t)ODR_COUNT] = { 0x00000000UL, /* No abort */ 0x05040005UL, /* Out of memory */ @@ -293,65 +295,73 @@ uint32_t OD_getSDOabCode(ODR_t returnCode) { 0x08000024UL /* No data available */ }; - return ((returnCode < ODR_OK) || (returnCode >= ODR_COUNT)) ? - abortCodes[ODR_DEV_INCOMPAT] : abortCodes[returnCode]; + return ((returnCode < ODR_OK) || (returnCode >= ODR_COUNT)) ? abortCodes[ODR_DEV_INCOMPAT] : abortCodes[returnCode]; } +ODR_t +OD_get_value(const OD_entry_t* entry, uint8_t subIndex, void* val, OD_size_t len, bool_t odOrig) { + if (val == NULL) { + return ODR_DEV_INCOMPAT; + } -ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, - void *val, OD_size_t len, bool_t odOrig) -{ - if (val == NULL) { return ODR_DEV_INCOMPAT; } - - OD_IO_t io = { NULL }; - OD_stream_t *stream = &io.stream; + OD_IO_t io = {NULL}; + OD_stream_t* stream = &io.stream; OD_size_t countRd = 0; ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - if (ret != ODR_OK) { return ret; } - if (stream->dataLength != len) { return ODR_TYPE_MISMATCH; } + if (ret != ODR_OK) { + return ret; + } + if (stream->dataLength != len) { + return ODR_TYPE_MISMATCH; + } return io.read(stream, val, len, &countRd); } -ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, - OD_size_t len, bool_t odOrig) -{ - if (val == NULL) { return ODR_DEV_INCOMPAT; } +ODR_t +OD_set_value(const OD_entry_t* entry, uint8_t subIndex, void* val, OD_size_t len, bool_t odOrig) { + if (val == NULL) { + return ODR_DEV_INCOMPAT; + } - OD_IO_t io = { NULL }; - OD_stream_t *stream = &io.stream; + OD_IO_t io = {NULL}; + OD_stream_t* stream = &io.stream; OD_size_t countWritten = 0; ODR_t ret = OD_getSub(entry, subIndex, &io, odOrig); - if (ret != ODR_OK) { return ret; } - if (stream->dataLength != len) { return ODR_TYPE_MISMATCH; } + if (ret != ODR_OK) { + return ret; + } + if (stream->dataLength != len) { + return ODR_TYPE_MISMATCH; + } return io.write(stream, val, len, &countWritten); } -void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, - ODR_t *err) -{ +void* +OD_getPtr(const OD_entry_t* entry, uint8_t subIndex, OD_size_t len, ODR_t* err) { ODR_t errCopy; OD_IO_t io; - OD_stream_t *stream = &io.stream; + OD_stream_t* stream = &io.stream; errCopy = OD_getSub(entry, subIndex, &io, true); if (errCopy == ODR_OK) { if ((stream->dataOrig == NULL) || (stream->dataLength == 0U)) { errCopy = ODR_DEV_INCOMPAT; - } - else if ((len != 0U) && (len != stream->dataLength)) { + } else if ((len != 0U) && (len != stream->dataLength)) { errCopy = ODR_TYPE_MISMATCH; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } - if (err != NULL) { *err = errCopy; } + if (err != NULL) { + *err = errCopy; + } return (errCopy == ODR_OK) ? stream->dataOrig : NULL; } diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 18c5dfb4..c136f8c5 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -24,23 +24,25 @@ #if ((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) != 0 -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 - #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 - #error Dynamic PDO mapping is not possible without CO_CONFIG_PDO_OD_IO_ACCESS - #endif +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) == 0 +#error Dynamic PDO mapping is not possible without CO_CONFIG_PDO_OD_IO_ACCESS +#endif #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) != 0 /* * Custom function for write dummy OD object. Will be used only from RPDO. * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_dummy(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - (void) stream; (void) buf; - if (countWritten != NULL) { *countWritten = count; } +static ODR_t +OD_write_dummy(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + (void)stream; + (void)buf; + if (countWritten != NULL) { + *countWritten = count; + } return ODR_OK; } @@ -49,9 +51,8 @@ static ODR_t OD_write_dummy(OD_stream_t *stream, const void *buf, * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_read_dummy(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ +static ODR_t +OD_read_dummy(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { if ((buf == NULL) || (stream == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } @@ -66,7 +67,6 @@ static ODR_t OD_read_dummy(OD_stream_t *stream, void *buf, return ODR_OK; } - /* * Find mapped variable in Object Dictionary and configure entry in RPDO or TPDO * @@ -79,17 +79,13 @@ static ODR_t OD_read_dummy(OD_stream_t *stream, void *buf, * * @return ODR_OK on success, otherwise error reason. */ -static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, - uint32_t map, - uint8_t mapIndex, - bool_t isRPDO, - OD_t *OD) -{ - uint16_t index = (uint16_t) (map >> 16); - uint8_t subIndex = (uint8_t) (map >> 8); - uint8_t mappedLengthBits = (uint8_t) map; +static ODR_t +PDOconfigMap(CO_PDO_common_t* PDO, uint32_t map, uint8_t mapIndex, bool_t isRPDO, OD_t* OD) { + uint16_t index = (uint16_t)(map >> 16); + uint8_t subIndex = (uint8_t)(map >> 8); + uint8_t mappedLengthBits = (uint8_t)map; uint8_t mappedLength = mappedLengthBits >> 3; - OD_IO_t *OD_IO = &PDO->OD_IO[mapIndex]; + OD_IO_t* OD_IO = &PDO->OD_IO[mapIndex]; /* total PDO length can not be more than CO_PDO_MAX_SIZE bytes */ if (mappedLength > CO_PDO_MAX_SIZE) { @@ -98,7 +94,7 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, /* is there a reference to the dummy entry */ if ((index < 0x20U) && (subIndex == 0U)) { - OD_stream_t *stream = &OD_IO->stream; + OD_stream_t* stream = &OD_IO->stream; (void)memset(stream, 0, sizeof(OD_stream_t)); stream->dataLength = mappedLength; stream->dataOffset = mappedLength; @@ -109,7 +105,7 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, /* find entry in the Object Dictionary */ OD_IO_t OD_IOcopy; - OD_entry_t *entry = OD_find(OD, index); + OD_entry_t* entry = OD_find(OD, index); ODR_t odRet = OD_getSub(entry, subIndex, &OD_IOcopy, false); if (odRet != ODR_OK) { return odRet; @@ -117,10 +113,8 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, /* verify access attributes, byte alignment and length */ OD_attr_t testAttribute = isRPDO ? (OD_attr_t)(ODA_RPDO) : (OD_attr_t)(ODA_TPDO); - if (((OD_IOcopy.stream.attribute & testAttribute) == 0U) - || ((mappedLengthBits & 0x07U) != 0U) - || (OD_IOcopy.stream.dataLength < mappedLength) - ) { + if (((OD_IOcopy.stream.attribute & testAttribute) == 0U) || ((mappedLengthBits & 0x07U) != 0U) + || (OD_IOcopy.stream.dataLength < mappedLength)) { return ODR_NO_MAP; /* Object cannot be mapped to the PDO. */ } @@ -132,11 +126,9 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, #if OD_FLAGS_PDO_SIZE > 0 if (!isRPDO) { if ((subIndex < (OD_FLAGS_PDO_SIZE * 8U)) && (entry->extension != NULL)) { - PDO->flagPDObyte[mapIndex] = - &entry->extension->flagsPDO[subIndex >> 3]; + PDO->flagPDObyte[mapIndex] = &entry->extension->flagsPDO[subIndex >> 3]; PDO->flagPDObitmask[mapIndex] = 1U << (subIndex & 0x07U); - } - else { + } else { PDO->flagPDObyte[mapIndex] = NULL; } } @@ -157,13 +149,9 @@ static ODR_t PDOconfigMap(CO_PDO_common_t *PDO, * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, - OD_t *OD, - OD_entry_t *OD_PDOMapPar, - bool_t isRPDO, - uint32_t *errInfo, - uint32_t *erroneousMap) -{ +static CO_ReturnError_t +PDO_initMapping(CO_PDO_common_t* PDO, OD_t* OD, OD_entry_t* OD_PDOMapPar, bool_t isRPDO, uint32_t* errInfo, + uint32_t* erroneousMap) { ODR_t odRet; size_t pdoDataLength = 0; uint8_t mappedObjectsCount = 0; @@ -178,7 +166,7 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, } for (uint8_t i = 0; i < CO_PDO_MAX_MAPPED_ENTRIES; i++) { - OD_IO_t *OD_IO = &PDO->OD_IO[i]; + OD_IO_t* OD_IO = &PDO->OD_IO[i]; uint32_t map = 0; odRet = OD_get_u32(OD_PDOMapPar, i + 1U, &map, true); @@ -187,7 +175,7 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, } if (odRet != ODR_OK) { if (errInfo != NULL) { - *errInfo = (((uint32_t)OD_getIndex(OD_PDOMapPar))<<8) | i; + *errInfo = (((uint32_t)OD_getIndex(OD_PDOMapPar)) << 8) | i; } return CO_ERROR_OD_PARAMETERS; } @@ -197,17 +185,19 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, /* indicate erroneous mapping in initialization phase */ OD_IO->stream.dataLength = 0; OD_IO->stream.dataOffset = 0xFF; - if (*erroneousMap == 0U) { *erroneousMap = map; } + if (*erroneousMap == 0U) { + *erroneousMap = map; + } } if (i < mappedObjectsCount) { pdoDataLength += OD_IO->stream.dataOffset; } } - if ((pdoDataLength > CO_PDO_MAX_SIZE) - || ((pdoDataLength == 0U) && (mappedObjectsCount > 0U)) - ) { - if (*erroneousMap == 0U) { *erroneousMap = 1; } + if ((pdoDataLength > CO_PDO_MAX_SIZE) || ((pdoDataLength == 0U) && (mappedObjectsCount > 0U))) { + if (*erroneousMap == 0U) { + *erroneousMap = 1; + } } if (*erroneousMap == 0U) { @@ -218,24 +208,21 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, return CO_ERROR_NO; } -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "PDO mapping parameter" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ +static ODR_t +OD_write_PDO_mapping(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { /* "count" is already verified in *_init() function */ - if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) - || (stream->subIndex > CO_PDO_MAX_MAPPED_ENTRIES) - ) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (stream->subIndex > CO_PDO_MAX_MAPPED_ENTRIES)) { return ODR_DEV_INCOMPAT; } /* Only common part of the CO_RPDO_t or CO_TPDO_t will be used */ - CO_PDO_common_t *PDO = stream->object; + CO_PDO_common_t* PDO = stream->object; /* PDO must be disabled before mapping configuration */ if ((PDO->valid) || ((PDO->mappedObjectsCount != 0U) && (stream->subIndex > 0U))) { @@ -252,9 +239,9 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, /* validate enabled mapping parameters */ for (uint8_t i = 0; i < mappedObjectsCount; i++) { - OD_IO_t *OD_IO = &PDO->OD_IO[i]; - size_t dataLength = (size_t) OD_IO->stream.dataLength; - size_t mappedLength = (size_t) OD_IO->stream.dataOffset; + OD_IO_t* OD_IO = &PDO->OD_IO[i]; + size_t dataLength = (size_t)OD_IO->stream.dataLength; + size_t mappedLength = (size_t)OD_IO->stream.dataOffset; if (mappedLength > dataLength) { /* erroneous map since device initial values */ @@ -273,11 +260,9 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, /* success, update PDO */ PDO->dataLength = (CO_PDO_size_t)pdoDataLength; PDO->mappedObjectsCount = mappedObjectsCount; - } - else { + } else { uint32_t val = CO_getUint32(buf); - ODR_t odRet = PDOconfigMap(PDO, val, stream->subIndex-1U, - PDO->isRPDO, PDO->OD); + ODR_t odRet = PDOconfigMap(PDO, val, stream->subIndex - 1U, PDO->isRPDO, PDO->OD); if (odRet != ODR_OK) { return odRet; } @@ -289,15 +274,10 @@ static ODR_t OD_write_PDO_mapping(OD_stream_t *stream, const void *buf, #endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ #endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ - -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 -static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, - OD_t *OD, - OD_entry_t *OD_PDOMapPar, - bool_t isRPDO, - uint32_t *errInfo, - uint32_t *erroneousMap) -{ +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) == 0 +static CO_ReturnError_t +PDO_initMapping(CO_PDO_common_t* PDO, OD_t* OD, OD_entry_t* OD_PDOMapPar, bool_t isRPDO, uint32_t* errInfo, + uint32_t* erroneousMap) { ODR_t odRet; size_t pdoDataLength = 0; @@ -326,9 +306,9 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, } return CO_ERROR_OD_PARAMETERS; } - uint16_t index = (uint16_t) (map >> 16); - uint8_t subIndex = (uint8_t) (map >> 8); - uint8_t mappedLengthBits = (uint8_t) map; + uint16_t index = (uint16_t)(map >> 16); + uint8_t subIndex = (uint8_t)(map >> 8); + uint8_t mappedLengthBits = (uint8_t)map; uint8_t mappedLength = mappedLengthBits >> 3; uint8_t pdoDataStart = pdoDataLength; pdoDataLength += mappedLength; @@ -350,32 +330,27 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, /* find entry in the Object Dictionary, original location */ OD_IO_t OD_IO; - OD_entry_t *entry = OD_find(OD, index); + OD_entry_t* entry = OD_find(OD, index); OD_attr_t testAttribute = isRPDO ? ODA_RPDO : ODA_TPDO; ODR_t odRet = OD_getSub(entry, subIndex, &OD_IO, true); - if (odRet != ODR_OK - || (OD_IO.stream.attribute & testAttribute) == 0 - || OD_IO.stream.dataLength < mappedLength - || OD_IO.stream.dataOrig == NULL - ) { + if (odRet != ODR_OK || (OD_IO.stream.attribute & testAttribute) == 0 || OD_IO.stream.dataLength < mappedLength + || OD_IO.stream.dataOrig == NULL) { *erroneousMap = map; return CO_ERROR_NO; } /* write locations to OD variable data bytes into PDO map pointers */ #ifdef CO_BIG_ENDIAN - if((OD_IO.stream.attribute & ODA_MB) != 0) { - uint8_t *odDataPointer = OD_IO.stream.dataOrig - + OD_IO.stream.dataLength - 1; + if ((OD_IO.stream.attribute & ODA_MB) != 0) { + uint8_t* odDataPointer = OD_IO.stream.dataOrig + OD_IO.stream.dataLength - 1; for (uint8_t j = pdoDataStart; j < pdoDataLength; j++) { PDO->mapPointer[j] = odDataPointer--; } - } - else + } else #endif { - uint8_t *odDataPointer = OD_IO.stream.dataOrig; + uint8_t* odDataPointer = OD_IO.stream.dataOrig; for (uint8_t j = pdoDataStart; j < pdoDataLength; j++) { PDO->mapPointer[j] = odDataPointer++; } @@ -383,11 +358,8 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, /* get TPDO request flag byte from extension */ #if OD_FLAGS_PDO_SIZE > 0 - if (!isRPDO && subIndex < (OD_FLAGS_PDO_SIZE * 8) - && entry->extension != NULL - ) { - PDO->flagPDObyte[pdoDataStart] = - &entry->extension->flagsPDO[subIndex >> 3]; + if (!isRPDO && subIndex < (OD_FLAGS_PDO_SIZE * 8) && entry->extension != NULL) { + PDO->flagPDObyte[pdoDataStart] = &entry->extension->flagsPDO[subIndex >> 3]; PDO->flagPDObitmask[pdoDataStart] = 1 << (subIndex & 0x07); } #endif @@ -399,22 +371,20 @@ static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t *PDO, #endif /* ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 */ - -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for reading OD object "PDO communication parameter" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead) -{ +static ODR_t +OD_read_PDO_commParam(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { ODR_t returnCode = OD_readOriginal(stream, buf, count, countRead); /* When reading COB_ID, add Node-Id to the read value, if necessary */ if ((returnCode == ODR_OK) && (stream->subIndex == 1U) && (*countRead == 4U)) { /* Only common part of the CO_RPDO_t or CO_TPDO_t will be used */ - CO_PDO_common_t *PDO = stream->object; + CO_PDO_common_t* PDO = stream->object; uint32_t COB_ID = CO_getUint32(buf); uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); @@ -424,7 +394,9 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, } /* If PDO is not valid, set bit 31 */ - if (!PDO->valid) { COB_ID |= 0x80000000U; } + if (!PDO->valid) { + COB_ID |= 0x80000000U; + } (void)CO_setUint32(buf, COB_ID); } @@ -433,11 +405,10 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ - /******************************************************************************* * R P D O ******************************************************************************/ -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 /* * @defgroup CO_PDO_receiveErrors_t States for RPDO->receiveError indicates received RPDOs with wrong length. * @{ @@ -449,6 +420,7 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, #define CO_RPDO_RX_OK 11U /* Correct RPDO received, not acknowledged */ #define CO_RPDO_RX_SHORT 12U /* Too short RPDO received, not acknowledged */ #define CO_RPDO_RX_LONG 13U /* Too long RPDO received, not acknowledged */ + /** @} */ /* CO_PDO_receiveErrors_t */ /* @@ -460,29 +432,31 @@ static ODR_t OD_read_PDO_commParam(OD_stream_t *stream, void *buf, * If new message arrives and previous message wasn't processed yet, then * previous message will be lost and overwritten by the new message. */ -static void CO_PDO_receive(void *object, void *msg) { - CO_RPDO_t *RPDO = object; - CO_PDO_common_t *PDO = &RPDO->PDO_common; +static void +CO_PDO_receive(void* object, void* msg) { + CO_RPDO_t* RPDO = object; + CO_PDO_common_t* PDO = &RPDO->PDO_common; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); uint8_t err = RPDO->receiveError; if (PDO->valid) { if (DLC >= PDO->dataLength) { /* indicate errors in PDO length */ if (DLC == PDO->dataLength) { - if (err == CO_RPDO_RX_ACK_ERROR) { err = CO_RPDO_RX_OK; } - } - else { - if (err == CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_LONG; } + if (err == CO_RPDO_RX_ACK_ERROR) { + err = CO_RPDO_RX_OK; + } + } else { + if (err == CO_RPDO_RX_ACK_NO_ERROR) { + err = CO_RPDO_RX_LONG; + } } /* Determine, to which of the two rx buffers copy the message. */ uint8_t bufNo = 0; -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - if (RPDO->synchronous && (RPDO->SYNC != NULL) - && RPDO->SYNC->CANrxToggle - ) { +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 + if (RPDO->synchronous && (RPDO->SYNC != NULL) && RPDO->SYNC->CANrxToggle) { bufNo = 1; } #endif @@ -491,132 +465,117 @@ static void CO_PDO_receive(void *object, void *msg) { (void)memcpy(RPDO->CANrxData[bufNo], data, CO_PDO_MAX_SIZE); CO_FLAG_SET(RPDO->CANrxNew[bufNo]); -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles * the RPDO. */ if (RPDO->pFunctSignalPre != NULL) { RPDO->pFunctSignalPre(RPDO->functSignalObjectPre); } #endif - } - else if (err == CO_RPDO_RX_ACK_NO_ERROR) { + } else if (err == CO_RPDO_RX_ACK_NO_ERROR) { err = CO_RPDO_RX_SHORT; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } RPDO->receiveError = err; } - -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "RPDO communication parameter" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ +static ODR_t +OD_write_14xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { /* "count" is also verified in *_init() function */ if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4U)) { return ODR_DEV_INCOMPAT; } - CO_RPDO_t *RPDO = stream->object; - CO_PDO_common_t *PDO = &RPDO->PDO_common; + CO_RPDO_t* RPDO = stream->object; + CO_PDO_common_t* PDO = &RPDO->PDO_common; uint8_t bufCopy[4]; - (void)memcpy((void *)bufCopy, (const void *)buf, count); + (void)memcpy((void*)bufCopy, (const void*)buf, count); switch (stream->subIndex) { - case 1: { /* COB-ID used by PDO */ - uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); - bool_t valid = (COB_ID & 0x80000000U) == 0U; + case 1: { /* COB-ID used by PDO */ + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + bool_t valid = (COB_ID & 0x80000000U) == 0U; - /* bits 11...29 must be zero, PDO must be disabled on change, + /* bits 11...29 must be zero, PDO must be disabled on change, * CAN_ID == 0 is not allowed, mapping must be configured before * enabling the PDO */ - if (((COB_ID & 0x3FFFF800U) != 0U) - || (valid && PDO->valid && (CAN_ID != PDO->configuredCanId)) - || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - || (valid && (PDO->mappedObjectsCount == 0U)) - ) { - return ODR_INVALID_VALUE; - } - - /* parameter changed? */ - if ((valid != PDO->valid) || (CAN_ID != PDO->configuredCanId)) { - /* if default CAN-ID is written, store to OD without Node-ID */ - if (CAN_ID == PDO->preDefinedCanId) { - (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80U); - } - if (!valid) { - CAN_ID = 0; + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && PDO->valid && (CAN_ID != PDO->configuredCanId)) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) || (valid && (PDO->mappedObjectsCount == 0U))) { + return ODR_INVALID_VALUE; } - CO_ReturnError_t ret = CO_CANrxBufferInit( - PDO->CANdev, - PDO->CANdevIdx, - CAN_ID, - 0x7FF, - false, - (void*)RPDO, - CO_PDO_receive); - - if (valid && (ret == CO_ERROR_NO)) { - PDO->valid = true; - PDO->configuredCanId = CAN_ID; - } - else { - PDO->valid = false; - CO_FLAG_CLEAR(RPDO->CANrxNew[0]); -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - CO_FLAG_CLEAR(RPDO->CANrxNew[1]); + /* parameter changed? */ + if ((valid != PDO->valid) || (CAN_ID != PDO->configuredCanId)) { + /* if default CAN-ID is written, store to OD without Node-ID */ + if (CAN_ID == PDO->preDefinedCanId) { + (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80U); + } + if (!valid) { + CAN_ID = 0; + } + + CO_ReturnError_t ret = CO_CANrxBufferInit(PDO->CANdev, PDO->CANdevIdx, CAN_ID, 0x7FF, false, + (void*)RPDO, CO_PDO_receive); + + if (valid && (ret == CO_ERROR_NO)) { + PDO->valid = true; + PDO->configuredCanId = CAN_ID; + } else { + PDO->valid = false; + CO_FLAG_CLEAR(RPDO->CANrxNew[0]); +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); #endif - if (ret != CO_ERROR_NO) { - return ODR_DEV_INCOMPAT; + if (ret != CO_ERROR_NO) { + return ODR_DEV_INCOMPAT; + } } } + break; } - break; - } - case 2: { /* transmission type */ - uint8_t transmissionType = CO_getUint8(buf); -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) - && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) - ) { - return ODR_INVALID_VALUE; - } + case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 + if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) + && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)) { + return ODR_INVALID_VALUE; + } - bool_t synchronous = transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240; - /* Remove old message from the second buffer. */ - if (RPDO->synchronous != synchronous) { - CO_FLAG_CLEAR(RPDO->CANrxNew[1]); - } + bool_t synchronous = transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240; + /* Remove old message from the second buffer. */ + if (RPDO->synchronous != synchronous) { + CO_FLAG_CLEAR(RPDO->CANrxNew[1]); + } - RPDO->synchronous = synchronous; + RPDO->synchronous = synchronous; #else - if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { - return ODR_INVALID_VALUE; - } + if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { + return ODR_INVALID_VALUE; + } #endif - break; - } + break; + } -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 - case 5: { /* event-timer */ - uint32_t eventTime = CO_getUint16(buf); - RPDO->timeoutTime_us = eventTime * 1000U; - RPDO->timeoutTimer = 0; - break; - } +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 + case 5: { /* event-timer */ + uint32_t eventTime = CO_getUint16(buf); + RPDO->timeoutTime_us = eventTime * 1000U; + RPDO->timeoutTimer = 0; + break; + } #endif - default: - /* MISRA C 2004 15.3 */ - break; + default: + /* MISRA C 2004 15.3 */ + break; } /* write value to the original location in the Object Dictionary */ @@ -624,28 +583,20 @@ static ODR_t OD_write_14xx(OD_stream_t *stream, const void *buf, } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ - -CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, - OD_t *OD, - CO_EM_t *em, -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - CO_SYNC_t *SYNC, +CO_ReturnError_t +CO_RPDO_init(CO_RPDO_t* RPDO, OD_t* OD, CO_EM_t* em, +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 + CO_SYNC_t* SYNC, #endif - uint16_t preDefinedCanId, - OD_entry_t *OD_14xx_RPDOCommPar, - OD_entry_t *OD_16xx_RPDOMapPar, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - uint32_t *errInfo) -{ - CO_PDO_common_t *PDO = &RPDO->PDO_common; + uint16_t preDefinedCanId, OD_entry_t* OD_14xx_RPDOCommPar, OD_entry_t* OD_16xx_RPDOMapPar, + CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, uint32_t* errInfo) { + CO_PDO_common_t* PDO = &RPDO->PDO_common; CO_ReturnError_t ret; ODR_t odRet; /* verify arguments */ - if ((RPDO == NULL) || (OD == NULL) || (em == NULL) || (OD_14xx_RPDOCommPar == NULL) - || (OD_16xx_RPDOMapPar == NULL) || (CANdevRx == NULL) - ) { + if ((RPDO == NULL) || (OD == NULL) || (em == NULL) || (OD_14xx_RPDOCommPar == NULL) || (OD_16xx_RPDOMapPar == NULL) + || (CANdevRx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -658,17 +609,11 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, /* Configure mapping parameters */ uint32_t erroneousMap = 0; - ret = PDO_initMapping(PDO, - OD, - OD_16xx_RPDOMapPar, - true, - errInfo, - &erroneousMap); + ret = PDO_initMapping(PDO, OD, OD_16xx_RPDOMapPar, true, errInfo, &erroneousMap); if (ret != CO_ERROR_NO) { return ret; } - /* Configure communication parameter - COB-ID */ uint32_t COB_ID = 0; odRet = OD_get_u32(OD_14xx_RPDOCommPar, 1, &COB_ID, true); @@ -683,12 +628,13 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); if (valid && ((PDO->mappedObjectsCount == 0U) || (CAN_ID == 0U))) { valid = false; - if (erroneousMap == 0U) { erroneousMap = 1; } + if (erroneousMap == 0U) { + erroneousMap = 1; + } } if (erroneousMap != 0U) { - CO_errorReport(PDO->em, - CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, + CO_errorReport(PDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, (erroneousMap != 1U) ? erroneousMap : COB_ID); } if (!valid) { @@ -700,23 +646,15 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, CAN_ID = preDefinedCanId; } - ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - CAN_ID, - 0x7FF, - false, - (void*)RPDO, - CO_PDO_receive); + ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, CAN_ID, 0x7FF, false, (void*)RPDO, CO_PDO_receive); if (ret != CO_ERROR_NO) { return ret; } PDO->valid = valid; - /* Configure communication parameter - transmission type */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 uint8_t transmissionType = (uint8_t)(CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO); odRet = OD_get_u8(OD_14xx_RPDOCommPar, 2, &transmissionType, true); if (odRet != ODR_OK) { @@ -730,17 +668,15 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, RPDO->synchronous = transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240; #endif - /* Configure communication parameter - event-timer (optional) */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 uint16_t eventTime = 0; (void)OD_get_u16(OD_14xx_RPDOCommPar, 5, &eventTime, true); RPDO->timeoutTime_us = (uint32_t)eventTime * 1000U; #endif - /* Configure OD extensions */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 PDO->isRPDO = true; PDO->OD = OD; PDO->CANdevIdx = CANdevRxIdx; @@ -759,12 +695,9 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, return CO_ERROR_NO; } - -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, - void *object, - void (*pFunctSignalPre)(void *object)) -{ +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_RPDO_initCallbackPre(CO_RPDO_t* RPDO, void* object, void (*pFunctSignalPre)(void* object)) { if (RPDO != NULL) { RPDO->functSignalObjectPre = object; RPDO->pFunctSignalPre = pFunctSignalPre; @@ -772,43 +705,36 @@ void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, } #endif - -void CO_RPDO_process(CO_RPDO_t *RPDO, -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 - uint32_t timeDifference_us, - uint32_t *timerNext_us, +void +CO_RPDO_process(CO_RPDO_t* RPDO, +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 + uint32_t timeDifference_us, uint32_t* timerNext_us, #endif - bool_t NMTisOperational, - bool_t syncWas) -{ - (void) syncWas; -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 - (void) timerNext_us; + bool_t NMTisOperational, bool_t syncWas) { + (void)syncWas; +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 + (void)timerNext_us; #endif - - CO_PDO_common_t *PDO = &RPDO->PDO_common; + + CO_PDO_common_t* PDO = &RPDO->PDO_common; if (PDO->valid && NMTisOperational -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 && (syncWas || !RPDO->synchronous) #endif ) { /* Verify errors in length of received RPDO CAN message */ if (RPDO->receiveError > CO_RPDO_RX_ACK) { bool_t setError = RPDO->receiveError != CO_RPDO_RX_OK; - uint16_t code = (RPDO->receiveError == CO_RPDO_RX_SHORT) - ? CO_EMC_PDO_LENGTH : CO_EMC_PDO_LENGTH_EXC; - CO_error(PDO->em, setError, CO_EM_RPDO_WRONG_LENGTH, - code, PDO->dataLength); - RPDO->receiveError = setError - ? CO_RPDO_RX_ACK_ERROR : CO_RPDO_RX_ACK_NO_ERROR; + uint16_t code = (RPDO->receiveError == CO_RPDO_RX_SHORT) ? CO_EMC_PDO_LENGTH : CO_EMC_PDO_LENGTH_EXC; + CO_error(PDO->em, setError, CO_EM_RPDO_WRONG_LENGTH, code, PDO->dataLength); + RPDO->receiveError = setError ? CO_RPDO_RX_ACK_ERROR : CO_RPDO_RX_ACK_NO_ERROR; } /* Determine, which of the two rx buffers contains relevant message. */ uint8_t bufNo = 0; -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - if (RPDO->synchronous && (RPDO->SYNC != NULL) - && !RPDO->SYNC->CANrxToggle) { +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 + if (RPDO->synchronous && (RPDO->SYNC != NULL) && !RPDO->SYNC->CANrxToggle) { bufNo = 1; } #endif @@ -817,19 +743,19 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t rpdoReceived = false; while (CO_FLAG_READ(RPDO->CANrxNew[bufNo])) { rpdoReceived = true; - uint8_t *dataRPDO = RPDO->CANrxData[bufNo]; + uint8_t* dataRPDO = RPDO->CANrxData[bufNo]; /* Clear the flag. If between the copy operation CANrxNew is set * by receive thread, then copy the latest data again. */ CO_FLAG_CLEAR(RPDO->CANrxNew[bufNo]); -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) != 0 for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { - OD_IO_t *OD_IO = &PDO->OD_IO[i]; + OD_IO_t* OD_IO = &PDO->OD_IO[i]; /* get mappedLength from temporary storage */ - OD_size_t *dataOffset = &OD_IO->stream.dataOffset; - uint8_t mappedLength = (uint8_t) (*dataOffset); + OD_size_t* dataOffset = &OD_IO->stream.dataOffset; + uint8_t mappedLength = (uint8_t)(*dataOffset); /* length of OD variable may be larger than mappedLength */ OD_size_t ODdataLength = OD_IO->stream.dataLength; @@ -839,35 +765,33 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, /* Prepare data for writing into OD variable. If mappedLength * is smaller than ODdataLength, then use auxiliary buffer */ uint8_t buf[CO_PDO_MAX_SIZE]; - uint8_t *dataOD; + uint8_t* dataOD; if (ODdataLength > mappedLength) { (void)memset(buf, 0, sizeof(buf)); (void)memcpy(buf, dataRPDO, mappedLength); dataOD = buf; - } - else { + } else { dataOD = dataRPDO; } /* swap multibyte data if big-endian */ - #ifdef CO_BIG_ENDIAN +#ifdef CO_BIG_ENDIAN if ((OD_IO->stream.attribute & ODA_MB) != 0) { - uint8_t *lo = dataOD; - uint8_t *hi = dataOD + ODdataLength - 1; + uint8_t* lo = dataOD; + uint8_t* hi = dataOD + ODdataLength - 1; while (lo < hi) { uint8_t swap = *lo; *lo++ = *hi; *hi-- = swap; } } - #endif +#endif /* Set stream.dataOffset to zero, perform OD_IO.write() * and store mappedLength back to stream.dataOffset */ *dataOffset = 0; OD_size_t countWritten; - OD_IO->write(&OD_IO->stream, dataOD, - ODdataLength, &countWritten); + OD_IO->write(&OD_IO->stream, dataOD, ODdataLength, &countWritten); *dataOffset = mappedLength; dataRPDO += mappedLength; @@ -882,189 +806,170 @@ void CO_RPDO_process(CO_RPDO_t *RPDO, } /* while (CO_FLAG_READ(RPDO->CANrxNew[bufNo])) */ /* verify RPDO timeout */ - (void) rpdoReceived; -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 + (void)rpdoReceived; +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 if (RPDO->timeoutTime_us > 0U) { if (rpdoReceived) { if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { - CO_errorReset(PDO->em, CO_EM_RPDO_TIME_OUT, - RPDO->timeoutTimer); + CO_errorReset(PDO->em, CO_EM_RPDO_TIME_OUT, RPDO->timeoutTimer); } /* enable monitoring */ RPDO->timeoutTimer = 1; - } - else if ((RPDO->timeoutTimer > 0U) - && (RPDO->timeoutTimer < RPDO->timeoutTime_us) - ) { + } else if ((RPDO->timeoutTimer > 0U) && (RPDO->timeoutTimer < RPDO->timeoutTime_us)) { RPDO->timeoutTimer += timeDifference_us; if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { - CO_errorReport(PDO->em, CO_EM_RPDO_TIME_OUT, - CO_EMC_RPDO_TIMEOUT, RPDO->timeoutTimer); + CO_errorReport(PDO->em, CO_EM_RPDO_TIME_OUT, CO_EMC_RPDO_TIMEOUT, RPDO->timeoutTimer); } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } - #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - if ((timerNext_us != NULL) - && (RPDO->timeoutTimer < RPDO->timeoutTime_us) - ) { +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 + if ((timerNext_us != NULL) && (RPDO->timeoutTimer < RPDO->timeoutTime_us)) { uint32_t diff = RPDO->timeoutTime_us - RPDO->timeoutTimer; if (*timerNext_us > diff) { *timerNext_us = diff; } } - #endif +#endif } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE */ - } /* if (PDO->valid && NMTisOperational) */ + } /* if (PDO->valid && NMTisOperational) */ else { /* not valid and operational, clear CAN receive flags and timeoutTimer*/ -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 if (!PDO->valid || !NMTisOperational) { CO_FLAG_CLEAR(RPDO->CANrxNew[0]); CO_FLAG_CLEAR(RPDO->CANrxNew[1]); - #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 RPDO->timeoutTimer = 0; - #endif +#endif } #else CO_FLAG_CLEAR(RPDO->CANrxNew[0]); - #if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 RPDO->timeoutTimer = 0; - #endif +#endif #endif } } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE */ - /******************************************************************************* * T P D O ******************************************************************************/ -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "TPDO communication parameter" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ +static ODR_t +OD_write_18xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { /* "count" is also verified in *_init() function */ if ((stream == NULL) || (buf == NULL) || (countWritten == NULL) || (count > 4U)) { return ODR_DEV_INCOMPAT; } - CO_TPDO_t *TPDO = stream->object; - CO_PDO_common_t *PDO = &TPDO->PDO_common; + CO_TPDO_t* TPDO = stream->object; + CO_PDO_common_t* PDO = &TPDO->PDO_common; uint8_t bufCopy[4]; - (void)memcpy((void *)bufCopy, (const void *)buf, count); + (void)memcpy((void*)bufCopy, (const void*)buf, count); switch (stream->subIndex) { - case 1: { /* COB-ID used by PDO */ - uint32_t COB_ID = CO_getUint32(buf); - uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); - bool_t valid = (COB_ID & 0x80000000U) == 0U; + case 1: { /* COB-ID used by PDO */ + uint32_t COB_ID = CO_getUint32(buf); + uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); + bool_t valid = (COB_ID & 0x80000000U) == 0U; - /* bits 11...29 must be zero, PDO must be disabled on change, + /* bits 11...29 must be zero, PDO must be disabled on change, * CAN_ID == 0 is not allowed, mapping must be configured before * enabling the PDO */ - if (((COB_ID & 0x3FFFF800U) != 0U) - || (valid && (PDO->valid && (CAN_ID != PDO->configuredCanId))) - || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - || (valid && (PDO->mappedObjectsCount == 0U)) - ) { - return ODR_INVALID_VALUE; - } - - /* parameter changed? */ - if ((valid != PDO->valid) || (CAN_ID != PDO->configuredCanId)) { - /* if default CAN-ID is written, store to OD without Node-ID */ - if (CAN_ID == PDO->preDefinedCanId) { - (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80U); - } - if (!valid) { - CAN_ID = 0; + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && (PDO->valid && (CAN_ID != PDO->configuredCanId))) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) || (valid && (PDO->mappedObjectsCount == 0U))) { + return ODR_INVALID_VALUE; } - CO_CANtx_t *CANtxBuff = CO_CANtxBufferInit( - PDO->CANdev, - PDO->CANdevIdx, - CAN_ID, - false, - PDO->dataLength, - TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); + /* parameter changed? */ + if ((valid != PDO->valid) || (CAN_ID != PDO->configuredCanId)) { + /* if default CAN-ID is written, store to OD without Node-ID */ + if (CAN_ID == PDO->preDefinedCanId) { + (void)CO_setUint32(bufCopy, COB_ID & 0xFFFFFF80U); + } + if (!valid) { + CAN_ID = 0; + } - if (CANtxBuff == NULL) { - return ODR_DEV_INCOMPAT; - } + CO_CANtx_t* CANtxBuff = CO_CANtxBufferInit( + PDO->CANdev, PDO->CANdevIdx, CAN_ID, false, PDO->dataLength, + TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); - TPDO->CANtxBuff = CANtxBuff; - PDO->valid = valid; - PDO->configuredCanId = CAN_ID; - } - break; - } + if (CANtxBuff == NULL) { + return ODR_DEV_INCOMPAT; + } - case 2: { /* transmission type */ - uint8_t transmissionType = CO_getUint8(buf); -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) - && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) - ) { - return ODR_INVALID_VALUE; + TPDO->CANtxBuff = CANtxBuff; + PDO->valid = valid; + PDO->configuredCanId = CAN_ID; + } + break; } - TPDO->CANtxBuff->syncFlag = - transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240; - TPDO->syncCounter = 255; + + case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 + if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) + && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)) { + return ODR_INVALID_VALUE; + } + TPDO->CANtxBuff->syncFlag = transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240; + TPDO->syncCounter = 255; #else - if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { - return ODR_INVALID_VALUE; - } + if (transmissionType < CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { + return ODR_INVALID_VALUE; + } #endif - TPDO->transmissionType = transmissionType; - TPDO->sendRequest = true; -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 - TPDO->inhibitTimer = 0; - TPDO->eventTimer = 0; + TPDO->transmissionType = transmissionType; + TPDO->sendRequest = true; +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 + TPDO->inhibitTimer = 0; + TPDO->eventTimer = 0; #endif - break; - } + break; + } -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 - case 3: { /* inhibit time */ - if (PDO->valid) { - return ODR_INVALID_VALUE; +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 + case 3: { /* inhibit time */ + if (PDO->valid) { + return ODR_INVALID_VALUE; + } + uint32_t inhibitTime = CO_getUint16(buf); + TPDO->inhibitTime_us = inhibitTime * 100U; + TPDO->inhibitTimer = 0; + break; } - uint32_t inhibitTime = CO_getUint16(buf); - TPDO->inhibitTime_us = inhibitTime * 100U; - TPDO->inhibitTimer = 0; - break; - } - case 5: { /* event-timer */ - uint32_t eventTime = CO_getUint16(buf); - TPDO->eventTime_us = eventTime * 1000U; - TPDO->eventTimer = 0; - break; - } + case 5: { /* event-timer */ + uint32_t eventTime = CO_getUint16(buf); + TPDO->eventTime_us = eventTime * 1000U; + TPDO->eventTimer = 0; + break; + } #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - case 6: { /* SYNC start value */ - uint8_t syncStartValue = CO_getUint8(buf); +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 + case 6: { /* SYNC start value */ + uint8_t syncStartValue = CO_getUint8(buf); - if (PDO->valid || (syncStartValue > 240U)) { - return ODR_INVALID_VALUE; + if (PDO->valid || (syncStartValue > 240U)) { + return ODR_INVALID_VALUE; + } + TPDO->syncStartValue = syncStartValue; + break; } - TPDO->syncStartValue = syncStartValue; - break; - } #endif - default: - /* MISRA C 2004 15.3 */ - break; + default: + /* MISRA C 2004 15.3 */ + break; } /* write value to the original location in the Object Dictionary */ @@ -1072,27 +977,19 @@ static ODR_t OD_write_18xx(OD_stream_t *stream, const void *buf, } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ - -CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, - OD_t *OD, - CO_EM_t *em, -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 - CO_SYNC_t *SYNC, +CO_ReturnError_t +CO_TPDO_init(CO_TPDO_t* TPDO, OD_t* OD, CO_EM_t* em, +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 + CO_SYNC_t* SYNC, #endif - uint16_t preDefinedCanId, - OD_entry_t *OD_18xx_TPDOCommPar, - OD_entry_t *OD_1Axx_TPDOMapPar, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint32_t *errInfo) -{ - CO_PDO_common_t *PDO = &TPDO->PDO_common; + uint16_t preDefinedCanId, OD_entry_t* OD_18xx_TPDOCommPar, OD_entry_t* OD_1Axx_TPDOMapPar, + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, uint32_t* errInfo) { + CO_PDO_common_t* PDO = &TPDO->PDO_common; ODR_t odRet; /* verify arguments */ - if ((TPDO == NULL) || (OD == NULL) || (em == NULL) || (OD_18xx_TPDOCommPar == NULL) - || (OD_1Axx_TPDOMapPar == NULL) || (CANdevTx == NULL) - ) { + if ((TPDO == NULL) || (OD == NULL) || (em == NULL) || (OD_18xx_TPDOCommPar == NULL) || (OD_1Axx_TPDOMapPar == NULL) + || (CANdevTx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -1105,17 +1002,11 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, /* Configure mapping parameters */ uint32_t erroneousMap = 0; - CO_ReturnError_t ret = PDO_initMapping(PDO, - OD, - OD_1Axx_TPDOMapPar, - false, - errInfo, - &erroneousMap); + CO_ReturnError_t ret = PDO_initMapping(PDO, OD, OD_1Axx_TPDOMapPar, false, errInfo, &erroneousMap); if (ret != CO_ERROR_NO) { return ret; } - /* Configure communication parameter - transmission type */ uint8_t transmissionType = (uint8_t)(CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO); odRet = OD_get_u8(OD_18xx_TPDOCommPar, 2, &transmissionType, true); @@ -1126,7 +1017,7 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, return CO_ERROR_OD_PARAMETERS; } if ((transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 && (transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) #endif ) { @@ -1149,12 +1040,13 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); if (valid && ((PDO->mappedObjectsCount == 0U) || (CAN_ID == 0U))) { valid = false; - if (erroneousMap == 0U) { erroneousMap = 1; } + if (erroneousMap == 0U) { + erroneousMap = 1; + } } if (erroneousMap != 0U) { - CO_errorReport(PDO->em, - CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, + CO_errorReport(PDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, (erroneousMap != 1U) ? erroneousMap : COB_ID); } if (!valid) { @@ -1166,13 +1058,8 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, CAN_ID = preDefinedCanId; } - TPDO->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, - CANdevTxIdx, - CAN_ID, - false, - PDO->dataLength, - TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); + TPDO->CANtxBuff = CO_CANtxBufferInit(CANdevTx, CANdevTxIdx, CAN_ID, false, PDO->dataLength, + TPDO->transmissionType <= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240); if (TPDO->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -1180,9 +1067,8 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, PDO->valid = valid; - /* Configure communication parameter - inhibit time and event-timer (opt) */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 uint16_t inhibitTime = 0; uint16_t eventTime = 0; (void)OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); @@ -1191,18 +1077,16 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, TPDO->eventTime_us = (uint32_t)eventTime * 1000U; #endif - /* Configure communication parameter - SYNC start value (optional) */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncStartValue = 0; (void)OD_get_u8(OD_18xx_TPDOCommPar, 6, &TPDO->syncStartValue, true); TPDO->SYNC = SYNC; TPDO->syncCounter = 255; #endif - /* Configure OD extensions */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 PDO->isRPDO = false; PDO->OD = OD; PDO->CANdevIdx = CANdevTxIdx; @@ -1221,7 +1105,6 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, return CO_ERROR_NO; } - /* * Send TPDO message. * @@ -1232,22 +1115,22 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, * * @return Same as CO_CANsend(). */ -static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { - CO_PDO_common_t *PDO = &TPDO->PDO_common; - uint8_t *dataTPDO = &TPDO->CANtxBuff->data[0]; +static CO_ReturnError_t +CO_TPDOsend(CO_TPDO_t* TPDO) { + CO_PDO_common_t* PDO = &TPDO->PDO_common; + uint8_t* dataTPDO = &TPDO->CANtxBuff->data[0]; #if OD_FLAGS_PDO_SIZE > 0 - bool_t eventDriven = - ((TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) - || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)); + bool_t eventDriven = ((TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) + || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)); #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) != 0 for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { - OD_IO_t *OD_IO = &PDO->OD_IO[i]; - OD_stream_t *stream = &OD_IO->stream; + OD_IO_t* OD_IO = &PDO->OD_IO[i]; + OD_stream_t* stream = &OD_IO->stream; /* get mappedLength from temporary storage */ - uint8_t mappedLength = (uint8_t) stream->dataOffset; + uint8_t mappedLength = (uint8_t)stream->dataOffset; /* length of OD variable may be larger than mappedLength */ OD_size_t ODdataLength = stream->dataLength; @@ -1256,34 +1139,33 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { } /* If mappedLength is smaller than ODdataLength, use auxiliary buffer */ uint8_t buf[CO_PDO_MAX_SIZE]; - uint8_t *dataTPDOCopy; + uint8_t* dataTPDOCopy; if (ODdataLength > mappedLength) { (void)memset(buf, 0, sizeof(buf)); dataTPDOCopy = buf; - } - else { + } else { dataTPDOCopy = dataTPDO; } /* Set stream.dataOffset to zero, perform OD_IO.read() * and store mappedLength back to stream.dataOffset */ - stream->dataOffset= 0; + stream->dataOffset = 0; OD_size_t countRd; OD_IO->read(stream, dataTPDOCopy, ODdataLength, &countRd); stream->dataOffset = mappedLength; /* swap multibyte data if big-endian */ - #ifdef CO_BIG_ENDIAN +#ifdef CO_BIG_ENDIAN if ((stream->attribute & ODA_MB) != 0) { - uint8_t *lo = dataTPDOCopy; - uint8_t *hi = dataTPDOCopy + ODdataLength - 1; + uint8_t* lo = dataTPDOCopy; + uint8_t* hi = dataTPDOCopy + ODdataLength - 1; while (lo < hi) { uint8_t swap = *lo; *lo++ = *hi; *hi-- = swap; } } - #endif +#endif /* If auxiliary buffer, copy it to the TPDO */ if (ODdataLength > mappedLength) { @@ -1291,12 +1173,12 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { } /* In event driven TPDO indicate transmission of OD variable */ - #if OD_FLAGS_PDO_SIZE > 0 - uint8_t *flagPDObyte = PDO->flagPDObyte[i]; +#if OD_FLAGS_PDO_SIZE > 0 + uint8_t* flagPDObyte = PDO->flagPDObyte[i]; if ((flagPDObyte != NULL) && eventDriven) { - *flagPDObyte |= PDO->flagPDObitmask[i]; + *flagPDObyte |= PDO->flagPDObitmask[i]; } - #endif +#endif dataTPDO += mappedLength; } @@ -1305,66 +1187,61 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO) { dataTPDO[i] = *PDO->mapPointer[i]; /* In event driven TPDO indicate transmission of OD variable */ - #if OD_FLAGS_PDO_SIZE > 0 - uint8_t *flagPDObyte = PDO->flagPDObyte[i]; +#if OD_FLAGS_PDO_SIZE > 0 + uint8_t* flagPDObyte = PDO->flagPDObyte[i]; if (flagPDObyte != NULL && eventDriven) { - *flagPDObyte |= PDO->flagPDObitmask[i]; + *flagPDObyte |= PDO->flagPDObitmask[i]; } - #endif +#endif } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ TPDO->sendRequest = false; -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->eventTimer = TPDO->eventTime_us; TPDO->inhibitTimer = TPDO->inhibitTime_us; #endif return CO_CANsend(PDO->CANdev, TPDO->CANtxBuff); } - -void CO_TPDO_process(CO_TPDO_t *TPDO, -#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN - uint32_t timeDifference_us, - uint32_t *timerNext_us, +void +CO_TPDO_process(CO_TPDO_t* TPDO, +#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN + uint32_t timeDifference_us, uint32_t* timerNext_us, #endif - bool_t NMTisOperational, - bool_t syncWas) -{ - CO_PDO_common_t *PDO = &TPDO->PDO_common; -#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE)) != 0 - (void) timerNext_us; + bool_t NMTisOperational, bool_t syncWas) { + CO_PDO_common_t* PDO = &TPDO->PDO_common; +#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE)) != 0 + (void)timerNext_us; #endif - (void) syncWas; + (void)syncWas; if (PDO->valid && NMTisOperational) { /* check for event timer or application event */ -#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || (OD_FLAGS_PDO_SIZE > 0) +#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || (OD_FLAGS_PDO_SIZE > 0) if ((TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) - || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) - ) { + || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)) { /* event timer */ - #if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 if (TPDO->eventTime_us != 0U) { - TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) - ? (TPDO->eventTimer - timeDifference_us) : 0U; + TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) ? (TPDO->eventTimer - timeDifference_us) : 0U; if (TPDO->eventTimer == 0U) { TPDO->sendRequest = true; } - #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 if ((timerNext_us != NULL) && (*timerNext_us > TPDO->eventTimer)) { /* Schedule for next event time */ *timerNext_us = TPDO->eventTimer; } - #endif +#endif } - #endif +#endif /* check for any OD_requestTPDO() */ - #if OD_FLAGS_PDO_SIZE > 0 +#if OD_FLAGS_PDO_SIZE > 0 if (!TPDO->sendRequest) { for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { - uint8_t *flagPDObyte = PDO->flagPDObyte[i]; + uint8_t* flagPDObyte = PDO->flagPDObyte[i]; if (flagPDObyte != NULL) { if ((*flagPDObyte & PDO->flagPDObitmask[i]) == 0U) { TPDO->sendRequest = true; @@ -1373,30 +1250,27 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, } } } - #endif +#endif } #endif /*((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE)||(OD_FLAGS_PDO_SIZE>0)*/ - /* Send PDO by application request or by Event timer */ if (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 - TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) - ? (TPDO->inhibitTimer - timeDifference_us) : 0U; +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 + TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) + : 0U; /* send TPDO */ if (TPDO->sendRequest && (TPDO->inhibitTimer == 0U)) { (void)CO_TPDOsend(TPDO); } - #if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - if (TPDO->sendRequest - && (timerNext_us != NULL) && (*timerNext_us > TPDO->inhibitTimer) - ) { +#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 + if (TPDO->sendRequest && (timerNext_us != NULL) && (*timerNext_us > TPDO->inhibitTimer)) { /* Schedule for just beyond inhibit window */ *timerNext_us = TPDO->inhibitTimer; } - #endif +#endif #else if (TPDO->sendRequest) { (void)CO_TPDOsend(TPDO); @@ -1405,23 +1279,22 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, } /* if (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) */ /* Synchronous PDOs */ -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 else if ((TPDO->SYNC != NULL) && syncWas) { /* send synchronous acyclic TPDO */ if (TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { - if (TPDO->sendRequest) { (void)CO_TPDOsend(TPDO); } + if (TPDO->sendRequest) { + (void)CO_TPDOsend(TPDO); + } } /* send synchronous cyclic TPDO */ else { /* is the start of synchronous TPDO transmission */ if (TPDO->syncCounter == 255U) { - if ((TPDO->SYNC->counterOverflowValue != 0U) - && (TPDO->syncStartValue != 0U) - ) { + if ((TPDO->SYNC->counterOverflowValue != 0U) && (TPDO->syncStartValue != 0U)) { /* syncStartValue is in use */ TPDO->syncCounter = 254; - } - else { + } else { /* Send first TPDO somewhere in the middle */ TPDO->syncCounter = (TPDO->transmissionType / 2U) + 1U; } @@ -1438,22 +1311,22 @@ void CO_TPDO_process(CO_TPDO_t *TPDO, else if (--TPDO->syncCounter == 0U) { TPDO->syncCounter = TPDO->transmissionType; (void)CO_TPDOsend(TPDO); + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } - } /* else if (TPDO->SYNC && syncWas) */ - else { /* MISRA C 2004 14.10 */ } + } /* else if (TPDO->SYNC && syncWas) */ + else { /* MISRA C 2004 14.10 */ + } #endif - } - else { + } else { /* Not operational or valid, reset triggers */ TPDO->sendRequest = true; -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->inhibitTimer = 0; TPDO->eventTimer = 0; #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncCounter = 255; #endif } diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index d5022a13..8cad7b58 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -21,25 +21,25 @@ #include "301/CO_SDOclient.h" -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 /* verify configuration */ #if CO_CONFIG_SDO_CLI_BUFFER_SIZE < 7U - #error CO_CONFIG_SDO_CLI_BUFFER_SIZE must be set to 7 or more. +#error CO_CONFIG_SDO_CLI_BUFFER_SIZE must be set to 7 or more. #endif -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) == 0 - #error CO_CONFIG_FIFO_ENABLE must be enabled. +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ENABLE) == 0 +#error CO_CONFIG_FIFO_ENABLE must be enabled. +#endif +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) == 0 +#error CO_CONFIG_SDO_CLI_SEGMENTED must be enabled. +#endif +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ALT_READ) == 0 +#error CO_CONFIG_FIFO_ALT_READ must be enabled. +#endif +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_CRC16_CCITT) == 0 +#error CO_CONFIG_FIFO_CRC16_CCITT must be enabled. #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 - #error CO_CONFIG_SDO_CLI_SEGMENTED must be enabled. - #endif - #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) == 0 - #error CO_CONFIG_FIFO_ALT_READ must be enabled. - #endif - #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) == 0 - #error CO_CONFIG_FIFO_CRC16_CCITT must be enabled. - #endif #endif /* default 'protocol switch threshold' size for block transfer */ @@ -47,7 +47,6 @@ #define CO_CONFIG_SDO_CLI_PST 21U #endif - /* * Read received message from CAN module. * @@ -55,27 +54,25 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_SDOclient_receive(void *object, void *msg) { - CO_SDOclient_t *SDO_C = (CO_SDOclient_t*)object; +static void +CO_SDOclient_receive(void* object, void* msg) { + CO_SDOclient_t* SDO_C = (CO_SDOclient_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); /* Ignore messages in idle state and messages with wrong length. Ignore * message also if previous message was not processed yet and not abort */ - if ((SDO_C->state != CO_SDO_ST_IDLE) && (DLC == 8U) - && (!CO_FLAG_READ(SDO_C->CANrxNew) || (data[0] == 0x80U)) - ) { -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 + if ((SDO_C->state != CO_SDO_ST_IDLE) && (DLC == 8U) && (!CO_FLAG_READ(SDO_C->CANrxNew) || (data[0] == 0x80U))) { +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 bool_t state_not_upload_blk_sublock_sreq = (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ); bool_t state_not_upload_blk_sublock_crsp = (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP); if ((data[0] == 0x80U) /* abort from server */ - || (state_not_upload_blk_sublock_sreq && state_not_upload_blk_sublock_crsp) - ) { + || (state_not_upload_blk_sublock_sreq && state_not_upload_blk_sublock_crsp)) { #endif /* copy data and set 'new message' flag */ - (void)memcpy((void *)&SDO_C->CANrxData[0], (const void *)&data[0], 8); + (void)memcpy((void*)&SDO_C->CANrxData[0], (const void*)&data[0], 8); CO_FLAG_SET(SDO_C->CANrxNew); -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles * SDO client processing. */ if (SDO_C->pFunctSignal != NULL) { @@ -83,9 +80,8 @@ static void CO_SDOclient_receive(void *object, void *msg) { } #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - } - else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 + } else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { /* block upload, copy data directly */ CO_SDO_state_t state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; uint8_t seqno = data[0] & 0x7FU; @@ -93,26 +89,20 @@ static void CO_SDOclient_receive(void *object, void *msg) { SDO_C->block_timeoutTimer = 0; /* verify if sequence number is correct */ - if ((seqno <= SDO_C->block_blksize) - && (seqno == (SDO_C->block_seqno + 1U)) - ) { + if ((seqno <= SDO_C->block_blksize) && (seqno == (SDO_C->block_seqno + 1U))) { SDO_C->block_seqno = seqno; /* is this the last segment? */ if ((data[0] & 0x80U) != 0U) { /* copy data to temporary buffer, because we don't know the * number of bytes not containing data */ - (void)memcpy((void *)&SDO_C->block_dataUploadLast[0], - (const void *)&data[1], 7); + (void)memcpy((void*)&SDO_C->block_dataUploadLast[0], (const void*)&data[1], 7); SDO_C->finished = true; state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; - } - else { + } else { /* Copy data. There is always enough space in fifo buffer, * because block_blksize was calculated before */ - (void)CO_fifo_write(&SDO_C->bufFifo, - &data[1], - 7, &SDO_C->block_crc); + (void)CO_fifo_write(&SDO_C->bufFifo, &data[1], 7, &SDO_C->block_crc); SDO_C->sizeTran += 7U; /* all segments in sub-block has been transferred */ if (seqno == SDO_C->block_blksize) { @@ -127,19 +117,14 @@ static void CO_SDOclient_receive(void *object, void *msg) { state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; #ifdef CO_DEBUG_SDO_CLIENT char msg[80]; - sprintf(msg, - "sub-block, rx WRONG: sequno=%02X, previous=%02X", - seqno, SDO_C->block_seqno); + sprintf(msg, "sub-block, rx WRONG: sequno=%02X, previous=%02X", seqno, SDO_C->block_seqno); CO_DEBUG_SDO_CLIENT(msg); #endif - } - else { + } else { /* MISRA C 2004 14.10 */ #ifdef CO_DEBUG_SDO_CLIENT char msg[80]; - sprintf(msg, - "sub-block, rx ignored: sequno=%02X, expected=%02X", - seqno, SDO_C->block_seqno + 1); + sprintf(msg, "sub-block, rx ignored: sequno=%02X, expected=%02X", seqno, SDO_C->block_seqno + 1); CO_DEBUG_SDO_CLIENT(msg); #endif } @@ -150,7 +135,7 @@ static void CO_SDOclient_receive(void *object, void *msg) { * barrier here with CO_FLAG_CLEAR() call. */ CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->state = state; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles * SDO client processing. */ if (SDO_C->pFunctSignal != NULL) { @@ -158,34 +143,30 @@ static void CO_SDOclient_receive(void *object, void *msg) { } #endif } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } - + #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ } } - -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object _SDO client parameter_ * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ +static ODR_t +OD_write_1280(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { /* "count" is already verified in *_init() function */ if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_SDOclient_t *SDO_C = (CO_SDOclient_t *)stream->object; + CO_SDOclient_t* SDO_C = (CO_SDOclient_t*)stream->object; switch (stream->subIndex) { - case 0: /* Highest sub-index supported */ - return ODR_READONLY; - break; + case 0: /* Highest sub-index supported */ return ODR_READONLY; break; case 1: { /* COB-ID client -> server */ uint32_t COB_ID = CO_getUint32(buf); @@ -194,16 +175,11 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, bool_t valid = (COB_ID & 0x80000000U) == 0U; /* SDO client must not be valid when changing COB_ID */ - if (((COB_ID & 0x3FFFF800U) != 0U) - || (valid && SDO_C->valid && (CAN_ID != CAN_ID_cur)) - || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - ) { + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && SDO_C->valid && (CAN_ID != CAN_ID_cur)) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID))) { return ODR_INVALID_VALUE; } - (void)CO_SDOclient_setup(SDO_C, - COB_ID, - SDO_C->COB_IDServerToClient, - SDO_C->nodeIDOfTheSDOServer); + (void)CO_SDOclient_setup(SDO_C, COB_ID, SDO_C->COB_IDServerToClient, SDO_C->nodeIDOfTheSDOServer); break; } @@ -214,16 +190,11 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, bool_t valid = (COB_ID & 0x80000000U) == 0U; /* SDO client must not be valid when changing COB_ID */ - if (((COB_ID & 0x3FFFF800U) != 0U) - || (valid && SDO_C->valid && (CAN_ID != CAN_ID_cur)) - || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - ) { + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && SDO_C->valid && (CAN_ID != CAN_ID_cur)) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID))) { return ODR_INVALID_VALUE; } - (void)CO_SDOclient_setup(SDO_C, - SDO_C->COB_IDClientToServer, - COB_ID, - SDO_C->nodeIDOfTheSDOServer); + (void)CO_SDOclient_setup(SDO_C, SDO_C->COB_IDClientToServer, COB_ID, SDO_C->nodeIDOfTheSDOServer); break; } @@ -236,9 +207,7 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, break; } - default: - return ODR_SUB_NOT_EXIST; - break; + default: return ODR_SUB_NOT_EXIST; break; } /* write value to the original location in the Object Dictionary */ @@ -246,30 +215,21 @@ static ODR_t OD_write_1280(OD_stream_t *stream, const void *buf, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC */ - -CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, - OD_t *OD, - OD_entry_t *OD_1280_SDOcliPar, - uint8_t nodeId, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint32_t *errInfo) -{ +CO_ReturnError_t +CO_SDOclient_init(CO_SDOclient_t* SDO_C, OD_t* OD, OD_entry_t* OD_1280_SDOcliPar, uint8_t nodeId, + CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, + uint32_t* errInfo) { bool_t index_SDOcliPar_min = (OD_getIndex(OD_1280_SDOcliPar) < (uint16_t)(OD_H1280_SDO_CLIENT_1_PARAM)); bool_t index_SDOcliPar_max = (OD_getIndex(OD_1280_SDOcliPar) > ((uint16_t)(OD_H1280_SDO_CLIENT_1_PARAM) + 0x7FU)); /* verify arguments */ - if ((SDO_C == NULL) || (OD_1280_SDOcliPar == NULL) - || index_SDOcliPar_min || index_SDOcliPar_max - || (CANdevRx==NULL) || (CANdevTx==NULL) - ) { + if ((SDO_C == NULL) || (OD_1280_SDOcliPar == NULL) || index_SDOcliPar_min || index_SDOcliPar_max + || (CANdevRx == NULL) || (CANdevTx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } /* Configure object variables */ -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 SDO_C->OD = OD; SDO_C->nodeId = nodeId; #endif @@ -277,14 +237,13 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, SDO_C->CANdevRxIdx = CANdevRxIdx; SDO_C->CANdevTx = CANdevTx; SDO_C->CANdevTxIdx = CANdevTxIdx; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 SDO_C->pFunctSignal = NULL; SDO_C->functSignalObject = NULL; #endif /* prepare circular fifo buffer */ - CO_fifo_init(&SDO_C->bufFifo, SDO_C->buf, - CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U); + CO_fifo_init(&SDO_C->bufFifo, SDO_C->buf, CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U); /* Get parameters from Object Dictionary (initial values) */ uint8_t maxSubIndex, nodeIDOfTheSDOServer; @@ -294,21 +253,18 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, ODR_t odRet2 = OD_get_u32(OD_1280_SDOcliPar, 2, &COB_IDServerToClient, true); ODR_t odRet3 = OD_get_u8(OD_1280_SDOcliPar, 3, &nodeIDOfTheSDOServer, true); - if ((odRet0 != ODR_OK) || (maxSubIndex != 3U) - || (odRet1 != ODR_OK) || (odRet2 != ODR_OK) || (odRet3 != ODR_OK) - ) { + if ((odRet0 != ODR_OK) || (maxSubIndex != 3U) || (odRet1 != ODR_OK) || (odRet2 != ODR_OK) || (odRet3 != ODR_OK)) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1280_SDOcliPar); } return CO_ERROR_OD_PARAMETERS; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SDO_C->OD_1280_extension.object = SDO_C; SDO_C->OD_1280_extension.read = OD_readOriginal; SDO_C->OD_1280_extension.write = OD_write_1280; - ODR_t odRetE = OD_extension_init(OD_1280_SDOcliPar, - &SDO_C->OD_1280_extension); + ODR_t odRetE = OD_extension_init(OD_1280_SDOcliPar, &SDO_C->OD_1280_extension); if (odRetE != ODR_OK) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1280_SDOcliPar); @@ -321,9 +277,7 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, SDO_C->COB_IDServerToClient = 0; #endif - CO_SDO_return_t cliSetupRet = CO_SDOclient_setup(SDO_C, - COB_IDClientToServer, - COB_IDServerToClient, + CO_SDO_return_t cliSetupRet = CO_SDOclient_setup(SDO_C, COB_IDClientToServer, COB_IDServerToClient, nodeIDOfTheSDOServer); if (cliSetupRet != CO_SDO_RT_ok_communicationEnd) { @@ -333,12 +287,9 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, return CO_ERROR_NO; } - -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, - void *object, - void (*pFunctSignal)(void *object)) -{ +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_SDOclient_initCallbackPre(CO_SDOclient_t* SDOclient, void* object, void (*pFunctSignal)(void* object)) { if (SDOclient != NULL) { SDOclient->functSignalObject = object; SDOclient->pFunctSignal = pFunctSignal; @@ -346,10 +297,11 @@ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, } #endif -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0) && defined CO_BIG_ENDIAN -static inline void reverseBytes(void *start, OD_size_t size) { - uint8_t *lo = (uint8_t *)start; - uint8_t *hi = (uint8_t *)start + size - 1; +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0) && defined CO_BIG_ENDIAN +static inline void +reverseBytes(void* start, OD_size_t size) { + uint8_t* lo = (uint8_t*)start; + uint8_t* hi = (uint8_t*)start + size - 1; uint8_t swap; while (lo < hi) { swap = *lo; @@ -359,12 +311,9 @@ static inline void reverseBytes(void *start, OD_size_t size) { } #endif - -CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient, - uint8_t nodeIDOfTheSDOServer) -{ +CO_SDO_return_t +CO_SDOclient_setup(CO_SDOclient_t* SDO_C, uint32_t COB_IDClientToServer, uint32_t COB_IDServerToClient, + uint8_t nodeIDOfTheSDOServer) { /* verify parameters */ if (SDO_C == NULL) { return CO_SDO_RT_wrongArguments; @@ -375,11 +324,10 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->nodeIDOfTheSDOServer = nodeIDOfTheSDOServer; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* proceed only, if parameters change */ if ((COB_IDClientToServer == SDO_C->COB_IDClientToServer) - && (COB_IDServerToClient == SDO_C->COB_IDServerToClient) - ) { + && (COB_IDServerToClient == SDO_C->COB_IDServerToClient)) { return CO_SDO_RT_ok_communicationEnd; } /* store variables */ @@ -388,38 +336,22 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, #endif /* verify valid bit */ - uint16_t CanIdC2S = ((COB_IDClientToServer & 0x80000000UL) == 0U) ? - (uint16_t)(COB_IDClientToServer & 0x7FFU) : 0U; - uint16_t CanIdS2C = ((COB_IDServerToClient & 0x80000000UL) == 0U) ? - (uint16_t)(COB_IDServerToClient & 0x7FFU) : 0U; + uint16_t CanIdC2S = ((COB_IDClientToServer & 0x80000000UL) == 0U) ? (uint16_t)(COB_IDClientToServer & 0x7FFU) : 0U; + uint16_t CanIdS2C = ((COB_IDServerToClient & 0x80000000UL) == 0U) ? (uint16_t)(COB_IDServerToClient & 0x7FFU) : 0U; if ((CanIdC2S != 0U) && (CanIdS2C != 0U)) { SDO_C->valid = true; - } - else { + } else { CanIdC2S = 0; CanIdS2C = 0; SDO_C->valid = false; } /* configure SDO client CAN reception */ - CO_ReturnError_t ret = CO_CANrxBufferInit( - SDO_C->CANdevRx, - SDO_C->CANdevRxIdx, - CanIdS2C, - 0x7FF, - false, - (void*)SDO_C, - CO_SDOclient_receive); + CO_ReturnError_t ret = CO_CANrxBufferInit(SDO_C->CANdevRx, SDO_C->CANdevRxIdx, CanIdS2C, 0x7FF, false, (void*)SDO_C, + CO_SDOclient_receive); /* configure SDO client CAN transmission */ - SDO_C->CANtxBuff = CO_CANtxBufferInit( - SDO_C->CANdevTx, - SDO_C->CANdevTxIdx, - CanIdC2S, - false, - 8, - false); - + SDO_C->CANtxBuff = CO_CANtxBufferInit(SDO_C->CANdevTx, SDO_C->CANdevTxIdx, CanIdC2S, false, 8, false); if ((ret != CO_ERROR_NO) || (SDO_C->CANtxBuff == NULL)) { SDO_C->valid = false; @@ -429,17 +361,12 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, return CO_SDO_RT_ok_communicationEnd; } - /****************************************************************************** * DOWNLOAD * ******************************************************************************/ -CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - size_t sizeIndicated, - uint16_t SDOtimeoutTime_ms, - bool_t blockEnable) -{ +CO_SDO_return_t +CO_SDOclientDownloadInitiate(CO_SDOclient_t* SDO_C, uint16_t index, uint8_t subIndex, size_t sizeIndicated, + uint16_t SDOtimeoutTime_ms, bool_t blockEnable) { /* verify parameters */ if ((SDO_C == NULL) || !SDO_C->valid) { return CO_SDO_RT_wrongArguments; @@ -455,24 +382,18 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, SDO_C->timeoutTimer = 0; CO_fifo_reset(&SDO_C->bufFifo); -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ - if ((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U) - && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId) - ) { + if ((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U) && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId)) { SDO_C->OD_IO.write = NULL; SDO_C->state = CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER; - } - else + } else #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - if (blockEnable && ((sizeIndicated == 0U) || - (sizeIndicated > (size_t)(CO_CONFIG_SDO_CLI_PST))) - ) { +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 + if (blockEnable && ((sizeIndicated == 0U) || (sizeIndicated > (size_t)(CO_CONFIG_SDO_CLI_PST)))) { SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ; - } - else + } else #endif { SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; @@ -483,27 +404,21 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, return CO_SDO_RT_ok_communicationEnd; } - -void CO_SDOclientDownloadInitSize(CO_SDOclient_t *SDO_C, - size_t sizeIndicated) -{ +void +CO_SDOclientDownloadInitSize(CO_SDOclient_t* SDO_C, size_t sizeIndicated) { if (SDO_C != NULL) { SDO_C->sizeInd = sizeIndicated; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ) - && (sizeIndicated > 0U) && (sizeIndicated <= (size_t)(CO_CONFIG_SDO_CLI_PST)) - ) { +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 + if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ) && (sizeIndicated > 0U) + && (sizeIndicated <= (size_t)(CO_CONFIG_SDO_CLI_PST))) { SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; } #endif } } - -size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, - const uint8_t *buf, - size_t count) -{ +size_t +CO_SDOclientDownloadBufWrite(CO_SDOclient_t* SDO_C, const uint8_t* buf, size_t count) { size_t ret = 0; if ((SDO_C != NULL) && (buf != NULL)) { ret = CO_fifo_write(&SDO_C->bufFifo, buf, count, NULL); @@ -511,16 +426,11 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, return ret; } - -CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - bool_t send_abort, - bool_t bufferPartial, - CO_SDO_abortCode_t *SDOabortCode, - size_t *sizeTransferred, - uint32_t *timerNext_us) -{ - (void)timerNext_us; (void) bufferPartial; /* may be unused */ +CO_SDO_return_t +CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t send_abort, bool_t bufferPartial, + CO_SDO_abortCode_t* SDOabortCode, size_t* sizeTransferred, uint32_t* timerNext_us) { + (void)timerNext_us; + (void)bufferPartial; /* may be unused */ CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; @@ -528,37 +438,32 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if ((SDO_C == NULL) || !SDO_C->valid) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_wrongArguments; - } - else if (SDO_C->state == CO_SDO_ST_IDLE) { + } else if (SDO_C->state == CO_SDO_ST_IDLE) { ret = CO_SDO_RT_ok_communicationEnd; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 /* Transfer data locally **************************************************/ else if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) && !send_abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.write == NULL) { ODR_t odRet; - odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, - &SDO_C->OD_IO, false); + odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, &SDO_C->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithClientAbort; - } - else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_RW) == 0U) { + } else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_RW) == 0U) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; ret = CO_SDO_RT_endedWithClientAbort; - } - else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_W) == 0U) { + } else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_W) == 0U) { abortCode = CO_SDO_AB_READONLY; ret = CO_SDO_RT_endedWithClientAbort; - } - else if (SDO_C->OD_IO.write == NULL) { + } else if (SDO_C->OD_IO.write == NULL) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } /* write data, in several passes if necessary */ if (SDO_C->OD_IO.write != NULL) { @@ -569,7 +474,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->sizeTran += count; /* error: no data */ - if ((count == 0U) || (count > CO_CONFIG_SDO_CLI_BUFFER_SIZE)){ + if ((count == 0U) || (count > CO_CONFIG_SDO_CLI_BUFFER_SIZE)) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; } @@ -580,9 +485,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, ret = CO_SDO_RT_endedWithClientAbort; } /* Verify sizeTran is too small in last segment of data */ - else if (!bufferPartial - && (SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd) - ) { + else if (!bufferPartial && (SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; } @@ -601,8 +504,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, * bytes to terminate (unicode) string. Shorten also OD data * size, (temporary, send info about EOF into OD_IO.write) */ if (((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) - && ((sizeInOd == 0U) || (SDO_C->sizeTran < sizeInOd)) - ) { + && ((sizeInOd == 0U) || (SDO_C->sizeTran < sizeInOd))) { buf[count] = 0; count++; SDO_C->sizeTran++; @@ -619,21 +521,19 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } /* Verify if size of data downloaded matches data size in OD. */ else if (SDO_C->sizeTran != sizeInOd) { - abortCode = (SDO_C->sizeTran > sizeInOd) ? - CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + abortCode = (SDO_C->sizeTran > sizeInOd) ? CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } if (abortCode == CO_SDO_AB_NONE) { OD_size_t countWritten = 0; /* write data to Object Dictionary */ CO_LOCK_OD(SDO_C->CANdevTx); - ODR_t odRet = SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, - (OD_size_t)count, &countWritten); + ODR_t odRet = SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, (OD_size_t)count, &countWritten); CO_UNLOCK_OD(SDO_C->CANdevTx); /* verify for errors in write */ @@ -659,8 +559,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, else { ret = CO_SDO_RT_ok_communicationEnd; } - } - else { + } else { ret = CO_SDO_RT_waitingLocalTransfer; } } @@ -669,12 +568,12 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (ret != CO_SDO_RT_waitingLocalTransfer) { SDO_C->state = CO_SDO_ST_IDLE; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Inform OS to call this function again without delay. */ else if (timerNext_us != NULL) { *timerNext_us = 0; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } #endif } #endif /* CO_CONFIG_SDO_CLI_LOCAL */ @@ -683,24 +582,21 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80U) { uint32_t code; - (void)memcpy((void *)(&code), (const void *)(&SDO_C->CANrxData[4]), sizeof(code)); + (void)memcpy((void*)(&code), (const void*)(&SDO_C->CANrxData[4]), sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; - } - else if (send_abort) { - abortCode = (SDOabortCode != NULL) - ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + } else if (send_abort) { + abortCode = (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; - } - else { + } else { switch (SDO_C->state) { case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { if (SDO_C->CANrxData[0] == 0x60U) { /* verify index and subindex */ uint16_t index; uint8_t subindex; - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index = ((uint16_t)SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { @@ -709,13 +605,12 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, break; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0 if (SDO_C->finished) { /* expedited transfer */ SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; - } - else { + } else { /* segmented transfer - prepare the first segment */ SDO_C->toggle = 0x00; SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; @@ -725,15 +620,14 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; #endif - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } break; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0 case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { if ((SDO_C->CANrxData[0] & 0xEFU) == 0x20U) { /* verify and alternate toggle bit */ @@ -749,12 +643,10 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, if (SDO_C->finished) { SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; - } - else { + } else { SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; } - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } @@ -762,13 +654,13 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { if ((SDO_C->CANrxData[0] & 0xFBU) == 0xA0U) { /* verify index and subindex */ uint16_t index; uint8_t subindex; - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index = ((uint16_t)SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { @@ -785,8 +677,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->block_seqno = 0; (void)CO_fifo_altBegin(&SDO_C->bufFifo, 0); SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } @@ -803,17 +694,15 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, size_t cntFailed = (size_t)(SDO_C->block_seqno) - (size_t)(SDO_C->CANrxData[1]); cntFailed = (cntFailed * 7U) - SDO_C->block_noData; SDO_C->sizeTran -= cntFailed; - (void)CO_fifo_altBegin(&SDO_C->bufFifo, - (size_t)SDO_C->CANrxData[1] * 7U); + (void)CO_fifo_altBegin(&SDO_C->bufFifo, (size_t)SDO_C->CANrxData[1] * 7U); SDO_C->finished = false; - } - else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) { + } else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) { /* something strange from server, break transmission */ abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; break; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } /* confirm successfully transmitted data */ CO_fifo_altFinish(&SDO_C->bufFifo, &SDO_C->block_crc); @@ -826,8 +715,7 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, (void)CO_fifo_altBegin(&SDO_C->bufFifo, 0); SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; } - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } @@ -839,18 +727,17 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* SDO block download successfully transferred */ SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } break; } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) == 0 case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) == 0 case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: @@ -885,13 +772,11 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->timeoutTimer = 0; timeDifference_us = 0; CO_FLAG_CLEAR(SDO_C->CANrxNew); - } - else if (send_abort) { - abortCode = (SDOabortCode != NULL) - ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + } else if (send_abort) { + abortCode = (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } /* Timeout timers and transmit bufferFull flag ****************************/ if (ret == CO_SDO_RT_waitingResponse) { @@ -902,15 +787,15 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, abortCode = CO_SDO_AB_TIMEOUT; SDO_C->state = CO_SDO_ST_ABORT; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; if (*timerNext_us > diff) { *timerNext_us = diff; } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } #endif if (SDO_C->CANtxBuff->bufferFull) { ret = CO_SDO_RT_transmittBufferFull; @@ -920,220 +805,211 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, /* Transmit CAN data ******************************************************/ if (ret == CO_SDO_RT_waitingResponse) { size_t count; - (void)memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); + (void)memset((void*)&SDO_C->CANtxBuff->data[0], 0, 8); switch (SDO_C->state) { - case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { - SDO_C->CANtxBuff->data[0] = 0x20; - SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; - SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); - SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { + SDO_C->CANtxBuff->data[0] = 0x20; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - /* get count of data bytes to transfer */ - count = CO_fifo_getOccupied(&SDO_C->bufFifo); + /* get count of data bytes to transfer */ + count = CO_fifo_getOccupied(&SDO_C->bufFifo); - /* is expedited transfer, <= 4bytes of data */ - if (((SDO_C->sizeInd == 0U) && (count <= 4U)) - || ((SDO_C->sizeInd > 0U) && (SDO_C->sizeInd <= 4U)) - ) { - SDO_C->CANtxBuff->data[0] |= 0x02U; + /* is expedited transfer, <= 4bytes of data */ + if (((SDO_C->sizeInd == 0U) && (count <= 4U)) || ((SDO_C->sizeInd > 0U) && (SDO_C->sizeInd <= 4U))) { + SDO_C->CANtxBuff->data[0] |= 0x02U; + + /* verify length, indicate data size */ + if ((count == 0U) || ((SDO_C->sizeInd > 0U) && (SDO_C->sizeInd != count))) { + SDO_C->state = CO_SDO_ST_IDLE; + abortCode = CO_SDO_AB_TYPE_MISMATCH; + ret = CO_SDO_RT_endedWithClientAbort; + break; + } + if (SDO_C->sizeInd > 0U) { + SDO_C->CANtxBuff->data[0] |= (uint8_t)(0x01U | ((4U - count) << 2)); + } - /* verify length, indicate data size */ - if ((count == 0U) || ((SDO_C->sizeInd > 0U) && - (SDO_C->sizeInd != count)) - ) { + /* copy data */ + (void)CO_fifo_read(&SDO_C->bufFifo, &SDO_C->CANtxBuff->data[4], count, NULL); + SDO_C->sizeTran = count; + SDO_C->finished = true; + } else { +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0 + /* segmented transfer, indicate data size */ + if (SDO_C->sizeInd > 0U) { + uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); + SDO_C->CANtxBuff->data[0] |= 0x01U; + (void)memcpy((void*)(&SDO_C->CANtxBuff->data[4]), (const void*)(&size), sizeof(size)); + } +#else SDO_C->state = CO_SDO_ST_IDLE; - abortCode = CO_SDO_AB_TYPE_MISMATCH; + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; ret = CO_SDO_RT_endedWithClientAbort; break; - } - if (SDO_C->sizeInd > 0U) { - SDO_C->CANtxBuff->data[0] |= (uint8_t)(0x01U | ((4U - count) << 2)); - } - - /* copy data */ - (void)CO_fifo_read(&SDO_C->bufFifo, - &SDO_C->CANtxBuff->data[4], count, NULL); - SDO_C->sizeTran = count; - SDO_C->finished = true; - } - else { -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 - /* segmented transfer, indicate data size */ - if (SDO_C->sizeInd > 0U) { - uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); - SDO_C->CANtxBuff->data[0] |= 0x01U; - (void)memcpy((void *)(&SDO_C->CANtxBuff->data[4]), (const void *)(&size), sizeof(size)); - } -#else - SDO_C->state = CO_SDO_ST_IDLE; - abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; - ret = CO_SDO_RT_endedWithClientAbort; - break; #endif - } - - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; - break; - } - -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { - /* fill data bytes */ - count = CO_fifo_read(&SDO_C->bufFifo, - &SDO_C->CANtxBuff->data[1], - 7, NULL); + } - /* verify if sizeTran is too large */ - SDO_C->sizeTran += count; - if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { - SDO_C->sizeTran -= count; - abortCode = CO_SDO_AB_DATA_LONG; - SDO_C->state = CO_SDO_ST_ABORT; + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; break; } - /* SDO command specifier */ - SDO_C->CANtxBuff->data[0] = (uint8_t)(SDO_C->toggle | ((7U - count) << 1)); +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { + /* fill data bytes */ + count = CO_fifo_read(&SDO_C->bufFifo, &SDO_C->CANtxBuff->data[1], 7, NULL); - /* is end of transfer? Verify also sizeTran */ - if ((CO_fifo_getOccupied(&SDO_C->bufFifo) == 0U) && !bufferPartial) { - if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { - abortCode = CO_SDO_AB_DATA_SHORT; + /* verify if sizeTran is too large */ + SDO_C->sizeTran += count; + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { + SDO_C->sizeTran -= count; + abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; break; } - SDO_C->CANtxBuff->data[0] |= 0x01U; - SDO_C->finished = true; - } - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; - break; - } -#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ + /* SDO command specifier */ + SDO_C->CANtxBuff->data[0] = (uint8_t)(SDO_C->toggle | ((7U - count) << 1)); -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { - SDO_C->CANtxBuff->data[0] = 0xC4; - SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; - SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); - SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + /* is end of transfer? Verify also sizeTran */ + if ((CO_fifo_getOccupied(&SDO_C->bufFifo) == 0U) && !bufferPartial) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + SDO_C->CANtxBuff->data[0] |= 0x01U; + SDO_C->finished = true; + } - /* indicate data size */ - if (SDO_C->sizeInd > 0U) { - uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); - SDO_C->CANtxBuff->data[0] |= 0x02U; - (void)memcpy((void *)(&SDO_C->CANtxBuff->data[4]), (const void *)(&size), sizeof(size)); + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; + break; } +#endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; - break; - } +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { + SDO_C->CANtxBuff->data[0] = 0xC4; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + + /* indicate data size */ + if (SDO_C->sizeInd > 0U) { + uint32_t size = CO_SWAP_32((uint32_t)SDO_C->sizeInd); + SDO_C->CANtxBuff->data[0] |= 0x02U; + (void)memcpy((void*)(&SDO_C->CANtxBuff->data[4]), (const void*)(&size), sizeof(size)); + } - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { - if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) < 7U) && bufferPartial) { - /* wait until data are refilled */ + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; break; } - SDO_C->block_seqno++; - SDO_C->CANtxBuff->data[0] = SDO_C->block_seqno; - /* get up to 7 data bytes */ - count = CO_fifo_altRead(&SDO_C->bufFifo, - &SDO_C->CANtxBuff->data[1], 7); - SDO_C->block_noData = (uint8_t)(7U - count); + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { + if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) < 7U) && bufferPartial) { + /* wait until data are refilled */ + break; + } + SDO_C->block_seqno++; + SDO_C->CANtxBuff->data[0] = SDO_C->block_seqno; - /* verify if sizeTran is too large */ - SDO_C->sizeTran += count; - if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { - SDO_C->sizeTran -= count; - abortCode = CO_SDO_AB_DATA_LONG; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } + /* get up to 7 data bytes */ + count = CO_fifo_altRead(&SDO_C->bufFifo, &SDO_C->CANtxBuff->data[1], 7); + SDO_C->block_noData = (uint8_t)(7U - count); - /* is end of transfer? Verify also sizeTran */ - if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0U) && !bufferPartial){ - if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { - abortCode = CO_SDO_AB_DATA_SHORT; + /* verify if sizeTran is too large */ + SDO_C->sizeTran += count; + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { + SDO_C->sizeTran -= count; + abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; break; } - SDO_C->CANtxBuff->data[0] |= 0x80U; - SDO_C->finished = true; - SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; - } - /* are all segments in current block transferred? */ - else if (SDO_C->block_seqno >= SDO_C->block_blksize) { - SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; - } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - else { - /* Inform OS to call this function again without delay. */ - if (timerNext_us != NULL) { - *timerNext_us = 0; + + /* is end of transfer? Verify also sizeTran */ + if ((CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0U) && !bufferPartial) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } + SDO_C->CANtxBuff->data[0] |= 0x80U; + SDO_C->finished = true; + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; + } + /* are all segments in current block transferred? */ + else if (SDO_C->block_seqno >= SDO_C->block_blksize) { + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; + } +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_TIMERNEXT) != 0 + else { + /* Inform OS to call this function again without delay. */ + if (timerNext_us != NULL) { + *timerNext_us = 0; + } } - } #endif - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - break; - } + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + break; + } - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { - SDO_C->CANtxBuff->data[0] = (uint8_t)(0xC1U | (SDO_C->block_noData << 2)); - SDO_C->CANtxBuff->data[1] = (uint8_t) SDO_C->block_crc; - SDO_C->CANtxBuff->data[2] = (uint8_t) (SDO_C->block_crc >> 8); + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { + SDO_C->CANtxBuff->data[0] = (uint8_t)(0xC1U | (SDO_C->block_noData << 2)); + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->block_crc; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->block_crc >> 8); - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; - break; - } + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; + break; + } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) == 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) == 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: #endif - case CO_SDO_ST_IDLE: - case CO_SDO_ST_ABORT: - case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: - case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_UPLOAD_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: - case CO_SDO_ST_UPLOAD_BLK_END_SREQ: - case CO_SDO_ST_UPLOAD_BLK_END_CRSP: - default: { - /* none */ - break; - } + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: + default: { + /* none */ + break; + } } } @@ -1146,16 +1022,16 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - (void)memcpy((void *)(&SDO_C->CANtxBuff->data[4]), (const void *)(&code), sizeof(code)); + (void)memcpy((void*)(&SDO_C->CANtxBuff->data[4]), (const void*)(&code), sizeof(code)); (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { ret = CO_SDO_RT_blockDownldInProgress; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } #endif } @@ -1169,16 +1045,12 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, return ret; } - /****************************************************************************** * UPLOAD * ******************************************************************************/ -CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - uint16_t SDOtimeoutTime_ms, - bool_t blockEnable) -{ +CO_SDO_return_t +CO_SDOclientUploadInitiate(CO_SDOclient_t* SDO_C, uint16_t index, uint8_t subIndex, uint16_t SDOtimeoutTime_ms, + bool_t blockEnable) { /* verify parameters */ if ((SDO_C == NULL) || !SDO_C->valid) { return CO_SDO_RT_wrongArguments; @@ -1193,26 +1065,22 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, CO_fifo_reset(&SDO_C->bufFifo); SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000U; SDO_C->timeoutTimer = 0; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 SDO_C->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700U; #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 /* if node-ID of the SDO server is the same as node-ID of this node, then * transfer data within this node */ - if (((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U)) - && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId) - ) { + if (((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U)) && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId)) { SDO_C->OD_IO.read = NULL; SDO_C->state = CO_SDO_ST_UPLOAD_LOCAL_TRANSFER; - } - else + } else #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - if (blockEnable) { +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 + if (blockEnable) { SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ; - } - else + } else #endif { SDO_C->state = CO_SDO_ST_UPLOAD_INITIATE_REQ; @@ -1223,15 +1091,10 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, return CO_SDO_RT_ok_communicationEnd; } - -CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - bool_t send_abort, - CO_SDO_abortCode_t *SDOabortCode, - size_t *sizeIndicated, - size_t *sizeTransferred, - uint32_t *timerNext_us) -{ +CO_SDO_return_t +CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t send_abort, + CO_SDO_abortCode_t* SDOabortCode, size_t* sizeIndicated, size_t* sizeTransferred, + uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ CO_SDO_return_t ret = CO_SDO_RT_waitingResponse; @@ -1240,37 +1103,32 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, if ((SDO_C == NULL) || !SDO_C->valid) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_wrongArguments; - } - else if (SDO_C->state == CO_SDO_ST_IDLE) { + } else if (SDO_C->state == CO_SDO_ST_IDLE) { ret = CO_SDO_RT_ok_communicationEnd; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 /* Transfer data locally **************************************************/ else if ((SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) && !send_abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.read == NULL) { ODR_t odRet; - odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, - &SDO_C->OD_IO, false); + odRet = OD_getSub(OD_find(SDO_C->OD, SDO_C->index), SDO_C->subIndex, &SDO_C->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithClientAbort; - } - else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_RW) == 0U) { + } else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_RW) == 0U) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; ret = CO_SDO_RT_endedWithClientAbort; - } - else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_R) == 0U) { + } else if ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_R) == 0U) { abortCode = CO_SDO_AB_WRITEONLY; ret = CO_SDO_RT_endedWithClientAbort; - } - else if (SDO_C->OD_IO.read == NULL) { + } else if (SDO_C->OD_IO.read == NULL) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; ret = CO_SDO_RT_endedWithClientAbort; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } size_t countFifo = CO_fifo_getSpace(&SDO_C->bufFifo); @@ -1284,28 +1142,24 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* Get size of data in Object Dictionary. If size is not indicated * use maximum SDO client buffer size. Prepare temp buffer. */ OD_size_t countData = SDO_C->OD_IO.stream.dataLength; - OD_size_t countBuf = ((countData > 0U) && (countData <= countFifo)) - ? countData : (OD_size_t)countFifo; + OD_size_t countBuf = ((countData > 0U) && (countData <= countFifo)) ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U]; /* load data from OD variable into the buffer */ CO_LOCK_OD(SDO_C->CANdevTx); - ODR_t odRet = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, - buf, countBuf, &countRd); + ODR_t odRet = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, buf, countBuf, &countRd); CO_UNLOCK_OD(SDO_C->CANdevTx); if ((odRet != ODR_OK) && (odRet != ODR_PARTIAL)) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithServerAbort; - } - else { + } else { /* if data is string, send only data up to null termination */ if ((countRd > 0U) && (countRd <= CO_CONFIG_SDO_CLI_BUFFER_SIZE) - && ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) - ) { + && ((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U)) { buf[countRd] = 0; /* (buf is one byte larger) */ - OD_size_t countStr = (OD_size_t)strlen((char *)buf); + OD_size_t countStr = (OD_size_t)strlen((char*)buf); if (countStr == 0U) { countStr = 1; /* no zero length */ } @@ -1313,8 +1167,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* string terminator found, finish read, shorten data */ countRd = countStr; odRet = ODR_OK; - SDO_C->OD_IO.stream.dataLength = - (OD_size_t)SDO_C->sizeTran + countRd; + SDO_C->OD_IO.stream.dataLength = (OD_size_t)SDO_C->sizeTran + countRd; } } @@ -1330,32 +1183,28 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* If no more segments to be upload, finish */ else if (odRet == ODR_OK) { /* verify size of data uploaded */ - if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)){ + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; - } - else { + } else { ret = CO_SDO_RT_ok_communicationEnd; } - } - else { + } else { ret = CO_SDO_RT_waitingLocalTransfer; } } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } - if ((ret != CO_SDO_RT_uploadDataBufferFull) - && (ret != CO_SDO_RT_waitingLocalTransfer) - ) { + if ((ret != CO_SDO_RT_uploadDataBufferFull) && (ret != CO_SDO_RT_waitingLocalTransfer)) { SDO_C->state = CO_SDO_ST_IDLE; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Inform OS to call this function again without delay. */ else if (timerNext_us != NULL) { *timerNext_us = 0; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } #endif } #endif /* CO_CONFIG_SDO_CLI_LOCAL */ @@ -1364,24 +1213,21 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80U) { uint32_t code; - (void)memcpy((void *)(&code), (const void *)(&SDO_C->CANrxData[4]), sizeof(code)); + (void)memcpy((void*)(&code), (const void*)(&SDO_C->CANrxData[4]), sizeof(code)); abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; - } - else if (send_abort) { - abortCode = (SDOabortCode != NULL) - ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + } else if (send_abort) { + abortCode = (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; - } - else { + } else { switch (SDO_C->state) { case CO_SDO_ST_UPLOAD_INITIATE_RSP: { if ((SDO_C->CANrxData[0] & 0xF0U) == 0x40U) { /* verify index and subindex */ uint16_t index; uint8_t subindex; - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index = ((uint16_t)SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { @@ -1398,19 +1244,16 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, count -= (((size_t)SDO_C->CANrxData[0]) >> 2) & 0x03U; } /* copy data, indicate size and finish */ - (void)CO_fifo_write(&SDO_C->bufFifo, - &SDO_C->CANrxData[4], - count, NULL); + (void)CO_fifo_write(&SDO_C->bufFifo, &SDO_C->CANrxData[4], count, NULL); SDO_C->sizeTran = count; SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; - } - else { -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 + } else { +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0 /* segmented transfer, is size indicated? */ if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { uint32_t size; - (void)memcpy((void *)(&size), (void *)(&SDO_C->CANrxData[4]), sizeof(size)); + (void)memcpy((void*)(&size), (void*)(&SDO_C->CANrxData[4]), sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } SDO_C->toggle = 0x00; @@ -1420,15 +1263,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_ABORT; #endif } - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } break; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0 case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { if ((SDO_C->CANrxData[0] & 0xE0U) == 0x00U) { size_t count, countWr; @@ -1444,9 +1286,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* get data size and write data to the buffer */ count = (size_t)(7U) - (((size_t)(SDO_C->CANrxData[0]) >> 1) & 0x07U); - countWr = CO_fifo_write(&SDO_C->bufFifo, - &SDO_C->CANrxData[1], - count, NULL); + countWr = CO_fifo_write(&SDO_C->bufFifo, &SDO_C->CANrxData[1], count, NULL); SDO_C->sizeTran += countWr; /* verify, if there was not enough space in fifo buffer */ @@ -1457,9 +1297,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } /* verify if size of data uploaded is too large */ - if ((SDO_C->sizeInd > 0U) - && (SDO_C->sizeTran > SDO_C->sizeInd) - ) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_LONG; SDO_C->state = CO_SDO_ST_ABORT; break; @@ -1468,21 +1306,17 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* If no more segments to be upload, finish */ if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { /* verify size of data uploaded */ - if ((SDO_C->sizeInd > 0U) - && (SDO_C->sizeTran < SDO_C->sizeInd) - ) { + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran < SDO_C->sizeInd)) { abortCode = CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; } else { SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; } - } - else { + } else { SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; } - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } @@ -1490,7 +1324,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { if ((SDO_C->CANrxData[0] & 0xF9U) == 0xC0U) { uint16_t index; @@ -1504,19 +1338,18 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } if ((SDO_C->CANrxData[0] & 0x02U) != 0U) { uint32_t size; - (void)memcpy((void *)(&size), (const void *)(&SDO_C->CANrxData[4]), sizeof(size)); + (void)memcpy((void*)(&size), (const void*)(&SDO_C->CANrxData[4]), sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } /* verify index and subindex */ - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index = ((uint16_t)SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { abortCode = CO_SDO_AB_PRAM_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; - } - else { + } else { SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; } } @@ -1525,7 +1358,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* verify index and subindex */ uint16_t index; uint8_t subindex; - index = ((uint16_t) SDO_C->CANrxData[2]) << 8; + index = ((uint16_t)SDO_C->CANrxData[2]) << 8; index |= SDO_C->CANrxData[1]; subindex = SDO_C->CANrxData[3]; if ((index != SDO_C->index) || (subindex != SDO_C->subIndex)) { @@ -1542,25 +1375,21 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, count -= ((size_t)(SDO_C->CANrxData[0]) >> 2) & 0x03U; } /* copy data, indicate size and finish */ - (void)CO_fifo_write(&SDO_C->bufFifo, - &SDO_C->CANrxData[4], - count, NULL); + (void)CO_fifo_write(&SDO_C->bufFifo, &SDO_C->CANrxData[4], count, NULL); SDO_C->sizeTran = count; SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; - } - else { + } else { /* segmented transfer, is size indicated? */ if ((SDO_C->CANrxData[0] & 0x01U) != 0U) { uint32_t size; - (void)memcpy((void *)(&size), (const void *)(&SDO_C->CANrxData[4]), sizeof(size)); + (void)memcpy((void*)(&size), (const void*)(&SDO_C->CANrxData[4]), sizeof(size)); SDO_C->sizeInd = CO_SWAP_32(size); } SDO_C->toggle = 0x00; SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; } - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } @@ -1577,18 +1406,13 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* Get number of data bytes in last segment, that do not * contain data. Then copy remaining data into fifo */ uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07U); - (void)CO_fifo_write(&SDO_C->bufFifo, - &SDO_C->block_dataUploadLast[0], - (size_t)(7U) - noData, - &SDO_C->block_crc); + (void)CO_fifo_write(&SDO_C->bufFifo, &SDO_C->block_dataUploadLast[0], (size_t)(7U) - noData, + &SDO_C->block_crc); SDO_C->sizeTran += (size_t)(7U) - noData; /* verify length */ - if ((SDO_C->sizeInd > 0U) - && (SDO_C->sizeTran != SDO_C->sizeInd) - ) { - abortCode = (SDO_C->sizeTran > SDO_C->sizeInd) ? - CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran != SDO_C->sizeInd)) { + abortCode = (SDO_C->sizeTran > SDO_C->sizeInd) ? CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; SDO_C->state = CO_SDO_ST_ABORT; break; } @@ -1596,7 +1420,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* verify CRC */ if (SDO_C->block_crcEnabled) { uint16_t crcServer; - crcServer = ((uint16_t) SDO_C->CANrxData[2]) << 8; + crcServer = ((uint16_t)SDO_C->CANrxData[2]) << 8; crcServer |= SDO_C->CANrxData[1]; if (crcServer != SDO_C->block_crc) { abortCode = CO_SDO_AB_CRC; @@ -1605,8 +1429,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } } SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; - } - else { + } else { abortCode = CO_SDO_AB_CMD; SDO_C->state = CO_SDO_ST_ABORT; } @@ -1614,10 +1437,10 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) == 0 case CO_SDO_ST_UPLOAD_SEGMENT_RSP: #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) == 0 case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: case CO_SDO_ST_UPLOAD_BLK_END_SREQ: @@ -1652,13 +1475,11 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->timeoutTimer = 0; timeDifference_us = 0; CO_FLAG_CLEAR(SDO_C->CANrxNew); - } - else if (send_abort) { - abortCode = (SDOabortCode != NULL) - ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; + } else if (send_abort) { + abortCode = (SDOabortCode != NULL) ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT; SDO_C->state = CO_SDO_ST_ABORT; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } /* Timeout timers and transmit bufferFull flag ****************************/ if (ret == CO_SDO_RT_waitingResponse) { @@ -1676,18 +1497,18 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, } SDO_C->state = CO_SDO_ST_ABORT; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer; if (*timerNext_us > diff) { *timerNext_us = diff; } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 /* Timeout for sub-block reception */ if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { if (SDO_C->block_timeoutTimer < SDO_C->block_SDOtimeoutTime_us) { @@ -1699,16 +1520,15 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; CO_FLAG_CLEAR(SDO_C->CANrxNew); } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ - uint32_t diff = SDO_C->block_SDOtimeoutTime_us - - SDO_C->block_timeoutTimer; + uint32_t diff = SDO_C->block_SDOtimeoutTime_us - SDO_C->block_timeoutTimer; if (*timerNext_us > diff) { *timerNext_us = diff; } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } #endif } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ @@ -1720,200 +1540,194 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, /* Transmit CAN data ******************************************************/ if (ret == CO_SDO_RT_waitingResponse) { -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 size_t count; #endif - (void)memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8); + (void)memset((void*)&SDO_C->CANtxBuff->data[0], 0, 8); switch (SDO_C->state) { - case CO_SDO_ST_UPLOAD_INITIATE_REQ: { - SDO_C->CANtxBuff->data[0] = 0x40; - SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; - SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); - SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + case CO_SDO_ST_UPLOAD_INITIATE_REQ: { + SDO_C->CANtxBuff->data[0] = 0x40; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; + + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; + break; + } - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; - break; - } +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0 + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { + /* verify, if there is enough space in data buffer */ + if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7U) { + ret = CO_SDO_RT_uploadDataBufferFull; + break; + } + SDO_C->CANtxBuff->data[0] = 0x60U | SDO_C->toggle; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0 - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { - /* verify, if there is enough space in data buffer */ - if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7U) { - ret = CO_SDO_RT_uploadDataBufferFull; + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; break; } - SDO_C->CANtxBuff->data[0] = 0x60U | SDO_C->toggle; - - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; - break; - } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */ -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { - SDO_C->CANtxBuff->data[0] = 0xA4; - SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; - SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); - SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { + SDO_C->CANtxBuff->data[0] = 0xA4; + SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index; + SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); + SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - /* calculate number of block segments from free buffer space */ - count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7U; - if (count > 127U) { - count = 127; - } - else if (count == 0U) { - abortCode = CO_SDO_AB_OUT_OF_MEM; - SDO_C->state = CO_SDO_ST_ABORT; + /* calculate number of block segments from free buffer space */ + count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7U; + if (count > 127U) { + count = 127; + } else if (count == 0U) { + abortCode = CO_SDO_AB_OUT_OF_MEM; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } else { /* MISRA C 2004 14.10 */ + } + SDO_C->block_blksize = (uint8_t)count; + SDO_C->CANtxBuff->data[4] = SDO_C->block_blksize; + SDO_C->CANtxBuff->data[5] = CO_CONFIG_SDO_CLI_PST; + + /* reset timeout timer and send message */ + SDO_C->timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; break; } - else { /* MISRA C 2004 14.10 */ } - SDO_C->block_blksize = (uint8_t)count; - SDO_C->CANtxBuff->data[4] = SDO_C->block_blksize; - SDO_C->CANtxBuff->data[5] = CO_CONFIG_SDO_CLI_PST; - /* reset timeout timer and send message */ - SDO_C->timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; - break; - } - - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { - SDO_C->CANtxBuff->data[0] = 0xA3; + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { + SDO_C->CANtxBuff->data[0] = 0xA3; - /* reset timeout timers, seqno and send message */ - SDO_C->timeoutTimer = 0; - SDO_C->block_timeoutTimer = 0; - SDO_C->block_seqno = 0; - SDO_C->block_crc = 0; - /* Block segments will be received in different thread. Make memory + /* reset timeout timers, seqno and send message */ + SDO_C->timeoutTimer = 0; + SDO_C->block_timeoutTimer = 0; + SDO_C->block_seqno = 0; + SDO_C->block_crc = 0; + /* Block segments will be received in different thread. Make memory * barrier here with CO_FLAG_CLEAR() call. */ - SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - break; - } + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + CO_FLAG_CLEAR(SDO_C->CANrxNew); + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + break; + } - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { - SDO_C->CANtxBuff->data[0] = 0xA2; - SDO_C->CANtxBuff->data[1] = SDO_C->block_seqno; + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { + SDO_C->CANtxBuff->data[0] = 0xA2; + SDO_C->CANtxBuff->data[1] = SDO_C->block_seqno; #ifdef CO_DEBUG_SDO_CLIENT - bool_t transferShort = SDO_C->block_seqno != SDO_C->block_blksize; - uint8_t seqnoStart = SDO_C->block_seqno; + bool_t transferShort = SDO_C->block_seqno != SDO_C->block_blksize; + uint8_t seqnoStart = SDO_C->block_seqno; #endif - /* Is last segment? */ - if (SDO_C->finished) { - SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; - } - else { - /* verify if size of data uploaded is too large */ - if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { - abortCode = CO_SDO_AB_DATA_LONG; - SDO_C->state = CO_SDO_ST_ABORT; - break; - } + /* Is last segment? */ + if (SDO_C->finished) { + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; + } else { + /* verify if size of data uploaded is too large */ + if ((SDO_C->sizeInd > 0U) && (SDO_C->sizeTran > SDO_C->sizeInd)) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO_C->state = CO_SDO_ST_ABORT; + break; + } - /* calculate number of block segments from free buffer space */ - count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7U; - if (count >= 127U) { - count = 127; - } - else if (CO_fifo_getOccupied(&SDO_C->bufFifo) > 0U) { - /* application must empty data buffer first */ - ret = CO_SDO_RT_uploadDataBufferFull; + /* calculate number of block segments from free buffer space */ + count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7U; + if (count >= 127U) { + count = 127; + } else if (CO_fifo_getOccupied(&SDO_C->bufFifo) > 0U) { + /* application must empty data buffer first */ + ret = CO_SDO_RT_uploadDataBufferFull; #ifdef CO_DEBUG_SDO_CLIENT - if (transferShort) { - char msg[80]; - sprintf(msg, - "sub-block, uploadDataBufferFull: sequno=%02X", - seqnoStart); - CO_DEBUG_SDO_CLIENT(msg); - } + if (transferShort) { + char msg[80]; + sprintf(msg, "sub-block, uploadDataBufferFull: sequno=%02X", seqnoStart); + CO_DEBUG_SDO_CLIENT(msg); + } #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - /* Inform OS to call this function again without delay. */ - if (timerNext_us != NULL) { - *timerNext_us = 0; - } +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_TIMERNEXT) != 0 + /* Inform OS to call this function again without delay. */ + if (timerNext_us != NULL) { + *timerNext_us = 0; + } #endif - break; - } - else { /* MISRA C 2004 14.10 */ } - - SDO_C->block_blksize = (uint8_t)count; - SDO_C->block_seqno = 0; - /* Block segments will be received in different thread. Make + break; + } else { /* MISRA C 2004 14.10 */ + } + + SDO_C->block_blksize = (uint8_t)count; + SDO_C->block_seqno = 0; + /* Block segments will be received in different thread. Make * memory barrier here with CO_FLAG_CLEAR() call. */ - SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; - CO_FLAG_CLEAR(SDO_C->CANrxNew); - } + SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + CO_FLAG_CLEAR(SDO_C->CANrxNew); + } - SDO_C->CANtxBuff->data[2] = SDO_C->block_blksize; + SDO_C->CANtxBuff->data[2] = SDO_C->block_blksize; - /* reset block_timeoutTimer, but not SDO_C->timeoutTimer */ - SDO_C->block_timeoutTimer = 0; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + /* reset block_timeoutTimer, but not SDO_C->timeoutTimer */ + SDO_C->block_timeoutTimer = 0; + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); #ifdef CO_DEBUG_SDO_CLIENT - if (transferShort && !SDO_C->finished) { - char msg[80]; - sprintf(msg, - "sub-block restarted: sequnoPrev=%02X, blksize=%02X", - seqnoStart, SDO_C->block_blksize); - CO_DEBUG_SDO_CLIENT(msg); - } + if (transferShort && !SDO_C->finished) { + char msg[80]; + sprintf(msg, "sub-block restarted: sequnoPrev=%02X, blksize=%02X", seqnoStart, + SDO_C->block_blksize); + CO_DEBUG_SDO_CLIENT(msg); + } #endif - break; - } + break; + } - case CO_SDO_ST_UPLOAD_BLK_END_CRSP: { - SDO_C->CANtxBuff->data[0] = 0xA1; + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: { + SDO_C->CANtxBuff->data[0] = 0xA1; - (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); - SDO_C->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; - break; - } + (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); + SDO_C->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + break; + } #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */ -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) == 0 - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) == 0 + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) == 0 - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: - case CO_SDO_ST_UPLOAD_BLK_END_CRSP: +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) == 0 + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: #endif - case CO_SDO_ST_IDLE: - case CO_SDO_ST_ABORT: - case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: - case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_UPLOAD_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: - case CO_SDO_ST_UPLOAD_BLK_END_SREQ: - default: { - /* none */ - break; - } + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: + default: { + /* none */ + break; + } } } @@ -1926,16 +1740,16 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8); SDO_C->CANtxBuff->data[3] = SDO_C->subIndex; - (void)memcpy((void *)(&SDO_C->CANtxBuff->data[4]), (const void *)(&code), sizeof(code)); + (void)memcpy((void*)(&SDO_C->CANtxBuff->data[4]), (const void*)(&code), sizeof(code)); (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); SDO_C->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithClientAbort; } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { ret = CO_SDO_RT_blockUploadInProgress; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } #endif } @@ -1952,11 +1766,8 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, return ret; } - -size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, - uint8_t *buf, - size_t count) -{ +size_t +CO_SDOclientUploadBufRead(CO_SDOclient_t* SDO_C, uint8_t* buf, size_t count) { size_t ret = 0; if ((SDO_C != NULL) && (buf != NULL)) { ret = CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL); @@ -1964,8 +1775,8 @@ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, return ret; } - -void CO_SDOclientClose(CO_SDOclient_t *SDO_C) { +void +CO_SDOclientClose(CO_SDOclient_t* SDO_C) { if (SDO_C != NULL) { SDO_C->state = CO_SDO_ST_IDLE; } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 9948ff78..b1a8edee 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -24,21 +24,21 @@ #include "301/crc16-ccitt.h" /* verify configuration */ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 20 - #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 20. - #endif +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 +#if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 20 +#error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 20. +#endif +#endif +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) == 0 +#error CO_CONFIG_SDO_SRV_SEGMENTED must be enabled. +#endif +#if ((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_ENABLE) == 0 +#error CO_CONFIG_CRC16_ENABLE must be enabled. +#endif +#if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 900 +#error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 900. #endif -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 - #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) == 0 - #error CO_CONFIG_SDO_SRV_SEGMENTED must be enabled. - #endif - #if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) == 0 - #error CO_CONFIG_CRC16_ENABLE must be enabled. - #endif - #if CO_CONFIG_SDO_SRV_BUFFER_SIZE < 900 - #error CO_CONFIG_SDO_SRV_BUFFER_SIZE must be greater or equal than 900. - #endif #endif /* @@ -48,28 +48,27 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_SDO_receive(void *object, void *msg) { - CO_SDOserver_t *SDO = (CO_SDOserver_t *)object; +static void +CO_SDO_receive(void* object, void* msg) { + CO_SDOserver_t* SDO = (CO_SDOserver_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); /* ignore messages with wrong length */ if (DLC == 8U) { if (data[0] == 0x80U) { /* abort from client, just make idle */ SDO->state = CO_SDO_ST_IDLE; - } - else if (CO_FLAG_READ(SDO->CANrxNew)) { + } else if (CO_FLAG_READ(SDO->CANrxNew)) { /* ignore message if previous message was not processed yet */ } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 - else if (SDO->state == CO_SDO_ST_UPLOAD_BLK_END_CRSP && data[0]==0xA1) { +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 + else if (SDO->state == CO_SDO_ST_UPLOAD_BLK_END_CRSP && data[0] == 0xA1) { /* SDO block download successfully transferred, just make idle */ SDO->state = CO_SDO_ST_IDLE; - } - else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { + } else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { /* just in case, condition should always pass */ - if (SDO->bufOffsetWr <= (CO_CONFIG_SDO_SRV_BUFFER_SIZE - (7+2))) { + if (SDO->bufOffsetWr <= (CO_CONFIG_SDO_SRV_BUFFER_SIZE - (7 + 2))) { /* block download, copy data directly */ CO_SDO_state_t state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; uint8_t seqno = data[0] & 0x7F; @@ -77,9 +76,7 @@ static void CO_SDO_receive(void *object, void *msg) { SDO->block_timeoutTimer = 0; /* verify if sequence number is correct */ - if (seqno <= SDO->block_blksize - && seqno == (SDO->block_seqno + 1) - ) { + if (seqno <= SDO->block_blksize && seqno == (SDO->block_seqno + 1)) { SDO->block_seqno = seqno; /* Copy data. There is always enough space in buffer, @@ -92,8 +89,7 @@ static void CO_SDO_receive(void *object, void *msg) { if ((data[0] & 0x80) != 0) { SDO->finished = true; state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; - } - else if (seqno == SDO->block_blksize) { + } else if (seqno == SDO->block_blksize) { /* all segments in sub-block has been transferred */ state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; } @@ -105,18 +101,14 @@ static void CO_SDO_receive(void *object, void *msg) { state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; #ifdef CO_DEBUG_SDO_SERVER char msg[80]; - sprintf(msg, - "sub-block, rx WRONG: sequno=%02X, previous=%02X", - seqno, SDO->block_seqno); + sprintf(msg, "sub-block, rx WRONG: sequno=%02X, previous=%02X", seqno, SDO->block_seqno); CO_DEBUG_SDO_SERVER(msg); #endif } #ifdef CO_DEBUG_SDO_SERVER else { char msg[80]; - sprintf(msg, - "sub-block, rx ignored: sequno=%02X, expected=%02X", - seqno, SDO->block_seqno + 1); + sprintf(msg, "sub-block, rx ignored: sequno=%02X, expected=%02X", seqno, SDO->block_seqno + 1); CO_DEBUG_SDO_SERVER(msg); } #endif @@ -127,7 +119,7 @@ static void CO_SDO_receive(void *object, void *msg) { * CO_FLAG_CLEAR() call. */ CO_FLAG_CLEAR(SDO->CANrxNew); SDO->state = state; -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which * handles SDO server processing. */ if (SDO->pFunctSignalPre != NULL) { @@ -136,8 +128,7 @@ static void CO_SDO_receive(void *object, void *msg) { #endif } } - } - else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP) { + } else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP) { /* ignore subsequent server messages, if response was requested */ } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ @@ -146,7 +137,7 @@ static void CO_SDO_receive(void *object, void *msg) { * CO_SDOserver_process() */ (void)memcpy(SDO->CANrxData, data, DLC); CO_FLAG_SET(SDO->CANrxNew); -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles * SDO server processing. */ if (SDO->pFunctSignalPre != NULL) { @@ -157,20 +148,13 @@ static void CO_SDO_receive(void *object, void *msg) { } } - /* helper for configuring CANrx and CANtx *************************************/ -static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - uint16_t CANdevTxIdx, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient) -{ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +static CO_ReturnError_t +CO_SDOserver_init_canRxTx(CO_SDOserver_t* SDO, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, uint16_t CANdevTxIdx, + uint32_t COB_IDClientToServer, uint32_t COB_IDServerToClient) { +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* proceed only, if parameters change */ - if ((COB_IDClientToServer == SDO->COB_IDClientToServer) - && (COB_IDServerToClient == SDO->COB_IDServerToClient) - ) { + if ((COB_IDClientToServer == SDO->COB_IDClientToServer) && (COB_IDServerToClient == SDO->COB_IDServerToClient)) { return CO_ERROR_NO; } /* store variables */ @@ -179,37 +163,21 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, #endif /* verify valid bit */ - uint16_t idC2S = ((COB_IDClientToServer & 0x80000000UL) == 0U) ? - (uint16_t)COB_IDClientToServer : 0U; - uint16_t idS2C = ((COB_IDServerToClient & 0x80000000UL) == 0U) ? - (uint16_t)COB_IDServerToClient : 0U; + uint16_t idC2S = ((COB_IDClientToServer & 0x80000000UL) == 0U) ? (uint16_t)COB_IDClientToServer : 0U; + uint16_t idS2C = ((COB_IDServerToClient & 0x80000000UL) == 0U) ? (uint16_t)COB_IDServerToClient : 0U; if ((idC2S != 0U) && (idS2C != 0U)) { SDO->valid = true; - } - else { + } else { idC2S = 0; idS2C = 0; SDO->valid = false; } /* configure SDO server CAN reception */ - CO_ReturnError_t ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - idC2S, - 0x7FF, - false, - (void*)SDO, - CO_SDO_receive); + CO_ReturnError_t ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, idC2S, 0x7FF, false, (void*)SDO, CO_SDO_receive); /* configure SDO server CAN transmission */ - SDO->CANtxBuff = CO_CANtxBufferInit( - SDO->CANdevTx, - CANdevTxIdx, - idS2C, - false, - 8, - false); + SDO->CANtxBuff = CO_CANtxBufferInit(SDO->CANdevTx, CANdevTxIdx, idS2C, false, 8, false); if (SDO->CANtxBuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; @@ -219,28 +187,24 @@ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t *SDO, return ret; } - -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object _SDO server parameter_, additional * channels * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ +static ODR_t +OD_write_1201_additional(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { /* "count" is already verified in *_init() function */ if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_SDOserver_t *SDO = (CO_SDOserver_t *)stream->object; + CO_SDOserver_t* SDO = (CO_SDOserver_t*)stream->object; switch (stream->subIndex) { - case 0: /* Highest sub-index supported */ - return ODR_READONLY; - break; + case 0: /* Highest sub-index supported */ return ODR_READONLY; break; case 1: { /* COB-ID client -> server */ uint32_t COB_ID = CO_getUint32(buf); @@ -249,18 +213,12 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, bool_t valid = (COB_ID & 0x80000000U) == 0U; /* SDO client must not be valid when changing COB_ID */ - if (((COB_ID & 0x3FFFF800U) != 0U) - || ((valid && SDO->valid) && (CAN_ID != CAN_ID_cur)) - || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - ) { + if (((COB_ID & 0x3FFFF800U) != 0U) || ((valid && SDO->valid) && (CAN_ID != CAN_ID_cur)) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID))) { return ODR_INVALID_VALUE; } - (void)CO_SDOserver_init_canRxTx(SDO, - SDO->CANdevRx, - SDO->CANdevRxIdx, - SDO->CANdevTxIdx, - COB_ID, - SDO->COB_IDServerToClient); + (void)CO_SDOserver_init_canRxTx(SDO, SDO->CANdevRx, SDO->CANdevRxIdx, SDO->CANdevTxIdx, COB_ID, + SDO->COB_IDServerToClient); break; } @@ -271,18 +229,12 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, bool_t valid = (COB_ID & 0x80000000U) == 0U; /* SDO client must not be valid when changing COB_ID */ - if (((COB_ID & 0x3FFFF800U) != 0U) - || (valid && (SDO->valid && (CAN_ID != CAN_ID_cur))) - || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) - ) { + if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && (SDO->valid && (CAN_ID != CAN_ID_cur))) + || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID))) { return ODR_INVALID_VALUE; } - (void)CO_SDOserver_init_canRxTx(SDO, - SDO->CANdevRx, - SDO->CANdevRxIdx, - SDO->CANdevTxIdx, - SDO->COB_IDClientToServer, - COB_ID); + (void)CO_SDOserver_init_canRxTx(SDO, SDO->CANdevRx, SDO->CANdevRxIdx, SDO->CANdevTxIdx, + SDO->COB_IDClientToServer, COB_ID); break; } @@ -297,9 +249,7 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, break; } - default: - return ODR_SUB_NOT_EXIST; - break; + default: return ODR_SUB_NOT_EXIST; break; } /* write value to the original location in the Object Dictionary */ @@ -307,18 +257,10 @@ static ODR_t OD_write_1201_additional(OD_stream_t *stream, const void *buf, } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC */ - -CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, - OD_t *OD, - OD_entry_t *OD_1200_SDOsrvPar, - uint8_t nodeId, - uint16_t SDOtimeoutTime_ms, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint32_t *errInfo) -{ +CO_ReturnError_t +CO_SDOserver_init(CO_SDOserver_t* SDO, OD_t* OD, OD_entry_t* OD_1200_SDOsrvPar, uint8_t nodeId, + uint16_t SDOtimeoutTime_ms, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t* CANdevTx, + uint16_t CANdevTxIdx, uint32_t* errInfo) { /* verify arguments */ if ((SDO == NULL) || (OD == NULL) || (CANdevRx == NULL) || (CANdevTx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -327,15 +269,15 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, /* Configure object variables */ SDO->OD = OD; SDO->nodeId = nodeId; -#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED)) != 0 +#if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED)) != 0 SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000U; #endif -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 SDO->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700; #endif SDO->state = CO_SDO_ST_IDLE; -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 SDO->pFunctSignalPre = NULL; SDO->functSignalObjectPre = NULL; #endif @@ -345,13 +287,14 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, if (OD_1200_SDOsrvPar == NULL) { /* configure default SDO channel */ - if ((nodeId < 1U) || (nodeId > 127U)) { return CO_ERROR_ILLEGAL_ARGUMENT; } + if ((nodeId < 1U) || (nodeId > 127U)) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } CanId_ClientToServer = CO_CAN_ID_SDO_CLI + nodeId; CanId_ServerToClient = CO_CAN_ID_SDO_SRV + nodeId; SDO->valid = true; - } - else { + } else { uint16_t OD_SDOsrvParIdx = OD_getIndex(OD_1200_SDOsrvPar); if (OD_SDOsrvParIdx == (uint16_t)OD_H1200_SDO_SERVER_1_PARAM) { @@ -366,54 +309,52 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, (void)OD_set_u32(OD_1200_SDOsrvPar, 1, CanId_ClientToServer, true); (void)OD_set_u32(OD_1200_SDOsrvPar, 2, CanId_ServerToClient, true); - } - else if ((OD_SDOsrvParIdx > (uint16_t)OD_H1200_SDO_SERVER_1_PARAM) - && (OD_SDOsrvParIdx <= ((uint16_t)OD_H1200_SDO_SERVER_1_PARAM + 0x7FU)) - ) { + } else if ((OD_SDOsrvParIdx > (uint16_t)OD_H1200_SDO_SERVER_1_PARAM) + && (OD_SDOsrvParIdx <= ((uint16_t)OD_H1200_SDO_SERVER_1_PARAM + 0x7FU))) { /* configure additional SDO channel and SDO server parameters for it */ uint8_t maxSubIndex; uint32_t COB_IDClientToServer32, COB_IDServerToClient32; /* get and verify parameters from Object Dictionary (initial values) */ ODR_t odRet0 = OD_get_u8(OD_1200_SDOsrvPar, 0, &maxSubIndex, true); - ODR_t odRet1 = OD_get_u32(OD_1200_SDOsrvPar, 1, - &COB_IDClientToServer32, true); - ODR_t odRet2 = OD_get_u32(OD_1200_SDOsrvPar, 2, - &COB_IDServerToClient32, true); - - if ((odRet0 != ODR_OK) || ((maxSubIndex != 2U) && (maxSubIndex != 3U)) - || (odRet1 != ODR_OK) || (odRet2 != ODR_OK) - ) { - if (errInfo != NULL) { *errInfo = OD_SDOsrvParIdx; } + ODR_t odRet1 = OD_get_u32(OD_1200_SDOsrvPar, 1, &COB_IDClientToServer32, true); + ODR_t odRet2 = OD_get_u32(OD_1200_SDOsrvPar, 2, &COB_IDServerToClient32, true); + + if ((odRet0 != ODR_OK) || ((maxSubIndex != 2U) && (maxSubIndex != 3U)) || (odRet1 != ODR_OK) + || (odRet2 != ODR_OK)) { + if (errInfo != NULL) { + *errInfo = OD_SDOsrvParIdx; + } return CO_ERROR_OD_PARAMETERS; } - CanId_ClientToServer = ((COB_IDClientToServer32 & 0x80000000U) == 0U) - ? (uint16_t)(COB_IDClientToServer32 & 0x7FFU) : 0U; + ? (uint16_t)(COB_IDClientToServer32 & 0x7FFU) + : 0U; CanId_ServerToClient = ((COB_IDServerToClient32 & 0x80000000U) == 0U) - ? (uint16_t)(COB_IDServerToClient32 & 0x7FFU) : 0U; + ? (uint16_t)(COB_IDServerToClient32 & 0x7FFU) + : 0U; - #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SDO->OD_1200_extension.object = SDO; SDO->OD_1200_extension.read = OD_readOriginal; SDO->OD_1200_extension.write = OD_write_1201_additional; - ODR_t odRetE = OD_extension_init(OD_1200_SDOsrvPar, - &SDO->OD_1200_extension); + ODR_t odRetE = OD_extension_init(OD_1200_SDOsrvPar, &SDO->OD_1200_extension); if (odRetE != ODR_OK) { - if (errInfo != NULL) { *errInfo = OD_SDOsrvParIdx; } + if (errInfo != NULL) { + *errInfo = OD_SDOsrvParIdx; + } return CO_ERROR_OD_PARAMETERS; } - #endif - } - else { +#endif + } else { return CO_ERROR_ILLEGAL_ARGUMENT; } } CO_FLAG_CLEAR(SDO->CANrxNew); /* store the parameters and configure CANrx and CANtx */ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SDO->CANdevRx = CANdevRx; SDO->CANdevRxIdx = CANdevRxIdx; SDO->CANdevTxIdx = CANdevTxIdx; @@ -423,20 +364,13 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, #endif SDO->CANdevTx = CANdevTx; - return CO_SDOserver_init_canRxTx(SDO, - CANdevRx, - CANdevRxIdx, - CANdevTxIdx, - CanId_ClientToServer, + return CO_SDOserver_init_canRxTx(SDO, CANdevRx, CANdevRxIdx, CANdevTxIdx, CanId_ClientToServer, CanId_ServerToClient); } - -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, - void *object, - void (*pFunctSignalPre)(void *object)) -{ +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_SDOserver_initCallbackPre(CO_SDOserver_t* SDO, void* object, void (*pFunctSignalPre)(void* object)) { if (SDO != NULL) { SDO->functSignalObjectPre = object; SDO->pFunctSignalPre = pFunctSignalPre; @@ -444,11 +378,11 @@ void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, } #endif - #ifdef CO_BIG_ENDIAN -static inline void reverseBytes(void *start, OD_size_t size) { - uint8_t *lo = (uint8_t *)start; - uint8_t *hi = (uint8_t *)start + size - 1; +static inline void +reverseBytes(void* start, OD_size_t size) { + uint8_t* lo = (uint8_t*)start; + uint8_t* hi = (uint8_t*)start + size - 1; while (lo < hi) { uint8_t swap = *lo; *lo++ = *hi; @@ -457,8 +391,7 @@ static inline void reverseBytes(void *start, OD_size_t size) { } #endif - -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /** Helper function for writing data to Object dictionary. Function swaps data * if necessary, calcualtes (and verifies CRC) writes data to OD and verifies * data lengths. @@ -470,18 +403,14 @@ static inline void reverseBytes(void *start, OD_size_t size) { * * Returns true on success, otherwise write also abortCode and sets state to * CO_SDO_ST_ABORT */ -static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, - CO_SDO_abortCode_t *abortCode, - uint8_t crcOperation, - uint16_t crcClient) -{ +static bool_t +validateAndWriteToOD(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, uint8_t crcOperation, uint16_t crcClient) { OD_size_t bufOffsetWrOrig = SDO->bufOffsetWr; if (SDO->finished) { /* Verify if size of data downloaded matches size indicated. */ if ((SDO->sizeInd > 0U) && (SDO->sizeTran != SDO->sizeInd)) { - *abortCode = (SDO->sizeTran > SDO->sizeInd) ? - CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + *abortCode = (SDO->sizeTran > SDO->sizeInd) ? CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; return false; } @@ -501,8 +430,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, * (temporary, send information about EOF into OD_IO.write) */ if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) && ((sizeInOd == 0U) || (SDO->sizeTran < sizeInOd)) - && ((SDO->bufOffsetWr + 2U) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE) - ) { + && ((SDO->bufOffsetWr + 2U) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE)) { SDO->buf[SDO->bufOffsetWr] = 0; SDO->bufOffsetWr++; SDO->sizeTran++; @@ -519,14 +447,12 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, } /* Verify if size of data downloaded matches data size in OD. */ else if (SDO->sizeTran != sizeInOd) { - *abortCode = (SDO->sizeTran > sizeInOd) ? - CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + *abortCode = (SDO->sizeTran > sizeInOd) ? CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; return false; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } - } - else { + } else { /* Verify if size of data downloaded is not too large. */ if ((SDO->sizeInd > 0U) && (SDO->sizeTran > SDO->sizeInd)) { *abortCode = CO_SDO_AB_DATA_LONG; @@ -535,7 +461,7 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, } } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 /* calculate crc on current data */ if (SDO->block_crcEnabled && crcOperation > 0) { SDO->block_crc = crc16_ccitt(SDO->buf, bufOffsetWrOrig, SDO->block_crc); @@ -547,14 +473,15 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, } #endif /* may be unused */ - (void) crcOperation; (void) crcClient; (void) bufOffsetWrOrig; + (void)crcOperation; + (void)crcClient; + (void)bufOffsetWrOrig; /* write data */ OD_size_t countWritten = 0; CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, - SDO->bufOffsetWr, &countWritten); + ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, SDO->bufOffsetWr, &countWritten); CO_UNLOCK_OD(SDO->CANdevTx); SDO->bufOffsetWr = 0; @@ -564,25 +491,22 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, *abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); SDO->state = CO_SDO_ST_ABORT; return false; - } - else if (SDO->finished && (odRet == ODR_PARTIAL)) { + } else if (SDO->finished && (odRet == ODR_PARTIAL)) { /* OD variable was not written completely, but SDO download finished */ *abortCode = CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; return false; - } - else if (!SDO->finished && (odRet == ODR_OK)) { + } else if (!SDO->finished && (odRet == ODR_OK)) { /* OD variable was written completely, but SDO download still has data*/ *abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; return false; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } return true; } - /** Helper function for reading data from Object dictionary. Function also swaps * data if necessary and calcualtes CRC. * @@ -594,13 +518,10 @@ static bool_t validateAndWriteToOD(CO_SDOserver_t *SDO, * * Returns true on success, otherwise write also abortCode and sets state to * CO_SDO_ST_ABORT */ -static bool_t readFromOd(CO_SDOserver_t *SDO, - CO_SDO_abortCode_t *abortCode, - OD_size_t countMinimum, - bool_t calculateCrc) -{ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) == 0 - (void)calculateCrc; /* may be unused */ +static bool_t +readFromOd(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, OD_size_t countMinimum, bool_t calculateCrc) { +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) == 0 + (void)calculateCrc; /* may be unused */ #endif OD_size_t countRemain = SDO->bufOffsetWr - SDO->bufOffsetRd; @@ -617,8 +538,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, OD_size_t countRd = 0; CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->buf[countRemain], - countRdRequest, &countRd); + ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->buf[countRemain], countRdRequest, &countRd); CO_UNLOCK_OD(SDO->CANdevTx); if ((odRet != ODR_OK) && (odRet != ODR_PARTIAL)) { @@ -630,9 +550,11 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, /* if data is string, send only data up to null termination */ OD_size_t lastRd = countRd + countRemain; if ((countRd > 0U) && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U)) { - SDO->buf[lastRd] = 0; /* (SDO->buf is one byte larger) */ - OD_size_t countStr = (OD_size_t)strlen((char *)&SDO->buf[countRemain]); - if (countStr == 0U) { countStr = 1; }/* zero length is not allowed */ + SDO->buf[lastRd] = 0; /* (SDO->buf is one byte larger) */ + OD_size_t countStr = (OD_size_t)strlen((char*)&SDO->buf[countRemain]); + if (countStr == 0U) { + countStr = 1; + } /* zero length is not allowed */ if (countStr < countRd) { /* string terminator found, read is finished, shorten data */ countRd = countStr; @@ -650,8 +572,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_ABORT; return false; } - } - else { + } else { SDO->finished = true; } @@ -661,8 +582,7 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, if (SDO->finished) { /* int16_t .. uint64_t */ reverseBytes(&SDO->buf[countRemain], countRd); - } - else { + } else { *abortCode = CO_SDO_AB_PRAM_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; return false; @@ -670,24 +590,20 @@ static bool_t readFromOd(CO_SDOserver_t *SDO, } #endif -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 /* update the crc */ if (calculateCrc && SDO->block_crcEnabled) { SDO->block_crc = crc16_ccitt(&SDO->buf[countRemain], countRd, SDO->block_crc); } #endif - } return true; } #endif - -CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +CO_SDO_return_t +CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, + uint32_t* timerNext_us) { if (SDO == NULL) { return CO_SDO_RT_wrongArguments; } @@ -698,12 +614,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; bool_t isNew = CO_FLAG_READ(SDO->CANrxNew); - if ((SDO->state == CO_SDO_ST_IDLE) && SDO->valid && !isNew) { /* Idle and nothing new */ ret = CO_SDO_RT_ok_communicationEnd; - } - else if (!NMTisPreOrOperational || !SDO->valid) { + } else if (!NMTisPreOrOperational || !SDO->valid) { /* SDO is allowed only in operational or pre-operational NMT state * and must be valid */ SDO->state = CO_SDO_ST_IDLE; @@ -717,16 +631,14 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if ((SDO->CANrxData[0] & 0xF0U) == 0x20U) { SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ; - } - else if (SDO->CANrxData[0] == 0x40U) { + } else if (SDO->CANrxData[0] == 0x40U) { upload = true; SDO->state = CO_SDO_ST_UPLOAD_INITIATE_REQ; } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 else if ((SDO->CANrxData[0] & 0xF9) == 0xC0) { SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ; - } - else if ((SDO->CANrxData[0] & 0xFB) == 0xA0) { + } else if ((SDO->CANrxData[0] & 0xFB) == 0xA0) { upload = true; SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ; } @@ -739,38 +651,29 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, /* if no error search object dictionary for new SDO request */ if (abortCode == CO_SDO_AB_NONE) { ODR_t odRet; - SDO->index = (uint16_t)((((uint16_t)SDO->CANrxData[2]) << 8) - | SDO->CANrxData[1]); + SDO->index = (uint16_t)((((uint16_t)SDO->CANrxData[2]) << 8) | SDO->CANrxData[1]); SDO->subIndex = SDO->CANrxData[3]; - odRet = OD_getSub(OD_find(SDO->OD, SDO->index), SDO->subIndex, - &SDO->OD_IO, false); + odRet = OD_getSub(OD_find(SDO->OD, SDO->index), SDO->subIndex, &SDO->OD_IO, false); if (odRet != ODR_OK) { abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); SDO->state = CO_SDO_ST_ABORT; - } - else { + } else { /* verify read/write attributes */ if ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_RW) == 0U) { abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; SDO->state = CO_SDO_ST_ABORT; - } - else if (upload - && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_R) == 0U) - ) { + } else if (upload && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_R) == 0U)) { abortCode = CO_SDO_AB_WRITEONLY; SDO->state = CO_SDO_ST_ABORT; - } - else if (!upload - && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_W) == 0U) - ) { + } else if (!upload && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_SDO_W) == 0U)) { abortCode = CO_SDO_AB_READONLY; SDO->state = CO_SDO_ST_ABORT; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 /* load data from object dictionary, if upload and no error */ if (upload && (abortCode == CO_SDO_AB_NONE)) { SDO->bufOffsetRd = 0; @@ -787,426 +690,399 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, if (SDO->sizeInd == 0U) { SDO->sizeInd = SDO->bufOffsetWr; - } - else if (SDO->sizeInd != SDO->bufOffsetWr) { + } else if (SDO->sizeInd != SDO->bufOffsetWr) { abortCode = CO_SDO_AB_DEVICE_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } - } - else { + } else { /* If data type is string, size is not known */ - SDO->sizeInd = ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR)==0U) - ? SDO->OD_IO.stream.dataLength - : 0U; + SDO->sizeInd = ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) == 0U) + ? SDO->OD_IO.stream.dataLength + : 0U; } } } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ } /* (SDO->state == CO_SDO_ST_IDLE) */ bool isOKstate = (SDO->state != CO_SDO_ST_IDLE); isOKstate = (SDO->state != CO_SDO_ST_ABORT) && isOKstate; if (isOKstate) { switch (SDO->state) { - case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { - if ((SDO->CANrxData[0] & 0x02U) != 0U) { - /* Expedited transfer, max 4 bytes of data */ + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: { + if ((SDO->CANrxData[0] & 0x02U) != 0U) { + /* Expedited transfer, max 4 bytes of data */ - /* Size of OD variable (>0 if indicated) */ - OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + /* Size of OD variable (>0 if indicated) */ + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - /* Get SDO data size (indicated by SDO client or get from OD) */ - OD_size_t dataSizeToWrite = 4; - if ((SDO->CANrxData[0] & 0x01U) != 0U) { - dataSizeToWrite -= ((OD_size_t)(SDO->CANrxData[0]) >> 2) & 0x03U; - } - else if ((sizeInOd > 0U) && (sizeInOd < 4U)) { - dataSizeToWrite = sizeInOd; - } - else { /* MISRA C 2004 14.10 */ } - - /* copy data to the temp buffer, swap data if necessary */ - uint8_t buf[6] = {0}; - (void)memcpy(buf, &SDO->CANrxData[4], dataSizeToWrite); - #ifdef CO_BIG_ENDIAN - if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { - reverseBytes(buf, dataSizeToWrite); - } - #endif + /* Get SDO data size (indicated by SDO client or get from OD) */ + OD_size_t dataSizeToWrite = 4; + if ((SDO->CANrxData[0] & 0x01U) != 0U) { + dataSizeToWrite -= ((OD_size_t)(SDO->CANrxData[0]) >> 2) & 0x03U; + } else if ((sizeInOd > 0U) && (sizeInOd < 4U)) { + dataSizeToWrite = sizeInOd; + } else { /* MISRA C 2004 14.10 */ + } + + /* copy data to the temp buffer, swap data if necessary */ + uint8_t buf[6] = {0}; + (void)memcpy(buf, &SDO->CANrxData[4], dataSizeToWrite); +#ifdef CO_BIG_ENDIAN + if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { + reverseBytes(buf, dataSizeToWrite); + } +#endif - /* If dataType is string, then size of data downloaded may be + /* If dataType is string, then size of data downloaded may be * shorter as size of OD data buffer. If so, add two zero bytes * to terminate (unicode) string. Shorten also OD data size, * (temporary, send information about EOF into OD_IO.write) */ - if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) - && ((sizeInOd == 0U) || (dataSizeToWrite < sizeInOd)) - ) { - OD_size_t delta = sizeInOd - dataSizeToWrite; - dataSizeToWrite += (delta == 1U) ? 1U : 2U; - SDO->OD_IO.stream.dataLength = dataSizeToWrite; - } - else if (sizeInOd == 0U) { - SDO->OD_IO.stream.dataLength = dataSizeToWrite; - } - /* Verify if size of data downloaded matches data size in OD. */ - else if (dataSizeToWrite != sizeInOd) { - abortCode = (dataSizeToWrite > sizeInOd) ? - CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) + && ((sizeInOd == 0U) || (dataSizeToWrite < sizeInOd))) { + OD_size_t delta = sizeInOd - dataSizeToWrite; + dataSizeToWrite += (delta == 1U) ? 1U : 2U; + SDO->OD_IO.stream.dataLength = dataSizeToWrite; + } else if (sizeInOd == 0U) { + SDO->OD_IO.stream.dataLength = dataSizeToWrite; + } + /* Verify if size of data downloaded matches data size in OD. */ + else if (dataSizeToWrite != sizeInOd) { + abortCode = (dataSizeToWrite > sizeInOd) ? CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } else { /* MISRA C 2004 14.10 */ + } + + /* Copy data */ + OD_size_t countWritten = 0; + + CO_LOCK_OD(SDO->CANdevTx); + ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, dataSizeToWrite, &countWritten); + CO_UNLOCK_OD(SDO->CANdevTx); + + if (odRet != ODR_OK) { + abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; + } else { + SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + SDO->finished = true; +#endif + } + } else { +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + /* segmented transfer, is size indicated? */ + if ((SDO->CANrxData[0] & 0x01U) != 0U) { + uint32_t size; + OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; + + (void)memcpy((void*)(&size), (const void*)(&SDO->CANrxData[4]), sizeof(size)); + SDO->sizeInd = CO_SWAP_32(size); + + /* Indicated size of SDO matches sizeof OD variable? */ + if (sizeInOd > 0U) { + if (SDO->sizeInd > sizeInOd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } + /* strings are allowed to be shorter */ + else if ((SDO->sizeInd < sizeInOd) + && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) == 0U)) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } else { /* MISRA C 2004 14.10 */ + } + } + } else { + SDO->sizeInd = 0; + } + SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; + SDO->finished = false; +#else + abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; SDO->state = CO_SDO_ST_ABORT; - break; +#endif } - else { /* MISRA C 2004 14.10 */ } + break; + } + +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { + if ((SDO->CANrxData[0] & 0xE0U) == 0x00U) { + SDO->finished = (SDO->CANrxData[0] & 0x01U) != 0U; + + /* verify and alternate toggle bit */ + uint8_t toggle = SDO->CANrxData[0] & 0x10U; + if (toggle != SDO->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO->state = CO_SDO_ST_ABORT; + break; + } - /* Copy data */ - OD_size_t countWritten = 0; + /* get data size and write data to the buffer */ + OD_size_t count = (OD_size_t)(7U - (((OD_size_t)(SDO->CANrxData[0]) >> 1) & 0x07U)); + (void)memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); + SDO->bufOffsetWr += count; + SDO->sizeTran += count; + + /* if data size exceeds variable size, abort */ + if ((SDO->OD_IO.stream.dataLength > 0U) && (SDO->sizeTran > SDO->OD_IO.stream.dataLength)) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } - CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, - dataSizeToWrite, &countWritten); - CO_UNLOCK_OD(SDO->CANdevTx); + /* if necessary, empty the buffer */ + if (SDO->finished || ((CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr) < (7U + 2U))) { + if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) { + break; + } + } - if (odRet != ODR_OK) { - abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; + } else { + abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; - break; } - else { - SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; - #if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - SDO->finished = true; - #endif + break; + } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + + case CO_SDO_ST_UPLOAD_INITIATE_REQ: { + SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; + break; + } + +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { + if ((SDO->CANrxData[0] & 0xEFU) == 0x60U) { + /* verify and alternate toggle bit */ + uint8_t toggle = SDO->CANrxData[0] & 0x10U; + if (toggle != SDO->toggle) { + abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO->state = CO_SDO_ST_ABORT; + break; + } + SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; + } else { + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; } + break; } - else { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - /* segmented transfer, is size indicated? */ - if ((SDO->CANrxData[0] & 0x01U) != 0U) { +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { + SDO->block_crcEnabled = (SDO->CANrxData[0] & 0x04) != 0; + + /* is size indicated? */ + if ((SDO->CANrxData[0] & 0x02) != 0) { uint32_t size; OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - (void)memcpy((void *)(&size), (const void *)(&SDO->CANrxData[4]), sizeof(size)); + (void)memcpy(&size, &SDO->CANrxData[4], sizeof(size)); SDO->sizeInd = CO_SWAP_32(size); /* Indicated size of SDO matches sizeof OD variable? */ - if (sizeInOd > 0U) { + if (sizeInOd > 0) { if (SDO->sizeInd > sizeInOd) { abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; break; } /* strings are allowed to be shorter */ - else if ((SDO->sizeInd < sizeInOd) - && ((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) == 0U) - ) { + else if (SDO->sizeInd < sizeInOd && (SDO->OD_IO.stream.attribute & ODA_STR) == 0) { abortCode = CO_SDO_AB_DATA_SHORT; SDO->state = CO_SDO_ST_ABORT; break; } - else { /* MISRA C 2004 14.10 */ } - } - } - else { + } + } else { SDO->sizeInd = 0; } - SDO->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP; + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; SDO->finished = false; -#else - abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS; - SDO->state = CO_SDO_ST_ABORT; -#endif + break; } - break; - } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: { - if ((SDO->CANrxData[0] & 0xE0U) == 0x00U) { - SDO->finished = (SDO->CANrxData[0] & 0x01U) != 0U; - - /* verify and alternate toggle bit */ - uint8_t toggle = SDO->CANrxData[0] & 0x10U; - if (toggle != SDO->toggle) { - abortCode = CO_SDO_AB_TOGGLE_BIT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - - /* get data size and write data to the buffer */ - OD_size_t count = (OD_size_t)(7U - (((OD_size_t)(SDO->CANrxData[0]) >> 1) & 0x07U)); - (void)memcpy(SDO->buf + SDO->bufOffsetWr, &SDO->CANrxData[1], count); - SDO->bufOffsetWr += count; - SDO->sizeTran += count; - - /* if data size exceeds variable size, abort */ - if ((SDO->OD_IO.stream.dataLength > 0U) - && (SDO->sizeTran > SDO->OD_IO.stream.dataLength) - ) { - abortCode = CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; - } + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { + /* data are copied directly in the receive function */ + break; + } - /* if necessary, empty the buffer */ - if (SDO->finished - || ((CO_CONFIG_SDO_SRV_BUFFER_SIZE - SDO->bufOffsetWr)<(7U+2U)) - ) { - if (!validateAndWriteToOD(SDO, &abortCode, 0, 0)) { + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { + if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { + /* Get number of data bytes in last segment, that do not + * contain data. Then reduce buffer. */ + uint8_t noData = ((SDO->CANrxData[0] >> 2) & 0x07); + if (SDO->bufOffsetWr <= noData) { + /* just in case, should never happen */ + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + SDO->state = CO_SDO_ST_ABORT; break; } - } + SDO->sizeTran -= noData; + SDO->bufOffsetWr -= noData; - SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; - } - break; - } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + uint16_t crcClient = 0; + if (SDO->block_crcEnabled) { + crcClient = ((uint16_t)SDO->CANrxData[2]) << 8; + crcClient |= SDO->CANrxData[1]; + } - case CO_SDO_ST_UPLOAD_INITIATE_REQ: { - SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; - break; - } + if (!validateAndWriteToOD(SDO, &abortCode, 2, crcClient)) { + break; + } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: { - if ((SDO->CANrxData[0] & 0xEFU) == 0x60U) { - /* verify and alternate toggle bit */ - uint8_t toggle = SDO->CANrxData[0] & 0x10U; - if (toggle != SDO->toggle) { - abortCode = CO_SDO_AB_TOGGLE_BIT; + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; + } else { + abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; - break; } - SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; + break; } - break; - } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: { - SDO->block_crcEnabled = (SDO->CANrxData[0] & 0x04) != 0; - /* is size indicated? */ - if ((SDO->CANrxData[0] & 0x02) != 0) { - uint32_t size; - OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - - (void)memcpy(&size, &SDO->CANrxData[4], sizeof(size)); - SDO->sizeInd = CO_SWAP_32(size); + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { + /* if pst (protocol switch threshold, byte5) is larger than data + * size of OD variable, then switch to segmented transfer */ + if (SDO->sizeInd > 0 && SDO->CANrxData[5] > 0 && SDO->CANrxData[5] >= SDO->sizeInd) { + SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; + } else { + /* data were already loaded from OD variable, verify crc */ + if ((SDO->CANrxData[0] & 0x04) != 0) { + SDO->block_crcEnabled = true; + SDO->block_crc = crc16_ccitt(SDO->buf, SDO->bufOffsetWr, 0); + } else { + SDO->block_crcEnabled = false; + } - /* Indicated size of SDO matches sizeof OD variable? */ - if (sizeInOd > 0) { - if (SDO->sizeInd > sizeInOd) { - abortCode = CO_SDO_AB_DATA_LONG; + /* get blksize and verify it */ + SDO->block_blksize = SDO->CANrxData[4]; + if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { + abortCode = CO_SDO_AB_BLOCK_SIZE; SDO->state = CO_SDO_ST_ABORT; break; } - /* strings are allowed to be shorter */ - else if (SDO->sizeInd < sizeInOd - && (SDO->OD_IO.stream.attribute & ODA_STR) == 0 - ) { - abortCode = CO_SDO_AB_DATA_SHORT; + + /* verify, if there is enough data */ + if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize * 7U) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; SDO->state = CO_SDO_ST_ABORT; break; } + SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; } + break; } - else { - SDO->sizeInd = 0; - } - SDO->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP; - SDO->finished = false; - break; - } - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: { - /* data are copied directly in the receive function */ - break; - } - - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { - if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { - /* Get number of data bytes in last segment, that do not - * contain data. Then reduce buffer. */ - uint8_t noData = ((SDO->CANrxData[0] >> 2) & 0x07); - if (SDO->bufOffsetWr <= noData) { - /* just in case, should never happen */ - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { + if (SDO->CANrxData[0] == 0xA3) { + SDO->block_seqno = 0; + SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + } else { + abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; - break; } - SDO->sizeTran -= noData; - SDO->bufOffsetWr -= noData; - - uint16_t crcClient = 0; - if (SDO->block_crcEnabled) { - crcClient = ((uint16_t) SDO->CANrxData[2]) << 8; - crcClient |= SDO->CANrxData[1]; - } - - if (!validateAndWriteToOD(SDO, &abortCode, 2, crcClient)) - break; - - SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; - } - break; - } - - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { - /* if pst (protocol switch threshold, byte5) is larger than data - * size of OD variable, then switch to segmented transfer */ - if (SDO->sizeInd > 0 && SDO->CANrxData[5] > 0 - && SDO->CANrxData[5] >= SDO->sizeInd) - { - SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; + break; } - else { - /* data were already loaded from OD variable, verify crc */ - if ((SDO->CANrxData[0] & 0x04) != 0) { - SDO->block_crcEnabled = true; - SDO->block_crc = crc16_ccitt(SDO->buf, SDO->bufOffsetWr, 0); - } - else { - SDO->block_crcEnabled = false; - } - - /* get blksize and verify it */ - SDO->block_blksize = SDO->CANrxData[4]; - if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { - abortCode = CO_SDO_AB_BLOCK_SIZE; - SDO->state = CO_SDO_ST_ABORT; - break; - } - /* verify, if there is enough data */ - if (!SDO->finished && SDO->bufOffsetWr < SDO->block_blksize*7U){ - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - SDO->state = CO_SDO_ST_ABORT; - break; - } - SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP; - } - break; - } + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { + if (SDO->CANrxData[0] == 0xA2) { + SDO->block_blksize = SDO->CANrxData[2]; + if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { + abortCode = CO_SDO_AB_BLOCK_SIZE; + SDO->state = CO_SDO_ST_ABORT; + break; + } - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: { - if (SDO->CANrxData[0] == 0xA3) { - SDO->block_seqno = 0; - SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; - } - break; - } + /* check number of segments */ + if (SDO->CANrxData[1] < SDO->block_seqno) { + /* NOT all segments transferred successfully. + * Re-transmit data after erroneous segment. */ + OD_size_t cntFailed = SDO->block_seqno - SDO->CANrxData[1]; + cntFailed = cntFailed * 7 - SDO->block_noData; + SDO->bufOffsetRd -= cntFailed; + SDO->sizeTran -= cntFailed; + } else if (SDO->CANrxData[1] > SDO->block_seqno) { + /* something strange from server, break transmission */ + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; + break; + } - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: { - if (SDO->CANrxData[0] == 0xA2) { - SDO->block_blksize = SDO->CANrxData[2]; - if (SDO->block_blksize < 1 || SDO->block_blksize > 127) { - abortCode = CO_SDO_AB_BLOCK_SIZE; - SDO->state = CO_SDO_ST_ABORT; - break; - } + /* refill data buffer if necessary */ + if (!readFromOd(SDO, &abortCode, SDO->block_blksize * 7, true)) { + break; + } - /* check number of segments */ - if (SDO->CANrxData[1] < SDO->block_seqno) { - /* NOT all segments transferred successfully. - * Re-transmit data after erroneous segment. */ - OD_size_t cntFailed = SDO->block_seqno - SDO->CANrxData[1]; - cntFailed = cntFailed * 7 - SDO->block_noData; - SDO->bufOffsetRd -= cntFailed; - SDO->sizeTran -= cntFailed; - } - else if (SDO->CANrxData[1] > SDO->block_seqno) { - /* something strange from server, break transmission */ + if (SDO->bufOffsetWr == SDO->bufOffsetRd) { + SDO->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; + } else { + SDO->block_seqno = 0; + SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; + } + } else { abortCode = CO_SDO_AB_CMD; SDO->state = CO_SDO_ST_ABORT; - break; } - - /* refill data buffer if necessary */ - if (!readFromOd(SDO, &abortCode, SDO->block_blksize * 7, true)) - break; - - - if (SDO->bufOffsetWr == SDO->bufOffsetRd) { - SDO->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ; - } - else { - SDO->block_seqno = 0; - SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; - } - } - else { - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; + break; } - break; - } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ - case CO_SDO_ST_IDLE: - case CO_SDO_ST_ABORT: - case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: - case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_UPLOAD_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_BLK_END_SREQ: - case CO_SDO_ST_UPLOAD_BLK_END_CRSP: - -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) == 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: + +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) == 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) == 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) == 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ - default: { - /* unknown message received */ - abortCode = CO_SDO_AB_CMD; - SDO->state = CO_SDO_ST_ABORT; - break; - } + default: { + /* unknown message received */ + abortCode = CO_SDO_AB_CMD; + SDO->state = CO_SDO_ST_ABORT; + break; + } } /* switch (SDO->state) */ - } /* if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) */ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + } /* if (SDO->state != CO_SDO_ST_IDLE && SDO->state != CO_SDO_ST_ABORT) */ +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 SDO->timeoutTimer = 0; #endif timeDifference_us = 0; CO_FLAG_CLEAR(SDO->CANrxNew); - } /* else if (isNew) */ - else { /* MISRA C 2004 14.10 */ } + } /* else if (isNew) */ + else { /* MISRA C 2004 14.10 */ + } /* Timeout timers and transmit bufferFull flag ****************************/ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 if (ret == CO_SDO_RT_waitingResponse) { if (SDO->timeoutTimer < SDO->SDOtimeoutTime_us) { SDO->timeoutTimer += timeDifference_us; @@ -1215,7 +1091,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, abortCode = CO_SDO_AB_TIMEOUT; SDO->state = CO_SDO_ST_ABORT; } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ uint32_t diff = SDO->SDOtimeoutTime_us - SDO->timeoutTimer; @@ -1225,7 +1101,7 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, } #endif -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 /* Timeout for sub-block transmission */ if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { if (SDO->block_timeoutTimer < SDO->block_SDOtimeoutTime_us) { @@ -1237,11 +1113,10 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; CO_FLAG_CLEAR(SDO->CANrxNew); } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_TIMERNEXT) != 0 else if (timerNext_us != NULL) { /* check again after timeout time elapsed */ - uint32_t diff = SDO->block_SDOtimeoutTime_us - - SDO->block_timeoutTimer; + uint32_t diff = SDO->block_SDOtimeoutTime_us - SDO->block_timeoutTimer; if (*timerNext_us > diff) { *timerNext_us = diff; } @@ -1262,395 +1137,372 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, (void)memset(SDO->CANtxBuff->data, 0, sizeof(SDO->CANtxBuff->data)); switch (SDO->state) { - case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { - SDO->CANtxBuff->data[0] = 0x60; - SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; - SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); - SDO->CANtxBuff->data[3] = SDO->subIndex; - - /* reset timeout timer and send message */ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - SDO->timeoutTimer = 0; + case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: { + SDO->CANtxBuff->data[0] = 0x60; + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; + + /* reset timeout timer and send message */ +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + SDO->timeoutTimer = 0; #endif - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - if (SDO->finished) { + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + if (SDO->finished) { + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } else { + SDO->toggle = 0x00; + SDO->sizeTran = 0; + SDO->bufOffsetWr = 0; + SDO->bufOffsetRd = 0; + SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; + } +#else SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_ok_communicationEnd; - } - else { - SDO->toggle = 0x00; - SDO->sizeTran = 0; - SDO->bufOffsetWr = 0; - SDO->bufOffsetRd = 0; - SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; - } -#else - SDO->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; #endif - break; - } + break; + } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { - SDO->CANtxBuff->data[0] = 0x20U | SDO->toggle; - SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: { + SDO->CANtxBuff->data[0] = 0x20U | SDO->toggle; + SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; - /* reset timeout timer and send message */ - SDO->timeoutTimer = 0; - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - if (SDO->finished) { - SDO->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; - } - else { - SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + if (SDO->finished) { + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } else { + SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ; + } + break; } - break; - } #endif - case CO_SDO_ST_UPLOAD_INITIATE_RSP: { -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - /* data were already loaded from OD variable */ - if ((SDO->sizeInd > 0U) && (SDO->sizeInd <= 4U)) { - /* expedited transfer */ - SDO->CANtxBuff->data[0] = (uint8_t)(0x43U|((4U-SDO->sizeInd)<<2U)); - (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), (const void *)(&SDO->buf[0]), SDO->sizeInd); - SDO->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; - } - else { - /* data will be transferred with segmented transfer */ - if (SDO->sizeInd > 0U) { - /* indicate data size, if known */ - uint32_t sizeInd = SDO->sizeInd; - uint32_t sizeIndSw = CO_SWAP_32(sizeInd); - SDO->CANtxBuff->data[0] = 0x41; - (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), - (const void *)(&sizeIndSw), sizeof(sizeIndSw)); - } - else { - SDO->CANtxBuff->data[0] = 0x40; + case CO_SDO_ST_UPLOAD_INITIATE_RSP: { +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + /* data were already loaded from OD variable */ + if ((SDO->sizeInd > 0U) && (SDO->sizeInd <= 4U)) { + /* expedited transfer */ + SDO->CANtxBuff->data[0] = (uint8_t)(0x43U | ((4U - SDO->sizeInd) << 2U)); + (void)memcpy((void*)(&SDO->CANtxBuff->data[4]), (const void*)(&SDO->buf[0]), SDO->sizeInd); + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } else { + /* data will be transferred with segmented transfer */ + if (SDO->sizeInd > 0U) { + /* indicate data size, if known */ + uint32_t sizeInd = SDO->sizeInd; + uint32_t sizeIndSw = CO_SWAP_32(sizeInd); + SDO->CANtxBuff->data[0] = 0x41; + (void)memcpy((void*)(&SDO->CANtxBuff->data[4]), (const void*)(&sizeIndSw), sizeof(sizeIndSw)); + } else { + SDO->CANtxBuff->data[0] = 0x40; + } + SDO->toggle = 0x00; + SDO->timeoutTimer = 0; + SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; } - SDO->toggle = 0x00; - SDO->timeoutTimer = 0; - SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; - } #else /* Expedited transfer only */ - /* load data from OD variable */ - OD_size_t count = 0; - - CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, - &SDO->CANtxBuff->data[4], 4, &count); - CO_UNLOCK_OD(SDO->CANdevTx); - - /* strings are allowed to be shorter */ - if (odRet == ODR_PARTIAL - && (SDO->OD_IO.stream.attribute & ODA_STR) != 0 - ) { - odRet = ODR_OK; - } + /* load data from OD variable */ + OD_size_t count = 0; - if (odRet != ODR_OK || count == 0) { - abortCode = (odRet == ODR_OK) ? CO_SDO_AB_DEVICE_INCOMPAT : - (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); - SDO->state = CO_SDO_ST_ABORT; - break; - } + CO_LOCK_OD(SDO->CANdevTx); + ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->CANtxBuff->data[4], 4, &count); + CO_UNLOCK_OD(SDO->CANdevTx); + + /* strings are allowed to be shorter */ + if (odRet == ODR_PARTIAL && (SDO->OD_IO.stream.attribute & ODA_STR) != 0) { + odRet = ODR_OK; + } + + if (odRet != ODR_OK || count == 0) { + abortCode = (odRet == ODR_OK) ? CO_SDO_AB_DEVICE_INCOMPAT + : (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); + SDO->state = CO_SDO_ST_ABORT; + break; + } #ifdef CO_BIG_ENDIAN - /* swap data if necessary */ - if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { - reverseBytes(buf, dataSizeToWrite); - } + /* swap data if necessary */ + if ((SDO->OD_IO.stream.attribute & ODA_MB) != 0) { + reverseBytes(buf, dataSizeToWrite); + } #endif - SDO->CANtxBuff->data[0] = 0x43 | ((4 - count) << 2); - SDO->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; + SDO->CANtxBuff->data[0] = 0x43 | ((4 - count) << 2); + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - /* send message */ - SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; - SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); - SDO->CANtxBuff->data[3] = SDO->subIndex; - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - break; - } - -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0 - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { - /* refill the data buffer if necessary */ - if (!readFromOd(SDO, &abortCode, 7, false)) { + /* send message */ + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); break; } - /* SDO command specifier with toggle bit */ - SDO->CANtxBuff->data[0] = SDO->toggle; - SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; - - OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; - /* verify, if this is the last segment */ - if ((count < 7U) || (SDO->finished && (count == 7U))) { - /* indicate last segment and nnn */ - SDO->CANtxBuff->data[0] |= (uint8_t)(((7U - count) << 1U) | 0x01U); - SDO->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; - } - else { - SDO->timeoutTimer = 0; - SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; - count = 7; - } - - /* copy data segment to CAN message */ - (void)memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, - count); - SDO->bufOffsetRd += count; - SDO->sizeTran += count; - - /* verify if sizeTran is too large or too short if last segment */ - if (SDO->sizeInd > 0U) { - if (SDO->sizeTran > SDO->sizeInd) { - abortCode = CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: { + /* refill the data buffer if necessary */ + if (!readFromOd(SDO, &abortCode, 7, false)) { break; } - else if ((ret == CO_SDO_RT_ok_communicationEnd) - && (SDO->sizeTran < SDO->sizeInd) - ) { - abortCode = CO_SDO_AB_DATA_SHORT; - ret = CO_SDO_RT_waitingResponse; - SDO->state = CO_SDO_ST_ABORT; - break; + + /* SDO command specifier with toggle bit */ + SDO->CANtxBuff->data[0] = SDO->toggle; + SDO->toggle = (SDO->toggle == 0x00U) ? 0x10U : 0x00U; + + OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; + /* verify, if this is the last segment */ + if ((count < 7U) || (SDO->finished && (count == 7U))) { + /* indicate last segment and nnn */ + SDO->CANtxBuff->data[0] |= (uint8_t)(((7U - count) << 1U) | 0x01U); + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + } else { + SDO->timeoutTimer = 0; + SDO->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ; + count = 7; } - else { /* MISRA C 2004 14.10 */ } - } - /* send message */ - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - break; - } -#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ + /* copy data segment to CAN message */ + (void)memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, count); + SDO->bufOffsetRd += count; + SDO->sizeTran += count; -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { - SDO->CANtxBuff->data[0] = 0xA4; - SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; - SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); - SDO->CANtxBuff->data[3] = SDO->subIndex; + /* verify if sizeTran is too large or too short if last segment */ + if (SDO->sizeInd > 0U) { + if (SDO->sizeTran > SDO->sizeInd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } else if ((ret == CO_SDO_RT_ok_communicationEnd) && (SDO->sizeTran < SDO->sizeInd)) { + abortCode = CO_SDO_AB_DATA_SHORT; + ret = CO_SDO_RT_waitingResponse; + SDO->state = CO_SDO_ST_ABORT; + break; + } else { /* MISRA C 2004 14.10 */ + } + } - /* calculate number of block segments from free buffer space */ - OD_size_t count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE-2) / 7; - if (count > 127) { - count = 127; + /* send message */ + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + break; } - SDO->block_blksize = (uint8_t)count; - SDO->CANtxBuff->data[4] = SDO->block_blksize; - - /* reset variables */ - SDO->sizeTran = 0; - SDO->finished = false; - SDO->bufOffsetWr = 0; - SDO->bufOffsetRd = 0; - SDO->block_seqno = 0; - SDO->block_crc = 0; - SDO->timeoutTimer = 0; - SDO->block_timeoutTimer = 0; - - /* Block segments will be received in different thread. Make memory - * barrier here with CO_FLAG_CLEAR() call. */ - SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; - CO_FLAG_CLEAR(SDO->CANrxNew); - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - break; - } +#endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED */ - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { - SDO->CANtxBuff->data[0] = 0xA2; - SDO->CANtxBuff->data[1] = SDO->block_seqno; -#ifdef CO_DEBUG_SDO_SERVER - bool_t transferShort = SDO->block_seqno != SDO->block_blksize; - uint8_t seqnoStart = SDO->block_seqno; -#endif +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: { + SDO->CANtxBuff->data[0] = 0xA4; + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; - /* Is last segment? */ - if (SDO->finished) { - SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_REQ; - } - else { /* calculate number of block segments from free buffer space */ - OD_size_t count; - count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE-2-SDO->bufOffsetWr)/7; - if (count >= 127) { + OD_size_t count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE - 2) / 7; + if (count > 127) { count = 127; } - else if (SDO->bufOffsetWr > 0) { - /* it is necessary to empty the buffer */ - if (!validateAndWriteToOD(SDO, &abortCode, 1, 0)) - break; - - count =(CO_CONFIG_SDO_SRV_BUFFER_SIZE-2-SDO->bufOffsetWr)/7; - if (count >= 127) { - count = 127; - } - } - SDO->block_blksize = (uint8_t)count; + SDO->CANtxBuff->data[4] = SDO->block_blksize; + + /* reset variables */ + SDO->sizeTran = 0; + SDO->finished = false; + SDO->bufOffsetWr = 0; + SDO->bufOffsetRd = 0; SDO->block_seqno = 0; - /* Block segments will be received in different thread. Make - * memory barrier here with CO_FLAG_CLEAR() call. */ + SDO->block_crc = 0; + SDO->timeoutTimer = 0; + SDO->block_timeoutTimer = 0; + + /* Block segments will be received in different thread. Make memory + * barrier here with CO_FLAG_CLEAR() call. */ SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; CO_FLAG_CLEAR(SDO->CANrxNew); + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + break; } - SDO->CANtxBuff->data[2] = SDO->block_blksize; - - /* reset block_timeoutTimer, but not SDO->timeoutTimer */ - SDO->block_timeoutTimer = 0; - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: { + SDO->CANtxBuff->data[0] = 0xA2; + SDO->CANtxBuff->data[1] = SDO->block_seqno; #ifdef CO_DEBUG_SDO_SERVER - if (transferShort && !SDO->finished) { - char msg[80]; - sprintf(msg, - "sub-block restarted: sequnoPrev=%02X, blksize=%02X", - seqnoStart, SDO->block_blksize); - CO_DEBUG_SDO_SERVER(msg); - } + bool_t transferShort = SDO->block_seqno != SDO->block_blksize; + uint8_t seqnoStart = SDO->block_seqno; #endif - break; - } - case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { - SDO->CANtxBuff->data[0] = 0xA1; + /* Is last segment? */ + if (SDO->finished) { + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_END_REQ; + } else { + /* calculate number of block segments from free buffer space */ + OD_size_t count; + count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE - 2 - SDO->bufOffsetWr) / 7; + if (count >= 127) { + count = 127; + } else if (SDO->bufOffsetWr > 0) { + /* it is necessary to empty the buffer */ + if (!validateAndWriteToOD(SDO, &abortCode, 1, 0)) { + break; + } - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - SDO->state = CO_SDO_ST_IDLE; - ret = CO_SDO_RT_ok_communicationEnd; - break; - } + count = (CO_CONFIG_SDO_SRV_BUFFER_SIZE - 2 - SDO->bufOffsetWr) / 7; + if (count >= 127) { + count = 127; + } + } - case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { - SDO->CANtxBuff->data[0] = 0xC4; - SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; - SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); - SDO->CANtxBuff->data[3] = SDO->subIndex; + SDO->block_blksize = (uint8_t)count; + SDO->block_seqno = 0; + /* Block segments will be received in different thread. Make + * memory barrier here with CO_FLAG_CLEAR() call. */ + SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; + CO_FLAG_CLEAR(SDO->CANrxNew); + } + + SDO->CANtxBuff->data[2] = SDO->block_blksize; - /* indicate data size */ - if (SDO->sizeInd > 0) { - uint32_t size = CO_SWAP_32(SDO->sizeInd); - SDO->CANtxBuff->data[0] |= 0x02; - (void)memcpy(&SDO->CANtxBuff->data[4], &size, sizeof(size)); + /* reset block_timeoutTimer, but not SDO->timeoutTimer */ + SDO->block_timeoutTimer = 0; + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); +#ifdef CO_DEBUG_SDO_SERVER + if (transferShort && !SDO->finished) { + char msg[80]; + sprintf(msg, "sub-block restarted: sequnoPrev=%02X, blksize=%02X", seqnoStart, SDO->block_blksize); + CO_DEBUG_SDO_SERVER(msg); + } +#endif + break; } - /* reset timeout timer and send message */ - SDO->timeoutTimer = 0; - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; - break; - } + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: { + SDO->CANtxBuff->data[0] = 0xA1; - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: { - /* write header and get current count */ - SDO->CANtxBuff->data[0] = ++SDO->block_seqno; - OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; - /* verify, if this is the last segment */ - if (count < 7 || (SDO->finished && count == 7)) { - SDO->CANtxBuff->data[0] |= 0x80; + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + SDO->state = CO_SDO_ST_IDLE; + ret = CO_SDO_RT_ok_communicationEnd; + break; } - else { - count = 7; + + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: { + SDO->CANtxBuff->data[0] = 0xC4; + SDO->CANtxBuff->data[1] = (uint8_t)SDO->index; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); + SDO->CANtxBuff->data[3] = SDO->subIndex; + + /* indicate data size */ + if (SDO->sizeInd > 0) { + uint32_t size = CO_SWAP_32(SDO->sizeInd); + SDO->CANtxBuff->data[0] |= 0x02; + (void)memcpy(&SDO->CANtxBuff->data[4], &size, sizeof(size)); + } + + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + SDO->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2; + break; } - /* copy data segment to CAN message */ - (void)memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, - count); - SDO->bufOffsetRd += count; - SDO->block_noData = (uint8_t)(7 - count); - SDO->sizeTran += count; - - /* verify if sizeTran is too large or too short if last segment */ - if (SDO->sizeInd > 0) { - if (SDO->sizeTran > SDO->sizeInd) { - abortCode = CO_SDO_AB_DATA_LONG; - SDO->state = CO_SDO_ST_ABORT; - break; + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: { + /* write header and get current count */ + SDO->CANtxBuff->data[0] = ++SDO->block_seqno; + OD_size_t count = SDO->bufOffsetWr - SDO->bufOffsetRd; + /* verify, if this is the last segment */ + if (count < 7 || (SDO->finished && count == 7)) { + SDO->CANtxBuff->data[0] |= 0x80; + } else { + count = 7; } - else if (SDO->bufOffsetWr == SDO->bufOffsetRd - && SDO->sizeTran < SDO->sizeInd - ) { - abortCode = CO_SDO_AB_DATA_SHORT; - SDO->state = CO_SDO_ST_ABORT; - break; + + /* copy data segment to CAN message */ + (void)memcpy(&SDO->CANtxBuff->data[1], SDO->buf + SDO->bufOffsetRd, count); + SDO->bufOffsetRd += count; + SDO->block_noData = (uint8_t)(7 - count); + SDO->sizeTran += count; + + /* verify if sizeTran is too large or too short if last segment */ + if (SDO->sizeInd > 0) { + if (SDO->sizeTran > SDO->sizeInd) { + abortCode = CO_SDO_AB_DATA_LONG; + SDO->state = CO_SDO_ST_ABORT; + break; + } else if (SDO->bufOffsetWr == SDO->bufOffsetRd && SDO->sizeTran < SDO->sizeInd) { + abortCode = CO_SDO_AB_DATA_SHORT; + SDO->state = CO_SDO_ST_ABORT; + break; + } } - } - /* is last segment or all segments in current block transferred? */ - if (SDO->bufOffsetWr == SDO->bufOffsetRd - || SDO->block_seqno >= SDO->block_blksize - ) { - SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; - } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - else { - /* Inform OS to call this function again without delay. */ - if (timerNext_us != NULL) { - *timerNext_us = 0; + /* is last segment or all segments in current block transferred? */ + if (SDO->bufOffsetWr == SDO->bufOffsetRd || SDO->block_seqno >= SDO->block_blksize) { + SDO->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; + } +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_TIMERNEXT) != 0 + else { + /* Inform OS to call this function again without delay. */ + if (timerNext_us != NULL) { + *timerNext_us = 0; + } } - } #endif - /* reset timeout timer and send message */ - SDO->timeoutTimer = 0; - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - break; - } + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + break; + } - case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { - SDO->CANtxBuff->data[0] = 0xC1 | (SDO->block_noData << 2); - SDO->CANtxBuff->data[1] = (uint8_t) SDO->block_crc; - SDO->CANtxBuff->data[2] = (uint8_t) (SDO->block_crc >> 8); + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: { + SDO->CANtxBuff->data[0] = 0xC1 | (SDO->block_noData << 2); + SDO->CANtxBuff->data[1] = (uint8_t)SDO->block_crc; + SDO->CANtxBuff->data[2] = (uint8_t)(SDO->block_crc >> 8); - /* reset timeout timer and send message */ - SDO->timeoutTimer = 0; - (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); - SDO->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; - break; - } + /* reset timeout timer and send message */ + SDO->timeoutTimer = 0; + (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); + SDO->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP; + break; + } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) == 0 - case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: - case CO_SDO_ST_UPLOAD_SEGMENT_RSP: +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) == 0 + case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: + case CO_SDO_ST_UPLOAD_SEGMENT_RSP: #endif -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) == 0 - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: - case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: - case CO_SDO_ST_UPLOAD_BLK_END_SREQ: +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) == 0 + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: + case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: + case CO_SDO_ST_UPLOAD_BLK_END_SREQ: #endif - case CO_SDO_ST_IDLE: - case CO_SDO_ST_ABORT: - case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: - case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: - case CO_SDO_ST_UPLOAD_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_SEGMENT_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: - case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: - case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: - case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: - case CO_SDO_ST_UPLOAD_BLK_END_CRSP: - default: { - /* none */ - break; - } + case CO_SDO_ST_IDLE: + case CO_SDO_ST_ABORT: + case CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: + case CO_SDO_ST_UPLOAD_LOCAL_TRANSFER: + case CO_SDO_ST_UPLOAD_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_SEGMENT_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: + case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: + case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: + case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: + case CO_SDO_ST_UPLOAD_BLK_END_CRSP: + default: { + /* none */ + break; + } } /* switch (SDO->state) */ } @@ -1663,16 +1515,15 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, SDO->CANtxBuff->data[2] = (uint8_t)(SDO->index >> 8); SDO->CANtxBuff->data[3] = SDO->subIndex; - (void)memcpy((void *)(&SDO->CANtxBuff->data[4]), (const void *)(&code), sizeof(code)); + (void)memcpy((void*)(&SDO->CANtxBuff->data[4]), (const void*)(&code), sizeof(code)); (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); SDO->state = CO_SDO_ST_IDLE; ret = CO_SDO_RT_endedWithServerAbort; } -#if ((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0 +#if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 else if (SDO->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { ret = CO_SDO_RT_blockDownldInProgress; - } - else if (SDO->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { + } else if (SDO->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) { ret = CO_SDO_RT_blockUploadInProgress; } #endif diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index a1aebdec..19874b3c 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -20,7 +20,7 @@ #include "301/CO_SYNC.h" -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 /* * Read received message from CAN module. @@ -29,26 +29,24 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_SYNC_receive(void *object, void *msg) { - CO_SYNC_t *SYNC = object; +static void +CO_SYNC_receive(void* object, void* msg) { + CO_SYNC_t* SYNC = object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); bool_t syncReceived = false; if (SYNC->counterOverflowValue == 0U) { if (DLC == 0U) { syncReceived = true; - } - else { + } else { SYNC->receiveError = DLC | 0x40U; } - } - else { + } else { if (DLC == 1U) { - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); SYNC->counter = data[0]; syncReceived = true; - } - else { + } else { SYNC->receiveError = DLC | 0x80U; } } @@ -59,7 +57,7 @@ static void CO_SYNC_receive(void *object, void *msg) { CO_FLAG_SET(SYNC->CANrxNew); -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles SYNC.*/ if (SYNC->pFunctSignalPre != NULL) { SYNC->pFunctSignalPre(SYNC->functSignalObjectPre); @@ -68,32 +66,28 @@ static void CO_SYNC_receive(void *object, void *msg) { } } - -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "COB-ID sync message" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count != sizeof(uint32_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_1005(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint32_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_SYNC_t *SYNC = stream->object; + CO_SYNC_t* SYNC = stream->object; uint32_t cobIdSync = CO_getUint32(buf); uint16_t CAN_ID = (uint16_t)(cobIdSync & 0x7FFU); /* verify written value */ -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 bool_t isProducer = (cobIdSync & 0x40000000U) != 0U; if (((cobIdSync & 0xBFFFF800U) != 0U) || CO_IS_RESTRICTED_CAN_ID(CAN_ID) - || (SYNC->isProducer && isProducer && (CAN_ID != SYNC->CAN_ID)) - ) { + || (SYNC->isProducer && isProducer && (CAN_ID != SYNC->CAN_ID))) { return ODR_INVALID_VALUE; } #else @@ -104,27 +98,16 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, /* Configure CAN receive and transmit buffers */ if (CAN_ID != SYNC->CAN_ID) { - CO_ReturnError_t CANret = CO_CANrxBufferInit( - SYNC->CANdevRx, - SYNC->CANdevRxIdx, - CAN_ID, - 0x7FF, - false, - (void*)SYNC, - CO_SYNC_receive); + CO_ReturnError_t CANret = CO_CANrxBufferInit(SYNC->CANdevRx, SYNC->CANdevRxIdx, CAN_ID, 0x7FF, false, + (void*)SYNC, CO_SYNC_receive); if (CANret != CO_ERROR_NO) { return ODR_DEV_INCOMPAT; } -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 - SYNC->CANtxBuff = CO_CANtxBufferInit( - SYNC->CANdevTx, - SYNC->CANdevTxIdx, - CAN_ID, - false, - (SYNC->counterOverflowValue != 0U) ? 1U : 0U, - false); +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 + SYNC->CANtxBuff = CO_CANtxBufferInit(SYNC->CANdevTx, SYNC->CANdevTxIdx, CAN_ID, false, + (SYNC->counterOverflowValue != 0U) ? 1U : 0U, false); if (SYNC->CANtxBuff == NULL) { SYNC->isProducer = false; @@ -135,7 +118,7 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, SYNC->CAN_ID = CAN_ID; } -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->isProducer = isProducer; if (isProducer) { SYNC->counter = 0; @@ -147,22 +130,20 @@ static ODR_t OD_write_1005(OD_stream_t *stream, const void *buf, return OD_writeOriginal(stream, buf, count, countWritten); } -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 /* * Custom function for writing OD object "Synchronous counter overflow value" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count != sizeof(uint8_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_1019(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint8_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_SYNC_t *SYNC = stream->object; + CO_SYNC_t* SYNC = stream->object; uint8_t syncCounterOvf = CO_getUint8(buf); /* verify written value */ @@ -174,13 +155,8 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, } /* Configure CAN transmit buffer */ - SYNC->CANtxBuff = CO_CANtxBufferInit( - SYNC->CANdevTx, - SYNC->CANdevTxIdx, - SYNC->CAN_ID, - false, - (syncCounterOvf != 0U) ? 1U : 0U, - false); + SYNC->CANtxBuff = CO_CANtxBufferInit(SYNC->CANdevTx, SYNC->CANdevTxIdx, SYNC->CAN_ID, false, + (syncCounterOvf != 0U) ? 1U : 0U, false); if (SYNC->CANtxBuff == NULL) { SYNC->isProducer = false; @@ -195,30 +171,22 @@ static ODR_t OD_write_1019(OD_stream_t *stream, const void *buf, #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC */ - -CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, - CO_EM_t *em, - OD_entry_t *OD_1005_cobIdSync, - OD_entry_t *OD_1006_commCyclePeriod, - OD_entry_t *OD_1007_syncWindowLen, - OD_entry_t *OD_1019_syncCounterOvf, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, +CO_ReturnError_t +CO_SYNC_init(CO_SYNC_t* SYNC, CO_EM_t* em, OD_entry_t* OD_1005_cobIdSync, OD_entry_t* OD_1006_commCyclePeriod, + OD_entry_t* OD_1007_syncWindowLen, OD_entry_t* OD_1019_syncCounterOvf, CO_CANmodule_t* CANdevRx, + uint16_t CANdevRxIdx, +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, #endif - uint32_t *errInfo) -{ + uint32_t* errInfo) { ODR_t odRet; /* verify arguments */ if ((SYNC == NULL) || (em == NULL) || (OD_1005_cobIdSync == NULL) -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 || (OD_1006_commCyclePeriod == NULL) || (CANdevTx == NULL) #endif - || (CANdevRx == NULL) - ) { + || (CANdevRx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -230,10 +198,12 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, odRet = OD_get_u32(OD_1005_cobIdSync, 0, &cobIdSync, true); if (odRet != ODR_OK) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1005_cobIdSync); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1005_cobIdSync); + } return CO_ERROR_OD_PARAMETERS; } -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SYNC->OD_1005_extension.object = SYNC; SYNC->OD_1005_extension.read = OD_readOriginal; SYNC->OD_1005_extension.write = OD_write_1005; @@ -241,11 +211,10 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, #endif /* get and verify "Communication cycle period" from OD */ - SYNC->OD_1006_period = OD_getPtr(OD_1006_commCyclePeriod, 0, - sizeof(uint32_t), NULL); -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 + SYNC->OD_1006_period = OD_getPtr(OD_1006_commCyclePeriod, 0, sizeof(uint32_t), NULL); +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 if (SYNC->OD_1006_period == NULL) { - if (errInfo != NULL) { + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1006_commCyclePeriod); } return CO_ERROR_OD_PARAMETERS; @@ -260,8 +229,7 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, #endif /* get "Synchronous window length" from OD (optional parameter) */ - SYNC->OD_1007_window = OD_getPtr(OD_1007_syncWindowLen, 0, - sizeof(uint32_t), NULL); + SYNC->OD_1007_window = OD_getPtr(OD_1007_syncWindowLen, 0, sizeof(uint32_t), NULL); if ((OD_1007_syncWindowLen != NULL) && (SYNC->OD_1007_window == NULL)) { if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1007_syncWindowLen); @@ -276,17 +244,20 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, if (OD_1019_syncCounterOvf != NULL) { odRet = OD_get_u8(OD_1019_syncCounterOvf, 0, &syncCounterOvf, true); if (odRet != ODR_OK) { - if (errInfo != NULL) { + if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1019_syncCounterOvf); } return CO_ERROR_OD_PARAMETERS; } - if (syncCounterOvf == 1U) { syncCounterOvf = 2; } - else if (syncCounterOvf > 240U) { syncCounterOvf = 240; } - else { /* MISRA C 2004 14.10 */ } + if (syncCounterOvf == 1U) { + syncCounterOvf = 2; + } else if (syncCounterOvf > 240U) { + syncCounterOvf = 240; + } else { /* MISRA C 2004 14.10 */ + } -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->OD_1019_extension.object = SYNC; SYNC->OD_1019_extension.read = OD_readOriginal; SYNC->OD_1019_extension.write = OD_write_1019; @@ -298,40 +269,29 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, /* Configure object variables */ SYNC->em = em; -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->isProducer = (cobIdSync & 0x40000000U) != 0U; #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SYNC->CAN_ID = (uint16_t)(cobIdSync & 0x7FFU); SYNC->CANdevRx = CANdevRx; SYNC->CANdevRxIdx = CANdevRxIdx; - #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->CANdevTx = CANdevTx; SYNC->CANdevTxIdx = CANdevTxIdx; - #endif +#endif #endif /* configure SYNC CAN reception and transmission */ - CO_ReturnError_t ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - (uint16_t)(cobIdSync & 0x7FFU), - 0x7FF, - false, - (void*)SYNC, - CO_SYNC_receive); + CO_ReturnError_t ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, (uint16_t)(cobIdSync & 0x7FFU), 0x7FF, false, + (void*)SYNC, CO_SYNC_receive); if (ret != CO_ERROR_NO) { return ret; } -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 - SYNC->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, - CANdevTxIdx, - (uint16_t)(cobIdSync & 0x7FFU), - false, - (syncCounterOvf != 0U) ? 1U : 0U, - false); +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 + SYNC->CANtxBuff = CO_CANtxBufferInit(CANdevTx, CANdevTxIdx, (uint16_t)(cobIdSync & 0x7FFU), false, + (syncCounterOvf != 0U) ? 1U : 0U, false); if (SYNC->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -341,13 +301,9 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, return CO_ERROR_NO; } - -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_SYNC_initCallbackPre( - CO_SYNC_t *SYNC, - void *object, - void (*pFunctSignalPre)(void *object)) -{ +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_SYNC_initCallbackPre(CO_SYNC_t* SYNC, void* object, void (*pFunctSignalPre)(void* object)) { if (SYNC != NULL) { SYNC->functSignalObjectPre = object; SYNC->pFunctSignalPre = pFunctSignalPre; @@ -355,12 +311,8 @@ void CO_SYNC_initCallbackPre( } #endif - -CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +CO_SYNC_status_t +CO_SYNC_process(CO_SYNC_t* SYNC, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ CO_SYNC_status_t syncStatus = CO_SYNC_NONE; @@ -368,7 +320,9 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, if (NMTisPreOrOperational) { /* update sync timer, no overflow */ uint32_t timerNew = SYNC->timer + timeDifference_us; - if (timerNew > SYNC->timer) { SYNC->timer = timerNew; } + if (timerNew > SYNC->timer) { + SYNC->timer = timerNew; + } /* was SYNC just received */ if (CO_FLAG_READ(SYNC->CANrxNew)) { @@ -377,17 +331,16 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, CO_FLAG_CLEAR(SYNC->CANrxNew); } - uint32_t OD_1006_period = (SYNC->OD_1006_period != NULL) - ? *SYNC->OD_1006_period : 0U; + uint32_t OD_1006_period = (SYNC->OD_1006_period != NULL) ? *SYNC->OD_1006_period : 0U; if (OD_1006_period > 0U) { -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 if (SYNC->isProducer) { if (SYNC->timer >= OD_1006_period) { syncStatus = CO_SYNC_RX_TX; (void)CO_SYNCsend(SYNC); } - #if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_TIMERNEXT) != 0 /* Calculate when next SYNC needs to be sent */ if (timerNext_us != NULL) { uint32_t diff = OD_1006_period - SYNC->timer; @@ -395,54 +348,48 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, *timerNext_us = diff; } } - #endif - } - else +#endif + } else #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */ - /* Verify timeout of SYNC */ - if (SYNC->timeoutError == 1U) { - /* periodTimeout is 1,5 * OD_1006_period, no overflow */ - uint32_t periodTimeout = OD_1006_period + (OD_1006_period >> 1); - if (periodTimeout < OD_1006_period) { - periodTimeout = 0xFFFFFFFFU; - } + /* Verify timeout of SYNC */ + if (SYNC->timeoutError == 1U) { + /* periodTimeout is 1,5 * OD_1006_period, no overflow */ + uint32_t periodTimeout = OD_1006_period + (OD_1006_period >> 1); + if (periodTimeout < OD_1006_period) { + periodTimeout = 0xFFFFFFFFU; + } - if (SYNC->timer > periodTimeout) { - CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, - CO_EMC_COMMUNICATION, SYNC->timer); - SYNC->timeoutError = 2; - } -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT) != 0 - else if (timerNext_us != NULL) { - uint32_t diff = periodTimeout - SYNC->timer; - if (*timerNext_us > diff) { - *timerNext_us = diff; + if (SYNC->timer > periodTimeout) { + CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer); + SYNC->timeoutError = 2; + } +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_TIMERNEXT) != 0 + else if (timerNext_us != NULL) { + uint32_t diff = periodTimeout - SYNC->timer; + if (*timerNext_us > diff) { + *timerNext_us = diff; + } + } else { /* MISRA C 2004 14.10 */ } - } - else { /* MISRA C 2004 14.10 */ } #endif - } - else { /* MISRA C 2004 14.10 */ } + } else { /* MISRA C 2004 14.10 */ + } } /* if (OD_1006_period > 0) */ /* Synchronous PDOs are allowed only inside time window */ - if ((SYNC->OD_1007_window != NULL) && (*SYNC->OD_1007_window > 0U) - && (SYNC->timer > *SYNC->OD_1007_window) - ) { + if ((SYNC->OD_1007_window != NULL) && (*SYNC->OD_1007_window > 0U) && (SYNC->timer > *SYNC->OD_1007_window)) { if (!SYNC->syncIsOutsideWindow) { syncStatus = CO_SYNC_PASSED_WINDOW; } SYNC->syncIsOutsideWindow = true; - } - else { + } else { SYNC->syncIsOutsideWindow = false; } /* verify error from receive function */ if (SYNC->receiveError != 0U) { - CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, - CO_EMC_SYNC_DATA_LENGTH, SYNC->receiveError); + CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, CO_EMC_SYNC_DATA_LENGTH, SYNC->receiveError); SYNC->receiveError = 0; } } /* if (NMTisPreOrOperational) */ diff --git a/301/CO_TIME.c b/301/CO_TIME.c index fe847d69..8b8e6b2d 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -22,7 +22,7 @@ #include "301/CO_TIME.h" -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 /* * Read received message from CAN module. @@ -31,16 +31,17 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_TIME_receive(void *object, void *msg) { - CO_TIME_t *TIME = object; +static void +CO_TIME_receive(void* object, void* msg) { + CO_TIME_t* TIME = object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); if (DLC == CO_TIME_MSG_LENGTH) { (void)memcpy(TIME->timeStamp, data, sizeof(TIME->timeStamp)); CO_FLAG_SET(TIME->CANrxNew); -#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles TIME.*/ if (TIME->pFunctSignalPre != NULL) { TIME->pFunctSignalPre(TIME->functSignalObjectPre); @@ -49,23 +50,20 @@ static void CO_TIME_receive(void *object, void *msg) { } } - -#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "COB-ID time stamp" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ - if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) - || (count != sizeof(uint32_t)) || (countWritten == NULL) - ) { +static ODR_t +OD_write_1012(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (stream->subIndex != 0U) || (buf == NULL) || (count != sizeof(uint32_t)) + || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_TIME_t *TIME = stream->object; + CO_TIME_t* TIME = stream->object; /* verify written value */ uint32_t cobIdTimeStamp = CO_getUint32(buf); @@ -83,20 +81,15 @@ static ODR_t OD_write_1012(OD_stream_t *stream, const void *buf, } #endif - -CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, - OD_entry_t *OD_1012_cobIdTimeStamp, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, +CO_ReturnError_t +CO_TIME_init(CO_TIME_t* TIME, OD_entry_t* OD_1012_cobIdTimeStamp, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, #endif - uint32_t *errInfo) -{ + uint32_t* errInfo) { /* verify arguments */ if ((TIME == NULL) || (OD_1012_cobIdTimeStamp == NULL) || (CANdevRx == NULL) -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 || CANdevTx == NULL #endif ) { @@ -109,10 +102,12 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, uint32_t cobIdTimeStamp; ODR_t odRet = OD_get_u32(OD_1012_cobIdTimeStamp, 0, &cobIdTimeStamp, true); if (odRet != ODR_OK) { - if (errInfo != NULL) { *errInfo = OD_getIndex(OD_1012_cobIdTimeStamp); } + if (errInfo != NULL) { + *errInfo = OD_getIndex(OD_1012_cobIdTimeStamp); + } return CO_ERROR_OD_PARAMETERS; } -#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 TIME->OD_1012_extension.object = TIME; TIME->OD_1012_extension.read = OD_readOriginal; TIME->OD_1012_extension.write = OD_write_1012; @@ -127,29 +122,17 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, /* configure TIME consumer message reception */ if (TIME->isConsumer) { - CO_ReturnError_t ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - cobId, - 0x7FF, - false, - (void*)TIME, - CO_TIME_receive); + CO_ReturnError_t ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, cobId, 0x7FF, false, (void*)TIME, + CO_TIME_receive); if (ret != CO_ERROR_NO) { return ret; } } -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 /* configure TIME producer message transmission */ TIME->CANdevTx = CANdevTx; - TIME->CANtxBuff = CO_CANtxBufferInit( - CANdevTx, - CANdevTxIdx, - cobId, - false, - CO_TIME_MSG_LENGTH, - false); + TIME->CANtxBuff = CO_CANtxBufferInit(CANdevTx, CANdevTxIdx, cobId, false, CO_TIME_MSG_LENGTH, false); if (TIME->CANtxBuff == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; @@ -159,12 +142,9 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, return CO_ERROR_NO; } - -#if ((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_TIME_initCallbackPre(CO_TIME_t *TIME, - void *object, - void (*pFunctSignalPre)(void *object)) -{ +#if ((CO_CONFIG_TIME)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_TIME_initCallbackPre(CO_TIME_t* TIME, void* object, void (*pFunctSignalPre)(void* object)) { if (TIME != NULL) { TIME->functSignalObjectPre = object; TIME->pFunctSignalPre = pFunctSignalPre; @@ -172,16 +152,13 @@ void CO_TIME_initCallbackPre(CO_TIME_t *TIME, } #endif - -bool_t CO_TIME_process(CO_TIME_t *TIME, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us) -{ +bool_t +CO_TIME_process(CO_TIME_t* TIME, bool_t NMTisPreOrOperational, uint32_t timeDifference_us) { bool_t timestampReceived = false; /* Was TIME stamp message just received */ if (NMTisPreOrOperational && TIME->isConsumer) { - if(CO_FLAG_READ(TIME->CANrxNew)) { + if (CO_FLAG_READ(TIME->CANrxNew)) { uint32_t ms_swapped = CO_getUint32(&TIME->timeStamp[0]); uint16_t days_swapped = CO_getUint16(&TIME->timeStamp[4]); TIME->ms = CO_SWAP_32(ms_swapped) & 0x0FFFFFFFU; @@ -191,8 +168,7 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, CO_FLAG_CLEAR(TIME->CANrxNew); } - } - else { + } else { CO_FLAG_CLEAR(TIME->CANrxNew); } @@ -203,16 +179,14 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, ms = us / 1000U; TIME->residual_us = (uint16_t)(us % 1000U); TIME->ms += ms; - if (TIME->ms >= ((uint32_t)1000U*60U*60U*24U)) { - TIME->ms -= ((uint32_t)1000U*60U*60U*24U); + if (TIME->ms >= ((uint32_t)1000U * 60U * 60U * 24U)) { + TIME->ms -= ((uint32_t)1000U * 60U * 60U * 24U); TIME->days += 1U; } } -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 - if (NMTisPreOrOperational && TIME->isProducer - && TIME->producerInterval_ms > 0 - ) { +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 + if (NMTisPreOrOperational && TIME->isProducer && TIME->producerInterval_ms > 0) { if (TIME->producerTimer_ms >= TIME->producerInterval_ms) { TIME->producerTimer_ms -= TIME->producerInterval_ms; @@ -221,12 +195,10 @@ bool_t CO_TIME_process(CO_TIME_t *TIME, (void)CO_setUint32(&TIME->CANtxBuff->data[0], ms_swapped); (void)CO_setUint16(&TIME->CANtxBuff->data[4], days_swapped); (void)CO_CANsend(TIME->CANdevTx, TIME->CANtxBuff); - } - else { + } else { TIME->producerTimer_ms += ms; } - } - else { + } else { TIME->producerTimer_ms = TIME->producerInterval_ms; } #endif diff --git a/301/CO_fifo.c b/301/CO_fifo.c index 21b52151..e7ccd135 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -22,13 +22,13 @@ #include "301/CO_fifo.h" -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) != 0 +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ENABLE) != 0 #include #include #include "crc16-ccitt.h" -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 #include #include @@ -37,17 +37,18 @@ /* Graphical character for comment delimiter */ #define DELIM_COMMENT ((uint8_t)'#') /* Graphical character for double quotes */ -#define DELIM_DQUOTE ((uint8_t)'"') +#define DELIM_DQUOTE ((uint8_t)'"') #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ /* verify configuration */ -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) != 0 - #if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) == 0 - #error CO_CONFIG_CRC16_ENABLE must be enabled. - #endif +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_CRC16_CCITT) != 0 +#if ((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_ENABLE) == 0 +#error CO_CONFIG_CRC16_ENABLE must be enabled. +#endif #endif -void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize) { +void +CO_fifo_init(CO_fifo_t* fifo, uint8_t* buf, size_t bufSize) { if ((fifo == NULL) || (buf == NULL) || (bufSize < 2U)) { return; @@ -61,7 +62,6 @@ void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize) { return; } - /* Circular FIFO buffer example for fifo->bufSize = 7 (usable size = 6): ****** * * * 0 * * * * * @@ -75,13 +75,10 @@ void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize) { * empty 3 bytes 4 bytes buffer * * buffer in buff in buff full * ******************************************************************************/ -size_t CO_fifo_write(CO_fifo_t *fifo, - const uint8_t *buf, - size_t count, - uint16_t *crc) -{ +size_t +CO_fifo_write(CO_fifo_t* fifo, const uint8_t* buf, size_t count, uint16_t* crc) { size_t i; - uint8_t *bufDest; + uint8_t* bufDest; if ((fifo == NULL) || (fifo->buf == NULL) || (buf == NULL)) { return 0; @@ -92,14 +89,13 @@ size_t CO_fifo_write(CO_fifo_t *fifo, size_t writePtrNext = fifo->writePtr + 1U; /* is circular buffer full */ - if ((writePtrNext == fifo->readPtr) || - ((writePtrNext == fifo->bufSize) && (fifo->readPtr == 0U))) { + if ((writePtrNext == fifo->readPtr) || ((writePtrNext == fifo->bufSize) && (fifo->readPtr == 0U))) { break; } *bufDest = *buf; -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) != 0 +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_CRC16_CCITT) != 0 if (crc != NULL) { crc16_ccitt_single(crc, *buf); } @@ -109,8 +105,7 @@ size_t CO_fifo_write(CO_fifo_t *fifo, if (writePtrNext == fifo->bufSize) { fifo->writePtr = 0; bufDest = &fifo->buf[0]; - } - else { + } else { fifo->writePtr++; bufDest++; } @@ -120,10 +115,10 @@ size_t CO_fifo_write(CO_fifo_t *fifo, return count - i; } - -size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { +size_t +CO_fifo_read(CO_fifo_t* fifo, uint8_t* buf, size_t count, bool_t* eof) { size_t i; - const uint8_t *bufSrc; + const uint8_t* bufSrc; bool_t alive_cycle = true; if (eof != NULL) { @@ -134,14 +129,13 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { } bufSrc = &fifo->buf[fifo->readPtr]; - for (i = count; (i > 0U) && alive_cycle; ) { + for (i = count; (i > 0U) && alive_cycle;) { const uint8_t c = *bufSrc; /* is circular buffer empty */ if (fifo->readPtr == fifo->writePtr) { alive_cycle = false; - } - else { + } else { *buf = c; buf++; @@ -149,13 +143,12 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { if (++fifo->readPtr == fifo->bufSize) { fifo->readPtr = 0; bufSrc = &fifo->buf[0]; - } - else { + } else { bufSrc++; } i--; -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 /* is delimiter? */ if ((eof != NULL) && (c == DELIM_COMMAND)) { *eof = true; @@ -168,9 +161,9 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof) { return count - i; } - -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) != 0 -size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset) { +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ALT_READ) != 0 +size_t +CO_fifo_altBegin(CO_fifo_t* fifo, size_t offset) { size_t i; if (fifo == NULL) { @@ -193,7 +186,8 @@ size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset) { return offset - i; } -void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { +void +CO_fifo_altFinish(CO_fifo_t* fifo, uint16_t* crc) { if (fifo == NULL) { return; @@ -201,28 +195,27 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc) { if (crc == NULL) { fifo->readPtr = fifo->altReadPtr; - } - else { - const uint8_t *bufSrc = &fifo->buf[fifo->readPtr]; + } else { + const uint8_t* bufSrc = &fifo->buf[fifo->readPtr]; while (fifo->readPtr != fifo->altReadPtr) { -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT) != 0 +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_CRC16_CCITT) != 0 crc16_ccitt_single(crc, *bufSrc); #endif /* increment variable */ if (++fifo->readPtr == fifo->bufSize) { fifo->readPtr = 0; bufSrc = &fifo->buf[0]; - } - else { + } else { bufSrc++; } } } } -size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count) { +size_t +CO_fifo_altRead(CO_fifo_t* fifo, uint8_t* buf, size_t count) { size_t i; - const uint8_t *bufSrc; + const uint8_t* bufSrc; bufSrc = &fifo->buf[fifo->altReadPtr]; for (i = count; i > 0U; i--) { @@ -240,8 +233,7 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count) { if (++fifo->altReadPtr == fifo->bufSize) { fifo->altReadPtr = 0; bufSrc = &fifo->buf[0]; - } - else { + } else { bufSrc++; } } @@ -250,12 +242,12 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count) { } #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ */ - -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 -bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 +bool_t +CO_fifo_CommSearch(CO_fifo_t* fifo, bool_t clear) { bool_t newCommand = false; size_t count; - uint8_t *commandEnd; + uint8_t* commandEnd; if ((fifo == NULL) || (fifo->readPtr == fifo->writePtr)) { return false; @@ -267,27 +259,21 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { } else { count = fifo->bufSize - fifo->readPtr; } - commandEnd = (uint8_t *)memchr((const void *)&fifo->buf[fifo->readPtr], - (int32_t)DELIM_COMMAND, - count); + commandEnd = (uint8_t*)memchr((const void*)&fifo->buf[fifo->readPtr], (int32_t)DELIM_COMMAND, count); if (commandEnd != NULL) { newCommand = true; - } - else if (fifo->readPtr > fifo->writePtr) { + } else if (fifo->readPtr > fifo->writePtr) { /* not found, search in the beginning of the circular buffer */ - commandEnd = (uint8_t *)memchr((const void *)&fifo->buf[0], - (int32_t)DELIM_COMMAND, - fifo->writePtr); + commandEnd = (uint8_t*)memchr((const void*)&fifo->buf[0], (int32_t)DELIM_COMMAND, fifo->writePtr); if ((commandEnd != NULL) || (fifo->readPtr == (fifo->writePtr + 1U))) { /* command delimiter found or buffer full */ newCommand = true; } - } - else if ((fifo->readPtr == 0U) && (fifo->writePtr == (fifo->bufSize - 1U))) { + } else if ((fifo->readPtr == 0U) && (fifo->writePtr == (fifo->bufSize - 1U))) { /* buffer full */ newCommand = true; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } /* Clear buffer if set so */ if (clear) { @@ -296,8 +282,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { if (fifo->readPtr == fifo->bufSize) { fifo->readPtr = 0; } - } - else { + } else { fifo->readPtr = fifo->writePtr; } } @@ -305,8 +290,8 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear) { return newCommand; } - -bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { +bool_t +CO_fifo_trimSpaces(CO_fifo_t* fifo, bool_t* insideComment) { bool_t delimCommandFound = false; bool_t alive_cycle = true; @@ -316,13 +301,12 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { if (c == DELIM_COMMENT) { *insideComment = true; - } - else if ((isgraph((int)c) != 0) && !(*insideComment)) { + } else if ((isgraph((int)c) != 0) && !(*insideComment)) { alive_cycle = false; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } - if( alive_cycle ) { + if (alive_cycle) { if (++fifo->readPtr == fifo->bufSize) { fifo->readPtr = 0; } @@ -337,120 +321,107 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment) { return delimCommandFound; } - -size_t CO_fifo_readToken(CO_fifo_t *fifo, - char *buf, - size_t count, - uint8_t *closed, - bool_t *err) -{ +size_t +CO_fifo_readToken(CO_fifo_t* fifo, char* buf, size_t count, uint8_t* closed, bool_t* err) { bool_t delimCommandFound = false; bool_t delimCommentFound = false; size_t tokenSize = 0; if ((fifo != NULL) && (buf != NULL) && (count > 1U) && ((err == NULL) || (*err == false)) - && (fifo->readPtr != fifo->writePtr) - ) { + && (fifo->readPtr != fifo->writePtr)) { bool_t finished = false; uint8_t step = 0; - size_t ptr = fifo->readPtr; /* current pointer (integer, 0 based) */ - uint8_t *c = &fifo->buf[ptr]; /* current character */ + size_t ptr = fifo->readPtr; /* current pointer (integer, 0 based) */ + uint8_t* c = &fifo->buf[ptr]; /* current character */ do { switch (step) { - case 0: /* skip leading empty characters, stop on delimiter */ - if (isgraph((int)*c) != 0) { - if (*c == DELIM_COMMENT) { - delimCommentFound = true; + case 0: /* skip leading empty characters, stop on delimiter */ + if (isgraph((int)*c) != 0) { + if (*c == DELIM_COMMENT) { + delimCommentFound = true; + } else { + buf[tokenSize] = (char)*c; + tokenSize++; + step++; + } + } else if (*c == DELIM_COMMAND) { + delimCommandFound = true; + } else { /* MISRA C 2004 14.10 */ + } + break; + case 1: /* search for end of the token */ + if (isgraph((int)*c) != 0) { + if (*c == DELIM_COMMENT) { + delimCommentFound = true; + } else if (tokenSize < count) { + buf[tokenSize] = (char)*c; + tokenSize++; + } else { /* MISRA C 2004 14.10 */ + } } else { - buf[tokenSize] = (char)*c; - tokenSize++; + if (*c == DELIM_COMMAND) { + delimCommandFound = true; + } step++; } - } - else if (*c == DELIM_COMMAND) { - delimCommandFound = true; - } - else { /* MISRA C 2004 14.10 */ } - break; - case 1: /* search for end of the token */ - if (isgraph((int)*c) != 0) { - if (*c == DELIM_COMMENT) { - delimCommentFound = true; - } else if (tokenSize < count) { - buf[tokenSize] = (char)*c; - tokenSize++; - } - else { /* MISRA C 2004 14.10 */ } - } - else { - if (*c == DELIM_COMMAND) { + break; + case 2: /* skip trailing empty characters */ + if (isgraph((int)*c) != 0) { + if (*c == DELIM_COMMENT) { + delimCommentFound = true; + } else { + fifo->readPtr = ptr; + finished = true; + } + } else if (*c == DELIM_COMMAND) { delimCommandFound = true; + } else { /* MISRA C 2004 14.10 */ } - step++; - } - break; - case 2: /* skip trailing empty characters */ - if (isgraph((int)*c) != 0) { - if (*c == DELIM_COMMENT) { - delimCommentFound = true; - } else { - fifo->readPtr = ptr; - finished = true; - } - } - else if (*c == DELIM_COMMAND) { - delimCommandFound = true; - } - else { /* MISRA C 2004 14.10 */ } - break; - default: - /* MISRA C 2004 15.3 */ - break; + break; + default: + /* MISRA C 2004 15.3 */ + break; } if (delimCommentFound == true) { /* Comment delimiter found, clear all till end of the line. */ fifo->readPtr = ptr; delimCommandFound = CO_fifo_CommSearch(fifo, true); finished = true; - } - else if (delimCommandFound) { + } else if (delimCommandFound) { /* command delimiter found, set readPtr behind it. */ if (++ptr == fifo->bufSize) { ptr = 0; } fifo->readPtr = ptr; finished = true; - } - else if (!finished) { + } else if (!finished) { /* find next character in the circular buffer */ if (++ptr == fifo->bufSize) { ptr = 0; c = &fifo->buf[ptr]; - } - else { + } else { c++; } /* end, if buffer is now empty */ if (ptr == fifo->writePtr) { if (step == 2U) { fifo->readPtr = ptr; - } - else { + } else { tokenSize = 0; } finished = true; } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } while (!finished); } /* set 'err' return value */ if ((err != NULL) && (*err == false)) { - if ((tokenSize == count) || ((closed != NULL) && - (((*closed == 1U) && (!delimCommandFound || (tokenSize == 0U))) || - ((*closed == 0U) && (delimCommandFound || (tokenSize == 0U)))) - )) { + if ((tokenSize == count) + || ((closed != NULL) + && (((*closed == 1U) && (!delimCommandFound || (tokenSize == 0U))) + || ((*closed == 0U) && (delimCommandFound || (tokenSize == 0U)))))) { *err = true; } } @@ -472,252 +443,249 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, } #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ - -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0 +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_DATATYPES) != 0 /* Tables for mime-base64 encoding, as specified in RFC 2045, (without CR-LF, * but one long string). Base64 is used for encoding binary data into easy * transferable printable characters. In general, each three bytes of binary * data are translated into four characters, where characters are selected from * 64 characters long table. See https://en.wikipedia.org/wiki/Base64 */ -static const char base64EncTable[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char base64EncTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const uint8_t base64DecTable[] = { - 255,255,255,255,255,255,255,255,255,103,101,255,255,102,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 103,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,100,255,255, - 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255}; - -size_t CO_fifo_readU82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint8_t n=0; - - if(fifo == NULL) { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 103, 101, 255, 255, 102, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 103, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, + 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 100, 255, 255, 255, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255}; + +size_t +CO_fifo_readU82a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + uint8_t n = 0; + + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { (void)CO_fifo_read(fifo, &n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%"PRIu8, n); - } - else { + return (size_t)sprintf(buf, "%" PRIu8, n); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint16_t n=0; +size_t +CO_fifo_readU162a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + uint16_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%"PRIu16, CO_SWAP_16(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "%" PRIu16, CO_SWAP_16(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint32_t n=0; +size_t +CO_fifo_readU322a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + uint32_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 12U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%"PRIu32, CO_SWAP_32(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "%" PRIu32, CO_SWAP_32(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint64_t n=0; +size_t +CO_fifo_readU642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + uint64_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%"PRIu64, CO_SWAP_64(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "%" PRIu64, CO_SWAP_64(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readX82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint8_t n=0; +size_t +CO_fifo_readX82a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + uint8_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "0x%02"PRIX8, (uint32_t)n); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "0x%02" PRIX8, (uint32_t)n); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint16_t n=0; +size_t +CO_fifo_readX162a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + uint16_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "0x%04"PRIX16, (uint32_t)CO_SWAP_16(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "0x%04" PRIX16, (uint32_t)CO_SWAP_16(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint32_t n=0; +size_t +CO_fifo_readX322a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + uint32_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 12U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "0x%08"PRIX32, CO_SWAP_32(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "0x%08" PRIX32, CO_SWAP_32(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - uint64_t n=0; +size_t +CO_fifo_readX642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + uint64_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "0x%016"PRIX64, CO_SWAP_64(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "0x%016" PRIX64, CO_SWAP_64(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readI82a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - int8_t n=0; +size_t +CO_fifo_readI82a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + int8_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 6U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%"PRId8, n); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "%" PRId8, n); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - int16_t n=0; +size_t +CO_fifo_readI162a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + int16_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 8U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%"PRId16, CO_SWAP_16(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "%" PRId16, CO_SWAP_16(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - int32_t n=0; +size_t +CO_fifo_readI322a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + int32_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 13U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%"PRId32, CO_SWAP_32(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "%" PRId32, CO_SWAP_32(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - int64_t n=0; +size_t +CO_fifo_readI642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + int64_t n = 0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 23U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); - return (size_t)sprintf(buf, "%"PRId64, CO_SWAP_64(n)); - } - else { + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); + return (size_t)sprintf(buf, "%" PRId64, CO_SWAP_64(n)); + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - float32_t n=(float32_t)0; +size_t +CO_fifo_readR322a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + float32_t n = (float32_t)0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 20U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); return (size_t)sprintf(buf, "%g", (float32_t)CO_SWAP_32(n)); - } - else { + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - float64_t n=(float64_t)0; +size_t +CO_fifo_readR642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + float64_t n = (float64_t)0; - if(fifo == NULL) { + if (fifo == NULL) { return 0; } if ((CO_fifo_getOccupied(fifo) == sizeof(n)) && (count >= 30U)) { - (void)CO_fifo_read(fifo, (uint8_t *)&n, sizeof(n), NULL); + (void)CO_fifo_read(fifo, (uint8_t*)&n, sizeof(n), NULL); return (size_t)sprintf(buf, "%g", (float64_t)CO_SWAP_64(n)); - } - else { + } else { return CO_fifo_readHex2a(fifo, buf, count, end); } } -size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { - (void)end; /* unused */ +size_t +CO_fifo_readHex2a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { + (void)end; /* unused */ size_t len = 0; @@ -725,25 +693,26 @@ size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { /* Very first write is without leading space */ if (!fifo->started) { uint8_t c; - if(CO_fifo_getc(fifo, &c)) { - len = (size_t)sprintf(&buf[0], "%02"PRIX8, (uint32_t)c); + if (CO_fifo_getc(fifo, &c)) { + len = (size_t)sprintf(&buf[0], "%02" PRIX8, (uint32_t)c); fifo->started = true; } } while ((len + 3U) < count) { uint8_t c; - if(!CO_fifo_getc(fifo, &c)) { + if (!CO_fifo_getc(fifo, &c)) { break; } - len += (size_t)sprintf(&buf[len], " %02"PRIX8, (uint32_t)c); + len += (size_t)sprintf(&buf[len], " %02" PRIX8, (uint32_t)c); } } return len; } -size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { +size_t +CO_fifo_readVs2a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { size_t len = 0; if ((fifo != NULL) && (count > 3U)) { @@ -756,14 +725,13 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { while ((len + 2U) < count) { uint8_t c; - if(!CO_fifo_getc(fifo, &c)) { + if (!CO_fifo_getc(fifo, &c)) { if (end) { buf[len] = '"'; len++; } break; - } - else if ((c != 0U) && (c != (uint8_t)'\r')) { + } else if ((c != 0U) && (c != (uint8_t)'\r')) { /* skip null and CR inside string */ buf[len] = (char)c; len++; @@ -771,15 +739,16 @@ size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { buf[len] = '"'; len++; } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } } return len; } -size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { +size_t +CO_fifo_readB642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end) { /* mime-base64 encoding, see description above base64EncTable */ size_t len = 0; @@ -792,8 +761,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { fifo->started = true; step = 0; word = 0; - } - else { + } else { /* get memorized variables from previous function calls */ step = (uint8_t)(fifo->aux >> 16); word = (uint16_t)fifo->aux; @@ -802,7 +770,7 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { while ((len + 3U) <= count) { uint8_t c; - if(!CO_fifo_getc(fifo, &c)) { + if (!CO_fifo_getc(fifo, &c)) { /* buffer is empty, is also SDO communication finished? */ if (end) { /* add padding if necessary */ @@ -858,8 +826,8 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end) { return len; } - -size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2U8(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[15]; uint8_t closed = 0xFFU; bool_t err = false; @@ -868,15 +836,13 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; uint32_t u32 = strtoul(buf, &sRet, 0); if ((sRet != strchr(buf, (int32_t)('\0'))) || (u32 > (uint32_t)UINT8_MAX)) { st |= CO_fifo_st_errVal; - } - else { - uint8_t num = (uint8_t) u32; + } else { + uint8_t num = (uint8_t)u32; nWr = CO_fifo_write(dest, &num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; @@ -889,7 +855,8 @@ size_t CO_fifo_cpyTok2U8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return nWr; } -size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2U16(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[15]; uint8_t closed = 0xFFU; bool_t err = false; @@ -898,16 +865,14 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; uint32_t u32 = strtoul(buf, &sRet, 0); if ((sRet != strchr(buf, (int32_t)('\0'))) || (u32 > (uint32_t)UINT16_MAX)) { st |= CO_fifo_st_errVal; - } - else { - uint16_t num = CO_SWAP_16((uint16_t) u32); - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + } else { + uint16_t num = CO_SWAP_16((uint16_t)u32); + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } @@ -919,7 +884,8 @@ size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return nWr; } -size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2U32(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[15]; uint8_t closed = 0xFFU; bool_t err = false; @@ -928,16 +894,14 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; uint32_t u32 = strtoul(buf, &sRet, 0); if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; - } - else { + } else { uint32_t num = CO_SWAP_32(u32); - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } @@ -949,7 +913,8 @@ size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return nWr; } -size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2U64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[25]; uint8_t closed = 0xFFU; bool_t err = false; @@ -958,28 +923,27 @@ size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; uint64_t u64 = strtoull(buf, &sRet, 0); if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; - } - else { + } else { uint64_t num = CO_SWAP_64(u64); - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } } } if (status != NULL) { - *status = (uint8_t) st; + *status = (uint8_t)st; } return nWr; } -size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2I8(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[15]; uint8_t closed = 0xFFU; bool_t err = false; @@ -988,15 +952,14 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; int32_t i32 = strtol(buf, &sRet, 0); if ((sRet != strchr(buf, (int32_t)('\0'))) || (i32 < INT8_MIN) || (i32 > INT8_MAX)) { st |= CO_fifo_st_errVal; } else { - int8_t num = (int8_t) i32; - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + int8_t num = (int8_t)i32; + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } @@ -1008,7 +971,8 @@ size_t CO_fifo_cpyTok2I8(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return nWr; } -size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2I16(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[15]; uint8_t closed = 0xFFU; bool_t err = false; @@ -1017,15 +981,14 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; int32_t i32 = strtol(buf, &sRet, 0); if ((sRet != strchr(buf, (int32_t)('\0'))) || (i32 < INT16_MIN) || (i32 > INT16_MAX)) { st |= CO_fifo_st_errVal; } else { - int16_t num = CO_SWAP_16((int16_t) i32); - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + int16_t num = CO_SWAP_16((int16_t)i32); + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } @@ -1037,7 +1000,8 @@ size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return nWr; } -size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2I32(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[15]; uint8_t closed = 0xFFU; bool_t err = false; @@ -1046,16 +1010,14 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; int32_t i32 = strtol(buf, &sRet, 0); if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; - } - else { + } else { int32_t num = CO_SWAP_32(i32); - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } @@ -1067,7 +1029,8 @@ size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return nWr; } -size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2I64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[25]; uint8_t closed = 0xFFU; bool_t err = false; @@ -1076,28 +1039,27 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; int64_t i64 = strtoll(buf, &sRet, 0); if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; - } - else { + } else { int64_t num = CO_SWAP_64(i64); - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } } } if (status != NULL) { - *status = (uint8_t) st; + *status = (uint8_t)st; } return nWr; } -size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2R32(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[30]; uint8_t closed = 0xFFU; bool_t err = false; @@ -1106,16 +1068,14 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; float32_t f32 = strtof(buf, &sRet); if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; - } - else { + } else { float32_t num = CO_SWAP_32(f32); - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } @@ -1127,7 +1087,8 @@ size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return nWr; } -size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2R64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { char buf[40]; uint8_t closed = 0xFFU; bool_t err = false; @@ -1136,16 +1097,14 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { uint8_t st = closed; if ((nRd == 0U) || err) { st |= CO_fifo_st_errTok; - } - else { - char *sRet; + } else { + char* sRet; float64_t f64 = strtof(buf, &sRet); if (sRet != strchr(buf, (int32_t)('\0'))) { st |= CO_fifo_st_errVal; - } - else { + } else { float64_t num = CO_SWAP_64(f64); - nWr = CO_fifo_write(dest, (uint8_t *)&num, sizeof(num), NULL); + nWr = CO_fifo_write(dest, (uint8_t*)&num, sizeof(num), NULL); if (nWr != sizeof(num)) { st |= CO_fifo_st_errBuf; } @@ -1157,7 +1116,8 @@ size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return nWr; } -size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2Hex(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { size_t destSpace, destSpaceStart; bool_t finished = false; uint8_t step; @@ -1182,8 +1142,7 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { dest->started = true; step = 0; firstChar = 0; - } - else { + } else { /* get memorized variables from previous function calls */ step = (uint8_t)(dest->aux >> 8); firstChar = (uint8_t)(dest->aux & 0xFFU); @@ -1212,49 +1171,47 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { if (step == 0U) { firstChar = c; step = 1; - } - else { + } else { /* write the byte */ uint8_t s[3]; int32_t num; - s[0] = firstChar; s[1] = c; s[2] = 0; - num = strtol((char *)&s[0], NULL, 16); - (void)CO_fifo_putc(dest, (uint8_t) num); + s[0] = firstChar; + s[1] = c; + s[2] = 0; + num = strtol((char*)&s[0], NULL, 16); + (void)CO_fifo_putc(dest, (uint8_t)num); destSpace--; step = 0; } - } - else if ((int32_t)(isgraph((int32_t)c)) != 0) { + } else if ((int32_t)(isgraph((int32_t)c)) != 0) { /* printable character, not hex digit */ if (c == DELIM_COMMENT) { /* comment start */ step = 6; - } - else {/* syntax error */ + } else { /* syntax error */ st |= CO_fifo_st_errTok; } - } - else { + } else { /* this is space or delimiter */ if (step == 1U) { /* write the byte */ uint8_t s[2]; int32_t num; - s[0] = firstChar; s[1] = 0; - num = strtol((char *)&s[0], NULL, 16); - (void)CO_fifo_putc(dest, (uint8_t) num); + s[0] = firstChar; + s[1] = 0; + num = strtol((char*)&s[0], NULL, 16); + (void)CO_fifo_putc(dest, (uint8_t)num); destSpace--; step = 0; } bool_t insideComment = false; - if (CO_fifo_trimSpaces(src, &insideComment) ||(c == DELIM_COMMAND)) { + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { /* newline found, finish */ st |= CO_fifo_st_closed; finished = true; - } - else if (insideComment) { + } else if (insideComment) { step = 6; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } } /* while ... */ @@ -1271,7 +1228,8 @@ size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return destSpaceStart - destSpace; } -size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2Vs(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { size_t destSpace, destSpaceStart; bool_t finished = false; uint8_t step; @@ -1294,8 +1252,7 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } dest->started = true; step = 0; - } - else { + } else { /* get memorized variables from previous function calls */ step = (uint8_t)dest->aux; } @@ -1309,114 +1266,100 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { } switch (step) { - case 0: /* beginning of the string, first write into dest */ - if (c == DELIM_DQUOTE) { - /* Indicated beginning of the string, skip this character. */ - step = 1; - } - else { - /* this must be a single word string without '"' */ - /* copy the character */ - (void)CO_fifo_putc(dest, c); - destSpace--; - step = 2; - } - break; - - case 1: /* inside string, quoted string */ - case 2: /* inside string, single word, no quotes */ - if (c == DELIM_DQUOTE) { - /* double quote found, this may be end of the string or escaped - * double quote (with two double quotes) */ - step += 2U; - } - else if ((isgraph((int)c) == 0) && (step == 2U)) { - /* end of single word string */ - bool_t insideComment = false; - if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { - st |= CO_fifo_st_closed; - finished = true; - } - else { - step = insideComment ? 6U : 5U; + case 0: /* beginning of the string, first write into dest */ + if (c == DELIM_DQUOTE) { + /* Indicated beginning of the string, skip this character. */ + step = 1; + } else { + /* this must be a single word string without '"' */ + /* copy the character */ + (void)CO_fifo_putc(dest, c); + destSpace--; + step = 2; } - } - else if (c == DELIM_COMMAND) { - /* no closing quote, error */ - st |= CO_fifo_st_errTok; - } - else { - /* copy the character */ - (void)CO_fifo_putc(dest, c); - destSpace--; - } - break; + break; - case 3: /* previous was double quote, parsing quoted string */ - case 4: /* previous was double quote, parsing no quoted word */ - if (c == DELIM_DQUOTE) { - /* escaped double quote, copy the character and continue */ - (void)CO_fifo_putc(dest, c); - destSpace--; - step -= 2U; - } - else { - /* previous character was closing double quote */ - if (step == 4U) { - /* no opening double quote, syntax error */ + case 1: /* inside string, quoted string */ + case 2: /* inside string, single word, no quotes */ + if (c == DELIM_DQUOTE) { + /* double quote found, this may be end of the string or escaped + * double quote (with two double quotes) */ + step += 2U; + } else if ((isgraph((int)c) == 0) && (step == 2U)) { + /* end of single word string */ + bool_t insideComment = false; + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { + st |= CO_fifo_st_closed; + finished = true; + } else { + step = insideComment ? 6U : 5U; + } + } else if (c == DELIM_COMMAND) { + /* no closing quote, error */ st |= CO_fifo_st_errTok; + } else { + /* copy the character */ + (void)CO_fifo_putc(dest, c); + destSpace--; } - else { - if (isgraph((int)c) == 0) { - /* end of quoted string */ - bool_t insideComment = false; - if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { - st |= CO_fifo_st_closed; - finished = true; - } - else { - step = insideComment ? 6U : 5U; - } - } - else { - /* space must follow closing double quote, error */ + break; + + case 3: /* previous was double quote, parsing quoted string */ + case 4: /* previous was double quote, parsing no quoted word */ + if (c == DELIM_DQUOTE) { + /* escaped double quote, copy the character and continue */ + (void)CO_fifo_putc(dest, c); + destSpace--; + step -= 2U; + } else { + /* previous character was closing double quote */ + if (step == 4U) { + /* no opening double quote, syntax error */ st |= CO_fifo_st_errTok; + } else { + if (isgraph((int)c) == 0) { + /* end of quoted string */ + bool_t insideComment = false; + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { + st |= CO_fifo_st_closed; + finished = true; + } else { + step = insideComment ? 6U : 5U; + } + } else { + /* space must follow closing double quote, error */ + st |= CO_fifo_st_errTok; + } } } - } - break; + break; - case 5: { /* String token is finished, waiting for command delimiter */ - bool_t insideComment = false; - if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { - st |= CO_fifo_st_closed; - finished = true; - } - else if (insideComment) { - step = 6; - } - else if (isgraph((int)c) != 0) { - if (c == DELIM_COMMENT) { /* comment start */ + case 5: { /* String token is finished, waiting for command delimiter */ + bool_t insideComment = false; + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { + st |= CO_fifo_st_closed; + finished = true; + } else if (insideComment) { step = 6; + } else if (isgraph((int)c) != 0) { + if (c == DELIM_COMMENT) { /* comment start */ + step = 6; + } else { /* syntax error */ + st |= CO_fifo_st_errTok; + } + } else { /* MISRA C 2004 14.10 */ } - else {/* syntax error */ - st |= CO_fifo_st_errTok; - } + break; } - else { /* MISRA C 2004 14.10 */ } - break; - } - case 6: { /* String token is finished, waiting for command delimiter */ - bool_t insideComment = true; - if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { - st |= CO_fifo_st_closed; - finished = true; + case 6: { /* String token is finished, waiting for command delimiter */ + bool_t insideComment = true; + if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { + st |= CO_fifo_st_closed; + finished = true; + } + break; } - break; - } - default: /* internal error */ - st |= CO_fifo_st_errInt; - break; + default: /* internal error */ st |= CO_fifo_st_errInt; break; } } @@ -1433,7 +1376,8 @@ size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { return destSpaceStart - destSpace; } -size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { +size_t +CO_fifo_cpyTok2B64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { /* mime-base64 decoding, see description above base64EncTable */ size_t destSpace, destSpaceStart; @@ -1460,8 +1404,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { dest->started = true; step = 0; dword = 0; - } - else { + } else { /* get memorized variables from previous function calls */ step = (uint8_t)(dest->aux >> 24); dword = dest->aux & 0xFFFFFFU; @@ -1481,19 +1424,16 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; - } - else if (insideComment) { + } else if (insideComment) { step = 6; - } - else if ((isgraph((int)c) != 0) && (c != (uint8_t)'=')) { + } else if ((isgraph((int)c) != 0) && (c != (uint8_t)'=')) { if (c == DELIM_COMMENT) { /* comment start */ step = 6; - } - else {/* syntax error */ + } else { /* syntax error */ st |= CO_fifo_st_errTok; } + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } continue; } @@ -1501,13 +1441,12 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { if (((c & 0x80U) != 0U) || ((code & 0x80U) != 0U)) { st |= CO_fifo_st_errTok; - } - else if (code >= 64U /* '=' (pad) or DELIM_COMMAND or space */) { + } else if (code >= 64U /* '=' (pad) or DELIM_COMMAND or space */) { /* base64 string finished, write remaining bytes */ switch (step) { case 2: (void)CO_fifo_putc(dest, (uint8_t)(dword >> 4)); - destSpace --; + destSpace--; break; case 3: (void)CO_fifo_putc(dest, (uint8_t)(dword >> 10)); @@ -1523,12 +1462,10 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status) { if (CO_fifo_trimSpaces(src, &insideComment) || (c == DELIM_COMMAND)) { st |= CO_fifo_st_closed; finished = true; - } - else { + } else { step = insideComment ? 6U : 5U; } - } - else { + } else { dword = (dword << 6) | code; if (step++ == 3U) { (void)CO_fifo_putc(dest, (uint8_t)((dword >> 16) & 0xFFU)); diff --git a/301/crc16-ccitt.c b/301/crc16-ccitt.c index 778e1eba..5f1c2f34 100644 --- a/301/crc16-ccitt.c +++ b/301/crc16-ccitt.c @@ -20,8 +20,8 @@ #include "301/crc16-ccitt.h" -#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) != 0 -#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_EXTERNAL) == 0 +#if ((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_ENABLE) != 0 +#if ((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_EXTERNAL) == 0 /* * CRC table calculated by the following algorithm: @@ -41,51 +41,35 @@ * } */ static const uint16_t crc16_ccitt_table[256] = { - 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50A5U, 0x60C6U, 0x70E7U, - 0x8108U, 0x9129U, 0xA14AU, 0xB16BU, 0xC18CU, 0xD1ADU, 0xE1CEU, 0xF1EFU, - 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52B5U, 0x4294U, 0x72F7U, 0x62D6U, - 0x9339U, 0x8318U, 0xB37BU, 0xA35AU, 0xD3BDU, 0xC39CU, 0xF3FFU, 0xE3DEU, - 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64E6U, 0x74C7U, 0x44A4U, 0x5485U, - 0xA56AU, 0xB54BU, 0x8528U, 0x9509U, 0xE5EEU, 0xF5CFU, 0xC5ACU, 0xD58DU, - 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76D7U, 0x66F6U, 0x5695U, 0x46B4U, - 0xB75BU, 0xA77AU, 0x9719U, 0x8738U, 0xF7DFU, 0xE7FEU, 0xD79DU, 0xC7BCU, - 0x48C4U, 0x58E5U, 0x6886U, 0x78A7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, - 0xC9CCU, 0xD9EDU, 0xE98EU, 0xF9AFU, 0x8948U, 0x9969U, 0xA90AU, 0xB92BU, - 0x5AF5U, 0x4AD4U, 0x7AB7U, 0x6A96U, 0x1A71U, 0x0A50U, 0x3A33U, 0x2A12U, - 0xDBFDU, 0xCBDCU, 0xFBBFU, 0xEB9EU, 0x9B79U, 0x8B58U, 0xBB3BU, 0xAB1AU, - 0x6CA6U, 0x7C87U, 0x4CE4U, 0x5CC5U, 0x2C22U, 0x3C03U, 0x0C60U, 0x1C41U, - 0xEDAEU, 0xFD8FU, 0xCDECU, 0xDDCDU, 0xAD2AU, 0xBD0BU, 0x8D68U, 0x9D49U, - 0x7E97U, 0x6EB6U, 0x5ED5U, 0x4EF4U, 0x3E13U, 0x2E32U, 0x1E51U, 0x0E70U, - 0xFF9FU, 0xEFBEU, 0xDFDDU, 0xCFFCU, 0xBF1BU, 0xAF3AU, 0x9F59U, 0x8F78U, - 0x9188U, 0x81A9U, 0xB1CAU, 0xA1EBU, 0xD10CU, 0xC12DU, 0xF14EU, 0xE16FU, - 0x1080U, 0x00A1U, 0x30C2U, 0x20E3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, - 0x83B9U, 0x9398U, 0xA3FBU, 0xB3DAU, 0xC33DU, 0xD31CU, 0xE37FU, 0xF35EU, - 0x02B1U, 0x1290U, 0x22F3U, 0x32D2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, - 0xB5EAU, 0xA5CBU, 0x95A8U, 0x8589U, 0xF56EU, 0xE54FU, 0xD52CU, 0xC50DU, - 0x34E2U, 0x24C3U, 0x14A0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, - 0xA7DBU, 0xB7FAU, 0x8799U, 0x97B8U, 0xE75FU, 0xF77EU, 0xC71DU, 0xD73CU, - 0x26D3U, 0x36F2U, 0x0691U, 0x16B0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, - 0xD94CU, 0xC96DU, 0xF90EU, 0xE92FU, 0x99C8U, 0x89E9U, 0xB98AU, 0xA9ABU, - 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18C0U, 0x08E1U, 0x3882U, 0x28A3U, - 0xCB7DU, 0xDB5CU, 0xEB3FU, 0xFB1EU, 0x8BF9U, 0x9BD8U, 0xABBBU, 0xBB9AU, - 0x4A75U, 0x5A54U, 0x6A37U, 0x7A16U, 0x0AF1U, 0x1AD0U, 0x2AB3U, 0x3A92U, - 0xFD2EU, 0xED0FU, 0xDD6CU, 0xCD4DU, 0xBDAAU, 0xAD8BU, 0x9DE8U, 0x8DC9U, - 0x7C26U, 0x6C07U, 0x5C64U, 0x4C45U, 0x3CA2U, 0x2C83U, 0x1CE0U, 0x0CC1U, - 0xEF1FU, 0xFF3EU, 0xCF5DU, 0xDF7CU, 0xAF9BU, 0xBFBAU, 0x8FD9U, 0x9FF8U, - 0x6E17U, 0x7E36U, 0x4E55U, 0x5E74U, 0x2E93U, 0x3EB2U, 0x0ED1U, 0x1EF0U -}; + 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50A5U, 0x60C6U, 0x70E7U, 0x8108U, 0x9129U, 0xA14AU, 0xB16BU, 0xC18CU, + 0xD1ADU, 0xE1CEU, 0xF1EFU, 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52B5U, 0x4294U, 0x72F7U, 0x62D6U, 0x9339U, 0x8318U, + 0xB37BU, 0xA35AU, 0xD3BDU, 0xC39CU, 0xF3FFU, 0xE3DEU, 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64E6U, 0x74C7U, 0x44A4U, + 0x5485U, 0xA56AU, 0xB54BU, 0x8528U, 0x9509U, 0xE5EEU, 0xF5CFU, 0xC5ACU, 0xD58DU, 0x3653U, 0x2672U, 0x1611U, 0x0630U, + 0x76D7U, 0x66F6U, 0x5695U, 0x46B4U, 0xB75BU, 0xA77AU, 0x9719U, 0x8738U, 0xF7DFU, 0xE7FEU, 0xD79DU, 0xC7BCU, 0x48C4U, + 0x58E5U, 0x6886U, 0x78A7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, 0xC9CCU, 0xD9EDU, 0xE98EU, 0xF9AFU, 0x8948U, 0x9969U, + 0xA90AU, 0xB92BU, 0x5AF5U, 0x4AD4U, 0x7AB7U, 0x6A96U, 0x1A71U, 0x0A50U, 0x3A33U, 0x2A12U, 0xDBFDU, 0xCBDCU, 0xFBBFU, + 0xEB9EU, 0x9B79U, 0x8B58U, 0xBB3BU, 0xAB1AU, 0x6CA6U, 0x7C87U, 0x4CE4U, 0x5CC5U, 0x2C22U, 0x3C03U, 0x0C60U, 0x1C41U, + 0xEDAEU, 0xFD8FU, 0xCDECU, 0xDDCDU, 0xAD2AU, 0xBD0BU, 0x8D68U, 0x9D49U, 0x7E97U, 0x6EB6U, 0x5ED5U, 0x4EF4U, 0x3E13U, + 0x2E32U, 0x1E51U, 0x0E70U, 0xFF9FU, 0xEFBEU, 0xDFDDU, 0xCFFCU, 0xBF1BU, 0xAF3AU, 0x9F59U, 0x8F78U, 0x9188U, 0x81A9U, + 0xB1CAU, 0xA1EBU, 0xD10CU, 0xC12DU, 0xF14EU, 0xE16FU, 0x1080U, 0x00A1U, 0x30C2U, 0x20E3U, 0x5004U, 0x4025U, 0x7046U, + 0x6067U, 0x83B9U, 0x9398U, 0xA3FBU, 0xB3DAU, 0xC33DU, 0xD31CU, 0xE37FU, 0xF35EU, 0x02B1U, 0x1290U, 0x22F3U, 0x32D2U, + 0x4235U, 0x5214U, 0x6277U, 0x7256U, 0xB5EAU, 0xA5CBU, 0x95A8U, 0x8589U, 0xF56EU, 0xE54FU, 0xD52CU, 0xC50DU, 0x34E2U, + 0x24C3U, 0x14A0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, 0xA7DBU, 0xB7FAU, 0x8799U, 0x97B8U, 0xE75FU, 0xF77EU, + 0xC71DU, 0xD73CU, 0x26D3U, 0x36F2U, 0x0691U, 0x16B0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, 0xD94CU, 0xC96DU, 0xF90EU, + 0xE92FU, 0x99C8U, 0x89E9U, 0xB98AU, 0xA9ABU, 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18C0U, 0x08E1U, 0x3882U, 0x28A3U, + 0xCB7DU, 0xDB5CU, 0xEB3FU, 0xFB1EU, 0x8BF9U, 0x9BD8U, 0xABBBU, 0xBB9AU, 0x4A75U, 0x5A54U, 0x6A37U, 0x7A16U, 0x0AF1U, + 0x1AD0U, 0x2AB3U, 0x3A92U, 0xFD2EU, 0xED0FU, 0xDD6CU, 0xCD4DU, 0xBDAAU, 0xAD8BU, 0x9DE8U, 0x8DC9U, 0x7C26U, 0x6C07U, + 0x5C64U, 0x4C45U, 0x3CA2U, 0x2C83U, 0x1CE0U, 0x0CC1U, 0xEF1FU, 0xFF3EU, 0xCF5DU, 0xDF7CU, 0xAF9BU, 0xBFBAU, 0x8FD9U, + 0x9FF8U, 0x6E17U, 0x7E36U, 0x4E55U, 0x5E74U, 0x2E93U, 0x3EB2U, 0x0ED1U, 0x1EF0U}; - -void crc16_ccitt_single(uint16_t *crc, const uint8_t chr) { +void +crc16_ccitt_single(uint16_t* crc, const uint8_t chr) { uint8_t tmp = (uint8_t)(*crc >> 8U) ^ chr; *crc = (uint16_t)((*crc << 8U) ^ crc16_ccitt_table[tmp]); } - -uint16_t crc16_ccitt(const uint8_t block[], - size_t blockLength, - uint16_t crc) -{ +uint16_t +crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) { size_t i; for (i = 0U; i < blockLength; i++) { diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index e23f5ecb..3562ea5b 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -20,9 +20,10 @@ #include "303/CO_LEDs.h" -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 +#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 -CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { +CO_ReturnError_t +CO_LEDs_init(CO_LEDs_t* LEDs) { CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ @@ -36,20 +37,10 @@ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs) { return ret; } - -void CO_LEDs_process(CO_LEDs_t *LEDs, - uint32_t timeDifference_us, - CO_NMT_internalState_t NMTstate, - bool_t LSSconfig, - bool_t ErrCANbusOff, - bool_t ErrCANbusWarn, - bool_t ErrRpdo, - bool_t ErrSync, - bool_t ErrHbCons, - bool_t ErrOther, - bool_t firmwareDownload, - uint32_t *timerNext_us) -{ +void +CO_LEDs_process(CO_LEDs_t* LEDs, uint32_t timeDifference_us, CO_NMT_internalState_t NMTstate, bool_t LSSconfig, + bool_t ErrCANbusOff, bool_t ErrCANbusWarn, bool_t ErrRpdo, bool_t ErrSync, bool_t ErrHbCons, + bool_t ErrOther, bool_t firmwareDownload, uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ uint8_t rd = 0; @@ -69,8 +60,11 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, rd = 0; gr = 0; - if ((LEDs->LEDred & CO_LED_blink) == 0U) { rd |= CO_LED_blink; } - else { gr |= CO_LED_blink; } + if ((LEDs->LEDred & CO_LED_blink) == 0U) { + rd |= CO_LED_blink; + } else { + gr |= CO_LED_blink; + } switch (++LEDs->LEDtmrflash_1) { case 1: rd |= CO_LED_flash_1; break; @@ -79,33 +73,47 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, default: /* none */ break; } switch (++LEDs->LEDtmrflash_2) { - case 1: case 3: rd |= CO_LED_flash_2; break; - case 2: case 4: gr |= CO_LED_flash_2; break; + case 1: + case 3: rd |= CO_LED_flash_2; break; + case 2: + case 4: gr |= CO_LED_flash_2; break; case 8: LEDs->LEDtmrflash_2 = 0; break; default: /* none */ break; } switch (++LEDs->LEDtmrflash_3) { - case 1: case 3: case 5: rd |= CO_LED_flash_3; break; - case 2: case 4: case 6: gr |= CO_LED_flash_3; break; + case 1: + case 3: + case 5: rd |= CO_LED_flash_3; break; + case 2: + case 4: + case 6: gr |= CO_LED_flash_3; break; case 10: LEDs->LEDtmrflash_3 = 0; break; default: /* none */ break; } switch (++LEDs->LEDtmrflash_4) { - case 1: case 3: case 5: case 7: rd |= CO_LED_flash_4; break; - case 2: case 4: case 6: case 8: gr |= CO_LED_flash_4; break; + case 1: + case 3: + case 5: + case 7: rd |= CO_LED_flash_4; break; + case 2: + case 4: + case 6: + case 8: gr |= CO_LED_flash_4; break; case 12: LEDs->LEDtmrflash_4 = 0; break; default: /* none */ break; } - } - else { + } else { /* clear flicker and CANopen bits, keep others */ rd = LEDs->LEDred & (0xFFU ^ (CO_LED_flicker | CO_LED_CANopen)); gr = LEDs->LEDgreen & (0xFFU ^ (CO_LED_flicker | CO_LED_CANopen)); } /* calculate 10Hz flickering */ - if (rdFlickerNext) { rd |= CO_LED_flicker; } - else { gr |= CO_LED_flicker; } + if (rdFlickerNext) { + rd |= CO_LED_flicker; + } else { + gr |= CO_LED_flicker; + } } /* while (LEDs->LEDtmr50ms >= 50000) */ @@ -113,30 +121,50 @@ void CO_LEDs_process(CO_LEDs_t *LEDs, uint8_t rd_co, gr_co; /* CANopen red ERROR LED */ - if (ErrCANbusOff) { rd_co = 1;} - else if (NMTstate == CO_NMT_INITIALIZING){ rd_co = rd & CO_LED_flicker;} - else if (ErrRpdo) { rd_co = rd & CO_LED_flash_4;} - else if (ErrSync) { rd_co = rd & CO_LED_flash_3;} - else if (ErrHbCons) { rd_co = rd & CO_LED_flash_2;} - else if (ErrCANbusWarn) { rd_co = rd & CO_LED_flash_1;} - else if (ErrOther) { rd_co = rd & CO_LED_blink;} - else { rd_co = 0;} + if (ErrCANbusOff) { + rd_co = 1; + } else if (NMTstate == CO_NMT_INITIALIZING) { + rd_co = rd & CO_LED_flicker; + } else if (ErrRpdo) { + rd_co = rd & CO_LED_flash_4; + } else if (ErrSync) { + rd_co = rd & CO_LED_flash_3; + } else if (ErrHbCons) { + rd_co = rd & CO_LED_flash_2; + } else if (ErrCANbusWarn) { + rd_co = rd & CO_LED_flash_1; + } else if (ErrOther) { + rd_co = rd & CO_LED_blink; + } else { + rd_co = 0; + } /* CANopen green RUN LED */ - if (LSSconfig) {gr_co = gr & CO_LED_flicker;} - else if (firmwareDownload) {gr_co = gr & CO_LED_flash_3;} - else if (NMTstate == CO_NMT_STOPPED) {gr_co = gr & CO_LED_flash_1;} - else if (NMTstate == CO_NMT_PRE_OPERATIONAL){gr_co = gr & CO_LED_blink;} - else if (NMTstate == CO_NMT_OPERATIONAL) {gr_co = 1;} - else {gr_co = 0;} - - if (rd_co != 0U) { rd |= CO_LED_CANopen; } - if (gr_co != 0U) { gr |= CO_LED_CANopen; } + if (LSSconfig) { + gr_co = gr & CO_LED_flicker; + } else if (firmwareDownload) { + gr_co = gr & CO_LED_flash_3; + } else if (NMTstate == CO_NMT_STOPPED) { + gr_co = gr & CO_LED_flash_1; + } else if (NMTstate == CO_NMT_PRE_OPERATIONAL) { + gr_co = gr & CO_LED_blink; + } else if (NMTstate == CO_NMT_OPERATIONAL) { + gr_co = 1; + } else { + gr_co = 0; + } + + if (rd_co != 0U) { + rd |= CO_LED_CANopen; + } + if (gr_co != 0U) { + gr |= CO_LED_CANopen; + } LEDs->LEDred = rd; LEDs->LEDgreen = gr; } /* if (tick) */ -#if ((CO_CONFIG_LEDS) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_LEDS)&CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL) { uint32_t diff = 50000 - LEDs->LEDtmr50ms; if (*timerNext_us > diff) { diff --git a/304/CO_GFC.c b/304/CO_GFC.c index 8618c0c8..bbf6dde0 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -21,7 +21,7 @@ #include "304/CO_GFC.h" -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 /* * Custom function for reading or writing OD object. @@ -47,7 +47,7 @@ OD_write_1300(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* return OD_writeOriginal(stream, buf, count, countWritten); } -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) != 0 static void CO_GFC_receive(void* object, void* msg) { CO_GFC_t* GFC; @@ -73,10 +73,9 @@ CO_GFC_initCallbackEnterSafeState(CO_GFC_t* GFC, void* object, void (*pFunctSign } #endif - CO_ReturnError_t -CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC_CANdevRx, uint16_t GFC_rxIdx, uint16_t CANidRxGFC, - CO_CANmodule_t* GFC_CANdevTx, uint16_t GFC_txIdx, uint16_t CANidTxGFC) { +CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC_CANdevRx, uint16_t GFC_rxIdx, + uint16_t CANidRxGFC, CO_CANmodule_t* GFC_CANdevTx, uint16_t GFC_txIdx, uint16_t CANidTxGFC) { if ((GFC == NULL) || (OD_1300_gfcParameter == NULL) || (GFC_CANdevRx == NULL) || (GFC_CANdevTx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -93,14 +92,9 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC GFC->OD_gfcParam_ext.write = OD_write_1300; (void)OD_extension_init(OD_1300_gfcParameter, &GFC->OD_gfcParam_ext); -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_PRODUCER) != 0 GFC->CANdevTx = GFC_CANdevTx; - GFC->CANtxBuff = CO_CANtxBufferInit(GFC->CANdevTx, - GFC_txIdx, - CANidTxGFC, - false, - 0, - false); + GFC->CANtxBuff = CO_CANtxBufferInit(GFC->CANdevTx, GFC_txIdx, CANidTxGFC, false, 0, false); if (GFC->CANtxBuff == NULL) { return CO_ERROR_TX_UNCONFIGURED; @@ -110,15 +104,10 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC (void)CANidTxGFC; /* unused */ #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) != 0 GFC->functSignalObjectSafe = NULL; GFC->pFunctSignalSafe = NULL; - const CO_ReturnError_t r = CO_CANrxBufferInit(GFC_CANdevRx, - GFC_rxIdx, - CANidRxGFC, - 0x7FF, - false, - (void*)GFC, + const CO_ReturnError_t r = CO_CANrxBufferInit(GFC_CANdevRx, GFC_rxIdx, CANidRxGFC, 0x7FF, false, (void*)GFC, CO_GFC_receive); if (r != CO_ERROR_NO) { return r; @@ -131,7 +120,7 @@ CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC return CO_ERROR_NO; } -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_PRODUCER) != 0 CO_ReturnError_t CO_GFCsend(CO_GFC_t* GFC) { if (GFC->valid) { diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index a6074fb6..003e5e3e 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -22,12 +22,12 @@ #include "304/CO_SRDO.h" -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 #include "301/crc16-ccitt.h" /* verify configuration */ -#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) == 0 +#if ((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_ENABLE) == 0 #error CO_CONFIG_CRC16_ENABLE must be enabled. #endif @@ -36,10 +36,10 @@ #endif /* values for informationDirection and configurationValid */ -#define CO_SRDO_INVALID (0U) -#define CO_SRDO_TX (1U) -#define CO_SRDO_RX (2U) -#define CO_SRDO_VALID_MAGIC (0xA5U) +#define CO_SRDO_INVALID (0U) +#define CO_SRDO_TX (1U) +#define CO_SRDO_RX (2U) +#define CO_SRDO_VALID_MAGIC (0xA5U) /* macro for information about SRDO configuration error */ #define ERR_INFO(index, subindex, info) (((uint32_t)(index) << 16) | ((uint32_t)(subindex) << 8) | ((uint32_t)(info))) @@ -55,17 +55,16 @@ CO_SRDO_receive_normal(void* object, void* msg) { (void)memcpy(SRDO->CANrxData[0], data, sizeof(SRDO->CANrxData[0])); CO_FLAG_SET(SRDO->CANrxNew[0]); -#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles SRDO. */ if (SRDO->pFunctSignalPre != NULL) { SRDO->pFunctSignalPre(SRDO->functSignalObjectPre); } #endif - } - else if (DLC < SRDO->dataLength) { + } else if (DLC < SRDO->dataLength) { SRDO->rxSrdoShort = true; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } static void @@ -79,17 +78,16 @@ CO_SRDO_receive_inverted(void* object, void* msg) { (void)memcpy(SRDO->CANrxData[1], data, sizeof(SRDO->CANrxData[1])); CO_FLAG_SET(SRDO->CANrxNew[1]); -#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles SRDO. */ if (SRDO->pFunctSignalPre != NULL) { SRDO->pFunctSignalPre(SRDO->functSignalObjectPre); } #endif - } - else if (DLC < SRDO->dataLength) { + } else if (DLC < SRDO->dataLength) { SRDO->rxSrdoShort = true; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } /* Set OD object 13FE:00 to CO_SRDO_INVALID and clear configurationValid flag. */ @@ -112,16 +110,17 @@ configurationValidUnset(CO_SRDOGuard_t* SRDOGuard) { * For more information see file CO_ODinterface.h, OD_IO_t. */ static ODR_t -OD_write_dummy(OD_stream_t *stream, const void *buf, OD_size_t count, OD_size_t *countWritten) -{ - (void) stream; (void) buf; - if (countWritten != NULL) { *countWritten = count; } +OD_write_dummy(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + (void)stream; + (void)buf; + if (countWritten != NULL) { + *countWritten = count; + } return ODR_OK; } static ODR_t -OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countRead) -{ +OD_read_dummy(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { if ((buf == NULL) || (stream == NULL) || (countRead == NULL)) { return ODR_DEV_INCOMPAT; } @@ -138,18 +137,18 @@ OD_read_dummy(OD_stream_t *stream, void *buf, OD_size_t count, OD_size_t *countR #ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION static bool_t -OD_not_write_same_value(OD_stream_t *stream, const void *buf, OD_size_t count) { +OD_not_write_same_value(OD_stream_t* stream, const void* buf, OD_size_t count) { // The conformance test tool does not recognize CANopen Safety and on all object dictionaty tries to read and write the same value OD_size_t countRead = 0; - uint8_t bufRead[6] = { 0 }; - if( count > 6U ) { + uint8_t bufRead[6] = {0}; + if (count > 6U) { return false; } ODR_t returnCode = OD_readOriginal(stream, bufRead, count, &countRead); - if ( returnCode != ODR_OK ){ + if (returnCode != ODR_OK) { return false; } - if ( memcmp((const void *)(buf),(const void *)(bufRead),count) == 0 ){ + if (memcmp((const void*)(buf), (const void*)(bufRead), count) == 0) { return true; } return false; @@ -185,7 +184,7 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t } #ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION - if( OD_not_write_same_value(stream, buf, count) ) { + if (OD_not_write_same_value(stream, buf, count)) { return ODR_OK; } #endif @@ -193,7 +192,7 @@ OD_write_SRDO_communicationParam(OD_stream_t* stream, const void* buf, OD_size_t CO_SRDO_t* SRDO = stream->object; CO_SRDOGuard_t* SRDOGuard = SRDO->SRDOGuard; uint8_t bufCopy[4]; - (void)memcpy((void *)(bufCopy), (const void *)(buf), count); + (void)memcpy((void*)(bufCopy), (const void*)(buf), count); /* Writing Object Dictionary variable */ if (SRDOGuard->NMTisOperational) { @@ -255,7 +254,7 @@ OD_write_SRDO_mappingParam(OD_stream_t* stream, const void* buf, OD_size_t count } #ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION - if( OD_not_write_same_value(stream, buf, count) ) { + if (OD_not_write_same_value(stream, buf, count)) { return ODR_OK; } #endif @@ -310,9 +309,9 @@ OD_write_13FE(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* /* Data cannot be transferred or stored to the application because of the present device state. */ return ODR_DATA_DEV_STATE; } - + uint8_t configurationValid = CO_getUint8(buf); - if( configurationValid == CO_SRDO_VALID_MAGIC ) { + if (configurationValid == CO_SRDO_VALID_MAGIC) { SRDOGuard->configurationValid = true; } else { SRDOGuard->configurationValid = false; @@ -342,7 +341,7 @@ OD_write_13FF(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* return OD_writeOriginal(stream, buf, count, countWritten); } -#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 void CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalPre)(void* object)) { if (SRDO != NULL) { @@ -354,7 +353,7 @@ CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalPre)(v CO_ReturnError_t CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, - OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo) { + OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo) { ODR_t odRet; uint8_t configurationValid; @@ -365,7 +364,7 @@ CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationVa /* clear object */ (void)memset(SRDOGuard, 0, sizeof(CO_SRDOGuard_t)); - + SRDOGuard->OD_13FE_entry = OD_13FE_configurationValid; SRDOGuard->OD_13FF_entry = OD_13FF_safetyConfigurationSignature; @@ -394,7 +393,7 @@ CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationVa *errInfo = (((uint32_t)OD_getIndex(OD_13FE_configurationValid)) << 8) | 1U; return CO_ERROR_OD_PARAMETERS; } - if( configurationValid == CO_SRDO_VALID_MAGIC ) { + if (configurationValid == CO_SRDO_VALID_MAGIC) { SRDOGuard->configurationValid = true; } else { SRDOGuard->configurationValid = false; @@ -404,7 +403,7 @@ CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationVa } CO_ReturnError_t -CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, uint32_t* errInfo) { +CO_SRDO_config(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, uint32_t* errInfo) { CO_ReturnError_t ret = CO_ERROR_NO; uint32_t err = 0; bool_t configurationInProgress = false; @@ -426,45 +425,36 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, if (err == 0U) { if (OD_get_u8(SRDOGuard->OD_13FE_entry, 0, &configurationValid, true) != ODR_OK) { err = ERR_INFO(0x13FEUL, 0, 1); - } - else if (OD_get_u16(SRDOGuard->OD_13FF_entry, SRDO_Index + 1U, &crcSignatureFromOD, true) != ODR_OK) { + } else if (OD_get_u16(SRDOGuard->OD_13FF_entry, SRDO_Index + 1U, &crcSignatureFromOD, true) != ODR_OK) { err = ERR_INFO(0x13FFUL, SRDO_Index + 1UL, 1); - } - else if (OD_get_u8(SRDO->OD_communicationParam_entry, 0, &cp_highestSubindexSupported, true) != ODR_OK) { + } else if (OD_get_u8(SRDO->OD_communicationParam_entry, 0, &cp_highestSubindexSupported, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 0, 1); - } - else if (OD_get_u8(SRDO->OD_communicationParam_entry, 1, &informationDirection, true) != ODR_OK) { + } else if (OD_get_u8(SRDO->OD_communicationParam_entry, 1, &informationDirection, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 1, 1); - } - else if (OD_get_u16(SRDO->OD_communicationParam_entry, 2, &safetyCycleTime, true) != ODR_OK) { + } else if (OD_get_u16(SRDO->OD_communicationParam_entry, 2, &safetyCycleTime, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 2, 1); - } - else if (OD_get_u8(SRDO->OD_communicationParam_entry, 3, &safetyRelatedValidationTime, true) != ODR_OK) { + } else if (OD_get_u8(SRDO->OD_communicationParam_entry, 3, &safetyRelatedValidationTime, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 3, 1); - } - else if (OD_get_u8(SRDO->OD_communicationParam_entry, 4, &transmissionType, true) != ODR_OK) { + } else if (OD_get_u8(SRDO->OD_communicationParam_entry, 4, &transmissionType, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 4, 1); - } - else if (OD_get_u32(SRDO->OD_communicationParam_entry, 5, &COB_ID1_normal, true) != ODR_OK) { + } else if (OD_get_u32(SRDO->OD_communicationParam_entry, 5, &COB_ID1_normal, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 5, 1); - } - else if (OD_get_u32(SRDO->OD_communicationParam_entry, 6, &COB_ID2_inverted, true) != ODR_OK) { + } else if (OD_get_u32(SRDO->OD_communicationParam_entry, 6, &COB_ID2_inverted, true) != ODR_OK) { err = ERR_INFO(0x1301UL + SRDO_Index, 6, 1); - } - else if (OD_get_u8(SRDO->OD_mappingParam_entry, 0, &mappedObjectsCount, true) != ODR_OK) { + } else if (OD_get_u8(SRDO->OD_mappingParam_entry, 0, &mappedObjectsCount, true) != ODR_OK) { err = ERR_INFO(0x1381UL + SRDO_Index, 0, 1); - } - else { + } else { for (uint8_t i = 0; i < mappedObjectsCount; i++) { - if (OD_get_u32(SRDO->OD_mappingParam_entry, i+1U, &mapping[i], true) != ODR_OK) { - err = ERR_INFO(0x1381UL + SRDO_Index, i+1UL, 1); + if (OD_get_u32(SRDO->OD_mappingParam_entry, i + 1U, &mapping[i], true) != ODR_OK) { + err = ERR_INFO(0x1381UL + SRDO_Index, i + 1UL, 1); break; } } } /* if OD contains default COB_IDs, add node-id */ - if ((COB_ID1_normal == SRDO->defaultCOB_ID) && (COB_ID2_inverted == ((uint32_t)SRDO->defaultCOB_ID + 1UL)) && (SRDO->nodeId <= 64U)) { + if ((COB_ID1_normal == SRDO->defaultCOB_ID) && (COB_ID2_inverted == ((uint32_t)SRDO->defaultCOB_ID + 1UL)) + && (SRDO->nodeId <= 64U)) { uint32_t add = (uint32_t)SRDO->nodeId * 2U; COB_ID1_normal += add; COB_ID2_inverted += add; @@ -485,29 +475,21 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, if ((err == 0U) && configurationInProgress) { if (cp_highestSubindexSupported != 6U) { err = ERR_INFO(0x1301UL + SRDO_Index, 0, 2); - } - else if (informationDirection > 3U) { + } else if (informationDirection > 3U) { err = ERR_INFO(0x1301UL + SRDO_Index, 1, 2); - } - else if (safetyCycleTime < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000U) + 1U)) { + } else if (safetyCycleTime < ((CO_CONFIG_SRDO_MINIMUM_DELAY / 1000U) + 1U)) { err = ERR_INFO(0x1301UL + SRDO_Index, 2, 2); - } - else if (safetyRelatedValidationTime < 1U) { + } else if (safetyRelatedValidationTime < 1U) { err = ERR_INFO(0x1301UL + SRDO_Index, 3, 2); - } - else if (transmissionType != 254U) { + } else if (transmissionType != 254U) { err = ERR_INFO(0x1301UL + SRDO_Index, 4, 2); - } - else if ((COB_ID1_normal < 0x101U) || ((COB_ID1_normal & 1U) == 0U)) { + } else if ((COB_ID1_normal < 0x101U) || ((COB_ID1_normal & 1U) == 0U)) { err = ERR_INFO(0x1301UL + SRDO_Index, 5, 2); - } - else if (((COB_ID1_normal + 1U) != COB_ID2_inverted) || (COB_ID2_inverted > 0x180U)) { + } else if (((COB_ID1_normal + 1U) != COB_ID2_inverted) || (COB_ID2_inverted > 0x180U)) { err = ERR_INFO(0x1301UL + SRDO_Index, 6, 2); - } - else if ((mappedObjectsCount > CO_SRDO_MAX_MAPPED_ENTRIES) || ((mappedObjectsCount & 1U) != 0U)) { + } else if ((mappedObjectsCount > CO_SRDO_MAX_MAPPED_ENTRIES) || ((mappedObjectsCount & 1U) != 0U)) { err = ERR_INFO(0x1381UL + SRDO_Index, 0, 2); - } - else { + } else { /* MISRA C 2004 14.10 */ } } @@ -520,18 +502,18 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, crcResult = crc16_ccitt(&informationDirection, 1, crcResult); tmp_u16 = CO_SWAP_16(safetyCycleTime); - crcResult = crc16_ccitt((uint8_t *)&tmp_u16, 2, crcResult); + crcResult = crc16_ccitt((uint8_t*)&tmp_u16, 2, crcResult); crcResult = crc16_ccitt(&safetyRelatedValidationTime, 1, crcResult); tmp_u32 = CO_SWAP_32(COB_ID1_normal); - crcResult = crc16_ccitt((uint8_t *)&tmp_u32, 4, crcResult); + crcResult = crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); tmp_u32 = CO_SWAP_32(COB_ID2_inverted); - crcResult = crc16_ccitt((uint8_t *)&tmp_u32, 4, crcResult); + crcResult = crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); crcResult = crc16_ccitt(&mappedObjectsCount, 1, crcResult); for (uint8_t i = 0; i < mappedObjectsCount; i++) { uint8_t crcsubindex = i + 1U; crcResult = crc16_ccitt(&crcsubindex, 1, crcResult); tmp_u32 = CO_SWAP_32(mapping[i]); - crcResult = crc16_ccitt((uint8_t *)&tmp_u32, 4, crcResult); + crcResult = crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); } if (crcResult != crcSignatureFromOD) { @@ -546,11 +528,11 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, for (uint8_t i = 0; i < mappedObjectsCount; i++) { uint8_t plain_inverted = i % 2U; uint32_t map = mapping[i]; - uint16_t index = (uint16_t) (map >> 16); - uint8_t subIndex = (uint8_t) (map >> 8); - uint8_t mappedLengthBits = (uint8_t) map; + uint16_t index = (uint16_t)(map >> 16); + uint8_t subIndex = (uint8_t)(map >> 8); + uint8_t mappedLengthBits = (uint8_t)map; uint8_t mappedLength = mappedLengthBits >> 3; - OD_IO_t *OD_IO = &SRDO->OD_IO[i]; + OD_IO_t* OD_IO = &SRDO->OD_IO[i]; /* total SRDO length can not be more than CO_SRDO_MAX_SIZE bytes */ if (mappedLength > CO_SRDO_MAX_SIZE) { @@ -558,7 +540,7 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, } /* is there a reference to the dummy entry */ else if ((index < 0x20U) && (subIndex == 0U)) { - OD_stream_t *stream = &OD_IO->stream; + OD_stream_t* stream = &OD_IO->stream; (void)memset(stream, 0, sizeof(OD_stream_t)); stream->dataLength = mappedLength; stream->dataOffset = mappedLength; @@ -568,18 +550,16 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, /* find entry in the Object Dictionary */ else { OD_IO_t OD_IOcopy; - OD_entry_t *entry = OD_find(SRDO->OD, index); + OD_entry_t* entry = OD_find(SRDO->OD, index); ODR_t odRet = OD_getSub(entry, subIndex, &OD_IOcopy, false); if (odRet != ODR_OK) { err = ERR_INFO(0x1381UL + SRDO_Index, i + 1UL, 5); - } - else { + } else { /* verify access attributes, byte alignment and length */ - OD_attr_t testAttribute = (informationDirection == CO_SRDO_RX) ? (OD_attr_t)(ODA_RSRDO) : (OD_attr_t)(ODA_TSRDO); - if (((OD_IOcopy.stream.attribute & testAttribute) == 0U) - || ((mappedLengthBits & 0x07U) != 0U) - || (OD_IOcopy.stream.dataLength < mappedLength) - ) { + OD_attr_t testAttribute = (informationDirection == CO_SRDO_RX) ? (OD_attr_t)(ODA_RSRDO) + : (OD_attr_t)(ODA_TSRDO); + if (((OD_IOcopy.stream.attribute & testAttribute) == 0U) || ((mappedLengthBits & 0x07U) != 0U) + || (OD_IOcopy.stream.dataLength < mappedLength)) { err = ERR_INFO(0x1381UL + SRDO_Index, i + 1UL, 6); } @@ -597,11 +577,9 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, if (err == 0U) { if (srdoDataLength[0] != srdoDataLength[1]) { err = ERR_INFO(0x1381UL + SRDO_Index, 0, 7); - } - else if ((srdoDataLength[0] == 0U) || (srdoDataLength[0] > CO_SRDO_MAX_SIZE)) { + } else if ((srdoDataLength[0] == 0U) || (srdoDataLength[0] > CO_SRDO_MAX_SIZE)) { err = ERR_INFO(0x1381UL + SRDO_Index, 0, 8); - } - else { + } else { SRDO->dataLength = srdoDataLength[0]; SRDO->mappedObjectsCount = mappedObjectsCount; } @@ -611,24 +589,16 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, /* Configure CAN tx buffers */ if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_TX)) { /* Normal Configuration */ - SRDO->CANtxBuff[0] = CO_CANtxBufferInit(SRDO->CANdevTx[0], - SRDO->CANdevTxIdx[0], - (uint16_t)COB_ID1_normal, - false, - SRDO->dataLength, - false); + SRDO->CANtxBuff[0] = CO_CANtxBufferInit(SRDO->CANdevTx[0], SRDO->CANdevTxIdx[0], (uint16_t)COB_ID1_normal, + false, SRDO->dataLength, false); if (SRDO->CANtxBuff[0] == NULL) { err = ERR_INFO(0x1301UL + SRDO_Index, 5, 10); } /* Inverted Configuration */ - SRDO->CANtxBuff[1] = CO_CANtxBufferInit(SRDO->CANdevTx[1], - SRDO->CANdevTxIdx[1], - (uint16_t)COB_ID2_inverted, - false, - SRDO->dataLength, - false); + SRDO->CANtxBuff[1] = CO_CANtxBufferInit(SRDO->CANdevTx[1], SRDO->CANdevTxIdx[1], (uint16_t)COB_ID2_inverted, + false, SRDO->dataLength, false); if (SRDO->CANtxBuff[1] == NULL) { err = ERR_INFO(0x1301UL + SRDO_Index, 6, 10); @@ -638,26 +608,16 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, /* Configure CAN rx buffers */ if ((err == 0U) && configurationInProgress && (informationDirection == CO_SRDO_RX)) { /* Normal Configuration */ - ret = CO_CANrxBufferInit(SRDO->CANdevRx[0], - SRDO->CANdevRxIdx[0], - (uint16_t)COB_ID1_normal, - 0x7FF, - false, - (void*)SRDO, - CO_SRDO_receive_normal); + ret = CO_CANrxBufferInit(SRDO->CANdevRx[0], SRDO->CANdevRxIdx[0], (uint16_t)COB_ID1_normal, 0x7FF, false, + (void*)SRDO, CO_SRDO_receive_normal); if (ret != CO_ERROR_NO) { err = ERR_INFO(0x1301UL + SRDO_Index, 5, 11); } /* Inverted Configuration */ - ret = CO_CANrxBufferInit(SRDO->CANdevRx[1], - SRDO->CANdevRxIdx[1], - (uint16_t)COB_ID2_inverted, - 0x7FF, - false, - (void*)SRDO, - CO_SRDO_receive_inverted); + ret = CO_CANrxBufferInit(SRDO->CANdevRx[1], SRDO->CANdevRxIdx[1], (uint16_t)COB_ID2_inverted, 0x7FF, false, + (void*)SRDO, CO_SRDO_receive_inverted); if (ret != CO_ERROR_NO) { err = ERR_INFO(0x1301UL + SRDO_Index, 6, 11); @@ -669,15 +629,13 @@ CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, SRDO->informationDirection = informationDirection; SRDO->cycleTime_us = (uint32_t)safetyCycleTime * 1000U; SRDO->validationTime_us = (uint32_t)safetyRelatedValidationTime * 1000U; - } - else { + } else { if (ret == CO_ERROR_NO) { CO_errorReport(SRDO->em, CO_EM_SRDO_CONFIGURATION, CO_EMC_DATA_SET, err); configurationValidUnset(SRDO->SRDOGuard); } } - if (errInfo != NULL) { *errInfo = err; } @@ -695,9 +653,8 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if ((SRDO == NULL) || (SRDOGuard == NULL) || (OD == NULL) || (em == NULL) - || (OD_130x_SRDOCommPar == NULL) || (OD_138x_SRDOMapPar == NULL) - || (CANdevRxNormal == NULL) || (CANdevRxInverted == NULL) + if ((SRDO == NULL) || (SRDOGuard == NULL) || (OD == NULL) || (em == NULL) || (OD_130x_SRDOCommPar == NULL) + || (OD_138x_SRDOMapPar == NULL) || (CANdevRxNormal == NULL) || (CANdevRxInverted == NULL) || (CANdevTxNormal == NULL) || (CANdevTxInverted == NULL)) { ret = CO_ERROR_ILLEGAL_ARGUMENT; } @@ -714,12 +671,12 @@ CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_ SRDO->CANdevTx[1] = CANdevTxInverted; SRDO->CANdevRx[0] = CANdevRxNormal; SRDO->CANdevRx[1] = CANdevRxInverted; - + SRDO->CANdevTxIdx[0] = CANdevTxIdxNormal; SRDO->CANdevTxIdx[1] = CANdevTxIdxInverted; SRDO->CANdevRxIdx[0] = CANdevRxIdxNormal; SRDO->CANdevRxIdx[1] = CANdevRxIdxInverted; - + SRDO->OD_communicationParam_entry = OD_130x_SRDOCommPar; SRDO->OD_mappingParam_entry = OD_138x_SRDOMapPar; @@ -768,14 +725,17 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext if (NMTisOperational && (SRDO->informationDirection != CO_SRDO_INVALID) && SRDO->SRDOGuard->configurationValid && (SRDO->internalState >= CO_SRDO_state_unknown)) { SRDO->cycleTimer = (SRDO->cycleTimer > timeDifference_us) ? (SRDO->cycleTimer - timeDifference_us) : 0U; - SRDO->invertedDelay = (SRDO->invertedDelay > timeDifference_us) ? (SRDO->invertedDelay - timeDifference_us) : 0U; - SRDO->validationTimer = (SRDO->validationTimer > timeDifference_us) ? (SRDO->validationTimer - timeDifference_us) : 0U; + SRDO->invertedDelay = (SRDO->invertedDelay > timeDifference_us) ? (SRDO->invertedDelay - timeDifference_us) + : 0U; + SRDO->validationTimer = (SRDO->validationTimer > timeDifference_us) + ? (SRDO->validationTimer - timeDifference_us) + : 0U; /* Detect transition to NMT operational */ if (!SRDO->NMTisOperationalPrevious) { SRDO->cycleTimer = (SRDO->informationDirection == CO_SRDO_TX) - ? ((uint32_t)SRDO->nodeId * 500U) /* 0.5ms * node-ID delay*/ - : SRDO->cycleTime_us; + ? ((uint32_t)SRDO->nodeId * 500U) /* 0.5ms * node-ID delay*/ + : SRDO->cycleTime_us; SRDO->validationTimer = SRDO->cycleTime_us; SRDO->internalState = CO_SRDO_state_initializing; SRDO->nextIsNormal = true; @@ -783,21 +743,20 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext if (SRDO->internalState <= CO_SRDO_state_unknown) { SRDO->internalState = CO_SRDO_state_error_internal; /* should not happen */ - } - else if (SRDO->informationDirection == CO_SRDO_TX) { + } else if (SRDO->informationDirection == CO_SRDO_TX) { if (SRDO->nextIsNormal) { if (SRDO->cycleTimer == 0U) { - uint8_t *dataSRDO[2] = {&SRDO->CANtxBuff[0]->data[0], &SRDO->CANtxBuff[1]->data[0]}; - size_t verifyLength[2] = { 0, 0 }; + uint8_t* dataSRDO[2] = {&SRDO->CANtxBuff[0]->data[0], &SRDO->CANtxBuff[1]->data[0]}; + size_t verifyLength[2] = {0, 0}; /* copy mapped data from Object Dictionary into CAN buffers */ for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) { uint8_t plain_inverted = i % 2U; - OD_IO_t *OD_IO = &SRDO->OD_IO[i]; - OD_stream_t *stream = &OD_IO->stream; + OD_IO_t* OD_IO = &SRDO->OD_IO[i]; + OD_stream_t* stream = &OD_IO->stream; /* get mappedLength from temporary storage */ - uint8_t mappedLength = (uint8_t) stream->dataOffset; + uint8_t mappedLength = (uint8_t)stream->dataOffset; /* additional safety check */ verifyLength[plain_inverted] += mappedLength; @@ -812,18 +771,17 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } /* If mappedLength is smaller than ODdataLength, use auxiliary buffer */ uint8_t buf[CO_SRDO_MAX_SIZE]; - uint8_t *dataSRDOCopy; + uint8_t* dataSRDOCopy; if (ODdataLength > mappedLength) { (void)memset(buf, 0, sizeof(buf)); dataSRDOCopy = buf; - } - else { + } else { dataSRDOCopy = dataSRDO[plain_inverted]; } /* Set stream.dataOffset to zero, perform OD_IO.read() * and store mappedLength back to stream.dataOffset */ - stream->dataOffset= 0; + stream->dataOffset = 0; OD_size_t countRd; OD_IO->read(stream, dataSRDOCopy, ODdataLength, &countRd); stream->dataOffset = mappedLength; @@ -831,8 +789,8 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* swap multibyte data if big-endian */ #ifdef CO_BIG_ENDIAN if ((stream->attribute & ODA_MB) != 0) { - uint8_t *lo = dataSRDOCopy; - uint8_t *hi = dataSRDOCopy + ODdataLength - 1; + uint8_t* lo = dataSRDOCopy; + uint8_t* hi = dataSRDOCopy + ODdataLength - 1; while (lo < hi) { uint8_t swap = *lo; *lo++ = *hi; @@ -849,12 +807,12 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext dataSRDO[plain_inverted] += mappedLength; } - if ((verifyLength[0] != verifyLength[1]) || (verifyLength[0] > CO_SRDO_MAX_SIZE) || (verifyLength[0] != SRDO->dataLength)) { + if ((verifyLength[0] != verifyLength[1]) || (verifyLength[0] > CO_SRDO_MAX_SIZE) + || (verifyLength[0] != SRDO->dataLength)) { SRDO->internalState = CO_SRDO_state_error_internal; /* should not happen */ - } - else { + } else { bool_t data_ok = true; -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_CHECK_TX) != 0 /* check data before sending (optional) */ for (uint8_t i = 0; i < SRDO->dataLength; i++) { if ((uint8_t)(~SRDO->CANtxBuff[0]->data[i]) != SRDO->CANtxBuff[1]->data[i]) { @@ -866,12 +824,12 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext #endif if (data_ok) { if (CO_CANsend(SRDO->CANdevTx[0], SRDO->CANtxBuff[0]) == CO_ERROR_NO) { - SRDO->cycleTimer = SRDO->cycleTime_us; /* cycleTime_us is verified, result can't be <0 */ + SRDO->cycleTimer = + SRDO->cycleTime_us; /* cycleTime_us is verified, result can't be <0 */ SRDO->invertedDelay = CO_CONFIG_SRDO_MINIMUM_DELAY; SRDO->nextIsNormal = false; SRDO->internalState = CO_SRDO_state_communicationEstablished; - } - else { + } else { SRDO->internalState = CO_SRDO_state_error_txFail; } } @@ -881,28 +839,25 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext if (SRDO->invertedDelay == 0U) { if (CO_CANsend(SRDO->CANdevTx[1], SRDO->CANtxBuff[1]) == CO_ERROR_NO) { SRDO->nextIsNormal = true; - } - else { + } else { SRDO->internalState = CO_SRDO_state_error_txFail; } } } -#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL) { if (*timerNext_us > SRDO->cycleTimer) { *timerNext_us = SRDO->cycleTimer; /* Schedule for the next message timer */ } } #endif - } - else { /* CO_SRDO_RX */ + } else { /* CO_SRDO_RX */ /* verify error from receive function */ if (SRDO->rxSrdoShort) { CO_errorReport(SRDO->em, CO_EM_RPDO_WRONG_LENGTH, CO_EMC_PDO_LENGTH, 0); SRDO->internalState = CO_SRDO_state_error_rxShort; - } - else if (CO_FLAG_READ(SRDO->CANrxNew[SRDO->nextIsNormal ? 0 : 1])) { + } else if (CO_FLAG_READ(SRDO->CANrxNew[SRDO->nextIsNormal ? 0 : 1])) { /* normal message received ? */ if (SRDO->nextIsNormal) { SRDO->validationTimer = SRDO->validationTime_us; @@ -914,7 +869,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext SRDO->validationTimer = SRDO->cycleTime_us; SRDO->nextIsNormal = true; - uint8_t *dataSRDO[2] = {&SRDO->CANrxData[0][0], &SRDO->CANrxData[1][0]}; + uint8_t* dataSRDO[2] = {&SRDO->CANrxData[0][0], &SRDO->CANrxData[1][0]}; bool_t data_ok = true; /* Verify, if normal and inverted data matches properly */ @@ -928,15 +883,15 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* copy data from CAN messages into mapped data from Object Dictionary */ if (data_ok) { - size_t verifyLength[2] = { 0, 0 }; + size_t verifyLength[2] = {0, 0}; for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) { uint8_t plain_inverted = i % 2U; - OD_IO_t *OD_IO = &SRDO->OD_IO[i]; - OD_stream_t *stream = &OD_IO->stream; + OD_IO_t* OD_IO = &SRDO->OD_IO[i]; + OD_stream_t* stream = &OD_IO->stream; /* get mappedLength from temporary storage */ - OD_size_t *dataOffset = &stream->dataOffset; - uint8_t mappedLength = (uint8_t) (*dataOffset); + OD_size_t* dataOffset = &stream->dataOffset; + uint8_t mappedLength = (uint8_t)(*dataOffset); /* additional safety check */ verifyLength[plain_inverted] += mappedLength; @@ -952,21 +907,20 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* Prepare data for writing into OD variable. If mappedLength * is smaller than ODdataLength, then use auxiliary buffer */ uint8_t buf[CO_SRDO_MAX_SIZE]; - uint8_t *dataOD; + uint8_t* dataOD; if (ODdataLength > mappedLength) { (void)memset(buf, 0, sizeof(buf)); (void)memcpy(buf, dataSRDO[plain_inverted], mappedLength); dataOD = buf; - } - else { + } else { dataOD = dataSRDO[plain_inverted]; } /* swap multibyte data if big-endian */ #ifdef CO_BIG_ENDIAN if ((stream->attribute & ODA_MB) != 0) { - uint8_t *lo = dataOD; - uint8_t *hi = dataOD + ODdataLength - 1; + uint8_t* lo = dataOD; + uint8_t* hi = dataOD + ODdataLength - 1; while (lo < hi) { uint8_t swap = *lo; *lo++ = *hi; @@ -979,39 +933,36 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext * and store mappedLength back to stream.dataOffset */ *dataOffset = 0; OD_size_t countWritten; - OD_IO->write(&OD_IO->stream, dataOD, - ODdataLength, &countWritten); + OD_IO->write(&OD_IO->stream, dataOD, ODdataLength, &countWritten); *dataOffset = mappedLength; dataSRDO[plain_inverted] += mappedLength; } /* for (uint8_t i = 0; i < SRDO->mappedObjectsCount; i++) */ /* safety check, this should not happen */ - if ((verifyLength[0] != verifyLength[1]) || (verifyLength[0] > CO_SRDO_MAX_SIZE) || (verifyLength[0] != SRDO->dataLength)) { + if ((verifyLength[0] != verifyLength[1]) || (verifyLength[0] > CO_SRDO_MAX_SIZE) + || (verifyLength[0] != SRDO->dataLength)) { SRDO->internalState = CO_SRDO_state_error_internal; - } - else { + } else { SRDO->internalState = CO_SRDO_state_communicationEstablished; } } /* if (data_ok) { */ CO_FLAG_CLEAR(SRDO->CANrxNew[0]); CO_FLAG_CLEAR(SRDO->CANrxNew[1]); - } /* inverted message received */ + } /* inverted message received */ + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } /* verify timeouts */ if (SRDO->cycleTimer == 0U) { SRDO->internalState = CO_SRDO_state_error_rxTimeoutSCT; - } - else if (SRDO->validationTimer == 0U) { + } else if (SRDO->validationTimer == 0U) { SRDO->internalState = CO_SRDO_state_error_rxTimeoutSRVT; - } - else { + } else { /* MISRA C 2004 14.10 */ } -#if ((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL) { if (*timerNext_us > SRDO->cycleTimer) { *timerNext_us = SRDO->cycleTimer; /* Schedule for the next message timer */ @@ -1022,20 +973,17 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } #endif } /* CO_SRDO_RX */ - } /* if (NMTisOperational && ... */ + } /* if (NMTisOperational && ... */ else { CO_FLAG_CLEAR(SRDO->CANrxNew[0]); CO_FLAG_CLEAR(SRDO->CANrxNew[1]); if (!SRDO->SRDOGuard->configurationValid) { SRDO->internalState = CO_SRDO_state_error_configuration; - } - else if (!NMTisOperational) { + } else if (!NMTisOperational) { SRDO->internalState = CO_SRDO_state_nmtNotOperational; - } - else if (SRDO->informationDirection == CO_SRDO_INVALID) { + } else if (SRDO->informationDirection == CO_SRDO_INVALID) { SRDO->internalState = CO_SRDO_state_deleted; - } - else { + } else { /* keep internalState unchanged */ /* MISRA C 2004 14.10 */ } diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 7336b9ba..1e78c0ac 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -23,8 +23,7 @@ #include "305/CO_LSSmaster.h" -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 - +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 /* * @defgroup CO_LSSmaster_state_t @@ -33,9 +32,9 @@ * has information if we currently have selected one or all slaves. This * allows for some basic error checking. */ -#define CO_LSSmaster_STATE_WAITING 0x00U -#define CO_LSSmaster_STATE_CFG_SLECTIVE 0x01U -#define CO_LSSmaster_STATE_CFG_GLOBAL 0x02U +#define CO_LSSmaster_STATE_WAITING 0x00U +#define CO_LSSmaster_STATE_CFG_SLECTIVE 0x01U +#define CO_LSSmaster_STATE_CFG_GLOBAL 0x02U /** @} */ /* CO_LSSmaster_state_t */ /* @@ -43,26 +42,27 @@ * @{ * */ -#define CO_LSSmaster_COMMAND_WAITING 0x00U -#define CO_LSSmaster_COMMAND_SWITCH_STATE 0x01U -#define CO_LSSmaster_COMMAND_CFG_BIT_TIMING 0x02U -#define CO_LSSmaster_COMMAND_CFG_NODE_ID 0x03U -#define CO_LSSmaster_COMMAND_CFG_STORE 0x04U -#define CO_LSSmaster_COMMAND_INQUIRE_VENDOR 0x05U -#define CO_LSSmaster_COMMAND_INQUIRE_PRODUCT 0x06U -#define CO_LSSmaster_COMMAND_INQUIRE_REV 0x07U -#define CO_LSSmaster_COMMAND_INQUIRE_SERIAL 0x08U -#define CO_LSSmaster_COMMAND_INQUIRE 0x09U -#define CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN 0x0AU +#define CO_LSSmaster_COMMAND_WAITING 0x00U +#define CO_LSSmaster_COMMAND_SWITCH_STATE 0x01U +#define CO_LSSmaster_COMMAND_CFG_BIT_TIMING 0x02U +#define CO_LSSmaster_COMMAND_CFG_NODE_ID 0x03U +#define CO_LSSmaster_COMMAND_CFG_STORE 0x04U +#define CO_LSSmaster_COMMAND_INQUIRE_VENDOR 0x05U +#define CO_LSSmaster_COMMAND_INQUIRE_PRODUCT 0x06U +#define CO_LSSmaster_COMMAND_INQUIRE_REV 0x07U +#define CO_LSSmaster_COMMAND_INQUIRE_SERIAL 0x08U +#define CO_LSSmaster_COMMAND_INQUIRE 0x09U +#define CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN 0x0AU /** @} */ /* CO_LSSmaster_command_t */ /* * @defgroup CO_LSSmaster_fs_t LSS master fastscan state machine * @{ */ -#define CO_LSSmaster_FS_STATE_CHECK 0x00U -#define CO_LSSmaster_FS_STATE_SCAN 0x01U -#define CO_LSSmaster_FS_STATE_VERIFY 0x02U +#define CO_LSSmaster_FS_STATE_CHECK 0x00U +#define CO_LSSmaster_FS_STATE_SCAN 0x01U +#define CO_LSSmaster_FS_STATE_VERIFY 0x02U + /** @} */ /* CO_LSSmaster_fs_t */ /* @@ -72,26 +72,25 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_LSSmaster_receive(void *object, void *msg) -{ - CO_LSSmaster_t *LSSmaster; +static void +CO_LSSmaster_receive(void* object, void* msg) { + CO_LSSmaster_t* LSSmaster; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); - LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */ + LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */ /* verify message length and message overflow (previous message was not processed yet) */ - if((DLC==8U) && !CO_FLAG_READ(LSSmaster->CANrxNew) && - (LSSmaster->command != CO_LSSmaster_COMMAND_WAITING)){ + if ((DLC == 8U) && !CO_FLAG_READ(LSSmaster->CANrxNew) && (LSSmaster->command != CO_LSSmaster_COMMAND_WAITING)) { /* copy data and set 'new message' flag */ (void)memcpy(LSSmaster->CANrxData, data, sizeof(LSSmaster->CANrxData)); CO_FLAG_SET(LSSmaster->CANrxNew); -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles further processing. */ - if(LSSmaster->pFunctSignal != NULL) { + if (LSSmaster->pFunctSignal != NULL) { LSSmaster->pFunctSignal(LSSmaster->functSignalObject); } #endif @@ -105,10 +104,8 @@ static void CO_LSSmaster_receive(void *object, void *msg) * or after the timeout expired. Only if no message has been received we have * to check for timeouts */ -static inline CO_LSSmaster_return_t CO_LSSmaster_check_timeout( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us) -{ +static inline CO_LSSmaster_return_t +CO_LSSmaster_check_timeout(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us) { CO_LSSmaster_return_t ret = CO_LSSmaster_WAIT_SLAVE; LSSmaster->timeoutTimer += timeDifference_us; @@ -120,21 +117,13 @@ static inline CO_LSSmaster_return_t CO_LSSmaster_check_timeout( return ret; } - -CO_ReturnError_t CO_LSSmaster_init( - CO_LSSmaster_t *LSSmaster, - uint16_t timeout_ms, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - uint16_t CANidLssSlave, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint16_t CANidLssMaster) -{ +CO_ReturnError_t +CO_LSSmaster_init(CO_LSSmaster_t* LSSmaster, uint16_t timeout_ms, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, + uint16_t CANidLssSlave, CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, uint16_t CANidLssMaster) { CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if ((LSSmaster == NULL) || (CANdevRx == NULL) || (CANdevTx == NULL)){ + if ((LSSmaster == NULL) || (CANdevRx == NULL) || (CANdevTx == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -144,30 +133,18 @@ CO_ReturnError_t CO_LSSmaster_init( LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); (void)memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData)); -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 LSSmaster->pFunctSignal = NULL; LSSmaster->functSignalObject = NULL; #endif /* configure LSS CAN Slave response message reception */ - ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - CANidLssSlave, - 0x7FF, - false, - (void*)LSSmaster, - CO_LSSmaster_receive); + ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, CANidLssSlave, 0x7FF, false, (void*)LSSmaster, + CO_LSSmaster_receive); /* configure LSS CAN Master message transmission */ LSSmaster->CANdevTx = CANdevTx; - LSSmaster->TXbuff = CO_CANtxBufferInit( - CANdevTx, - CANdevTxIdx, - CANidLssMaster, - false, - 8, - false); + LSSmaster->TXbuff = CO_CANtxBufferInit(CANdevTx, CANdevTxIdx, CANidLssMaster, false, 8, false); if (LSSmaster->TXbuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; @@ -176,86 +153,73 @@ CO_ReturnError_t CO_LSSmaster_init( return ret; } - -void CO_LSSmaster_changeTimeout( - CO_LSSmaster_t *LSSmaster, - uint16_t timeout_ms) -{ +void +CO_LSSmaster_changeTimeout(CO_LSSmaster_t* LSSmaster, uint16_t timeout_ms) { if (LSSmaster != NULL) { LSSmaster->timeout_us = (uint32_t)timeout_ms * 1000U; } } - -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_LSSmaster_initCallbackPre( - CO_LSSmaster_t *LSSmaster, - void *object, - void (*pFunctSignal)(void *object)) -{ - if(LSSmaster != NULL){ +#if ((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_LSSmaster_initCallbackPre(CO_LSSmaster_t* LSSmaster, void* object, void (*pFunctSignal)(void* object)) { + if (LSSmaster != NULL) { LSSmaster->functSignalObject = object; LSSmaster->pFunctSignal = pFunctSignal; } } #endif - /* * Helper function - initiate switch state */ -static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate( - CO_LSSmaster_t *LSSmaster, - CO_LSS_address_t *lssAddress) -{ - CO_LSSmaster_return_t ret; - - if (lssAddress != NULL) { - /* switch state select specific using LSS address */ - LSSmaster->state = CO_LSSmaster_STATE_CFG_SLECTIVE; - LSSmaster->command = CO_LSSmaster_COMMAND_SWITCH_STATE; - LSSmaster->timeoutTimer = 0; - - CO_FLAG_CLEAR(LSSmaster->CANrxNew); - (void)memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6U); - LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); - (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); - LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_PRODUCT; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.productCode); - (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); - LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_REV; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.revisionNumber); - (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); - LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_SERIAL; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.serialNumber); - (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); - - ret = CO_LSSmaster_WAIT_SLAVE; - } - else { - /* switch state global */ - LSSmaster->state = CO_LSSmaster_STATE_CFG_GLOBAL; - - CO_FLAG_CLEAR(LSSmaster->CANrxNew); - LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; - LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION; - (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2U); - (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); - - /* This is non-confirmed service! */ - ret = CO_LSSmaster_OK; - } - return ret; +static CO_LSSmaster_return_t +CO_LSSmaster_switchStateSelectInitiate(CO_LSSmaster_t* LSSmaster, CO_LSS_address_t* lssAddress) { + CO_LSSmaster_return_t ret; + + if (lssAddress != NULL) { + /* switch state select specific using LSS address */ + LSSmaster->state = CO_LSSmaster_STATE_CFG_SLECTIVE; + LSSmaster->command = CO_LSSmaster_COMMAND_SWITCH_STATE; + LSSmaster->timeoutTimer = 0; + + CO_FLAG_CLEAR(LSSmaster->CANrxNew); + (void)memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6U); + LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_PRODUCT; + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.productCode); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_REV; + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.revisionNumber); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_SERIAL; + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.serialNumber); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + + ret = CO_LSSmaster_WAIT_SLAVE; + } else { + /* switch state global */ + LSSmaster->state = CO_LSSmaster_STATE_CFG_GLOBAL; + + CO_FLAG_CLEAR(LSSmaster->CANrxNew); + LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL; + LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION; + (void)memset(&LSSmaster->TXbuff->data[2], 0, sizeof(LSSmaster->TXbuff->data) - 2U); + (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); + + /* This is non-confirmed service! */ + ret = CO_LSSmaster_OK; + } + return ret; } /* * Helper function - wait for confirmation */ -static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us) -{ +static CO_LSSmaster_return_t +CO_LSSmaster_switchStateSelectWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us) { CO_LSSmaster_return_t ret; if (CO_FLAG_READ(LSSmaster->CANrxNew)) { @@ -265,40 +229,34 @@ static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait( if (cs == CO_LSS_SWITCH_STATE_SEL) { /* confirmation received */ ret = CO_LSSmaster_OK; - } - else { + } else { ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } - } - else { + } else { ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } return ret; } -CO_LSSmaster_return_t CO_LSSmaster_swStateSelect( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSS_address_t *lssAddress) -{ +CO_LSSmaster_return_t +CO_LSSmaster_swStateSelect(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSS_address_t* lssAddress) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if (LSSmaster == NULL){ + if (LSSmaster == NULL) { return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* Initiate select */ - if ((LSSmaster->state == CO_LSSmaster_STATE_WAITING) && - (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)){ + if ((LSSmaster->state == CO_LSSmaster_STATE_WAITING) && (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { ret = CO_LSSmaster_switchStateSelectInitiate(LSSmaster, lssAddress); } /* Wait for confirmation */ else if (LSSmaster->command == CO_LSSmaster_COMMAND_SWITCH_STATE) { ret = CO_LSSmaster_switchStateSelectWait(LSSmaster, timeDifference_us); + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ @@ -306,19 +264,17 @@ CO_LSSmaster_return_t CO_LSSmaster_swStateSelect( } if (ret < CO_LSSmaster_OK) { /* switching failed, go back to waiting */ - LSSmaster->state=CO_LSSmaster_STATE_WAITING; + LSSmaster->state = CO_LSSmaster_STATE_WAITING; LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; } return ret; } - -CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect( - CO_LSSmaster_t *LSSmaster) -{ +CO_LSSmaster_return_t +CO_LSSmaster_swStateDeselect(CO_LSSmaster_t* LSSmaster) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if (LSSmaster == NULL){ + if (LSSmaster == NULL) { return CO_LSSmaster_ILLEGAL_ARGUMENT; } @@ -341,7 +297,6 @@ CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect( return ret; } - /* * Helper function - wait for confirmation, check for returned error code * @@ -360,11 +315,8 @@ CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect( * - CO_LSS_cfgBitTiming_t * - CO_LSS_cfgStore_t */ -static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - uint8_t csWait) -{ +static CO_LSSmaster_return_t +CO_LSSmaster_configureCheckWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint8_t csWait) { CO_LSSmaster_return_t ret; if (CO_FLAG_READ(LSSmaster->CANrxNew)) { @@ -375,19 +327,15 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( if (cs == csWait) { if (errorCode == 0U) { ret = CO_LSSmaster_OK; - } - else if (errorCode == 0xFFU) { + } else if (errorCode == 0xFFU) { ret = CO_LSSmaster_OK_MANUFACTURER; - } - else { + } else { ret = CO_LSSmaster_OK_ILLEGAL_ARGUMENT; } - } - else { + } else { ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } - } - else { + } else { ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } @@ -398,35 +346,30 @@ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait( return ret; } - -CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - uint16_t bit) -{ +CO_LSSmaster_return_t +CO_LSSmaster_configureBitTiming(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint16_t bit) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; uint8_t bitTiming; - if (LSSmaster == NULL){ + if (LSSmaster == NULL) { return CO_LSSmaster_ILLEGAL_ARGUMENT; } switch (bit) { - case 1000: bitTiming = CO_LSS_BIT_TIMING_1000; break; - case 800: bitTiming = CO_LSS_BIT_TIMING_800; break; - case 500: bitTiming = CO_LSS_BIT_TIMING_500; break; - case 250: bitTiming = CO_LSS_BIT_TIMING_250; break; - case 125: bitTiming = CO_LSS_BIT_TIMING_125; break; - case 50: bitTiming = CO_LSS_BIT_TIMING_50; break; - case 20: bitTiming = CO_LSS_BIT_TIMING_20; break; - case 10: bitTiming = CO_LSS_BIT_TIMING_10; break; - case 0: bitTiming = CO_LSS_BIT_TIMING_AUTO; break; - default: return CO_LSSmaster_ILLEGAL_ARGUMENT; break; + case 1000: bitTiming = CO_LSS_BIT_TIMING_1000; break; + case 800: bitTiming = CO_LSS_BIT_TIMING_800; break; + case 500: bitTiming = CO_LSS_BIT_TIMING_500; break; + case 250: bitTiming = CO_LSS_BIT_TIMING_250; break; + case 125: bitTiming = CO_LSS_BIT_TIMING_125; break; + case 50: bitTiming = CO_LSS_BIT_TIMING_50; break; + case 20: bitTiming = CO_LSS_BIT_TIMING_20; break; + case 10: bitTiming = CO_LSS_BIT_TIMING_10; break; + case 0: bitTiming = CO_LSS_BIT_TIMING_AUTO; break; + default: return CO_LSSmaster_ILLEGAL_ARGUMENT; break; } /* Initiate config bit */ - if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) && - (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)){ + if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) && (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { LSSmaster->command = CO_LSSmaster_COMMAND_CFG_BIT_TIMING; LSSmaster->timeoutTimer = 0; @@ -443,10 +386,9 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( /* Wait for confirmation */ else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_BIT_TIMING) { - ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, - CO_LSS_CFG_BIT_TIMING); + ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_BIT_TIMING); + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ @@ -455,24 +397,19 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( return ret; } - -CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - uint8_t nodeId) -{ +CO_LSSmaster_return_t +CO_LSSmaster_configureNodeId(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint8_t nodeId) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if ((LSSmaster == NULL) || !CO_LSS_NODE_ID_VALID(nodeId)){ + if ((LSSmaster == NULL) || !CO_LSS_NODE_ID_VALID(nodeId)) { return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* Initiate config node ID */ if (((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || - /* Let un-config node ID also be run in global mode for unconfiguring all nodes */ - ((LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL) && - (nodeId == CO_LSS_NODE_ID_ASSIGNMENT))) && - (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { + /* Let un-config node ID also be run in global mode for unconfiguring all nodes */ + ((LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL) && (nodeId == CO_LSS_NODE_ID_ASSIGNMENT))) + && (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { LSSmaster->command = CO_LSSmaster_COMMAND_CFG_NODE_ID; LSSmaster->timeoutTimer = 0; @@ -488,10 +425,9 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( /* Wait for confirmation */ else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_NODE_ID) { - ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, - CO_LSS_CFG_NODE_ID); + ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_NODE_ID); + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ @@ -500,20 +436,16 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( return ret; } - -CO_LSSmaster_return_t CO_LSSmaster_configureStore( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us) -{ +CO_LSSmaster_return_t +CO_LSSmaster_configureStore(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if (LSSmaster == NULL){ + if (LSSmaster == NULL) { return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* Initiate config store */ - if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) && - (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)){ + if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) && (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { LSSmaster->command = CO_LSSmaster_COMMAND_CFG_STORE; LSSmaster->timeoutTimer = 0; @@ -528,10 +460,9 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( /* Wait for confirmation */ else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_STORE) { - ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, - CO_LSS_CFG_STORE); + ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_us, CO_LSS_CFG_STORE); + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { /* finished */ @@ -540,21 +471,17 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( return ret; } - -CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( - CO_LSSmaster_t *LSSmaster, - uint16_t switchDelay_ms) -{ +CO_LSSmaster_return_t +CO_LSSmaster_ActivateBit(CO_LSSmaster_t* LSSmaster, uint16_t switchDelay_ms) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - if (LSSmaster == NULL){ + if (LSSmaster == NULL) { return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* for activating bit timing, we need to have all slaves set to config * state. This check makes it a bit harder to shoot ourselves in the foot */ - if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL) && - (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)){ + if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL) && (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; @@ -572,10 +499,8 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( /* * Helper function - send request */ -static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( - CO_LSSmaster_t *LSSmaster, - uint8_t cs) -{ +static CO_LSSmaster_return_t +CO_LSSmaster_inquireInitiate(CO_LSSmaster_t* LSSmaster, uint8_t cs) { CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = cs; (void)memset(&LSSmaster->TXbuff->data[1], 0, sizeof(LSSmaster->TXbuff->data) - 1U); @@ -587,12 +512,8 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate( /* * Helper function - wait for confirmation */ -static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - uint8_t csWait, - uint32_t *value) -{ +static CO_LSSmaster_return_t +CO_LSSmaster_inquireCheckWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint8_t csWait, uint32_t* value) { CO_LSSmaster_return_t ret; if (CO_FLAG_READ(LSSmaster->CANrxNew)) { @@ -602,97 +523,85 @@ static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait( if (cs == csWait) { ret = CO_LSSmaster_OK; - } - else { + } else { ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } - } - else { + } else { ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); } return ret; } -CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSS_address_t *lssAddress) -{ +CO_LSSmaster_return_t +CO_LSSmaster_InquireLssAddress(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSS_address_t* lssAddress) { CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; uint8_t next = CO_LSSmaster_COMMAND_WAITING; - if ((LSSmaster == NULL) || (lssAddress == NULL)){ + if ((LSSmaster == NULL) || (lssAddress == NULL)) { return CO_LSSmaster_ILLEGAL_ARGUMENT; } /* Check for reply */ if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_VENDOR) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, - CO_LSS_INQUIRE_VENDOR, &lssAddress->identity.vendorID); + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_VENDOR, + &lssAddress->identity.vendorID); if (ret == CO_LSSmaster_OK) { /* Start next request */ next = CO_LSSmaster_COMMAND_INQUIRE_PRODUCT; ret = CO_LSSmaster_WAIT_SLAVE; } - } - else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_PRODUCT) { + } else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_PRODUCT) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, - CO_LSS_INQUIRE_PRODUCT, &lssAddress->identity.productCode); + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_PRODUCT, + &lssAddress->identity.productCode); if (ret == CO_LSSmaster_OK) { /* Start next request */ next = CO_LSSmaster_COMMAND_INQUIRE_REV; ret = CO_LSSmaster_WAIT_SLAVE; } - } - else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_REV) { + } else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_REV) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, - CO_LSS_INQUIRE_REV, &lssAddress->identity.revisionNumber); + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_REV, + &lssAddress->identity.revisionNumber); if (ret == CO_LSSmaster_OK) { /* Start next request */ next = CO_LSSmaster_COMMAND_INQUIRE_SERIAL; ret = CO_LSSmaster_WAIT_SLAVE; } - } - else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_SERIAL) { + } else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_SERIAL) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, - CO_LSS_INQUIRE_SERIAL, &lssAddress->identity.serialNumber); + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, CO_LSS_INQUIRE_SERIAL, + &lssAddress->identity.serialNumber); + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } /* Check for next request */ - if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || - (LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL)) { + if ((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || (LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL)) { if (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING) { LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_VENDOR; LSSmaster->timeoutTimer = 0; ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_VENDOR); - } - else if (next == CO_LSSmaster_COMMAND_INQUIRE_PRODUCT) { + } else if (next == CO_LSSmaster_COMMAND_INQUIRE_PRODUCT) { LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_PRODUCT; LSSmaster->timeoutTimer = 0; ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_PRODUCT); - } - else if (next == CO_LSSmaster_COMMAND_INQUIRE_REV) { + } else if (next == CO_LSSmaster_COMMAND_INQUIRE_REV) { LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_REV; LSSmaster->timeoutTimer = 0; ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_REV); - } - else if (next == CO_LSSmaster_COMMAND_INQUIRE_SERIAL) { + } else if (next == CO_LSSmaster_COMMAND_INQUIRE_SERIAL) { LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_SERIAL; LSSmaster->timeoutTimer = 0; ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_SERIAL); + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } } if ((ret != CO_LSSmaster_INVALID_STATE) && (ret != CO_LSSmaster_WAIT_SLAVE)) { @@ -702,52 +611,41 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( return ret; } +CO_LSSmaster_return_t +CO_LSSmaster_Inquire(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint8_t lssInquireCs, uint32_t* value) { + CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; + + if ((LSSmaster == NULL) || (value == NULL)) { + return CO_LSSmaster_ILLEGAL_ARGUMENT; + } + + /* send request */ + if (((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || (LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL)) + && (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { + + LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE; + LSSmaster->timeoutTimer = 0; + + ret = CO_LSSmaster_inquireInitiate(LSSmaster, lssInquireCs); + } + /* Check for reply */ + else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE) { + ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, lssInquireCs, value); + } else { /* MISRA C 2004 14.10 */ + } -CO_LSSmaster_return_t CO_LSSmaster_Inquire( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - uint8_t lssInquireCs, - uint32_t *value) -{ - CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; - - if ((LSSmaster == NULL) || (value == NULL)){ - return CO_LSSmaster_ILLEGAL_ARGUMENT; - } - - /* send request */ - if (((LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE) || - (LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL)) && - (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING)) { - - LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE; - LSSmaster->timeoutTimer = 0; - - ret = CO_LSSmaster_inquireInitiate(LSSmaster, lssInquireCs); - } - /* Check for reply */ - else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE) { - ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us, - lssInquireCs, value); - } - else { /* MISRA C 2004 14.10 */ } - - if (ret != CO_LSSmaster_WAIT_SLAVE) { - LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; - } - return ret; + if (ret != CO_LSSmaster_WAIT_SLAVE) { + LSSmaster->command = CO_LSSmaster_COMMAND_WAITING; + } + return ret; } /* * Helper function - send request */ -static void CO_LSSmaster_FsSendMsg( - CO_LSSmaster_t *LSSmaster, - uint32_t idNumber, - uint8_t bitCheck, - uint8_t lssSub, - uint8_t lssNext) -{ +static void +CO_LSSmaster_FsSendMsg(CO_LSSmaster_t* LSSmaster, uint32_t idNumber, uint8_t bitCheck, uint8_t lssSub, + uint8_t lssNext) { LSSmaster->timeoutTimer = 0; CO_FLAG_CLEAR(LSSmaster->CANrxNew); @@ -763,10 +661,8 @@ static void CO_LSSmaster_FsSendMsg( /* * Helper function - wait for confirmation */ -static CO_LSSmaster_return_t CO_LSSmaster_FsCheckWait( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us) -{ +static CO_LSSmaster_return_t +CO_LSSmaster_FsCheckWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us) { CO_LSSmaster_return_t ret; ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); @@ -790,35 +686,29 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsCheckWait( /* * Helper function - initiate scan for 32 bit part of LSS address */ -static CO_LSSmaster_return_t CO_LSSmaster_FsScanInitiate( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSSmaster_scantype_t scan, - uint8_t lssSub) -{ - (void)timeDifference_us; /* unused */ +static CO_LSSmaster_return_t +CO_LSSmaster_FsScanInitiate(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, + uint8_t lssSub) { + (void)timeDifference_us; /* unused */ LSSmaster->fsLssSub = lssSub; LSSmaster->fsIdNumber = 0; switch (scan) { - case CO_LSSmaster_FS_SCAN: - break; + case CO_LSSmaster_FS_SCAN: break; case CO_LSSmaster_FS_MATCH: /* No scanning requested */ return CO_LSSmaster_SCAN_FINISHED; break; case CO_LSSmaster_FS_SKIP: - default: - return CO_LSSmaster_SCAN_FAILED; - break; + default: return CO_LSSmaster_SCAN_FAILED; break; } LSSmaster->fsBitChecked = CO_LSS_FASTSCAN_BIT31; /* trigger scan procedure by sending first message */ - CO_LSSmaster_FsSendMsg(LSSmaster, LSSmaster->fsIdNumber, - LSSmaster->fsBitChecked, LSSmaster->fsLssSub, LSSmaster->fsLssSub); + CO_LSSmaster_FsSendMsg(LSSmaster, LSSmaster->fsIdNumber, LSSmaster->fsBitChecked, LSSmaster->fsLssSub, + LSSmaster->fsLssSub); return CO_LSSmaster_WAIT_SLAVE; } @@ -826,24 +716,18 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanInitiate( /* * Helper function - scan for 32 bits of LSS address, one by one */ -static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSSmaster_scantype_t scan) -{ +static CO_LSSmaster_return_t +CO_LSSmaster_FsScanWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan) { CO_LSSmaster_return_t ret; switch (scan) { - case CO_LSSmaster_FS_SCAN: - break; + case CO_LSSmaster_FS_SCAN: break; case CO_LSSmaster_FS_MATCH: /* No scanning requested */ return CO_LSSmaster_SCAN_FINISHED; break; case CO_LSSmaster_FS_SKIP: - default: - return CO_LSSmaster_SCAN_FAILED; - break; + default: return CO_LSSmaster_SCAN_FAILED; break; } ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_us); @@ -859,8 +743,7 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( /* wrong response received. Can not continue */ return CO_LSSmaster_SCAN_FAILED; } - } - else { + } else { /* no response received, assumption is wrong */ LSSmaster->fsIdNumber |= 1UL << LSSmaster->fsBitChecked; } @@ -868,13 +751,11 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( if (LSSmaster->fsBitChecked == CO_LSS_FASTSCAN_BIT0) { /* Scanning cycle is finished, we now have 32 bit address data */ ret = CO_LSSmaster_SCAN_FINISHED; - } - else { - LSSmaster->fsBitChecked --; + } else { + LSSmaster->fsBitChecked--; - CO_LSSmaster_FsSendMsg(LSSmaster, - LSSmaster->fsIdNumber, LSSmaster->fsBitChecked, - LSSmaster->fsLssSub, LSSmaster->fsLssSub); + CO_LSSmaster_FsSendMsg(LSSmaster, LSSmaster->fsIdNumber, LSSmaster->fsBitChecked, LSSmaster->fsLssSub, + LSSmaster->fsLssSub); } } @@ -884,14 +765,10 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait( /* * Helper function - initiate check for 32 bit part of LSS address */ -static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSSmaster_scantype_t scan, - uint32_t idNumberCheck, - uint8_t lssNext) -{ - (void)timeDifference_us; /* unused */ +static CO_LSSmaster_return_t +CO_LSSmaster_FsVerifyInitiate(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, + uint32_t idNumberCheck, uint8_t lssNext) { + (void)timeDifference_us; /* unused */ switch (scan) { case CO_LSSmaster_FS_SCAN: @@ -902,16 +779,13 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate( LSSmaster->fsIdNumber = idNumberCheck; break; case CO_LSSmaster_FS_SKIP: - default: - return CO_LSSmaster_SCAN_FAILED; - break; + default: return CO_LSSmaster_SCAN_FAILED; break; } LSSmaster->fsBitChecked = CO_LSS_FASTSCAN_BIT0; /* send request */ - CO_LSSmaster_FsSendMsg(LSSmaster, LSSmaster->fsIdNumber, - LSSmaster->fsBitChecked, LSSmaster->fsLssSub, lssNext); + CO_LSSmaster_FsSendMsg(LSSmaster, LSSmaster->fsIdNumber, LSSmaster->fsBitChecked, LSSmaster->fsLssSub, lssNext); return CO_LSSmaster_WAIT_SLAVE; } @@ -920,12 +794,9 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate( * Helper function - verify 32 bit LSS address, request node(s) to switch * their state machine to the next state */ -static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSSmaster_scantype_t scan, - uint32_t *idNumberRet) -{ +static CO_LSSmaster_return_t +CO_LSSmaster_FsVerifyWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, + uint32_t* idNumberRet) { CO_LSSmaster_return_t ret; if (scan == CO_LSSmaster_FS_SKIP) { @@ -957,10 +828,8 @@ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait( /* * Helper function - check which 32 bit to scan for next, if any */ -static uint8_t CO_LSSmaster_FsSearchNext( - CO_LSSmaster_t *LSSmaster, - const CO_LSSmaster_fastscan_t *fastscan) -{ +static uint8_t +CO_LSSmaster_FsSearchNext(CO_LSSmaster_t* LSSmaster, const CO_LSSmaster_fastscan_t* fastscan) { uint8_t i; /* we search for the next LSS address part to scan for, beginning with the @@ -976,18 +845,16 @@ static uint8_t CO_LSSmaster_FsSearchNext( return CO_LSS_FASTSCAN_VENDOR_ID; } -CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSSmaster_fastscan_t *fastscan) -{ +CO_LSSmaster_return_t +CO_LSSmaster_IdentifyFastscan(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, + CO_LSSmaster_fastscan_t* fastscan) { uint8_t i; uint8_t count; CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE; uint8_t next; /* parameter validation */ - if ((LSSmaster == NULL) || (fastscan == NULL)){ + if ((LSSmaster == NULL) || (fastscan == NULL)) { return CO_LSSmaster_ILLEGAL_ARGUMENT; } if (fastscan->scan[0] == CO_LSSmaster_FS_SKIP) { @@ -997,7 +864,7 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( count = 0; for (i = 0; i < (sizeof(fastscan->scan) / sizeof(fastscan->scan[0])); i++) { if (fastscan->scan[i] == CO_LSSmaster_FS_SKIP) { - count ++; + count++; } if (count > 2U) { /* Node selection needs the Vendor ID and at least one other value */ @@ -1006,9 +873,9 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( } /* state machine validation */ - if ((LSSmaster->state != CO_LSSmaster_STATE_WAITING) || - ((LSSmaster->command != CO_LSSmaster_COMMAND_WAITING) && - (LSSmaster->command != CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN))) { + if ((LSSmaster->state != CO_LSSmaster_STATE_WAITING) + || ((LSSmaster->command != CO_LSSmaster_COMMAND_WAITING) + && (LSSmaster->command != CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN))) { /* state machine not ready, other command is already processed */ return CO_LSSmaster_INVALID_STATE; } @@ -1048,32 +915,28 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( /* start scanning procedure by triggering vendor ID scan */ (void)CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_us, - fastscan->scan[CO_LSS_FASTSCAN_VENDOR_ID], - CO_LSS_FASTSCAN_VENDOR_ID); + fastscan->scan[CO_LSS_FASTSCAN_VENDOR_ID], CO_LSS_FASTSCAN_VENDOR_ID); ret = CO_LSSmaster_WAIT_SLAVE; LSSmaster->fsState = CO_LSSmaster_FS_STATE_SCAN; } break; case CO_LSSmaster_FS_STATE_SCAN: - ret = CO_LSSmaster_FsScanWait(LSSmaster, timeDifference_us, - fastscan->scan[LSSmaster->fsLssSub]); + ret = CO_LSSmaster_FsScanWait(LSSmaster, timeDifference_us, fastscan->scan[LSSmaster->fsLssSub]); if (ret == CO_LSSmaster_SCAN_FINISHED) { /* scanning finished, initiate verifcation. The verification * message also contains the node state machine "switch to * next state" request */ next = CO_LSSmaster_FsSearchNext(LSSmaster, fastscan); - ret = CO_LSSmaster_FsVerifyInitiate(LSSmaster, timeDifference_us, - fastscan->scan[LSSmaster->fsLssSub], - fastscan->match.addr[LSSmaster->fsLssSub], next); + ret = CO_LSSmaster_FsVerifyInitiate(LSSmaster, timeDifference_us, fastscan->scan[LSSmaster->fsLssSub], + fastscan->match.addr[LSSmaster->fsLssSub], next); LSSmaster->fsState = CO_LSSmaster_FS_STATE_VERIFY; } break; case CO_LSSmaster_FS_STATE_VERIFY: - ret = CO_LSSmaster_FsVerifyWait(LSSmaster, timeDifference_us, - fastscan->scan[LSSmaster->fsLssSub], - &fastscan->found.addr[LSSmaster->fsLssSub]); + ret = CO_LSSmaster_FsVerifyWait(LSSmaster, timeDifference_us, fastscan->scan[LSSmaster->fsLssSub], + &fastscan->found.addr[LSSmaster->fsLssSub]); if (ret == CO_LSSmaster_SCAN_FINISHED) { /* verification successful: * - assumed node id is correct @@ -1084,11 +947,9 @@ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( /* fastscan finished, one node is now in LSS configuration * mode */ LSSmaster->state = CO_LSSmaster_STATE_CFG_SLECTIVE; - } - else { + } else { /* initiate scan for next part of LSS address */ - ret = CO_LSSmaster_FsScanInitiate(LSSmaster, - timeDifference_us, fastscan->scan[next], next); + ret = CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_us, fastscan->scan[next], next); if (ret == CO_LSSmaster_SCAN_FINISHED) { /* Scanning is not requested. Initiate verification * step in next function call */ diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index e39b9e40..10125fed 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -24,14 +24,14 @@ #include "305/CO_LSSslave.h" -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 /* 'bit' must be unsigned or additional range check must be added: bit>=CO_LSS_FASTSCAN_BIT0 */ -#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit<=CO_LSS_FASTSCAN_BIT31) || (bit==CO_LSS_FASTSCAN_CONFIRM)) +#define CO_LSS_FASTSCAN_BITCHECK_VALID(bit) ((bit <= CO_LSS_FASTSCAN_BIT31) || (bit == CO_LSS_FASTSCAN_CONFIRM)) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_FASTSCAN_VENDOR_ID */ -#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index<=CO_LSS_FASTSCAN_SERIAL) +#define CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(index) (index <= CO_LSS_FASTSCAN_SERIAL) /* 'index' must be unsigned or additional range check must be added: index>=CO_LSS_BIT_TIMING_1000 */ -#define CO_LSS_BIT_TIMING_VALID(index) ((index != 5U) && (index <= CO_LSS_BIT_TIMING_AUTO)) +#define CO_LSS_BIT_TIMING_VALID(index) ((index != 5U) && (index <= CO_LSS_BIT_TIMING_AUTO)) /* * Read received message from CAN module. @@ -40,14 +40,14 @@ * message with correct identifier will be received. For more information and * description of parameters see file CO_driver.h. */ -static void CO_LSSslave_receive(void *object, void *msg) -{ - CO_LSSslave_t *LSSslave = (CO_LSSslave_t*)object; +static void +CO_LSSslave_receive(void* object, void* msg) { + CO_LSSslave_t* LSSslave = (CO_LSSslave_t*)object; uint8_t DLC = CO_CANrxMsg_readDLC(msg); - if((DLC == 8U) && !CO_FLAG_READ(LSSslave->sendResponse)) { + if ((DLC == 8U) && !CO_FLAG_READ(LSSslave->sendResponse)) { bool_t request_LSSslave_process = false; - const uint8_t *data = CO_CANrxMsg_readData(msg); + const uint8_t* data = CO_CANrxMsg_readData(msg); uint8_t cs = data[0]; if (cs == CO_LSS_SWITCH_STATE_GLOBAL) { @@ -55,136 +55,121 @@ static void CO_LSSslave_receive(void *object, void *msg) switch (mode) { case CO_LSS_STATE_WAITING: - if ((LSSslave->lssState == CO_LSS_STATE_CONFIGURATION) && - (LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT) && - (*LSSslave->pendingNodeID != CO_LSS_NODE_ID_ASSIGNMENT)) - { + if ((LSSslave->lssState == CO_LSS_STATE_CONFIGURATION) + && (LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT) + && (*LSSslave->pendingNodeID != CO_LSS_NODE_ID_ASSIGNMENT)) { /* Slave process function will request NMT Reset comm.*/ LSSslave->service = cs; request_LSSslave_process = true; } LSSslave->lssState = CO_LSS_STATE_WAITING; - (void)memset(&LSSslave->lssSelect, 0, - sizeof(LSSslave->lssSelect)); - break; - case CO_LSS_STATE_CONFIGURATION: - LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; + (void)memset(&LSSslave->lssSelect, 0, sizeof(LSSslave->lssSelect)); break; + case CO_LSS_STATE_CONFIGURATION: LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; break; default: /* none */ break; } - } - else if(LSSslave->lssState == CO_LSS_STATE_WAITING) { + } else if (LSSslave->lssState == CO_LSS_STATE_WAITING) { switch (cs) { - case CO_LSS_SWITCH_STATE_SEL_VENDOR: { - uint32_t valSw; - (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); - LSSslave->lssSelect.identity.vendorID = CO_SWAP_32(valSw); - break; - } - case CO_LSS_SWITCH_STATE_SEL_PRODUCT: { - uint32_t valSw; - (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); - LSSslave->lssSelect.identity.productCode = CO_SWAP_32(valSw); - break; - } - case CO_LSS_SWITCH_STATE_SEL_REV: { - uint32_t valSw; - (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); - LSSslave->lssSelect.identity.revisionNumber = CO_SWAP_32(valSw); - break; - } - case CO_LSS_SWITCH_STATE_SEL_SERIAL: { - uint32_t valSw; - (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); - LSSslave->lssSelect.identity.serialNumber = CO_SWAP_32(valSw); - - if (CO_LSS_ADDRESS_EQUAL(LSSslave->lssAddress, - LSSslave->lssSelect) - ) { - LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; - LSSslave->service = cs; - request_LSSslave_process = true; + case CO_LSS_SWITCH_STATE_SEL_VENDOR: { + uint32_t valSw; + (void)memcpy((void*)(&valSw), (const void*)(&data[1]), sizeof(valSw)); + LSSslave->lssSelect.identity.vendorID = CO_SWAP_32(valSw); + break; } - break; - } - case CO_LSS_IDENT_FASTSCAN: { - /* fastscan is only active on unconfigured nodes */ - if ((*LSSslave->pendingNodeID == CO_LSS_NODE_ID_ASSIGNMENT) && - (LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT)) - { - uint8_t bitCheck = data[5]; - uint8_t lssSub = data[6]; - uint8_t lssNext = data[7]; + case CO_LSS_SWITCH_STATE_SEL_PRODUCT: { uint32_t valSw; - uint32_t idNumber; - bool_t ack; - - if (!CO_LSS_FASTSCAN_BITCHECK_VALID(bitCheck) || - !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssSub) || - !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssNext)) { - /* Invalid request */ - break; - } - - (void)memcpy((void *)(&valSw), (const void *)(&data[1]), sizeof(valSw)); - idNumber = CO_SWAP_32(valSw); - ack = false; + (void)memcpy((void*)(&valSw), (const void*)(&data[1]), sizeof(valSw)); + LSSslave->lssSelect.identity.productCode = CO_SWAP_32(valSw); + break; + } + case CO_LSS_SWITCH_STATE_SEL_REV: { + uint32_t valSw; + (void)memcpy((void*)(&valSw), (const void*)(&data[1]), sizeof(valSw)); + LSSslave->lssSelect.identity.revisionNumber = CO_SWAP_32(valSw); + break; + } + case CO_LSS_SWITCH_STATE_SEL_SERIAL: { + uint32_t valSw; + (void)memcpy((void*)(&valSw), (const void*)(&data[1]), sizeof(valSw)); + LSSslave->lssSelect.identity.serialNumber = CO_SWAP_32(valSw); - if (bitCheck == CO_LSS_FASTSCAN_CONFIRM) { - /* Confirm, Reset */ - ack = true; - LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; - (void)memset(&LSSslave->lssFastscan, 0, - sizeof(LSSslave->lssFastscan)); + if (CO_LSS_ADDRESS_EQUAL(LSSslave->lssAddress, LSSslave->lssSelect)) { + LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; + LSSslave->service = cs; + request_LSSslave_process = true; } - else if (LSSslave->fastscanPos == lssSub) { - uint32_t mask = 0xFFFFFFFFU << bitCheck; + break; + } + case CO_LSS_IDENT_FASTSCAN: { + /* fastscan is only active on unconfigured nodes */ + if ((*LSSslave->pendingNodeID == CO_LSS_NODE_ID_ASSIGNMENT) + && (LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT)) { + uint8_t bitCheck = data[5]; + uint8_t lssSub = data[6]; + uint8_t lssNext = data[7]; + uint32_t valSw; + uint32_t idNumber; + bool_t ack; + + if (!CO_LSS_FASTSCAN_BITCHECK_VALID(bitCheck) || !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssSub) + || !CO_LSS_FASTSCAN_LSS_SUB_NEXT_VALID(lssNext)) { + /* Invalid request */ + break; + } - if ((LSSslave->lssAddress.addr[lssSub] & mask) - == (idNumber & mask)) - { - /* all requested bits match */ - ack = true; - LSSslave->fastscanPos = lssNext; + (void)memcpy((void*)(&valSw), (const void*)(&data[1]), sizeof(valSw)); + idNumber = CO_SWAP_32(valSw); + ack = false; - if ((bitCheck == 0U) && (lssNext < lssSub)) { - /* complete match, enter configuration state */ - LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; + if (bitCheck == CO_LSS_FASTSCAN_CONFIRM) { + /* Confirm, Reset */ + ack = true; + LSSslave->fastscanPos = CO_LSS_FASTSCAN_VENDOR_ID; + (void)memset(&LSSslave->lssFastscan, 0, sizeof(LSSslave->lssFastscan)); + } else if (LSSslave->fastscanPos == lssSub) { + uint32_t mask = 0xFFFFFFFFU << bitCheck; + + if ((LSSslave->lssAddress.addr[lssSub] & mask) == (idNumber & mask)) { + /* all requested bits match */ + ack = true; + LSSslave->fastscanPos = lssNext; + + if ((bitCheck == 0U) && (lssNext < lssSub)) { + /* complete match, enter configuration state */ + LSSslave->lssState = CO_LSS_STATE_CONFIGURATION; + } } + } else { /* MISRA C 2004 14.10 */ } - } - else { /* MISRA C 2004 14.10 */ } - if (ack) { -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND) != 0 - LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; - (void)memset(&LSSslave->TXbuff->data[1], 0, - sizeof(LSSslave->TXbuff->data) - 1U); - (void)CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); + if (ack) { +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND) != 0 + LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; + (void)memset(&LSSslave->TXbuff->data[1], 0, sizeof(LSSslave->TXbuff->data) - 1U); + (void)CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); #else - LSSslave->service = cs; - request_LSSslave_process = true; + LSSslave->service = cs; + request_LSSslave_process = true; #endif + } } + break; + } + default: { + /* none */ + break; } - break; - } - default: { - /* none */ - break; - } } - } - else { /* LSSslave->lssState == CO_LSS_STATE_CONFIGURATION */ - (void)memcpy((void *)(&LSSslave->CANdata[0]), (const void *)(&data[0]), sizeof(LSSslave->CANdata)); + } else { /* LSSslave->lssState == CO_LSS_STATE_CONFIGURATION */ + (void)memcpy((void*)(&LSSslave->CANdata[0]), (const void*)(&data[0]), sizeof(LSSslave->CANdata)); LSSslave->service = cs; request_LSSslave_process = true; } if (request_LSSslave_process) { CO_FLAG_SET(LSSslave->sendResponse); -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, * which handles further processing. */ if (LSSslave->pFunctSignalPre != NULL) { @@ -195,26 +180,15 @@ static void CO_LSSslave_receive(void *object, void *msg) } } - -CO_ReturnError_t CO_LSSslave_init( - CO_LSSslave_t *LSSslave, - CO_LSS_address_t *lssAddress, - uint16_t *pendingBitRate, - uint8_t *pendingNodeID, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - uint16_t CANidLssMaster, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint16_t CANidLssSlave) -{ +CO_ReturnError_t +CO_LSSslave_init(CO_LSSslave_t* LSSslave, CO_LSS_address_t* lssAddress, uint16_t* pendingBitRate, + uint8_t* pendingNodeID, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, uint16_t CANidLssMaster, + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, uint16_t CANidLssSlave) { CO_ReturnError_t ret = CO_ERROR_NO; /* verify arguments */ - if ((LSSslave==NULL) || (pendingBitRate == NULL) || (pendingNodeID == NULL) || - (CANdevRx==NULL) || (CANdevTx==NULL) || - !CO_LSS_NODE_ID_VALID(*pendingNodeID) - ) { + if ((LSSslave == NULL) || (pendingBitRate == NULL) || (pendingNodeID == NULL) || (CANdevRx == NULL) + || (CANdevTx == NULL) || !CO_LSS_NODE_ID_VALID(*pendingNodeID)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -234,24 +208,11 @@ CO_ReturnError_t CO_LSSslave_init( CO_FLAG_CLEAR(LSSslave->sendResponse); /* configure LSS CAN Master message reception */ - ret = CO_CANrxBufferInit( - CANdevRx, - CANdevRxIdx, - CANidLssMaster, - 0x7FF, - false, - (void*)LSSslave, - CO_LSSslave_receive); + ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, CANidLssMaster, 0x7FF, false, (void*)LSSslave, CO_LSSslave_receive); /* configure LSS CAN Slave response message transmission */ LSSslave->CANdevTx = CANdevTx; - LSSslave->TXbuff = CO_CANtxBufferInit( - CANdevTx, - CANdevTxIdx, - CANidLssSlave, - false, - 8, - false); + LSSslave->TXbuff = CO_CANtxBufferInit(CANdevTx, CANdevTxIdx, CANidLssSlave, false, 8, false); if (LSSslave->TXbuff == NULL) { ret = CO_ERROR_ILLEGAL_ARGUMENT; @@ -260,58 +221,45 @@ CO_ReturnError_t CO_LSSslave_init( return ret; } - -#if ((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 -void CO_LSSslave_initCallbackPre( - CO_LSSslave_t *LSSslave, - void *object, - void (*pFunctSignalPre)(void *object)) -{ - if(LSSslave != NULL){ +#if ((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +void +CO_LSSslave_initCallbackPre(CO_LSSslave_t* LSSslave, void* object, void (*pFunctSignalPre)(void* object)) { + if (LSSslave != NULL) { LSSslave->functSignalObjectPre = object; LSSslave->pFunctSignalPre = pFunctSignalPre; } } #endif - -void CO_LSSslave_initCkBitRateCall( - CO_LSSslave_t *LSSslave, - void *object, - bool_t (*pFunctLSScheckBitRate)(void *object, uint16_t bitRate)) -{ - if(LSSslave != NULL){ +void +CO_LSSslave_initCkBitRateCall(CO_LSSslave_t* LSSslave, void* object, + bool_t (*pFunctLSScheckBitRate)(void* object, uint16_t bitRate)) { + if (LSSslave != NULL) { LSSslave->functLSScheckBitRateObject = object; LSSslave->pFunctLSScheckBitRate = pFunctLSScheckBitRate; } } - -void CO_LSSslave_initActBitRateCall( - CO_LSSslave_t *LSSslave, - void *object, - void (*pFunctLSSactivateBitRate)(void *object, uint16_t delay)) -{ - if(LSSslave != NULL){ +void +CO_LSSslave_initActBitRateCall(CO_LSSslave_t* LSSslave, void* object, + void (*pFunctLSSactivateBitRate)(void* object, uint16_t delay)) { + if (LSSslave != NULL) { LSSslave->functLSSactivateBitRateObject = object; LSSslave->pFunctLSSactivateBitRate = pFunctLSSactivateBitRate; } } - -void CO_LSSslave_initCfgStoreCall( - CO_LSSslave_t *LSSslave, - void *object, - bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate)) -{ - if(LSSslave != NULL){ +void +CO_LSSslave_initCfgStoreCall(CO_LSSslave_t* LSSslave, void* object, + bool_t (*pFunctLSScfgStore)(void* object, uint8_t id, uint16_t bitRate)) { + if (LSSslave != NULL) { LSSslave->functLSScfgStoreObject = object; LSSslave->pFunctLSScfgStore = pFunctLSScfgStore; } } - -bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { +bool_t +CO_LSSslave_process(CO_LSSslave_t* LSSslave) { bool_t resetCommunication = false; if (CO_FLAG_READ(LSSslave->sendResponse)) { @@ -326,158 +274,151 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave) { (void)memset(&LSSslave->TXbuff->data[0], 0, sizeof(LSSslave->TXbuff->data)); switch (LSSslave->service) { - case CO_LSS_SWITCH_STATE_GLOBAL: { - /* Node-Id was unconfigured before, now it is configured, + case CO_LSS_SWITCH_STATE_GLOBAL: { + /* Node-Id was unconfigured before, now it is configured, * enter the NMT Reset communication autonomously. */ - resetCommunication = true; - break; - } - case CO_LSS_SWITCH_STATE_SEL_SERIAL: { - LSSslave->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL; - CANsend = true; - break; - } - case CO_LSS_CFG_NODE_ID: { - nid = LSSslave->CANdata[1]; - errorCode = CO_LSS_CFG_NODE_ID_OK; - - if (CO_LSS_NODE_ID_VALID(nid)) { - *LSSslave->pendingNodeID = nid; + resetCommunication = true; + break; } - else { - errorCode = CO_LSS_CFG_NODE_ID_OUT_OF_RANGE; + case CO_LSS_SWITCH_STATE_SEL_SERIAL: { + LSSslave->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL; + CANsend = true; + break; } + case CO_LSS_CFG_NODE_ID: { + nid = LSSslave->CANdata[1]; + errorCode = CO_LSS_CFG_NODE_ID_OK; + + if (CO_LSS_NODE_ID_VALID(nid)) { + *LSSslave->pendingNodeID = nid; + } else { + errorCode = CO_LSS_CFG_NODE_ID_OUT_OF_RANGE; + } - /* send confirmation */ - LSSslave->TXbuff->data[0] = LSSslave->service; - LSSslave->TXbuff->data[1] = errorCode; - /* we do not use spec-error, always 0 */ - CANsend = true; - break; - } - case CO_LSS_CFG_BIT_TIMING: { - if (LSSslave->pFunctLSScheckBitRate == NULL) { - /* setting bit timing is not supported. Drop request */ + /* send confirmation */ + LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[1] = errorCode; + /* we do not use spec-error, always 0 */ + CANsend = true; break; } + case CO_LSS_CFG_BIT_TIMING: { + if (LSSslave->pFunctLSScheckBitRate == NULL) { + /* setting bit timing is not supported. Drop request */ + break; + } - tableSelector = LSSslave->CANdata[1]; - tableIndex = LSSslave->CANdata[2]; - errorCode = CO_LSS_CFG_BIT_TIMING_OK; - errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OK; + tableSelector = LSSslave->CANdata[1]; + tableIndex = LSSslave->CANdata[2]; + errorCode = CO_LSS_CFG_BIT_TIMING_OK; + errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OK; + + if ((tableSelector == 0U) && CO_LSS_BIT_TIMING_VALID(tableIndex)) { + uint16_t bit = CO_LSS_bitTimingTableLookup[tableIndex]; + bool_t bit_rate_supported = LSSslave->pFunctLSScheckBitRate(LSSslave->functLSScheckBitRateObject, + bit); + + if (bit_rate_supported) { + *LSSslave->pendingBitRate = bit; + } else { + errorCode = CO_LSS_CFG_BIT_TIMING_MANUFACTURER; + errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; + } + } else { + /* we currently only support CiA301 bit timing table */ + errorCode = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; + } - if ((tableSelector == 0U) && CO_LSS_BIT_TIMING_VALID(tableIndex)) { - uint16_t bit = CO_LSS_bitTimingTableLookup[tableIndex]; - bool_t bit_rate_supported = LSSslave->pFunctLSScheckBitRate( - LSSslave->functLSScheckBitRateObject, bit); + /* send confirmation */ + LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[1] = errorCode; + LSSslave->TXbuff->data[2] = errorCodeManuf; + CANsend = true; + break; + } + case CO_LSS_CFG_ACTIVATE_BIT_TIMING: { + if (LSSslave->pFunctLSScheckBitRate == NULL) { + /* setting bit timing is not supported. Drop request */ + break; + } - if (bit_rate_supported) { - *LSSslave->pendingBitRate = bit; + /* notify application */ + if (LSSslave->pFunctLSSactivateBitRate != NULL) { + uint16_t delay = ((uint16_t)LSSslave->CANdata[2]) << 8; + delay |= LSSslave->CANdata[1]; + LSSslave->pFunctLSSactivateBitRate(LSSslave->functLSSactivateBitRateObject, delay); } - else { - errorCode = CO_LSS_CFG_BIT_TIMING_MANUFACTURER; - errorCodeManuf = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; + break; + } + case CO_LSS_CFG_STORE: { + errorCode = CO_LSS_CFG_STORE_OK; + + if (LSSslave->pFunctLSScfgStore == NULL) { + /* storing is not supported. Reply error */ + errorCode = CO_LSS_CFG_STORE_NOT_SUPPORTED; + } else { + bool_t result; + /* Store "pending" to "persistent" */ + result = LSSslave->pFunctLSScfgStore(LSSslave->functLSScfgStoreObject, *LSSslave->pendingNodeID, + *LSSslave->pendingBitRate); + if (!result) { + errorCode = CO_LSS_CFG_STORE_FAILED; + } } + + /* send confirmation */ + LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[1] = errorCode; + /* we do not use spec-error, always 0 */ + CANsend = true; + break; } - else { - /* we currently only support CiA301 bit timing table */ - errorCode = CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE; + case CO_LSS_INQUIRE_VENDOR: { + LSSslave->TXbuff->data[0] = LSSslave->service; + valSw = CO_SWAP_32(LSSslave->lssAddress.identity.vendorID); + (void)memcpy((void*)(&LSSslave->TXbuff->data[1]), (const void*)(&valSw), sizeof(valSw)); + CANsend = true; + break; } - - /* send confirmation */ - LSSslave->TXbuff->data[0] = LSSslave->service; - LSSslave->TXbuff->data[1] = errorCode; - LSSslave->TXbuff->data[2] = errorCodeManuf; - CANsend = true; - break; - } - case CO_LSS_CFG_ACTIVATE_BIT_TIMING: { - if (LSSslave->pFunctLSScheckBitRate == NULL) { - /* setting bit timing is not supported. Drop request */ + case CO_LSS_INQUIRE_PRODUCT: { + LSSslave->TXbuff->data[0] = LSSslave->service; + valSw = CO_SWAP_32(LSSslave->lssAddress.identity.productCode); + (void)memcpy((void*)(&LSSslave->TXbuff->data[1]), (const void*)(&valSw), sizeof(valSw)); + CANsend = true; break; } - - /* notify application */ - if (LSSslave->pFunctLSSactivateBitRate != NULL) { - uint16_t delay = ((uint16_t) LSSslave->CANdata[2]) << 8; - delay |= LSSslave->CANdata[1]; - LSSslave->pFunctLSSactivateBitRate( - LSSslave->functLSSactivateBitRateObject, delay); + case CO_LSS_INQUIRE_REV: { + LSSslave->TXbuff->data[0] = LSSslave->service; + valSw = CO_SWAP_32(LSSslave->lssAddress.identity.revisionNumber); + (void)memcpy((void*)(&LSSslave->TXbuff->data[1]), (const void*)(&valSw), sizeof(valSw)); + CANsend = true; + break; } - break; - } - case CO_LSS_CFG_STORE: { - errorCode = CO_LSS_CFG_STORE_OK; - - if (LSSslave->pFunctLSScfgStore == NULL) { - /* storing is not supported. Reply error */ - errorCode = CO_LSS_CFG_STORE_NOT_SUPPORTED; + case CO_LSS_INQUIRE_SERIAL: { + LSSslave->TXbuff->data[0] = LSSslave->service; + valSw = CO_SWAP_32(LSSslave->lssAddress.identity.serialNumber); + (void)memcpy((void*)(&LSSslave->TXbuff->data[1]), (const void*)(&valSw), sizeof(valSw)); + CANsend = true; + break; } - else { - bool_t result; - /* Store "pending" to "persistent" */ - result = - LSSslave->pFunctLSScfgStore(LSSslave->functLSScfgStoreObject, - *LSSslave->pendingNodeID, - *LSSslave->pendingBitRate); - if (!result) { - errorCode = CO_LSS_CFG_STORE_FAILED; - } + case CO_LSS_INQUIRE_NODE_ID: { + LSSslave->TXbuff->data[0] = LSSslave->service; + LSSslave->TXbuff->data[1] = LSSslave->activeNodeID; + CANsend = true; + break; + } + case CO_LSS_IDENT_FASTSCAN: { + LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; + CANsend = true; + break; + } + default: { + /* none */ + break; } - - /* send confirmation */ - LSSslave->TXbuff->data[0] = LSSslave->service; - LSSslave->TXbuff->data[1] = errorCode; - /* we do not use spec-error, always 0 */ - CANsend = true; - break; - } - case CO_LSS_INQUIRE_VENDOR: { - LSSslave->TXbuff->data[0] = LSSslave->service; - valSw = CO_SWAP_32(LSSslave->lssAddress.identity.vendorID); - (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); - CANsend = true; - break; - } - case CO_LSS_INQUIRE_PRODUCT: { - LSSslave->TXbuff->data[0] = LSSslave->service; - valSw = CO_SWAP_32(LSSslave->lssAddress.identity.productCode); - (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); - CANsend = true; - break; - } - case CO_LSS_INQUIRE_REV: { - LSSslave->TXbuff->data[0] = LSSslave->service; - valSw = CO_SWAP_32(LSSslave->lssAddress.identity.revisionNumber); - (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); - CANsend = true; - break; - } - case CO_LSS_INQUIRE_SERIAL: { - LSSslave->TXbuff->data[0] = LSSslave->service; - valSw = CO_SWAP_32(LSSslave->lssAddress.identity.serialNumber); - (void)memcpy((void *)(&LSSslave->TXbuff->data[1]), (const void *)(&valSw), sizeof(valSw)); - CANsend = true; - break; - } - case CO_LSS_INQUIRE_NODE_ID: { - LSSslave->TXbuff->data[0] = LSSslave->service; - LSSslave->TXbuff->data[1] = LSSslave->activeNodeID; - CANsend = true; - break; - } - case CO_LSS_IDENT_FASTSCAN: { - LSSslave->TXbuff->data[0] = CO_LSS_IDENT_SLAVE; - CANsend = true; - break; - } - default: { - /* none */ - break; - } } - if(CANsend) { + if (CANsend) { (void)CO_CANsend(LSSslave->CANdevTx, LSSslave->TXbuff); } diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 6071c671..7fd45c3d 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -23,7 +23,7 @@ #include "309/CO_gateway_ascii.h" -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0 #include #include @@ -31,48 +31,46 @@ #include /* verify configuration */ -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) == 0 - #error CO_CONFIG_FIFO_ENABLE must be enabled. +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ENABLE) == 0 +#error CO_CONFIG_FIFO_ENABLE must be enabled. #endif -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) == 0 - #error CO_CONFIG_FIFO_ASCII_COMMANDS must be enabled. +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_COMMANDS) == 0 +#error CO_CONFIG_FIFO_ASCII_COMMANDS must be enabled. +#endif +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_DATATYPES) == 0 +#error CO_CONFIG_FIFO_ASCII_DATATYPES must be enabled. #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 - #if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) == 0 - #error CO_CONFIG_FIFO_ASCII_DATATYPES must be enabled. - #endif #endif -CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN - CO_SDOclient_t* SDO_C, - uint16_t SDOclientTimeoutTime_ms, - bool_t SDOclientBlockTransfer, +CO_ReturnError_t +CO_GTWA_init(CO_GTWA_t* gtwa, +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN + CO_SDOclient_t* SDO_C, uint16_t SDOclientTimeoutTime_ms, bool_t SDOclientBlockTransfer, #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN - CO_NMT_t *NMT, +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN + CO_NMT_t* NMT, #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN - CO_LSSmaster_t *LSSmaster, +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN + CO_LSSmaster_t* LSSmaster, #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN - CO_LEDs_t *LEDs, +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN + CO_LEDs_t* LEDs, #endif - uint8_t dummy) -{ + uint8_t dummy) { (void)dummy; /* verify arguments */ if ((gtwa == NULL) -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 || (SDO_C == NULL) || (SDOclientTimeoutTime_ms == 0U) #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0 || (NMT == NULL) #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0 || (LSSmaster == NULL) #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 || (LEDs == NULL) #endif ) { @@ -83,18 +81,18 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, (void)memset(gtwa, 0, sizeof(CO_GTWA_t)); /* initialize variables */ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 gtwa->SDO_C = SDO_C; gtwa->SDOtimeoutTime = SDOclientTimeoutTime_ms; gtwa->SDOblockTransferEnable = SDOclientBlockTransfer; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0 gtwa->NMT = NMT; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0 gtwa->LSSmaster = LSSmaster; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 gtwa->LEDs = LEDs; #endif gtwa->net_default = -1; @@ -102,38 +100,30 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, gtwa->state = CO_GTWA_ST_IDLE; gtwa->respHold = false; - CO_fifo_init(>wa->commFifo, - >wa->commBuf[0], - CO_CONFIG_GTWA_COMM_BUF_SIZE + 1); + CO_fifo_init(>wa->commFifo, >wa->commBuf[0], CO_CONFIG_GTWA_COMM_BUF_SIZE + 1); -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 - CO_fifo_init(>wa->logFifo, - >wa->logBuf[0], - CO_CONFIG_GTWA_LOG_BUF_SIZE + 1); +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0 + CO_fifo_init(>wa->logFifo, >wa->logBuf[0], CO_CONFIG_GTWA_LOG_BUF_SIZE + 1); #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) */ return CO_ERROR_NO; } - -void CO_GTWA_initRead(CO_GTWA_t* gtwa, - size_t (*readCallback)(void *object, - const char *buf, - size_t count, - uint8_t *connectionOK), - void *readCallbackObject) -{ +void +CO_GTWA_initRead(CO_GTWA_t* gtwa, + size_t (*readCallback)(void* object, const char* buf, size_t count, uint8_t* connectionOK), + void* readCallbackObject) { if (gtwa != NULL) { gtwa->readCallback = readCallback; gtwa->readCallbackObject = readCallbackObject; } } - -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 -void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0 +void +CO_GTWA_log_print(CO_GTWA_t* gtwa, const char* message) { if ((gtwa != NULL) && (message != NULL)) { - const char *c; + const char* c; for (c = &message[0]; *c != '\0'; c++) { CO_fifo_putc_ov(>wa->logFifo, (const uint8_t)*c); @@ -142,98 +132,92 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) { } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ - /******************************************************************************* * HELPER FUNCTIONS ******************************************************************************/ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 /* help strings ("\n" is used between string, "\r\n" closes the response.) */ static const char CO_GTWA_helpString[] = -"\nCommand strings start with '\"[\"\"]\"' followed by:\n" \ -"[[] ] r[ead] [] # SDO upload.\n" \ -"[[] ] w[rite] # SDO download.\n" \ -"\n" \ -"[[] ] start # NMT Start node.\n" \ -"[[] ] stop # NMT Stop node.\n" \ -"[[] ] preop[erational] # NMT Set node to pre-operational.\n" \ -"[[] ] reset node # NMT Reset node.\n" \ -"[[] ] reset comm[unication] # NMT Reset communication.\n" \ -"\n" \ -"[] set network # Set default net.\n" \ -"[] set node # Set default node.\n" \ -"[] set sdo_timeout # Configure SDO client time-out in ms.\n" \ -"[] set sdo_block <0|1> # Enable/disable SDO block transfer.\n" \ -"\n" \ -"help [datatype|lss] # Print this or datatype or lss help.\n" \ -"led # Print status LEDs of this device.\n" \ -"log # Print message log.\n" \ -"\n" \ -"Response:\n" \ -"\"[\"\"]\" OK | |\n" \ -" ERROR: | ERROR:\n" \ -"\n" \ -"* Every command must be terminated with ('\\r\\n'). characters. Same\n" \ -" is response. String is not null terminated, is optional in command.\n" \ -"* Comments started with '#' are ignored. They may be on the beginning of the\n" \ -" line or after the command string.\n" \ -"* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is\n" \ -" disabled by default.\n" \ -"* If '' or '' is not specified within commands, then value defined\n" \ -" by 'set network' or 'set node' command is used.\r\n"; + "\nCommand strings start with '\"[\"\"]\"' followed by:\n" + "[[] ] r[ead] [] # SDO upload.\n" + "[[] ] w[rite] # SDO download.\n" + "\n" + "[[] ] start # NMT Start node.\n" + "[[] ] stop # NMT Stop node.\n" + "[[] ] preop[erational] # NMT Set node to pre-operational.\n" + "[[] ] reset node # NMT Reset node.\n" + "[[] ] reset comm[unication] # NMT Reset communication.\n" + "\n" + "[] set network # Set default net.\n" + "[] set node # Set default node.\n" + "[] set sdo_timeout # Configure SDO client time-out in ms.\n" + "[] set sdo_block <0|1> # Enable/disable SDO block transfer.\n" + "\n" + "help [datatype|lss] # Print this or datatype or lss help.\n" + "led # Print status LEDs of this device.\n" + "log # Print message log.\n" + "\n" + "Response:\n" + "\"[\"\"]\" OK | |\n" + " ERROR: | ERROR:\n" + "\n" + "* Every command must be terminated with ('\\r\\n'). characters. Same\n" + " is response. String is not null terminated, is optional in command.\n" + "* Comments started with '#' are ignored. They may be on the beginning of the\n" + " line or after the command string.\n" + "* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is\n" + " disabled by default.\n" + "* If '' or '' is not specified within commands, then value defined\n" + " by 'set network' or 'set node' command is used.\r\n"; static const char CO_GTWA_helpStringDatatypes[] = -"\nDatatypes:\n" \ -"b # Boolean.\n" \ -"i8, i16, i32, i64 # Signed integers.\n" \ -"u8, u16, u32, u64 # Unsigned integers.\n" \ -"x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard.\n" \ -"r32, r64 # Real numbers.\n" \ -"vs # Visible string (between double quotes if multi-word).\n" \ -"os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line).\n" \ -"d # domain (mime-base64 (RFC2045) based, one line).\n" \ -"hex # Hexagonal data, optionally space separated, non-standard.\r\n"; + "\nDatatypes:\n" + "b # Boolean.\n" + "i8, i16, i32, i64 # Signed integers.\n" + "u8, u16, u32, u64 # Unsigned integers.\n" + "x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard.\n" + "r32, r64 # Real numbers.\n" + "vs # Visible string (between double quotes if multi-word).\n" + "os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line).\n" + "d # domain (mime-base64 (RFC2045) based, one line).\n" + "hex # Hexagonal data, optionally space separated, non-standard.\r\n"; static const char CO_GTWA_helpStringLss[] = -"\nLSS commands:\n" \ -"lss_switch_glob <0|1> # Switch state global command.\n" \ -"lss_switch_sel \\\n" \ -" #Switch state selective.\n" \ -"lss_set_node # Configure node-ID.\n" \ -"lss_conf_bitrate \\\n" \ -" # Configure bit-rate.\n" \ -"lss_activate_bitrate # Activate new bit-rate.\n" \ -"lss_store # LSS store configuration.\n" \ -"lss_inquire_addr [] # Inquire LSS address.\n" \ -"lss_get_node # Inquire node-ID.\n" \ -"_lss_fastscan [] # Identify fastscan, non-standard.\n" \ -"lss_allnodes [ [ \\\n" \ -" [ \\\n" \ -" ]]]\n" \ -" # Node-ID configuration of all nodes.\n" \ -"\n" \ -"* All LSS commands start with '\"[\"\"]\" []'.\n" \ -"* : 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\n" \ -" 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\n" \ -"* : 0=fastscan, 1=ignore, 2=match value in next parameter\r\n"; + "\nLSS commands:\n" + "lss_switch_glob <0|1> # Switch state global command.\n" + "lss_switch_sel \\\n" + " #Switch state selective.\n" + "lss_set_node # Configure node-ID.\n" + "lss_conf_bitrate \\\n" + " # Configure bit-rate.\n" + "lss_activate_bitrate # Activate new bit-rate.\n" + "lss_store # LSS store configuration.\n" + "lss_inquire_addr [] # Inquire LSS address.\n" + "lss_get_node # Inquire node-ID.\n" + "_lss_fastscan [] # Identify fastscan, non-standard.\n" + "lss_allnodes [ [ \\\n" + " [ \\\n" + " ]]]\n" + " # Node-ID configuration of all nodes.\n" + "\n" + "* All LSS commands start with '\"[\"\"]\" []'.\n" + "* : 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\n" + " 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\n" + "* : 0=fastscan, 1=ignore, 2=match value in next parameter\r\n"; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 #define CO_GTWA_LED_PRINTOUTS_SIZE 5U -static const char *CO_GTWA_LED_PRINTOUTS[CO_GTWA_LED_PRINTOUTS_SIZE] = { - " CANopen status LEDs: R G \r", - " CANopen status LEDs: R G* \r", - " CANopen status LEDs: R* G \r", - " CANopen status LEDs: R* G* \r", - " \r" -}; +static const char* CO_GTWA_LED_PRINTOUTS[CO_GTWA_LED_PRINTOUTS_SIZE] = { + " CANopen status LEDs: R G \r", " CANopen status LEDs: R G* \r", + " CANopen status LEDs: R* G \r", " CANopen status LEDs: R* G* \r", + " \r"}; #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */ - /* Get uint32 number from token, verify limits and set *err if necessary */ -static inline uint32_t getU32(char *token, uint32_t min, - uint32_t max, bool_t *err) -{ - char *sRet; +static inline uint32_t +getU32(char* token, uint32_t min, uint32_t max, bool_t* err) { + char* sRet; uint32_t num = strtoul(token, &sRet, 0); if ((sRet != strchr(token, (int32_t)'\0')) || (num < min) || (num > max)) { @@ -244,22 +228,19 @@ static inline uint32_t getU32(char *token, uint32_t min, } /* Verify net and node, return true on error */ -static bool_t checkNetNode(CO_GTWA_t *gtwa, - int32_t net, int16_t node, uint8_t NodeMin, - CO_GTWA_respErrorCode_t *errCode) -{ +static bool_t +checkNetNode(CO_GTWA_t* gtwa, int32_t net, int16_t node, uint8_t NodeMin, CO_GTWA_respErrorCode_t* errCode) { bool_t e = false; CO_GTWA_respErrorCode_t eCode; if (node == -1) { eCode = CO_GTWA_respErrorNoDefaultNodeSet; e = true; - } - else if ((node < (int16_t)NodeMin) || (node > (int16_t)127)) { + } else if ((node < (int16_t)NodeMin) || (node > (int16_t)127)) { eCode = CO_GTWA_respErrorUnsupportedNode; e = true; } -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_MULTI_NET) != 0 else if (net == -1) { eCode = CO_GTWA_respErrorNoDefaultNetSet; e = true; @@ -281,10 +262,9 @@ static bool_t checkNetNode(CO_GTWA_t *gtwa, } /* Verify net, return true on error */ -static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, - CO_GTWA_respErrorCode_t *errCode) -{ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET) != 0 +static bool_t +checkNet(CO_GTWA_t* gtwa, int32_t net, CO_GTWA_respErrorCode_t* errCode) { +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_MULTI_NET) != 0 bool_t e = false; CO_GTWA_respErrorCode_t eCode; @@ -296,8 +276,7 @@ static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, else if ((net < CO_CONFIG_GTW_NET_MIN) || (net > CO_CONFIG_GTW_NET_MAX)) { eCode = CO_GTWA_respErrorUnsupportedNet; e = true; - } - else { + } else { gtwa->net = (uint16_t)net; } if (e) { @@ -305,49 +284,48 @@ static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net, } return e; #else - (void)errCode; /* unused */ - #define CO_CONFIG_GTW_NET_MIN 0 - #define CO_CONFIG_GTW_NET_MAX 0xFFFF + (void)errCode; /* unused */ +#define CO_CONFIG_GTW_NET_MIN 0 +#define CO_CONFIG_GTW_NET_MAX 0xFFFF gtwa->net = (uint16_t)net; return false; #endif } - -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 /* data types for SDO read or write */ static const CO_GTWA_dataType_t dataTypes[] = { - {(char *)"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */ - {(char *)"b", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* BOOLEAN */ - {(char *)"i8", 1, CO_fifo_readI82a, CO_fifo_cpyTok2I8}, /* INTEGER8 */ - {(char *)"i16", 2, CO_fifo_readI162a, CO_fifo_cpyTok2I16}, /* INTEGER16 */ - {(char *)"i32", 4, CO_fifo_readI322a, CO_fifo_cpyTok2I32}, /* INTEGER32 */ - {(char *)"i64", 8, CO_fifo_readI642a, CO_fifo_cpyTok2I64}, /* INTEGER64 */ - {(char *)"u8", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ - {(char *)"u16", 2, CO_fifo_readU162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ - {(char *)"u32", 4, CO_fifo_readU322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ - {(char *)"u64", 8, CO_fifo_readU642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ - {(char *)"x8", 1, CO_fifo_readX82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ - {(char *)"x16", 2, CO_fifo_readX162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ - {(char *)"x32", 4, CO_fifo_readX322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ - {(char *)"x64", 8, CO_fifo_readX642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ - {(char *)"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */ - {(char *)"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */ - {(char *)"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}, /* VISIBLE_STRING */ - {(char *)"os", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* OCTET_STRING base64*/ - {(char *)"us", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64},/* UNICODE_STRING base64*/ - {(char *)"d", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64} /* DOMAIN - base64 */ + {(char*)"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */ + {(char*)"b", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* BOOLEAN */ + {(char*)"i8", 1, CO_fifo_readI82a, CO_fifo_cpyTok2I8}, /* INTEGER8 */ + {(char*)"i16", 2, CO_fifo_readI162a, CO_fifo_cpyTok2I16}, /* INTEGER16 */ + {(char*)"i32", 4, CO_fifo_readI322a, CO_fifo_cpyTok2I32}, /* INTEGER32 */ + {(char*)"i64", 8, CO_fifo_readI642a, CO_fifo_cpyTok2I64}, /* INTEGER64 */ + {(char*)"u8", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ + {(char*)"u16", 2, CO_fifo_readU162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ + {(char*)"u32", 4, CO_fifo_readU322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ + {(char*)"u64", 8, CO_fifo_readU642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ + {(char*)"x8", 1, CO_fifo_readX82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */ + {(char*)"x16", 2, CO_fifo_readX162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */ + {(char*)"x32", 4, CO_fifo_readX322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */ + {(char*)"x64", 8, CO_fifo_readX642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */ + {(char*)"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */ + {(char*)"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */ + {(char*)"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}, /* VISIBLE_STRING */ + {(char*)"os", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* OCTET_STRING base64*/ + {(char*)"us", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* UNICODE_STRING base64*/ + {(char*)"d", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64} /* DOMAIN - base64 */ }; - /* get data type from token */ -static const CO_GTWA_dataType_t *CO_GTWA_getDataType(char *token, bool_t *err) { +static const CO_GTWA_dataType_t* +CO_GTWA_getDataType(char* token, bool_t* err) { if ((token != NULL) && (*err == false)) { uint32_t i; uint32_t len = sizeof(dataTypes) / sizeof(CO_GTWA_dataType_t); for (i = 0; i < len; i++) { - const CO_GTWA_dataType_t *dt = &dataTypes[i]; + const CO_GTWA_dataType_t* dt = &dataTypes[i]; if (strcmp(token, dt->syntax) == 0) { return dt; } @@ -359,10 +337,10 @@ static const CO_GTWA_dataType_t *CO_GTWA_getDataType(char *token, bool_t *err) { } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ - /* transfer response buffer and verify if all bytes was read. Return true on * success, or false, if communication is broken. */ -static bool_t respBufTransfer(CO_GTWA_t *gtwa) { +static bool_t +respBufTransfer(CO_GTWA_t* gtwa) { uint8_t connectionOK = 1; if (gtwa->readCallback == NULL) { @@ -370,21 +348,17 @@ static bool_t respBufTransfer(CO_GTWA_t *gtwa) { gtwa->respBufOffset = 0; gtwa->respBufCount = 0; gtwa->respHold = false; - } - else { + } else { /* transfer response to the application */ - size_t countRead = - gtwa->readCallback(gtwa->readCallbackObject, - (const char *)>wa->respBuf[gtwa->respBufOffset], - gtwa->respBufCount, - &connectionOK); + size_t countRead = gtwa->readCallback(gtwa->readCallbackObject, + (const char*)>wa->respBuf[gtwa->respBufOffset], gtwa->respBufCount, + &connectionOK); if (countRead < gtwa->respBufCount) { gtwa->respBufOffset += countRead; gtwa->respBufCount -= countRead; gtwa->respHold = true; - } - else { + } else { gtwa->respBufOffset = 0; gtwa->respBufCount = 0; gtwa->respHold = false; @@ -393,45 +367,43 @@ static bool_t respBufTransfer(CO_GTWA_t *gtwa) { return connectionOK != 0U; } - -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_ERROR_DESC) != 0 #ifndef CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS #define CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS + typedef struct { const uint32_t code; const char* desc; } errorDescs_t; -static const errorDescs_t errorDescs[] = { - {100, "Request not supported."}, - {101, "Syntax error."}, - {102, "Request not processed due to internal state."}, - {103, "Time-out."}, - {104, "No default net set."}, - {105, "No default node set."}, - {106, "Unsupported net."}, - {107, "Unsupported node."}, - {200, "Lost guarding message."}, - {201, "Lost connection."}, - {202, "Heartbeat started."}, - {203, "Heartbeat lost."}, - {204, "Wrong NMT state."}, - {205, "Boot-up."}, - {300, "Error passive."}, - {301, "Bus off."}, - {303, "CAN buffer overflow."}, - {304, "CAN init."}, - {305, "CAN active (at init or start-up)."}, - {400, "PDO already used."}, - {401, "PDO length exceeded."}, - {501, "LSS implementation- / manufacturer-specific error."}, - {502, "LSS node-ID not supported."}, - {503, "LSS bit-rate not supported."}, - {504, "LSS parameter storing failed."}, - {505, "LSS command failed because of media error."}, - {600, "Running out of memory."} -}; -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 +static const errorDescs_t errorDescs[] = {{100, "Request not supported."}, + {101, "Syntax error."}, + {102, "Request not processed due to internal state."}, + {103, "Time-out."}, + {104, "No default net set."}, + {105, "No default node set."}, + {106, "Unsupported net."}, + {107, "Unsupported node."}, + {200, "Lost guarding message."}, + {201, "Lost connection."}, + {202, "Heartbeat started."}, + {203, "Heartbeat lost."}, + {204, "Wrong NMT state."}, + {205, "Boot-up."}, + {300, "Error passive."}, + {301, "Bus off."}, + {303, "CAN buffer overflow."}, + {304, "CAN init."}, + {305, "CAN active (at init or start-up)."}, + {400, "PDO already used."}, + {401, "PDO length exceeded."}, + {501, "LSS implementation- / manufacturer-specific error."}, + {502, "LSS node-ID not supported."}, + {503, "LSS bit-rate not supported."}, + {504, "LSS parameter storing failed."}, + {505, "LSS command failed because of media error."}, + {600, "Running out of memory."}}; +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 static const errorDescs_t errorDescsSDO[] = { {0x00000000, "No abort."}, {0x05030000, "Toggle bit not altered."}, @@ -464,56 +436,49 @@ static const errorDescs_t errorDescsSDO[] = { {0x08000021, "Data cannot be transferred or stored to application because of local control."}, {0x08000022, "Data cannot be transferred or stored to application because of present device state."}, {0x08000023, "Object dictionary not present or dynamic generation fails."}, - {0x08000024, "No data available."} -}; + {0x08000024, "No data available."}}; #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #endif /* CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS */ -static void responseWithError(CO_GTWA_t *gtwa, - CO_GTWA_respErrorCode_t respErrorCode) -{ +static void +responseWithError(CO_GTWA_t* gtwa, CO_GTWA_respErrorCode_t respErrorCode) { uint32_t i; uint32_t len = sizeof(errorDescs) / sizeof(errorDescs_t); - const char *desc = "-"; + const char* desc = "-"; for (i = 0; i < len; i++) { - const errorDescs_t *ed = &errorDescs[i]; - if((CO_GTWA_respErrorCode_t)ed->code == respErrorCode) { + const errorDescs_t* ed = &errorDescs[i]; + if ((CO_GTWA_respErrorCode_t)ed->code == respErrorCode) { desc = ed->desc; } } - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] ERROR:%d #%s\r\n", - (int32_t)gtwa->sequence, (int32_t)respErrorCode, desc); + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%" PRId32 "] ERROR:%d #%s\r\n", + (int32_t)gtwa->sequence, (int32_t)respErrorCode, desc); (void)respBufTransfer(gtwa); } -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 -static void responseWithErrorSDO(CO_GTWA_t *gtwa, - CO_SDO_abortCode_t abortCode, - bool_t postponed) -{ +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 +static void +responseWithErrorSDO(CO_GTWA_t* gtwa, CO_SDO_abortCode_t abortCode, bool_t postponed) { uint32_t i; uint32_t len = sizeof(errorDescsSDO) / sizeof(errorDescs_t); - const char *desc = "-"; + const char* desc = "-"; for (i = 0; i < len; i++) { - const errorDescs_t *ed = &errorDescsSDO[i]; - if((CO_SDO_abortCode_t)ed->code == abortCode) { + const errorDescs_t* ed = &errorDescsSDO[i]; + if ((CO_SDO_abortCode_t)ed->code == abortCode) { desc = ed->desc; } } if (!postponed) { gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] ERROR:0x%08X #%s\r\n", - (int32_t)gtwa->sequence, (uint32_t)abortCode, desc); - } - else { - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "\n...ERROR:0x%08X #%s\r\n", - (uint32_t)abortCode, desc); + "[%" PRId32 "] ERROR:0x%08X #%s\r\n", (int32_t)gtwa->sequence, + (uint32_t)abortCode, desc); + } else { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "\n...ERROR:0x%08X #%s\r\n", + (uint32_t)abortCode, desc); } (void)respBufTransfer(gtwa); @@ -521,29 +486,21 @@ static void responseWithErrorSDO(CO_GTWA_t *gtwa, #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #else /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */ -static inline void responseWithError(CO_GTWA_t *gtwa, - CO_GTWA_respErrorCode_t respErrorCode) -{ - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] ERROR:%d\r\n", - gtwa->sequence, respErrorCode); +static inline void +responseWithError(CO_GTWA_t* gtwa, CO_GTWA_respErrorCode_t respErrorCode) { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%" PRId32 "] ERROR:%d\r\n", + gtwa->sequence, respErrorCode); (void)respBufTransfer(gtwa); } -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 -static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, - CO_SDO_abortCode_t abortCode, - bool_t postponed) -{ +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 +static inline void +responseWithErrorSDO(CO_GTWA_t* gtwa, CO_SDO_abortCode_t abortCode, bool_t postponed) { if (!postponed) { - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] ERROR:0x%08X\r\n", - gtwa->sequence, abortCode); - } - else { - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "\n...ERROR:0x%08X\r\n", - abortCode); + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%" PRId32 "] ERROR:0x%08X\r\n", + gtwa->sequence, abortCode); + } else { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "\n...ERROR:0x%08X\r\n", abortCode); } (void)respBufTransfer(gtwa); @@ -551,37 +508,32 @@ static inline void responseWithErrorSDO(CO_GTWA_t *gtwa, #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */ - -static inline void responseWithOK(CO_GTWA_t *gtwa) { - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] OK\r\n", - (int32_t)gtwa->sequence); +static inline void +responseWithOK(CO_GTWA_t* gtwa) { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "[%" PRId32 "] OK\r\n", + (int32_t)gtwa->sequence); (void)respBufTransfer(gtwa); } - -static inline void responseWithEmpty(CO_GTWA_t *gtwa) { - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "\r\n"); +static inline void +responseWithEmpty(CO_GTWA_t* gtwa) { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "\r\n"); (void)respBufTransfer(gtwa); } - -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 -static void responseLSS(CO_GTWA_t *gtwa, CO_LSSmaster_return_t lss_ret) { +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0 +static void +responseLSS(CO_GTWA_t* gtwa, CO_LSSmaster_return_t lss_ret) { if (lss_ret == CO_LSSmaster_OK) { responseWithOK(gtwa); - } - else { + } else { CO_GTWA_respErrorCode_t respErrorCode; - if ((lss_ret==CO_LSSmaster_TIMEOUT) || (lss_ret==CO_LSSmaster_SCAN_NOACK)) { + if ((lss_ret == CO_LSSmaster_TIMEOUT) || (lss_ret == CO_LSSmaster_SCAN_NOACK)) { respErrorCode = CO_GTWA_respErrorTimeOut; - } - else if (lss_ret == CO_LSSmaster_OK_MANUFACTURER) { + } else if (lss_ret == CO_LSSmaster_OK_MANUFACTURER) { respErrorCode = CO_GTWA_respErrorLSSmanufacturer; - } - else { + } else { respErrorCode = CO_GTWA_respErrorInternalState; } responseWithError(gtwa, respErrorCode); @@ -589,10 +541,10 @@ static void responseLSS(CO_GTWA_t *gtwa, CO_LSSmaster_return_t lss_ret) { } #endif - -static inline void convertToLower(char *token, size_t maxCount) { +static inline void +convertToLower(char* token, size_t maxCount) { size_t i; - char *c = &token[0]; + char* c = &token[0]; for (i = 0; i < maxCount; i++) { if (*c == '\0') { @@ -604,19 +556,15 @@ static inline void convertToLower(char *token, size_t maxCount) { } } - /******************************************************************************* * PROCESS FUNCTION ******************************************************************************/ -void CO_GTWA_process(CO_GTWA_t *gtwa, - bool_t enable, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +void +CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint32_t* timerNext_us) { (void)timerNext_us; /* may be unused */ bool_t err = false; /* syntax or other error, true or false, I/O variable */ - uint8_t closed; /* indication of command delimiter, I/O variable */ + uint8_t closed; /* indication of command delimiter, I/O variable */ CO_GTWA_respErrorCode_t respErrorCode = CO_GTWA_respErrorNone; if (gtwa == NULL) { @@ -638,8 +586,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (gtwa->respHold) { gtwa->timeDifference_us_cumulative = timeDifference_us; return; - } - else { + } else { gtwa->timeDifference_us_cumulative = 0; } } @@ -648,9 +595,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * COMMAND PARSER ***************************************************************************/ /* if idle, search for new command, skip comments or empty lines */ - while (CO_fifo_CommSearch(>wa->commFifo, false) && - (gtwa->state == CO_GTWA_ST_IDLE) - ) { + while (CO_fifo_CommSearch(>wa->commFifo, false) && (gtwa->state == CO_GTWA_ST_IDLE)) { char tok[20]; size_t n; uint32_t ui[3]; @@ -658,7 +603,6 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, int32_t net = gtwa->net_default; int16_t node = gtwa->node_default; - /* parse mandatory token '"[""]"' */ closed = 0xFFU; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); @@ -672,30 +616,28 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if ((n == 0U) && (closed != 0U)) { responseWithEmpty(gtwa); continue; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } if (tok[0] != '[') { err = true; break; } - if (tok[strlen(tok)-1U] != ']') { + if (tok[strlen(tok) - 1U] != ']') { err = true; break; } - tok[strlen(tok)-1U] = '\0'; + tok[strlen(tok) - 1U] = '\0'; gtwa->sequence = getU32(tok + 1, 0, 0xFFFFFFFFU, &err); if (err) { break; } - /* parse optional tokens '[[] ]', both numerical. Then * follows mandatory token , which is not numerical. */ for (i = 0; i < 3; i++) { closed = 0xFFU; - n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); + n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err || (n == 0U)) { /* empty token, break on error */ err = true; @@ -707,8 +649,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* numerical value must not be closed */ err = true; break; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } ui[i] = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { @@ -719,38 +661,32 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, break; } - switch(i) { - case 0: /* only (pointed by token) */ - break; - case 1: /* and tokens */ - if (ui[0] > 127U) { - err = true; - respErrorCode = CO_GTWA_respErrorUnsupportedNode; - } - else { - node = (int16_t) ui[0]; - } - break; - case 2: /* , and tokens */ - if (ui[0] > 0xFFFFU) { - err = true; - respErrorCode = CO_GTWA_respErrorUnsupportedNet; - } - else if (ui[1] > 127U) { - err = true; - respErrorCode = CO_GTWA_respErrorUnsupportedNode; - } - else { - net = (int32_t) ui[0]; - node = (int16_t) ui[1]; - } - break; - case 3: /* token contains digit */ - err = true; - break; - default: - /* MISRA C 2004 15.3 */ - break; + switch (i) { + case 0: /* only (pointed by token) */ break; + case 1: /* and tokens */ + if (ui[0] > 127U) { + err = true; + respErrorCode = CO_GTWA_respErrorUnsupportedNode; + } else { + node = (int16_t)ui[0]; + } + break; + case 2: /* , and tokens */ + if (ui[0] > 0xFFFFU) { + err = true; + respErrorCode = CO_GTWA_respErrorUnsupportedNet; + } else if (ui[1] > 127U) { + err = true; + respErrorCode = CO_GTWA_respErrorUnsupportedNode; + } else { + net = (int32_t)ui[0]; + node = (int16_t)ui[1]; + } + break; + case 3: /* token contains digit */ err = true; break; + default: + /* MISRA C 2004 15.3 */ + break; } if (err) { break; @@ -760,38 +696,38 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, convertToLower(tok, sizeof(tok)); bool_t tok_is_set = strcmp(tok, "set") == 0; -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 bool_t tok_is_read = strcmp(tok, "r") == 0; tok_is_read = (strcmp(tok, "read") == 0) || tok_is_read; bool_t tok_is_write = strcmp(tok, "w") == 0; tok_is_write = (strcmp(tok, "write") == 0) || tok_is_write; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0 bool_t tok_is_start = strcmp(tok, "start") == 0; bool_t tok_is_stop = strcmp(tok, "stop") == 0; bool_t tok_is_preop = strcmp(tok, "preop") == 0; tok_is_preop = (strcmp(tok, "preoperational") == 0) || tok_is_preop; bool_t tok_is_reset = strcmp(tok, "reset") == 0; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0 bool_t tok_is_lss_switch_glob = strcmp(tok, "lss_switch_glob") == 0; bool_t tok_is_lss_switch_sel = strcmp(tok, "lss_switch_sel") == 0; bool_t tok_is_lss_set_node = strcmp(tok, "lss_set_node") == 0; bool_t tok_is_lss_conf_bitrate = strcmp(tok, "lss_conf_bitrate") == 0; bool_t tok_is_lss_activate_bitrate = strcmp(tok, "lss_activate_bitrate") == 0; bool_t tok_is_lss_store = strcmp(tok, "lss_store") == 0; - bool_t tok_is_lss_inquire_addr= strcmp(tok, "lss_inquire_addr") == 0; + bool_t tok_is_lss_inquire_addr = strcmp(tok, "lss_inquire_addr") == 0; bool_t tok_is_lss_get_node = strcmp(tok, "lss_get_node") == 0; bool_t tok_is__lss_fastscan = strcmp(tok, "_lss_fastscan") == 0; bool_t tok_is_lss_allnodes = strcmp(tok, "lss_allnodes") == 0; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0 bool_t tok_is_log = strcmp(tok, "log") == 0; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 bool_t tok_is_help = strcmp(tok, "help") == 0; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 bool_t tok_is_led = strcmp(tok, "led") == 0; #endif /* set command - multiple sub commands */ @@ -820,10 +756,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); - value = (uint16_t)getU32(tok, CO_CONFIG_GTW_NET_MIN, - CO_CONFIG_GTW_NET_MAX, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + value = (uint16_t)getU32(tok, CO_CONFIG_GTW_NET_MIN, CO_CONFIG_GTW_NET_MAX, &err); if (err) { break; } @@ -843,8 +777,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint8_t)getU32(tok, 1, 127, &err); if (err) { break; @@ -853,7 +786,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, gtwa->node_default = (int16_t)value; responseWithOK(gtwa); } -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 /* 'set sdo_timeout ' */ else if (strcmp(tok, "sdo_timeout") == 0) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); @@ -866,8 +799,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, 1, 0xFFFF, &err); if (err) { break; @@ -888,14 +820,13 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* value */ closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); value = (uint16_t)getU32(tok, 0, 1, &err); if (err) { break; } - gtwa->SDOblockTransferEnable = (value==1U) ? true : false; + gtwa->SDOblockTransferEnable = (value == 1U) ? true : false; responseWithOK(gtwa); } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ @@ -906,7 +837,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 /* Upload SDO command - 'r[ead] ' */ else if (tok_is_read) { uint16_t idx; @@ -929,8 +860,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* subindex */ closed = 0xFFU; - n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); + n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); if (err || (n == 0U)) { err = true; @@ -940,23 +870,19 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* optional data type */ if (closed == 0U) { closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); convertToLower(tok, sizeof(tok)); gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err); if (err) { break; } - } - else { + } else { gtwa->SDOdataType = &dataTypes[0]; /* use generic data type */ } /* setup client */ - SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, - (uint32_t)CO_CAN_ID_SDO_CLI + gtwa->node, - (uint32_t)CO_CAN_ID_SDO_SRV + gtwa->node, - gtwa->node); + SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, (uint32_t)CO_CAN_ID_SDO_CLI + gtwa->node, + (uint32_t)CO_CAN_ID_SDO_SRV + gtwa->node, gtwa->node); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; @@ -964,8 +890,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* initiate upload */ - SDO_ret = CO_SDOclientUploadInitiate(gtwa->SDO_C, idx, subidx, - gtwa->SDOtimeoutTime, + SDO_ret = CO_SDOclientUploadInitiate(gtwa->SDO_C, idx, subidx, gtwa->SDOtimeoutTime, gtwa->SDOblockTransferEnable); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; @@ -1004,8 +929,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* subindex */ closed = 0U; - n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); + n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); subidx = (uint8_t)getU32(tok, 0, 0xFF, &err); if (err) { break; @@ -1013,8 +937,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* data type */ closed = 0U; - (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), - &closed, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); convertToLower(tok, sizeof(tok)); gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err); if (err) { @@ -1022,10 +945,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* setup client */ - SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, - (uint32_t)CO_CAN_ID_SDO_CLI + gtwa->node, - (uint32_t)CO_CAN_ID_SDO_SRV + gtwa->node, - gtwa->node); + SDO_ret = CO_SDOclient_setup(gtwa->SDO_C, (uint32_t)CO_CAN_ID_SDO_CLI + gtwa->node, + (uint32_t)CO_CAN_ID_SDO_SRV + gtwa->node, gtwa->node); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; @@ -1033,11 +954,8 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* initiate download */ - SDO_ret = - CO_SDOclientDownloadInitiate(gtwa->SDO_C, idx, subidx, - gtwa->SDOdataType->length, - gtwa->SDOtimeoutTime, - gtwa->SDOblockTransferEnable); + SDO_ret = CO_SDOclientDownloadInitiate(gtwa->SDO_C, idx, subidx, gtwa->SDOdataType->length, + gtwa->SDOtimeoutTime, gtwa->SDOblockTransferEnable); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { respErrorCode = CO_GTWA_respErrorInternalState; err = true; @@ -1045,9 +963,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } /* copy data from comm to the SDO buffer, according to data type */ - size = gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, - >wa->commFifo, - &status); + size = gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, >wa->commFifo, &status); /* set to true, if command delimiter was found */ closed = ((status & CO_fifo_st_closed) == 0U) ? 0U : 1U; /* set to true, if data are copied only partially */ @@ -1056,8 +972,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* is syntax error in command or size is zero or not the last token * in command */ if (((status & CO_fifo_st_errMask) != 0U) || (size == 0U) - || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U)) - ) { + || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U))) { err = true; break; } @@ -1074,7 +989,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0 /* NMT start node - 'start' */ else if (tok_is_start) { CO_ReturnError_t ret; @@ -1089,8 +1004,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (ret == CO_ERROR_NO) { responseWithOK(gtwa); - } - else { + } else { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -1111,8 +1025,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (ret == CO_ERROR_NO) { responseWithOK(gtwa); - } - else { + } else { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -1133,8 +1046,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (ret == CO_ERROR_NO) { responseWithOK(gtwa); - } - else { + } else { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -1175,8 +1087,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (ret == CO_ERROR_NO) { responseWithOK(gtwa); - } - else { + } else { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -1184,7 +1095,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT */ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0 /* Switch state global command - 'lss_switch_glob <0|1>' */ else if (tok_is_lss_switch_glob) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); @@ -1209,14 +1120,12 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, ret = CO_LSSmaster_swStateDeselect(gtwa->LSSmaster); if (ret == CO_LSSmaster_OK) { responseWithOK(gtwa); - } - else { + } else { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; } - } - else { + } else { /* continue with state machine */ gtwa->state = CO_GTWA_ST_LSS_SWITCH_GLOB; } @@ -1225,7 +1134,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, * 'lss_switch_sel ' */ else if (tok_is_lss_switch_sel) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); - CO_LSS_address_t *addr = >wa->lssAddress; + CO_LSS_address_t* addr = >wa->lssAddress; if ((closed != 0U) || NodeErr) { err = true; @@ -1292,10 +1201,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, else if (tok_is_lss_conf_bitrate) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint8_t tableIndex; - uint32_t maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / - sizeof(CO_LSS_bitTimingTableLookup[0])) - 1U; + uint32_t maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) / sizeof(CO_LSS_bitTimingTableLookup[0])) - 1U; - if ((closed != 0U)|| NodeErr) { + if ((closed != 0U) || NodeErr) { err = true; break; } @@ -1345,8 +1253,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, ret = CO_LSSmaster_ActivateBit(gtwa->LSSmaster, switchDelay); if (ret == CO_LSSmaster_OK) { responseWithOK(gtwa); - } - else { + } else { respErrorCode = CO_GTWA_respErrorInternalState; err = true; break; @@ -1377,7 +1284,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, uint8_t lsssub; /* get value */ closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); lsssub = (uint8_t)getU32(tok, 0, 3, &err); if (err) { break; @@ -1391,8 +1298,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, /* continue with state machine */ gtwa->state = CO_GTWA_ST_LSS_INQUIRE; - } - else { + } else { /* continue with state machine */ gtwa->state = CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL; } @@ -1424,7 +1330,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (closed == 0U) { /* get value */ closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) { break; @@ -1470,12 +1376,11 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, if (closed == 0U) { /* get optional token timeout (non standard) */ closed = 0xFFU; - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err); if (err) { break; } - } /* If timeout not specified, use 100ms. Should work in most cases */ gtwa->lssTimeout_ms = (timeout_ms == 0U) ? 100U : timeout_ms; @@ -1495,14 +1400,14 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } if (closed == 0U) { /* more arguments follow */ - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); gtwa->lssNID = (uint8_t)getU32(tok, 1, 127, &err); if (err) { break; } closed = 0xFFU; - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); gtwa->lssStore = (bool_t)getU32(tok, 0, 1, &err); if (err) { break; @@ -1515,53 +1420,53 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } if (closed == 0U) { /* more arguments follow */ - CO_LSSmaster_fastscan_t *fs = >wa->lssFastscan; + CO_LSSmaster_fastscan_t* fs = >wa->lssFastscan; - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); fs->scan[CO_LSS_FASTSCAN_VENDOR_ID] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); fs->match.identity.vendorID = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); fs->scan[CO_LSS_FASTSCAN_PRODUCT] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->match.identity.productCode = getU32(tok,0,0xFFFFFFFFU, &err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + fs->match.identity.productCode = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); fs->scan[CO_LSS_FASTSCAN_REV] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->match.identity.revisionNumber=getU32(tok,0,0xFFFFFFFFU,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + fs->match.identity.revisionNumber = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); fs->scan[CO_LSS_FASTSCAN_SERIAL] = (CO_LSSmaster_scantype_t)getU32(tok, 0, 2, &err); if (err) { break; } closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); - fs->match.identity.serialNumber = getU32(tok,0,0xFFFFFFFFU,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); + fs->match.identity.serialNumber = getU32(tok, 0, 0xFFFFFFFFU, &err); if (err) { break; } @@ -1572,7 +1477,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0 /* Print message log */ else if (tok_is_log) { if (closed == 0U) { @@ -1583,16 +1488,15 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 /* Print help */ else if (tok_is_help) { if (closed == 1U) { gtwa->helpString = CO_GTWA_helpString; - } - else { + } else { /* get second token */ closed = 1U; - (void)CO_fifo_readToken(>wa->commFifo,tok,sizeof(tok),&closed,&err); + (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); if (err) { break; } @@ -1600,11 +1504,9 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, convertToLower(tok, sizeof(tok)); if (strcmp(tok, "datatype") == 0) { gtwa->helpString = CO_GTWA_helpStringDatatypes; - } - else if (strcmp(tok, "lss") == 0) { + } else if (strcmp(tok, "lss") == 0) { gtwa->helpString = CO_GTWA_helpStringLss; - } - else { + } else { err = true; break; } @@ -1615,7 +1517,7 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP */ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 /* Print status led diodes */ else if (tok_is_led) { if (closed == 0U) { @@ -1635,8 +1537,6 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } } /* while CO_GTWA_ST_IDLE && CO_fifo_CommSearch */ - - /*************************************************************************** * STATE MACHINE ***************************************************************************/ @@ -1648,547 +1548,466 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, responseWithError(gtwa, respErrorCode); /* delete command, if it was only partially read */ - if(closed == 0U) { + if (closed == 0U) { (void)CO_fifo_CommSearch(>wa->commFifo, true); } gtwa->state = CO_GTWA_ST_IDLE; } else { - switch (gtwa->state) { - case CO_GTWA_ST_IDLE: { - return; /* skip timerNext_us calculation */ - break; - } + switch (gtwa->state) { + case CO_GTWA_ST_IDLE: { + return; /* skip timerNext_us calculation */ + break; + } -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 - /* SDO upload state */ - case CO_GTWA_ST_READ: { - CO_SDO_abortCode_t abortCode; - size_t sizeTransferred; - CO_SDO_return_t ret; - - ret = CO_SDOclientUpload(gtwa->SDO_C, - timeDifference_us, - false, - &abortCode, - NULL, - &sizeTransferred, - timerNext_us); - - if (ret < CO_SDO_RT_ok_communicationEnd) { - responseWithErrorSDO(gtwa, abortCode, gtwa->SDOdataCopyStatus); - gtwa->state = CO_GTWA_ST_IDLE; - } - /* Response data must be read, partially or whole */ - else if ((ret == CO_SDO_RT_uploadDataBufferFull) - || (ret == CO_SDO_RT_ok_communicationEnd) - ) { - size_t fifoRemain; - - /* write response head first */ - if (!gtwa->SDOdataCopyStatus) { - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, - CO_GTWA_RESP_BUF_SIZE - 2U, - "[%"PRId32"] ", - (int32_t)gtwa->sequence); - gtwa->SDOdataCopyStatus = true; - } - - /* Empty SDO fifo buffer in multiple cycles. Repeat until - * application runs out of space (respHold) or fifo empty. */ - do { - /* read SDO fifo (partially) and print specific data type as - * ascii into intermediate respBuf */ - gtwa->respBufCount += gtwa->SDOdataType->dataTypePrint( - >wa->SDO_C->bufFifo, - >wa->respBuf[gtwa->respBufCount], - (CO_GTWA_RESP_BUF_SIZE - 2U) - gtwa->respBufCount, - ret == CO_SDO_RT_ok_communicationEnd); - fifoRemain = CO_fifo_getOccupied(>wa->SDO_C->bufFifo); - - /* end of communication, print newline and enter idle state */ - if ((ret == CO_SDO_RT_ok_communicationEnd) && (fifoRemain == 0U)) { - gtwa->respBufCount += - (size_t)sprintf(>wa->respBuf[gtwa->respBufCount], "\r\n"); - gtwa->state = CO_GTWA_ST_IDLE; - } +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 + /* SDO upload state */ + case CO_GTWA_ST_READ: { + CO_SDO_abortCode_t abortCode; + size_t sizeTransferred; + CO_SDO_return_t ret; + + ret = CO_SDOclientUpload(gtwa->SDO_C, timeDifference_us, false, &abortCode, NULL, &sizeTransferred, + timerNext_us); - /* transfer response to the application */ - if (respBufTransfer(gtwa) == false) { - /* broken communication, send SDO abort and force finish. */ - abortCode = CO_SDO_AB_DATA_TRANSF; - (void)CO_SDOclientUpload(gtwa->SDO_C, - 0, - true, - &abortCode, - NULL, - NULL, - NULL); + if (ret < CO_SDO_RT_ok_communicationEnd) { + responseWithErrorSDO(gtwa, abortCode, gtwa->SDOdataCopyStatus); gtwa->state = CO_GTWA_ST_IDLE; - break; } - } while ((gtwa->respHold == false) && (fifoRemain > 0U)); - } - else { /* MISRA C 2004 14.10 */ } - break; - } - - /* SDO download state */ - case CO_GTWA_ST_WRITE: - case CO_GTWA_ST_WRITE_ABORTED: { - CO_SDO_abortCode_t abortCode; - size_t sizeTransferred; - bool_t abort_comm = false; - bool_t hold = false; - CO_SDO_return_t ret; - - /* copy data to the SDO buffer if previous dataTypeScan was partial */ - if (gtwa->SDOdataCopyStatus) { - uint8_t status; - gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, - >wa->commFifo, - &status); - /* set to true, if command delimiter was found */ - closed = ((status & CO_fifo_st_closed) == 0U) ? 0U : 1U; - /* set to true, if data are copied only partially */ - gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0U; + /* Response data must be read, partially or whole */ + else if ((ret == CO_SDO_RT_uploadDataBufferFull) || (ret == CO_SDO_RT_ok_communicationEnd)) { + size_t fifoRemain; + + /* write response head first */ + if (!gtwa->SDOdataCopyStatus) { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE - 2U, + "[%" PRId32 "] ", (int32_t)gtwa->sequence); + gtwa->SDOdataCopyStatus = true; + } - /* is syntax error in command or not the last token in command */ - if (((status & CO_fifo_st_errMask) != 0U) - || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U)) - ) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - abort_comm = true; /* abort SDO communication */ - /* clear the rest of the command, if necessary */ - if (closed != 1U) { - (void)CO_fifo_CommSearch(>wa->commFifo, true); + /* Empty SDO fifo buffer in multiple cycles. Repeat until + * application runs out of space (respHold) or fifo empty. */ + do { + /* read SDO fifo (partially) and print specific data type as + * ascii into intermediate respBuf */ + gtwa->respBufCount += gtwa->SDOdataType->dataTypePrint( + >wa->SDO_C->bufFifo, >wa->respBuf[gtwa->respBufCount], + (CO_GTWA_RESP_BUF_SIZE - 2U) - gtwa->respBufCount, ret == CO_SDO_RT_ok_communicationEnd); + fifoRemain = CO_fifo_getOccupied(>wa->SDO_C->bufFifo); + + /* end of communication, print newline and enter idle state */ + if ((ret == CO_SDO_RT_ok_communicationEnd) && (fifoRemain == 0U)) { + gtwa->respBufCount += (size_t)sprintf(>wa->respBuf[gtwa->respBufCount], "\r\n"); + gtwa->state = CO_GTWA_ST_IDLE; + } + + /* transfer response to the application */ + if (respBufTransfer(gtwa) == false) { + /* broken communication, send SDO abort and force finish. */ + abortCode = CO_SDO_AB_DATA_TRANSF; + (void)CO_SDOclientUpload(gtwa->SDO_C, 0, true, &abortCode, NULL, NULL, NULL); + gtwa->state = CO_GTWA_ST_IDLE; + break; + } + } while ((gtwa->respHold == false) && (fifoRemain > 0U)); + } else { /* MISRA C 2004 14.10 */ } + break; } - if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) { - /* Stay in this state, until all data transferred via commFifo + + /* SDO download state */ + case CO_GTWA_ST_WRITE: + case CO_GTWA_ST_WRITE_ABORTED: { + CO_SDO_abortCode_t abortCode; + size_t sizeTransferred; + bool_t abort_comm = false; + bool_t hold = false; + CO_SDO_return_t ret; + + /* copy data to the SDO buffer if previous dataTypeScan was partial */ + if (gtwa->SDOdataCopyStatus) { + uint8_t status; + gtwa->SDOdataType->dataTypeScan(>wa->SDO_C->bufFifo, >wa->commFifo, &status); + /* set to true, if command delimiter was found */ + closed = ((status & CO_fifo_st_closed) == 0U) ? 0U : 1U; + /* set to true, if data are copied only partially */ + gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0U; + + /* is syntax error in command or not the last token in command */ + if (((status & CO_fifo_st_errMask) != 0U) + || ((gtwa->SDOdataCopyStatus == false) && (closed != 1U))) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + abort_comm = true; /* abort SDO communication */ + /* clear the rest of the command, if necessary */ + if (closed != 1U) { + (void)CO_fifo_CommSearch(>wa->commFifo, true); + } + } + if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) { + /* Stay in this state, until all data transferred via commFifo * will be purged. */ - if (!CO_fifo_purge(>wa->SDO_C->bufFifo) || (closed == 1U)) { - gtwa->state = CO_GTWA_ST_IDLE; + if (!CO_fifo_purge(>wa->SDO_C->bufFifo) || (closed == 1U)) { + gtwa->state = CO_GTWA_ST_IDLE; + } + break; + } } - break; - } - } - /* If not all data were transferred, make sure, there is enough data in + /* If not all data were transferred, make sure, there is enough data in * SDO buffer, to continue communication. Otherwise wait and check for * timeout */ - if (gtwa->SDOdataCopyStatus) { - if( CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7U)) { - if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { - abortCode = CO_SDO_AB_DEVICE_INCOMPAT; - abort_comm = true; - } - else { - gtwa->stateTimeoutTmr += timeDifference_us; - hold = true; + if (gtwa->SDOdataCopyStatus) { + if (CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7U)) { + if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { + abortCode = CO_SDO_AB_DEVICE_INCOMPAT; + abort_comm = true; + } else { + gtwa->stateTimeoutTmr += timeDifference_us; + hold = true; + } + } } - } - } - if (!hold || abort_comm) { - /* if OS has CANtx queue, speedup block transfer */ - uint32_t loop = 0; - do { - ret = CO_SDOclientDownload(gtwa->SDO_C, - timeDifference_us, - abort_comm, - gtwa->SDOdataCopyStatus, - &abortCode, - &sizeTransferred, - timerNext_us); - if (++loop >= CO_CONFIG_GTW_BLOCK_DL_LOOP) { - break; + if (!hold || abort_comm) { + /* if OS has CANtx queue, speedup block transfer */ + uint32_t loop = 0; + do { + ret = CO_SDOclientDownload(gtwa->SDO_C, timeDifference_us, abort_comm, gtwa->SDOdataCopyStatus, + &abortCode, &sizeTransferred, timerNext_us); + if (++loop >= CO_CONFIG_GTW_BLOCK_DL_LOOP) { + break; + } + } while (ret == CO_SDO_RT_blockDownldInProgress); + + /* send response in case of error or finish */ + if (ret < CO_SDO_RT_ok_communicationEnd) { + responseWithErrorSDO(gtwa, abortCode, false); + /* purge remaining data if necessary */ + gtwa->state = gtwa->SDOdataCopyStatus ? CO_GTWA_ST_WRITE_ABORTED : CO_GTWA_ST_IDLE; + } else if (ret == CO_SDO_RT_ok_communicationEnd) { + responseWithOK(gtwa); + gtwa->state = CO_GTWA_ST_IDLE; + } else { /* MISRA C 2004 14.10 */ + } } - } while (ret == CO_SDO_RT_blockDownldInProgress); - - /* send response in case of error or finish */ - if (ret < CO_SDO_RT_ok_communicationEnd) { - responseWithErrorSDO(gtwa, abortCode, false); - /* purge remaining data if necessary */ - gtwa->state = gtwa->SDOdataCopyStatus - ? CO_GTWA_ST_WRITE_ABORTED - : CO_GTWA_ST_IDLE; - } - else if (ret == CO_SDO_RT_ok_communicationEnd) { - responseWithOK(gtwa); - gtwa->state = CO_GTWA_ST_IDLE; + break; } - else { /* MISRA C 2004 14.10 */ } - } - break; - } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 - case CO_GTWA_ST_LSS_SWITCH_GLOB: { - CO_LSSmaster_return_t ret; - ret = CO_LSSmaster_swStateSelect(gtwa->LSSmaster, - timeDifference_us, - NULL); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - responseLSS(gtwa, ret); - gtwa->state = CO_GTWA_ST_IDLE; - } - break; - } - case CO_GTWA_ST_LSS_SWITCH_SEL: { - CO_LSSmaster_return_t ret; - ret = CO_LSSmaster_swStateSelect(gtwa->LSSmaster, - timeDifference_us, - >wa->lssAddress); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - responseLSS(gtwa, ret); - gtwa->state = CO_GTWA_ST_IDLE; - } - break; - } - case CO_GTWA_ST_LSS_SET_NODE: { - CO_LSSmaster_return_t ret; - ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster, - timeDifference_us, - gtwa->lssNID); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { - respErrorCode = CO_GTWA_respErrorLSSnodeIdNotSupported; - responseWithError(gtwa, respErrorCode); - } - else { - responseLSS(gtwa, ret); - } - gtwa->state = CO_GTWA_ST_IDLE; - } - break; - } - case CO_GTWA_ST_LSS_CONF_BITRATE: { - CO_LSSmaster_return_t ret; - ret = CO_LSSmaster_configureBitTiming(gtwa->LSSmaster, - timeDifference_us, - gtwa->lssBitrate); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { - respErrorCode = CO_GTWA_respErrorLSSbitRateNotSupported; - responseWithError(gtwa, respErrorCode); - } - else { - responseLSS(gtwa, ret); - } - gtwa->state = CO_GTWA_ST_IDLE; - } - break; - } - case CO_GTWA_ST_LSS_STORE: { - CO_LSSmaster_return_t ret; - - ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, timeDifference_us); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { - respErrorCode = CO_GTWA_respErrorLSSparameterStoringFailed; - responseWithError(gtwa, respErrorCode); - } - else { - responseLSS(gtwa, ret); - } - gtwa->state = CO_GTWA_ST_IDLE; - } - break; - } - case CO_GTWA_ST_LSS_INQUIRE: { - CO_LSSmaster_return_t ret; - uint32_t value; - - ret = CO_LSSmaster_Inquire(gtwa->LSSmaster, timeDifference_us, - gtwa->lssInquireCs, &value); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - if (ret == CO_LSSmaster_OK) { - if (gtwa->lssInquireCs == CO_LSS_INQUIRE_NODE_ID) { - gtwa->respBufCount = - (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] 0x%02"PRIX32"\r\n", - (int32_t)gtwa->sequence, value & 0xFFU); - } else { - gtwa->respBufCount = - (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] 0x%08"PRIX32"\r\n", - (int32_t)gtwa->sequence, value); - } - (void)respBufTransfer(gtwa); - } - else { - responseLSS(gtwa, ret); - } - gtwa->state = CO_GTWA_ST_IDLE; - } - break; - } - case CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL: { - CO_LSSmaster_return_t ret; - - ret = CO_LSSmaster_InquireLssAddress(gtwa->LSSmaster, timeDifference_us, - >wa->lssAddress); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - if (ret == CO_LSSmaster_OK) { - gtwa->respBufCount = - (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ - " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", - (int32_t)gtwa->sequence, - gtwa->lssAddress.identity.vendorID, - gtwa->lssAddress.identity.productCode, - gtwa->lssAddress.identity.revisionNumber, - gtwa->lssAddress.identity.serialNumber); - (void)respBufTransfer(gtwa); - } - else { - responseLSS(gtwa, ret); - } - gtwa->state = CO_GTWA_ST_IDLE; - } - break; - } - case CO_GTWA_ST__LSS_FASTSCAN: { - CO_LSSmaster_return_t ret; - - ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, timeDifference_us, - >wa->lssFastscan); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - if ((ret == CO_LSSmaster_OK) || (ret == CO_LSSmaster_SCAN_FINISHED)) { - gtwa->respBufCount = - (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \ - " 0x%08"PRIX32" 0x%08"PRIX32"\r\n", - (int32_t)gtwa->sequence, - gtwa->lssFastscan.found.identity.vendorID, - gtwa->lssFastscan.found.identity.productCode, - gtwa->lssFastscan.found.identity.revisionNumber, - gtwa->lssFastscan.found.identity.serialNumber); - (void)respBufTransfer(gtwa); - } - else { - responseLSS(gtwa, ret); - } - CO_LSSmaster_changeTimeout(gtwa->LSSmaster, - CO_LSSmaster_DEFAULT_TIMEOUT); - gtwa->state = CO_GTWA_ST_IDLE; - } - break; - } - case CO_GTWA_ST_LSS_ALLNODES: { - CO_LSSmaster_return_t ret; - if (gtwa->lssSubState == 0U) { /* _lss_fastscan */ - ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, - timeDifference_us, - >wa->lssFastscan); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - CO_LSSmaster_changeTimeout(gtwa->LSSmaster, - CO_LSSmaster_DEFAULT_TIMEOUT); - - if ((ret == CO_LSSmaster_OK) || (ret == CO_LSSmaster_SCAN_NOACK)) { - /* no (more) nodes found, send report sum and finish */ - gtwa->respBufCount = - (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "# Found %d nodes, search finished.\n" \ - "[%"PRId32"] OK\r\n", - gtwa->lssNodeCount, - (int32_t)gtwa->sequence); - (void)respBufTransfer(gtwa); +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0 + case CO_GTWA_ST_LSS_SWITCH_GLOB: { + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_swStateSelect(gtwa->LSSmaster, timeDifference_us, NULL); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + responseLSS(gtwa, ret); gtwa->state = CO_GTWA_ST_IDLE; } - else if (ret == CO_LSSmaster_SCAN_FINISHED) { - /* next sub-step */ - gtwa->lssSubState++; - } - else { - /* error occurred */ + break; + } + case CO_GTWA_ST_LSS_SWITCH_SEL: { + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_swStateSelect(gtwa->LSSmaster, timeDifference_us, >wa->lssAddress); + if (ret != CO_LSSmaster_WAIT_SLAVE) { responseLSS(gtwa, ret); gtwa->state = CO_GTWA_ST_IDLE; } + break; } - } - if (gtwa->lssSubState == 1U) { /* lss_set_node */ - ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster, - timeDifference_us, - gtwa->lssNID); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - if (ret == CO_LSSmaster_OK) { - /* next sub-step */ - gtwa->lssSubState += gtwa->lssStore ? 1U : 2U; - } - else { - /* error occurred */ + case CO_GTWA_ST_LSS_SET_NODE: { + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster, timeDifference_us, gtwa->lssNID); + if (ret != CO_LSSmaster_WAIT_SLAVE) { if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { respErrorCode = CO_GTWA_respErrorLSSnodeIdNotSupported; responseWithError(gtwa, respErrorCode); - } - else { + } else { responseLSS(gtwa, ret); } gtwa->state = CO_GTWA_ST_IDLE; } + break; } - } - if (gtwa->lssSubState == 2U) { /* lss_store */ - ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, - timeDifference_us); - if (ret != CO_LSSmaster_WAIT_SLAVE) { - if (ret == CO_LSSmaster_OK) { - /* next sub-step */ - gtwa->lssSubState++; - } - else { - /* error occurred */ + case CO_GTWA_ST_LSS_CONF_BITRATE: { + CO_LSSmaster_return_t ret; + ret = CO_LSSmaster_configureBitTiming(gtwa->LSSmaster, timeDifference_us, gtwa->lssBitrate); + if (ret != CO_LSSmaster_WAIT_SLAVE) { if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { - respErrorCode = - CO_GTWA_respErrorLSSparameterStoringFailed; + respErrorCode = CO_GTWA_respErrorLSSbitRateNotSupported; responseWithError(gtwa, respErrorCode); - } - else { + } else { responseLSS(gtwa, ret); } gtwa->state = CO_GTWA_ST_IDLE; } + break; } - } - if (gtwa->lssSubState >= 3U) { /* lss_switch_glob 0 */ - /* send non-confirmed message */ - ret = CO_LSSmaster_swStateDeselect(gtwa->LSSmaster); - if (ret != CO_LSSmaster_OK) { - /* error occurred */ - responseLSS(gtwa, ret); - gtwa->state = CO_GTWA_ST_IDLE; - } - else { - /* cycle finished successfully, send report */ - uint8_t lssNidAssigned = gtwa->lssNID; - const char msg2Fmt[] = "# Not all nodes scanned!\n" \ - "[%"PRId32"] OK\r\n"; - char msg2[sizeof(msg2Fmt)+10U] = {0}; - - /* increment variables, check end-of-nodeId */ - gtwa->lssNodeCount++; - if (gtwa->lssNID < 127U) { - /* repeat cycle with next node-id */ - gtwa->lssNID++; - CO_LSSmaster_changeTimeout(gtwa->LSSmaster, - gtwa->lssTimeout_ms); - gtwa->lssSubState = 0; + case CO_GTWA_ST_LSS_STORE: { + CO_LSSmaster_return_t ret; + + ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, timeDifference_us); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { + respErrorCode = CO_GTWA_respErrorLSSparameterStoringFailed; + responseWithError(gtwa, respErrorCode); + } else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; } - else { - /* If we can't assign more node IDs, quit scanning */ - sprintf(msg2, msg2Fmt, (int32_t)gtwa->sequence); + break; + } + case CO_GTWA_ST_LSS_INQUIRE: { + CO_LSSmaster_return_t ret; + uint32_t value; + + ret = CO_LSSmaster_Inquire(gtwa->LSSmaster, timeDifference_us, gtwa->lssInquireCs, &value); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK) { + if (gtwa->lssInquireCs == CO_LSS_INQUIRE_NODE_ID) { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%" PRId32 "] 0x%02" PRIX32 "\r\n", + (int32_t)gtwa->sequence, value & 0xFFU); + } else { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%" PRId32 "] 0x%08" PRIX32 "\r\n", + (int32_t)gtwa->sequence, value); + } + (void)respBufTransfer(gtwa); + } else { + responseLSS(gtwa, ret); + } gtwa->state = CO_GTWA_ST_IDLE; } + break; + } + case CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL: { + CO_LSSmaster_return_t ret; - /* send report */ - gtwa->respBufCount = - (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "# Node-ID %d assigned to: 0x%08"PRIX32" 0x%08" \ - PRIX32" 0x%08"PRIX32" 0x%08"PRIX32"\n%s", - lssNidAssigned, - gtwa->lssFastscan.found.identity.vendorID, - gtwa->lssFastscan.found.identity.productCode, - gtwa->lssFastscan.found.identity.revisionNumber, - gtwa->lssFastscan.found.identity.serialNumber, - msg2); - (void)respBufTransfer(gtwa); + ret = CO_LSSmaster_InquireLssAddress(gtwa->LSSmaster, timeDifference_us, >wa->lssAddress); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK) { + gtwa->respBufCount = (size_t)snprintf( + gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%" PRId32 "] 0x%08" PRIX32 " 0x%08" PRIX32 " 0x%08" PRIX32 " 0x%08" PRIX32 "\r\n", + (int32_t)gtwa->sequence, gtwa->lssAddress.identity.vendorID, + gtwa->lssAddress.identity.productCode, gtwa->lssAddress.identity.revisionNumber, + gtwa->lssAddress.identity.serialNumber); + (void)respBufTransfer(gtwa); + } else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + break; } - } - break; - } /* CO_GTWA_ST_LSS_ALLNODES */ -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ + case CO_GTWA_ST__LSS_FASTSCAN: { + CO_LSSmaster_return_t ret; -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0 - /* print message log */ - case CO_GTWA_ST_LOG: { - do { - gtwa->respBufCount = CO_fifo_read(>wa->logFifo, - (uint8_t *)gtwa->respBuf, - CO_GTWA_RESP_BUF_SIZE, NULL); - (void)respBufTransfer(gtwa); + ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, timeDifference_us, >wa->lssFastscan); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if ((ret == CO_LSSmaster_OK) || (ret == CO_LSSmaster_SCAN_FINISHED)) { + gtwa->respBufCount = (size_t)snprintf( + gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "[%" PRId32 "] 0x%08" PRIX32 " 0x%08" PRIX32 " 0x%08" PRIX32 " 0x%08" PRIX32 "\r\n", + (int32_t)gtwa->sequence, gtwa->lssFastscan.found.identity.vendorID, + gtwa->lssFastscan.found.identity.productCode, + gtwa->lssFastscan.found.identity.revisionNumber, + gtwa->lssFastscan.found.identity.serialNumber); + (void)respBufTransfer(gtwa); + } else { + responseLSS(gtwa, ret); + } + CO_LSSmaster_changeTimeout(gtwa->LSSmaster, CO_LSSmaster_DEFAULT_TIMEOUT); + gtwa->state = CO_GTWA_ST_IDLE; + } + break; + } + case CO_GTWA_ST_LSS_ALLNODES: { + CO_LSSmaster_return_t ret; + if (gtwa->lssSubState == 0U) { /* _lss_fastscan */ + ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, timeDifference_us, >wa->lssFastscan); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + CO_LSSmaster_changeTimeout(gtwa->LSSmaster, CO_LSSmaster_DEFAULT_TIMEOUT); + + if ((ret == CO_LSSmaster_OK) || (ret == CO_LSSmaster_SCAN_NOACK)) { + /* no (more) nodes found, send report sum and finish */ + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "# Found %d nodes, search finished.\n" + "[%" PRId32 "] OK\r\n", + gtwa->lssNodeCount, (int32_t)gtwa->sequence); + (void)respBufTransfer(gtwa); + gtwa->state = CO_GTWA_ST_IDLE; + } else if (ret == CO_LSSmaster_SCAN_FINISHED) { + /* next sub-step */ + gtwa->lssSubState++; + } else { + /* error occurred */ + responseLSS(gtwa, ret); + gtwa->state = CO_GTWA_ST_IDLE; + } + } + } + if (gtwa->lssSubState == 1U) { /* lss_set_node */ + ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster, timeDifference_us, gtwa->lssNID); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK) { + /* next sub-step */ + gtwa->lssSubState += gtwa->lssStore ? 1U : 2U; + } else { + /* error occurred */ + if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { + respErrorCode = CO_GTWA_respErrorLSSnodeIdNotSupported; + responseWithError(gtwa, respErrorCode); + } else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + } + if (gtwa->lssSubState == 2U) { /* lss_store */ + ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, timeDifference_us); + if (ret != CO_LSSmaster_WAIT_SLAVE) { + if (ret == CO_LSSmaster_OK) { + /* next sub-step */ + gtwa->lssSubState++; + } else { + /* error occurred */ + if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) { + respErrorCode = CO_GTWA_respErrorLSSparameterStoringFailed; + responseWithError(gtwa, respErrorCode); + } else { + responseLSS(gtwa, ret); + } + gtwa->state = CO_GTWA_ST_IDLE; + } + } + } + if (gtwa->lssSubState >= 3U) { /* lss_switch_glob 0 */ + /* send non-confirmed message */ + ret = CO_LSSmaster_swStateDeselect(gtwa->LSSmaster); + if (ret != CO_LSSmaster_OK) { + /* error occurred */ + responseLSS(gtwa, ret); + gtwa->state = CO_GTWA_ST_IDLE; + } else { + /* cycle finished successfully, send report */ + uint8_t lssNidAssigned = gtwa->lssNID; + const char msg2Fmt[] = "# Not all nodes scanned!\n" + "[%" PRId32 "] OK\r\n"; + char msg2[sizeof(msg2Fmt) + 10U] = {0}; + + /* increment variables, check end-of-nodeId */ + gtwa->lssNodeCount++; + if (gtwa->lssNID < 127U) { + /* repeat cycle with next node-id */ + gtwa->lssNID++; + CO_LSSmaster_changeTimeout(gtwa->LSSmaster, gtwa->lssTimeout_ms); + gtwa->lssSubState = 0; + } else { + /* If we can't assign more node IDs, quit scanning */ + sprintf(msg2, msg2Fmt, (int32_t)gtwa->sequence); + gtwa->state = CO_GTWA_ST_IDLE; + } + + /* send report */ + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + "# Node-ID %d assigned to: 0x%08" PRIX32 " 0x%08" PRIX32 + " 0x%08" PRIX32 " 0x%08" PRIX32 "\n%s", + lssNidAssigned, gtwa->lssFastscan.found.identity.vendorID, + gtwa->lssFastscan.found.identity.productCode, + gtwa->lssFastscan.found.identity.revisionNumber, + gtwa->lssFastscan.found.identity.serialNumber, msg2); + (void)respBufTransfer(gtwa); + } + } + break; + } /* CO_GTWA_ST_LSS_ALLNODES */ +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */ + +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0 + /* print message log */ + case CO_GTWA_ST_LOG: { + do { + gtwa->respBufCount = CO_fifo_read(>wa->logFifo, (uint8_t*)gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, + NULL); + (void)respBufTransfer(gtwa); - if (CO_fifo_getOccupied(>wa->logFifo) == 0U) { - gtwa->state = CO_GTWA_ST_IDLE; + if (CO_fifo_getOccupied(>wa->logFifo) == 0U) { + gtwa->state = CO_GTWA_ST_IDLE; + break; + } + } while (gtwa->respHold == false); break; } - } while (gtwa->respHold == false); - break; - } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 - /* Print help string (in multiple segments if necessary) */ - case CO_GTWA_ST_HELP: { - size_t lenBuf = CO_GTWA_RESP_BUF_SIZE; - size_t lenHelp = strlen(gtwa->helpString); +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0 + /* Print help string (in multiple segments if necessary) */ + case CO_GTWA_ST_HELP: { + size_t lenBuf = CO_GTWA_RESP_BUF_SIZE; + size_t lenHelp = strlen(gtwa->helpString); - do { - size_t lenHelpRemain = lenHelp - gtwa->helpStringOffset; - size_t lenCopied = (lenBuf < lenHelpRemain) ? lenBuf : lenHelpRemain; + do { + size_t lenHelpRemain = lenHelp - gtwa->helpStringOffset; + size_t lenCopied = (lenBuf < lenHelpRemain) ? lenBuf : lenHelpRemain; - (void)memcpy(gtwa->respBuf, - >wa->helpString[gtwa->helpStringOffset], - lenCopied); + (void)memcpy(gtwa->respBuf, >wa->helpString[gtwa->helpStringOffset], lenCopied); - gtwa->respBufCount = lenCopied; - gtwa->helpStringOffset += lenCopied; - (void)respBufTransfer(gtwa); + gtwa->respBufCount = lenCopied; + gtwa->helpStringOffset += lenCopied; + (void)respBufTransfer(gtwa); - if (gtwa->helpStringOffset == lenHelp) { - gtwa->state = CO_GTWA_ST_IDLE; + if (gtwa->helpStringOffset == lenHelp) { + gtwa->state = CO_GTWA_ST_IDLE; + break; + } + } while (gtwa->respHold == false); break; } - } while (gtwa->respHold == false); - break; - } #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 - /* print CANopen status LED diodes */ - case CO_GTWA_ST_LED: { - uint8_t i; +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 + /* print CANopen status LED diodes */ + case CO_GTWA_ST_LED: { + uint8_t i; - if (CO_fifo_CommSearch(>wa->commFifo, false)) { - gtwa->state = CO_GTWA_ST_IDLE; - i = 4; - } - else { - i = (CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2U) + - CO_LED_GREEN(gtwa->LEDs, CO_LED_CANopen); - } - if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1U)) { - i = CO_GTWA_LED_PRINTOUTS_SIZE - 1U; - } + if (CO_fifo_CommSearch(>wa->commFifo, false)) { + gtwa->state = CO_GTWA_ST_IDLE; + i = 4; + } else { + i = (CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2U) + CO_LED_GREEN(gtwa->LEDs, CO_LED_CANopen); + } + if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1U)) { + i = CO_GTWA_LED_PRINTOUTS_SIZE - 1U; + } - if (i != gtwa->ledStringPreviousIndex) { - gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, - "%s", CO_GTWA_LED_PRINTOUTS[i]); - (void)respBufTransfer(gtwa); - gtwa->ledStringPreviousIndex = i; - } - break; - } + if (i != gtwa->ledStringPreviousIndex) { + gtwa->respBufCount = (size_t)snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, "%s", + CO_GTWA_LED_PRINTOUTS[i]); + (void)respBufTransfer(gtwa); + gtwa->ledStringPreviousIndex = i; + } + break; + } #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */ - /* illegal state */ - default: { - respErrorCode = CO_GTWA_respErrorInternalState; - responseWithError(gtwa, respErrorCode); - gtwa->state = CO_GTWA_ST_IDLE; - break; - } - } /* switch (gtwa->state) */ + /* illegal state */ + default: { + respErrorCode = CO_GTWA_respErrorInternalState; + responseWithError(gtwa, respErrorCode); + gtwa->state = CO_GTWA_ST_IDLE; + break; + } + } /* switch (gtwa->state) */ } /* execute next CANopen processing immediately, if idle and more commands * available */ if ((timerNext_us != NULL) && (gtwa->state == CO_GTWA_ST_IDLE)) { - if(CO_fifo_CommSearch(>wa->commFifo, false)) { + if (CO_fifo_CommSearch(>wa->commFifo, false)) { *timerNext_us = 0; } } } -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ diff --git a/CANopen.c b/CANopen.c index a954af58..220e97f7 100644 --- a/CANopen.c +++ b/CANopen.c @@ -22,14 +22,14 @@ /* Get values from CO_config_t or from single default OD.h ********************/ #ifdef CO_MULTIPLE_OD -#define CO_GET_CO(obj) co->obj -#define CO_GET_CNT(obj) co->config->CNT_##obj +#define CO_GET_CO(obj) co->obj +#define CO_GET_CNT(obj) co->config->CNT_##obj #define OD_GET(entry, index) co->config->ENTRY_##entry #else #include "OD.h" -#define CO_GET_CO(obj) ((uint16_t)(CO_##obj)) -#define CO_GET_CNT(obj) (uint8_t)(OD_CNT_##obj) +#define CO_GET_CO(obj) ((uint16_t)(CO_##obj)) +#define CO_GET_CNT(obj) (uint8_t)(OD_CNT_##obj) #define OD_GET(entry, index) OD_ENTRY_##entry /* Verify parameters from "OD.h" and calculate necessary values for each object: @@ -40,267 +40,266 @@ * - calculate total count of CAN message buffers: CO_CNT_ALL_RX_MSGS and * CO_CNT_ALL_TX_MSGS. */ #if OD_CNT_NMT != 1 - #error OD_CNT_NMT from OD.h not correct! +#error OD_CNT_NMT from OD.h not correct! #endif #define CO_RX_CNT_NMT_SLV OD_CNT_NMT -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 - #define CO_TX_CNT_NMT_MST 1 +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0 +#define CO_TX_CNT_NMT_MST 1 #else - #define CO_TX_CNT_NMT_MST 0 +#define CO_TX_CNT_NMT_MST 0 #endif #if OD_CNT_HB_PROD != 1 - #error OD_CNT_HB_PROD from OD.h not correct! +#error OD_CNT_HB_PROD from OD.h not correct! #endif #define CO_TX_CNT_HB_PROD OD_CNT_HB_PROD #if !defined OD_CNT_HB_CONS - #define OD_CNT_HB_CONS 0 +#define OD_CNT_HB_CONS 0 #elif OD_CNT_HB_CONS < 0 || OD_CNT_HB_CONS > 1 - #error OD_CNT_HB_CONS from OD.h not correct! +#error OD_CNT_HB_CONS from OD.h not correct! #endif -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0) && OD_CNT_HB_CONS == 1 - #if OD_CNT_ARR_1016 < 1 || OD_CNT_ARR_1016 > 127 - #error OD_CNT_ARR_1016 is not defined in Object Dictionary or value is wrong! - #endif - #define CO_RX_CNT_HB_CONS OD_CNT_ARR_1016 +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0) && OD_CNT_HB_CONS == 1 +#if OD_CNT_ARR_1016 < 1 || OD_CNT_ARR_1016 > 127 +#error OD_CNT_ARR_1016 is not defined in Object Dictionary or value is wrong! +#endif +#define CO_RX_CNT_HB_CONS OD_CNT_ARR_1016 #else - #define CO_RX_CNT_HB_CONS 0 +#define CO_RX_CNT_HB_CONS 0 #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 - #define CO_RX_CNT_NG_SLV 1 - #define CO_TX_CNT_NG_SLV 1 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 +#define CO_RX_CNT_NG_SLV 1 +#define CO_TX_CNT_NG_SLV 1 #else - #define CO_RX_CNT_NG_SLV 0 - #define CO_TX_CNT_NG_SLV 0 +#define CO_RX_CNT_NG_SLV 0 +#define CO_TX_CNT_NG_SLV 0 #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 - #define CO_RX_CNT_NG_MST 1 - #define CO_TX_CNT_NG_MST 1 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 +#define CO_RX_CNT_NG_MST 1 +#define CO_TX_CNT_NG_MST 1 #else - #define CO_RX_CNT_NG_MST 0 - #define CO_TX_CNT_NG_MST 0 +#define CO_RX_CNT_NG_MST 0 +#define CO_TX_CNT_NG_MST 0 #endif #if OD_CNT_EM != 1 - #error OD_CNT_EM from OD.h not correct! +#error OD_CNT_EM from OD.h not correct! #endif #ifndef OD_ENTRY_H1003 - #define OD_ENTRY_H1003 NULL +#define OD_ENTRY_H1003 NULL #endif #ifndef OD_CNT_ARR_1003 - #define OD_CNT_ARR_1003 8 -#endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 - #if OD_CNT_EM_PROD == 1 - #define CO_TX_CNT_EM_PROD OD_CNT_EM_PROD - #else - #error wrong OD_CNT_EM_PROD - #endif - #ifndef OD_ENTRY_H1015 - #define OD_ENTRY_H1015 NULL - #endif +#define OD_CNT_ARR_1003 8 +#endif +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 +#if OD_CNT_EM_PROD == 1 +#define CO_TX_CNT_EM_PROD OD_CNT_EM_PROD +#else +#error wrong OD_CNT_EM_PROD +#endif +#ifndef OD_ENTRY_H1015 +#define OD_ENTRY_H1015 NULL +#endif #else - #define CO_TX_CNT_EM_PROD 0 +#define CO_TX_CNT_EM_PROD 0 #endif -#if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 - #define CO_RX_CNT_EM_CONS 1 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 +#define CO_RX_CNT_EM_CONS 1 #else - #define CO_RX_CNT_EM_CONS 0 +#define CO_RX_CNT_EM_CONS 0 #endif #if !defined OD_CNT_SDO_SRV - #define OD_CNT_SDO_SRV 1 - #define OD_ENTRY_H1200 NULL +#define OD_CNT_SDO_SRV 1 +#define OD_ENTRY_H1200 NULL #elif OD_CNT_SDO_SRV < 1 || OD_CNT_SDO_SRV > 128 - #error OD_CNT_SDO_SRV from OD.h not correct! +#error OD_CNT_SDO_SRV from OD.h not correct! #endif #define CO_RX_CNT_SDO_SRV OD_CNT_SDO_SRV #define CO_TX_CNT_SDO_SRV OD_CNT_SDO_SRV -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 - #if !defined OD_CNT_SDO_CLI - #define OD_CNT_SDO_CLI 0 - #define OD_ENTRY_H1280 NULL - #elif OD_CNT_SDO_CLI < 0 || OD_CNT_SDO_CLI > 128 - #error OD_CNT_SDO_CLI from OD.h not correct! - #endif - #define CO_RX_CNT_SDO_CLI OD_CNT_SDO_CLI - #define CO_TX_CNT_SDO_CLI OD_CNT_SDO_CLI +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 +#if !defined OD_CNT_SDO_CLI +#define OD_CNT_SDO_CLI 0 +#define OD_ENTRY_H1280 NULL +#elif OD_CNT_SDO_CLI < 0 || OD_CNT_SDO_CLI > 128 +#error OD_CNT_SDO_CLI from OD.h not correct! +#endif +#define CO_RX_CNT_SDO_CLI OD_CNT_SDO_CLI +#define CO_TX_CNT_SDO_CLI OD_CNT_SDO_CLI #else - #define CO_RX_CNT_SDO_CLI 0 - #define CO_TX_CNT_SDO_CLI 0 -#endif - -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 - #if !defined OD_CNT_TIME - #define OD_CNT_TIME 0 - #define OD_ENTRY_H1012 NULL - #elif OD_CNT_TIME < 0 || OD_CNT_TIME > 1 - #error OD_CNT_TIME from OD.h not correct! - #endif - #define CO_RX_CNT_TIME OD_CNT_TIME - #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 - #define CO_TX_CNT_TIME OD_CNT_TIME - #else - #define CO_TX_CNT_TIME 0 - #endif +#define CO_RX_CNT_SDO_CLI 0 +#define CO_TX_CNT_SDO_CLI 0 +#endif + +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 +#if !defined OD_CNT_TIME +#define OD_CNT_TIME 0 +#define OD_ENTRY_H1012 NULL +#elif OD_CNT_TIME < 0 || OD_CNT_TIME > 1 +#error OD_CNT_TIME from OD.h not correct! +#endif +#define CO_RX_CNT_TIME OD_CNT_TIME +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 +#define CO_TX_CNT_TIME OD_CNT_TIME #else - #define CO_RX_CNT_TIME 0 - #define CO_TX_CNT_TIME 0 -#endif - -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 - #if !defined OD_CNT_SYNC - #define OD_CNT_SYNC 0 - #define OD_ENTRY_H1005 NULL - #define OD_ENTRY_H1006 NULL - #elif OD_CNT_SYNC < 0 || OD_CNT_SYNC > 1 - #error OD_CNT_SYNC from OD.h not correct! - #endif - #define CO_RX_CNT_SYNC OD_CNT_SYNC - #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 - #define CO_TX_CNT_SYNC OD_CNT_SYNC - #else - #define CO_TX_CNT_SYNC 0 - #endif - #ifndef OD_ENTRY_H1007 - #define OD_ENTRY_H1007 NULL - #endif - #ifndef OD_ENTRY_H1019 - #define OD_ENTRY_H1019 NULL - #endif +#define CO_TX_CNT_TIME 0 +#endif #else - #define CO_RX_CNT_SYNC 0 - #define CO_TX_CNT_SYNC 0 -#endif - -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 - #if !defined OD_CNT_RPDO - #define OD_CNT_RPDO 0 - #define OD_ENTRY_H1400 NULL - #define OD_ENTRY_H1600 NULL - #elif OD_CNT_RPDO < 0 || OD_CNT_RPDO > 0x200 - #error OD_CNT_RPDO from OD.h not correct! - #endif - #define CO_RX_CNT_RPDO OD_CNT_RPDO +#define CO_RX_CNT_TIME 0 +#define CO_TX_CNT_TIME 0 +#endif + +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 +#if !defined OD_CNT_SYNC +#define OD_CNT_SYNC 0 +#define OD_ENTRY_H1005 NULL +#define OD_ENTRY_H1006 NULL +#elif OD_CNT_SYNC < 0 || OD_CNT_SYNC > 1 +#error OD_CNT_SYNC from OD.h not correct! +#endif +#define CO_RX_CNT_SYNC OD_CNT_SYNC +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 +#define CO_TX_CNT_SYNC OD_CNT_SYNC #else - #define CO_RX_CNT_RPDO 0 -#endif - -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 - #if !defined OD_CNT_TPDO - #define OD_CNT_TPDO 0 - #define OD_ENTRY_H1800 NULL - #define OD_ENTRY_H1A00 NULL - #elif OD_CNT_TPDO < 0 || OD_CNT_TPDO > 0x200 - #error OD_CNT_TPDO from OD.h not correct! - #endif - #define CO_TX_CNT_TPDO OD_CNT_TPDO +#define CO_TX_CNT_SYNC 0 +#endif +#ifndef OD_ENTRY_H1007 +#define OD_ENTRY_H1007 NULL +#endif +#ifndef OD_ENTRY_H1019 +#define OD_ENTRY_H1019 NULL +#endif #else - #define CO_TX_CNT_TPDO 0 +#define CO_RX_CNT_SYNC 0 +#define CO_TX_CNT_SYNC 0 #endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 - #define OD_CNT_LEDS 1 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 +#if !defined OD_CNT_RPDO +#define OD_CNT_RPDO 0 +#define OD_ENTRY_H1400 NULL +#define OD_ENTRY_H1600 NULL +#elif OD_CNT_RPDO < 0 || OD_CNT_RPDO > 0x200 +#error OD_CNT_RPDO from OD.h not correct! +#endif +#define CO_RX_CNT_RPDO OD_CNT_RPDO +#else +#define CO_RX_CNT_RPDO 0 #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 - #if !defined OD_CNT_GFC - #define OD_CNT_GFC 0 - #define OD_ENTRY_H1300 NULL - #elif OD_CNT_GFC < 0 || OD_CNT_GFC > 1 - #error OD_CNT_GFC from OD.h not correct! - #endif - #define CO_RX_CNT_GFC OD_CNT_GFC - #define CO_TX_CNT_GFC OD_CNT_GFC +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 +#if !defined OD_CNT_TPDO +#define OD_CNT_TPDO 0 +#define OD_ENTRY_H1800 NULL +#define OD_ENTRY_H1A00 NULL +#elif OD_CNT_TPDO < 0 || OD_CNT_TPDO > 0x200 +#error OD_CNT_TPDO from OD.h not correct! +#endif +#define CO_TX_CNT_TPDO OD_CNT_TPDO #else - #define CO_RX_CNT_GFC 0 - #define CO_TX_CNT_GFC 0 -#endif - -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 - #if !defined OD_CNT_SRDO - #define OD_CNT_SRDO 0 - #define OD_ENTRY_H1301 NULL - #define OD_ENTRY_H1381 NULL - #define OD_ENTRY_H13FE NULL - #define OD_ENTRY_H13FF NULL - #elif OD_CNT_SRDO < 0 || OD_CNT_SRDO > 64 - #error OD_CNT_SRDO from OD.h not correct! - #endif - #define CO_RX_CNT_SRDO OD_CNT_SRDO - #define CO_TX_CNT_SRDO OD_CNT_SRDO +#define CO_TX_CNT_TPDO 0 +#endif + +#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 +#define OD_CNT_LEDS 1 +#endif + +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 +#if !defined OD_CNT_GFC +#define OD_CNT_GFC 0 +#define OD_ENTRY_H1300 NULL +#elif OD_CNT_GFC < 0 || OD_CNT_GFC > 1 +#error OD_CNT_GFC from OD.h not correct! +#endif +#define CO_RX_CNT_GFC OD_CNT_GFC +#define CO_TX_CNT_GFC OD_CNT_GFC #else - #define CO_RX_CNT_SRDO 0 - #define CO_TX_CNT_SRDO 0 +#define CO_RX_CNT_GFC 0 +#define CO_TX_CNT_GFC 0 +#endif + +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 +#if !defined OD_CNT_SRDO +#define OD_CNT_SRDO 0 +#define OD_ENTRY_H1301 NULL +#define OD_ENTRY_H1381 NULL +#define OD_ENTRY_H13FE NULL +#define OD_ENTRY_H13FF NULL +#elif OD_CNT_SRDO < 0 || OD_CNT_SRDO > 64 +#error OD_CNT_SRDO from OD.h not correct! +#endif +#define CO_RX_CNT_SRDO OD_CNT_SRDO +#define CO_TX_CNT_SRDO OD_CNT_SRDO +#else +#define CO_RX_CNT_SRDO 0 +#define CO_TX_CNT_SRDO 0 #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 - #define OD_CNT_LSS_SLV 1 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 +#define OD_CNT_LSS_SLV 1 #else - #define OD_CNT_LSS_SLV 0 +#define OD_CNT_LSS_SLV 0 #endif #define CO_RX_CNT_LSS_SLV OD_CNT_LSS_SLV #define CO_TX_CNT_LSS_SLV OD_CNT_LSS_SLV -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 - #define OD_CNT_LSS_MST 1 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 +#define OD_CNT_LSS_MST 1 #else - #define OD_CNT_LSS_MST 0 +#define OD_CNT_LSS_MST 0 #endif #define CO_RX_CNT_LSS_MST OD_CNT_LSS_MST #define CO_TX_CNT_LSS_MST OD_CNT_LSS_MST -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 - #define OD_CNT_GTWA 1 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0 +#define OD_CNT_GTWA 1 #endif #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE - #if !defined OD_CNT_TRACE - #define OD_CNT_TRACE 0 - #elif OD_CNT_TRACE < 0 - #error OD_CNT_TRACE from OD.h not correct! - #endif +#if !defined OD_CNT_TRACE +#define OD_CNT_TRACE 0 +#elif OD_CNT_TRACE < 0 +#error OD_CNT_TRACE from OD.h not correct! +#endif #endif /* Indexes of CO_CANrx_t and CO_CANtx_t objects in CO_CANmodule_t and total * number of them. Indexes are sorted in a way, that objects with highest * priority of the CAN identifier are listed first. */ -#define CO_RX_IDX_NMT_SLV 0U -#define CO_RX_IDX_GFC (CO_RX_IDX_NMT_SLV + (uint16_t)CO_RX_CNT_NMT_SLV) -#define CO_RX_IDX_SYNC (CO_RX_IDX_GFC + (uint16_t)CO_RX_CNT_GFC) -#define CO_RX_IDX_EM_CONS (CO_RX_IDX_SYNC + (uint16_t)CO_RX_CNT_SYNC) -#define CO_RX_IDX_TIME (CO_RX_IDX_EM_CONS + (uint16_t)CO_RX_CNT_EM_CONS) -#define CO_RX_IDX_SRDO (CO_RX_IDX_TIME + (uint16_t)CO_RX_CNT_TIME) -#define CO_RX_IDX_RPDO (CO_RX_IDX_SRDO + ((uint16_t)CO_RX_CNT_SRDO * 2U)) -#define CO_RX_IDX_SDO_SRV (CO_RX_IDX_RPDO + (uint16_t)CO_RX_CNT_RPDO) -#define CO_RX_IDX_SDO_CLI (CO_RX_IDX_SDO_SRV + (uint16_t)CO_RX_CNT_SDO_SRV) -#define CO_RX_IDX_HB_CONS (CO_RX_IDX_SDO_CLI + (uint16_t)CO_RX_CNT_SDO_CLI) -#define CO_RX_IDX_NG_SLV (CO_RX_IDX_HB_CONS + (uint16_t)CO_RX_CNT_HB_CONS) -#define CO_RX_IDX_NG_MST (CO_RX_IDX_NG_SLV + (uint16_t)CO_RX_CNT_NG_SLV) -#define CO_RX_IDX_LSS_SLV (CO_RX_IDX_NG_MST + (uint16_t)CO_RX_CNT_NG_MST) -#define CO_RX_IDX_LSS_MST (CO_RX_IDX_LSS_SLV + (uint16_t)CO_RX_CNT_LSS_SLV) -#define CO_CNT_ALL_RX_MSGS (CO_RX_IDX_LSS_MST + (uint16_t)CO_RX_CNT_LSS_MST) - -#define CO_TX_IDX_NMT_MST 0U -#define CO_TX_IDX_GFC (CO_TX_IDX_NMT_MST + (uint16_t)CO_TX_CNT_NMT_MST) -#define CO_TX_IDX_SYNC (CO_TX_IDX_GFC + (uint16_t)CO_TX_CNT_GFC) -#define CO_TX_IDX_EM_PROD (CO_TX_IDX_SYNC + (uint16_t)CO_TX_CNT_SYNC) -#define CO_TX_IDX_TIME (CO_TX_IDX_EM_PROD + (uint16_t)CO_TX_CNT_EM_PROD) -#define CO_TX_IDX_SRDO (CO_TX_IDX_TIME + (uint16_t)CO_TX_CNT_TIME) -#define CO_TX_IDX_TPDO (CO_TX_IDX_SRDO + ((uint16_t)CO_TX_CNT_SRDO * 2U)) -#define CO_TX_IDX_SDO_SRV (CO_TX_IDX_TPDO + (uint16_t)CO_TX_CNT_TPDO) -#define CO_TX_IDX_SDO_CLI (CO_TX_IDX_SDO_SRV + (uint16_t)CO_TX_CNT_SDO_SRV) -#define CO_TX_IDX_HB_PROD (CO_TX_IDX_SDO_CLI + (uint16_t)CO_TX_CNT_SDO_CLI) -#define CO_TX_IDX_NG_SLV (CO_TX_IDX_HB_PROD + (uint16_t)CO_TX_CNT_HB_PROD) -#define CO_TX_IDX_NG_MST (CO_TX_IDX_NG_SLV + (uint16_t)CO_TX_CNT_NG_SLV) -#define CO_TX_IDX_LSS_SLV (CO_TX_IDX_NG_MST + (uint16_t)CO_TX_CNT_NG_MST) -#define CO_TX_IDX_LSS_MST (CO_TX_IDX_LSS_SLV + (uint16_t)CO_TX_CNT_LSS_SLV) -#define CO_CNT_ALL_TX_MSGS (CO_TX_IDX_LSS_MST + (uint16_t)CO_TX_CNT_LSS_MST) +#define CO_RX_IDX_NMT_SLV 0U +#define CO_RX_IDX_GFC (CO_RX_IDX_NMT_SLV + (uint16_t)CO_RX_CNT_NMT_SLV) +#define CO_RX_IDX_SYNC (CO_RX_IDX_GFC + (uint16_t)CO_RX_CNT_GFC) +#define CO_RX_IDX_EM_CONS (CO_RX_IDX_SYNC + (uint16_t)CO_RX_CNT_SYNC) +#define CO_RX_IDX_TIME (CO_RX_IDX_EM_CONS + (uint16_t)CO_RX_CNT_EM_CONS) +#define CO_RX_IDX_SRDO (CO_RX_IDX_TIME + (uint16_t)CO_RX_CNT_TIME) +#define CO_RX_IDX_RPDO (CO_RX_IDX_SRDO + ((uint16_t)CO_RX_CNT_SRDO * 2U)) +#define CO_RX_IDX_SDO_SRV (CO_RX_IDX_RPDO + (uint16_t)CO_RX_CNT_RPDO) +#define CO_RX_IDX_SDO_CLI (CO_RX_IDX_SDO_SRV + (uint16_t)CO_RX_CNT_SDO_SRV) +#define CO_RX_IDX_HB_CONS (CO_RX_IDX_SDO_CLI + (uint16_t)CO_RX_CNT_SDO_CLI) +#define CO_RX_IDX_NG_SLV (CO_RX_IDX_HB_CONS + (uint16_t)CO_RX_CNT_HB_CONS) +#define CO_RX_IDX_NG_MST (CO_RX_IDX_NG_SLV + (uint16_t)CO_RX_CNT_NG_SLV) +#define CO_RX_IDX_LSS_SLV (CO_RX_IDX_NG_MST + (uint16_t)CO_RX_CNT_NG_MST) +#define CO_RX_IDX_LSS_MST (CO_RX_IDX_LSS_SLV + (uint16_t)CO_RX_CNT_LSS_SLV) +#define CO_CNT_ALL_RX_MSGS (CO_RX_IDX_LSS_MST + (uint16_t)CO_RX_CNT_LSS_MST) + +#define CO_TX_IDX_NMT_MST 0U +#define CO_TX_IDX_GFC (CO_TX_IDX_NMT_MST + (uint16_t)CO_TX_CNT_NMT_MST) +#define CO_TX_IDX_SYNC (CO_TX_IDX_GFC + (uint16_t)CO_TX_CNT_GFC) +#define CO_TX_IDX_EM_PROD (CO_TX_IDX_SYNC + (uint16_t)CO_TX_CNT_SYNC) +#define CO_TX_IDX_TIME (CO_TX_IDX_EM_PROD + (uint16_t)CO_TX_CNT_EM_PROD) +#define CO_TX_IDX_SRDO (CO_TX_IDX_TIME + (uint16_t)CO_TX_CNT_TIME) +#define CO_TX_IDX_TPDO (CO_TX_IDX_SRDO + ((uint16_t)CO_TX_CNT_SRDO * 2U)) +#define CO_TX_IDX_SDO_SRV (CO_TX_IDX_TPDO + (uint16_t)CO_TX_CNT_TPDO) +#define CO_TX_IDX_SDO_CLI (CO_TX_IDX_SDO_SRV + (uint16_t)CO_TX_CNT_SDO_SRV) +#define CO_TX_IDX_HB_PROD (CO_TX_IDX_SDO_CLI + (uint16_t)CO_TX_CNT_SDO_CLI) +#define CO_TX_IDX_NG_SLV (CO_TX_IDX_HB_PROD + (uint16_t)CO_TX_CNT_HB_PROD) +#define CO_TX_IDX_NG_MST (CO_TX_IDX_NG_SLV + (uint16_t)CO_TX_CNT_NG_SLV) +#define CO_TX_IDX_LSS_SLV (CO_TX_IDX_NG_MST + (uint16_t)CO_TX_CNT_NG_MST) +#define CO_TX_IDX_LSS_MST (CO_TX_IDX_LSS_SLV + (uint16_t)CO_TX_CNT_LSS_SLV) +#define CO_CNT_ALL_TX_MSGS (CO_TX_IDX_LSS_MST + (uint16_t)CO_TX_CNT_LSS_MST) #endif /* #ifdef #else CO_MULTIPLE_OD */ - /* Objects from heap **********************************************************/ #ifndef CO_USE_GLOBALS #include @@ -320,15 +319,21 @@ * Allocate memory for number of elements, each of specific size * Allocated memory must be reset to all zeros */ -#define CO_alloc(num, size) calloc((num), (size)) -#define CO_free(ptr) free((ptr)) +#define CO_alloc(num, size) calloc((num), (size)) +#define CO_free(ptr) free((ptr)) #endif /* Define macros for allocation */ -#define CO_alloc_break_on_fail(var, num, size) { \ - var = CO_alloc((num), (size)); \ - if((var) != NULL) { mem += (size) * (num); } else { break; } } +#define CO_alloc_break_on_fail(var, num, size) \ + { \ + var = CO_alloc((num), (size)); \ + if ((var) != NULL) { \ + mem += (size) * (num); \ + } else { \ + break; \ + } \ + } #ifdef CO_MULTIPLE_OD #define ON_MULTI_OD(sentence) sentence @@ -336,10 +341,11 @@ #define ON_MULTI_OD(sentence) #endif -CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { - CO_t *co = NULL; +CO_t* +CO_new(CO_config_t* config, uint32_t* heapMemoryUsed) { + CO_t* co = NULL; /* return values */ - CO_t *coFinal = NULL; + CO_t* coFinal = NULL; uint32_t mem = 0; /* For each object: @@ -354,19 +360,14 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { do { #ifdef CO_MULTIPLE_OD /* verify arguments */ - if (config == NULL || config->CNT_NMT > 1 || config->CNT_HB_CONS > 1 - || config->CNT_EM > 1 || config->CNT_SDO_SRV > 128 - || config->CNT_SDO_CLI > 128 || config->CNT_SYNC > 1 - || config->CNT_RPDO > 512 || config->CNT_TPDO > 512 - || config->CNT_TIME > 1 || config->CNT_LEDS > 1 - || config->CNT_GFC > 1 || config->CNT_SRDO > 64 - || config->CNT_LSS_SLV > 1 || config->CNT_LSS_MST > 1 - || config->CNT_GTWA > 1 - ) { + if (config == NULL || config->CNT_NMT > 1 || config->CNT_HB_CONS > 1 || config->CNT_EM > 1 + || config->CNT_SDO_SRV > 128 || config->CNT_SDO_CLI > 128 || config->CNT_SYNC > 1 || config->CNT_RPDO > 512 + || config->CNT_TPDO > 512 || config->CNT_TIME > 1 || config->CNT_LEDS > 1 || config->CNT_GFC > 1 + || config->CNT_SRDO > 64 || config->CNT_LSS_SLV > 1 || config->CNT_LSS_MST > 1 || config->CNT_GTWA > 1) { break; } #else - (void) config; + (void)config; #endif /* CANopen object */ @@ -383,13 +384,13 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { if (CO_GET_CNT(NMT) == 1U) { CO_alloc_break_on_fail(co->NMT, CO_GET_CNT(NMT), sizeof(*co->NMT)); ON_MULTI_OD(RX_CNT_NMT_SLV = 1); - #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0 ON_MULTI_OD(TX_CNT_NMT_MST = 1); - #endif +#endif ON_MULTI_OD(TX_CNT_HB_PROD = 1); } -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_HB_CONS = 0); if (CO_GET_CNT(HB_CONS) == 1U) { uint8_t countOfMonitoredNodes = CO_GET_CNT(ARR_1016); @@ -400,10 +401,10 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { #endif /* Node guarding */ -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 CO_alloc_break_on_fail(co->NGslave, 1, sizeof(*co->NGslave)); #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 CO_alloc_break_on_fail(co->NGmaster, 1, sizeof(*co->NGmaster)); #endif @@ -412,18 +413,18 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(uint8_t TX_CNT_EM_PROD = 0); if (CO_GET_CNT(EM) == 1U) { CO_alloc_break_on_fail(co->em, CO_GET_CNT(EM), sizeof(*co->em)); - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 ON_MULTI_OD(RX_CNT_EM_CONS = 1); - #endif - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 +#endif +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 ON_MULTI_OD(TX_CNT_EM_PROD = 1); - #endif - #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 +#endif +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 uint8_t fifoSize = CO_GET_CNT(ARR_1003) + 1U; if (fifoSize >= 2U) { CO_alloc_break_on_fail(co->em_fifo, fifoSize, sizeof(*co->em_fifo)); } - #endif +#endif } /* SDOserver */ @@ -435,7 +436,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { ON_MULTI_OD(TX_CNT_SDO_SRV = config->CNT_SDO_SRV); } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SDO_CLI = 0); ON_MULTI_OD(uint8_t TX_CNT_SDO_CLI = 0); if (CO_GET_CNT(SDO_CLI) > 0U) { @@ -445,31 +446,31 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_TIME = 0); ON_MULTI_OD(uint8_t TX_CNT_TIME = 0); if (CO_GET_CNT(TIME) == 1U) { CO_alloc_break_on_fail(co->TIME, CO_GET_CNT(TIME), sizeof(*co->TIME)); ON_MULTI_OD(RX_CNT_TIME = 1); - #if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 ON_MULTI_OD(TX_CNT_TIME = 1); - #endif +#endif } #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SYNC = 0); ON_MULTI_OD(uint8_t TX_CNT_SYNC = 0); if (CO_GET_CNT(SYNC) == 1U) { CO_alloc_break_on_fail(co->SYNC, CO_GET_CNT(SYNC), sizeof(*co->SYNC)); ON_MULTI_OD(RX_CNT_SYNC = 1); - #if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 ON_MULTI_OD(TX_CNT_SYNC = 1); - #endif +#endif } #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 ON_MULTI_OD(uint16_t RX_CNT_RPDO = 0); if (CO_GET_CNT(RPDO) > 0U) { CO_alloc_break_on_fail(co->RPDO, CO_GET_CNT(RPDO), sizeof(*co->RPDO)); @@ -477,7 +478,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 ON_MULTI_OD(uint16_t TX_CNT_TPDO = 0); if (CO_GET_CNT(TPDO) > 0U) { CO_alloc_break_on_fail(co->TPDO, CO_GET_CNT(TPDO), sizeof(*co->TPDO)); @@ -485,13 +486,13 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 +#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 if (CO_GET_CNT(LEDS) == 1U) { CO_alloc_break_on_fail(co->LEDs, CO_GET_CNT(LEDS), sizeof(*co->LEDs)); } #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_GFC = 0); ON_MULTI_OD(uint8_t TX_CNT_GFC = 0); if (CO_GET_CNT(GFC) == 1) { @@ -501,7 +502,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 ON_MULTI_OD(uint8_t RX_CNT_SRDO = 0); ON_MULTI_OD(uint8_t TX_CNT_SRDO = 0); if (CO_GET_CNT(SRDO) > 0U) { @@ -512,7 +513,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 ON_MULTI_OD(uint8_t RX_CNT_LSS_SLV = 0); ON_MULTI_OD(uint8_t TX_CNT_LSS_SLV = 0); if (CO_GET_CNT(LSS_SLV) == 1U) { @@ -522,7 +523,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 ON_MULTI_OD(uint8_t RX_CNT_LSS_MST = 0); ON_MULTI_OD(uint8_t TX_CNT_LSS_MST = 0); if (CO_GET_CNT(LSS_MST) == 1U) { @@ -532,7 +533,7 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { } #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0 if (CO_GET_CNT(GTWA) == 1U) { CO_alloc_break_on_fail(co->gtwa, CO_GET_CNT(GTWA), sizeof(*co->gtwa)); } @@ -549,78 +550,106 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { * total number of them. Indexes are sorted in a way, that objects with * highest priority of the CAN identifier are listed first. */ int16_t idxRx = 0; - co->RX_IDX_NMT_SLV = idxRx; idxRx += RX_CNT_NMT_SLV; -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 - co->RX_IDX_GFC = idxRx; idxRx += RX_CNT_GFC; -#endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 - co->RX_IDX_SYNC = idxRx; idxRx += RX_CNT_SYNC; -#endif - co->RX_IDX_EM_CONS = idxRx; idxRx += RX_CNT_EM_CONS; -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 - co->RX_IDX_TIME = idxRx; idxRx += RX_CNT_TIME; -#endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 - co->RX_IDX_SRDO = idxRx; idxRx += RX_CNT_SRDO * 2; -#endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 - co->RX_IDX_RPDO = idxRx; idxRx += RX_CNT_RPDO; -#endif - co->RX_IDX_SDO_SRV = idxRx; idxRx += RX_CNT_SDO_SRV; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 - co->RX_IDX_SDO_CLI = idxRx; idxRx += RX_CNT_SDO_CLI; -#endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 - co->RX_IDX_HB_CONS = idxRx; idxRx += RX_CNT_HB_CONS; -#endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 - co->RX_IDX_NG_SLV = idxRx; idxRx += 1; -#endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 - co->RX_IDX_NG_MST = idxRx; idxRx += 1; -#endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 - co->RX_IDX_LSS_SLV = idxRx; idxRx += RX_CNT_LSS_SLV; -#endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 - co->RX_IDX_LSS_MST = idxRx; idxRx += RX_CNT_LSS_MST; + co->RX_IDX_NMT_SLV = idxRx; + idxRx += RX_CNT_NMT_SLV; +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 + co->RX_IDX_GFC = idxRx; + idxRx += RX_CNT_GFC; +#endif +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 + co->RX_IDX_SYNC = idxRx; + idxRx += RX_CNT_SYNC; +#endif + co->RX_IDX_EM_CONS = idxRx; + idxRx += RX_CNT_EM_CONS; +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 + co->RX_IDX_TIME = idxRx; + idxRx += RX_CNT_TIME; +#endif +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 + co->RX_IDX_SRDO = idxRx; + idxRx += RX_CNT_SRDO * 2; +#endif +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 + co->RX_IDX_RPDO = idxRx; + idxRx += RX_CNT_RPDO; +#endif + co->RX_IDX_SDO_SRV = idxRx; + idxRx += RX_CNT_SDO_SRV; +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 + co->RX_IDX_SDO_CLI = idxRx; + idxRx += RX_CNT_SDO_CLI; +#endif +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 + co->RX_IDX_HB_CONS = idxRx; + idxRx += RX_CNT_HB_CONS; +#endif +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 + co->RX_IDX_NG_SLV = idxRx; + idxRx += 1; +#endif +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 + co->RX_IDX_NG_MST = idxRx; + idxRx += 1; +#endif +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 + co->RX_IDX_LSS_SLV = idxRx; + idxRx += RX_CNT_LSS_SLV; +#endif +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 + co->RX_IDX_LSS_MST = idxRx; + idxRx += RX_CNT_LSS_MST; #endif co->CNT_ALL_RX_MSGS = idxRx; int16_t idxTx = 0; - co->TX_IDX_NMT_MST = idxTx; idxTx += TX_CNT_NMT_MST; -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 - co->TX_IDX_GFC = idxTx; idxTx += TX_CNT_GFC; -#endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 - co->TX_IDX_SYNC = idxTx; idxTx += TX_CNT_SYNC; -#endif - co->TX_IDX_EM_PROD = idxTx; idxTx += TX_CNT_EM_PROD; -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 - co->TX_IDX_TIME = idxTx; idxTx += TX_CNT_TIME; -#endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 - co->TX_IDX_SRDO = idxTx; idxTx += TX_CNT_SRDO * 2; -#endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 - co->TX_IDX_TPDO = idxTx; idxTx += TX_CNT_TPDO; -#endif - co->TX_IDX_SDO_SRV = idxTx; idxTx += TX_CNT_SDO_SRV; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 - co->TX_IDX_SDO_CLI = idxTx; idxTx += TX_CNT_SDO_CLI; -#endif - co->TX_IDX_HB_PROD = idxTx; idxTx += TX_CNT_HB_PROD; -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 - co->TX_IDX_NG_SLV = idxTx; idxTx += 1; -#endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 - co->TX_IDX_NG_MST = idxTx; idxTx += 1; -#endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 - co->TX_IDX_LSS_SLV = idxTx; idxTx += TX_CNT_LSS_SLV; -#endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 - co->TX_IDX_LSS_MST = idxTx; idxTx += TX_CNT_LSS_MST; + co->TX_IDX_NMT_MST = idxTx; + idxTx += TX_CNT_NMT_MST; +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 + co->TX_IDX_GFC = idxTx; + idxTx += TX_CNT_GFC; +#endif +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 + co->TX_IDX_SYNC = idxTx; + idxTx += TX_CNT_SYNC; +#endif + co->TX_IDX_EM_PROD = idxTx; + idxTx += TX_CNT_EM_PROD; +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 + co->TX_IDX_TIME = idxTx; + idxTx += TX_CNT_TIME; +#endif +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 + co->TX_IDX_SRDO = idxTx; + idxTx += TX_CNT_SRDO * 2; +#endif +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 + co->TX_IDX_TPDO = idxTx; + idxTx += TX_CNT_TPDO; +#endif + co->TX_IDX_SDO_SRV = idxTx; + idxTx += TX_CNT_SDO_SRV; +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 + co->TX_IDX_SDO_CLI = idxTx; + idxTx += TX_CNT_SDO_CLI; +#endif + co->TX_IDX_HB_PROD = idxTx; + idxTx += TX_CNT_HB_PROD; +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 + co->TX_IDX_NG_SLV = idxTx; + idxTx += 1; +#endif +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 + co->TX_IDX_NG_MST = idxTx; + idxTx += 1; +#endif +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 + co->TX_IDX_LSS_SLV = idxTx; + idxTx += TX_CNT_LSS_SLV; +#endif +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 + co->TX_IDX_LSS_MST = idxTx; + idxTx += TX_CNT_LSS_MST; #endif co->CNT_ALL_TX_MSGS = idxTx; #endif /* #ifdef CO_MULTIPLE_OD */ @@ -648,7 +677,8 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { return coFinal; } -void CO_delete(CO_t *co) { +void +CO_delete(CO_t* co) { if (co == NULL) { return; } @@ -664,48 +694,48 @@ void CO_delete(CO_t *co) { CO_free(co->trace); #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0 CO_free(co->gtwa); #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 CO_free(co->LSSmaster); #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 CO_free(co->LSSslave); #endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 CO_free(co->SRDO); CO_free(co->SRDOGuard); #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 CO_free(co->GFC); #endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 +#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 CO_free(co->LEDs); #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 CO_free(co->TPDO); #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 CO_free(co->RPDO); #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 CO_free(co->SYNC); #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 CO_free(co->TIME); #endif -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 free(co->SDOclient); #endif @@ -718,15 +748,14 @@ void CO_delete(CO_t *co) { CO_free(co->em_fifo); #endif - -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 CO_free(co->NGslave); #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 CO_free(co->NGmaster); #endif -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 CO_free(co->HBconsMonitoredNodes); CO_free(co->HBcons); #endif @@ -739,93 +768,94 @@ void CO_delete(CO_t *co) { } #endif /* #ifndef CO_USE_GLOBALS */ - /* Objects as globals *********************************************************/ #ifdef CO_USE_GLOBALS - #ifdef CO_MULTIPLE_OD - #error CO_MULTIPLE_OD can not be used with CO_USE_GLOBALS - #endif - static CO_t COO; - static CO_CANmodule_t COO_CANmodule; - static CO_CANrx_t COO_CANmodule_rxArray[CO_CNT_ALL_RX_MSGS]; - static CO_CANtx_t COO_CANmodule_txArray[CO_CNT_ALL_TX_MSGS]; - static CO_NMT_t COO_NMT; -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 - static CO_HBconsumer_t COO_HBcons; - static CO_HBconsNode_t COO_HBconsMonitoredNodes[OD_CNT_ARR_1016]; -#endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 - static CO_nodeGuardingSlave_t COO_NGslave; -#endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 - static CO_nodeGuardingMaster_t COO_NGmaster; -#endif - static CO_EM_t COO_EM; +#ifdef CO_MULTIPLE_OD +#error CO_MULTIPLE_OD can not be used with CO_USE_GLOBALS +#endif +static CO_t COO; +static CO_CANmodule_t COO_CANmodule; +static CO_CANrx_t COO_CANmodule_rxArray[CO_CNT_ALL_RX_MSGS]; +static CO_CANtx_t COO_CANmodule_txArray[CO_CNT_ALL_TX_MSGS]; +static CO_NMT_t COO_NMT; +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 +static CO_HBconsumer_t COO_HBcons; +static CO_HBconsNode_t COO_HBconsMonitoredNodes[OD_CNT_ARR_1016]; +#endif +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 +static CO_nodeGuardingSlave_t COO_NGslave; +#endif +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 +static CO_nodeGuardingMaster_t COO_NGmaster; +#endif +static CO_EM_t COO_EM; #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 - static CO_EM_fifo_t COO_EM_FIFO[CO_GET_CNT(ARR_1003) + 1U]; +static CO_EM_fifo_t COO_EM_FIFO[CO_GET_CNT(ARR_1003) + 1U]; #endif - static CO_SDOserver_t COO_SDOserver[OD_CNT_SDO_SRV]; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 - static CO_SDOclient_t COO_SDOclient[OD_CNT_SDO_CLI]; +static CO_SDOserver_t COO_SDOserver[OD_CNT_SDO_SRV]; +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 +static CO_SDOclient_t COO_SDOclient[OD_CNT_SDO_CLI]; #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 - static CO_TIME_t COO_TIME; +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 +static CO_TIME_t COO_TIME; #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 - static CO_SYNC_t COO_SYNC; +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 +static CO_SYNC_t COO_SYNC; #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 - static CO_RPDO_t COO_RPDO[OD_CNT_RPDO]; +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 +static CO_RPDO_t COO_RPDO[OD_CNT_RPDO]; #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 - static CO_TPDO_t COO_TPDO[OD_CNT_TPDO]; +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 +static CO_TPDO_t COO_TPDO[OD_CNT_TPDO]; #endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 - static CO_LEDs_t COO_LEDs; +#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 +static CO_LEDs_t COO_LEDs; #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 - static CO_GFC_t COO_GFC; +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 +static CO_GFC_t COO_GFC; #endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 - static CO_SRDOGuard_t COO_SRDOGuard; - static CO_SRDO_t COO_SRDO[OD_CNT_SRDO]; +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 +static CO_SRDOGuard_t COO_SRDOGuard; +static CO_SRDO_t COO_SRDO[OD_CNT_SRDO]; #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 - static CO_LSSslave_t COO_LSSslave; +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 +static CO_LSSslave_t COO_LSSslave; #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 - static CO_LSSmaster_t COO_LSSmaster; +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 +static CO_LSSmaster_t COO_LSSmaster; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 - static CO_GTWA_t COO_gtwa; +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0 +static CO_GTWA_t COO_gtwa; #endif -#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) != 0 - #ifndef CO_TRACE_BUFFER_SIZE_FIXED - #define CO_TRACE_BUFFER_SIZE_FIXED 100 - #endif - static CO_trace_t COO_trace[OD_CNT_TRACE]; - static uint32_t COO_traceTimeBuffers[OD_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; - static int32_t COO_traceValueBuffers[OD_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; +#if ((CO_CONFIG_TRACE)&CO_CONFIG_TRACE_ENABLE) != 0 +#ifndef CO_TRACE_BUFFER_SIZE_FIXED +#define CO_TRACE_BUFFER_SIZE_FIXED 100 +#endif +static CO_trace_t COO_trace[OD_CNT_TRACE]; +static uint32_t COO_traceTimeBuffers[OD_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; +static int32_t COO_traceValueBuffers[OD_CNT_TRACE][CO_TRACE_BUFFER_SIZE_FIXED]; #endif -CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { - (void)config; (void)heapMemoryUsed; +CO_t* +CO_new(CO_config_t* config, uint32_t* heapMemoryUsed) { + (void)config; + (void)heapMemoryUsed; - CO_t *co = &COO; + CO_t* co = &COO; co->CANmodule = &COO_CANmodule; co->CANrx = &COO_CANmodule_rxArray[0]; co->CANtx = &COO_CANmodule_txArray[0]; co->NMT = &COO_NMT; -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 co->HBcons = &COO_HBcons; co->HBconsMonitoredNodes = &COO_HBconsMonitoredNodes[0]; #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 co->NGslave = &COO_NGslave; #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 co->NGmaster = &COO_NGmaster; #endif co->em = &COO_EM; @@ -833,41 +863,41 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { co->em_fifo = &COO_EM_FIFO[0]; #endif co->SDOserver = &COO_SDOserver[0]; -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 co->SDOclient = &COO_SDOclient[0]; #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 co->TIME = &COO_TIME; #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 co->SYNC = &COO_SYNC; #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 co->RPDO = &COO_RPDO[0]; #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 co->TPDO = &COO_TPDO[0]; #endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 +#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 co->LEDs = &COO_LEDs; #endif -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 co->GFC = &COO_GFC; #endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 co->SRDOGuard = &COO_SRDOGuard; co->SRDO = &COO_SRDO[0]; #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 co->LSSslave = &COO_LSSslave; #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 co->LSSmaster = &COO_LSSmaster; #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0 co->gtwa = &COO_gtwa; #endif -#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) != 0 +#if ((CO_CONFIG_TRACE)&CO_CONFIG_TRACE_ENABLE) != 0 co->trace = &COO_trace[0]; co->traceTimeBuffers = &COO_traceTimeBuffers[0][0]; co->traceValueBuffers = &COO_traceValueBuffers[0][0]; @@ -877,7 +907,8 @@ CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed) { return co; } -void CO_delete(CO_t *co) { +void +CO_delete(CO_t* co) { if (co == NULL) { return; } @@ -887,44 +918,41 @@ void CO_delete(CO_t *co) { #endif /* #ifdef CO_USE_GLOBALS */ /* Helper functions ***********************************************************/ -bool_t CO_isLSSslaveEnabled(CO_t *co) { - (void) co; /* may be unused */ +bool_t +CO_isLSSslaveEnabled(CO_t* co) { + (void)co; /* may be unused */ bool_t en = false; -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 - if (CO_GET_CNT(LSS_SLV) == 1U) { en = true; } +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 + if (CO_GET_CNT(LSS_SLV) == 1U) { + en = true; + } #endif return en; } /******************************************************************************/ -CO_ReturnError_t CO_CANinit(CO_t *co, void *CANptr, uint16_t bitRate) { +CO_ReturnError_t +CO_CANinit(CO_t* co, void* CANptr, uint16_t bitRate) { CO_ReturnError_t err; - if (co == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } + if (co == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } co->CANmodule->CANnormal = false; CO_CANsetConfigurationMode(CANptr); /* CANmodule */ - err = CO_CANmodule_init(co->CANmodule, - CANptr, - co->CANrx, - CO_GET_CO(CNT_ALL_RX_MSGS), - co->CANtx, - CO_GET_CO(CNT_ALL_TX_MSGS), - bitRate); + err = CO_CANmodule_init(co->CANmodule, CANptr, co->CANrx, CO_GET_CO(CNT_ALL_RX_MSGS), co->CANtx, + CO_GET_CO(CNT_ALL_TX_MSGS), bitRate); return err; } - /******************************************************************************/ -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 -CO_ReturnError_t CO_LSSinit(CO_t *co, - CO_LSS_address_t *lssAddress, - uint8_t *pendingNodeID, - uint16_t *pendingBitRate) -{ +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 +CO_ReturnError_t +CO_LSSinit(CO_t* co, CO_LSS_address_t* lssAddress, uint8_t* pendingNodeID, uint16_t* pendingBitRate) { CO_ReturnError_t err; if ((co == NULL) || (CO_GET_CNT(LSS_SLV) != 1U)) { @@ -932,47 +960,28 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, } /* LSSslave */ - err = CO_LSSslave_init(co->LSSslave, - lssAddress, - pendingBitRate, - pendingNodeID, - co->CANmodule, - CO_GET_CO(RX_IDX_LSS_SLV), - CO_CAN_ID_LSS_MST, - co->CANmodule, - CO_GET_CO(TX_IDX_LSS_SLV), + err = CO_LSSslave_init(co->LSSslave, lssAddress, pendingBitRate, pendingNodeID, co->CANmodule, + CO_GET_CO(RX_IDX_LSS_SLV), CO_CAN_ID_LSS_MST, co->CANmodule, CO_GET_CO(TX_IDX_LSS_SLV), CO_CAN_ID_LSS_SLV); return err; } #endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE */ - /******************************************************************************/ -CO_ReturnError_t CO_CANopenInit(CO_t *co, - CO_NMT_t *NMT, - CO_EM_t *em, - OD_t *od, - OD_entry_t *OD_statusBits, - uint16_t NMTcontrol, - uint16_t firstHBTime_ms, - uint16_t SDOserverTimeoutTime_ms, - uint16_t SDOclientTimeoutTime_ms, - bool_t SDOclientBlockTransfer, - uint8_t nodeId, - uint32_t *errInfo) -{ - (void)SDOclientTimeoutTime_ms; (void)SDOclientBlockTransfer; +CO_ReturnError_t +CO_CANopenInit(CO_t* co, CO_NMT_t* NMT, CO_EM_t* em, OD_t* od, OD_entry_t* OD_statusBits, uint16_t NMTcontrol, + uint16_t firstHBTime_ms, uint16_t SDOserverTimeoutTime_ms, uint16_t SDOclientTimeoutTime_ms, + bool_t SDOclientBlockTransfer, uint8_t nodeId, uint32_t* errInfo) { + (void)SDOclientTimeoutTime_ms; + (void)SDOclientBlockTransfer; CO_ReturnError_t err; - - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) == 0 - (void)OD_statusBits; /* may be unused */ - #endif - - if ((co == NULL) - || ((CO_GET_CNT(NMT) == 0U) && (NMT == NULL)) - || ((CO_GET_CNT(EM) == 0U) && (em == NULL)) - ) { + +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) == 0 + (void)OD_statusBits; /* may be unused */ +#endif + + if ((co == NULL) || ((CO_GET_CNT(NMT) == 0U) && (NMT == NULL)) || ((CO_GET_CNT(EM) == 0U) && (em == NULL))) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -986,21 +995,22 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, /* Verify CANopen Node-ID */ co->nodeIdUnconfigured = false; -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 if ((CO_GET_CNT(LSS_SLV) == 1U) && (nodeId == CO_LSS_NODE_ID_ASSIGNMENT)) { co->nodeIdUnconfigured = true; - } - else + } else #endif - if ((nodeId < 1U) || (nodeId > 127U)) { + if ((nodeId < 1U) || (nodeId > 127U)) { return CO_ERROR_ILLEGAL_ARGUMENT; + } else { /* MISRA C 2004 14.10 */ } - else { /* MISRA C 2004 14.10 */ } -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 +#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 if (CO_GET_CNT(LEDS) == 1U) { err = CO_LEDs_init(co->LEDs); - if (err != CO_ERROR_NO) { return err; } + if (err != CO_ERROR_NO) { + return err; + } } #endif @@ -1011,223 +1021,172 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, /* Emergency */ if (CO_GET_CNT(EM) == 1U) { - err = CO_EM_init(co->em, - co->CANmodule, - OD_GET(H1001, OD_H1001_ERR_REG), - #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 - co->em_fifo, - (CO_GET_CNT(ARR_1003) + 1U), - #endif - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0 - OD_GET(H1014, OD_H1014_COBID_EMERGENCY), - CO_GET_CO(TX_IDX_EM_PROD), - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0 + err = CO_EM_init(co->em, co->CANmodule, OD_GET(H1001, OD_H1001_ERR_REG), +#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 + co->em_fifo, (CO_GET_CNT(ARR_1003) + 1U), +#endif +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 + OD_GET(H1014, OD_H1014_COBID_EMERGENCY), CO_GET_CO(TX_IDX_EM_PROD), +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0 OD_GET(H1015, OD_H1015_INHIBIT_TIME_EMCY), - #endif - #endif - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0 +#endif +#endif +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0 OD_GET(H1003, OD_H1003_PREDEF_ERR_FIELD), - #endif - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0 +#endif +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0 OD_statusBits, - #endif - #if ((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0 - co->CANmodule, - CO_GET_CO(RX_IDX_EM_CONS), - #endif - nodeId, - errInfo); - if (err != CO_ERROR_NO) { return err; } +#endif +#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 + co->CANmodule, CO_GET_CO(RX_IDX_EM_CONS), +#endif + nodeId, errInfo); + if (err != CO_ERROR_NO) { + return err; + } } /* NMT_Heartbeat */ if (CO_GET_CNT(NMT) == 1U) { - err = CO_NMT_init(co->NMT, - OD_GET(H1017, OD_H1017_PRODUCER_HB_TIME), - em, - nodeId, - NMTcontrol, - firstHBTime_ms, - co->CANmodule, - CO_GET_CO(RX_IDX_NMT_SLV), - CO_CAN_ID_NMT_SERVICE, - #if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0 - co->CANmodule, - CO_GET_CO(TX_IDX_NMT_MST), - CO_CAN_ID_NMT_SERVICE, - #endif - co->CANmodule, - CO_GET_CO(TX_IDX_HB_PROD), - CO_CAN_ID_HEARTBEAT + nodeId, - errInfo); - if (err != CO_ERROR_NO) { return err; } + err = CO_NMT_init(co->NMT, OD_GET(H1017, OD_H1017_PRODUCER_HB_TIME), em, nodeId, NMTcontrol, firstHBTime_ms, + co->CANmodule, CO_GET_CO(RX_IDX_NMT_SLV), CO_CAN_ID_NMT_SERVICE, +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0 + co->CANmodule, CO_GET_CO(TX_IDX_NMT_MST), CO_CAN_ID_NMT_SERVICE, +#endif + co->CANmodule, CO_GET_CO(TX_IDX_HB_PROD), CO_CAN_ID_HEARTBEAT + nodeId, errInfo); + if (err != CO_ERROR_NO) { + return err; + } } -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 if (CO_GET_CNT(HB_CONS) == 1U) { - err = CO_HBconsumer_init(co->HBcons, - em, - co->HBconsMonitoredNodes, - CO_GET_CNT(ARR_1016), - OD_GET(H1016, OD_H1016_CONSUMER_HB_TIME), - co->CANmodule, - CO_GET_CO(RX_IDX_HB_CONS), + err = CO_HBconsumer_init(co->HBcons, em, co->HBconsMonitoredNodes, CO_GET_CNT(ARR_1016), + OD_GET(H1016, OD_H1016_CONSUMER_HB_TIME), co->CANmodule, CO_GET_CO(RX_IDX_HB_CONS), errInfo); - if (err != CO_ERROR_NO) { return err; } + if (err != CO_ERROR_NO) { + return err; + } } #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 - err = CO_nodeGuardingSlave_init(co->NGslave, - OD_GET(H100C, OD_H100C_GUARD_TIME), - OD_GET(H100D, OD_H100D_LIFETIME_FACTOR), - em, - CO_CAN_ID_HEARTBEAT + nodeId, - co->CANmodule, - CO_GET_CO(RX_IDX_NG_SLV), - co->CANmodule, - CO_GET_CO(TX_IDX_NG_SLV), +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 + err = CO_nodeGuardingSlave_init(co->NGslave, OD_GET(H100C, OD_H100C_GUARD_TIME), + OD_GET(H100D, OD_H100D_LIFETIME_FACTOR), em, CO_CAN_ID_HEARTBEAT + nodeId, + co->CANmodule, CO_GET_CO(RX_IDX_NG_SLV), co->CANmodule, CO_GET_CO(TX_IDX_NG_SLV), errInfo); - if (err != CO_ERROR_NO) { return err; } -#endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 - err = CO_nodeGuardingMaster_init(co->NGmaster, - em, - co->CANmodule, - CO_GET_CO(RX_IDX_NG_MST), - co->CANmodule, + if (err != CO_ERROR_NO) { + return err; + } +#endif +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 + err = CO_nodeGuardingMaster_init(co->NGmaster, em, co->CANmodule, CO_GET_CO(RX_IDX_NG_MST), co->CANmodule, CO_GET_CO(TX_IDX_NG_MST)); - if (err) { return err; } + if (err) { + return err; + } #endif /* SDOserver */ if (CO_GET_CNT(SDO_SRV) > 0U) { - OD_entry_t *SDOsrvPar = OD_GET(H1200, OD_H1200_SDO_SERVER_1_PARAM); + OD_entry_t* SDOsrvPar = OD_GET(H1200, OD_H1200_SDO_SERVER_1_PARAM); for (uint16_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { - err = CO_SDOserver_init(&co->SDOserver[i], - od, - SDOsrvPar, - nodeId, - SDOserverTimeoutTime_ms, - co->CANmodule, - CO_GET_CO(RX_IDX_SDO_SRV) + i, - co->CANmodule, - CO_GET_CO(TX_IDX_SDO_SRV) + i, + err = CO_SDOserver_init(&co->SDOserver[i], od, SDOsrvPar, nodeId, SDOserverTimeoutTime_ms, co->CANmodule, + CO_GET_CO(RX_IDX_SDO_SRV) + i, co->CANmodule, CO_GET_CO(TX_IDX_SDO_SRV) + i, errInfo); - if (err != CO_ERROR_NO) { return err; } + if (err != CO_ERROR_NO) { + return err; + } SDOsrvPar++; } } -#if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0 +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 if (CO_GET_CNT(SDO_CLI) > 0U) { - OD_entry_t *SDOcliPar = OD_GET(H1280, OD_H1280_SDO_CLIENT_1_PARAM); + OD_entry_t* SDOcliPar = OD_GET(H1280, OD_H1280_SDO_CLIENT_1_PARAM); for (uint16_t i = 0; i < CO_GET_CNT(SDO_CLI); i++) { - err = CO_SDOclient_init(&co->SDOclient[i], - od, - SDOcliPar, - nodeId, - co->CANmodule, - CO_GET_CO(RX_IDX_SDO_CLI) + i, - co->CANmodule, - CO_GET_CO(TX_IDX_SDO_CLI) + i, + err = CO_SDOclient_init(&co->SDOclient[i], od, SDOcliPar, nodeId, co->CANmodule, + CO_GET_CO(RX_IDX_SDO_CLI) + i, co->CANmodule, CO_GET_CO(TX_IDX_SDO_CLI) + i, errInfo); SDOcliPar++; - if (err != CO_ERROR_NO) { return err; } + if (err != CO_ERROR_NO) { + return err; + } } } #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 if (CO_GET_CNT(TIME) == 1U) { - err = CO_TIME_init(co->TIME, - OD_GET(H1012, OD_H1012_COBID_TIME), - co->CANmodule, - CO_GET_CO(RX_IDX_TIME), -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 - co->CANmodule, - CO_GET_CO(TX_IDX_TIME), + err = CO_TIME_init(co->TIME, OD_GET(H1012, OD_H1012_COBID_TIME), co->CANmodule, CO_GET_CO(RX_IDX_TIME), +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 + co->CANmodule, CO_GET_CO(TX_IDX_TIME), #endif errInfo); - if (err != CO_ERROR_NO) { return err; } + if (err != CO_ERROR_NO) { + return err; + } } #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 if (CO_GET_CNT(SYNC) == 1U) { - err = CO_SYNC_init(co->SYNC, - em, - OD_GET(H1005, OD_H1005_COBID_SYNC), - OD_GET(H1006, OD_H1006_COMM_CYCL_PERIOD), - OD_GET(H1007, OD_H1007_SYNC_WINDOW_LEN), - OD_GET(H1019, OD_H1019_SYNC_CNT_OVERFLOW), - co->CANmodule, - CO_GET_CO(RX_IDX_SYNC), -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0 - co->CANmodule, - CO_GET_CO(TX_IDX_SYNC), + err = CO_SYNC_init(co->SYNC, em, OD_GET(H1005, OD_H1005_COBID_SYNC), OD_GET(H1006, OD_H1006_COMM_CYCL_PERIOD), + OD_GET(H1007, OD_H1007_SYNC_WINDOW_LEN), OD_GET(H1019, OD_H1019_SYNC_CNT_OVERFLOW), + co->CANmodule, CO_GET_CO(RX_IDX_SYNC), +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 + co->CANmodule, CO_GET_CO(TX_IDX_SYNC), #endif errInfo); - if (err != CO_ERROR_NO) { return err; } + if (err != CO_ERROR_NO) { + return err; + } } #endif -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0 if (CO_GET_CNT(LSS_MST) == 1U) { - err = CO_LSSmaster_init(co->LSSmaster, - CO_LSSmaster_DEFAULT_TIMEOUT, - co->CANmodule, - CO_GET_CO(RX_IDX_LSS_MST), - CO_CAN_ID_LSS_SLV, - co->CANmodule, - CO_GET_CO(TX_IDX_LSS_MST), - CO_CAN_ID_LSS_MST); - if (err != CO_ERROR_NO) { return err; } + err = CO_LSSmaster_init(co->LSSmaster, CO_LSSmaster_DEFAULT_TIMEOUT, co->CANmodule, CO_GET_CO(RX_IDX_LSS_MST), + CO_CAN_ID_LSS_SLV, co->CANmodule, CO_GET_CO(TX_IDX_LSS_MST), CO_CAN_ID_LSS_MST); + if (err != CO_ERROR_NO) { + return err; + } } #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0 if (CO_GET_CNT(GTWA) == 1U) { err = CO_GTWA_init(co->gtwa, - #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0 - &co->SDOclient[0], - SDOclientTimeoutTime_ms, - SDOclientBlockTransfer, - #endif - #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0 + &co->SDOclient[0], SDOclientTimeoutTime_ms, SDOclientBlockTransfer, +#endif +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0 co->NMT, - #endif - #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0 +#endif +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0 co->LSSmaster, - #endif - #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 +#endif +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0 co->LEDs, - #endif +#endif 0); - if (err != CO_ERROR_NO) { return err; } + if (err != CO_ERROR_NO) { + return err; + } } #endif #if (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE if (CO_GET_CNT(TRACE) > 0) { for (uint16_t i = 0; i < CO_GET_CNT(TRACE); i++) { - err = CO_trace_init(co->trace[i], - co->SDO[0], - OD_traceConfig[i].axisNo, - CO_traceTimeBuffers[i], - CO_traceValueBuffers[i], - CO_traceBufferSize[i], - &OD_traceConfig[i].map, - &OD_traceConfig[i].format, - &OD_traceConfig[i].trigger, - &OD_traceConfig[i].threshold, - &OD_trace[i].value, - &OD_trace[i].min, - &OD_trace[i].max, - &OD_trace[i].triggerTime, - OD_INDEX_TRACE_CONFIG + i, - OD_INDEX_TRACE + i); - if (err) { return err; } + err = CO_trace_init(co->trace[i], co->SDO[0], OD_traceConfig[i].axisNo, CO_traceTimeBuffers[i], + CO_traceValueBuffers[i], CO_traceBufferSize[i], &OD_traceConfig[i].map, + &OD_traceConfig[i].format, &OD_traceConfig[i].trigger, &OD_traceConfig[i].threshold, + &OD_trace[i].value, &OD_trace[i].min, &OD_trace[i].max, &OD_trace[i].triggerTime, + OD_INDEX_TRACE_CONFIG + i, OD_INDEX_TRACE + i); + if (err) { + return err; + } } } #endif @@ -1235,26 +1194,20 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, return CO_ERROR_NO; } - /******************************************************************************/ -CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, - CO_EM_t *em, - OD_t *od, - uint8_t nodeId, - uint32_t *errInfo) -{ +CO_ReturnError_t +CO_CANopenInitPDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo) { if (co == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } if ((nodeId < 1U) || (nodeId > 127U) || co->nodeIdUnconfigured) { - return (co->nodeIdUnconfigured) - ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; + return (co->nodeIdUnconfigured) ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; } -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 if (CO_GET_CNT(RPDO) > 0U) { - OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); - OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); + OD_entry_t* RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM); + OD_entry_t* RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING); for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { CO_ReturnError_t err; uint16_t preDefinedCanId = 0; @@ -1264,33 +1217,27 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, #else uint16_t pdoOffset = i % 4; uint16_t nodeIdOffset = i / 4; - preDefinedCanId = (CO_CAN_ID_RPDO_1 + pdoOffset * 0x100) - + nodeId + nodeIdOffset; + preDefinedCanId = (CO_CAN_ID_RPDO_1 + pdoOffset * 0x100) + nodeId + nodeIdOffset; #endif } - err = CO_RPDO_init(&co->RPDO[i], - od, - em, - #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 + err = CO_RPDO_init(&co->RPDO[i], od, em, +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 co->SYNC, - #endif - preDefinedCanId, - RPDOcomm, - RPDOmap, - co->CANmodule, - CO_GET_CO(RX_IDX_RPDO) + i, - errInfo); - if (err != CO_ERROR_NO) { return err; } +#endif + preDefinedCanId, RPDOcomm, RPDOmap, co->CANmodule, CO_GET_CO(RX_IDX_RPDO) + i, errInfo); + if (err != CO_ERROR_NO) { + return err; + } RPDOcomm++; RPDOmap++; } } #endif -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 if (CO_GET_CNT(TPDO) > 0U) { - OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); - OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); + OD_entry_t* TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM); + OD_entry_t* TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING); for (uint16_t i = 0; i < CO_GET_CNT(TPDO); i++) { CO_ReturnError_t err; uint16_t preDefinedCanId = 0; @@ -1300,23 +1247,17 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, #else uint16_t pdoOffset = i % 4; uint16_t nodeIdOffset = i / 4; - preDefinedCanId = (CO_CAN_ID_TPDO_1 + pdoOffset * 0x100) - + nodeId + nodeIdOffset; + preDefinedCanId = (CO_CAN_ID_TPDO_1 + pdoOffset * 0x100) + nodeId + nodeIdOffset; #endif } - err = CO_TPDO_init(&co->TPDO[i], - od, - em, - #if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 + err = CO_TPDO_init(&co->TPDO[i], od, em, +#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 co->SYNC, - #endif - preDefinedCanId, - TPDOcomm, - TPDOmap, - co->CANmodule, - CO_GET_CO(TX_IDX_TPDO) + i, - errInfo); - if (err != CO_ERROR_NO) { return err; } +#endif + preDefinedCanId, TPDOcomm, TPDOmap, co->CANmodule, CO_GET_CO(TX_IDX_TPDO) + i, errInfo); + if (err != CO_ERROR_NO) { + return err; + } TPDOcomm++; TPDOmap++; } @@ -1326,73 +1267,49 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, return CO_ERROR_NO; } - /******************************************************************************/ -#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) -CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, - CO_EM_t *em, - OD_t *od, - uint8_t nodeId, - uint32_t *errInfo) -{ +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) +CO_ReturnError_t +CO_CANopenInitSRDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo) { if (co == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } if ((nodeId < 1U) || (nodeId > 127U) || co->nodeIdUnconfigured) { - return (co->nodeIdUnconfigured) - ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; + return (co->nodeIdUnconfigured) ? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT; } - -#if ((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0 +#if ((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0 if (CO_GET_CNT(GFC) == 1) { CO_ReturnError_t err; - err = CO_GFC_init(co->GFC, - OD_GET(H1300, OD_H1300_GFC_PARAM), - co->CANmodule, - CO_GET_CO(RX_IDX_GFC), - CO_CAN_ID_GFC, - co->CANmodule, - CO_GET_CO(TX_IDX_GFC), - CO_CAN_ID_GFC); - if (err) { return err; } + err = CO_GFC_init(co->GFC, OD_GET(H1300, OD_H1300_GFC_PARAM), co->CANmodule, CO_GET_CO(RX_IDX_GFC), + CO_CAN_ID_GFC, co->CANmodule, CO_GET_CO(TX_IDX_GFC), CO_CAN_ID_GFC); + if (err) { + return err; + } } #endif -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 if (CO_GET_CNT(SRDO) > 0U) { CO_ReturnError_t err; - err = CO_SRDOGuard_init(co->SRDOGuard, - OD_GET(H13FE, OD_H13FE_SRDO_VALID), - OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), - errInfo); - if (err != CO_ERROR_NO) { return err; } + err = CO_SRDOGuard_init(co->SRDOGuard, OD_GET(H13FE, OD_H13FE_SRDO_VALID), + OD_GET(H13FF, OD_H13FF_SRDO_CHECKSUM), errInfo); + if (err != CO_ERROR_NO) { + return err; + } - OD_entry_t *SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); - OD_entry_t *SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); + OD_entry_t* SRDOcomm = OD_GET(H1301, OD_H1301_SRDO_1_PARAM); + OD_entry_t* SRDOmap = OD_GET(H1381, OD_H1381_SRDO_1_MAPPING); for (uint8_t i = 0; i < CO_GET_CNT(SRDO); i++) { - uint16_t CANdevRxIdx = (uint16_t)(CO_GET_CO(RX_IDX_SRDO) + ((uint16_t)(i) * 2U)); - uint16_t CANdevTxIdx = (uint16_t)(CO_GET_CO(TX_IDX_SRDO) + ((uint16_t)(i) * 2U)); - - err = CO_SRDO_init(&co->SRDO[i], - i, - co->SRDOGuard, - od, - em, - nodeId, - ((i == 0U) ? CO_CAN_ID_SRDO_1 : 0U), - SRDOcomm, - SRDOmap, - co->CANmodule, - co->CANmodule, - CANdevRxIdx, - CANdevRxIdx + 1U, - co->CANmodule, - co->CANmodule, - CANdevTxIdx, - CANdevTxIdx + 1U, - errInfo); - if (err != CO_ERROR_NO) { return err; } + uint16_t CANdevRxIdx = (uint16_t)(CO_GET_CO(RX_IDX_SRDO) + ((uint16_t)(i)*2U)); + uint16_t CANdevTxIdx = (uint16_t)(CO_GET_CO(TX_IDX_SRDO) + ((uint16_t)(i)*2U)); + + err = CO_SRDO_init(&co->SRDO[i], i, co->SRDOGuard, od, em, nodeId, ((i == 0U) ? CO_CAN_ID_SRDO_1 : 0U), + SRDOcomm, SRDOmap, co->CANmodule, co->CANmodule, CANdevRxIdx, CANdevRxIdx + 1U, + co->CANmodule, co->CANmodule, CANdevTxIdx, CANdevTxIdx + 1U, errInfo); + if (err != CO_ERROR_NO) { + return err; + } SRDOcomm++; SRDOmap++; } @@ -1404,21 +1321,17 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, #endif /******************************************************************************/ -CO_NMT_reset_cmd_t CO_process(CO_t *co, - bool_t enableGateway, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ - (void) enableGateway; /* may be unused */ +CO_NMT_reset_cmd_t +CO_process(CO_t* co, bool_t enableGateway, uint32_t timeDifference_us, uint32_t* timerNext_us) { + (void)enableGateway; /* may be unused */ CO_NMT_reset_cmd_t reset = CO_RESET_NOT; CO_NMT_internalState_t NMTstate = CO_NMT_getInternalState(co->NMT); - bool_t NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) - || (NMTstate == CO_NMT_OPERATIONAL)); + bool_t NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) || (NMTstate == CO_NMT_OPERATIONAL)); /* CAN module */ CO_CANmodule_process(co->CANmodule); -#if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) if (CO_GET_CNT(LSS_SLV) == 1U) { if (CO_LSSslave_process(co->LSSslave)) { reset = CO_RESET_COMM; @@ -1426,38 +1339,31 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, } #endif -#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 +#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 bool_t unc = co->nodeIdUnconfigured; uint16_t CANerrorStatus = co->CANmodule->CANerrorStatus; bool_t LSSslave_configuration = false; - #if ((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0 +#if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 if (CO_GET_CNT(LSS_SLV) == 1U) { if (CO_LSSslave_getState(co->LSSslave) == CO_LSS_STATE_CONFIGURATION) { LSSslave_configuration = true; } } - #endif - /* default macro, can be defined externally */ - #ifndef CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS - #define CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS false - #endif +#endif +/* default macro, can be defined externally */ +#ifndef CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS +#define CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS false +#endif if (CO_GET_CNT(LEDS) == 1U) { - bool_t ErrSync = CO_isError(co->em, CO_EM_SYNC_TIME_OUT); + bool_t ErrSync = CO_isError(co->em, CO_EM_SYNC_TIME_OUT); bool_t ErrHbCons = CO_isError(co->em, CO_EM_HEARTBEAT_CONSUMER); bool_t ErrHbConsRemote = CO_isError(co->em, CO_EM_HB_CONSUMER_REMOTE_RESET); - CO_LEDs_process(co->LEDs, - timeDifference_us, - unc ? CO_NMT_INITIALIZING : NMTstate, - LSSslave_configuration, - (CANerrorStatus & CO_CAN_ERRTX_BUS_OFF) != 0U, - (CANerrorStatus & CO_CAN_ERR_WARN_PASSIVE) != 0U, - false, /* RPDO event timer timeout */ - unc ? false : ErrSync, - unc ? false : (ErrHbCons || ErrHbConsRemote), - CO_getErrorRegister(co->em) != 0U, - CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS, - timerNext_us); + CO_LEDs_process(co->LEDs, timeDifference_us, unc ? CO_NMT_INITIALIZING : NMTstate, LSSslave_configuration, + (CANerrorStatus & CO_CAN_ERRTX_BUS_OFF) != 0U, (CANerrorStatus & CO_CAN_ERR_WARN_PASSIVE) != 0U, + false, /* RPDO event timer timeout */ + unc ? false : ErrSync, unc ? false : (ErrHbCons || ErrHbConsRemote), + CO_getErrorRegister(co->em) != 0U, CO_STATUS_FIRMWARE_DOWNLOAD_IN_PROGRESS, timerNext_us); } #endif @@ -1468,98 +1374,66 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, /* Emergency */ if (CO_GET_CNT(EM) == 1U) { - CO_EM_process(co->em, - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); + CO_EM_process(co->em, NMTisPreOrOperational, timeDifference_us, timerNext_us); } /* NMT_Heartbeat */ if (CO_GET_CNT(NMT) == 1U) { - reset = CO_NMT_process(co->NMT, - &NMTstate, - timeDifference_us, - timerNext_us); + reset = CO_NMT_process(co->NMT, &NMTstate, timeDifference_us, timerNext_us); } - NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) - || (NMTstate == CO_NMT_OPERATIONAL)); + NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) || (NMTstate == CO_NMT_OPERATIONAL)); /* SDOserver */ for (uint8_t i = 0; i < CO_GET_CNT(SDO_SRV); i++) { - (void)CO_SDOserver_process(&co->SDOserver[i], - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); + (void)CO_SDOserver_process(&co->SDOserver[i], NMTisPreOrOperational, timeDifference_us, timerNext_us); } -#if ((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0 +#if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 if (CO_GET_CNT(HB_CONS) == 1U) { - CO_HBconsumer_process(co->HBcons, - NMTisPreOrOperational, - timeDifference_us, - timerNext_us); + CO_HBconsumer_process(co->HBcons, NMTisPreOrOperational, timeDifference_us, timerNext_us); } #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 - CO_nodeGuardingSlave_process(co->NGslave, - NMTstate, - (co->NMT->HBproducerTime_us > 0U), - timeDifference_us, +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0 + CO_nodeGuardingSlave_process(co->NGslave, NMTstate, (co->NMT->HBproducerTime_us > 0U), timeDifference_us, timerNext_us); #endif -#if ((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 - CO_nodeGuardingMaster_process(co->NGmaster, - timeDifference_us, - timerNext_us); +#if ((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0 + CO_nodeGuardingMaster_process(co->NGmaster, timeDifference_us, timerNext_us); #endif -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0 +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 if (CO_GET_CNT(TIME) == 1U) { (void)CO_TIME_process(co->TIME, NMTisPreOrOperational, timeDifference_us); } #endif -#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0 +#if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0 if (CO_GET_CNT(GTWA) == 1U) { - CO_GTWA_process(co->gtwa, - enableGateway, - timeDifference_us, - timerNext_us); + CO_GTWA_process(co->gtwa, enableGateway, timeDifference_us, timerNext_us); } #endif return reset; } - /******************************************************************************/ -#if ((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0 -bool_t CO_process_SYNC(CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +#if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 +bool_t +CO_process_SYNC(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us) { bool_t syncWas = false; if ((!co->nodeIdUnconfigured) && (CO_GET_CNT(SYNC) == 1U)) { CO_NMT_internalState_t NMTstate = CO_NMT_getInternalState(co->NMT); - bool_t NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) - || (NMTstate == CO_NMT_OPERATIONAL)); + bool_t NMTisPreOrOperational = ((NMTstate == CO_NMT_PRE_OPERATIONAL) || (NMTstate == CO_NMT_OPERATIONAL)); - CO_SYNC_status_t sync_process = CO_SYNC_process(co->SYNC, - NMTisPreOrOperational, - timeDifference_us, + CO_SYNC_status_t sync_process = CO_SYNC_process(co->SYNC, NMTisPreOrOperational, timeDifference_us, timerNext_us); switch (sync_process) { - case CO_SYNC_NONE: - break; - case CO_SYNC_RX_TX: - syncWas = true; - break; - case CO_SYNC_PASSED_WINDOW: - CO_CANclearPendingSyncPDOs(co->CANmodule); - break; + case CO_SYNC_NONE: break; + case CO_SYNC_RX_TX: syncWas = true; break; + case CO_SYNC_PASSED_WINDOW: CO_CANclearPendingSyncPDOs(co->CANmodule); break; default: /* MISRA C 2004 15.3 */ break; @@ -1570,90 +1444,73 @@ bool_t CO_process_SYNC(CO_t *co, } #endif - /******************************************************************************/ -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 -void CO_process_RPDO(CO_t *co, - bool_t syncWas, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ - (void) timeDifference_us; (void) timerNext_us; +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 +void +CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us) { + (void)timeDifference_us; + (void)timerNext_us; if (co->nodeIdUnconfigured) { return; } - bool_t NMTisOperational = - CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; + bool_t NMTisOperational = CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { CO_RPDO_process(&co->RPDO[i], -#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 - timeDifference_us, - timerNext_us, +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 + timeDifference_us, timerNext_us, #endif - NMTisOperational, - syncWas); + NMTisOperational, syncWas); } } #endif - /******************************************************************************/ -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 -void CO_process_TPDO(CO_t *co, - bool_t syncWas, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ - (void) timeDifference_us; (void) timerNext_us; +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 +void +CO_process_TPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us) { + (void)timeDifference_us; + (void)timerNext_us; if (co->nodeIdUnconfigured) { return; } - bool_t NMTisOperational = - CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; + bool_t NMTisOperational = CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; for (uint16_t i = 0; i < CO_GET_CNT(TPDO); i++) { CO_TPDO_process(&co->TPDO[i], -#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 - timeDifference_us, - timerNext_us, +#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 + timeDifference_us, timerNext_us, #endif - NMTisOperational, - syncWas); + NMTisOperational, syncWas); } } #endif - /******************************************************************************/ -#if ((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0 -CO_SRDO_state_t CO_process_SRDO(CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us) -{ +#if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 +CO_SRDO_state_t +CO_process_SRDO(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us) { static bool_t NMTisOperationalPrevius = false; uint8_t i; CO_ReturnError_t err; - + if (co->nodeIdUnconfigured) { return CO_SRDO_state_unknown; } - bool_t NMTisOperational = - CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; - + bool_t NMTisOperational = CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; - if( NMTisOperationalPrevius != NMTisOperational ) { + if (NMTisOperationalPrevius != NMTisOperational) { NMTisOperationalPrevius = NMTisOperational; - if( NMTisOperational ) { + if (NMTisOperational) { for (i = 0; i < CO_GET_CNT(SRDO); i++) { - err = CO_SRDO_config( &co->SRDO[i], - i, - co->SRDOGuard, NULL ); - - if (err != CO_ERROR_NO) { return CO_SRDO_state_error_internal; } + err = CO_SRDO_config(&co->SRDO[i], i, co->SRDOGuard, NULL); + + if (err != CO_ERROR_NO) { + return CO_SRDO_state_error_internal; + } } } } @@ -1661,10 +1518,7 @@ CO_SRDO_state_t CO_process_SRDO(CO_t *co, CO_SRDO_state_t lowestState = CO_SRDO_state_deleted; for (i = 0; i < CO_GET_CNT(SRDO); i++) { - CO_SRDO_state_t state = CO_SRDO_process(&co->SRDO[i], - timeDifference_us, - timerNext_us, - NMTisOperational); + CO_SRDO_state_t state = CO_SRDO_process(&co->SRDO[i], timeDifference_us, timerNext_us, NMTisOperational); if (state < lowestState) { lowestState = state; } diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index dfa46e68..fef5822d 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -20,35 +20,27 @@ * See the License for the specific language governing permissions and limitations under the License. */ - #include "301/CO_driver.h" - -void CO_CANsetConfigurationMode(void *CANptr){ +void +CO_CANsetConfigurationMode(void* CANptr) { /* Put CAN module in configuration mode */ } - -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ +void +CO_CANsetNormalMode(CO_CANmodule_t* CANmodule) { /* Put CAN module in normal mode */ CANmodule->CANnormal = true; } - -CO_ReturnError_t CO_CANmodule_init( - CO_CANmodule_t *CANmodule, - void *CANptr, - CO_CANrx_t rxArray[], - uint16_t rxSize, - CO_CANtx_t txArray[], - uint16_t txSize, - uint16_t CANbitRate) -{ +CO_ReturnError_t +CO_CANmodule_init(CO_CANmodule_t* CANmodule, void* CANptr, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], + uint16_t txSize, uint16_t CANbitRate) { uint16_t i; /* verify arguments */ - if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ + if (CANmodule == NULL || rxArray == NULL || txArray == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -60,71 +52,58 @@ CO_ReturnError_t CO_CANmodule_init( CANmodule->txSize = txSize; CANmodule->CANerrorStatus = 0; CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = (rxSize <= 32U) ? true : false;/* microcontroller dependent */ + CANmodule->useCANrxFilters = (rxSize <= 32U) ? true : false; /* microcontroller dependent */ CANmodule->bufferInhibitFlag = false; CANmodule->firstCANtxMessage = true; CANmodule->CANtxCount = 0U; CANmodule->errOld = 0U; - for(i=0U; iuseCANrxFilters){ + if (CANmodule->useCANrxFilters) { /* CAN module filters are used, they will be configured with */ /* CO_CANrxBufferInit() functions, called by separate CANopen */ /* init functions. */ /* Configure all masks so, that received message must match filter */ - } - else{ + } else { /* CAN module filters are not used, all messages with standard 11-bit */ /* identifier will be received */ /* Configure mask 0 so, that all messages with standard identifier are accepted */ } - /* configure CAN interrupt registers */ - return CO_ERROR_NO; } - -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) { +void +CO_CANmodule_disable(CO_CANmodule_t* CANmodule) { if (CANmodule != NULL) { /* turn off the module */ } } - -CO_ReturnError_t CO_CANrxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*CANrx_callback)(void *object, void *message)) -{ +CO_ReturnError_t +CO_CANrxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, uint16_t mask, bool_t rtr, void* object, + void (*CANrx_callback)(void* object, void* message)) { CO_ReturnError_t ret = CO_ERROR_NO; - if((CANmodule!=NULL) && (object!=NULL) && (CANrx_callback!=NULL) && (index < CANmodule->rxSize)){ + if ((CANmodule != NULL) && (object != NULL) && (CANrx_callback != NULL) && (index < CANmodule->rxSize)) { /* buffer, which will be configured */ - CO_CANrx_t *buffer = &CANmodule->rxArray[index]; + CO_CANrx_t* buffer = &CANmodule->rxArray[index]; /* Configure object variables */ buffer->object = object; @@ -132,43 +111,33 @@ CO_ReturnError_t CO_CANrxBufferInit( /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */ buffer->ident = ident & 0x07FFU; - if(rtr){ + if (rtr) { buffer->ident |= 0x0800U; } buffer->mask = (mask & 0x07FFU) | 0x0800U; /* Set CAN hardware module filter and mask. */ - if(CANmodule->useCANrxFilters){ - - } - } - else{ + if (CANmodule->useCANrxFilters) {} + } else { ret = CO_ERROR_ILLEGAL_ARGUMENT; } return ret; } +CO_CANtx_t* +CO_CANtxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, bool_t rtr, uint8_t noOfBytes, + bool_t syncFlag) { + CO_CANtx_t* buffer = NULL; -CO_CANtx_t *CO_CANtxBufferInit( - CO_CANmodule_t *CANmodule, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, - bool_t syncFlag) -{ - CO_CANtx_t *buffer = NULL; - - if((CANmodule != NULL) && (index < CANmodule->txSize)){ + if ((CANmodule != NULL) && (index < CANmodule->txSize)) { /* get specific buffer */ buffer = &CANmodule->txArray[index]; /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer. * Microcontroller specific. */ - buffer->ident = ((uint32_t)ident & 0x07FFU) - | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) - | ((uint32_t)(rtr ? 0x8000U : 0U)); + buffer->ident = ((uint32_t)ident & 0x07FFU) | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) + | ((uint32_t)(rtr ? 0x8000U : 0U)); buffer->bufferFull = false; buffer->syncFlag = syncFlag; @@ -177,13 +146,13 @@ CO_CANtx_t *CO_CANtxBufferInit( return buffer; } - -CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ +CO_ReturnError_t +CO_CANsend(CO_CANmodule_t* CANmodule, CO_CANtx_t* buffer) { CO_ReturnError_t err = CO_ERROR_NO; /* Verify overflow */ - if(buffer->bufferFull){ - if(!CANmodule->firstCANtxMessage){ + if (buffer->bufferFull) { + if (!CANmodule->firstCANtxMessage) { /* don't set error, if bootup message is still on buffers */ CANmodule->CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; } @@ -192,12 +161,12 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ CO_LOCK_CAN_SEND(CANmodule); /* if CAN TX buffer is free, copy message to it */ - if(1 && CANmodule->CANtxCount == 0){ + if (1 && CANmodule->CANtxCount == 0) { CANmodule->bufferInhibitFlag = buffer->syncFlag; /* copy message and txRequest */ } /* if no buffer is free, message will be sent by interrupt */ - else{ + else { buffer->bufferFull = true; CANmodule->CANtxCount++; } @@ -206,25 +175,25 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ return err; } - -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ +void +CO_CANclearPendingSyncPDOs(CO_CANmodule_t* CANmodule) { uint32_t tpdoDeleted = 0U; CO_LOCK_CAN_SEND(CANmodule); /* Abort message from CAN module, if there is synchronous TPDO. * Take special care with this functionality. */ - if(/*messageIsOnCanBuffer && */CANmodule->bufferInhibitFlag){ + if (/*messageIsOnCanBuffer && */ CANmodule->bufferInhibitFlag) { /* clear TXREQ */ CANmodule->bufferInhibitFlag = false; tpdoDeleted = 1U; } /* delete also pending synchronous TPDOs in TX buffers */ - if(CANmodule->CANtxCount != 0U){ + if (CANmodule->CANtxCount != 0U) { uint16_t i; - CO_CANtx_t *buffer = &CANmodule->txArray[0]; - for(i = CANmodule->txSize; i > 0U; i--){ - if(buffer->bufferFull){ - if(buffer->syncFlag){ + CO_CANtx_t* buffer = &CANmodule->txArray[0]; + for (i = CANmodule->txSize; i > 0U; i--) { + if (buffer->bufferFull) { + if (buffer->syncFlag) { buffer->bufferFull = false; CANmodule->CANtxCount--; tpdoDeleted = 2U; @@ -235,18 +204,17 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ } CO_UNLOCK_CAN_SEND(CANmodule); - - if(tpdoDeleted != 0U){ + if (tpdoDeleted != 0U) { CANmodule->CANerrorStatus |= CO_CAN_ERRTX_PDO_LATE; } } - /* Get error counters from the module. If necessary, function may use * different way to determine errors. */ -static uint16_t rxErrors=0, txErrors=0, overflow=0; +static uint16_t rxErrors = 0, txErrors = 0, overflow = 0; -void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { +void +CO_CANmodule_process(CO_CANmodule_t* CANmodule) { uint32_t err; err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; @@ -259,12 +227,11 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { if (txErrors >= 256U) { /* bus off */ status |= CO_CAN_ERRTX_BUS_OFF; - } - else { + } else { /* recalculate CANerrorStatus, first clear some flags */ - status &= 0xFFFF ^ (CO_CAN_ERRTX_BUS_OFF | - CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE | - CO_CAN_ERRTX_WARNING | CO_CAN_ERRTX_PASSIVE); + status &= 0xFFFF + ^ (CO_CAN_ERRTX_BUS_OFF | CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE | CO_CAN_ERRTX_WARNING + | CO_CAN_ERRTX_PASSIVE); /* rx bus warning or passive */ if (rxErrors >= 128) { @@ -295,43 +262,42 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { } } - typedef struct { uint32_t ident; uint8_t DLC; uint8_t data[8]; } CO_CANrxMsg_t; -void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ +void +CO_CANinterrupt(CO_CANmodule_t* CANmodule) { /* receive interrupt */ - if(1){ - CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint32_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ + if (1) { + CO_CANrxMsg_t* rcvMsg; /* pointer to received message in CAN module */ + uint16_t index; /* index of received message */ + uint32_t rcvMsgIdent; /* identifier of the received message */ + CO_CANrx_t* buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ bool_t msgMatched = false; rcvMsg = 0; /* get message from module here */ rcvMsgIdent = rcvMsg->ident; - if(CANmodule->useCANrxFilters){ + if (CANmodule->useCANrxFilters) { /* CAN module filters are used. Message with known 11-bit identifier has */ /* been received */ - index = 0; /* get index of the received message here. Or something similar */ - if(index < CANmodule->rxSize){ + index = 0; /* get index of the received message here. Or something similar */ + if (index < CANmodule->rxSize) { buffer = &CANmodule->rxArray[index]; /* verify also RTR */ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ + if (((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) { msgMatched = true; } } - } - else{ + } else { /* CAN module filters are not used, message with any standard 11-bit identifier */ /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ buffer = &CANmodule->rxArray[0]; - for(index = CANmodule->rxSize; index > 0U; index--){ - if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ + for (index = CANmodule->rxSize; index > 0U; index--) { + if (((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) { msgMatched = true; break; } @@ -340,16 +306,15 @@ void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ } /* Call specific function, which will process the message */ - if(msgMatched && (buffer != NULL) && (buffer->CANrx_callback != NULL)){ - buffer->CANrx_callback(buffer->object, (void*) rcvMsg); + if (msgMatched && (buffer != NULL) && (buffer->CANrx_callback != NULL)) { + buffer->CANrx_callback(buffer->object, (void*)rcvMsg); } /* Clear interrupt flag */ } - /* transmit interrupt */ - else if(0){ + else if (0) { /* Clear interrupt flag */ /* First CAN message (bootup) was sent successfully */ @@ -357,33 +322,32 @@ void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ /* clear flag from previous message */ CANmodule->bufferInhibitFlag = false; /* Are there any new messages waiting to be send */ - if(CANmodule->CANtxCount > 0U){ - uint16_t i; /* index of transmitting message */ + if (CANmodule->CANtxCount > 0U) { + uint16_t i; /* index of transmitting message */ /* first buffer */ - CO_CANtx_t *buffer = &CANmodule->txArray[0]; + CO_CANtx_t* buffer = &CANmodule->txArray[0]; /* search through whole array of pointers to transmit message buffers. */ - for(i = CANmodule->txSize; i > 0U; i--){ + for (i = CANmodule->txSize; i > 0U; i--) { /* if message buffer is full, send it. */ - if(buffer->bufferFull){ + if (buffer->bufferFull) { buffer->bufferFull = false; CANmodule->CANtxCount--; /* Copy message to CAN buffer */ CANmodule->bufferInhibitFlag = buffer->syncFlag; /* canSend... */ - break; /* exit for loop */ + break; /* exit for loop */ } buffer++; - }/* end of for loop */ + } /* end of for loop */ /* Clear counter if no more messages */ - if(i == 0U){ + if (i == 0U) { CANmodule->CANtxCount = 0U; } } - } - else{ + } else { /* some other interrupt reason */ } } diff --git a/example/CO_storageBlank.c b/example/CO_storageBlank.c index cf63f41c..e7795550 100644 --- a/example/CO_storageBlank.c +++ b/example/CO_storageBlank.c @@ -19,16 +19,15 @@ #include "CO_storageBlank.h" - #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - /* * Function for writing data on "Store parameters" command - OD object 1010 * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t storeBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { +static ODR_t +storeBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { /* Open a file and write data to it */ /* file = open(entry->pathToFileOrPointerToMemory); */ @@ -39,46 +38,33 @@ static ODR_t storeBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { return ODR_OK; } - /* * Function for restoring data on "Restore default parameters" command - OD 1011 * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t restoreBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule){ +static ODR_t +restoreBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { /* disable (delete) the file, so default values will stay after startup */ return ODR_OK; } - -CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, - CO_CANmodule_t *CANmodule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParam, - CO_storage_entry_t *entries, - uint8_t entriesCount, - uint32_t *storageInitError) -{ +CO_ReturnError_t +CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, + OD_entry_t* OD_1011_RestoreDefaultParam, CO_storage_entry_t* entries, uint8_t entriesCount, + uint32_t* storageInitError) { CO_ReturnError_t ret; /* verify arguments */ - if (storage == NULL || entries == NULL || entriesCount == 0 - || storageInitError == NULL - ) { + if (storage == NULL || entries == NULL || entriesCount == 0 || storageInitError == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } /* initialize storage and OD extensions */ - ret = CO_storage_init(storage, - CANmodule, - OD_1010_StoreParameters, - OD_1011_RestoreDefaultParam, - storeBlank, - restoreBlank, - entries, - entriesCount); + ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeBlank, + restoreBlank, entries, entriesCount); if (ret != CO_ERROR_NO) { return ret; } @@ -86,7 +72,7 @@ CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, /* initialize entries */ *storageInitError = 0; for (uint8_t i = 0; i < entriesCount; i++) { - CO_storage_entry_t *entry = &entries[i]; + CO_storage_entry_t* entry = &entries[i]; /* verify arguments */ if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { @@ -97,7 +83,6 @@ CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, /* Open a file and read data from file to entry->addr */ /* file = open(entry->pathToFileOrPointerToMemory); */ /* read(entry->addr, entry->len, file); */ - } return ret; diff --git a/example/main_blank.c b/example/main_blank.c index 4ec0583a..f4c0253b 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -19,66 +19,54 @@ * See the License for the specific language governing permissions and limitations under the License. */ - #include #include "CANopen.h" #include "OD.h" #include "CO_storageBlank.h" - -#define log_printf(macropar_message, ...) \ - printf(macropar_message, ##__VA_ARGS__) - +#define log_printf(macropar_message, ...) printf(macropar_message, ##__VA_ARGS__) /* default values for CO_CANopenInit() */ -#define NMT_CONTROL \ - CO_NMT_STARTUP_TO_OPERATIONAL \ - | CO_NMT_ERR_ON_ERR_REG \ - | CO_ERR_REG_GENERIC_ERR \ - | CO_ERR_REG_COMMUNICATION -#define FIRST_HB_TIME 500 +#define NMT_CONTROL \ + CO_NMT_STARTUP_TO_OPERATIONAL \ + | CO_NMT_ERR_ON_ERR_REG | CO_ERR_REG_GENERIC_ERR | CO_ERR_REG_COMMUNICATION +#define FIRST_HB_TIME 500 #define SDO_SRV_TIMEOUT_TIME 1000 #define SDO_CLI_TIMEOUT_TIME 500 -#define SDO_CLI_BLOCK false -#define OD_STATUS_BITS NULL - +#define SDO_CLI_BLOCK false +#define OD_STATUS_BITS NULL /* Global variables and objects */ -CO_t *CO = NULL; /* CANopen object */ +CO_t* CO = NULL; /* CANopen object */ uint8_t LED_red, LED_green; - /* main ***********************************************************************/ -int main (void){ +int +main(void) { CO_ReturnError_t err; CO_NMT_reset_cmd_t reset = CO_RESET_NOT; uint32_t heapMemoryUsed; - void *CANptr = NULL; /* CAN module address */ - uint8_t pendingNodeId = 10; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ - uint8_t activeNodeId = 10; /* Copied from CO_pendingNodeId in the communication reset section */ - uint16_t pendingBitRate = 125; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ + void* CANptr = NULL; /* CAN module address */ + uint8_t pendingNodeId = 10; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ + uint8_t activeNodeId = 10; /* Copied from CO_pendingNodeId in the communication reset section */ + uint16_t pendingBitRate = 125; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE CO_storage_t storage; - CO_storage_entry_t storageEntries[] = { - { - .addr = &OD_PERSIST_COMM, - .len = sizeof(OD_PERSIST_COMM), - .subIndexOD = 2, - .attr = CO_storage_cmd | CO_storage_restore, - .addrNV = NULL - } - }; + CO_storage_entry_t storageEntries[] = {{.addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), + .subIndexOD = 2, + .attr = CO_storage_cmd | CO_storage_restore, + .addrNV = NULL}}; uint8_t storageEntriesCount = sizeof(storageEntries) / sizeof(storageEntries[0]); uint32_t storageInitError = 0; #endif /* Configure microcontroller. */ - /* Allocate memory */ - CO_config_t *config_ptr = NULL; + CO_config_t* config_ptr = NULL; #ifdef CO_MULTIPLE_OD /* example usage of CO_MULTIPLE_OD (but still single OD here) */ CO_config_t co_config = {0}; @@ -91,19 +79,13 @@ int main (void){ if (CO == NULL) { log_printf("Error: Can't allocate memory\n"); return 0; - } - else { + } else { log_printf("Allocated %u bytes for CANopen objects\n", heapMemoryUsed); } - #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - err = CO_storageBlank_init(&storage, - CO->CANmodule, - OD_ENTRY_H1010_storeParameters, - OD_ENTRY_H1011_restoreDefaultParameters, - storageEntries, - storageEntriesCount, + err = CO_storageBlank_init(&storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, + OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, storageEntriesCount, &storageInitError); if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) { @@ -112,16 +94,15 @@ int main (void){ } #endif - - while(reset != CO_RESET_APP){ -/* CANopen communication reset - initialize CANopen objects *******************/ + while (reset != CO_RESET_APP) { + /* CANopen communication reset - initialize CANopen objects *******************/ log_printf("CANopenNode - Reset communication...\n"); /* Wait rt_thread. */ CO->CANmodule->CANnormal = false; /* Enter CAN configuration. */ - CO_CANsetConfigurationMode((void *)&CANptr); + CO_CANsetConfigurationMode((void*)&CANptr); CO_CANmodule_disable(CO->CANmodule); /* initialize CANopen */ @@ -131,14 +112,12 @@ int main (void){ return 0; } - CO_LSS_address_t lssAddress = {.identity = { - .vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, - .productCode = OD_PERSIST_COMM.x1018_identity.productCode, - .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, - .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber - }}; + CO_LSS_address_t lssAddress = {.identity = {.vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, + .productCode = OD_PERSIST_COMM.x1018_identity.productCode, + .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, + .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber}}; err = CO_LSSinit(CO, &lssAddress, &pendingNodeId, &pendingBitRate); - if(err != CO_ERROR_NO) { + if (err != CO_ERROR_NO) { log_printf("Error: LSS slave initialization failed: %d\n", err); return 0; } @@ -146,34 +125,31 @@ int main (void){ activeNodeId = pendingNodeId; uint32_t errInfo = 0; - err = CO_CANopenInit(CO, /* CANopen object */ - NULL, /* alternate NMT */ - NULL, /* alternate em */ - OD, /* Object dictionary */ - OD_STATUS_BITS, /* Optional OD_statusBits */ - NMT_CONTROL, /* CO_NMT_control_t */ - FIRST_HB_TIME, /* firstHBTime_ms */ + err = CO_CANopenInit(CO, /* CANopen object */ + NULL, /* alternate NMT */ + NULL, /* alternate em */ + OD, /* Object dictionary */ + OD_STATUS_BITS, /* Optional OD_statusBits */ + NMT_CONTROL, /* CO_NMT_control_t */ + FIRST_HB_TIME, /* firstHBTime_ms */ SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */ SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */ - SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ - activeNodeId, - &errInfo); - if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ + activeNodeId, &errInfo); + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { if (err == CO_ERROR_OD_PARAMETERS) { log_printf("Error: Object Dictionary entry 0x%X\n", errInfo); - } - else { + } else { log_printf("Error: CANopen initialization failed: %d\n", err); } return 0; } err = CO_CANopenInitPDO(CO, CO->em, OD, activeNodeId, &errInfo); - if(err != CO_ERROR_NO) { + if (err != CO_ERROR_NO) { if (err == CO_ERROR_OD_PARAMETERS) { log_printf("Error: Object Dictionary entry 0x%X\n", errInfo); - } - else { + } else { log_printf("Error: PDO initialization failed: %d\n", err); } return 0; @@ -181,25 +157,20 @@ int main (void){ /* Configure Timer interrupt function for execution every 1 millisecond */ - /* Configure CAN transmit and receive interrupt */ - /* Configure CANopen callbacks, etc */ - if(!CO->nodeIdUnconfigured) { + if (!CO->nodeIdUnconfigured) { #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - if(storageInitError != 0) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, - CO_EMC_HARDWARE, storageInitError); + if (storageInitError != 0) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, storageInitError); } #endif - } - else { + } else { log_printf("CANopenNode - Node-id not initialized\n"); } - /* start CAN */ CO_CANsetNormalMode(CO->CANmodule); @@ -208,8 +179,8 @@ int main (void){ log_printf("CANopenNode - Running...\n"); fflush(stdout); - while(reset == CO_RESET_NOT){ -/* loop for normal program execution ******************************************/ + while (reset == CO_RESET_NOT) { + /* loop for normal program execution ******************************************/ /* get time difference since last function call */ uint32_t timeDifference_us = 500; @@ -226,13 +197,11 @@ int main (void){ } } - -/* program exit ***************************************************************/ + /* program exit ***************************************************************/ /* stop threads */ - /* delete objects from memory */ - CO_CANsetConfigurationMode((void *)&CANptr); + CO_CANsetConfigurationMode((void*)&CANptr); CO_delete(CO); log_printf("CANopenNode finished\n"); @@ -241,11 +210,11 @@ int main (void){ return 0; } - /* timer thread executes in constant intervals ********************************/ -void tmrTask_thread(void){ +void +tmrTask_thread(void) { - for(;;) { + for (;;) { CO_LOCK_OD(CO->CANmodule); if (!CO->nodeIdUnconfigured && CO->CANmodule->CANnormal) { bool_t syncWas = false; @@ -268,9 +237,9 @@ void tmrTask_thread(void){ } } - /* CAN interrupt function executes on received CAN message ********************/ -void /* interrupt */ CO_CAN1InterruptHandler(void){ +void /* interrupt */ +CO_CAN1InterruptHandler(void) { /* clear interrupt flag */ } diff --git a/storage/CO_storage.c b/storage/CO_storage.c index eb9fd57f..089738ee 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -19,24 +19,21 @@ #include "storage/CO_storage.h" -#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 +#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0 /* * Custom function for writing OD object "Store parameters" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ +static ODR_t +OD_write_1010(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { /* verify arguments */ - if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) - || (countWritten == NULL) - ) { + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_storage_t *storage = stream->object; + CO_storage_t* storage = stream->object; if ((stream->subIndex == 0U) || (storage->store == NULL) || !storage->enabled) { return ODR_READONLY; @@ -52,7 +49,7 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, ODR_t returnCode = ODR_OK; for (uint8_t i = 0; i < storage->entriesCount; i++) { - CO_storage_entry_t *entry = &storage->entries[i]; + CO_storage_entry_t* entry = &storage->entries[i]; if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { if (found == 0U) { @@ -78,25 +75,21 @@ static ODR_t OD_write_1010(OD_stream_t *stream, const void *buf, return returnCode; } - /* * Custom function for writing OD object "Restore default parameters" * * For more information see file CO_ODinterface.h, OD_IO_t. */ -static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten) -{ +static ODR_t +OD_write_1011(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { /* verify arguments */ - if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) - || (countWritten == NULL) - ) { + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; } - CO_storage_t *storage = stream->object; + CO_storage_t* storage = stream->object; - if ((stream->subIndex == 0U) || (storage->restore == NULL) || !storage->enabled){ + if ((stream->subIndex == 0U) || (storage->restore == NULL) || !storage->enabled) { return ODR_READONLY; } @@ -110,7 +103,7 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, ODR_t returnCode = ODR_OK; for (uint8_t i = 0; i < storage->entriesCount; i++) { - CO_storage_entry_t *entry = &storage->entries[i]; + CO_storage_entry_t* entry = &storage->entries[i]; if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { if (found == 0U) { @@ -136,22 +129,15 @@ static ODR_t OD_write_1011(OD_stream_t *stream, const void *buf, return returnCode; } - -CO_ReturnError_t CO_storage_init(CO_storage_t *storage, - CO_CANmodule_t *CANmodule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParameters, - ODR_t (*store)(CO_storage_entry_t *entry, - CO_CANmodule_t *CANmodule), - ODR_t (*restore)(CO_storage_entry_t *entry, - CO_CANmodule_t *CANmodule), - CO_storage_entry_t *entries, - uint8_t entriesCount) -{ +CO_ReturnError_t +CO_storage_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, + OD_entry_t* OD_1011_RestoreDefaultParameters, + ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), + ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), CO_storage_entry_t* entries, + uint8_t entriesCount) { /* verify arguments */ - if ((storage == NULL) || (CANmodule == NULL) || (OD_1010_StoreParameters == NULL) || (OD_1011_RestoreDefaultParameters == NULL) - || (store == NULL) || (restore == NULL) || (entries == NULL) - ) { + if ((storage == NULL) || (CANmodule == NULL) || (OD_1010_StoreParameters == NULL) + || (OD_1011_RestoreDefaultParameters == NULL) || (store == NULL) || (restore == NULL) || (entries == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -171,8 +157,7 @@ CO_ReturnError_t CO_storage_init(CO_storage_t *storage, storage->OD_1011_extension.object = storage; storage->OD_1011_extension.read = OD_readOriginal; storage->OD_1011_extension.write = OD_write_1011; - (void)OD_extension_init(OD_1011_RestoreDefaultParameters, - &storage->OD_1011_extension); + (void)OD_extension_init(OD_1011_RestoreDefaultParameters, &storage->OD_1011_extension); return CO_ERROR_NO; } diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index a82efa09..397594ad 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -21,25 +21,24 @@ #include "storage/CO_eeprom.h" #include "301/crc16-ccitt.h" -#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 +#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0 /* * Function for writing data on "Store parameters" command - OD object 1010 * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t storeEeprom(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { - (void) CANmodule; +static ODR_t +storeEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { + (void)CANmodule; bool_t writeOk; /* save data to the eeprom */ - writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr, - entry->eepromAddr, entry->len); + writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len); entry->crc = crc16_ccitt(entry->addr, entry->len, 0); /* Verify, if data in eeprom are equal */ - uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, - entry->eepromAddr, entry->len); + uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, entry->eepromAddr, entry->len); if ((entry->crc != crc_read) || !writeOk) { return ODR_HW; } @@ -47,73 +46,56 @@ static ODR_t storeEeprom(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { /* Write signature (see CO_storageEeprom_init() for info) */ uint16_t signatureOfEntry = (uint16_t)entry->len; uint32_t signature = (((uint32_t)entry->crc) << 16) | signatureOfEntry; - writeOk = CO_eeprom_writeBlock(entry->storageModule, - (uint8_t *)&signature, - entry->eepromAddrSignature, + writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t*)&signature, entry->eepromAddrSignature, sizeof(signature)); /* verify signature and write */ uint32_t signatureRead; - CO_eeprom_readBlock(entry->storageModule, - (uint8_t *)&signatureRead, - entry->eepromAddrSignature, + CO_eeprom_readBlock(entry->storageModule, (uint8_t*)&signatureRead, entry->eepromAddrSignature, sizeof(signatureRead)); - if((signature != signatureRead) || !writeOk) { + if ((signature != signatureRead) || !writeOk) { return ODR_HW; } return ODR_OK; } - /* * Function for restoring data on "Restore default parameters" command - OD 1011 * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t restoreEeprom(CO_storage_entry_t *entry, - CO_CANmodule_t *CANmodule) -{ - (void) CANmodule; +static ODR_t +restoreEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { + (void)CANmodule; bool_t writeOk; /* Write empty signature */ uint32_t signature = 0xFFFFFFFFU; - writeOk = CO_eeprom_writeBlock(entry->storageModule, - (uint8_t *)&signature, - entry->eepromAddrSignature, + writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t*)&signature, entry->eepromAddrSignature, sizeof(signature)); /* verify signature and protection */ uint32_t signatureRead; - CO_eeprom_readBlock(entry->storageModule, - (uint8_t *)&signatureRead, - entry->eepromAddrSignature, + CO_eeprom_readBlock(entry->storageModule, (uint8_t*)&signatureRead, entry->eepromAddrSignature, sizeof(signatureRead)); - if((signature != signatureRead) || !writeOk) { + if ((signature != signatureRead) || !writeOk) { return ODR_HW; } return ODR_OK; } - -CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, - CO_CANmodule_t *CANmodule, - void *storageModule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParam, - CO_storage_entry_t *entries, - uint8_t entriesCount, - uint32_t *storageInitError) -{ +CO_ReturnError_t +CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* storageModule, + OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, + CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError) { CO_ReturnError_t ret; bool_t eepromOvf = false; /* verify arguments */ if ((storage == NULL) || (entries == NULL) || (entriesCount == 0U) - || (entriesCount > CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT) || (storageInitError == NULL) - ) { + || (entriesCount > CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT) || (storageInitError == NULL)) { return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -126,33 +108,21 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, } /* initialize storage and OD extensions */ - ret = CO_storage_init(storage, - CANmodule, - OD_1010_StoreParameters, - OD_1011_RestoreDefaultParam, - storeEeprom, - restoreEeprom, - entries, - entriesCount); + ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeEeprom, + restoreEeprom, entries, entriesCount); if (ret != CO_ERROR_NO) { return ret; } /* Read entry signatures from the eeprom */ uint32_t signatures[CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT]; - size_t signaturesAddress = CO_eeprom_getAddr(storageModule, - false, - sizeof(signatures), - &eepromOvf); - CO_eeprom_readBlock(storageModule, - (uint8_t *)signatures, - signaturesAddress, - sizeof(signatures)); + size_t signaturesAddress = CO_eeprom_getAddr(storageModule, false, sizeof(signatures), &eepromOvf); + CO_eeprom_readBlock(storageModule, (uint8_t*)signatures, signaturesAddress, sizeof(signatures)); /* initialize entries */ *storageInitError = 0; for (uint8_t i = 0; i < entriesCount; i++) { - CO_storage_entry_t *entry = &entries[i]; + CO_storage_entry_t* entry = &entries[i]; bool_t isAuto = (entry->attr & (uint8_t)CO_storage_auto) != 0U; /* verify arguments */ @@ -163,10 +133,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, /* calculate addresses inside eeprom */ entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); - entry->eepromAddr = CO_eeprom_getAddr(storageModule, - isAuto, - entry->len, - &eepromOvf); + entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); entry->offset = 0; /* verify if eeprom is too small */ @@ -187,11 +154,9 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, bool_t dataCorrupt = false; if (signatureInEeprom != signatureOfEntry) { dataCorrupt = true; - } - else { + } else { /* Read data into storage location */ - CO_eeprom_readBlock(entry->storageModule, entry->addr, - entry->eepromAddr, entry->len); + CO_eeprom_readBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len); /* Verify CRC, except for auto storage variables */ if (!isAuto) { @@ -208,7 +173,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, if (errorBit > 31U) { errorBit = 31; } - *storageInitError |= ((uint32_t) 1) << errorBit; + *storageInitError |= ((uint32_t)1) << errorBit; ret = CO_ERROR_DATA_CORRUPT; } } /* for (entries) */ @@ -217,8 +182,8 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, return ret; } - -void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { +void +CO_storageEeprom_auto_process(CO_storage_t* storage, bool_t saveAll) { /* verify arguments */ if ((storage == NULL) || !storage->enabled) { return; @@ -226,7 +191,7 @@ void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { /* loop through entries */ for (uint8_t n = 0; n < storage->entriesCount; n++) { - CO_storage_entry_t *entry = &storage->entries[n]; + CO_storage_entry_t* entry = &storage->entries[n]; if ((entry->attr & (uint8_t)CO_storage_auto) == 0U) { continue; @@ -234,24 +199,18 @@ void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll) { if (saveAll) { /* update all bytes */ - for (size_t i = 0; i < entry->len; ) { - uint8_t dataByteToUpdate = ((uint8_t *)(entry->addr))[i]; + for (size_t i = 0; i < entry->len;) { + uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[i]; size_t eepromAddr = entry->eepromAddr + i; - if (CO_eeprom_updateByte(entry->storageModule, - dataByteToUpdate, - eepromAddr) - ) { + if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, eepromAddr)) { i++; } } - } - else { + } else { /* update one data byte and if successful increment to next */ uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[entry->offset]; size_t eepromAddr = entry->eepromAddr + entry->offset; - if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, - eepromAddr) - ) { + if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, eepromAddr)) { if (++entry->offset >= entry->len) { entry->offset = 0; } From 82c95a2bc9839e3333908f6f5321c95ff9a43643 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 6 Jul 2024 21:48:21 +0200 Subject: [PATCH 476/520] Format comments in the .c files. --- 301/CO_Emergency.c | 21 ++++------ 301/CO_HBconsumer.c | 12 +++--- 301/CO_NMT_Heartbeat.c | 17 ++++---- 301/CO_Node_Guarding.c | 13 +++---- 301/CO_ODinterface.c | 12 +++--- 301/CO_PDO.c | 35 +++++++---------- 301/CO_SDOclient.c | 60 ++++++++++++----------------- 301/CO_SDOserver.c | 81 ++++++++++++++++----------------------- 301/CO_SYNC.c | 10 ++--- 301/CO_TIME.c | 7 ++-- 301/CO_fifo.c | 19 ++++----- 304/CO_GFC.c | 2 +- 304/CO_SRDO.c | 10 ++--- 305/CO_LSSmaster.c | 61 ++++++++++++----------------- 305/CO_LSSslave.c | 10 ++--- 309/CO_gateway_ascii.c | 48 +++++++++-------------- CANopen.c | 32 ++++------------ doc/objectDictionary.md | 4 +- example/CO_driver_blank.c | 11 ++---- 19 files changed, 183 insertions(+), 282 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index 53d25f29..d0b1ada3 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -88,8 +88,7 @@ OD_write_1014(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* return ODR_INVALID_VALUE; } - /* store values. If default CAN-ID is used, then store only value of - * CO_CAN_ID_EMERGENCY without node id. */ + /* store values. If default CAN-ID is used, then store only value of CO_CAN_ID_EMERGENCY without node id. */ em->producerEnabled = newEnabled; em->producerCanId = (newCanId == ((uint16_t)CO_CAN_ID_EMERGENCY + em->nodeId)) ? CO_CAN_ID_EMERGENCY : newCanId; @@ -273,9 +272,8 @@ OD_write_statusBits(OD_stream_t* stream, const void* buf, OD_size_t count, OD_si /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_EM_receive(void* object, void* msg) { @@ -392,9 +390,8 @@ CO_EM_init(CO_EM_t* em, CO_CANmodule_t* CANdevTx, const OD_entry_t* OD_1001_errR /* following two variables are used inside OD_read_1014 and OD_write_1014 */ em->producerCanId = producerCanId; em->CANdevTxIdx = CANdevTxIdx; - /* if default producerCanId is used, then value of CO_CAN_ID_EMERGENCY - * (0x80) is stored into non-volatile memory. In that case it is necessary - * to add nodeId of this node to the stored value. */ + /* if default producerCanId is used, then value of CO_CAN_ID_EMERGENCY (0x80) is stored into non-volatile + * memory. In that case it is necessary to add nodeId of this node to the stored value. */ if (producerCanId == CO_CAN_ID_EMERGENCY) { producerCanId += nodeId; } @@ -597,8 +594,7 @@ CO_EM_process(CO_EM_t* em, bool_t NMTisPreOrOperational, uint32_t timeDifference fifoPpPtr++; em->fifoPpPtr = (fifoPpPtr < em->fifoSize) ? fifoPpPtr : 0U; - /* verify message buffer overflow. Clear error condition if all - * messages from fifo buffer are processed */ + /* verify message buffer overflow. Clear error condition if all messages from fifo buffer are processed */ if (em->fifoOverflow == 1U) { em->fifoOverflow = 2; CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, CO_EMC_GENERIC, 0); @@ -673,7 +669,7 @@ CO_error(CO_EM_t* em, bool_t setError, const uint8_t errorBit, uint16_t errorCod } #if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 - /* prepare emergency message. Error register will be added in post-process*/ + /* prepare emergency message. Error register will be added in post-process */ uint32_t errMsg = ((uint32_t)errorBit << 24) | CO_SWAP_16(errorCode); #if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 uint32_t infoCodeSwapped = CO_SWAP_32(infoCode); @@ -715,8 +711,7 @@ CO_error(CO_EM_t* em, bool_t setError, const uint8_t errorBit, uint16_t errorCod #if ((CO_CONFIG_EM)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 #if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 - /* Optional signal to RTOS, which can resume task, which handles - * CO_EM_process */ + /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */ if ((em->pFunctSignalPre != NULL) && em->producerEnabled) { em->pFunctSignalPre(em->functSignalObjectPre); } diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index ae249325..1c361dbc 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -22,7 +22,7 @@ #if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0 -/* Verify HB consumer configuration *******************************************/ +/* Verify HB consumer configuration */ #if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ && (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) #error CO_CONFIG_HB_CONS_CALLBACK_CHANGE and CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously! @@ -31,9 +31,8 @@ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_HBcons_receive(void* object, void* msg) { @@ -57,8 +56,7 @@ CO_HBcons_receive(void* object, void* msg) { /* * Initialize one Heartbeat consumer entry * - * This function is called from the @ref CO_HBconsumer_init() or when writing - * to OD entry 1016. + * This function is called from the @ref CO_HBconsumer_init() or when writing to OD entry 1016. * * @param HBcons This object. * @param idx index of the node in HBcons object @@ -317,7 +315,7 @@ CO_HBconsumer_process(CO_HBconsumer_t* HBcons, bool_t NMTisPreOrOperational, uin /* Verify if received message is heartbeat or bootup */ if (CO_FLAG_READ(monitoredNode->CANrxNew)) { if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) { - /* bootup message*/ + /* bootup message */ #if ((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0 if (monitoredNode->pFunctSignalRemoteReset != NULL) { monitoredNode->pFunctSignalRemoteReset(monitoredNode->nodeId, i, diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index b95cf368..b4505cde 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -23,9 +23,8 @@ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_NMT_receive(void* object, void* msg) { @@ -184,7 +183,7 @@ CO_NMT_process(CO_NMT_t* NMT, CO_NMT_internalState_t* NMTstate, uint32_t timeDif /* Send heartbeat producer message if: * - First start, send bootup message or - * - HB producer enabled and: Timer expired or NMT->operatingState changed*/ + * - HB producer enabled and: Timer expired or NMT->operatingState changed */ if (NNTinit || ((NMT->HBproducerTime_us != 0U) && ((NMT->HBproducerTimer == 0U) || (NMTstateCpy != NMT->operatingStatePrev)))) { @@ -197,17 +196,15 @@ CO_NMT_process(CO_NMT_t* NMT, CO_NMT_internalState_t* NMTstate, uint32_t timeDif ? CO_NMT_OPERATIONAL : CO_NMT_PRE_OPERATIONAL; } else { - /* Start timer from the beginning. If OS is slow, time sliding may - * occur. However, heartbeat is not for synchronization, it is for - * health report. In case of initializing, timer is set in the - * CO_NMT_init() function with pre-defined value. */ + /* Start timer from the beginning. If OS is slow, time sliding may occur. However, + * heartbeat is not for synchronization, it is for health report. In case of + * initializing, timer is set in the CO_NMT_init() function with pre-defined value. */ NMT->HBproducerTimer = NMT->HBproducerTime_us; } } NMT->operatingStatePrev = NMTstateCpy; - /* process internal NMT commands, received from CO_NMT_receive() or - * CO_NMT_sendCommand() */ + /* process internal NMT commands, received from CO_NMT_receive() or CO_NMT_sendCommand() */ if (NMT->internalCommand != CO_NMT_NO_COMMAND) { switch (NMT->internalCommand) { case CO_NMT_ENTER_OPERATIONAL: NMTstateCpy = CO_NMT_OPERATIONAL; break; diff --git a/301/CO_Node_Guarding.c b/301/CO_Node_Guarding.c index 8be43dec..e7cda3d0 100644 --- a/301/CO_Node_Guarding.c +++ b/301/CO_Node_Guarding.c @@ -25,9 +25,8 @@ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_ngs_receive(void* object, void* msg) { @@ -235,9 +234,8 @@ CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t* ngs, CO_NMT_internalState_t /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. * * Function receives messages from CAN identifier from 0x700 to 0x7FF. It * searches matching node->ident from nodes array. @@ -283,8 +281,7 @@ CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t* ngm, CO_EM_t* em, CO_CANmodu /* Configure object variables */ ngm->em = em; - /* configure CAN reception. One buffer will receive all messages - * from CAN-id 0x700 to 0x7FF. */ + /* configure CAN reception. One buffer will receive all messages from CAN-id 0x700 to 0x7FF. */ ret = CO_CANrxBufferInit(CANdevRx, CANdevRxIdx, CO_CAN_ID_HEARTBEAT, 0x780, false, (void*)ngm, CO_ngm_receive); if (ret != CO_ERROR_NO) { return ret; diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index fcba2a83..605b88b6 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -78,9 +78,8 @@ OD_writeOriginal(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_ ODR_t returnCode = ODR_OK; - /* If previous write was partial or OD variable length is larger than - * current buffer size, then data was (will be) written in several - * segments */ + /* If previous write was partial or OD variable length is larger than current buffer size, + * then data was (will be) written in several segments */ if ((stream->dataOffset > 0U) || (dataLenToCopy > count)) { if (stream->dataOffset >= dataLenToCopy) { return ODR_DEV_INCOMPAT; @@ -117,7 +116,7 @@ OD_writeOriginal(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_ return returnCode; } -/* Read value from variable from Object Dictionary disabled, see OD_IO_t*/ +/* Read value from variable from Object Dictionary disabled, see OD_IO_t */ static ODR_t OD_readDisabled(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { (void)stream; @@ -146,9 +145,8 @@ OD_find(OD_t* od, uint16_t index) { uint16_t min = 0; uint16_t max = od->size - 1U; - /* Fast search in ordered Object Dictionary. If indexes are mixed, - * this won't work. If Object Dictionary has up to N entries, then the - * max number of loop passes is log2(N) */ + /* Fast search in ordered Object Dictionary. If indexes are mixed, this won't work. If Object + * Dictionary has up to N entries, then the max number of loop passes is log2(N) */ while (min < max) { /* get entry between min and max */ uint16_t cur = (min + max) >> 1; diff --git a/301/CO_PDO.c b/301/CO_PDO.c index c136f8c5..c57e01a1 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -70,8 +70,7 @@ OD_read_dummy(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countR /* * Find mapped variable in Object Dictionary and configure entry in RPDO or TPDO * - * @param PDO This object will be configured. If map is erroneous, then it will - * stay unchanged. + * @param PDO This object will be configured. If map is erroneous, then it will stay unchanged. * @param map PDO mapping parameter. * @param mapIndex from 0 to CO_PDO_MAX_MAPPED_ENTRIES * @param isRPDO True for RPDO and false for TPDO. @@ -412,7 +411,7 @@ OD_read_PDO_commParam(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t /* * @defgroup CO_PDO_receiveErrors_t States for RPDO->receiveError indicates received RPDOs with wrong length. * @{ - * + * */ #define CO_RPDO_RX_ACK_NO_ERROR 0U /* No error */ #define CO_RPDO_RX_ACK_ERROR 1U /* Error is acknowledged */ @@ -421,14 +420,13 @@ OD_read_PDO_commParam(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t #define CO_RPDO_RX_SHORT 12U /* Too short RPDO received, not acknowledged */ #define CO_RPDO_RX_LONG 13U /* Too long RPDO received, not acknowledged */ -/** @} */ /* CO_PDO_receiveErrors_t */ +/* @} */ /* CO_PDO_receiveErrors_t */ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. * If new message arrives and previous message wasn't processed yet, then * previous message will be lost and overwritten by the new message. */ @@ -466,8 +464,7 @@ CO_PDO_receive(void* object, void* msg) { CO_FLAG_SET(RPDO->CANrxNew[bufNo]); #if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 - /* Optional signal to RTOS, which can resume task, which handles - * the RPDO. */ + /* Optional signal to RTOS, which can resume task, which handles the RPDO. */ if (RPDO->pFunctSignalPre != NULL) { RPDO->pFunctSignalPre(RPDO->functSignalObjectPre); } @@ -505,9 +502,8 @@ OD_write_14xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); bool_t valid = (COB_ID & 0x80000000U) == 0U; - /* bits 11...29 must be zero, PDO must be disabled on change, - * CAN_ID == 0 is not allowed, mapping must be configured before - * enabling the PDO */ + /* bits 11...29 must be zero, PDO must be disabled on change, CAN_ID == 0 is + * not allowed, mapping must be configured before enabling the PDO */ if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && PDO->valid && (CAN_ID != PDO->configuredCanId)) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) || (valid && (PDO->mappedObjectsCount == 0U))) { return ODR_INVALID_VALUE; @@ -835,7 +831,7 @@ CO_RPDO_process(CO_RPDO_t* RPDO, #endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE */ } /* if (PDO->valid && NMTisOperational) */ else { - /* not valid and operational, clear CAN receive flags and timeoutTimer*/ + /* not valid and operational, clear CAN receive flags and timeoutTimer */ #if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 if (!PDO->valid || !NMTisOperational) { CO_FLAG_CLEAR(RPDO->CANrxNew[0]); @@ -882,9 +878,8 @@ OD_write_18xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* uint16_t CAN_ID = (uint16_t)(COB_ID & 0x7FFU); bool_t valid = (COB_ID & 0x80000000U) == 0U; - /* bits 11...29 must be zero, PDO must be disabled on change, - * CAN_ID == 0 is not allowed, mapping must be configured before - * enabling the PDO */ + /* bits 11...29 must be zero, PDO must be disabled on change, CAN_ID == 0 is + * not allowed, mapping must be configured before enabling the PDO */ if (((COB_ID & 0x3FFFF800U) != 0U) || (valid && (PDO->valid && (CAN_ID != PDO->configuredCanId))) || (valid && CO_IS_RESTRICTED_CAN_ID(CAN_ID)) || (valid && (PDO->mappedObjectsCount == 0U))) { return ODR_INVALID_VALUE; @@ -1147,8 +1142,7 @@ CO_TPDOsend(CO_TPDO_t* TPDO) { dataTPDOCopy = dataTPDO; } - /* Set stream.dataOffset to zero, perform OD_IO.read() - * and store mappedLength back to stream.dataOffset */ + /* Set stream.dataOffset to zero, perform OD_IO.read() and store mappedLength back to stream.dataOffset */ stream->dataOffset = 0; OD_size_t countRd; OD_IO->read(stream, dataTPDOCopy, ODdataLength, &countRd); @@ -1252,7 +1246,7 @@ CO_TPDO_process(CO_TPDO_t* TPDO, } #endif } -#endif /*((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE)||(OD_FLAGS_PDO_SIZE>0)*/ +#endif /* ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE)||(OD_FLAGS_PDO_SIZE>0) */ /* Send PDO by application request or by Event timer */ if (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { @@ -1299,8 +1293,7 @@ CO_TPDO_process(CO_TPDO_t* TPDO, TPDO->syncCounter = (TPDO->transmissionType / 2U) + 1U; } } - /* If the syncStartValue is in use, start first TPDO after SYNC - * with matched syncStartValue. */ + /* If the syncStartValue is in use, start first TPDO after SYNC with matched syncStartValue. */ if (TPDO->syncCounter == 254U) { if (TPDO->SYNC->counter == TPDO->syncStartValue) { TPDO->syncCounter = TPDO->transmissionType; diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 8cad7b58..c86514ae 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -50,9 +50,8 @@ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_SDOclient_receive(void* object, void* msg) { @@ -94,8 +93,7 @@ CO_SDOclient_receive(void* object, void* msg) { /* is this the last segment? */ if ((data[0] & 0x80U) != 0U) { - /* copy data to temporary buffer, because we don't know the - * number of bytes not containing data */ + /* copy data to temporary buffer, because we don't know the number of bytes not containing data */ (void)memcpy((void*)&SDO_C->block_dataUploadLast[0], (const void*)&data[1], 7); SDO_C->finished = true; state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; @@ -110,9 +108,8 @@ CO_SDOclient_receive(void* object, void* msg) { } } } - /* If message is duplicate or sequence didn't start yet, ignore - * it. Otherwise seqno is wrong, so break sub-block. Data after - * last good seqno will be re-transmitted. */ + /* If message is duplicate or sequence didn't start yet, ignore it. Otherwise seqno is wrong, + * so break sub-block. Data after last good seqno will be re-transmitted. */ else if ((seqno != SDO_C->block_seqno) && (SDO_C->block_seqno != 0U)) { state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; #ifdef CO_DEBUG_SDO_CLIENT @@ -136,8 +133,7 @@ CO_SDOclient_receive(void* object, void* msg) { CO_FLAG_CLEAR(SDO_C->CANrxNew); SDO_C->state = state; #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 - /* Optional signal to RTOS, which can resume task, which handles - * SDO client processing. */ + /* Optional signal to RTOS, which can resume task, which handles SDO client processing. */ if (SDO_C->pFunctSignal != NULL) { SDO_C->pFunctSignal(SDO_C->functSignalObject); } @@ -383,8 +379,7 @@ CO_SDOclientDownloadInitiate(CO_SDOclient_t* SDO_C, uint16_t index, uint8_t subI CO_fifo_reset(&SDO_C->bufFifo); #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 - /* if node-ID of the SDO server is the same as node-ID of this node, then - * transfer data within this node */ + /* if node-ID of the SDO server is the same as node-ID of this node, then transfer data within this node */ if ((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U) && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId)) { SDO_C->OD_IO.write = NULL; SDO_C->state = CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER; @@ -442,7 +437,7 @@ CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t s ret = CO_SDO_RT_ok_communicationEnd; } #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 - /* Transfer data locally **************************************************/ + /* Transfer data locally */ else if ((SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER) && !send_abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.write == NULL) { @@ -499,10 +494,9 @@ CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t s #endif OD_size_t sizeInOd = SDO_C->OD_IO.stream.dataLength; - /* If dataType is string, then size of data downloaded may be - * shorter than size of OD data buffer. If so, add two zero - * bytes to terminate (unicode) string. Shorten also OD data - * size, (temporary, send info about EOF into OD_IO.write) */ + /* If dataType is string, then size of data downloaded may be shorter than size of + * OD data buffer. If so, add two zero bytes to terminate (unicode) string. Shorten + * also OD data size, (temporary, send info about EOF into OD_IO.write) */ if (((SDO_C->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) && ((sizeInOd == 0U) || (SDO_C->sizeTran < sizeInOd))) { buf[count] = 0; @@ -541,16 +535,14 @@ CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t s abortCode = (CO_SDO_abortCode_t)OD_getSDOabCode(odRet); ret = CO_SDO_RT_endedWithServerAbort; } - /* error if OD variable was written completely, - * but SDO download still has data */ + /* error if OD variable was written completely, but SDO download still has data */ else if (bufferPartial && (odRet == ODR_OK)) { abortCode = CO_SDO_AB_DATA_LONG; ret = CO_SDO_RT_endedWithClientAbort; } /* is end of transfer? */ else if (!bufferPartial) { - /* error if OD variable was not written completely, but SDO - * download finished */ + /* error if OD variable was not written completely, but SDO download finished */ if (odRet == ODR_PARTIAL) { abortCode = CO_SDO_AB_DATA_SHORT; ret = CO_SDO_RT_endedWithClientAbort; @@ -577,7 +569,7 @@ CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t s #endif } #endif /* CO_CONFIG_SDO_CLI_LOCAL */ - /* CAN data received ******************************************************/ + /* CAN data received */ else if (CO_FLAG_READ(SDO_C->CANrxNew)) { /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80U) { @@ -689,8 +681,7 @@ CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t s if (SDO_C->CANrxData[0] == 0xA2U) { /* check number of segments */ if (SDO_C->CANrxData[1] < SDO_C->block_seqno) { - /* NOT all segments transferred successfully. - * Re-transmit data after erroneous segment. */ + /* NOT all segments transferred successfully. Re-transmit data after erroneous segment. */ size_t cntFailed = (size_t)(SDO_C->block_seqno) - (size_t)(SDO_C->CANrxData[1]); cntFailed = (cntFailed * 7U) - SDO_C->block_noData; SDO_C->sizeTran -= cntFailed; @@ -778,7 +769,7 @@ CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t s } else { /* MISRA C 2004 14.10 */ } - /* Timeout timers and transmit bufferFull flag ****************************/ + /* Timeout timers and transmit bufferFull flag */ if (ret == CO_SDO_RT_waitingResponse) { if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { SDO_C->timeoutTimer += timeDifference_us; @@ -802,7 +793,7 @@ CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t s } } - /* Transmit CAN data ******************************************************/ + /* Transmit CAN data */ if (ret == CO_SDO_RT_waitingResponse) { size_t count; (void)memset((void*)&SDO_C->CANtxBuff->data[0], 0, 8); @@ -1070,8 +1061,7 @@ CO_SDOclientUploadInitiate(CO_SDOclient_t* SDO_C, uint16_t index, uint8_t subInd #endif #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 - /* if node-ID of the SDO server is the same as node-ID of this node, then - * transfer data within this node */ + /* if node-ID of the SDO server is the same as node-ID of this node, then transfer data within this node */ if (((SDO_C->OD != NULL) && (SDO_C->nodeId != 0U)) && (SDO_C->nodeIDOfTheSDOServer == SDO_C->nodeId)) { SDO_C->OD_IO.read = NULL; SDO_C->state = CO_SDO_ST_UPLOAD_LOCAL_TRANSFER; @@ -1107,7 +1097,7 @@ CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t sen ret = CO_SDO_RT_ok_communicationEnd; } #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0 - /* Transfer data locally **************************************************/ + /* Transfer data locally */ else if ((SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER) && !send_abort) { /* search object dictionary in first pass */ if (SDO_C->OD_IO.read == NULL) { @@ -1208,7 +1198,7 @@ CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t sen #endif } #endif /* CO_CONFIG_SDO_CLI_LOCAL */ - /* CAN data received ******************************************************/ + /* CAN data received */ else if (CO_FLAG_READ(SDO_C->CANrxNew)) { /* is SDO abort */ if (SDO_C->CANrxData[0] == 0x80U) { @@ -1481,7 +1471,7 @@ CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t sen } else { /* MISRA C 2004 14.10 */ } - /* Timeout timers and transmit bufferFull flag ****************************/ + /* Timeout timers and transmit bufferFull flag */ if (ret == CO_SDO_RT_waitingResponse) { if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) { SDO_C->timeoutTimer += timeDifference_us; @@ -1516,7 +1506,7 @@ CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t sen } if (SDO_C->block_timeoutTimer >= SDO_C->block_SDOtimeoutTime_us) { /* SDO_C->state will change, processing will continue in this - * thread. Make memory barrier here with CO_FLAG_CLEAR() call.*/ + * thread. Make memory barrier here with CO_FLAG_CLEAR() call. */ SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP; CO_FLAG_CLEAR(SDO_C->CANrxNew); } @@ -1538,7 +1528,7 @@ CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t sen } } - /* Transmit CAN data ******************************************************/ + /* Transmit CAN data */ if (ret == CO_SDO_RT_waitingResponse) { #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 size_t count; @@ -1613,7 +1603,7 @@ CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t sen SDO_C->block_seqno = 0; SDO_C->block_crc = 0; /* Block segments will be received in different thread. Make memory - * barrier here with CO_FLAG_CLEAR() call. */ + * barrier here with CO_FLAG_CLEAR() call. */ SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; CO_FLAG_CLEAR(SDO_C->CANrxNew); (void)CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff); @@ -1666,7 +1656,7 @@ CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t sen SDO_C->block_blksize = (uint8_t)count; SDO_C->block_seqno = 0; /* Block segments will be received in different thread. Make - * memory barrier here with CO_FLAG_CLEAR() call. */ + * memory barrier here with CO_FLAG_CLEAR() call. */ SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ; CO_FLAG_CLEAR(SDO_C->CANrxNew); } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index b1a8edee..511db99a 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -44,9 +44,8 @@ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_SDO_receive(void* object, void* msg) { @@ -94,9 +93,8 @@ CO_SDO_receive(void* object, void* msg) { state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; } } - /* If message is duplicate or sequence didn't start yet, ignore - * it. Otherwise seqno is wrong, so break sub-block. Data after - * last good seqno will be re-transmitted. */ + /* If message is duplicate or sequence didn't start yet, ignore it. Otherwise seqno is wrong, + * so break sub-block. Data after last good seqno will be re-transmitted. */ else if (seqno != SDO->block_seqno && SDO->block_seqno != 0U) { state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; #ifdef CO_DEBUG_SDO_SERVER @@ -114,14 +112,12 @@ CO_SDO_receive(void* object, void* msg) { #endif if (state != CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) { - /* SDO->state has changed, processing will continue in - * another thread. Make memory barrier here with - * CO_FLAG_CLEAR() call. */ + /* SDO->state has changed, processing will continue in another thread. + * Make memory barrier here with CO_FLAG_CLEAR() call. */ CO_FLAG_CLEAR(SDO->CANrxNew); SDO->state = state; #if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 - /* Optional signal to RTOS, which can resume task, which - * handles SDO server processing. */ + /* Optional signal to RTOS, which can resume task, which handles SDO server processing. */ if (SDO->pFunctSignalPre != NULL) { SDO->pFunctSignalPre(SDO->functSignalObjectPre); } @@ -133,13 +129,11 @@ CO_SDO_receive(void* object, void* msg) { } #endif /* (CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK */ else { - /* copy data and set 'new message' flag, data will be processed in - * CO_SDOserver_process() */ + /* copy data and set 'new message' flag, data will be processed in CO_SDOserver_process() */ (void)memcpy(SDO->CANrxData, data, DLC); CO_FLAG_SET(SDO->CANrxNew); #if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 - /* Optional signal to RTOS, which can resume task, which handles - * SDO server processing. */ + /* Optional signal to RTOS, which can resume task, which handles SDO server processing. */ if (SDO->pFunctSignalPre != NULL) { SDO->pFunctSignalPre(SDO->functSignalObjectPre); } @@ -148,7 +142,7 @@ CO_SDO_receive(void* object, void* msg) { } } -/* helper for configuring CANrx and CANtx *************************************/ +/* helper for configuring CANrx and CANtx */ static CO_ReturnError_t CO_SDOserver_init_canRxTx(CO_SDOserver_t* SDO, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, uint16_t CANdevTxIdx, uint32_t COB_IDClientToServer, uint32_t COB_IDServerToClient) { @@ -189,8 +183,7 @@ CO_SDOserver_init_canRxTx(CO_SDOserver_t* SDO, CO_CANmodule_t* CANdevRx, uint16_ #if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* - * Custom function for writing OD object _SDO server parameter_, additional - * channels + * Custom function for writing OD object _SDO server parameter_, additional channels * * For more information see file CO_ODinterface.h, OD_IO_t. */ @@ -392,17 +385,15 @@ reverseBytes(void* start, OD_size_t size) { #endif #if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 -/** Helper function for writing data to Object dictionary. Function swaps data - * if necessary, calcualtes (and verifies CRC) writes data to OD and verifies - * data lengths. +/* Helper function for writing data to Object dictionary. Function swaps data if necessary, + * calcualtes (and verifies CRC) writes data to OD and verifies data lengths. * * @param SDO SDO server * @param [out] abortCode SDO abort code in case of error * @param crcOperation 0=none, 1=calculate, 2=calculate and compare * @parma crcClient crc checksum to campare with * - * Returns true on success, otherwise write also abortCode and sets state to - * CO_SDO_ST_ABORT */ + * Returns true on success, otherwise write also abortCode and sets state to CO_SDO_ST_ABORT */ static bool_t validateAndWriteToOD(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, uint8_t crcOperation, uint16_t crcClient) { OD_size_t bufOffsetWrOrig = SDO->bufOffsetWr; @@ -424,10 +415,9 @@ validateAndWriteToOD(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, uint8_t OD_size_t sizeInOd = SDO->OD_IO.stream.dataLength; - /* If dataType is string, then size of data downloaded may be - * shorter than size of OD data buffer. If so, add two zero bytes - * to terminate (unicode) string. Shorten also OD data size, - * (temporary, send information about EOF into OD_IO.write) */ + /* If dataType is string, then size of data downloaded may be shorter than size of the + * OD data buffer. If so, add two zero bytes to terminate (unicode) string. Shorten + * also OD data size, (temporary, send information about EOF into OD_IO.write) */ if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) && ((sizeInOd == 0U) || (SDO->sizeTran < sizeInOd)) && ((SDO->bufOffsetWr + 2U) <= CO_CONFIG_SDO_SRV_BUFFER_SIZE)) { @@ -441,7 +431,7 @@ validateAndWriteToOD(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, uint8_t } SDO->OD_IO.stream.dataLength = SDO->sizeTran; } - /* Indicate OD data size, if not indicated. Can be used for EOF check.*/ + /* Indicate OD data size, if not indicated. Can be used for EOF check. */ else if (sizeInOd == 0U) { SDO->OD_IO.stream.dataLength = SDO->sizeTran; } @@ -497,7 +487,7 @@ validateAndWriteToOD(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, uint8_t SDO->state = CO_SDO_ST_ABORT; return false; } else if (!SDO->finished && (odRet == ODR_OK)) { - /* OD variable was written completely, but SDO download still has data*/ + /* OD variable was written completely, but SDO download still has data */ *abortCode = CO_SDO_AB_DATA_LONG; SDO->state = CO_SDO_ST_ABORT; return false; @@ -507,17 +497,14 @@ validateAndWriteToOD(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, uint8_t return true; } -/** Helper function for reading data from Object dictionary. Function also swaps - * data if necessary and calcualtes CRC. +/* Helper function for reading data from Object dictionary. Function also swaps data if necessary and calcualtes CRC. * * @param SDO SDO server * @param [out] abortCode SDO abort code in case of error - * @parma countMinimum if data size in buffer is less than countMinimum, then - * buffer is refilled from OD variable + * @parma countMinimum if data size in buffer is less than countMinimum, then buffer is refilled from OD variable * @param calculateCrc if true, crc is calculated * - * Returns true on success, otherwise write also abortCode and sets state to - * CO_SDO_ST_ABORT */ + * Returns true on success, otherwise write also abortCode and sets state to CO_SDO_ST_ABORT */ static bool_t readFromOd(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, OD_size_t countMinimum, bool_t calculateCrc) { #if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) == 0 @@ -618,8 +605,7 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t /* Idle and nothing new */ ret = CO_SDO_RT_ok_communicationEnd; } else if (!NMTisPreOrOperational || !SDO->valid) { - /* SDO is allowed only in operational or pre-operational NMT state - * and must be valid */ + /* SDO is allowed only in operational or pre-operational NMT state and must be valid */ SDO->state = CO_SDO_ST_IDLE; CO_FLAG_CLEAR(SDO->CANrxNew); ret = CO_SDO_RT_ok_communicationEnd; @@ -735,10 +721,9 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t } #endif - /* If dataType is string, then size of data downloaded may be - * shorter as size of OD data buffer. If so, add two zero bytes - * to terminate (unicode) string. Shorten also OD data size, - * (temporary, send information about EOF into OD_IO.write) */ + /* If dataType is string, then size of data downloaded may be shorter as size of + * the OD data buffer. If so, add two zero bytes to terminate (unicode) string. + * Shorten also OD data size, (temporary, send information about EOF into OD_IO.write) */ if (((SDO->OD_IO.stream.attribute & (OD_attr_t)ODA_STR) != 0U) && ((sizeInOd == 0U) || (dataSizeToWrite < sizeInOd))) { OD_size_t delta = sizeInOd - dataSizeToWrite; @@ -918,8 +903,7 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: { if ((SDO->CANrxData[0] & 0xE3) == 0xC1) { - /* Get number of data bytes in last segment, that do not - * contain data. Then reduce buffer. */ + /* Get number of data bytes in last segment, that do not contain data. Then reduce buffer. */ uint8_t noData = ((SDO->CANrxData[0] >> 2) & 0x07); if (SDO->bufOffsetWr <= noData) { /* just in case, should never happen */ @@ -950,7 +934,7 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: { /* if pst (protocol switch threshold, byte5) is larger than data - * size of OD variable, then switch to segmented transfer */ + * size of OD variable, then switch to segmented transfer */ if (SDO->sizeInd > 0 && SDO->CANrxData[5] > 0 && SDO->CANrxData[5] >= SDO->sizeInd) { SDO->state = CO_SDO_ST_UPLOAD_INITIATE_RSP; } else { @@ -1004,8 +988,7 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t /* check number of segments */ if (SDO->CANrxData[1] < SDO->block_seqno) { - /* NOT all segments transferred successfully. - * Re-transmit data after erroneous segment. */ + /* NOT all segments transferred successfully. Re-transmit data after erroneous segment. */ OD_size_t cntFailed = SDO->block_seqno - SDO->CANrxData[1]; cntFailed = cntFailed * 7 - SDO->block_noData; SDO->bufOffsetRd -= cntFailed; @@ -1109,7 +1092,7 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t } if (SDO->block_timeoutTimer >= SDO->block_SDOtimeoutTime_us) { /* SDO->state will change, processing will continue in this - * thread. Make memory barrier here with CO_FLAG_CLEAR() call.*/ + * thread. Make memory barrier here with CO_FLAG_CLEAR() call. */ SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP; CO_FLAG_CLEAR(SDO->CANrxNew); } @@ -1323,7 +1306,7 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t SDO->block_timeoutTimer = 0; /* Block segments will be received in different thread. Make memory - * barrier here with CO_FLAG_CLEAR() call. */ + * barrier here with CO_FLAG_CLEAR() call. */ SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; CO_FLAG_CLEAR(SDO->CANrxNew); (void)CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff); @@ -1362,7 +1345,7 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t SDO->block_blksize = (uint8_t)count; SDO->block_seqno = 0; /* Block segments will be received in different thread. Make - * memory barrier here with CO_FLAG_CLEAR() call. */ + * memory barrier here with CO_FLAG_CLEAR() call. */ SDO->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ; CO_FLAG_CLEAR(SDO->CANrxNew); } diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index 19874b3c..a9062380 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -25,9 +25,8 @@ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_SYNC_receive(void* object, void* msg) { @@ -58,7 +57,7 @@ CO_SYNC_receive(void* object, void* msg) { CO_FLAG_SET(SYNC->CANrxNew); #if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 - /* Optional signal to RTOS, which can resume task, which handles SYNC.*/ + /* Optional signal to RTOS, which can resume task, which handles SYNC. */ if (SYNC->pFunctSignalPre != NULL) { SYNC->pFunctSignalPre(SYNC->functSignalObjectPre); } @@ -237,8 +236,7 @@ CO_SYNC_init(CO_SYNC_t* SYNC, CO_EM_t* em, OD_entry_t* OD_1005_cobIdSync, OD_ent return CO_ERROR_OD_PARAMETERS; } - /* get and verify optional "Synchronous counter overflow value" from OD and - * configure extension */ + /* get and verify optional "Synchronous counter overflow value" from OD and configure extension */ uint8_t syncCounterOvf = 0; if (OD_1019_syncCounterOvf != NULL) { diff --git a/301/CO_TIME.c b/301/CO_TIME.c index 8b8e6b2d..499271cd 100644 --- a/301/CO_TIME.c +++ b/301/CO_TIME.c @@ -27,9 +27,8 @@ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_TIME_receive(void* object, void* msg) { @@ -42,7 +41,7 @@ CO_TIME_receive(void* object, void* msg) { CO_FLAG_SET(TIME->CANrxNew); #if ((CO_CONFIG_TIME)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 - /* Optional signal to RTOS, which can resume task, which handles TIME.*/ + /* Optional signal to RTOS, which can resume task, which handles TIME. */ if (TIME->pFunctSignalPre != NULL) { TIME->pFunctSignalPre(TIME->functSignalObjectPre); } diff --git a/301/CO_fifo.c b/301/CO_fifo.c index e7ccd135..cadb7446 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -430,7 +430,7 @@ CO_fifo_readToken(CO_fifo_t* fifo, char* buf, size_t count, uint8_t* closed, boo *closed = delimCommandFound ? 1U : 0U; } - /* token was larger then size of the buffer, all was cleaned, return empty*/ + /* token was larger then size of the buffer, all was cleaned, return empty */ if (tokenSize == count) { tokenSize = 0; } @@ -444,11 +444,10 @@ CO_fifo_readToken(CO_fifo_t* fifo, char* buf, size_t count, uint8_t* closed, boo #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ #if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_DATATYPES) != 0 -/* Tables for mime-base64 encoding, as specified in RFC 2045, (without CR-LF, - * but one long string). Base64 is used for encoding binary data into easy - * transferable printable characters. In general, each three bytes of binary - * data are translated into four characters, where characters are selected from - * 64 characters long table. See https://en.wikipedia.org/wiki/Base64 */ +/* Tables for mime-base64 encoding, as specified in RFC 2045, (without CR-LF, but one long string). + * Base64 is used for encoding binary data into easy transferable printable characters. In general, + * each three bytes of binary data are translated into four characters, where characters are + * selected from 64 characters long table. See https://en.wikipedia.org/wiki/Base64 */ static const char base64EncTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const uint8_t base64DecTable[] = { @@ -1257,8 +1256,7 @@ CO_fifo_cpyTok2Vs(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { step = (uint8_t)dest->aux; } - /* repeat until destination space available and no error and not finished - * and source characters available */ + /* repeat until destination space available and no error and not finished and source characters available */ while ((destSpace > 0U) && ((st & CO_fifo_st_errMask) == 0U) && !finished) { uint8_t c; if (!CO_fifo_getc(src, &c)) { @@ -1283,7 +1281,7 @@ CO_fifo_cpyTok2Vs(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { case 2: /* inside string, single word, no quotes */ if (c == DELIM_DQUOTE) { /* double quote found, this may be end of the string or escaped - * double quote (with two double quotes) */ + * double quote (with two double quotes) */ step += 2U; } else if ((isgraph((int)c) == 0) && (step == 2U)) { /* end of single word string */ @@ -1410,8 +1408,7 @@ CO_fifo_cpyTok2B64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status) { dword = dest->aux & 0xFFFFFFU; } - /* repeat until destination space available and no error and not finished - * and source characters available */ + /* repeat until destination space available and no error and not finished and source characters available */ while ((destSpace >= 3U) && ((st & CO_fifo_st_errMask) == 0U) && !finished) { uint8_t c; if (!CO_fifo_getc(src, &c)) { diff --git a/304/CO_GFC.c b/304/CO_GFC.c index bbf6dde0..86743e30 100644 --- a/304/CO_GFC.c +++ b/304/CO_GFC.c @@ -1,4 +1,4 @@ -/** +/* * CANopen Global fail-safe command protocol. * * @file CO_GFC.c diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 003e5e3e..f8992f4c 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -1,4 +1,4 @@ -/** +/* * CANopen Safety Related Data Object protocol. * * @file CO_SRDO.c @@ -138,7 +138,8 @@ OD_read_dummy(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countR #ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION static bool_t OD_not_write_same_value(OD_stream_t* stream, const void* buf, OD_size_t count) { - // The conformance test tool does not recognize CANopen Safety and on all object dictionaty tries to read and write the same value + /* The conformance test tool does not recognize CANopen Safety and on all object + * dictionaty tries to read and write the same value */ OD_size_t countRead = 0; uint8_t bufRead[6] = {0}; if (count > 6U) { @@ -379,8 +380,7 @@ CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationVa SRDOGuard->OD_13FF_extension.write = OD_write_13FF; (void)OD_extension_init(OD_13FF_safetyConfigurationSignature, &SRDOGuard->OD_13FF_extension); - /* Configure SRDOGuard->OD_IO_configurationValid variable. - * It will be used for writing 0 to OD variable 13FE,00 */ + /* Configure SRDOGuard->OD_IO_configurationValid variable. It will be used for writing 0 to OD variable 13FE,00 */ odRet = OD_getSub(OD_13FE_configurationValid, 0, &SRDOGuard->OD_IO_configurationValid, false); if ((odRet != ODR_OK) || (SRDOGuard->OD_IO_configurationValid.stream.dataLength != 1U)) { if (errInfo != NULL) { @@ -734,7 +734,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext /* Detect transition to NMT operational */ if (!SRDO->NMTisOperationalPrevious) { SRDO->cycleTimer = (SRDO->informationDirection == CO_SRDO_TX) - ? ((uint32_t)SRDO->nodeId * 500U) /* 0.5ms * node-ID delay*/ + ? ((uint32_t)SRDO->nodeId * 500U) /* 0.5ms * node-ID delay */ : SRDO->cycleTime_us; SRDO->validationTimer = SRDO->cycleTime_us; SRDO->internalState = CO_SRDO_state_initializing; diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 1e78c0ac..35df2390 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -28,19 +28,17 @@ /* * @defgroup CO_LSSmaster_state_t * @{ - * LSS master slave select state machine. Compared to #CO_LSS_state_t this - * has information if we currently have selected one or all slaves. This - * allows for some basic error checking. + * LSS master slave select state machine. Compared to #CO_LSS_state_t this has information if we + * currently have selected one or all slaves. This allows for some basic error checking. */ #define CO_LSSmaster_STATE_WAITING 0x00U #define CO_LSSmaster_STATE_CFG_SLECTIVE 0x01U #define CO_LSSmaster_STATE_CFG_GLOBAL 0x02U -/** @} */ /* CO_LSSmaster_state_t */ +/* @} */ /* CO_LSSmaster_state_t */ /* * @defgroup CO_LSSmaster_command_t LSS master slave command state machine * @{ - * */ #define CO_LSSmaster_COMMAND_WAITING 0x00U #define CO_LSSmaster_COMMAND_SWITCH_STATE 0x01U @@ -53,7 +51,7 @@ #define CO_LSSmaster_COMMAND_INQUIRE_SERIAL 0x08U #define CO_LSSmaster_COMMAND_INQUIRE 0x09U #define CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN 0x0AU -/** @} */ /* CO_LSSmaster_command_t */ +/* @} */ /* CO_LSSmaster_command_t */ /* * @defgroup CO_LSSmaster_fs_t LSS master fastscan state machine @@ -63,14 +61,13 @@ #define CO_LSSmaster_FS_STATE_SCAN 0x01U #define CO_LSSmaster_FS_STATE_VERIFY 0x02U -/** @} */ /* CO_LSSmaster_fs_t */ +/* @} */ /* CO_LSSmaster_fs_t */ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_LSSmaster_receive(void* object, void* msg) { @@ -80,7 +77,7 @@ CO_LSSmaster_receive(void* object, void* msg) { LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */ - /* verify message length and message overflow (previous message was not processed yet) */ + /* verify message length and message overflow (previous message was not processed yet). */ if ((DLC == 8U) && !CO_FLAG_READ(LSSmaster->CANrxNew) && (LSSmaster->command != CO_LSSmaster_COMMAND_WAITING)) { /* copy data and set 'new message' flag */ @@ -100,9 +97,8 @@ CO_LSSmaster_receive(void* object, void* msg) { /* * Check LSS timeout. * - * Generally, we do not really care if the message has been received before - * or after the timeout expired. Only if no message has been received we have - * to check for timeouts + * Generally, we do not really care if the message has been received before or after the timeout + * expired. Only if no message has been received we have to check for timeouts. */ static inline CO_LSSmaster_return_t CO_LSSmaster_check_timeout(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us) { @@ -304,9 +300,8 @@ CO_LSSmaster_swStateDeselect(CO_LSSmaster_t* LSSmaster) { * - byte 0 -> cs * - byte 1 -> Error Code, where * - 0 = OK - * - 1 .. FE = Values defined by CiA. All currently defined values - * are slave rejects. No further distinction on why the - * slave did reject the request. + * - 1 .. FE = Values defined by CiA. All currently defined values are slave rejects. + * No further distinction on why the slave did reject the request. * - FF = Manufacturer Error Code in byte 2 * - byte 2 -> Manufacturer Error, currently not used * @@ -791,8 +786,7 @@ CO_LSSmaster_FsVerifyInitiate(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference } /* - * Helper function - verify 32 bit LSS address, request node(s) to switch - * their state machine to the next state + * Helper function - verify 32 bit LSS address, request node(s) to switch their state machine to the next state */ static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSSmaster_scantype_t scan, @@ -833,15 +827,13 @@ CO_LSSmaster_FsSearchNext(CO_LSSmaster_t* LSSmaster, const CO_LSSmaster_fastscan uint8_t i; /* we search for the next LSS address part to scan for, beginning with the - * one after the current one. If there is none remaining, scanning is - * finished */ + * one after the current one. If there is none remaining, scanning is finished */ for (i = LSSmaster->fsLssSub + 1U; i <= CO_LSS_FASTSCAN_SERIAL; i++) { if (fastscan->scan[i] != CO_LSSmaster_FS_SKIP) { return i; } } - /* node selection is triggered by switching node state machine back - * to initial state */ + /* node selection is triggered by switching node state machine back to initial state */ return CO_LSS_FASTSCAN_VENDOR_ID; } @@ -894,7 +886,8 @@ CO_LSSmaster_IdentifyFastscan(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference /* continue with evaluating fastscan state machine */ } - /* evaluate fastscan state machine. The state machine is evaluated as following + /* + * evaluate fastscan state machine. The state machine is evaluated as following * - check for non-configured nodes * - scan for vendor ID * - verify vendor ID, switch node state @@ -904,9 +897,9 @@ CO_LSSmaster_IdentifyFastscan(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference * - verify revision number, switch node state * - scan for serial number * - verify serial number, switch node to LSS configuration mode - * Certain steps can be skipped as mentioned in the function description. - * If one step is not ack'ed by a node, the scanning process is terminated - * and the correspondign error is returned. */ + * Certain steps can be skipped as mentioned in the function description. If one step is + * not ack'ed by a node, the scanning process is terminated and the correspondign error is returned. + */ switch (LSSmaster->fsState) { case CO_LSSmaster_FS_STATE_CHECK: ret = CO_LSSmaster_FsCheckWait(LSSmaster, timeDifference_us); @@ -924,9 +917,8 @@ CO_LSSmaster_IdentifyFastscan(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference case CO_LSSmaster_FS_STATE_SCAN: ret = CO_LSSmaster_FsScanWait(LSSmaster, timeDifference_us, fastscan->scan[LSSmaster->fsLssSub]); if (ret == CO_LSSmaster_SCAN_FINISHED) { - /* scanning finished, initiate verifcation. The verification - * message also contains the node state machine "switch to - * next state" request */ + /* scanning finished, initiate verifcation. The verification message also contains + * the node state machine "switch to next state" request */ next = CO_LSSmaster_FsSearchNext(LSSmaster, fastscan); ret = CO_LSSmaster_FsVerifyInitiate(LSSmaster, timeDifference_us, fastscan->scan[LSSmaster->fsLssSub], fastscan->match.addr[LSSmaster->fsLssSub], next); @@ -940,19 +932,16 @@ CO_LSSmaster_IdentifyFastscan(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference if (ret == CO_LSSmaster_SCAN_FINISHED) { /* verification successful: * - assumed node id is correct - * - node state machine has switched to the requested state, - * mirror that in the local copy */ + * - node state machine has switched to the requested state, mirror that in the local copy */ next = CO_LSSmaster_FsSearchNext(LSSmaster, fastscan); if (next == CO_LSS_FASTSCAN_VENDOR_ID) { - /* fastscan finished, one node is now in LSS configuration - * mode */ + /* fastscan finished, one node is now in LSS configuration mode */ LSSmaster->state = CO_LSSmaster_STATE_CFG_SLECTIVE; } else { /* initiate scan for next part of LSS address */ ret = CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_us, fastscan->scan[next], next); if (ret == CO_LSSmaster_SCAN_FINISHED) { - /* Scanning is not requested. Initiate verification - * step in next function call */ + /* Scanning is not requested. Initiate verification step in next function call */ ret = CO_LSSmaster_WAIT_SLAVE; } diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 10125fed..81d9aaec 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -36,9 +36,8 @@ /* * Read received message from CAN module. * - * Function will be called (by CAN receive interrupt) every time, when CAN - * message with correct identifier will be received. For more information and - * description of parameters see file CO_driver.h. + * Function will be called (by CAN receive interrupt) every time, when CAN message with correct identifier + * will be received. For more information and description of parameters see file CO_driver.h. */ static void CO_LSSslave_receive(void* object, void* msg) { @@ -58,7 +57,7 @@ CO_LSSslave_receive(void* object, void* msg) { if ((LSSslave->lssState == CO_LSS_STATE_CONFIGURATION) && (LSSslave->activeNodeID == CO_LSS_NODE_ID_ASSIGNMENT) && (*LSSslave->pendingNodeID != CO_LSS_NODE_ID_ASSIGNMENT)) { - /* Slave process function will request NMT Reset comm.*/ + /* Slave process function will request NMT Reset comm. */ LSSslave->service = cs; request_LSSslave_process = true; } @@ -170,8 +169,7 @@ CO_LSSslave_receive(void* object, void* msg) { if (request_LSSslave_process) { CO_FLAG_SET(LSSslave->sendResponse); #if ((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 - /* Optional signal to RTOS, which can resume task, - * which handles further processing. */ + /* Optional signal to RTOS, which can resume task, which handles further processing. */ if (LSSslave->pFunctSignalPre != NULL) { LSSslave->pFunctSignalPre(LSSslave->functSignalObjectPre); } diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index 7fd45c3d..b88d17c6 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -312,8 +312,8 @@ static const CO_GTWA_dataType_t dataTypes[] = { {(char*)"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */ {(char*)"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */ {(char*)"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}, /* VISIBLE_STRING */ - {(char*)"os", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* OCTET_STRING base64*/ - {(char*)"us", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* UNICODE_STRING base64*/ + {(char*)"os", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* OCTET_STRING base64 */ + {(char*)"us", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* UNICODE_STRING base64 */ {(char*)"d", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64} /* DOMAIN - base64 */ }; @@ -577,8 +577,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint return; } - /* If there is some more output data for application, read them first. - * Hold on this state, if necessary. */ + /* If there is some more output data for application, read them first. Hold on this state, if necessary. */ if (gtwa->respHold) { timeDifference_us += gtwa->timeDifference_us_cumulative; @@ -606,8 +605,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint /* parse mandatory token '"[""]"' */ closed = 0xFFU; n = CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); - /* Break if error in token or token was found, but closed with - * command delimiter. */ + /* Break if error in token or token was found, but closed with command delimiter. */ if (err || ((n > 0U) && (closed != 0U))) { err = true; break; @@ -1053,7 +1051,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint } } - /* NMT reset (node or communication) - 'reset '*/ + /* NMT reset (node or communication) - 'reset ' */ else if (tok_is_reset) { CO_ReturnError_t ret; bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode); @@ -1208,8 +1206,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint break; } - /* First parameter is table selector. We only support the CiA - * bit timing table from CiA301 ("0") */ + /* First parameter is table selector. We only support the CiA bit timing table from CiA301 ("0") */ closed = 0U; (void)CO_fifo_readToken(>wa->commFifo, tok, sizeof(tok), &closed, &err); (void)getU32(tok, 0, 0, &err); @@ -1303,7 +1300,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint gtwa->state = CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL; } } - /* LSS inquire node-ID command - 'lss_get_node'*/ + /* LSS inquire node-ID command - 'lss_get_node' */ else if (tok_is_lss_get_node) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); @@ -1317,7 +1314,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint gtwa->state = CO_GTWA_ST_LSS_INQUIRE; } /* LSS identify fastscan. This is a manufacturer specific command as - * the one in DSP309 is quite useless - '_lss_fastscan []'*/ + * the one in DSP309 is quite useless - '_lss_fastscan []' */ else if (tok_is__lss_fastscan) { bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t timeout_ms = 0; @@ -1354,17 +1351,14 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint * * ]]' */ else if (tok_is_lss_allnodes) { - /* Request node enumeration by LSS identify fastscan. - * This initiates node enumeration by the means of LSS fastscan - * mechanism. When this function is finished: - * - All nodes that match the given criteria are assigned a node ID - * beginning with nodeId. If 127 is reached, the process - * is stopped, no matter if there are nodes remaining or not. + /* Request node enumeration by LSS identify fastscan. This initiates node enumeration + * by the means of LSS fastscan mechanism. When this function is finished: + * - All nodes that match the given criteria are assigned a node ID beginning with nodeId. + * If 127 is reached, the process is stopped, no matter if there are nodes remaining or not. * - No IDs are assigned because: * - the given criteria do not match any node, * - all nodes are already configured. - * This function needs that no node is selected when starting the - * scan process. */ + * This function needs that no node is selected when starting the scan process. */ bool_t NodeErr = checkNet(gtwa, net, &respErrorCode); uint16_t timeout_ms = 0; @@ -1389,8 +1383,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint gtwa->lssSubState = 0; if (closed == 1U) { - /* No other arguments, as by CiA specification for this command. - * Do full scan. */ + /* No other arguments, as by CiA specification for this command. Do full scan. */ /* use start node ID 2. Should work in most cases */ gtwa->lssNID = 2; /* store node ID in node's NVM */ @@ -1587,10 +1580,10 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint } /* Empty SDO fifo buffer in multiple cycles. Repeat until - * application runs out of space (respHold) or fifo empty. */ + * application runs out of space (respHold) or fifo empty. */ do { /* read SDO fifo (partially) and print specific data type as - * ascii into intermediate respBuf */ + * ascii into intermediate respBuf */ gtwa->respBufCount += gtwa->SDOdataType->dataTypePrint( >wa->SDO_C->bufFifo, >wa->respBuf[gtwa->respBufCount], (CO_GTWA_RESP_BUF_SIZE - 2U) - gtwa->respBufCount, ret == CO_SDO_RT_ok_communicationEnd); @@ -1645,8 +1638,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint } } if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) { - /* Stay in this state, until all data transferred via commFifo - * will be purged. */ + /* Stay in this state, until all data transferred via commFifo will be purged. */ if (!CO_fifo_purge(>wa->SDO_C->bufFifo) || (closed == 1U)) { gtwa->state = CO_GTWA_ST_IDLE; } @@ -1654,8 +1646,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint } } /* If not all data were transferred, make sure, there is enough data in - * SDO buffer, to continue communication. Otherwise wait and check for - * timeout */ + * SDO buffer, to continue communication. Otherwise wait and check for timeout */ if (gtwa->SDOdataCopyStatus) { if (CO_fifo_getOccupied(>wa->SDO_C->bufFifo) < (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7U)) { if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) { @@ -2001,8 +1992,7 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint } /* switch (gtwa->state) */ } - /* execute next CANopen processing immediately, if idle and more commands - * available */ + /* execute next CANopen processing immediately, if idle and more commands available */ if ((timerNext_us != NULL) && (gtwa->state == CO_GTWA_ST_IDLE)) { if (CO_fifo_CommSearch(>wa->commFifo, false)) { *timerNext_us = 0; diff --git a/CANopen.c b/CANopen.c index 220e97f7..39eeac7c 100644 --- a/CANopen.c +++ b/CANopen.c @@ -37,8 +37,7 @@ * - calculate number of CANrx and CYNtx messages: CO_RX_CNT_xx and CO_TX_CNT_xx * - set optional undefined OD_ENTRY_Hxxxx to NULL. * - calculate indexes: CO_RX_IDX_xx and CO_TX_IDX_xx - * - calculate total count of CAN message buffers: CO_CNT_ALL_RX_MSGS and - * CO_CNT_ALL_TX_MSGS. */ + * - calculate total count of CAN message buffers: CO_CNT_ALL_RX_MSGS and CO_CNT_ALL_TX_MSGS. */ #if OD_CNT_NMT != 1 #error OD_CNT_NMT from OD.h not correct! #endif @@ -264,9 +263,8 @@ #endif #endif -/* Indexes of CO_CANrx_t and CO_CANtx_t objects in CO_CANmodule_t and total - * number of them. Indexes are sorted in a way, that objects with highest - * priority of the CAN identifier are listed first. */ +/* Indexes of CO_CANrx_t and CO_CANtx_t objects in CO_CANmodule_t and total number of them. Indexes + * are sorted in a way, that objects with highest priority of the CAN identifier are listed first. */ #define CO_RX_IDX_NMT_SLV 0U #define CO_RX_IDX_GFC (CO_RX_IDX_NMT_SLV + (uint16_t)CO_RX_CNT_NMT_SLV) #define CO_RX_IDX_SYNC (CO_RX_IDX_GFC + (uint16_t)CO_RX_CNT_GFC) @@ -315,10 +313,7 @@ #undef CO_free #endif -/* - * Allocate memory for number of elements, each of specific size - * Allocated memory must be reset to all zeros - */ +/* Allocate memory for number of elements, each of specific size Allocated memory must be reset to all zeros */ #define CO_alloc(num, size) calloc((num), (size)) #define CO_free(ptr) free((ptr)) @@ -354,9 +349,7 @@ CO_new(CO_config_t* config, uint32_t* heapMemoryUsed) { * - use config structure * - calculate number of CANrx and CYNtx messages: RX_CNT_xx and TX_CNT_xx * - calculate indexes: RX_IDX_xx and TX_IDX_xx - * - calculate total count of CAN message buffers: CNT_ALL_RX_MSGS and - * CNT_ALL_TX_MSGS. */ - + * - calculate total count of CAN message buffers: CNT_ALL_RX_MSGS and CNT_ALL_TX_MSGS. */ do { #ifdef CO_MULTIPLE_OD /* verify arguments */ @@ -546,9 +539,8 @@ CO_new(CO_config_t* config, uint32_t* heapMemoryUsed) { #endif #ifdef CO_MULTIPLE_OD - /* Indexes of CO_CANrx_t and CO_CANtx_t objects in CO_CANmodule_t and - * total number of them. Indexes are sorted in a way, that objects with - * highest priority of the CAN identifier are listed first. */ + /* Indexes of CO_CANrx_t and CO_CANtx_t objects in CO_CANmodule_t and total number of them. Indexes + * are sorted in a way, that objects with highest priority of the CAN identifier are listed first. */ int16_t idxRx = 0; co->RX_IDX_NMT_SLV = idxRx; idxRx += RX_CNT_NMT_SLV; @@ -930,7 +922,6 @@ CO_isLSSslaveEnabled(CO_t* co) { return en; } -/******************************************************************************/ CO_ReturnError_t CO_CANinit(CO_t* co, void* CANptr, uint16_t bitRate) { CO_ReturnError_t err; @@ -949,7 +940,6 @@ CO_CANinit(CO_t* co, void* CANptr, uint16_t bitRate) { return err; } -/******************************************************************************/ #if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 CO_ReturnError_t CO_LSSinit(CO_t* co, CO_LSS_address_t* lssAddress, uint8_t* pendingNodeID, uint16_t* pendingBitRate) { @@ -968,7 +958,6 @@ CO_LSSinit(CO_t* co, CO_LSS_address_t* lssAddress, uint8_t* pendingNodeID, uint1 } #endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE */ -/******************************************************************************/ CO_ReturnError_t CO_CANopenInit(CO_t* co, CO_NMT_t* NMT, CO_EM_t* em, OD_t* od, OD_entry_t* OD_statusBits, uint16_t NMTcontrol, uint16_t firstHBTime_ms, uint16_t SDOserverTimeoutTime_ms, uint16_t SDOclientTimeoutTime_ms, @@ -1194,7 +1183,6 @@ CO_CANopenInit(CO_t* co, CO_NMT_t* NMT, CO_EM_t* em, OD_t* od, OD_entry_t* OD_st return CO_ERROR_NO; } -/******************************************************************************/ CO_ReturnError_t CO_CANopenInitPDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo) { if (co == NULL) { @@ -1267,7 +1255,6 @@ CO_CANopenInitPDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* err return CO_ERROR_NO; } -/******************************************************************************/ #if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) CO_ReturnError_t CO_CANopenInitSRDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo) { @@ -1320,7 +1307,6 @@ CO_CANopenInitSRDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* er } #endif -/******************************************************************************/ CO_NMT_reset_cmd_t CO_process(CO_t* co, bool_t enableGateway, uint32_t timeDifference_us, uint32_t* timerNext_us) { (void)enableGateway; /* may be unused */ @@ -1417,7 +1403,6 @@ CO_process(CO_t* co, bool_t enableGateway, uint32_t timeDifference_us, uint32_t* return reset; } -/******************************************************************************/ #if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0 bool_t CO_process_SYNC(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us) { @@ -1444,7 +1429,6 @@ CO_process_SYNC(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us) { } #endif -/******************************************************************************/ #if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 void CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us) { @@ -1466,7 +1450,6 @@ CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* } #endif -/******************************************************************************/ #if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 void CO_process_TPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us) { @@ -1488,7 +1471,6 @@ CO_process_TPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* } #endif -/******************************************************************************/ #if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 CO_SRDO_state_t CO_process_SRDO(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us) { diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index f2f31ab2..d6656c6b 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -75,10 +75,10 @@ If OD object has OD extension enabled, then direct access to its OD variables mu #include ODxyz.h void myFuncGlob(void) { - //Direct address instead of OD_find() + /* Direct address instead of OD_find() */ OD_entry_t *entry_errReg = ODxyz_1001_errorRegister; - //Direct access to OD variable + /* Direct access to OD variable */ uint32_t devType = ODxyz_0.x1000_deviceType; ODxyz_0.x1018_identity.serialNumber = 0x12345678; } diff --git a/example/CO_driver_blank.c b/example/CO_driver_blank.c index fef5822d..7eeeddc2 100644 --- a/example/CO_driver_blank.c +++ b/example/CO_driver_blank.c @@ -134,8 +134,7 @@ CO_CANtxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, bo /* get specific buffer */ buffer = &CANmodule->txArray[index]; - /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer. - * Microcontroller specific. */ + /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer, microcontroller specific. */ buffer->ident = ((uint32_t)ident & 0x07FFU) | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) | ((uint32_t)(rtr ? 0x8000U : 0U)); @@ -182,7 +181,7 @@ CO_CANclearPendingSyncPDOs(CO_CANmodule_t* CANmodule) { CO_LOCK_CAN_SEND(CANmodule); /* Abort message from CAN module, if there is synchronous TPDO. * Take special care with this functionality. */ - if (/*messageIsOnCanBuffer && */ CANmodule->bufferInhibitFlag) { + if (/* messageIsOnCanBuffer && */ CANmodule->bufferInhibitFlag) { /* clear TXREQ */ CANmodule->bufferInhibitFlag = false; tpdoDeleted = 1U; @@ -209,8 +208,7 @@ CO_CANclearPendingSyncPDOs(CO_CANmodule_t* CANmodule) { } } -/* Get error counters from the module. If necessary, function may use - * different way to determine errors. */ +/* Get error counters from the module. If necessary, function may use different way to determine errors. */ static uint16_t rxErrors = 0, txErrors = 0, overflow = 0; void @@ -282,8 +280,7 @@ CO_CANinterrupt(CO_CANmodule_t* CANmodule) { rcvMsg = 0; /* get message from module here */ rcvMsgIdent = rcvMsg->ident; if (CANmodule->useCANrxFilters) { - /* CAN module filters are used. Message with known 11-bit identifier has */ - /* been received */ + /* CAN module filters are used. Message with known 11-bit identifier has been received */ index = 0; /* get index of the received message here. Or something similar */ if (index < CANmodule->rxSize) { buffer = &CANmodule->rxArray[index]; From b87fad2195e403b970e945531fabfb14234d47ad Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 6 Jul 2024 21:54:59 +0200 Subject: [PATCH 477/520] Format the .h files using clang-format v15. --- 301/CO_Emergency.h | 372 +++++++++++++++++-------------------- 301/CO_HBconsumer.h | 149 ++++++--------- 301/CO_NMT_Heartbeat.h | 102 ++++------ 301/CO_Node_Guarding.h | 66 +++---- 301/CO_ODinterface.h | 332 ++++++++++++++------------------- 301/CO_PDO.h | 147 ++++++--------- 301/CO_SDOclient.h | 120 ++++-------- 301/CO_SDOserver.h | 231 +++++++++++------------ 301/CO_SYNC.h | 84 ++++----- 301/CO_TIME.h | 64 +++---- 301/CO_config.h | 118 ++++++------ 301/CO_driver.h | 275 ++++++++++++++------------- 301/CO_fifo.h | 181 ++++++++---------- 301/crc16-ccitt.h | 11 +- 303/CO_LEDs.h | 59 +++--- 304/CO_GFC.h | 18 +- 304/CO_SRDO.h | 65 +++---- 305/CO_LSS.h | 135 +++++++------- 305/CO_LSSmaster.h | 159 ++++++---------- 305/CO_LSSslave.h | 101 +++++----- 309/CO_gateway_ascii.h | 159 +++++++--------- CANopen.h | 298 ++++++++++++----------------- example/CO_driver_target.h | 40 ++-- example/CO_storageBlank.h | 15 +- storage/CO_eeprom.h | 23 +-- storage/CO_storage.h | 36 ++-- storage/CO_storageEeprom.h | 17 +- 27 files changed, 1431 insertions(+), 1946 deletions(-) diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 9fec9041..80791b19 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -26,24 +26,21 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_EM -#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | \ - CO_CONFIG_EM_HISTORY | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) +#define CO_CONFIG_EM \ + (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE \ + | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifndef CO_CONFIG_EM_ERR_STATUS_BITS_COUNT -#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10U*8U) +#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10U * 8U) #endif #ifndef CO_CONFIG_ERR_CONDITION_GENERIC #define CO_CONFIG_ERR_CONDITION_GENERIC (em->errorStatusBits[5] != 0U) #endif #ifndef CO_CONFIG_ERR_CONDITION_COMMUNICATION -#define CO_CONFIG_ERR_CONDITION_COMMUNICATION ((em->errorStatusBits[2] != 0U) \ - || (em->errorStatusBits[3] != 0U)) +#define CO_CONFIG_ERR_CONDITION_COMMUNICATION ((em->errorStatusBits[2] != 0U) || (em->errorStatusBits[3] != 0U)) #endif #ifndef CO_CONFIG_ERR_CONDITION_MANUFACTURER -#define CO_CONFIG_ERR_CONDITION_MANUFACTURER (( em->errorStatusBits[8] != 0U) \ - || (em->errorStatusBits[9] != 0U)) +#define CO_CONFIG_ERR_CONDITION_MANUFACTURER ((em->errorStatusBits[8] != 0U) || (em->errorStatusBits[9] != 0U)) #endif #ifdef __cplusplus @@ -96,7 +93,6 @@ extern "C" { * registered by @ref CO_EM_initCallbackRx() function. */ - /** * @defgroup CO_errorRegister_t CANopen Error register * @{ @@ -110,14 +106,14 @@ extern "C" { * Internal errors may prevent device to stay in NMT Operational state and * changes may switch between the states. See @ref CO_NMT_control_t for details. */ -#define CO_ERR_REG_GENERIC_ERR 0x01U /**< bit 0, generic error */ -#define CO_ERR_REG_CURRENT 0x02U /**< bit 1, current */ -#define CO_ERR_REG_VOLTAGE 0x04U /**< bit 2, voltage */ -#define CO_ERR_REG_TEMPERATURE 0x08U /**< bit 3, temperature */ -#define CO_ERR_REG_COMMUNICATION 0x10U /**< bit 4, communication error */ -#define CO_ERR_REG_DEV_PROFILE 0x20U /**< bit 5, device profile specific */ -#define CO_ERR_REG_RESERVED 0x40U /**< bit 6, reserved (always 0) */ -#define CO_ERR_REG_MANUFACTURER 0x80U /**< bit 7, manufacturer specific */ +#define CO_ERR_REG_GENERIC_ERR 0x01U /**< bit 0, generic error */ +#define CO_ERR_REG_CURRENT 0x02U /**< bit 1, current */ +#define CO_ERR_REG_VOLTAGE 0x04U /**< bit 2, voltage */ +#define CO_ERR_REG_TEMPERATURE 0x08U /**< bit 3, temperature */ +#define CO_ERR_REG_COMMUNICATION 0x10U /**< bit 4, communication error */ +#define CO_ERR_REG_DEV_PROFILE 0x20U /**< bit 5, device profile specific */ +#define CO_ERR_REG_RESERVED 0x40U /**< bit 6, reserved (always 0) */ +#define CO_ERR_REG_MANUFACTURER 0x80U /**< bit 7, manufacturer specific */ /** @} */ /* CO_errorRegister_t */ @@ -127,55 +123,54 @@ extern "C" { * * Standard error codes according to CiA DS-301 and DS-401. */ -#define CO_EMC_NO_ERROR 0x0000U /**< 0x00xx error Reset or No Error */ -#define CO_EMC_GENERIC 0x1000U /**< 0x10xx Generic Error */ -#define CO_EMC_CURRENT 0x2000U /**< 0x20xx Current */ -#define CO_EMC_CURRENT_INPUT 0x2100U /**< 0x21xx Current device input side */ -#define CO_EMC_CURRENT_INSIDE 0x2200U /**< 0x22xx Current inside the device */ -#define CO_EMC_CURRENT_OUTPUT 0x2300U /**< 0x23xx Current device output side */ -#define CO_EMC_VOLTAGE 0x3000U /**< 0x30xx Voltage */ -#define CO_EMC_VOLTAGE_MAINS 0x3100U /**< 0x31xx Mains Voltage */ -#define CO_EMC_VOLTAGE_INSIDE 0x3200U /**< 0x32xx Voltage inside the device */ -#define CO_EMC_VOLTAGE_OUTPUT 0x3300U /**< 0x33xx Output Voltage */ -#define CO_EMC_TEMPERATURE 0x4000U /**< 0x40xx Temperature */ -#define CO_EMC_TEMP_AMBIENT 0x4100U /**< 0x41xx Ambient Temperature */ -#define CO_EMC_TEMP_DEVICE 0x4200U /**< 0x42xx Device Temperature */ -#define CO_EMC_HARDWARE 0x5000U /**< 0x50xx Device Hardware */ -#define CO_EMC_SOFTWARE_DEVICE 0x6000U /**< 0x60xx Device Software */ -#define CO_EMC_SOFTWARE_INTERNAL 0x6100U /**< 0x61xx Internal Software */ -#define CO_EMC_SOFTWARE_USER 0x6200U /**< 0x62xx User Software */ -#define CO_EMC_DATA_SET 0x6300U /**< 0x63xx Data Set */ -#define CO_EMC_ADDITIONAL_MODUL 0x7000U /**< 0x70xx Additional Modules */ -#define CO_EMC_MONITORING 0x8000U /**< 0x80xx Monitoring */ -#define CO_EMC_COMMUNICATION 0x8100U /**< 0x81xx Communication */ -#define CO_EMC_CAN_OVERRUN 0x8110U /**< 0x8110 CAN Overrun (Objects lost) */ -#define CO_EMC_CAN_PASSIVE 0x8120U /**< 0x8120 CAN in Error Passive Mode */ -#define CO_EMC_HEARTBEAT 0x8130U /**< 0x8130 Life Guard Error or Heartbeat Error */ -#define CO_EMC_BUS_OFF_RECOVERED 0x8140U /**< 0x8140 recovered from bus off */ -#define CO_EMC_CAN_ID_COLLISION 0x8150U /**< 0x8150 CAN-ID collision */ -#define CO_EMC_PROTOCOL_ERROR 0x8200U /**< 0x82xx Protocol Error */ -#define CO_EMC_PDO_LENGTH 0x8210U /**< 0x8210 PDO not processed due to length error */ -#define CO_EMC_PDO_LENGTH_EXC 0x8220U /**< 0x8220 PDO length exceeded */ -#define CO_EMC_DAM_MPDO 0x8230U /**< 0x8230 DAM MPDO not processed destination object not available */ -#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /**< 0x8240 Unexpected SYNC data length */ -#define CO_EMC_RPDO_TIMEOUT 0x8250U /**< 0x8250 RPDO timeout */ -#define CO_EMC_EXTERNAL_ERROR 0x9000U /**< 0x90xx External Error */ -#define CO_EMC_ADDITIONAL_FUNC 0xF000U /**< 0xF0xx Additional Functions */ -#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /**< 0xFFxx Device specific */ - -#define CO_EMC401_OUT_CUR_HI 0x2310U /**< 0x2310 DS401 Current at outputs too high (overload) */ -#define CO_EMC401_OUT_SHORTED 0x2320U /**< 0x2320 DS401 Short circuit at outputs */ -#define CO_EMC401_OUT_LOAD_DUMP 0x2330U /**< 0x2330 DS401 Load dump at outputs */ -#define CO_EMC401_IN_VOLT_HI 0x3110U /**< 0x3110 DS401 Input voltage too high */ -#define CO_EMC401_IN_VOLT_LOW 0x3120U /**< 0x3120 DS401 Input voltage too low */ -#define CO_EMC401_INTERN_VOLT_HI 0x3210U /**< 0x3210 DS401 Internal voltage too high */ -#define CO_EMC401_INTERN_VOLT_LO 0x3220U /**< 0x3220 DS401 Internal voltage too low */ -#define CO_EMC401_OUT_VOLT_HIGH 0x3310U /**< 0x3310 DS401 Output voltage too high */ -#define CO_EMC401_OUT_VOLT_LOW 0x3320U /**< 0x3320 DS401 Output voltage too low */ +#define CO_EMC_NO_ERROR 0x0000U /**< 0x00xx error Reset or No Error */ +#define CO_EMC_GENERIC 0x1000U /**< 0x10xx Generic Error */ +#define CO_EMC_CURRENT 0x2000U /**< 0x20xx Current */ +#define CO_EMC_CURRENT_INPUT 0x2100U /**< 0x21xx Current device input side */ +#define CO_EMC_CURRENT_INSIDE 0x2200U /**< 0x22xx Current inside the device */ +#define CO_EMC_CURRENT_OUTPUT 0x2300U /**< 0x23xx Current device output side */ +#define CO_EMC_VOLTAGE 0x3000U /**< 0x30xx Voltage */ +#define CO_EMC_VOLTAGE_MAINS 0x3100U /**< 0x31xx Mains Voltage */ +#define CO_EMC_VOLTAGE_INSIDE 0x3200U /**< 0x32xx Voltage inside the device */ +#define CO_EMC_VOLTAGE_OUTPUT 0x3300U /**< 0x33xx Output Voltage */ +#define CO_EMC_TEMPERATURE 0x4000U /**< 0x40xx Temperature */ +#define CO_EMC_TEMP_AMBIENT 0x4100U /**< 0x41xx Ambient Temperature */ +#define CO_EMC_TEMP_DEVICE 0x4200U /**< 0x42xx Device Temperature */ +#define CO_EMC_HARDWARE 0x5000U /**< 0x50xx Device Hardware */ +#define CO_EMC_SOFTWARE_DEVICE 0x6000U /**< 0x60xx Device Software */ +#define CO_EMC_SOFTWARE_INTERNAL 0x6100U /**< 0x61xx Internal Software */ +#define CO_EMC_SOFTWARE_USER 0x6200U /**< 0x62xx User Software */ +#define CO_EMC_DATA_SET 0x6300U /**< 0x63xx Data Set */ +#define CO_EMC_ADDITIONAL_MODUL 0x7000U /**< 0x70xx Additional Modules */ +#define CO_EMC_MONITORING 0x8000U /**< 0x80xx Monitoring */ +#define CO_EMC_COMMUNICATION 0x8100U /**< 0x81xx Communication */ +#define CO_EMC_CAN_OVERRUN 0x8110U /**< 0x8110 CAN Overrun (Objects lost) */ +#define CO_EMC_CAN_PASSIVE 0x8120U /**< 0x8120 CAN in Error Passive Mode */ +#define CO_EMC_HEARTBEAT 0x8130U /**< 0x8130 Life Guard Error or Heartbeat Error */ +#define CO_EMC_BUS_OFF_RECOVERED 0x8140U /**< 0x8140 recovered from bus off */ +#define CO_EMC_CAN_ID_COLLISION 0x8150U /**< 0x8150 CAN-ID collision */ +#define CO_EMC_PROTOCOL_ERROR 0x8200U /**< 0x82xx Protocol Error */ +#define CO_EMC_PDO_LENGTH 0x8210U /**< 0x8210 PDO not processed due to length error */ +#define CO_EMC_PDO_LENGTH_EXC 0x8220U /**< 0x8220 PDO length exceeded */ +#define CO_EMC_DAM_MPDO 0x8230U /**< 0x8230 DAM MPDO not processed destination object not available */ +#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /**< 0x8240 Unexpected SYNC data length */ +#define CO_EMC_RPDO_TIMEOUT 0x8250U /**< 0x8250 RPDO timeout */ +#define CO_EMC_EXTERNAL_ERROR 0x9000U /**< 0x90xx External Error */ +#define CO_EMC_ADDITIONAL_FUNC 0xF000U /**< 0xF0xx Additional Functions */ +#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /**< 0xFFxx Device specific */ + +#define CO_EMC401_OUT_CUR_HI 0x2310U /**< 0x2310 DS401 Current at outputs too high (overload) */ +#define CO_EMC401_OUT_SHORTED 0x2320U /**< 0x2320 DS401 Short circuit at outputs */ +#define CO_EMC401_OUT_LOAD_DUMP 0x2330U /**< 0x2330 DS401 Load dump at outputs */ +#define CO_EMC401_IN_VOLT_HI 0x3110U /**< 0x3110 DS401 Input voltage too high */ +#define CO_EMC401_IN_VOLT_LOW 0x3120U /**< 0x3120 DS401 Input voltage too low */ +#define CO_EMC401_INTERN_VOLT_HI 0x3210U /**< 0x3210 DS401 Internal voltage too high */ +#define CO_EMC401_INTERN_VOLT_LO 0x3220U /**< 0x3220 DS401 Internal voltage too low */ +#define CO_EMC401_OUT_VOLT_HIGH 0x3310U /**< 0x3310 DS401 Output voltage too high */ +#define CO_EMC401_OUT_VOLT_LOW 0x3320U /**< 0x3320 DS401 Output voltage too low */ /** @} */ /* CO_EM_errorCode_t */ - /** * @defgroup CO_EM_errorStatusBits_t Error status bits * @{ @@ -193,85 +188,88 @@ extern "C" { * uses first 6 bytes. Additional 4 bytes are pre-defined for manufacturer * or device specific error indications, by default. */ -#define CO_EM_NO_ERROR 0x00U /**< 0x00 Error Reset or No Error */ -#define CO_EM_CAN_BUS_WARNING 0x01U /**< 0x01 communication info CAN bus warning limit reached */ -#define CO_EM_RXMSG_WRONG_LENGTH 0x02U /**< 0x02 communication info Wrong data length of the received CAN message */ -#define CO_EM_RXMSG_OVERFLOW 0x03U /**< 0x03 communication info Previous received CAN message wasn't processed yet */ -#define CO_EM_RPDO_WRONG_LENGTH 0x04U /**< 0x04 communication info Wrong data length of received PDO */ -#define CO_EM_RPDO_OVERFLOW 0x05U /**< 0x05 communication info Previous received PDO wasn't processed yet */ -#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /**< 0x06 communication info CAN receive bus is passive */ -#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /**< 0x07 communication info CAN transmit bus is passive */ -#define CO_EM_NMT_WRONG_COMMAND 0x08U /**< 0x08 communication info Wrong NMT command received */ -#define CO_EM_TIME_TIMEOUT 0x09U /**< 0x09 communication info TIME message timeout */ -#define CO_EM_0A_unused 0x0AU /**< 0x0A communication info (unused) */ -#define CO_EM_0B_unused 0x0BU /**< 0x0B communication info (unused) */ -#define CO_EM_0C_unused 0x0CU /**< 0x0C communication info (unused) */ -#define CO_EM_0D_unused 0x0DU /**< 0x0D communication info (unused) */ -#define CO_EM_0E_unused 0x0EU /**< 0x0E communication info (unused) */ -#define CO_EM_0F_unused 0x0FU /**< 0x0F communication info (unused) */ - -#define CO_EM_10_unused 0x10U /**< 0x10 communication critical (unused) */ -#define CO_EM_11_unused 0x11U /**< 0x11 communication critical (unused) */ -#define CO_EM_CAN_TX_BUS_OFF 0x12U /**< 0x12 communication critical CAN transmit bus is off */ -#define CO_EM_CAN_RXB_OVERFLOW 0x13U /**< 0x13 communication critical CAN module receive buffer has overflowed */ -#define CO_EM_CAN_TX_OVERFLOW 0x14U /**< 0x14 communication critical CAN transmit buffer has overflowed */ -#define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /**< 0x15 communication critical TPDO is outside SYNC window */ -#define CO_EM_16_unused 0x16U /**< 0x16 communication critical (unused) */ -#define CO_EM_RPDO_TIME_OUT 0x17U /**< 0x17 communication critical RPDO message timeout */ -#define CO_EM_SYNC_TIME_OUT 0x18U /**< 0x18 communication critical SYNC message timeout */ -#define CO_EM_SYNC_LENGTH 0x19U /**< 0x19 communication critical Unexpected SYNC data length */ -#define CO_EM_PDO_WRONG_MAPPING 0x1AU /**< 0x1A communication critical Error with PDO mapping */ -#define CO_EM_HEARTBEAT_CONSUMER 0x1BU /**< 0x1B communication critical Heartbeat consumer timeout */ -#define CO_EM_HB_CONSUMER_REMOTE_RESET 0x1CU /**< 0x1C communication critical Heartbeat consumer detected remote node reset */ -#define CO_EM_SRDO_CONFIGURATION 0x1DU /**< 0x1D communication critical Error in SRDO configuration parameters. */ -#define CO_EM_1E_unused 0x1EU /**< 0x1E communication critical (unused) */ -#define CO_EM_1F_unused 0x1FU /**< 0x1F communication critical (unused) */ - -#define CO_EM_EMERGENCY_BUFFER_FULL 0x20U /**< 0x20 generic info Emergency buffer is full Emergency message wasn't sent */ -#define CO_EM_21_unused 0x21U /**< 0x21 generic info (unused) */ -#define CO_EM_MICROCONTROLLER_RESET 0x22U /**< 0x22 generic info Microcontroller has just started */ -#define CO_EM_23_unused 0x23U /**< 0x23 generic info (unused) */ -#define CO_EM_24_unused 0x24U /**< 0x24 generic info (unused) */ -#define CO_EM_25_unused 0x25U /**< 0x25 generic info (unused) */ -#define CO_EM_26_unused 0x26U /**< 0x26 generic info (unused) */ -#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /**< 0x27 generic info Automatic store to non-volatile memory failed */ - -#define CO_EM_WRONG_ERROR_REPORT 0x28U /**< 0x28 generic critical Wrong parameters to CO_errorReport() function*/ -#define CO_EM_ISR_TIMER_OVERFLOW 0x29U /**< 0x29 generic critical Timer task has overflowed */ -#define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /**< 0x2A generic critical Unable to allocate memory for objects */ -#define CO_EM_GENERIC_ERROR 0x2BU /**< 0x2B generic critical Generic error test usage */ -#define CO_EM_GENERIC_SOFTWARE_ERROR 0x2CU /**< 0x2C generic critical Software error */ -#define CO_EM_INCONSISTENT_OBJECT_DICT 0x2DU /**< 0x2D generic critical Object dictionary does not match the software*/ -#define CO_EM_CALCULATION_OF_PARAMETERS 0x2EU /**< 0x2E generic critical Error in calculation of device parameters */ -#define CO_EM_NON_VOLATILE_MEMORY 0x2FU /**< 0x2F generic critical Error with access to non volatile device memory */ +#define CO_EM_NO_ERROR 0x00U /**< 0x00 Error Reset or No Error */ +#define CO_EM_CAN_BUS_WARNING 0x01U /**< 0x01 communication info CAN bus warning limit reached */ +#define CO_EM_RXMSG_WRONG_LENGTH \ + 0x02U /**< 0x02 communication info Wrong data length of the received CAN message */ +#define CO_EM_RXMSG_OVERFLOW \ + 0x03U /**< 0x03 communication info Previous received CAN message wasn't processed yet */ +#define CO_EM_RPDO_WRONG_LENGTH 0x04U /**< 0x04 communication info Wrong data length of received PDO */ +#define CO_EM_RPDO_OVERFLOW 0x05U /**< 0x05 communication info Previous received PDO wasn't processed yet */ +#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /**< 0x06 communication info CAN receive bus is passive */ +#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /**< 0x07 communication info CAN transmit bus is passive */ +#define CO_EM_NMT_WRONG_COMMAND 0x08U /**< 0x08 communication info Wrong NMT command received */ +#define CO_EM_TIME_TIMEOUT 0x09U /**< 0x09 communication info TIME message timeout */ +#define CO_EM_0A_unused 0x0AU /**< 0x0A communication info (unused) */ +#define CO_EM_0B_unused 0x0BU /**< 0x0B communication info (unused) */ +#define CO_EM_0C_unused 0x0CU /**< 0x0C communication info (unused) */ +#define CO_EM_0D_unused 0x0DU /**< 0x0D communication info (unused) */ +#define CO_EM_0E_unused 0x0EU /**< 0x0E communication info (unused) */ +#define CO_EM_0F_unused 0x0FU /**< 0x0F communication info (unused) */ + +#define CO_EM_10_unused 0x10U /**< 0x10 communication critical (unused) */ +#define CO_EM_11_unused 0x11U /**< 0x11 communication critical (unused) */ +#define CO_EM_CAN_TX_BUS_OFF 0x12U /**< 0x12 communication critical CAN transmit bus is off */ +#define CO_EM_CAN_RXB_OVERFLOW 0x13U /**< 0x13 communication critical CAN module receive buffer has overflowed */ +#define CO_EM_CAN_TX_OVERFLOW 0x14U /**< 0x14 communication critical CAN transmit buffer has overflowed */ +#define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /**< 0x15 communication critical TPDO is outside SYNC window */ +#define CO_EM_16_unused 0x16U /**< 0x16 communication critical (unused) */ +#define CO_EM_RPDO_TIME_OUT 0x17U /**< 0x17 communication critical RPDO message timeout */ +#define CO_EM_SYNC_TIME_OUT 0x18U /**< 0x18 communication critical SYNC message timeout */ +#define CO_EM_SYNC_LENGTH 0x19U /**< 0x19 communication critical Unexpected SYNC data length */ +#define CO_EM_PDO_WRONG_MAPPING 0x1AU /**< 0x1A communication critical Error with PDO mapping */ +#define CO_EM_HEARTBEAT_CONSUMER 0x1BU /**< 0x1B communication critical Heartbeat consumer timeout */ +#define CO_EM_HB_CONSUMER_REMOTE_RESET \ + 0x1CU /**< 0x1C communication critical Heartbeat consumer detected remote node reset */ +#define CO_EM_SRDO_CONFIGURATION 0x1DU /**< 0x1D communication critical Error in SRDO configuration parameters. */ +#define CO_EM_1E_unused 0x1EU /**< 0x1E communication critical (unused) */ +#define CO_EM_1F_unused 0x1FU /**< 0x1F communication critical (unused) */ + +#define CO_EM_EMERGENCY_BUFFER_FULL \ + 0x20U /**< 0x20 generic info Emergency buffer is full Emergency message wasn't sent */ +#define CO_EM_21_unused 0x21U /**< 0x21 generic info (unused) */ +#define CO_EM_MICROCONTROLLER_RESET 0x22U /**< 0x22 generic info Microcontroller has just started */ +#define CO_EM_23_unused 0x23U /**< 0x23 generic info (unused) */ +#define CO_EM_24_unused 0x24U /**< 0x24 generic info (unused) */ +#define CO_EM_25_unused 0x25U /**< 0x25 generic info (unused) */ +#define CO_EM_26_unused 0x26U /**< 0x26 generic info (unused) */ +#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /**< 0x27 generic info Automatic store to non-volatile memory failed */ + +#define CO_EM_WRONG_ERROR_REPORT 0x28U /**< 0x28 generic critical Wrong parameters to CO_errorReport() function*/ +#define CO_EM_ISR_TIMER_OVERFLOW 0x29U /**< 0x29 generic critical Timer task has overflowed */ +#define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /**< 0x2A generic critical Unable to allocate memory for objects */ +#define CO_EM_GENERIC_ERROR 0x2BU /**< 0x2B generic critical Generic error test usage */ +#define CO_EM_GENERIC_SOFTWARE_ERROR 0x2CU /**< 0x2C generic critical Software error */ +#define CO_EM_INCONSISTENT_OBJECT_DICT \ + 0x2DU /**< 0x2D generic critical Object dictionary does not match the software*/ +#define CO_EM_CALCULATION_OF_PARAMETERS \ + 0x2EU /**< 0x2E generic critical Error in calculation of device parameters */ +#define CO_EM_NON_VOLATILE_MEMORY \ + 0x2FU /**< 0x2F generic critical Error with access to non volatile device memory */ /** 0x30+ manufacturer info or critical Error status buts free to use by * manufacturer. By default bits 0x30..0x3F are set as informational and * bits 0x40..0x4F are set as critical. Manufacturer critical bits sets the * error register as specified by @ref CO_CONFIG_ERR_CONDITION_MANUFACTURER */ -#define CO_EM_MANUFACTURER_START 0x30U +#define CO_EM_MANUFACTURER_START 0x30U /** (@ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1) largest value of the Error status bit. */ -#define CO_EM_MANUFACTURER_END (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1U) +#define CO_EM_MANUFACTURER_END (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1U) /** @} */ /* CO_EM_errorStatusBits_t */ - - -#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) \ - || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) || defined CO_DOXYGEN /** * Fifo buffer for emergency producer and error history */ typedef struct { uint32_t msg; -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN uint32_t info; #endif } CO_EM_fifo_t; #endif - /** * Emergency object. */ @@ -279,21 +277,20 @@ typedef struct { /** Bitfield for the internal indication of the error condition. */ uint8_t errorStatusBits[CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U]; /** Pointer to error register in object dictionary at 0x1001,00. */ - uint8_t *errorRegister; + uint8_t* errorRegister; /** Old CAN error status bitfield */ uint16_t CANerrorStatusOld; /** From CO_EM_init() */ - CO_CANmodule_t *CANdevTx; + CO_CANmodule_t* CANdevTx; -#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) \ - || defined CO_DOXYGEN +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) || defined CO_DOXYGEN /** Internal circular FIFO buffer for storing pre-processed emergency * messages. Messages are added by @ref CO_error() function. All messages * are later post-processed by @ref CO_EM_process() function. In case of * overflow, error is indicated but emergency message is not sent. Fifo is * also used for error history, OD object 0x1003, "Pre-defined error field". * Buffer is defined by @ref CO_EM_init(). */ - CO_EM_fifo_t *fifo; + CO_EM_fifo_t* fifo; /** Size of the above buffer, specified by @ref CO_EM_init(). */ uint8_t fifoSize; /** Pointer for the fifo buffer, where next emergency message will be @@ -309,59 +306,55 @@ typedef struct { uint8_t fifoCount; #endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN /** True, if emergency producer is enabled, from Object dictionary */ bool_t producerEnabled; /** Copy of CANopen node ID, from CO_EM_init() */ uint8_t nodeId; /** CAN transmit buffer */ - CO_CANtx_t *CANtxBuff; + CO_CANtx_t* CANtxBuff; /** Extension for OD object */ OD_extension_t OD_1014_extension; - #if (((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_CONFIGURABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_CONFIGURABLE) != 0) || defined CO_DOXYGEN /** COB ID of emergency message, from Object dictionary */ uint16_t producerCanId; /** From CO_EM_init() */ uint16_t CANdevTxIdx; - #endif - #if (((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0) || defined CO_DOXYGEN - /** Inhibit time for emergency message, from Object dictionary */ +#endif +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0) || defined CO_DOXYGEN + /** Inhibit time for emergency message, from Object dictionary */ uint32_t inhibitEmTime_us; /**< Internal timer for inhibit time */ uint32_t inhibitEmTimer; /** Extension for OD object */ OD_extension_t OD_1015_extension; - #endif +#endif #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0) || defined CO_DOXYGEN /** Extension for OD object */ OD_extension_t OD_1003_extension; #endif -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0) || defined CO_DOXYGEN /** Extension for OD object */ OD_extension_t OD_statusBits_extension; #endif -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN /** From CO_EM_initCallbackRx() or NULL */ - void (*pFunctSignalRx)(const uint16_t ident, - const uint16_t errorCode, - const uint8_t errorRegister, - const uint8_t errorBit, - const uint32_t infoCode); + void (*pFunctSignalRx)(const uint16_t ident, const uint16_t errorCode, const uint8_t errorRegister, + const uint8_t errorBit, const uint32_t infoCode); #endif -#if (((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_EM_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void* object); /** From CO_EM_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void* functSignalObjectPre; #endif } CO_EM_t; - /** * Initialize Emergency object. * @@ -396,36 +389,28 @@ typedef struct { * * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_EM_init(CO_EM_t *em, - CO_CANmodule_t *CANdevTx, - const OD_entry_t *OD_1001_errReg, -#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) \ - || defined CO_DOXYGEN - CO_EM_fifo_t *fifo, - uint8_t fifoSize, +CO_ReturnError_t CO_EM_init(CO_EM_t* em, CO_CANmodule_t* CANdevTx, const OD_entry_t* OD_1001_errReg, +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) || defined CO_DOXYGEN + CO_EM_fifo_t* fifo, uint8_t fifoSize, #endif -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN - OD_entry_t *OD_1014_cobIdEm, - uint16_t CANdevTxIdx, - #if (((CO_CONFIG_EM) & CO_CONFIG_EM_PROD_INHIBIT) != 0) || defined CO_DOXYGEN - OD_entry_t *OD_1015_InhTime, - #endif +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN + OD_entry_t* OD_1014_cobIdEm, uint16_t CANdevTxIdx, +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0) || defined CO_DOXYGEN + OD_entry_t* OD_1015_InhTime, #endif -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_HISTORY) != 0) || defined CO_DOXYGEN - OD_entry_t *OD_1003_preDefErr, #endif -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_STATUS_BITS) != 0) || defined CO_DOXYGEN - OD_entry_t *OD_statusBits, +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0) || defined CO_DOXYGEN + OD_entry_t* OD_1003_preDefErr, #endif -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0) || defined CO_DOXYGEN + OD_entry_t* OD_statusBits, #endif - const uint8_t nodeId, - uint32_t *errInfo); - +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN + CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, +#endif + const uint8_t nodeId, uint32_t* errInfo); -#if (((CO_CONFIG_EM) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize Emergency callback function. * @@ -440,13 +425,10 @@ CO_ReturnError_t CO_EM_init(CO_EM_t *em, * be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_EM_initCallbackPre(CO_EM_t *em, - void *object, - void (*pFunctSignal)(void *object)); +void CO_EM_initCallbackPre(CO_EM_t* em, void* object, void (*pFunctSignal)(void* object)); #endif - -#if (((CO_CONFIG_EM) & CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN /** * Initialize Emergency received callback function. * @@ -462,15 +444,11 @@ void CO_EM_initCallbackPre(CO_EM_t *em, * @param em This object. * @param pFunctSignalRx Pointer to the callback function. Not called if NULL. */ -void CO_EM_initCallbackRx(CO_EM_t *em, - void (*pFunctSignalRx)(const uint16_t ident, - const uint16_t errorCode, - const uint8_t errorRegister, - const uint8_t errorBit, - const uint32_t infoCode)); +void CO_EM_initCallbackRx(CO_EM_t* em, void (*pFunctSignalRx)(const uint16_t ident, const uint16_t errorCode, + const uint8_t errorRegister, const uint8_t errorBit, + const uint32_t infoCode)); #endif - /** * Process Error control and Emergency object. * @@ -485,11 +463,7 @@ void CO_EM_initCallbackRx(CO_EM_t *em, * [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_EM_process(CO_EM_t *em, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us); - +void CO_EM_process(CO_EM_t* em, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, uint32_t* timerNext_us); /** * Set or reset error condition. @@ -509,23 +483,17 @@ void CO_EM_process(CO_EM_t *em, * @param infoCode 32 bit value is passed to bytes 4...7 of the Emergency * message. It contains optional additional information. */ -void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, - uint16_t errorCode, uint32_t infoCode); - +void CO_error(CO_EM_t* em, bool_t setError, const uint8_t errorBit, uint16_t errorCode, uint32_t infoCode); /** * Report error condition, for description of parameters see @ref CO_error. */ -#define CO_errorReport(em, errorBit, errorCode, infoCode) \ - CO_error(em, true, errorBit, errorCode, infoCode) - +#define CO_errorReport(em, errorBit, errorCode, infoCode) CO_error(em, true, errorBit, errorCode, infoCode) /** * Reset error condition, for description of parameters see @ref CO_error. */ -#define CO_errorReset(em, errorBit, infoCode) \ - CO_error(em, false, errorBit, CO_EMC_NO_ERROR, infoCode) - +#define CO_errorReset(em, errorBit, infoCode) CO_error(em, false, errorBit, CO_EMC_NO_ERROR, infoCode) /** * Check specific error condition. @@ -537,12 +505,15 @@ void CO_error(CO_EM_t *em, bool_t setError, const uint8_t errorBit, * * @return true if Error is present. */ -static inline bool_t CO_isError(CO_EM_t *em, const uint8_t errorBit) { +static inline bool_t +CO_isError(CO_EM_t* em, const uint8_t errorBit) { uint8_t index = errorBit >> 3; uint8_t bitmask = 1 << (errorBit & 0x7); return (em == NULL || index >= (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U) - || (em->errorStatusBits[index] & bitmask) != 0) ? true : false; + || (em->errorStatusBits[index] & bitmask) != 0) + ? true + : false; } /** @@ -552,7 +523,8 @@ static inline bool_t CO_isError(CO_EM_t *em, const uint8_t errorBit) { * * @return Error register or 0 if doesn't exist. */ -static inline uint8_t CO_getErrorRegister(CO_EM_t *em) { +static inline uint8_t +CO_getErrorRegister(CO_EM_t* em) { return (em == NULL || em->errorRegister == NULL) ? 0 : *em->errorRegister; } diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index 38232f51..b3d1273b 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -28,13 +28,12 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_HB_CONS -#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_HB_CONS \ + (CO_CONFIG_HB_CONS_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT \ + | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -63,13 +62,12 @@ extern "C" { * Heartbeat state of a node */ typedef enum { - CO_HBconsumer_UNCONFIGURED = 0x00U, /**< Consumer entry inactive */ - CO_HBconsumer_UNKNOWN = 0x01U, /**< Consumer enabled, but no heartbeat received yet */ - CO_HBconsumer_ACTIVE = 0x02U, /**< Heartbeat received within set time */ - CO_HBconsumer_TIMEOUT = 0x03U, /**< No heatbeat received for set time */ + CO_HBconsumer_UNCONFIGURED = 0x00U, /**< Consumer entry inactive */ + CO_HBconsumer_UNKNOWN = 0x01U, /**< Consumer enabled, but no heartbeat received yet */ + CO_HBconsumer_ACTIVE = 0x02U, /**< Heartbeat received within set time */ + CO_HBconsumer_TIMEOUT = 0x03U, /**< No heatbeat received for set time */ } CO_HBconsumer_state_t; - /** * One monitored node inside CO_HBconsumer_t. */ @@ -85,46 +83,42 @@ typedef struct { /** Consumer heartbeat time from OD */ uint32_t time_us; /** Indication if new Heartbeat message received from the CAN bus */ - volatile void *CANrxNew; -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN + volatile void* CANrxNew; +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_HBconsumer_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void* object); /** From CO_HBconsumer_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void* functSignalObjectPre; #endif -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ - || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) \ - || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN /** Previous value of the remote node (Heartbeat payload) */ CO_NMT_internalState_t NMTstatePrev; #endif -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ - void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t NMTstate, - void *object); + void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t NMTstate, void* object); /** Pointer to object */ - void *pFunctSignalObjectNmtChanged; + void* pFunctSignalObjectNmtChanged; /** Callback for heartbeat state change to active event. * From CO_HBconsumer_initCallbackHeartbeatStarted() or NULL. */ - void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void *object); + void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void* object); /** Pointer to object */ - void *functSignalObjectHbStarted; + void* functSignalObjectHbStarted; /** Callback for consumer timeout event. * From CO_HBconsumer_initCallbackTimeout() or NULL. */ - void (*pFunctSignalTimeout)(uint8_t nodeId, uint8_t idx, void *object); + void (*pFunctSignalTimeout)(uint8_t nodeId, uint8_t idx, void* object); /** Pointer to object */ - void *functSignalObjectTimeout; + void* functSignalObjectTimeout; /** Callback for remote reset event. * From CO_HBconsumer_initCallbackRemoteReset() or NULL. */ - void (*pFunctSignalRemoteReset)(uint8_t nodeId, uint8_t idx, void *object); + void (*pFunctSignalRemoteReset)(uint8_t nodeId, uint8_t idx, void* object); /** Pointer to object */ - void *functSignalObjectRemoteReset; + void* functSignalObjectRemoteReset; #endif } CO_HBconsNode_t; - /** * Heartbeat consumer object. * @@ -133,9 +127,9 @@ typedef struct { */ typedef struct { /** From CO_HBconsumer_init() */ - CO_EM_t *em; + CO_EM_t* em; /** Array of monitored nodes, from CO_HBconsumer_init() */ - CO_HBconsNode_t *monitoredNodes; + CO_HBconsNode_t* monitoredNodes; /** Actual number of monitored nodes, size-of-the-above-array or * number-of-array-elements-in-OD-0x1016, whichever is smaller. */ uint8_t numberOfMonitoredNodes; @@ -148,25 +142,22 @@ typedef struct { /** previous state of the variable */ bool_t NMTisPreOrOperationalPrev; /** From CO_HBconsumer_init() */ - CO_CANmodule_t *CANdevRx; + CO_CANmodule_t* CANdevRx; /** From CO_HBconsumer_init() */ uint16_t CANdevRxIdxStart; -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** Extension for OD object */ OD_extension_t OD_1016_extension; #endif -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN /** Callback for remote NMT changed event. * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ - void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t NMTstate, - void *object); + void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t NMTstate, void* object); /** Pointer to object */ - void *pFunctSignalObjectNmtChanged; + void* pFunctSignalObjectNmtChanged; #endif } CO_HBconsumer_t; - /** * Initialize Heartbeat consumer object. * @@ -186,17 +177,11 @@ typedef struct { * * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, - CO_EM_t *em, - CO_HBconsNode_t *monitoredNodes, - uint8_t monitoredNodesCount, - OD_entry_t *OD_1016_HBcons, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdxStart, - uint32_t *errInfo); +CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t* HBcons, CO_EM_t* em, CO_HBconsNode_t* monitoredNodes, + uint8_t monitoredNodesCount, OD_entry_t* OD_1016_HBcons, CO_CANmodule_t* CANdevRx, + uint16_t CANdevRxIdxStart, uint32_t* errInfo); - -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer callback function. * @@ -208,15 +193,11 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t *HBcons, * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_HBconsumer_initCallbackPre( - CO_HBconsumer_t *HBcons, - void *object, - void (*pFunctSignal)(void *object)); +void CO_HBconsumer_initCallbackPre(CO_HBconsumer_t* HBcons, void* object, void (*pFunctSignal)(void* object)); #endif -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ - || (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) \ - || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ + || (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer NMT changed callback function. * @@ -230,16 +211,12 @@ void CO_HBconsumer_initCallbackPre( * Can be NULL. * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_HBconsumer_initCallbackNmtChanged( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, - CO_NMT_internalState_t NMTstate, - void *object)); +void CO_HBconsumer_initCallbackNmtChanged(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, + CO_NMT_internalState_t NMTstate, void* object)); #endif -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN /** * Initialize Heartbeat consumer started callback function. * @@ -252,11 +229,8 @@ void CO_HBconsumer_initCallbackNmtChanged( * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_HBconsumer_initCallbackHeartbeatStarted( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); +void CO_HBconsumer_initCallbackHeartbeatStarted(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void* object)); /** * Initialize Heartbeat consumer timeout callback function. @@ -270,11 +244,8 @@ void CO_HBconsumer_initCallbackHeartbeatStarted( * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_HBconsumer_initCallbackTimeout( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); +void CO_HBconsumer_initCallbackTimeout(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void* object)); /** * Initialize Heartbeat consumer remote reset detected callback function. @@ -288,11 +259,8 @@ void CO_HBconsumer_initCallbackTimeout( * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_HBconsumer_initCallbackRemoteReset( - CO_HBconsumer_t *HBcons, - uint8_t idx, - void *object, - void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); +void CO_HBconsumer_initCallbackRemoteReset(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, + void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void* object)); #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI */ /** @@ -305,14 +273,10 @@ void CO_HBconsumer_initCallbackRemoteReset( * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_HBconsumer_process( - CO_HBconsumer_t *HBcons, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us); - +void CO_HBconsumer_process(CO_HBconsumer_t* HBcons, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, + uint32_t* timerNext_us); -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_QUERY_FUNCT) != 0) || defined CO_DOXYGEN /** * Get the heartbeat producer object index by node ID * @@ -320,9 +284,7 @@ void CO_HBconsumer_process( * @param nodeId producer node ID * @return index. -1 if not found */ -int8_t CO_HBconsumer_getIdxByNodeId( - CO_HBconsumer_t *HBcons, - uint8_t nodeId); +int8_t CO_HBconsumer_getIdxByNodeId(CO_HBconsumer_t* HBcons, uint8_t nodeId); /** * Get the current state of a heartbeat producer by the index in OD 0x1016 @@ -331,9 +293,7 @@ int8_t CO_HBconsumer_getIdxByNodeId( * @param idx object sub index * @return #CO_HBconsumer_state_t */ -CO_HBconsumer_state_t CO_HBconsumer_getState( - CO_HBconsumer_t *HBcons, - uint8_t idx); +CO_HBconsumer_state_t CO_HBconsumer_getState(CO_HBconsumer_t* HBcons, uint8_t idx); /** * Get the current NMT state of a heartbeat producer by the index in OD 0x1016 @@ -346,10 +306,7 @@ CO_HBconsumer_state_t CO_HBconsumer_getState( * @retval 0 NMT state has been received and is valid * @retval -1 not valid */ -int8_t CO_HBconsumer_getNmtState( - CO_HBconsumer_t *HBcons, - uint8_t idx, - CO_NMT_internalState_t *nmtState); +int8_t CO_HBconsumer_getNmtState(CO_HBconsumer_t* HBcons, uint8_t idx, CO_NMT_internalState_t* nmtState); #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT */ diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index 0bd39370..c95d9c5e 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -27,8 +27,7 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_NMT -#define CO_CONFIG_NMT (CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) +#define CO_CONFIG_NMT (CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #ifdef __cplusplus @@ -82,7 +81,6 @@ typedef enum { CO_NMT_STOPPED = 4 } CO_NMT_internalState_t; - /** * Commands from NMT master. */ @@ -101,7 +99,6 @@ typedef enum { CO_NMT_RESET_COMMUNICATION = 130 } CO_NMT_command_t; - /** * Return code from CO_NMT_process() that tells application code what to * reset. @@ -118,7 +115,6 @@ typedef enum { CO_RESET_QUIT = 3 } CO_NMT_reset_cmd_t; - /** * @defgroup CO_NMT_control_t NMT control bitfield for NMT internal state. * @{ @@ -134,28 +130,27 @@ typedef enum { /** First 8 bits can be used to specify bitmask for the * @ref CO_errorRegister_t to get relevant bits for the calculation. */ -#define CO_NMT_ERR_REG_MASK 0x00FFU +#define CO_NMT_ERR_REG_MASK 0x00FFU /** If bit is set then device enters NMT operational state after the * initialization phase otherwise it enters NMT pre-operational state. */ #define CO_NMT_STARTUP_TO_OPERATIONAL 0x0100U /** If bit is set and device is operational it enters NMT pre-operational * or stopped state if CAN bus is off or heartbeat consumer timeout is * detected. */ -#define CO_NMT_ERR_ON_BUSOFF_HB 0x1000U +#define CO_NMT_ERR_ON_BUSOFF_HB 0x1000U /** If bit is set and device is operational it enters NMT pre-operational * or stopped state if masked CANopen error register is different than * zero. */ -#define CO_NMT_ERR_ON_ERR_REG 0x2000U +#define CO_NMT_ERR_ON_ERR_REG 0x2000U /** If bit is set and CO_NMT_ERR_ON_xx condition is met then device will * enter NMT stopped state otherwise it will enter NMT pre-op state. */ -#define CO_NMT_ERR_TO_STOPPED 0x4000U +#define CO_NMT_ERR_TO_STOPPED 0x4000U /** If bit is set and device is pre-operational it enters NMT operational * state automatically if conditions from CO_NMT_ERR_ON_xx are all false.*/ -#define CO_NMT_ERR_FREE_TO_OPERATIONAL 0x8000U +#define CO_NMT_ERR_FREE_TO_OPERATIONAL 0x8000U /** @} */ /* CO_NMT_control_t */ - /** * NMT consumer and Heartbeat producer object */ @@ -178,30 +173,29 @@ typedef struct { /** Extension for OD object */ OD_extension_t OD_1017_extension; /** From CO_NMT_init() */ - CO_EM_t *em; -#if (((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0) || defined CO_DOXYGEN + CO_EM_t* em; +#if (((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0) || defined CO_DOXYGEN /** From CO_NMT_init() */ - CO_CANmodule_t *NMT_CANdevTx; + CO_CANmodule_t* NMT_CANdevTx; /** CAN transmit buffer for NMT master message */ - CO_CANtx_t *NMT_TXbuff; + CO_CANtx_t* NMT_TXbuff; #endif /** From CO_NMT_init() */ - CO_CANmodule_t *HB_CANdevTx; + CO_CANmodule_t* HB_CANdevTx; /** CAN transmit buffer for heartbeat message */ - CO_CANtx_t *HB_TXbuff; -#if (((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN + CO_CANtx_t* HB_TXbuff; +#if (((CO_CONFIG_NMT)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_NMT_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void* object); /** From CO_NMT_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void* functSignalObjectPre; #endif -#if (((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT)&CO_CONFIG_NMT_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN /** From CO_NMT_initCallbackChanged() or NULL */ void (*pFunctNMT)(CO_NMT_internalState_t state); #endif } CO_NMT_t; - /** * Initialize NMT and Heartbeat producer object. * @@ -231,27 +225,15 @@ typedef struct { * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, - OD_entry_t *OD_1017_ProducerHbTime, - CO_EM_t *em, - uint8_t nodeId, - uint16_t NMTcontrol, - uint16_t firstHBTime_ms, - CO_CANmodule_t *NMT_CANdevRx, - uint16_t NMT_rxIdx, - uint16_t CANidRxNMT, -#if (((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) != 0) || defined CO_DOXYGEN - CO_CANmodule_t *NMT_CANdevTx, - uint16_t NMT_txIdx, - uint16_t CANidTxNMT, +CO_ReturnError_t CO_NMT_init(CO_NMT_t* NMT, OD_entry_t* OD_1017_ProducerHbTime, CO_EM_t* em, uint8_t nodeId, + uint16_t NMTcontrol, uint16_t firstHBTime_ms, CO_CANmodule_t* NMT_CANdevRx, + uint16_t NMT_rxIdx, uint16_t CANidRxNMT, +#if (((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0) || defined CO_DOXYGEN + CO_CANmodule_t* NMT_CANdevTx, uint16_t NMT_txIdx, uint16_t CANidTxNMT, #endif - CO_CANmodule_t *HB_CANdevTx, - uint16_t HB_txIdx, - uint16_t CANidTxHB, - uint32_t *errInfo); - + CO_CANmodule_t* HB_CANdevTx, uint16_t HB_txIdx, uint16_t CANidTxHB, uint32_t* errInfo); -#if (((CO_CONFIG_NMT) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize NMT callback function after message preprocessed. * @@ -264,13 +246,10 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t *NMT, * Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_NMT_initCallbackPre(CO_NMT_t *NMT, - void *object, - void (*pFunctSignal)(void *object)); +void CO_NMT_initCallbackPre(CO_NMT_t* NMT, void* object, void (*pFunctSignal)(void* object)); #endif - -#if (((CO_CONFIG_NMT) & CO_CONFIG_NMT_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_NMT)&CO_CONFIG_NMT_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN /** * Initialize NMT callback function. * @@ -282,11 +261,9 @@ void CO_NMT_initCallbackPre(CO_NMT_t *NMT, * @param NMT This object. * @param pFunctNMT Pointer to the callback function. Not called if NULL. */ -void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, - void (*pFunctNMT)(CO_NMT_internalState_t state)); +void CO_NMT_initCallbackChanged(CO_NMT_t* NMT, void (*pFunctNMT)(CO_NMT_internalState_t state)); #endif - /** * Process received NMT and produce Heartbeat messages. * @@ -300,11 +277,8 @@ void CO_NMT_initCallbackChanged(CO_NMT_t *NMT, * * @return #CO_NMT_reset_cmd_t */ -CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, - CO_NMT_internalState_t *NMTstate, - uint32_t timeDifference_us, - uint32_t *timerNext_us); - +CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t* NMT, CO_NMT_internalState_t* NMTstate, uint32_t timeDifference_us, + uint32_t* timerNext_us); /** * Query current NMT state @@ -313,11 +287,11 @@ CO_NMT_reset_cmd_t CO_NMT_process(CO_NMT_t *NMT, * * @return @ref CO_NMT_internalState_t */ -static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { +static inline CO_NMT_internalState_t +CO_NMT_getInternalState(CO_NMT_t* NMT) { return (NMT == NULL) ? CO_NMT_INITIALIZING : NMT->operatingState; } - /** * Send NMT command to self, without sending NMT message * @@ -326,14 +300,14 @@ static inline CO_NMT_internalState_t CO_NMT_getInternalState(CO_NMT_t *NMT) { * @param NMT This object. * @param command NMT command */ -static inline void CO_NMT_sendInternalCommand(CO_NMT_t *NMT, - CO_NMT_command_t command) -{ - if (NMT != NULL) { NMT->internalCommand = command; } +static inline void +CO_NMT_sendInternalCommand(CO_NMT_t* NMT, CO_NMT_command_t command) { + if (NMT != NULL) { + NMT->internalCommand = command; + } } - -#if ((CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN +#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) || defined CO_DOXYGEN /** * Send NMT master command. * @@ -349,9 +323,7 @@ static inline void CO_NMT_sendInternalCommand(CO_NMT_t *NMT, * * @return CO_ERROR_NO on success or CO_ReturnError_t from CO_CANsend(). */ -CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t *NMT, - CO_NMT_command_t command, - uint8_t nodeID); +CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t* NMT, CO_NMT_command_t command, uint8_t nodeID); #endif /* (CO_CONFIG_NMT) & CO_CONFIG_NMT_MASTER */ diff --git a/301/CO_Node_Guarding.h b/301/CO_Node_Guarding.h index 35596f27..1f7eba5c 100644 --- a/301/CO_Node_Guarding.h +++ b/301/CO_Node_Guarding.h @@ -34,7 +34,7 @@ #define CO_CONFIG_NODE_GUARDING_MASTER_COUNT 0x7F #endif -#if (((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -77,9 +77,9 @@ extern "C" { */ typedef struct { /** From CO_nodeGuardingSlave_init() */ - CO_EM_t *em; + CO_EM_t* em; /** Indicates, if new rtr message received from CAN bus */ - volatile void *CANrxNew; + volatile void* CANrxNew; /** Guard time in microseconds, calculated from OD_0x100C */ uint32_t guardTime_us; /** Life time in microseconds, calculated from guardTime_us * lifeTimeFactor */ @@ -97,12 +97,11 @@ typedef struct { /** Extension for OD object */ OD_extension_t OD_100D_extension; /** From CO_nodeGuardingSlave_init() */ - CO_CANmodule_t *CANdevTx; + CO_CANmodule_t* CANdevTx; /** CAN transmit buffer for the message */ - CO_CANtx_t *CANtxBuff; + CO_CANtx_t* CANtxBuff; } CO_nodeGuardingSlave_t; - /** * Initialize Node Guarding slave object. * @@ -124,17 +123,10 @@ typedef struct { * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, - OD_entry_t *OD_100C_GuardTime, - OD_entry_t *OD_100D_LifeTimeFactor, - CO_EM_t *em, - uint16_t CANidNodeGuarding, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint32_t *errInfo); - +CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t* ngs, OD_entry_t* OD_100C_GuardTime, + OD_entry_t* OD_100D_LifeTimeFactor, CO_EM_t* em, uint16_t CANidNodeGuarding, + CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t* CANdevTx, + uint16_t CANdevTxIdx, uint32_t* errInfo); /** * Process Node Guarding slave. @@ -148,12 +140,8 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t *ngs, * microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, - CO_NMT_internalState_t NMTstate, - bool_t slaveDisable, - uint32_t timeDifference_us, - uint32_t *timerNext_us); - +void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t* ngs, CO_NMT_internalState_t NMTstate, bool_t slaveDisable, + uint32_t timeDifference_us, uint32_t* timerNext_us); /** * Inquire, if Node guarding slave detected life time timeout @@ -164,12 +152,11 @@ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t *ngs, * * @return true, if life time timeout was detected. */ -static inline bool_t CO_nodeGuardingSlave_isTimeout(CO_nodeGuardingSlave_t *ngs) -{ +static inline bool_t +CO_nodeGuardingSlave_isTimeout(CO_nodeGuardingSlave_t* ngs) { return (ngs == NULL) || ngs->lifeTimeTimeout; } - /** @} */ /* CO_Node_Guarding */ #ifdef __cplusplus @@ -178,10 +165,7 @@ static inline bool_t CO_nodeGuardingSlave_isTimeout(CO_nodeGuardingSlave_t *ngs) #endif /* (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE */ - - - -#if (((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0) || defined CO_DOXYGEN #if CO_CONFIG_NODE_GUARDING_MASTER_COUNT < 1 || CO_CONFIG_NODE_GUARDING_MASTER_COUNT > 127 #error CO_CONFIG_NODE_GUARDING_MASTER_COUNT value is wrong! @@ -223,13 +207,13 @@ typedef struct { */ typedef struct { /** From CO_nodeGuardingMaster_init() */ - CO_EM_t *em; + CO_EM_t* em; /** From CO_nodeGuardingMaster_init() */ - CO_CANmodule_t *CANdevTx; + CO_CANmodule_t* CANdevTx; /** From CO_nodeGuardingMaster_init() */ uint16_t CANdevTxIdx; /** CAN transmit buffer for the message */ - CO_CANtx_t *CANtxBuff; + CO_CANtx_t* CANtxBuff; /** True, if all monitored nodes are active or no node is monitored. Can be * read by the application */ bool_t allMonitoredActive; @@ -254,12 +238,8 @@ typedef struct { * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, - CO_EM_t *em, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx); +CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t* ngm, CO_EM_t* em, CO_CANmodule_t* CANdevRx, + uint16_t CANdevRxIdx, CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx); /** * Initialize node inside Node Guarding master object. @@ -275,9 +255,7 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t *ngm, * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t *ngm, - uint8_t index, - uint8_t nodeId, +CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t* ngm, uint8_t index, uint8_t nodeId, uint16_t guardTime_ms); /** @@ -290,9 +268,7 @@ CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t *ngm, * microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t *ngm, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t* ngm, uint32_t timeDifference_us, uint32_t* timerNext_us); /** @} */ /* @addtogroup CO_Node_Guarding */ diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index b7d3b868..d9034fbe 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -54,88 +54,85 @@ typedef uint8_t OD_attr_t; #define CO_PROGMEM const #endif - /** * Common DS301 object dictionary entries. */ typedef enum { - OD_H1000_DEV_TYPE = 0x1000U,/**< Device type */ - OD_H1001_ERR_REG = 0x1001U,/**< Error register */ - OD_H1002_MANUF_STATUS_REG = 0x1002U,/**< Manufacturer status register */ - OD_H1003_PREDEF_ERR_FIELD = 0x1003U,/**< Predefined error field */ - OD_H1004_RSV = 0x1004U,/**< Reserved */ - OD_H1005_COBID_SYNC = 0x1005U,/**< Sync message cob-id */ - OD_H1006_COMM_CYCL_PERIOD = 0x1006U,/**< Communication cycle period */ - OD_H1007_SYNC_WINDOW_LEN = 0x1007U,/**< Sync windows length */ - OD_H1008_MANUF_DEV_NAME = 0x1008U,/**< Manufacturer device name */ - OD_H1009_MANUF_HW_VERSION = 0x1009U,/**< Manufacturer hardware version */ - OD_H100A_MANUF_SW_VERSION = 0x100AU,/**< Manufacturer software version */ - OD_H100B_RSV = 0x100BU,/**< Reserved */ - OD_H100C_GUARD_TIME = 0x100CU,/**< Guard time */ - OD_H100D_LIFETIME_FACTOR = 0x100DU,/**< Life time factor */ - OD_H100E_RSV = 0x100EU,/**< Reserved */ - OD_H100F_RSV = 0x100FU,/**< Reserved */ - OD_H1010_STORE_PARAMETERS = 0x1010U,/**< Store params in persistent mem.*/ - OD_H1011_RESTORE_DEFAULT = 0x1011U,/**< Restore default parameters */ - OD_H1012_COBID_TIME = 0x1012U,/**< Timestamp message cob-id */ - OD_H1013_HIGH_RES_TIMESTAMP = 0x1013U,/**< High resolution timestamp */ - OD_H1014_COBID_EMERGENCY = 0x1014U,/**< Emergency message cob-id */ - OD_H1015_INHIBIT_TIME_EMCY = 0x1015U,/**< Inhibit time emergency message */ - OD_H1016_CONSUMER_HB_TIME = 0x1016U,/**< Consumer heartbeat time */ - OD_H1017_PRODUCER_HB_TIME = 0x1017U,/**< Producer heartbeat time */ - OD_H1018_IDENTITY_OBJECT = 0x1018U,/**< Identity object */ - OD_H1019_SYNC_CNT_OVERFLOW = 0x1019U,/**< Sync counter overflow value */ - OD_H1020_VERIFY_CONFIG = 0x1020U,/**< Verify configuration */ - OD_H1021_STORE_EDS = 0x1021U,/**< Store EDS */ - OD_H1022_STORE_FORMAT = 0x1022U,/**< Store format */ - OD_H1023_OS_CMD = 0x1023U,/**< OS command */ - OD_H1024_OS_CMD_MODE = 0x1024U,/**< OS command mode */ - OD_H1025_OS_DBG_INTERFACE = 0x1025U,/**< OS debug interface */ - OD_H1026_OS_PROMPT = 0x1026U,/**< OS prompt */ - OD_H1027_MODULE_LIST = 0x1027U,/**< Module list */ - OD_H1028_EMCY_CONSUMER = 0x1028U,/**< Emergency consumer object */ - OD_H1029_ERR_BEHAVIOR = 0x1029U,/**< Error behaviour */ - OD_H1200_SDO_SERVER_1_PARAM = 0x1200U,/**< SDO server parameter */ - OD_H1280_SDO_CLIENT_1_PARAM = 0x1280U,/**< SDO client parameter */ - OD_H1300_GFC_PARAM = 0x1300U,/**< Global fail-safe command param */ - OD_H1301_SRDO_1_PARAM = 0x1301U,/**< SRDO communication parameter */ - OD_H1381_SRDO_1_MAPPING = 0x1381U,/**< SRDO mapping parameter */ - OD_H13FE_SRDO_VALID = 0x13FEU,/**< SRDO Configuration valid */ - OD_H13FF_SRDO_CHECKSUM = 0x13FFU,/**< SRDO configuration checksum */ - OD_H1400_RXPDO_1_PARAM = 0x1400U,/**< RXPDO communication parameter */ - OD_H1600_RXPDO_1_MAPPING = 0x1600U,/**< RXPDO mapping parameters */ - OD_H1800_TXPDO_1_PARAM = 0x1800U,/**< TXPDO communication parameter */ - OD_H1A00_TXPDO_1_MAPPING = 0x1A00U,/**< TXPDO mapping parameters */ + OD_H1000_DEV_TYPE = 0x1000U, /**< Device type */ + OD_H1001_ERR_REG = 0x1001U, /**< Error register */ + OD_H1002_MANUF_STATUS_REG = 0x1002U, /**< Manufacturer status register */ + OD_H1003_PREDEF_ERR_FIELD = 0x1003U, /**< Predefined error field */ + OD_H1004_RSV = 0x1004U, /**< Reserved */ + OD_H1005_COBID_SYNC = 0x1005U, /**< Sync message cob-id */ + OD_H1006_COMM_CYCL_PERIOD = 0x1006U, /**< Communication cycle period */ + OD_H1007_SYNC_WINDOW_LEN = 0x1007U, /**< Sync windows length */ + OD_H1008_MANUF_DEV_NAME = 0x1008U, /**< Manufacturer device name */ + OD_H1009_MANUF_HW_VERSION = 0x1009U, /**< Manufacturer hardware version */ + OD_H100A_MANUF_SW_VERSION = 0x100AU, /**< Manufacturer software version */ + OD_H100B_RSV = 0x100BU, /**< Reserved */ + OD_H100C_GUARD_TIME = 0x100CU, /**< Guard time */ + OD_H100D_LIFETIME_FACTOR = 0x100DU, /**< Life time factor */ + OD_H100E_RSV = 0x100EU, /**< Reserved */ + OD_H100F_RSV = 0x100FU, /**< Reserved */ + OD_H1010_STORE_PARAMETERS = 0x1010U, /**< Store params in persistent mem.*/ + OD_H1011_RESTORE_DEFAULT = 0x1011U, /**< Restore default parameters */ + OD_H1012_COBID_TIME = 0x1012U, /**< Timestamp message cob-id */ + OD_H1013_HIGH_RES_TIMESTAMP = 0x1013U, /**< High resolution timestamp */ + OD_H1014_COBID_EMERGENCY = 0x1014U, /**< Emergency message cob-id */ + OD_H1015_INHIBIT_TIME_EMCY = 0x1015U, /**< Inhibit time emergency message */ + OD_H1016_CONSUMER_HB_TIME = 0x1016U, /**< Consumer heartbeat time */ + OD_H1017_PRODUCER_HB_TIME = 0x1017U, /**< Producer heartbeat time */ + OD_H1018_IDENTITY_OBJECT = 0x1018U, /**< Identity object */ + OD_H1019_SYNC_CNT_OVERFLOW = 0x1019U, /**< Sync counter overflow value */ + OD_H1020_VERIFY_CONFIG = 0x1020U, /**< Verify configuration */ + OD_H1021_STORE_EDS = 0x1021U, /**< Store EDS */ + OD_H1022_STORE_FORMAT = 0x1022U, /**< Store format */ + OD_H1023_OS_CMD = 0x1023U, /**< OS command */ + OD_H1024_OS_CMD_MODE = 0x1024U, /**< OS command mode */ + OD_H1025_OS_DBG_INTERFACE = 0x1025U, /**< OS debug interface */ + OD_H1026_OS_PROMPT = 0x1026U, /**< OS prompt */ + OD_H1027_MODULE_LIST = 0x1027U, /**< Module list */ + OD_H1028_EMCY_CONSUMER = 0x1028U, /**< Emergency consumer object */ + OD_H1029_ERR_BEHAVIOR = 0x1029U, /**< Error behaviour */ + OD_H1200_SDO_SERVER_1_PARAM = 0x1200U, /**< SDO server parameter */ + OD_H1280_SDO_CLIENT_1_PARAM = 0x1280U, /**< SDO client parameter */ + OD_H1300_GFC_PARAM = 0x1300U, /**< Global fail-safe command param */ + OD_H1301_SRDO_1_PARAM = 0x1301U, /**< SRDO communication parameter */ + OD_H1381_SRDO_1_MAPPING = 0x1381U, /**< SRDO mapping parameter */ + OD_H13FE_SRDO_VALID = 0x13FEU, /**< SRDO Configuration valid */ + OD_H13FF_SRDO_CHECKSUM = 0x13FFU, /**< SRDO configuration checksum */ + OD_H1400_RXPDO_1_PARAM = 0x1400U, /**< RXPDO communication parameter */ + OD_H1600_RXPDO_1_MAPPING = 0x1600U, /**< RXPDO mapping parameters */ + OD_H1800_TXPDO_1_PARAM = 0x1800U, /**< TXPDO communication parameter */ + OD_H1A00_TXPDO_1_MAPPING = 0x1A00U, /**< TXPDO mapping parameters */ } OD_ObjDicId_30x_t; - /** * Attributes (bit masks) for OD sub-object. */ typedef enum { - ODA_SDO_R = 0x01U, /**< SDO server may read from the variable */ - ODA_SDO_W = 0x02U, /**< SDO server may write to the variable */ + ODA_SDO_R = 0x01U, /**< SDO server may read from the variable */ + ODA_SDO_W = 0x02U, /**< SDO server may write to the variable */ ODA_SDO_RW = 0x03U, /**< SDO server may read from or write to the variable */ - ODA_TPDO = 0x04U, /**< Variable is mappable into TPDO (can be read) */ - ODA_RPDO = 0x08U, /**< Variable is mappable into RPDO (can be written) */ - ODA_TRPDO = 0x0CU, /**< Variable is mappable into TPDO or RPDO */ - ODA_TSRDO = 0x10U, /**< Variable is mappable into transmitting SRDO */ - ODA_RSRDO = 0x20U, /**< Variable is mappable into receiving SRDO */ + ODA_TPDO = 0x04U, /**< Variable is mappable into TPDO (can be read) */ + ODA_RPDO = 0x08U, /**< Variable is mappable into RPDO (can be written) */ + ODA_TRPDO = 0x0CU, /**< Variable is mappable into TPDO or RPDO */ + ODA_TSRDO = 0x10U, /**< Variable is mappable into transmitting SRDO */ + ODA_RSRDO = 0x20U, /**< Variable is mappable into receiving SRDO */ ODA_TRSRDO = 0x30U, /**< Variable is mappable into tx or rx SRDO */ - ODA_MB = 0x40U, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */ - ODA_STR = 0x80U /**< Shorter value, than specified variable size, may be + ODA_MB = 0x40U, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */ + ODA_STR = 0x80U /**< Shorter value, than specified variable size, may be written to the variable. SDO write will fill remaining memory with zeroes. Attribute is used for VISIBLE_STRING and UNICODE_STRING. */ } OD_attributes_t; - /** * Return codes from OD access functions. * * @ref OD_getSDOabCode() can be used to retrieve corresponding SDO abort code. */ typedef enum { -/* !!!! WARNING !!!! + /* !!!! WARNING !!!! * If changing these values, change also OD_getSDOabCode() function! */ /** Read/write is only partial, make more calls */ @@ -196,7 +193,6 @@ typedef enum { ODR_COUNT = 26 } ODR_t; - /** * IO stream structure, used for read/write access to OD variable, part of * @ref OD_IO_t. @@ -206,11 +202,11 @@ typedef struct { * read/write functions operate on it. If memory for data object is not * specified by Object Dictionary, then dataOrig is NULL. */ - void *dataOrig; + void* dataOrig; /** Pointer to object, passed by @ref OD_extension_init(). Can be used * inside read / write functions from IO extension. */ - void *object; + void* object; /** Data length in bytes or 0, if length is not specified */ OD_size_t dataLength; /** In case of large data, dataOffset indicates position of already @@ -224,7 +220,6 @@ typedef struct { uint8_t subIndex; } OD_stream_t; - /** * Structure for input / output on the OD variable. It is initialized with * @ref OD_getSub() function. Access principle to OD variable is via read/write @@ -265,8 +260,7 @@ typedef struct { * * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ - ODR_t (*read)(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead); + ODR_t (*read)(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead); /** * Function pointer for writing value into specified variable inside Object * Dictionary. If OD variable is larger than buf, then this function must @@ -295,28 +289,24 @@ typedef struct { * * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ - ODR_t (*write)(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten); + ODR_t (*write)(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten); } OD_IO_t; - /** * Extension of OD object, which can optionally be specified by application in * initialization phase with @ref OD_extension_init() function. */ typedef struct { /** Object on which read and write will operate, part of @ref OD_stream_t */ - void *object; + void* object; /** Application specified read function pointer. If NULL, then read will be * disabled. @ref OD_readOriginal can be used here to keep the original read * function. For function description see @ref OD_IO_t. */ - ODR_t (*read)(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead); + ODR_t (*read)(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead); /** Application specified write function pointer. If NULL, then write will * be disabled. @ref OD_writeOriginal can be used here to keep the original * write function. For function description see @ref OD_IO_t. */ - ODR_t (*write)(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten); + ODR_t (*write)(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten); #if OD_FLAGS_PDO_SIZE > 0 /**PDO flags bit-field provides one bit for each OD variable, which exist * inside OD object at specific sub index. If application clears that bit, @@ -332,7 +322,6 @@ typedef struct { #endif } OD_extension_t; - /** * Object Dictionary entry for one OD object. * @@ -350,12 +339,11 @@ typedef struct { uint8_t odObjectType; /** OD object of type indicated by odObjectType, from which @ref OD_getSub() * fetches the information */ - CO_PROGMEM void *odObject; + CO_PROGMEM void* odObject; /** Extension to OD, specified by application */ - OD_extension_t *extension; + OD_extension_t* extension; } OD_entry_t; - /** * Object Dictionary */ @@ -363,10 +351,9 @@ typedef struct { /** Number of elements in the list, without last element, which is blank */ uint16_t size; /** List OD entries (table of contents), ordered by index */ - OD_entry_t *list; + OD_entry_t* list; } OD_t; - /** * Read value from original OD location * @@ -376,9 +363,7 @@ typedef struct { * io->read returned by @ref OD_getSub() equals to this function. See * also @ref OD_IO_t. */ -ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, - OD_size_t count, OD_size_t *countRead); - +ODR_t OD_readOriginal(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead); /** * Write value to original OD location @@ -389,9 +374,7 @@ ODR_t OD_readOriginal(OD_stream_t *stream, void *buf, * io->write returned by @ref OD_getSub() equals to this function. See * also @ref OD_IO_t. */ -ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, - OD_size_t count, OD_size_t *countWritten); - +ODR_t OD_writeOriginal(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten); /** * Find OD entry in Object Dictionary @@ -401,8 +384,7 @@ ODR_t OD_writeOriginal(OD_stream_t *stream, const void *buf, * * @return Pointer to OD entry or NULL if not found */ -OD_entry_t *OD_find(OD_t *od, uint16_t index); - +OD_entry_t* OD_find(OD_t* od, uint16_t index); /** * Find sub-object with specified sub-index on OD entry returned by OD_find. @@ -420,9 +402,7 @@ OD_entry_t *OD_find(OD_t *od, uint16_t index); * * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ -ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, - OD_IO_t *io, bool_t odOrig); - +ODR_t OD_getSub(const OD_entry_t* entry, uint8_t subIndex, OD_IO_t* io, bool_t odOrig); /** * Return index from OD entry @@ -431,11 +411,11 @@ ODR_t OD_getSub(const OD_entry_t *entry, uint8_t subIndex, * * @return OD index */ -static inline uint16_t OD_getIndex(const OD_entry_t *entry) { +static inline uint16_t +OD_getIndex(const OD_entry_t* entry) { return (entry != NULL) ? entry->index : 0U; } - /** * Check, if OD variable is mappable to PDO or SRDO. * @@ -446,12 +426,11 @@ static inline uint16_t OD_getIndex(const OD_entry_t *entry) { * * @return true, if OD variable is mappable. */ -static inline bool_t OD_mappable(OD_stream_t *stream) { - return (stream != NULL) - ? ((stream->attribute & ((OD_attr_t)ODA_TRPDO | (OD_attr_t)ODA_TRSRDO)) != 0U) : false; +static inline bool_t +OD_mappable(OD_stream_t* stream) { + return (stream != NULL) ? ((stream->attribute & ((OD_attr_t)ODA_TRPDO | (OD_attr_t)ODA_TRSRDO)) != 0U) : false; } - /** * Restart read or write operation on OD variable * @@ -461,11 +440,13 @@ static inline bool_t OD_mappable(OD_stream_t *stream) { * * @param stream Object Dictionary stream object. */ -static inline void OD_rwRestart(OD_stream_t *stream) { - if (stream != NULL) { stream->dataOffset = 0U; } +static inline void +OD_rwRestart(OD_stream_t* stream) { + if (stream != NULL) { + stream->dataOffset = 0U; + } } - /** * Get TPDO request flags for OD entry. * @@ -475,7 +456,8 @@ static inline void OD_rwRestart(OD_stream_t *stream) { * * @return pointer to flagsPDO */ -static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) { +static inline uint8_t* +OD_getFlagsPDO(OD_entry_t* entry) { #if OD_FLAGS_PDO_SIZE > 0 if ((entry != NULL) && (entry->extension != NULL)) { return &entry->extension->flagsPDO[0]; @@ -484,7 +466,6 @@ static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) { return NULL; } - /** * Request TPDO, to which OD variable is mapped * @@ -502,7 +483,8 @@ static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) { * @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO. * @param subIndex subIndex of the OD variable. */ -static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) { +static inline void +OD_requestTPDO(uint8_t* flagsPDO, uint8_t subIndex) { #if OD_FLAGS_PDO_SIZE > 0 if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) { /* clear subIndex-th bit */ @@ -512,7 +494,6 @@ static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) { #endif } - /** * Check if requested TPDO was transmitted * @@ -524,7 +505,8 @@ static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) { * @ref OD_requestTPDO call. If there was no @ref OD_requestTPDO call yet and * TPDO was transmitted by other event, function also returns true. */ -static inline bool_t OD_TPDOtransmitted(uint8_t *flagsPDO, uint8_t subIndex) { +static inline bool_t +OD_TPDOtransmitted(uint8_t* flagsPDO, uint8_t subIndex) { #if OD_FLAGS_PDO_SIZE > 0 if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) { /* return true, if subIndex-th bit is set */ @@ -537,7 +519,6 @@ static inline bool_t OD_TPDOtransmitted(uint8_t *flagsPDO, uint8_t subIndex) { return false; } - /** * Get SDO abort code from returnCode * @@ -547,7 +528,6 @@ static inline bool_t OD_TPDOtransmitted(uint8_t *flagsPDO, uint8_t subIndex) { */ uint32_t OD_getSDOabCode(ODR_t returnCode); - /** * Extend OD object with own read/write functions and/or flagsPDO * @@ -580,15 +560,15 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); * * @return "ODR_OK" on success, "ODR_IDX_NOT_EXIST" if OD object doesn't exist. */ -static inline ODR_t OD_extension_init(OD_entry_t *entry, - OD_extension_t *extension) -{ - if (entry == NULL) { return ODR_IDX_NOT_EXIST; } +static inline ODR_t +OD_extension_init(OD_entry_t* entry, OD_extension_t* extension) { + if (entry == NULL) { + return ODR_IDX_NOT_EXIST; + } entry->extension = extension; return ODR_OK; } - /** * @defgroup CO_ODgetSetters Getters and setters * @{ @@ -610,76 +590,65 @@ static inline ODR_t OD_extension_init(OD_entry_t *entry, * variable does not exist in object dictionary or it does not have the correct * length or other reason. */ -ODR_t OD_get_value(const OD_entry_t *entry, uint8_t subIndex, - void *val, OD_size_t len, bool_t odOrig); +ODR_t OD_get_value(const OD_entry_t* entry, uint8_t subIndex, void* val, OD_size_t len, bool_t odOrig); /** Get int8_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_i8(const OD_entry_t *entry, uint8_t subIndex, - int8_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_i8(const OD_entry_t* entry, uint8_t subIndex, int8_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get int16_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_i16(const OD_entry_t *entry, uint8_t subIndex, - int16_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_i16(const OD_entry_t* entry, uint8_t subIndex, int16_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get int32_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_i32(const OD_entry_t *entry, uint8_t subIndex, - int32_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_i32(const OD_entry_t* entry, uint8_t subIndex, int32_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get int64_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_i64(const OD_entry_t *entry, uint8_t subIndex, - int64_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_i64(const OD_entry_t* entry, uint8_t subIndex, int64_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get uint8_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_u8(const OD_entry_t *entry, uint8_t subIndex, - uint8_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_u8(const OD_entry_t* entry, uint8_t subIndex, uint8_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get uint16_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_u16(const OD_entry_t *entry, uint8_t subIndex, - uint16_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_u16(const OD_entry_t* entry, uint8_t subIndex, uint16_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get uint32_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_u32(const OD_entry_t *entry, uint8_t subIndex, - uint32_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_u32(const OD_entry_t* entry, uint8_t subIndex, uint32_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get uint64_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_u64(const OD_entry_t *entry, uint8_t subIndex, - uint64_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_u64(const OD_entry_t* entry, uint8_t subIndex, uint64_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get float32_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_f32(const OD_entry_t *entry, uint8_t subIndex, - float32_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_f32(const OD_entry_t* entry, uint8_t subIndex, float32_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } /** Get float64_t variable from Object Dictionary, see @ref OD_get_value */ -static inline ODR_t OD_get_f64(const OD_entry_t *entry, uint8_t subIndex, - float64_t *val, bool_t odOrig) -{ +static inline ODR_t +OD_get_f64(const OD_entry_t* entry, uint8_t subIndex, float64_t* val, bool_t odOrig) { return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig); } @@ -697,76 +666,65 @@ static inline ODR_t OD_get_f64(const OD_entry_t *entry, uint8_t subIndex, * variable does not exist in object dictionary or it does not have the correct * length or other reason. */ -ODR_t OD_set_value(const OD_entry_t *entry, uint8_t subIndex, void *val, - OD_size_t len, bool_t odOrig); +ODR_t OD_set_value(const OD_entry_t* entry, uint8_t subIndex, void* val, OD_size_t len, bool_t odOrig); /** Set int8_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_i8(const OD_entry_t *entry, uint8_t subIndex, - int8_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_i8(const OD_entry_t* entry, uint8_t subIndex, int8_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set int16_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_i16(const OD_entry_t *entry, uint8_t subIndex, - int16_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_i16(const OD_entry_t* entry, uint8_t subIndex, int16_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set int32_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_i32(const OD_entry_t *entry, uint8_t subIndex, - int32_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_i32(const OD_entry_t* entry, uint8_t subIndex, int32_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set int32_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_i64(const OD_entry_t *entry, uint8_t subIndex, - int64_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_i64(const OD_entry_t* entry, uint8_t subIndex, int64_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set uint8_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_u8(const OD_entry_t *entry, uint8_t subIndex, - uint8_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_u8(const OD_entry_t* entry, uint8_t subIndex, uint8_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set uint16_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_u16(const OD_entry_t *entry, uint8_t subIndex, - uint16_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_u16(const OD_entry_t* entry, uint8_t subIndex, uint16_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set uint32_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_u32(const OD_entry_t *entry, uint8_t subIndex, - uint32_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_u32(const OD_entry_t* entry, uint8_t subIndex, uint32_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set uint64_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_u64(const OD_entry_t *entry, uint8_t subIndex, - uint64_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_u64(const OD_entry_t* entry, uint8_t subIndex, uint64_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set float32_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_f32(const OD_entry_t *entry, uint8_t subIndex, - float32_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_f32(const OD_entry_t* entry, uint8_t subIndex, float32_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } /** Set float64_t variable in Object Dictionary, see @ref OD_set_value */ -static inline ODR_t OD_set_f64(const OD_entry_t *entry, uint8_t subIndex, - float64_t val, bool_t odOrig) -{ +static inline ODR_t +OD_set_f64(const OD_entry_t* entry, uint8_t subIndex, float64_t val, bool_t odOrig) { return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig); } @@ -785,11 +743,9 @@ static inline ODR_t OD_set_f64(const OD_entry_t *entry, uint8_t subIndex, * * @return Pointer to variable in Object Dictionary or NULL in case of error. */ -void *OD_getPtr(const OD_entry_t *entry, uint8_t subIndex, OD_size_t len, - ODR_t *err); +void* OD_getPtr(const OD_entry_t* entry, uint8_t subIndex, OD_size_t len, ODR_t* err); /** @} */ /* CO_ODgetSetters */ - #if defined OD_DEFINITION || defined CO_DOXYGEN /** * @defgroup CO_ODdefinition OD definition objects @@ -827,8 +783,8 @@ typedef enum { * Object for single OD variable, used for "VAR" type OD objects */ typedef struct { - void *dataOrig; /**< Pointer to data */ - OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ + void* dataOrig; /**< Pointer to data */ + OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ OD_size_t dataLength; /**< Data length in bytes */ } OD_obj_var_t; @@ -836,11 +792,11 @@ typedef struct { * Object for OD array of variables, used for "ARRAY" type OD objects */ typedef struct { - uint8_t *dataOrig0; /**< Pointer to data for sub-index 0 */ - void *dataOrig; /**< Pointer to array of data */ - OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see + uint8_t* dataOrig0; /**< Pointer to data for sub-index 0 */ + void* dataOrig; /**< Pointer to array of data */ + OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see @ref OD_attributes_t */ - OD_attr_t attribute; /**< Attribute bitfield for array elements */ + OD_attr_t attribute; /**< Attribute bitfield for array elements */ OD_size_t dataElementLength; /**< Data length of array elements in bytes */ OD_size_t dataElementSizeof; /**< Sizeof one array element in bytes */ } OD_obj_array_t; @@ -849,9 +805,9 @@ typedef struct { * Object for OD sub-elements, used in "RECORD" type OD objects */ typedef struct { - void *dataOrig; /**< Pointer to data */ - uint8_t subIndex; /**< Sub index of element. */ - OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ + void* dataOrig; /**< Pointer to data */ + uint8_t subIndex; /**< Sub index of element. */ + OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */ OD_size_t dataLength; /**< Data length in bytes */ } OD_obj_record_t; diff --git a/301/CO_PDO.h b/301/CO_PDO.h index ff738458..55d1ad48 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -27,15 +27,10 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_PDO -#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \ - CO_CONFIG_TPDO_ENABLE | \ - CO_CONFIG_RPDO_TIMERS_ENABLE | \ - CO_CONFIG_TPDO_TIMERS_ENABLE | \ - CO_CONFIG_PDO_SYNC_ENABLE | \ - CO_CONFIG_PDO_OD_IO_ACCESS | \ - CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_PDO \ + (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_RPDO_TIMERS_ENABLE | CO_CONFIG_TPDO_TIMERS_ENABLE \ + | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_PDO_OD_IO_ACCESS | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE \ + | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #if (((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) != 0) || defined CO_DOXYGEN @@ -168,13 +163,13 @@ typedef uint8_t CO_PDO_size_t; * PDO transmission Types */ typedef enum { - CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC = 0U, /**< synchronous (acyclic) */ - CO_PDO_TRANSM_TYPE_SYNC_1 = 1U, /**< synchronous (cyclic every sync) */ - CO_PDO_TRANSM_TYPE_SYNC_240 = 0xF0U, /**< synchronous (cyclic every 240-th + CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC = 0U, /**< synchronous (acyclic) */ + CO_PDO_TRANSM_TYPE_SYNC_1 = 1U, /**< synchronous (cyclic every sync) */ + CO_PDO_TRANSM_TYPE_SYNC_240 = 0xF0U, /**< synchronous (cyclic every 240-th sync) */ CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO = 0xFEU, /**< event-driven, lower value (manufacturer specific), */ - CO_PDO_TRANSM_TYPE_SYNC_EVENT_HI = 0xFFU /**< event-driven, higher value + CO_PDO_TRANSM_TYPE_SYNC_EVENT_HI = 0xFFU /**< event-driven, higher value (device profile and application profile specific) */ } CO_PDO_transmissionTypes_t; @@ -183,16 +178,16 @@ typedef enum { */ typedef struct { /** From CO_xPDO_init() */ - CO_EM_t *em; + CO_EM_t* em; /** From CO_xPDO_init() */ - CO_CANmodule_t *CANdev; + CO_CANmodule_t* CANdev; /** True, if PDO is enabled and valid */ bool_t valid; /** Data length of the received PDO message. Calculated from mapping */ CO_PDO_size_t dataLength; /** Number of mapped objects in PDO */ uint8_t mappedObjectsCount; -#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) != 0) || defined CO_DOXYGEN /** Object dictionary interface for all mapped entries. OD_IO.dataOffset has * special usage with PDO. It stores information about mappedLength of * the variable. mappedLength can be less or equal to the OD_IO.dataLength. @@ -200,25 +195,25 @@ typedef struct { * OD_IO.dataOffset is set to 0 before read/write function call and after * the call OD_IO.dataOffset is set back to mappedLength. */ OD_IO_t OD_IO[CO_PDO_MAX_MAPPED_ENTRIES]; - #if OD_FLAGS_PDO_SIZE > 0 +#if OD_FLAGS_PDO_SIZE > 0 /** Pointer to byte, which contains PDO flag bit from @ref OD_extension_t */ - uint8_t *flagPDObyte[CO_PDO_MAX_MAPPED_ENTRIES]; + uint8_t* flagPDObyte[CO_PDO_MAX_MAPPED_ENTRIES]; /** Bitmask for the flagPDObyte */ uint8_t flagPDObitmask[CO_PDO_MAX_MAPPED_ENTRIES]; - #endif +#endif #else /* Pointers to data objects inside OD, where PDO will be copied */ - uint8_t *mapPointer[CO_PDO_MAX_SIZE]; - #if OD_FLAGS_PDO_SIZE > 0 - uint8_t *flagPDObyte[CO_PDO_MAX_SIZE]; + uint8_t* mapPointer[CO_PDO_MAX_SIZE]; +#if OD_FLAGS_PDO_SIZE > 0 + uint8_t* flagPDObyte[CO_PDO_MAX_SIZE]; uint8_t flagPDObitmask[CO_PDO_MAX_SIZE]; - #endif #endif -#if (((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** True for RPDO, false for TPDO */ bool_t isRPDO; /** From CO_xPDO_init() */ - OD_t *OD; + OD_t* OD; /** From CO_xPDO_init() */ uint16_t CANdevIdx; /** From CO_xPDO_init() */ @@ -232,21 +227,19 @@ typedef struct { #endif } CO_PDO_common_t; - /******************************************************************************* * R P D O ******************************************************************************/ -#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN /** * Number of buffers for received CAN message for RPDO */ -#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN #define CO_RPDO_CAN_BUFFERS_COUNT 2 #else #define CO_RPDO_CAN_BUFFERS_COUNT 1 #endif - /** * RPDO object. */ @@ -254,33 +247,32 @@ typedef struct { /** PDO common properties, must be first element in this object */ CO_PDO_common_t PDO_common; /** Variable indicates, if new PDO message received from CAN bus. */ - volatile void *CANrxNew[CO_RPDO_CAN_BUFFERS_COUNT]; + volatile void* CANrxNew[CO_RPDO_CAN_BUFFERS_COUNT]; /** CO_PDO_MAX_SIZE data bytes of the received message. */ uint8_t CANrxData[CO_RPDO_CAN_BUFFERS_COUNT][CO_PDO_MAX_SIZE]; /** Indication of RPDO length errors, use with CO_PDO_receiveErrors_t */ uint8_t receiveError; -#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN /** From CO_RPDO_init() */ - CO_SYNC_t *SYNC; + CO_SYNC_t* SYNC; /** True if transmissionType <= 240 */ bool_t synchronous; #endif -#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN /** Maximum timeout time between received PDOs in microseconds. Configurable * by OD variable RPDO communication parameter, event-timer. */ uint32_t timeoutTime_us; /** Timeout timer variable in microseconds */ uint32_t timeoutTimer; #endif -#if (((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_RPDO_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void* object); /** From CO_RPDO_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void* functSignalObjectPre; #endif } CO_RPDO_t; - /** * Initialize RPDO object. * @@ -304,21 +296,14 @@ typedef struct { * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, - OD_t *OD, - CO_EM_t *em, -#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN - CO_SYNC_t *SYNC, +CO_ReturnError_t CO_RPDO_init(CO_RPDO_t* RPDO, OD_t* OD, CO_EM_t* em, +#if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN + CO_SYNC_t* SYNC, #endif - uint16_t preDefinedCanId, - OD_entry_t *OD_14xx_RPDOCommPar, - OD_entry_t *OD_16xx_RPDOMapPar, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - uint32_t *errInfo); - + uint16_t preDefinedCanId, OD_entry_t* OD_14xx_RPDOCommPar, OD_entry_t* OD_16xx_RPDOMapPar, + CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, uint32_t* errInfo); -#if (((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize RPDO callback function. * @@ -330,12 +315,9 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO, * @param object Pointer to object, which will be passed to pFunctSignalPre(). * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_RPDO_initCallbackPre(CO_RPDO_t* RPDO, void* object, void (*pFunctSignalPre)(void* object)); #endif - /** * Process received PDO messages. * @@ -351,20 +333,17 @@ void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO, * @param syncWas True, if CANopen SYNC message was just received or * transmitted. */ -void CO_RPDO_process(CO_RPDO_t *RPDO, -#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN - uint32_t timeDifference_us, - uint32_t *timerNext_us, +void CO_RPDO_process(CO_RPDO_t* RPDO, +#if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN + uint32_t timeDifference_us, uint32_t* timerNext_us, #endif - bool_t NMTisOperational, - bool_t syncWas); + bool_t NMTisOperational, bool_t syncWas); #endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE */ - /******************************************************************************* * T P D O ******************************************************************************/ -#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN /** * TPDO object. */ @@ -372,21 +351,21 @@ typedef struct { /** PDO common properties, must be first element in this object */ CO_PDO_common_t PDO_common; /** CAN transmit buffer inside CANdev */ - CO_CANtx_t *CANtxBuff; + CO_CANtx_t* CANtxBuff; /** Copy of the variable from object dictionary */ uint8_t transmissionType; /** If this flag is set and TPDO is event driven (transmission type is 0, * 254 or 255), then PDO will be sent by CO_TPDO_process(). */ bool_t sendRequest; -#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN /** From CO_TPDO_init() */ - CO_SYNC_t *SYNC; + CO_SYNC_t* SYNC; /** Copy of the variable from object dictionary */ uint8_t syncStartValue; /** SYNC counter used for PDO sending */ uint8_t syncCounter; #endif -#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN /** Inhibit time from object dictionary translated to microseconds */ uint32_t inhibitTime_us; /** Event time from object dictionary translated to microseconds */ @@ -398,7 +377,6 @@ typedef struct { #endif } CO_TPDO_t; - /** * Initialize TPDO object. * @@ -422,19 +400,12 @@ typedef struct { * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, - OD_t *OD, - CO_EM_t *em, -#if (((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN - CO_SYNC_t *SYNC, +CO_ReturnError_t CO_TPDO_init(CO_TPDO_t* TPDO, OD_t* OD, CO_EM_t* em, +#if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN + CO_SYNC_t* SYNC, #endif - uint16_t preDefinedCanId, - OD_entry_t *OD_18xx_TPDOCommPar, - OD_entry_t *OD_1Axx_TPDOMapPar, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint32_t *errInfo); - + uint16_t preDefinedCanId, OD_entry_t* OD_18xx_TPDOCommPar, OD_entry_t* OD_1Axx_TPDOMapPar, + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, uint32_t* errInfo); /** * Request transmission of TPDO message. @@ -445,11 +416,13 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t *TPDO, * * @param TPDO TPDO object. */ -static inline void CO_TPDOsendRequest(CO_TPDO_t *TPDO) { - if (TPDO != NULL) { TPDO->sendRequest = true; } +static inline void +CO_TPDOsendRequest(CO_TPDO_t* TPDO) { + if (TPDO != NULL) { + TPDO->sendRequest = true; + } } - /** * Process transmitting PDO messages. * @@ -463,13 +436,11 @@ static inline void CO_TPDOsendRequest(CO_TPDO_t *TPDO) { * @param syncWas True, if CANopen SYNC message was just received or * transmitted. */ -void CO_TPDO_process(CO_TPDO_t *TPDO, -#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN - uint32_t timeDifference_us, - uint32_t *timerNext_us, +void CO_TPDO_process(CO_TPDO_t* TPDO, +#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN + uint32_t timeDifference_us, uint32_t* timerNext_us, #endif - bool_t NMTisOperational, - bool_t syncWas); + bool_t NMTisOperational, bool_t syncWas); #endif /* (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE */ /** @} */ /* CO_PDO */ diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index f4cac5c7..df096cdf 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -32,14 +32,14 @@ #define CO_CONFIG_SDO_CLI (0) #endif #ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE - #if ((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0 - #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000U - #else - #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32U - #endif +#if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000U +#else +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32U +#endif #endif -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -164,30 +164,29 @@ CO_SDO_abortCode_t write_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, * @see @ref CO_SDOserver */ - /** * SDO client object */ typedef struct { -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0) || defined CO_DOXYGEN /** From CO_SDOclient_init() */ - OD_t *OD; + OD_t* OD; /** From CO_SDOclient_init() */ uint8_t nodeId; /** Object dictionary interface for locally transferred object */ OD_IO_t OD_IO; #endif /** From CO_SDOclient_init() */ - CO_CANmodule_t *CANdevRx; + CO_CANmodule_t* CANdevRx; /** From CO_SDOclient_init() */ uint16_t CANdevRxIdx; /** From CO_SDOclient_init() */ - CO_CANmodule_t *CANdevTx; + CO_CANmodule_t* CANdevTx; /** From CO_SDOclient_init() */ uint16_t CANdevTxIdx; /** CAN transmit buffer inside CANdevTx for CAN tx message */ - CO_CANtx_t *CANtxBuff; -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN + CO_CANtx_t* CANtxBuff; +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** Copy of CANopen COB_ID Client -> Server, meaning of the specific bits: - Bit 0...10: 11-bit CAN identifier. - Bit 11..30: reserved, must be 0. @@ -226,20 +225,20 @@ typedef struct { uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U]; /** Indicates, if new SDO message received from CAN bus. It is not cleared, * until received message is completely processed. */ - volatile void *CANrxNew; + volatile void* CANrxNew; /** 8 data bytes of the received message */ uint8_t CANrxData[8]; -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_SDOclient_initCallbackPre() or NULL */ - void (*pFunctSignal)(void *object); + void (*pFunctSignal)(void* object); /** From CO_SDOclient_initCallbackPre() or NULL */ - void *functSignalObject; + void* functSignalObject; #endif -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0) || defined CO_DOXYGEN /** Toggle bit toggled in each segment in segmented transfer */ uint8_t toggle; #endif -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0) || defined CO_DOXYGEN /** Timeout time for SDO sub-block upload, half of #SDOtimeoutTime_us */ uint32_t block_SDOtimeoutTime_us; /** Timeout timer for SDO sub-block upload */ @@ -259,7 +258,6 @@ typedef struct { #endif } CO_SDOclient_t; - /** * Initialize SDO client object. * @@ -281,18 +279,11 @@ typedef struct { * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, - OD_t *OD, - OD_entry_t *OD_1280_SDOcliPar, - uint8_t nodeId, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint32_t *errInfo); - - -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t* SDO_C, OD_t* OD, OD_entry_t* OD_1280_SDOcliPar, uint8_t nodeId, + CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, CO_CANmodule_t* CANdevTx, + uint16_t CANdevTxIdx, uint32_t* errInfo); + +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize SDOclient callback function. * @@ -307,12 +298,9 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C, * be NULL. * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, - void *object, - void (*pFunctSignal)(void *object)); +void CO_SDOclient_initCallbackPre(CO_SDOclient_t* SDOclient, void* object, void (*pFunctSignal)(void* object)); #endif - /** * Setup SDO client object. * @@ -331,12 +319,9 @@ void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient, * @return #CO_SDO_return_t, CO_SDO_RT_ok_communicationEnd or * CO_SDO_RT_wrongArguments */ -CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, - uint32_t COB_IDClientToServer, - uint32_t COB_IDServerToClient, +CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t* SDO_C, uint32_t COB_IDClientToServer, uint32_t COB_IDServerToClient, uint8_t nodeIDOfTheSDOServer); - /** * Initiate SDO download communication. * @@ -361,13 +346,8 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C, * * @return #CO_SDO_return_t */ -CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - size_t sizeIndicated, - uint16_t SDOtimeoutTime_ms, - bool_t blockEnable); - +CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t* SDO_C, uint16_t index, uint8_t subIndex, + size_t sizeIndicated, uint16_t SDOtimeoutTime_ms, bool_t blockEnable); /** * Initiate SDO download communication - update size. @@ -380,9 +360,7 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C, * @param SDO_C This object. * @param sizeIndicated Same as in CO_SDOclientDownloadInitiate(). */ -void CO_SDOclientDownloadInitSize(CO_SDOclient_t *SDO_C, - size_t sizeIndicated); - +void CO_SDOclientDownloadInitSize(CO_SDOclient_t* SDO_C, size_t sizeIndicated); /** * Write data into SDO client buffer @@ -403,10 +381,7 @@ void CO_SDOclientDownloadInitSize(CO_SDOclient_t *SDO_C, * * @return number of bytes actually written. */ -size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, - const uint8_t *buf, - size_t count); - +size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t* SDO_C, const uint8_t* buf, size_t count); /** * Process SDO download communication. @@ -436,14 +411,9 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C, * ends successfully and state becomes idle. If greater than 0, then * communication is in progress. */ -CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - bool_t send_abort, - bool_t bufferPartial, - CO_SDO_abortCode_t *SDOabortCode, - size_t *sizeTransferred, - uint32_t *timerNext_us); - +CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t send_abort, + bool_t bufferPartial, CO_SDO_abortCode_t* SDOabortCode, size_t* sizeTransferred, + uint32_t* timerNext_us); /** * Initiate SDO upload communication. @@ -460,12 +430,8 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C, * * @return #CO_SDO_return_t */ -CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, - uint16_t index, - uint8_t subIndex, - uint16_t SDOtimeoutTime_ms, - bool_t blockEnable); - +CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t* SDO_C, uint16_t index, uint8_t subIndex, + uint16_t SDOtimeoutTime_ms, bool_t blockEnable); /** * Process SDO upload communication. @@ -497,14 +463,9 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C, * ends successfully and state becomes idle. If greater than 0, then * communication is in progress. */ -CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, - uint32_t timeDifference_us, - bool_t send_abort, - CO_SDO_abortCode_t *SDOabortCode, - size_t *sizeIndicated, - size_t *sizeTransferred, - uint32_t *timerNext_us); - +CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t send_abort, + CO_SDO_abortCode_t* SDOabortCode, size_t* sizeIndicated, size_t* sizeTransferred, + uint32_t* timerNext_us); /** * Read data from SDO client buffer. @@ -526,10 +487,7 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C, * * @return number of bytes actually read. */ -size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, - uint8_t *buf, - size_t count); - +size_t CO_SDOclientUploadBufRead(CO_SDOclient_t* SDO_C, uint8_t* buf, size_t count); /** * Close SDO communication temporary. @@ -540,7 +498,7 @@ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C, * * @param SDO_C This object. */ -void CO_SDOclientClose(CO_SDOclient_t *SDO_C); +void CO_SDOclientClose(CO_SDOclient_t* SDO_C); /** @} */ /* CO_SDOclient */ diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index ed786091..3e29a9ea 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -26,10 +26,9 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_SDO_SRV -#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_SDO_SRV \ + (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT \ + | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE #define CO_CONFIG_SDO_SRV_BUFFER_SIZE 32U @@ -76,16 +75,15 @@ extern "C" { * Access to Object dictionary is specified in @ref CO_ODinterface. */ - /** * Internal state flags indicate type of transfer * * These flags correspond to the upper nibble of the SDO state machine states * and can be used to determine the type of state an SDO object is in. */ -#define CO_SDO_ST_FLAG_DOWNLOAD 0x10U -#define CO_SDO_ST_FLAG_UPLOAD 0x20U -#define CO_SDO_ST_FLAG_BLOCK 0x40U +#define CO_SDO_ST_FLAG_DOWNLOAD 0x10U +#define CO_SDO_ST_FLAG_UPLOAD 0x20U +#define CO_SDO_ST_FLAG_BLOCK 0x40U /** * Internal states of the SDO state machine. @@ -98,26 +96,26 @@ extern "C" { * Note: CANopen has little endian byte order. */ typedef enum { -/** + /** * - SDO client may start new download to or upload from specified node, * specified index and specified subindex. It can start normal or block * communication. * - SDO server is waiting for client request. */ -CO_SDO_ST_IDLE = 0x00U, -/** + CO_SDO_ST_IDLE = 0x00U, + /** * - SDO client or server may send SDO abort message in case of error: * - byte 0: @b 10000000 binary. * - byte 1..3: Object index and subIndex. * - byte 4..7: #CO_SDO_abortCode_t. */ -CO_SDO_ST_ABORT = 0x01U, + CO_SDO_ST_ABORT = 0x01U, -/** + /** * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, * SDO client is the same device as SDO server. Transfer data directly without * communication on CAN. * - SDO server does not use this state. */ -CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER = 0x10U, -/** + CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER = 0x10U, + /** * - SDO client initiates SDO download: * - byte 0: @b 0010nnes binary: (nn: if e=s=1, number of data bytes, that do * @b not contain data; e=1 for expedited transfer; s=1 if data size is @@ -126,45 +124,45 @@ CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER = 0x10U, * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for * segmented transfer is indicated here. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ -CO_SDO_ST_DOWNLOAD_INITIATE_REQ = 0x11U, -/** + CO_SDO_ST_DOWNLOAD_INITIATE_REQ = 0x11U, + /** * - SDO client waits for response. * - SDO server responses: * - byte 0: @b 01100000 binary. * - byte 1..3: Object index and subIndex. * - byte 4..7: Reserved. * - In case of expedited transfer communication ends here. */ -CO_SDO_ST_DOWNLOAD_INITIATE_RSP = 0x12U, -/** + CO_SDO_ST_DOWNLOAD_INITIATE_RSP = 0x12U, + /** * - SDO client sends SDO segment: * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; * nnn: number of data bytes, that do @b not contain data; c=1 if this is the * last segment). * - byte 1..7: Data segment. * - SDO server waits for segment. */ -CO_SDO_ST_DOWNLOAD_SEGMENT_REQ = 0x13U, -/** + CO_SDO_ST_DOWNLOAD_SEGMENT_REQ = 0x13U, + /** * - SDO client waits for response. * - SDO server responses: * - byte 0: @b 001t0000 binary: (t: toggle bit, set to 0 in first segment). * - byte 1..7: Reserved. * - If c was set to 1, then communication ends here. */ -CO_SDO_ST_DOWNLOAD_SEGMENT_RSP = 0x14U, + CO_SDO_ST_DOWNLOAD_SEGMENT_RSP = 0x14U, -/** + /** * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, * SDO client is the same device as SDO server. Transfer data directly without * communication on CAN. * - SDO server does not use this state. */ -CO_SDO_ST_UPLOAD_LOCAL_TRANSFER = 0x20U, -/** + CO_SDO_ST_UPLOAD_LOCAL_TRANSFER = 0x20U, + /** * - SDO client initiates SDO upload: * - byte 0: @b 01000000 binary. * - byte 1..3: Object index and subIndex. * - byte 4..7: Reserved. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ -CO_SDO_ST_UPLOAD_INITIATE_REQ = 0x21U, -/** + CO_SDO_ST_UPLOAD_INITIATE_REQ = 0x21U, + /** * - SDO client waits for response. * - SDO server responses: * - byte 0: @b 0100nnes binary: (nn: if e=s=1, number of data bytes, that do @@ -174,14 +172,14 @@ CO_SDO_ST_UPLOAD_INITIATE_REQ = 0x21U, * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for * segmented transfer is indicated here. * - In case of expedited transfer communication ends here. */ -CO_SDO_ST_UPLOAD_INITIATE_RSP = 0x22U, -/** + CO_SDO_ST_UPLOAD_INITIATE_RSP = 0x22U, + /** * - SDO client requests SDO segment: * - byte 0: @b 011t0000 binary: (t: toggle bit, set to 0 in first segment). * - byte 1..7: Reserved. * - SDO server waits for segment request. */ -CO_SDO_ST_UPLOAD_SEGMENT_REQ = 0x23U, -/** + CO_SDO_ST_UPLOAD_SEGMENT_REQ = 0x23U, + /** * - SDO client waits for response. * - SDO server responses with data: * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; @@ -189,17 +187,17 @@ CO_SDO_ST_UPLOAD_SEGMENT_REQ = 0x23U, * last segment). * - byte 1..7: Data segment. * - If c is set to 1, then communication ends here. */ -CO_SDO_ST_UPLOAD_SEGMENT_RSP = 0x24U, + CO_SDO_ST_UPLOAD_SEGMENT_RSP = 0x24U, -/** + /** * - SDO client initiates SDO block download: * - byte 0: @b 11000rs0 binary: (r=1 if client supports generating CRC on * data; s=1 if data size is indicated.) * - byte 1..3: Object index and subIndex. * - byte 4..7: If s=1, then size of data for block download is indicated here. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ -CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ = 0x51U, -/** + CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ = 0x51U, + /** * - SDO client waits for response. * - SDO server responses: * - byte 0: @b 10100r00 binary: (r=1 if server supports generating CRC on @@ -208,16 +206,16 @@ CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ = 0x51U, * - byte 4: blksize: Number of segments per block that shall be used by the * client for the following block download with 0 < blksize < 128. * - byte 5..7: Reserved. */ -CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP = 0x52U, -/** + CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP = 0x52U, + /** * - SDO client sends 'blksize' segments of data in sequence: * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be downloaded, * enter SDO block download end phase; nnnnnnn is sequence number of segment, * 1..127. * - byte 1..7: At most 7 bytes of segment data to be downloaded. * - SDO server reads sequence of 'blksize' blocks. */ -CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x53U, -/** + CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x53U, + /** * - SDO client waits for response. * - SDO server responses: * - byte 0: @b 10100010 binary. @@ -231,25 +229,25 @@ CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x53U, * - byte 3..7: Reserved. * - If c was set to 1, then communication enters SDO block download end phase. */ -CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP = 0x54U, -/** + CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP = 0x54U, + /** * - SDO client sends SDO block download end: * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not * contain data) * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. * - byte 3..7: Reserved. * - SDO server waits for client request. */ -CO_SDO_ST_DOWNLOAD_BLK_END_REQ = 0x55U, -/** + CO_SDO_ST_DOWNLOAD_BLK_END_REQ = 0x55U, + /** * - SDO client waits for response. * - SDO server responses: * - byte 0: @b 10100001 binary. * - byte 1..7: Reserved. * - Block download successfully ends here. */ -CO_SDO_ST_DOWNLOAD_BLK_END_RSP = 0x56U, + CO_SDO_ST_DOWNLOAD_BLK_END_RSP = 0x56U, -/** + /** * - SDO client initiates SDO block upload: * - byte 0: @b 10100r00 binary: (r=1 if client supports generating CRC on * data.) @@ -260,8 +258,8 @@ CO_SDO_ST_DOWNLOAD_BLK_END_RSP = 0x56U, * upload protocol #CO_SDO_ST_UPLOAD_INITIATE_RSP. * - byte 6..7: Reserved. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ -CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x61U, -/** + CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x61U, + /** * - SDO client waits for response. * - SDO server responses: * - byte 0: @b 11000rs0 binary: (r=1 if server supports generating CRC on @@ -270,22 +268,22 @@ CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x61U, * - byte 4..7: If s=1, then size of data for block upload is indicated here. * - If enabled by pst, then server may alternatively response with * #CO_SDO_ST_UPLOAD_INITIATE_RSP */ -CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP = 0x62U, -/** + CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP = 0x62U, + /** * - SDO client sends second initiate for SDO block upload: * - byte 0: @b 10100011 binary. * - byte 1..7: Reserved. * - SDO server waits for client request. */ -CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2 = 0x63U, -/** + CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2 = 0x63U, + /** * - SDO client reads sequence of 'blksize' blocks. * - SDO server sends 'blksize' segments of data in sequence: * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be uploaded, * enter SDO block upload end phase; nnnnnnn is sequence number of segment, * 1..127. * - byte 1..7: At most 7 bytes of segment data to be uploaded. */ -CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x64U, -/** + CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x64U, + /** * - SDO client responses: * - byte 0: @b 10100010 binary. * - byte 1: ackseq: sequence number of last segment that was received @@ -299,16 +297,16 @@ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x64U, * - SDO server waits for response. * - If c was set to 1 and all segments were successfull received, then * communication enters SDO block upload end phase. */ -CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x65U, -/** + CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x65U, + /** * - SDO client waits for server request. * - SDO server sends SDO block upload end: * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not * contain data) * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. * - byte 3..7: Reserved. */ -CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x66U, -/** + CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x66U, + /** * - SDO client responses: * - byte 0: @b 10100001 binary. * - byte 1..7: Reserved. @@ -317,10 +315,9 @@ CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x66U, * with client response. Client may then start next SDO communication * immediately. */ -CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x67U, + CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x67U, } CO_SDO_state_t; - /** * SDO abort codes. * @@ -330,78 +327,77 @@ CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x67U, */ typedef enum { /** 0x00000000, No abort */ - CO_SDO_AB_NONE = 0x00000000UL, + CO_SDO_AB_NONE = 0x00000000UL, /** 0x05030000, Toggle bit not altered */ - CO_SDO_AB_TOGGLE_BIT = 0x05030000UL, + CO_SDO_AB_TOGGLE_BIT = 0x05030000UL, /** 0x05040000, SDO protocol timed out */ - CO_SDO_AB_TIMEOUT = 0x05040000UL, + CO_SDO_AB_TIMEOUT = 0x05040000UL, /** 0x05040001, Command specifier not valid or unknown */ - CO_SDO_AB_CMD = 0x05040001UL, + CO_SDO_AB_CMD = 0x05040001UL, /** 0x05040002, Invalid block size in block mode */ - CO_SDO_AB_BLOCK_SIZE = 0x05040002UL, + CO_SDO_AB_BLOCK_SIZE = 0x05040002UL, /** 0x05040003, Invalid sequence number in block mode */ - CO_SDO_AB_SEQ_NUM = 0x05040003UL, + CO_SDO_AB_SEQ_NUM = 0x05040003UL, /** 0x05040004, CRC error (block mode only) */ - CO_SDO_AB_CRC = 0x05040004UL, + CO_SDO_AB_CRC = 0x05040004UL, /** 0x05040005, Out of memory */ - CO_SDO_AB_OUT_OF_MEM = 0x05040005UL, + CO_SDO_AB_OUT_OF_MEM = 0x05040005UL, /** 0x06010000, Unsupported access to an object */ - CO_SDO_AB_UNSUPPORTED_ACCESS = 0x06010000UL, + CO_SDO_AB_UNSUPPORTED_ACCESS = 0x06010000UL, /** 0x06010001, Attempt to read a write only object */ - CO_SDO_AB_WRITEONLY = 0x06010001UL, + CO_SDO_AB_WRITEONLY = 0x06010001UL, /** 0x06010002, Attempt to write a read only object */ - CO_SDO_AB_READONLY = 0x06010002UL, + CO_SDO_AB_READONLY = 0x06010002UL, /** 0x06020000, Object does not exist in the object dictionary */ - CO_SDO_AB_NOT_EXIST = 0x06020000UL, + CO_SDO_AB_NOT_EXIST = 0x06020000UL, /** 0x06040041, Object cannot be mapped to the PDO */ - CO_SDO_AB_NO_MAP = 0x06040041UL, + CO_SDO_AB_NO_MAP = 0x06040041UL, /** 0x06040042, Number and length of object to be mapped exceeds PDO * length */ - CO_SDO_AB_MAP_LEN = 0x06040042UL, + CO_SDO_AB_MAP_LEN = 0x06040042UL, /** 0x06040043, General parameter incompatibility reasons */ - CO_SDO_AB_PRAM_INCOMPAT = 0x06040043UL, + CO_SDO_AB_PRAM_INCOMPAT = 0x06040043UL, /** 0x06040047, General internal incompatibility in device */ - CO_SDO_AB_DEVICE_INCOMPAT = 0x06040047UL, + CO_SDO_AB_DEVICE_INCOMPAT = 0x06040047UL, /** 0x06060000, Access failed due to hardware error */ - CO_SDO_AB_HW = 0x06060000UL, + CO_SDO_AB_HW = 0x06060000UL, /** 0x06070010, Data type does not match, length of service parameter does * not match */ - CO_SDO_AB_TYPE_MISMATCH = 0x06070010UL, + CO_SDO_AB_TYPE_MISMATCH = 0x06070010UL, /** 0x06070012, Data type does not match, length of service parameter too * high */ - CO_SDO_AB_DATA_LONG = 0x06070012UL, + CO_SDO_AB_DATA_LONG = 0x06070012UL, /** 0x06070013, Data type does not match, length of service parameter too * short */ - CO_SDO_AB_DATA_SHORT = 0x06070013UL, + CO_SDO_AB_DATA_SHORT = 0x06070013UL, /** 0x06090011, Sub index does not exist */ - CO_SDO_AB_SUB_UNKNOWN = 0x06090011UL, + CO_SDO_AB_SUB_UNKNOWN = 0x06090011UL, /** 0x06090030, Invalid value for parameter (download only). */ - CO_SDO_AB_INVALID_VALUE = 0x06090030UL, + CO_SDO_AB_INVALID_VALUE = 0x06090030UL, /** 0x06090031, Value range of parameter written too high */ - CO_SDO_AB_VALUE_HIGH = 0x06090031UL, + CO_SDO_AB_VALUE_HIGH = 0x06090031UL, /** 0x06090032, Value range of parameter written too low */ - CO_SDO_AB_VALUE_LOW = 0x06090032UL, + CO_SDO_AB_VALUE_LOW = 0x06090032UL, /** 0x06090036, Maximum value is less than minimum value. */ - CO_SDO_AB_MAX_LESS_MIN = 0x06090036UL, + CO_SDO_AB_MAX_LESS_MIN = 0x06090036UL, /** 0x060A0023, Resource not available: SDO connection */ - CO_SDO_AB_NO_RESOURCE = 0x060A0023UL, + CO_SDO_AB_NO_RESOURCE = 0x060A0023UL, /** 0x08000000, General error */ - CO_SDO_AB_GENERAL = 0x08000000UL, + CO_SDO_AB_GENERAL = 0x08000000UL, /** 0x08000020, Data cannot be transferred or stored to application */ - CO_SDO_AB_DATA_TRANSF = 0x08000020UL, + CO_SDO_AB_DATA_TRANSF = 0x08000020UL, /** 0x08000021, Data cannot be transferred or stored to application because * of local control */ - CO_SDO_AB_DATA_LOC_CTRL = 0x08000021UL, + CO_SDO_AB_DATA_LOC_CTRL = 0x08000021UL, /** 0x08000022, Data cannot be transferred or stored to application because * of present device state */ - CO_SDO_AB_DATA_DEV_STATE = 0x08000022UL, + CO_SDO_AB_DATA_DEV_STATE = 0x08000022UL, /** 0x08000023, Object dictionary not present or dynamic generation fails */ - CO_SDO_AB_DATA_OD = 0x08000023UL, + CO_SDO_AB_DATA_OD = 0x08000023UL, /** 0x08000024, No data available */ - CO_SDO_AB_NO_DATA = 0x08000024UL + CO_SDO_AB_NO_DATA = 0x08000024UL } CO_SDO_abortCode_t; - /** * Return values from SDO server or client functions. */ @@ -430,17 +426,16 @@ typedef enum { CO_SDO_RT_endedWithServerAbort = -10, } CO_SDO_return_t; - /** * SDO server object. */ typedef struct { /** From CO_SDOserver_init() */ - CO_CANmodule_t *CANdevTx; + CO_CANmodule_t* CANdevTx; /** CAN transmit buffer inside CANdevTx for CAN tx message */ - CO_CANtx_t *CANtxBuff; + CO_CANtx_t* CANtxBuff; /** From CO_SDOserver_init() */ - OD_t *OD; + OD_t* OD; /** From CO_SDOserver_init() */ uint8_t nodeId; /* If true, SDO channel is valid */ @@ -455,12 +450,12 @@ typedef struct { uint8_t subIndex; /** Indicates, if new SDO message received from CAN bus. It is not cleared, * until received message is completely processed. */ - volatile void *CANrxNew; + volatile void* CANrxNew; /** 8 data bytes of the received message */ uint8_t CANrxData[8]; -#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** From CO_SDOserver_init() */ - CO_CANmodule_t *CANdevRx; + CO_CANmodule_t* CANdevRx; /** From CO_SDOserver_init() */ uint16_t CANdevRxIdx; /** From CO_SDOserver_init() */ @@ -475,7 +470,7 @@ typedef struct { /** Extension for OD object */ OD_extension_t OD_1200_extension; #endif -#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_SEGMENTED) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0) || defined CO_DOXYGEN /** Size of data, which will be transferred. It is optionally indicated by * client in case of download or by server in case of upload. */ OD_size_t sizeInd; @@ -497,7 +492,7 @@ typedef struct { /** Offset of first data available for read in the buffer */ OD_size_t bufOffsetRd; #endif -#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_SDO_SRV_BLOCK) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0) || defined CO_DOXYGEN /** Timeout time for SDO sub-block download, half of #SDOtimeoutTime_us */ uint32_t block_SDOtimeoutTime_us; /** Timeout timer for SDO sub-block download */ @@ -513,15 +508,14 @@ typedef struct { /** Calculated CRC checksum */ uint16_t block_crc; #endif -#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_SDOserver_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void* object); /** From CO_SDOserver_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void* functSignalObjectPre; #endif } CO_SDOserver_t; - /** * Initialize SDO object. * @@ -544,19 +538,11 @@ typedef struct { * * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, - OD_t *OD, - OD_entry_t *OD_1200_SDOsrvPar, - uint8_t nodeId, - uint16_t SDOtimeoutTime_ms, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint32_t *errInfo); +CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t* SDO, OD_t* OD, OD_entry_t* OD_1200_SDOsrvPar, uint8_t nodeId, + uint16_t SDOtimeoutTime_ms, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, uint32_t* errInfo); - -#if (((CO_CONFIG_SDO_SRV) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize SDOrx callback function. * @@ -570,12 +556,9 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t *SDO, * Can be NULL * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_SDOserver_initCallbackPre(CO_SDOserver_t* SDO, void* object, void (*pFunctSignalPre)(void* object)); #endif - /** * Process SDO communication. * @@ -590,10 +573,8 @@ void CO_SDOserver_initCallbackPre(CO_SDOserver_t *SDO, * * @return #CO_SDO_return_t */ -CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t *SDO, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, + uint32_t* timerNext_us); /** @} */ /* CO_SDOserver */ diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 8c2038a2..080f0f8f 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -25,17 +25,14 @@ #include "301/CO_ODinterface.h" #include "301/CO_Emergency.h" - /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_SYNC -#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \ - CO_CONFIG_SYNC_PRODUCER | \ - CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_SYNC \ + (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE \ + | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -69,15 +66,14 @@ extern "C" { * RPDO reception and which for RPDO processing. */ - /** * SYNC producer and consumer object. */ typedef struct { /** From CO_SYNC_init() */ - CO_EM_t *em; + CO_EM_t* em; /** Indicates, if new SYNC message received from CAN bus */ - volatile void *CANrxNew; + volatile void* CANrxNew; /** Set to nonzero value, if SYNC with wrong data length is received */ uint8_t receiveError; /** Variable toggles, if new SYNC message received from CAN bus */ @@ -97,21 +93,21 @@ typedef struct { Set to zero after received or transmitted SYNC message */ uint32_t timer; /**Pointer to variable in OD, "Communication cycle period" in microseconds*/ - uint32_t *OD_1006_period; + uint32_t* OD_1006_period; /** Pointer to variable in OD, "Synchronous window length" in microseconds*/ - uint32_t *OD_1007_window; + uint32_t* OD_1007_window; -#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN /** True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ variable from Object dictionary (index 0x1005). */ bool_t isProducer; /** CAN transmit buffer inside CANdevTx */ - CO_CANtx_t *CANtxBuff; + CO_CANtx_t* CANtxBuff; #endif -#if ((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN +#if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN /** From CO_SYNC_init() */ - CO_CANmodule_t *CANdevRx; + CO_CANmodule_t* CANdevRx; /** From CO_SYNC_init() */ uint16_t CANdevRxIdx; /** Extension for OD object */ @@ -119,25 +115,24 @@ typedef struct { /** CAN ID of the SYNC message. Calculated from _COB ID SYNC Message_ variable from Object dictionary (index 0x1005). */ uint16_t CAN_ID; - #if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN /** From CO_SYNC_init() */ - CO_CANmodule_t *CANdevTx; + CO_CANmodule_t* CANdevTx; /** From CO_SYNC_init() */ uint16_t CANdevTxIdx; /** Extension for OD object */ OD_extension_t OD_1019_extension; - #endif +#endif #endif -#if (((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_SYNC_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void* object); /** From CO_SYNC_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void* functSignalObjectPre; #endif } CO_SYNC_t; - /** Return value for @ref CO_SYNC_process */ typedef enum { /** No SYNC event in last cycle */ @@ -148,7 +143,6 @@ typedef enum { CO_SYNC_PASSED_WINDOW = 2 } CO_SYNC_status_t; - /** * Initialize SYNC object. * @@ -172,22 +166,15 @@ typedef enum { * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, - CO_EM_t *em, - OD_entry_t *OD_1005_cobIdSync, - OD_entry_t *OD_1006_commCyclePeriod, - OD_entry_t *OD_1007_syncWindowLen, - OD_entry_t *OD_1019_syncCounterOvf, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, -#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, +CO_ReturnError_t CO_SYNC_init(CO_SYNC_t* SYNC, CO_EM_t* em, OD_entry_t* OD_1005_cobIdSync, + OD_entry_t* OD_1006_commCyclePeriod, OD_entry_t* OD_1007_syncWindowLen, + OD_entry_t* OD_1019_syncCounterOvf, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, +#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, #endif - uint32_t *errInfo); - + uint32_t* errInfo); -#if (((CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize SYNC callback function. * @@ -199,13 +186,10 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t *SYNC, * @param object Pointer to object, which will be passed to pFunctSignalPre(). * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_SYNC_initCallbackPre(CO_SYNC_t *SYNC, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_SYNC_initCallbackPre(CO_SYNC_t* SYNC, void* object, void (*pFunctSignalPre)(void* object)); #endif - -#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN /** * Send SYNC message. * @@ -217,8 +201,11 @@ void CO_SYNC_initCallbackPre(CO_SYNC_t *SYNC, * * @return Same as CO_CANsend(). */ -static inline CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC) { - if (++SYNC->counter > SYNC->counterOverflowValue) { SYNC->counter = 1; } +static inline CO_ReturnError_t +CO_SYNCsend(CO_SYNC_t* SYNC) { + if (++SYNC->counter > SYNC->counterOverflowValue) { + SYNC->counter = 1; + } SYNC->timer = 0; SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true; SYNC->CANtxBuff->data[0] = SYNC->counter; @@ -226,7 +213,6 @@ static inline CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC) { } #endif - /** * Process SYNC communication. * @@ -241,10 +227,8 @@ static inline CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC) { * * @return @ref CO_SYNC_status_t */ -CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t* SYNC, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, + uint32_t* timerNext_us); /** @} */ /* CO_SYNC */ diff --git a/301/CO_TIME.h b/301/CO_TIME.h index b57bc552..cf7e3522 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -25,15 +25,12 @@ #include "301/CO_ODinterface.h" #include "301/CO_NMT_Heartbeat.h" - /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_TIME -#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \ - CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#if (((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -65,11 +62,9 @@ extern "C" { * send from @ref CO_TIME_process() in intervals specified by @ref CO_TIME_set() */ - /** Length of the TIME message */ #define CO_TIME_MSG_LENGTH 6U - /** * TIME producer and consumer object. */ @@ -82,37 +77,36 @@ typedef struct { uint16_t days; /** Residual microseconds calculated inside CO_TIME_process() */ uint16_t residual_us; - /** True, if device is TIME consumer. Calculated from _COB ID TIME Message_ + /** True, if device is TIME consumer. Calculated from _COB ID TIME Message_ variable from Object dictionary (index 0x1012). */ bool_t isConsumer; /** True, if device is TIME producer. Calculated from _COB ID TIME Message_ variable from Object dictionary (index 0x1012). */ bool_t isProducer; /** Variable indicates, if new TIME message received from CAN bus */ - volatile void *CANrxNew; -#if (((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN + volatile void* CANrxNew; +#if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN /** Interval for time producer in milli seconds */ uint32_t producerInterval_ms; /** Sync producer timer */ uint32_t producerTimer_ms; /** From CO_TIME_init() */ - CO_CANmodule_t *CANdevTx; + CO_CANmodule_t* CANdevTx; /** CAN transmit buffer */ - CO_CANtx_t *CANtxBuff; + CO_CANtx_t* CANtxBuff; #endif -#if (((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_TIME_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void *object); + void (*pFunctSignalPre)(void* object); /** From CO_TIME_initCallbackPre() or NULL */ - void *functSignalObjectPre; + void* functSignalObjectPre; #endif -#if (((CO_CONFIG_TIME) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN /** Extension for OD object */ OD_extension_t OD_1012_extension; #endif } CO_TIME_t; - /** * Initialize TIME object. * @@ -129,18 +123,14 @@ typedef struct { * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ -CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, - OD_entry_t *OD_1012_cobIdTimeStamp, - CO_CANmodule_t *CANdevRx, +CO_ReturnError_t CO_TIME_init(CO_TIME_t* TIME, OD_entry_t* OD_1012_cobIdTimeStamp, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, -#if (((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, +#if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN + CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, #endif - uint32_t *errInfo); + uint32_t* errInfo); - -#if (((CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_TIME)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize TIME callback function. * @@ -152,12 +142,9 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t *TIME, * @param object Pointer to object, which will be passed to pFunctSignalPre(). * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_TIME_initCallbackPre(CO_TIME_t *TIME, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_TIME_initCallbackPre(CO_TIME_t* TIME, void* object, void (*pFunctSignalPre)(void* object)); #endif - /** * Set current time * @@ -166,24 +153,20 @@ void CO_TIME_initCallbackPre(CO_TIME_t *TIME, * @param days Number of days since January 1, 1984 * @param producerInterval_ms Interval time for time producer in milliseconds */ -static inline void CO_TIME_set(CO_TIME_t *TIME, - uint32_t ms, - uint16_t days, - uint32_t producerInterval_ms) -{ +static inline void +CO_TIME_set(CO_TIME_t* TIME, uint32_t ms, uint16_t days, uint32_t producerInterval_ms) { (void)producerInterval_ms; /* may be unused */ if (TIME != NULL) { TIME->residual_us = 0; TIME->ms = ms; TIME->days = days; -#if ((CO_CONFIG_TIME) & CO_CONFIG_TIME_PRODUCER) != 0 - TIME->producerTimer_ms = TIME->producerInterval_ms =producerInterval_ms; +#if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 + TIME->producerTimer_ms = TIME->producerInterval_ms = producerInterval_ms; #endif } } - /** * Process TIME object. * @@ -199,10 +182,7 @@ static inline void CO_TIME_set(CO_TIME_t *TIME, * * @return True if new TIME stamp message recently received (consumer). */ -bool_t CO_TIME_process(CO_TIME_t *TIME, - bool_t NMTisPreOrOperational, - uint32_t timeDifference_us); - +bool_t CO_TIME_process(CO_TIME_t* TIME, bool_t NMTisPreOrOperational, uint32_t timeDifference_us); /** @} */ /* CO_TIME */ diff --git a/301/CO_config.h b/301/CO_config.h index 89e77305..5a07ae63 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -18,7 +18,6 @@ * See the License for the specific language governing permissions and limitations under the License. */ - #ifndef CO_CONFIG_FLAGS_H #define CO_CONFIG_FLAGS_H @@ -49,7 +48,6 @@ extern "C" { * @{ */ - /** * @defgroup CO_STACK_CONFIG_COMMON Common definitions * Constants for common definitions. @@ -81,7 +79,7 @@ extern "C" { * * This flag is common to multiple configuration macros. */ -#define CO_CONFIG_FLAG_TIMERNEXT 0x2000 +#define CO_CONFIG_FLAG_TIMERNEXT 0x2000 /** * Enable dynamic behaviour of Object Dictionary variables @@ -93,7 +91,7 @@ extern "C" { * * This flag is common to multiple configuration macros. */ -#define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000 +#define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000 /** This flag may be set globally for mainline objects to * @ref CO_CONFIG_FLAG_CALLBACK_PRE */ @@ -118,7 +116,6 @@ extern "C" { #endif /** @} */ /* CO_STACK_CONFIG_COMMON */ - /** * @defgroup CO_STACK_CONFIG_NMT_HB NMT master/slave and HB producer/consumer * Specified in standard CiA 301 @@ -142,7 +139,7 @@ extern "C" { #define CO_CONFIG_NMT (CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif #define CO_CONFIG_NMT_CALLBACK_CHANGE 0x01 -#define CO_CONFIG_NMT_MASTER 0x02 +#define CO_CONFIG_NMT_MASTER 0x02 /** * Configuration of @ref CO_HBconsumer @@ -172,15 +169,16 @@ extern "C" { * CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_HB_CONS (CO_CONFIG_HB_CONS_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_HB_CONS \ + (CO_CONFIG_HB_CONS_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT \ + | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#define CO_CONFIG_HB_CONS_ENABLE 0x01 +#define CO_CONFIG_HB_CONS_ENABLE 0x01 #define CO_CONFIG_HB_CONS_CALLBACK_CHANGE 0x02 -#define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x04 -#define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x08 +#define CO_CONFIG_HB_CONS_CALLBACK_MULTI 0x04 +#define CO_CONFIG_HB_CONS_QUERY_FUNCT 0x08 /** @} */ /* CO_STACK_CONFIG_NMT_HB */ - /** * @defgroup CO_STACK_CONFIG_NODE_GUARDING CANopen Node Guarding slave and master objects. * Specified in standard CiA 301 @@ -198,7 +196,7 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_NODE_GUARDING (0) #endif -#define CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE 0x01 +#define CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE 0x01 #define CO_CONFIG_NODE_GUARDING_MASTER_ENABLE 0x02 /** @@ -209,7 +207,6 @@ extern "C" { #endif /** @} */ /* CO_STACK_CONFIG_NODE_GUARDING */ - /** * @defgroup CO_STACK_CONFIG_EMERGENCY Emergency producer/consumer * Specified in standard CiA 301 @@ -236,14 +233,16 @@ extern "C" { * inside CO_EM_process(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) +#define CO_CONFIG_EM \ + (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE \ + | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif -#define CO_CONFIG_EM_PRODUCER 0x01 +#define CO_CONFIG_EM_PRODUCER 0x01 #define CO_CONFIG_EM_PROD_CONFIGURABLE 0x02 -#define CO_CONFIG_EM_PROD_INHIBIT 0x04 -#define CO_CONFIG_EM_HISTORY 0x08 -#define CO_CONFIG_EM_STATUS_BITS 0x10 -#define CO_CONFIG_EM_CONSUMER 0x20 +#define CO_CONFIG_EM_PROD_INHIBIT 0x04 +#define CO_CONFIG_EM_HISTORY 0x08 +#define CO_CONFIG_EM_STATUS_BITS 0x10 +#define CO_CONFIG_EM_CONSUMER 0x20 /** * Maximum number of @ref CO_EM_errorStatusBits_t @@ -253,7 +252,7 @@ extern "C" { * Default is 80. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10*8) +#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (10 * 8) #endif /** @@ -333,7 +332,6 @@ extern "C" { #endif /** @} */ /* CO_STACK_CONFIG_EMERGENCY */ - /** * @defgroup CO_STACK_CONFIG_SDO SDO server/client * Specified in standard CiA 301 @@ -355,10 +353,12 @@ extern "C" { * servers (Writing to object 0x1201+ re-configures the additional server). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_SDO_SRV \ + (CO_CONFIG_SDO_SRV_SEGMENTED | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT \ + | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_SDO_SRV_SEGMENTED 0x02 -#define CO_CONFIG_SDO_SRV_BLOCK 0x04 +#define CO_CONFIG_SDO_SRV_BLOCK 0x04 /** * Size of the internal data buffer for the SDO server. @@ -395,10 +395,10 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_SDO_CLI (0) #endif -#define CO_CONFIG_SDO_CLI_ENABLE 0x01 +#define CO_CONFIG_SDO_CLI_ENABLE 0x01 #define CO_CONFIG_SDO_CLI_SEGMENTED 0x02 -#define CO_CONFIG_SDO_CLI_BLOCK 0x04 -#define CO_CONFIG_SDO_CLI_LOCAL 0x08 +#define CO_CONFIG_SDO_CLI_BLOCK 0x04 +#define CO_CONFIG_SDO_CLI_LOCAL 0x08 /** * Size of the internal data buffer for the SDO client. @@ -416,7 +416,6 @@ extern "C" { #endif /** @} */ /* CO_STACK_CONFIG_SDO */ - /** * @defgroup CO_STACK_CONFIG_TIME Time producer/consumer * Specified in standard CiA 301 @@ -437,11 +436,10 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#define CO_CONFIG_TIME_ENABLE 0x01 +#define CO_CONFIG_TIME_ENABLE 0x01 #define CO_CONFIG_TIME_PRODUCER 0x02 /** @} */ /* CO_STACK_CONFIG_TIME */ - /** * @defgroup CO_STACK_CONFIG_SYNC_PDO SYNC and PDO producer/consumer * Specified in standard CiA 301 @@ -461,9 +459,11 @@ extern "C" { * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of SYNC. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_SYNC \ + (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE \ + | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#define CO_CONFIG_SYNC_ENABLE 0x01 +#define CO_CONFIG_SYNC_ENABLE 0x01 #define CO_CONFIG_SYNC_PRODUCER 0x02 /** @@ -490,17 +490,19 @@ extern "C" { * - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of PDO. */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_RPDO_TIMERS_ENABLE | CO_CONFIG_TPDO_TIMERS_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_PDO_OD_IO_ACCESS | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) +#define CO_CONFIG_PDO \ + (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_RPDO_TIMERS_ENABLE | CO_CONFIG_TPDO_TIMERS_ENABLE \ + | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_PDO_OD_IO_ACCESS | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE \ + | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif -#define CO_CONFIG_RPDO_ENABLE 0x01 -#define CO_CONFIG_TPDO_ENABLE 0x02 +#define CO_CONFIG_RPDO_ENABLE 0x01 +#define CO_CONFIG_TPDO_ENABLE 0x02 #define CO_CONFIG_RPDO_TIMERS_ENABLE 0x04 #define CO_CONFIG_TPDO_TIMERS_ENABLE 0x08 -#define CO_CONFIG_PDO_SYNC_ENABLE 0x10 -#define CO_CONFIG_PDO_OD_IO_ACCESS 0x20 +#define CO_CONFIG_PDO_SYNC_ENABLE 0x10 +#define CO_CONFIG_PDO_OD_IO_ACCESS 0x20 /** @} */ /* CO_STACK_CONFIG_SYNC_PDO */ - /** * @defgroup CO_STACK_CONFIG_STORAGE Data storage * Data storage with CANopen OD objects 1010 and 1011, CiA 301 @@ -518,7 +520,6 @@ extern "C" { #define CO_CONFIG_STORAGE_ENABLE 0x01 /** @} */ /* CO_STACK_CONFIG_STORAGE */ - /** * @defgroup CO_STACK_CONFIG_LEDS CANopen LED diodes * Specified in standard CiA 303-3 @@ -538,7 +539,6 @@ extern "C" { #define CO_CONFIG_LEDS_ENABLE 0x01 /** @} */ /* CO_STACK_CONFIG_LEDS */ - /** * @defgroup CO_STACK_CONFIG_SRDO Safety Related Data Objects (SRDO) * Specified in standard EN 50325-5 (CiA 304) @@ -555,7 +555,7 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_GFC (0) #endif -#define CO_CONFIG_GFC_ENABLE 0x01 +#define CO_CONFIG_GFC_ENABLE 0x01 #define CO_CONFIG_GFC_CONSUMER 0x02 #define CO_CONFIG_GFC_PRODUCER 0x04 @@ -574,7 +574,7 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_SRDO (0) #endif -#define CO_CONFIG_SRDO_ENABLE 0x01 +#define CO_CONFIG_SRDO_ENABLE 0x01 #define CO_CONFIG_SRDO_CHECK_TX 0x02 /** @@ -588,7 +588,6 @@ extern "C" { #endif /** @} */ /* CO_STACK_CONFIG_SRDO */ - /** * @defgroup CO_STACK_CONFIG_LSS LSS master/slave * Specified in standard CiA 305 @@ -609,12 +608,11 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) #endif -#define CO_CONFIG_LSS_SLAVE 0x01 +#define CO_CONFIG_LSS_SLAVE 0x01 #define CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND 0x02 -#define CO_CONFIG_LSS_MASTER 0x10 +#define CO_CONFIG_LSS_MASTER 0x10 /** @} */ /* CO_STACK_CONFIG_LSS */ - /** * @defgroup CO_STACK_CONFIG_GATEWAY CANopen gateway * Specified in standard CiA 309 @@ -647,12 +645,12 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_GTW (0) #endif -#define CO_CONFIG_GTW_MULTI_NET 0x01 -#define CO_CONFIG_GTW_ASCII 0x02 -#define CO_CONFIG_GTW_ASCII_SDO 0x04 -#define CO_CONFIG_GTW_ASCII_NMT 0x08 -#define CO_CONFIG_GTW_ASCII_LSS 0x10 -#define CO_CONFIG_GTW_ASCII_LOG 0x20 +#define CO_CONFIG_GTW_MULTI_NET 0x01 +#define CO_CONFIG_GTW_ASCII 0x02 +#define CO_CONFIG_GTW_ASCII_SDO 0x04 +#define CO_CONFIG_GTW_ASCII_NMT 0x08 +#define CO_CONFIG_GTW_ASCII_LSS 0x10 +#define CO_CONFIG_GTW_ASCII_LOG 0x20 #define CO_CONFIG_GTW_ASCII_ERROR_DESC 0x40 #define CO_CONFIG_GTW_ASCII_PRINT_HELP 0x80 #define CO_CONFIG_GTW_ASCII_PRINT_LEDS 0x100 @@ -686,7 +684,6 @@ extern "C" { #endif /** @} */ /* CO_STACK_CONFIG_GATEWAY */ - /** * @defgroup CO_STACK_CONFIG_CRC16 CRC 16 calculation * Helper object for CRC-16 checksum @@ -702,11 +699,10 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_CRC16 (0) #endif -#define CO_CONFIG_CRC16_ENABLE 0x01 +#define CO_CONFIG_CRC16_ENABLE 0x01 #define CO_CONFIG_CRC16_EXTERNAL 0x02 /** @} */ /* CO_STACK_CONFIG_CRC16 */ - /** * @defgroup CO_STACK_CONFIG_FIFO FIFO buffer * Helper object for FIFO buffer @@ -736,14 +732,13 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_FIFO (0) #endif -#define CO_CONFIG_FIFO_ENABLE 0x01 -#define CO_CONFIG_FIFO_ALT_READ 0x02 -#define CO_CONFIG_FIFO_CRC16_CCITT 0x04 -#define CO_CONFIG_FIFO_ASCII_COMMANDS 0x08 +#define CO_CONFIG_FIFO_ENABLE 0x01 +#define CO_CONFIG_FIFO_ALT_READ 0x02 +#define CO_CONFIG_FIFO_CRC16_CCITT 0x04 +#define CO_CONFIG_FIFO_ASCII_COMMANDS 0x08 #define CO_CONFIG_FIFO_ASCII_DATATYPES 0x10 /** @} */ /* CO_STACK_CONFIG_FIFO */ - /** * @defgroup CO_STACK_CONFIG_TRACE Trace recorder * Non standard object @@ -760,11 +755,10 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_TRACE (0) #endif -#define CO_CONFIG_TRACE_ENABLE 0x01 +#define CO_CONFIG_TRACE_ENABLE 0x01 #define CO_CONFIG_TRACE_OWN_INTTYPES 0x02 /** @} */ /* CO_STACK_CONFIG_TRACE */ - /** * @defgroup CO_STACK_CONFIG_DEBUG Debug messages * Messages from different parts of the stack. @@ -784,7 +778,7 @@ extern "C" { #ifdef CO_DOXYGEN #define CO_CONFIG_DEBUG (0) #endif -#define CO_CONFIG_DEBUG_COMMON 0x01 +#define CO_CONFIG_DEBUG_COMMON 0x01 #define CO_CONFIG_DEBUG_SDO_CLIENT 0x02 #define CO_CONFIG_DEBUG_SDO_SERVER 0x04 /** @} */ /* CO_STACK_CONFIG_DEBUG */ diff --git a/301/CO_driver.h b/301/CO_driver.h index d5885054..834e3697 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -33,24 +33,24 @@ extern "C" { /* Stack configuration default global values. * For more information see file CO_config.h. */ #ifndef CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE - #define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0) +#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0) #endif #ifndef CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE - #define CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE (0) +#define CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE (0) #endif #ifndef CO_CONFIG_GLOBAL_FLAG_TIMERNEXT - #define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT (0) +#define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT (0) #endif #ifndef CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC - #define CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC CO_CONFIG_FLAG_OD_DYNAMIC +#define CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC CO_CONFIG_FLAG_OD_DYNAMIC #endif #ifdef CO_DEBUG_COMMON - #if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_CLIENT - #define CO_DEBUG_SDO_CLIENT(msg) CO_DEBUG_COMMON(msg) - #endif - #if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_SERVER - #define CO_DEBUG_SDO_SERVER(msg) CO_DEBUG_COMMON(msg) - #endif +#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_CLIENT +#define CO_DEBUG_SDO_CLIENT(msg) CO_DEBUG_COMMON(msg) +#endif +#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_SDO_SERVER +#define CO_DEBUG_SDO_SERVER(msg) CO_DEBUG_COMMON(msg) +#endif #endif /** @@ -111,7 +111,6 @@ extern "C" { /** Minor version number of CANopenNode */ #define CO_VERSION_MINOR 0 - /* Macros and declarations in following part are only used for documentation. */ #ifdef CO_DOXYGEN /** @@ -139,11 +138,11 @@ extern "C" { /** Macro must swap bytes, if CO_BIG_ENDIAN is defined */ #define CO_SWAP_64(x) x /** NULL, for general usage */ -#define NULL (0) +#define NULL (0) /** Logical true, for general use */ -#define true 1 +#define true 1 /** Logical false, for general use */ -#define false 0 +#define false 0 /** Boolean data type for general use */ typedef uint_fast8_t bool_t; /** INTEGER8 in CANopen (0002h), 8-bit signed integer */ @@ -168,7 +167,6 @@ typedef float float32_t; typedef double float64_t; /** @} */ - /** * @defgroup CO_CAN_Message_reception Reception of CAN messages * @{ @@ -200,7 +198,7 @@ typedef double float64_t; * registered with CO_CANrxBufferInit() * @param rxMsg pointer to received CAN message */ -void CANrx_callback(void *object, void *rxMsg); +void CANrx_callback(void* object, void* rxMsg); /** * CANrx_callback() can read CAN identifier from received CAN message @@ -216,7 +214,8 @@ void CANrx_callback(void *object, void *rxMsg); * @param rxMsg Pointer to received message * @return 11-bit CAN standard identifier. */ -static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg) { +static inline uint16_t +CO_CANrxMsg_readIdent(void* rxMsg) { return 0; } @@ -228,7 +227,8 @@ static inline uint16_t CO_CANrxMsg_readIdent(void *rxMsg) { * @param rxMsg Pointer to received message * @return data length in bytes (0 to 8) */ -static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg) { +static inline uint8_t +CO_CANrxMsg_readDLC(void* rxMsg) { return 0; } @@ -240,7 +240,8 @@ static inline uint8_t CO_CANrxMsg_readDLC(void *rxMsg) { * @param rxMsg Pointer to received message * @return pointer to data buffer */ -static inline const uint8_t *CO_CANrxMsg_readData(void *rxMsg) { +static inline const uint8_t* +CO_CANrxMsg_readData(void* rxMsg) { return NULL; } @@ -256,17 +257,16 @@ static inline const uint8_t *CO_CANrxMsg_readData(void *rxMsg) { * CO_CANmodule_t. */ typedef struct { - uint16_t ident; /**< Standard CAN Identifier (bits 0..10) + RTR (bit 11) */ - uint16_t mask; /**< Standard CAN Identifier mask with the same alignment as + uint16_t ident; /**< Standard CAN Identifier (bits 0..10) + RTR (bit 11) */ + uint16_t mask; /**< Standard CAN Identifier mask with the same alignment as ident */ - void *object; /**< \ref CO_obj "CANopenNode Object" initialized in from + void* object; /**< \ref CO_obj "CANopenNode Object" initialized in from CO_CANrxBufferInit() */ - void (*pCANrx_callback)( - void *object, void *message); /**< Pointer to CANrx_callback() + void (*pCANrx_callback)(void* object, void* message); /**< Pointer to CANrx_callback() initialized in CO_CANrxBufferInit() */ } CO_CANrx_t; -/** @} */ +/** @} */ /** * @defgroup CO_CAN_Message_transmission Transmission of CAN messages @@ -306,8 +306,8 @@ typedef struct { volatile bool_t syncFlag; /**< Synchronous PDO messages has this flag set. It prevents them to be sent outside the synchronous window */ } CO_CANtx_t; -/** @} */ +/** @} */ /** * Complete CAN module object. @@ -318,10 +318,10 @@ typedef struct { * microcontrollers. */ typedef struct { - void *CANptr; /**< From CO_CANmodule_init() */ - CO_CANrx_t *rxArray; /**< From CO_CANmodule_init() */ + void* CANptr; /**< From CO_CANmodule_init() */ + CO_CANrx_t* rxArray; /**< From CO_CANmodule_init() */ uint16_t rxSize; /**< From CO_CANmodule_init() */ - CO_CANtx_t *txArray; /**< From CO_CANmodule_init() */ + CO_CANtx_t* txArray; /**< From CO_CANmodule_init() */ uint16_t txSize; /**< From CO_CANmodule_init() */ uint16_t CANerrorStatus; /**< CAN error status bitfield, see @ref CO_CAN_ERR_status_t */ @@ -341,7 +341,6 @@ typedef struct { uint32_t errOld; /**< Previous state of CAN errors */ } CO_CANmodule_t; - /** * Data storage object for one entry. * @@ -354,7 +353,7 @@ typedef struct { */ typedef struct { /** Address of data to store, always required. */ - void *addr; + void* addr; /** Length of data to store, always required. */ size_t len; /** Sub index in OD objects 1010 and 1011, from 2 to 127. Writing @@ -366,7 +365,7 @@ typedef struct { uint8_t attr; /** Pointer to storage module, target system specific usage, required with * @ref CO_storage_eeprom. */ - void *storageModule; + void* storageModule; /** CRC checksum of the data stored in eeprom, set on store, required with * @ref CO_storage_eeprom. */ uint16_t crc; @@ -380,10 +379,9 @@ typedef struct { * @ref CO_storage_eeprom. */ size_t offset; /** Additional target specific parameters, optional. */ - void *additionalParameters; + void* additionalParameters; } CO_storage_entry_t; - /** * @defgroup CO_critical_sections Critical sections * @{ @@ -455,14 +453,21 @@ typedef struct { /** Check if new message has arrived */ #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) /** Set new message flag */ -#define CO_FLAG_SET(rxNew) { __sync_synchronize(); rxNew = (void *)1L; } +#define CO_FLAG_SET(rxNew) \ + { \ + __sync_synchronize(); \ + rxNew = (void*)1L; \ + } /** Clear new message flag */ -#define CO_FLAG_CLEAR(rxNew) { __sync_synchronize(); rxNew = NULL; } +#define CO_FLAG_CLEAR(rxNew) \ + { \ + __sync_synchronize(); \ + rxNew = NULL; \ + } /** @} */ #endif /* CO_DOXYGEN */ - /** * @defgroup CO_Default_CAN_ID_t Default CANopen identifiers * @{ @@ -472,29 +477,28 @@ typedef struct { * can be changed in CANopen. Especially PDO identifiers are configured * in PDO linking phase of the CANopen network configuration. */ -#define CO_CAN_ID_NMT_SERVICE 0x000U /**< 0x000 Network management */ -#define CO_CAN_ID_GFC 0x001U /**< 0x001 Global fail-safe command */ -#define CO_CAN_ID_SYNC 0x080U /**< 0x080 Synchronous message */ -#define CO_CAN_ID_EMERGENCY 0x080U /**< 0x080 Emergency messages (+nodeID) */ -#define CO_CAN_ID_TIME 0x100U /**< 0x100 Time message */ -#define CO_CAN_ID_SRDO_1 0x0FFU /**< 0x0FF Default SRDO1 (+2*nodeID) */ -#define CO_CAN_ID_TPDO_1 0x180U /**< 0x180 Default TPDO1 (+nodeID) */ -#define CO_CAN_ID_RPDO_1 0x200U /**< 0x200 Default RPDO1 (+nodeID) */ -#define CO_CAN_ID_TPDO_2 0x280U /**< 0x280 Default TPDO2 (+nodeID) */ -#define CO_CAN_ID_RPDO_2 0x300U /**< 0x300 Default RPDO2 (+nodeID) */ -#define CO_CAN_ID_TPDO_3 0x380U /**< 0x380 Default TPDO3 (+nodeID) */ -#define CO_CAN_ID_RPDO_3 0x400U /**< 0x400 Default RPDO3 (+nodeID) */ -#define CO_CAN_ID_TPDO_4 0x480U /**< 0x480 Default TPDO4 (+nodeID) */ -#define CO_CAN_ID_RPDO_4 0x500U /**< 0x500 Default RPDO5 (+nodeID) */ -#define CO_CAN_ID_SDO_SRV 0x580U /**< 0x580 SDO response from server (+nodeID) */ -#define CO_CAN_ID_SDO_CLI 0x600U /**< 0x600 SDO request from client (+nodeID) */ -#define CO_CAN_ID_HEARTBEAT 0x700U /**< 0x700 Heartbeat message */ -#define CO_CAN_ID_LSS_SLV 0x7E4U /**< 0x7E4 LSS response from slave */ -#define CO_CAN_ID_LSS_MST 0x7E5U /**< 0x7E5 LSS request from master */ +#define CO_CAN_ID_NMT_SERVICE 0x000U /**< 0x000 Network management */ +#define CO_CAN_ID_GFC 0x001U /**< 0x001 Global fail-safe command */ +#define CO_CAN_ID_SYNC 0x080U /**< 0x080 Synchronous message */ +#define CO_CAN_ID_EMERGENCY 0x080U /**< 0x080 Emergency messages (+nodeID) */ +#define CO_CAN_ID_TIME 0x100U /**< 0x100 Time message */ +#define CO_CAN_ID_SRDO_1 0x0FFU /**< 0x0FF Default SRDO1 (+2*nodeID) */ +#define CO_CAN_ID_TPDO_1 0x180U /**< 0x180 Default TPDO1 (+nodeID) */ +#define CO_CAN_ID_RPDO_1 0x200U /**< 0x200 Default RPDO1 (+nodeID) */ +#define CO_CAN_ID_TPDO_2 0x280U /**< 0x280 Default TPDO2 (+nodeID) */ +#define CO_CAN_ID_RPDO_2 0x300U /**< 0x300 Default RPDO2 (+nodeID) */ +#define CO_CAN_ID_TPDO_3 0x380U /**< 0x380 Default TPDO3 (+nodeID) */ +#define CO_CAN_ID_RPDO_3 0x400U /**< 0x400 Default RPDO3 (+nodeID) */ +#define CO_CAN_ID_TPDO_4 0x480U /**< 0x480 Default TPDO4 (+nodeID) */ +#define CO_CAN_ID_RPDO_4 0x500U /**< 0x500 Default RPDO5 (+nodeID) */ +#define CO_CAN_ID_SDO_SRV 0x580U /**< 0x580 SDO response from server (+nodeID) */ +#define CO_CAN_ID_SDO_CLI 0x600U /**< 0x600 SDO request from client (+nodeID) */ +#define CO_CAN_ID_HEARTBEAT 0x700U /**< 0x700 Heartbeat message */ +#define CO_CAN_ID_LSS_SLV 0x7E4U /**< 0x7E4 LSS response from slave */ +#define CO_CAN_ID_LSS_MST 0x7E5U /**< 0x7E5 LSS request from master */ /** @} */ /* CO_Default_CAN_ID_t */ - /** * Restricted CAN-IDs * @@ -502,15 +506,12 @@ typedef struct { * They shall not be used for SYNC, TIME, EMCY, PDO and SDO. */ #ifndef CO_IS_RESTRICTED_CAN_ID -#define CO_IS_RESTRICTED_CAN_ID(CAN_ID) (((CAN_ID) <= 0x7FU) \ - || (((CAN_ID) >= 0x101U) && ((CAN_ID) <= 0x180U)) \ - || (((CAN_ID) >= 0x581U) && ((CAN_ID) <= 0x5FFU)) \ - || (((CAN_ID) >= 0x601U) && ((CAN_ID) <= 0x67FU)) \ - || (((CAN_ID) >= 0x6E0U) && ((CAN_ID) <= 0x6FFU)) \ - || ((CAN_ID) >= 0x701U)) +#define CO_IS_RESTRICTED_CAN_ID(CAN_ID) \ + (((CAN_ID) <= 0x7FU) || (((CAN_ID) >= 0x101U) && ((CAN_ID) <= 0x180U)) \ + || (((CAN_ID) >= 0x581U) && ((CAN_ID) <= 0x5FFU)) || (((CAN_ID) >= 0x601U) && ((CAN_ID) <= 0x67FU)) \ + || (((CAN_ID) >= 0x6E0U) && ((CAN_ID) <= 0x6FFU)) || ((CAN_ID) >= 0x701U)) #endif - /** * @defgroup CO_CAN_ERR_status_t CAN error status bitmasks * @{ @@ -520,15 +521,15 @@ typedef struct { * equal to 128. Transmitter goes in error state 'bus off' if transmit error * counter is more or equal to 256. */ -#define CO_CAN_ERRTX_WARNING 0x0001U /**< 0x0001 CAN transmitter warning */ -#define CO_CAN_ERRTX_PASSIVE 0x0002U /**< 0x0002 CAN transmitter passive */ -#define CO_CAN_ERRTX_BUS_OFF 0x0004U /**< 0x0004 CAN transmitter bus off */ -#define CO_CAN_ERRTX_OVERFLOW 0x0008U /**< 0x0008 CAN transmitter overflow */ -#define CO_CAN_ERRTX_PDO_LATE 0x0080U /**< 0x0080 TPDO is outside sync window */ -#define CO_CAN_ERRRX_WARNING 0x0100U /**< 0x0100 CAN receiver warning */ -#define CO_CAN_ERRRX_PASSIVE 0x0200U /**< 0x0200 CAN receiver passive */ -#define CO_CAN_ERRRX_OVERFLOW 0x0800U /**< 0x0800 CAN receiver overflow */ -#define CO_CAN_ERR_WARN_PASSIVE 0x0303U /**< 0x0303 combination */ +#define CO_CAN_ERRTX_WARNING 0x0001U /**< 0x0001 CAN transmitter warning */ +#define CO_CAN_ERRTX_PASSIVE 0x0002U /**< 0x0002 CAN transmitter passive */ +#define CO_CAN_ERRTX_BUS_OFF 0x0004U /**< 0x0004 CAN transmitter bus off */ +#define CO_CAN_ERRTX_OVERFLOW 0x0008U /**< 0x0008 CAN transmitter overflow */ +#define CO_CAN_ERRTX_PDO_LATE 0x0080U /**< 0x0080 TPDO is outside sync window */ +#define CO_CAN_ERRRX_WARNING 0x0100U /**< 0x0100 CAN receiver warning */ +#define CO_CAN_ERRRX_PASSIVE 0x0200U /**< 0x0200 CAN receiver passive */ +#define CO_CAN_ERRRX_OVERFLOW 0x0800U /**< 0x0800 CAN receiver overflow */ +#define CO_CAN_ERR_WARN_PASSIVE 0x0303U /**< 0x0303 combination */ /** @} */ /* CO_CAN_ERR_status_t */ @@ -537,52 +538,49 @@ typedef struct { * successfully it returns 0 otherwise it returns <0. */ typedef enum { - CO_ERROR_NO = 0, /**< Operation completed successfully */ - CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ - CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ - CO_ERROR_TIMEOUT = -3, /**< Function timeout */ - CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function + CO_ERROR_NO = 0, /**< Operation completed successfully */ + CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ + CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ + CO_ERROR_TIMEOUT = -3, /**< Function timeout */ + CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function CO_CANmodule_init() */ - CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed + CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed yet */ - CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ - CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ - CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ - CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, + CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ + CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ + CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ + CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, buffer full */ - CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ - CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not configured + CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ + CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not configured properly */ - CO_ERROR_OD_PARAMETERS = -12, /**< Error in Object Dictionary parameters*/ - CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ - CO_ERROR_CRC = -14, /**< CRC does not match */ - CO_ERROR_TX_BUSY = -15, /**< Sending rejected because driver is + CO_ERROR_OD_PARAMETERS = -12, /**< Error in Object Dictionary parameters*/ + CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ + CO_ERROR_CRC = -14, /**< CRC does not match */ + CO_ERROR_TX_BUSY = -15, /**< Sending rejected because driver is busy. Try again */ - CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current + CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current state */ - CO_ERROR_SYSCALL = -17, /**< Syscall failed */ - CO_ERROR_INVALID_STATE = -18, /**< Driver not ready */ + CO_ERROR_SYSCALL = -17, /**< Syscall failed */ + CO_ERROR_INVALID_STATE = -18, /**< Driver not ready */ CO_ERROR_NODE_ID_UNCONFIGURED_LSS = -19 /**< Node-id is in LSS unconfigured state. If objects are handled properly, this may not be an error. */ } CO_ReturnError_t; - /** * Request CAN configuration (stopped) mode and *wait* until it is set. * * @param CANptr Pointer to CAN device */ -void CO_CANsetConfigurationMode(void *CANptr); - +void CO_CANsetConfigurationMode(void* CANptr); /** * Request CAN normal (operational) mode and *wait* until it is set. * * @param CANmodule CO_CANmodule_t object. */ -void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); - +void CO_CANsetNormalMode(CO_CANmodule_t* CANmodule); /** * Initialize CAN module object. @@ -603,22 +601,15 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule); * * Return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, - void *CANptr, - CO_CANrx_t rxArray[], - uint16_t rxSize, - CO_CANtx_t txArray[], - uint16_t txSize, - uint16_t CANbitRate); - +CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t* CANmodule, void* CANptr, CO_CANrx_t rxArray[], uint16_t rxSize, + CO_CANtx_t txArray[], uint16_t txSize, uint16_t CANbitRate); /** * Switch off CANmodule. Call at program exit. * * @param CANmodule CAN module object. */ -void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); - +void CO_CANmodule_disable(CO_CANmodule_t* CANmodule); /** * Configure CAN message receive buffer. @@ -645,15 +636,8 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule); * 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, - uint16_t index, - uint16_t ident, - uint16_t mask, - bool_t rtr, - void *object, - void (*CANrx_callback)(void *object, - void *message)); - +CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, uint16_t mask, + bool_t rtr, void* object, void (*CANrx_callback)(void* object, void* message)); /** * Configure CAN message transmit buffer. @@ -673,14 +657,9 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, * 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, - uint16_t index, - uint16_t ident, - bool_t rtr, - uint8_t noOfBytes, +CO_CANtx_t* CO_CANtxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, bool_t rtr, uint8_t noOfBytes, bool_t syncFlag); - /** * Send CAN message. * @@ -691,8 +670,7 @@ CO_CANtx_t *CO_CANtxBufferInit(CO_CANmodule_t *CANmodule, * @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); - +CO_ReturnError_t CO_CANsend(CO_CANmodule_t* CANmodule, CO_CANtx_t* buffer); /** * Clear all synchronous TPDOs from CAN module transmit buffers. @@ -708,8 +686,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer); * * @param CANmodule This object. */ -void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); - +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t* CANmodule); /** * Process can module - verify CAN errors @@ -719,8 +696,7 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule); * * @param CANmodule This object. */ -void CO_CANmodule_process(CO_CANmodule_t *CANmodule); - +void CO_CANmodule_process(CO_CANmodule_t* CANmodule); /** * Get uint8_t value from memory buffer @@ -729,16 +705,27 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule); * * @return Value */ -static inline uint8_t CO_getUint8(const void *buf) { - uint8_t value; (void)memmove((void *)&value, buf, sizeof(value)); return value; +static inline uint8_t +CO_getUint8(const void* buf) { + uint8_t value; + (void)memmove((void*)&value, buf, sizeof(value)); + return value; } + /** Get uint16_t value from memory buffer, see @ref CO_getUint8 */ -static inline uint16_t CO_getUint16(const void *buf) { - uint16_t value; (void)memmove((void *)&value, buf, sizeof(value)); return value; +static inline uint16_t +CO_getUint16(const void* buf) { + uint16_t value; + (void)memmove((void*)&value, buf, sizeof(value)); + return value; } + /** Get uint32_t value from memory buffer, see @ref CO_getUint8 */ -static inline uint32_t CO_getUint32(const void *buf) { - uint32_t value; (void)memmove((void *)&value, buf, sizeof(value)); return value; +static inline uint32_t +CO_getUint32(const void* buf) { + uint32_t value; + (void)memmove((void*)&value, buf, sizeof(value)); + return value; } /** @@ -749,16 +736,24 @@ static inline uint32_t CO_getUint32(const void *buf) { * * @return number of bytes written. */ -static inline uint8_t CO_setUint8(void *buf, uint8_t value) { - (void)memmove(buf, (const void *)&value, sizeof(value)); return (uint8_t)(sizeof(value)); +static inline uint8_t +CO_setUint8(void* buf, uint8_t value) { + (void)memmove(buf, (const void*)&value, sizeof(value)); + return (uint8_t)(sizeof(value)); } + /** Write uint16_t value into memory buffer, see @ref CO_setUint8 */ -static inline uint8_t CO_setUint16(void *buf, uint16_t value) { - (void)memmove(buf, (const void *)&value, sizeof(value)); return (uint8_t)(sizeof(value)); +static inline uint8_t +CO_setUint16(void* buf, uint16_t value) { + (void)memmove(buf, (const void*)&value, sizeof(value)); + return (uint8_t)(sizeof(value)); } + /** Write uint32_t value into memory buffer, see @ref CO_setUint8 */ -static inline uint8_t CO_setUint32(void *buf, uint32_t value) { - (void)memmove(buf, (const void *)&value, sizeof(value)); return (uint8_t)(sizeof(value)); +static inline uint8_t +CO_setUint32(void* buf, uint32_t value) { + (void)memmove(buf, (const void*)&value, sizeof(value)); + return (uint8_t)(sizeof(value)); } /** @} */ /* CO_driver */ diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 671699b0..8c1a9ca2 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -28,7 +28,7 @@ #define CO_CONFIG_FIFO (0) #endif -#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -56,18 +56,18 @@ extern "C" { */ typedef struct { /** Buffer of size bufSize. Initialized by CO_fifo_init() */ - uint8_t *buf; + uint8_t* buf; /** Initialized by CO_fifo_init() */ size_t bufSize; /** Location in the buffer, which will be next written. */ size_t writePtr; /** Location in the buffer, which will be next read. */ size_t readPtr; -#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ALT_READ) != 0) || defined CO_DOXYGEN /** Location in the buffer, which will be next read. */ size_t altReadPtr; #endif -#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_DATATYPES) != 0) || defined CO_DOXYGEN /** helper variable, set to false in CO_fifo_reset(), used in some * functions. */ bool_t started; @@ -76,8 +76,6 @@ typedef struct { #endif } CO_fifo_t; - - /** * Initialize fifo object * @@ -86,19 +84,19 @@ typedef struct { * @param bufSize Size of the above buffer. Usable size of the buffer will be * one byte less than bufSize, it is used for operation of the circular buffer. */ -void CO_fifo_init(CO_fifo_t *fifo, uint8_t *buf, size_t bufSize); - +void CO_fifo_init(CO_fifo_t* fifo, uint8_t* buf, size_t bufSize); /** * Reset fifo object, make it empty * * @param fifo This object */ -static inline void CO_fifo_reset(CO_fifo_t *fifo) { +static inline void +CO_fifo_reset(CO_fifo_t* fifo) { if (fifo != NULL) { fifo->readPtr = 0; fifo->writePtr = 0; -#if ((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0 +#if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_DATATYPES) != 0 fifo->started = false; #endif } @@ -106,7 +104,6 @@ static inline void CO_fifo_reset(CO_fifo_t *fifo) { return; } - /** * Purge all data in fifo object, keep other properties * @@ -114,7 +111,8 @@ static inline void CO_fifo_reset(CO_fifo_t *fifo) { * * @return true, if data were purged or false, if fifo were already empty */ -static inline bool_t CO_fifo_purge(CO_fifo_t *fifo) { +static inline bool_t +CO_fifo_purge(CO_fifo_t* fifo) { if (fifo != NULL && fifo->readPtr != fifo->writePtr) { fifo->readPtr = 0; fifo->writePtr = 0; @@ -124,7 +122,6 @@ static inline bool_t CO_fifo_purge(CO_fifo_t *fifo) { return false; } - /** * Get free buffer space in CO_fifo_t object * @@ -132,16 +129,16 @@ static inline bool_t CO_fifo_purge(CO_fifo_t *fifo) { * * @return number of available bytes */ -static inline size_t CO_fifo_getSpace(CO_fifo_t *fifo) { +static inline size_t +CO_fifo_getSpace(CO_fifo_t* fifo) { int sizeLeft = (int)fifo->readPtr - (int)fifo->writePtr - 1; if (sizeLeft < 0) { sizeLeft += (int)fifo->bufSize; } - return (size_t) sizeLeft; + return (size_t)sizeLeft; } - /** * Get size of data inside CO_fifo_t buffer object * @@ -149,16 +146,16 @@ static inline size_t CO_fifo_getSpace(CO_fifo_t *fifo) { * * @return number of occupied bytes */ -static inline size_t CO_fifo_getOccupied(CO_fifo_t *fifo) { +static inline size_t +CO_fifo_getOccupied(CO_fifo_t* fifo) { int sizeOccupied = (int)fifo->writePtr - (int)fifo->readPtr; if (sizeOccupied < 0) { sizeOccupied += (int)fifo->bufSize; } - return (size_t) sizeOccupied; + return (size_t)sizeOccupied; } - /** * Put one character into CO_fifo_t buffer object * @@ -167,12 +164,11 @@ static inline size_t CO_fifo_getOccupied(CO_fifo_t *fifo) { * * @return true, if write was successful (enough space in fifo buffer) */ -static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const uint8_t c) { +static inline bool_t +CO_fifo_putc(CO_fifo_t* fifo, const uint8_t c) { if (fifo != NULL && fifo->buf != NULL) { size_t writePtrNext = fifo->writePtr + 1; - if (writePtrNext != fifo->readPtr && - !(writePtrNext == fifo->bufSize && fifo->readPtr == 0)) - { + if (writePtrNext != fifo->readPtr && !(writePtrNext == fifo->bufSize && fifo->readPtr == 0)) { fifo->buf[fifo->writePtr] = c; fifo->writePtr = (writePtrNext == fifo->bufSize) ? 0 : writePtrNext; return true; @@ -181,7 +177,6 @@ static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const uint8_t c) { return false; } - /** * Put one character into CO_fifo_t buffer object * @@ -190,18 +185,22 @@ static inline bool_t CO_fifo_putc(CO_fifo_t *fifo, const uint8_t c) { * @param fifo This object * @param c Character to put */ -static inline void CO_fifo_putc_ov(CO_fifo_t *fifo, const uint8_t c) { +static inline void +CO_fifo_putc_ov(CO_fifo_t* fifo, const uint8_t c) { if (fifo != NULL && fifo->buf != NULL) { fifo->buf[fifo->writePtr] = c; - if (++fifo->writePtr == fifo->bufSize) fifo->writePtr = 0; + if (++fifo->writePtr == fifo->bufSize) { + fifo->writePtr = 0; + } if (fifo->readPtr == fifo->writePtr) { - if (++fifo->readPtr == fifo->bufSize) fifo->readPtr = 0; + if (++fifo->readPtr == fifo->bufSize) { + fifo->readPtr = 0; + } } } } - /** * Get one character from CO_fifo_t buffer object * @@ -210,7 +209,8 @@ static inline void CO_fifo_putc_ov(CO_fifo_t *fifo, const uint8_t c) { * * @return true, if read was successful (non-empty fifo buffer) */ -static inline bool_t CO_fifo_getc(CO_fifo_t *fifo, uint8_t *buf) { +static inline bool_t +CO_fifo_getc(CO_fifo_t* fifo, uint8_t* buf) { if (fifo != NULL && buf != NULL && fifo->readPtr != fifo->writePtr) { *buf = fifo->buf[fifo->readPtr]; if (++fifo->readPtr == fifo->bufSize) { @@ -221,7 +221,6 @@ static inline bool_t CO_fifo_getc(CO_fifo_t *fifo, uint8_t *buf) { return false; } - /** * Write data into CO_fifo_t object. * @@ -237,11 +236,7 @@ static inline bool_t CO_fifo_getc(CO_fifo_t *fifo, uint8_t *buf) { * * @return number of bytes actually written. */ -size_t CO_fifo_write(CO_fifo_t *fifo, - const uint8_t *buf, - size_t count, - uint16_t *crc); - +size_t CO_fifo_write(CO_fifo_t* fifo, const uint8_t* buf, size_t count, uint16_t* crc); /** * Read data from CO_fifo_t object. @@ -259,10 +254,9 @@ size_t CO_fifo_write(CO_fifo_t *fifo, * * @return number of bytes actually read. */ -size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof); - +size_t CO_fifo_read(CO_fifo_t* fifo, uint8_t* buf, size_t count, bool_t* eof); -#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ALT_READ) != 0) || defined CO_DOXYGEN /** * Initializes alternate read with #CO_fifo_altRead * @@ -271,8 +265,7 @@ size_t CO_fifo_read(CO_fifo_t *fifo, uint8_t *buf, size_t count, bool_t *eof); * * @return same as offset or lower, if there is not enough data. */ -size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset); - +size_t CO_fifo_altBegin(CO_fifo_t* fifo, size_t offset); /** * Ends alternate read with #CO_fifo_altRead and calculate crc checksum @@ -281,8 +274,7 @@ size_t CO_fifo_altBegin(CO_fifo_t *fifo, size_t offset); * @param [in,out] crc Externally defined variable for CRC checksum, ignored if * NULL */ -void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc); - +void CO_fifo_altFinish(CO_fifo_t* fifo, uint16_t* crc); /** * Get alternate size of remaining data, see #CO_fifo_altRead @@ -291,16 +283,16 @@ void CO_fifo_altFinish(CO_fifo_t *fifo, uint16_t *crc); * * @return number of occupied bytes. */ -static inline size_t CO_fifo_altGetOccupied(CO_fifo_t *fifo) { +static inline size_t +CO_fifo_altGetOccupied(CO_fifo_t* fifo) { int sizeOccupied = (int)fifo->writePtr - (int)fifo->altReadPtr; if (sizeOccupied < 0) { sizeOccupied += (int)fifo->bufSize; } - return (size_t) sizeOccupied; + return (size_t)sizeOccupied; } - /** * Alternate read data from CO_fifo_t object. * @@ -317,11 +309,10 @@ static inline size_t CO_fifo_altGetOccupied(CO_fifo_t *fifo) { * * @return number of bytes actually read. */ -size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count); +size_t CO_fifo_altRead(CO_fifo_t* fifo, uint8_t* buf, size_t count); #endif /* #if (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ */ - -#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_COMMANDS) != 0) || defined CO_DOXYGEN /** * Search command inside FIFO * @@ -346,8 +337,7 @@ size_t CO_fifo_altRead(CO_fifo_t *fifo, uint8_t *buf, size_t count); * * @return true if command with delimiter found or buffer full. */ -bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear); - +bool_t CO_fifo_CommSearch(CO_fifo_t* fifo, bool_t clear); /** * Trim spaces inside FIFO @@ -363,8 +353,7 @@ bool_t CO_fifo_CommSearch(CO_fifo_t *fifo, bool_t clear); * * @return true if command delimiter was found. */ -bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment); - +bool_t CO_fifo_trimSpaces(CO_fifo_t* fifo, bool_t* insideComment); /** * Get token from FIFO buffer @@ -403,15 +392,10 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t *fifo, bool_t *insideComment); * * @return Number of bytes read. */ -size_t CO_fifo_readToken(CO_fifo_t *fifo, - char *buf, - size_t count, - uint8_t *closed, - bool_t *err); +size_t CO_fifo_readToken(CO_fifo_t* fifo, char* buf, size_t count, uint8_t* closed, bool_t* err); #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS */ - -#if (((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_DATATYPES) != 0) || defined CO_DOXYGEN /** * Read uint8_t variable from fifo and output as ascii string. * @@ -422,64 +406,63 @@ size_t CO_fifo_readToken(CO_fifo_t *fifo, * * @return Number of ascii bytes written into buf. */ -size_t CO_fifo_readU82a (CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readU82a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read uint16_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readU162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readU162a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read uint32_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readU322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readU322a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read uint64_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readU642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readU642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read uint8_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readX82a (CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readX82a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read uint16_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readX162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readX162a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read uint32_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readX322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readX322a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read uint64_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readX642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readX642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read int8_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readI82a (CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readI82a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read int16_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readI162a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readI162a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read int32_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readI322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readI322a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read int64_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readI642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readI642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read float32_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readR322a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readR322a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read float64_t variable from fifo as ascii string, see CO_fifo_readU82a */ -size_t CO_fifo_readR642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readR642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read data from fifo and output as space separated two digit ascii string, * see also CO_fifo_readU82a */ -size_t CO_fifo_readHex2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readHex2a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read data from fifo and output as visible string. A visible string is * enclosed with double quotes. If a double quote is used within the string, * the quotes are escaped by a second quotes, e.g. “Hello “”World””, CANopen * is great”. UTF-8 characters and also line breaks works with this function. * Function removes all NULL and CR characters from output string. * See also CO_fifo_readU82a */ -size_t CO_fifo_readVs2a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); +size_t CO_fifo_readVs2a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read data from fifo and output as mime-base64 encoded string. Encoding is as * specified in RFC 2045, without CR-LF, but one long string. See also * CO_fifo_readU82a */ -size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); - +size_t CO_fifo_readB642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar */ - /** * @defgroup uint8_t Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar * @{ */ -#define CO_fifo_st_closed 0x01U /**< Bit is set, if command delimiter is reached in src */ -#define CO_fifo_st_partial 0x02U /**< Bit is set, if copy was partial and more data are available. If unset and no error, then all data was successfully copied. */ -#define CO_fifo_st_errTok 0x10U /**< Bit is set, if no valid token found */ -#define CO_fifo_st_errVal 0x20U /**< Bit is set, if value is not valid or out of limits */ -#define CO_fifo_st_errBuf 0x40U /**< Bit is set, if destination buffer is to small */ -#define CO_fifo_st_errInt 0x80U /**< Bit is set, if internal error */ -#define CO_fifo_st_errMask 0xF0U /**< Bitmask for error bits */ -/** @} */ /* uint8_t */ +#define CO_fifo_st_closed 0x01U /**< Bit is set, if command delimiter is reached in src */ +#define CO_fifo_st_partial \ + 0x02U /**< Bit is set, if copy was partial and more data are available. If unset and no error, then all data was successfully copied. */ +#define CO_fifo_st_errTok 0x10U /**< Bit is set, if no valid token found */ +#define CO_fifo_st_errVal 0x20U /**< Bit is set, if value is not valid or out of limits */ +#define CO_fifo_st_errBuf 0x40U /**< Bit is set, if destination buffer is to small */ +#define CO_fifo_st_errInt 0x80U /**< Bit is set, if internal error */ +#define CO_fifo_st_errMask 0xF0U /**< Bitmask for error bits */ +/** @} */ /* uint8_t */ /** * Read ascii string from src fifo and copy as uint8_t variable to dest fifo. @@ -490,37 +473,37 @@ size_t CO_fifo_readB642a(CO_fifo_t *fifo, char *buf, size_t count, bool_t end); * * @return Number of bytes written into dest. */ -size_t CO_fifo_cpyTok2U8 (CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2U8(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to uint16_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2U16(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to uint32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2U32(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to uint64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2U64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2U64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to int8_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I8 (CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2I8(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to int16_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I16(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2I16(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to int32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2I32(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to int64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2I64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2I64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to float32_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2R32(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2R32(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to float64_t variable, see CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2R64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2R64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy bytes written as two hex digits into to data. Bytes may be space * separated. See CO_fifo_cpyTok2U8 for parameters. */ -size_t CO_fifo_cpyTok2Hex(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2Hex(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy visible string to data. A visible string must be enclosed with double * quotes, if it contains space. If a double quote is used within the string, * the quotes are escaped by a second quotes. Input string can not contain * newline characters. See CO_fifo_cpyTok2U8 */ -size_t CO_fifo_cpyTok2Vs(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2Vs(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Read ascii mime-base64 encoded string from src fifo and copy as binary data * to dest fifo. Encoding is as specified in RFC 2045, without CR-LF, but one * long string in single line. See also CO_fifo_readU82a */ -size_t CO_fifo_cpyTok2B64(CO_fifo_t *dest, CO_fifo_t *src, uint8_t *status); +size_t CO_fifo_cpyTok2B64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES */ diff --git a/301/crc16-ccitt.h b/301/crc16-ccitt.h index 22569039..8643d6d7 100644 --- a/301/crc16-ccitt.h +++ b/301/crc16-ccitt.h @@ -29,7 +29,7 @@ #define CO_CONFIG_CRC16 (0) #endif -#if (((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -47,7 +47,6 @@ extern "C" { * `x^16 + x^12 + x^5 + 1` */ - /** * Update crc16_ccitt variable with one data byte * @@ -58,8 +57,7 @@ extern "C" { * start of new CRC calculation, variable must be initialized (zero for xmodem). * @param chr One byte of data */ -void crc16_ccitt_single(uint16_t *crc, const uint8_t chr); - +void crc16_ccitt_single(uint16_t* crc, const uint8_t chr); /** * Calculate CRC sum on block of data. @@ -71,10 +69,7 @@ void crc16_ccitt_single(uint16_t *crc, const uint8_t chr); * * @return Calculated CRC. */ -uint16_t crc16_ccitt(const uint8_t block[], - size_t blockLength, - uint16_t crc); - +uint16_t crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc); /** @} */ /* CO_crc16_ccitt */ diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index caa2fb23..7cb4d9ac 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -26,11 +26,10 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_LEDS -#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | \ - CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif -#if (((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -73,37 +72,35 @@ extern "C" { * @{ * */ -#define CO_LED_flicker 0x01U /**< LED flickering 10Hz */ -#define CO_LED_blink 0x02U /**< LED blinking 2,5Hz */ -#define CO_LED_flash_1 0x04U /**< LED single flash */ -#define CO_LED_flash_2 0x08U /**< LED double flash */ -#define CO_LED_flash_3 0x10U /**< LED triple flash */ -#define CO_LED_flash_4 0x20U /**< LED quadruple flash */ -#define CO_LED_CANopen 0x80U /**< LED CANopen according to CiA 303-3 */ +#define CO_LED_flicker 0x01U /**< LED flickering 10Hz */ +#define CO_LED_blink 0x02U /**< LED blinking 2,5Hz */ +#define CO_LED_flash_1 0x04U /**< LED single flash */ +#define CO_LED_flash_2 0x08U /**< LED double flash */ +#define CO_LED_flash_3 0x10U /**< LED triple flash */ +#define CO_LED_flash_4 0x20U /**< LED quadruple flash */ +#define CO_LED_CANopen 0x80U /**< LED CANopen according to CiA 303-3 */ /** @} */ /* CO_LED_BITFIELD_t */ /** Get on/off state for green led for specified bitfield */ -#define CO_LED_RED(LEDs, BITFIELD) ((((LEDs)->LEDred & BITFIELD) != 0U) ? 1U : 0U) +#define CO_LED_RED(LEDs, BITFIELD) ((((LEDs)->LEDred & BITFIELD) != 0U) ? 1U : 0U) /** Get on/off state for green led for specified bitfield */ #define CO_LED_GREEN(LEDs, BITFIELD) ((((LEDs)->LEDgreen & BITFIELD) != 0U) ? 1U : 0U) - /** * LEDs object, initialized by CO_LEDs_init() */ -typedef struct{ - uint32_t LEDtmr50ms; /**< 50ms led timer */ - uint8_t LEDtmr200ms; /**< 200ms led timer */ - uint8_t LEDtmrflash_1; /**< single flash led timer */ - uint8_t LEDtmrflash_2; /**< double flash led timer */ - uint8_t LEDtmrflash_3; /**< triple flash led timer */ - uint8_t LEDtmrflash_4; /**< quadruple flash led timer */ - uint8_t LEDred; /**< red led #CO_LED_BITFIELD_t */ - uint8_t LEDgreen; /**< green led #CO_LED_BITFIELD_t */ +typedef struct { + uint32_t LEDtmr50ms; /**< 50ms led timer */ + uint8_t LEDtmr200ms; /**< 200ms led timer */ + uint8_t LEDtmrflash_1; /**< single flash led timer */ + uint8_t LEDtmrflash_2; /**< double flash led timer */ + uint8_t LEDtmrflash_3; /**< triple flash led timer */ + uint8_t LEDtmrflash_4; /**< quadruple flash led timer */ + uint8_t LEDred; /**< red led #CO_LED_BITFIELD_t */ + uint8_t LEDgreen; /**< green led #CO_LED_BITFIELD_t */ } CO_LEDs_t; - /** * Initialize LEDs object. * @@ -113,8 +110,7 @@ typedef struct{ * * @return #CO_ReturnError_t CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs); - +CO_ReturnError_t CO_LEDs_init(CO_LEDs_t* LEDs); /** * Process indicator states @@ -135,18 +131,9 @@ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t *LEDs); * @param firmwareDownload Firmware download is in progress indication. * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_LEDs_process(CO_LEDs_t *LEDs, - uint32_t timeDifference_us, - CO_NMT_internalState_t NMTstate, - bool_t LSSconfig, - bool_t ErrCANbusOff, - bool_t ErrCANbusWarn, - bool_t ErrRpdo, - bool_t ErrSync, - bool_t ErrHbCons, - bool_t ErrOther, - bool_t firmwareDownload, - uint32_t *timerNext_us); +void CO_LEDs_process(CO_LEDs_t* LEDs, uint32_t timeDifference_us, CO_NMT_internalState_t NMTstate, bool_t LSSconfig, + bool_t ErrCANbusOff, bool_t ErrCANbusWarn, bool_t ErrRpdo, bool_t ErrSync, bool_t ErrHbCons, + bool_t ErrOther, bool_t firmwareDownload, uint32_t* timerNext_us); /** @} */ /* CO_LEDs */ diff --git a/304/CO_GFC.h b/304/CO_GFC.h index 121946d1..5f7ebeca 100644 --- a/304/CO_GFC.h +++ b/304/CO_GFC.h @@ -30,7 +30,7 @@ #define CO_CONFIG_GFC (0) #endif -#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -53,13 +53,13 @@ extern "C" { * GFC object. */ typedef struct { - bool_t valid; /**< From OD parameter 1300 */ + bool_t valid; /**< From OD parameter 1300 */ OD_extension_t OD_gfcParam_ext; /**< Extension for OD object */ -#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_PRODUCER) != 0) || defined CO_DOXYGEN CO_CANmodule_t* CANdevTx; /**< From CO_GFC_init() */ CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ #endif -#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) != 0) || defined CO_DOXYGEN /** From CO_GFC_initCallbackEnterSafeState() or NULL */ void (*pFunctSignalSafe)(void* object); /** From CO_GFC_initCallbackEnterSafeState() or NULL */ @@ -84,11 +84,11 @@ typedef struct { * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, - CO_CANmodule_t* GFC_CANdevRx, uint16_t GFC_rxIdx, uint16_t CANidRxGFC, - CO_CANmodule_t* GFC_CANdevTx, uint16_t GFC_txIdx, uint16_t CANidTxGFC); +CO_ReturnError_t CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO_CANmodule_t* GFC_CANdevRx, + uint16_t GFC_rxIdx, uint16_t CANidRxGFC, CO_CANmodule_t* GFC_CANdevTx, uint16_t GFC_txIdx, + uint16_t CANidTxGFC); -#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_CONSUMER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) != 0) || defined CO_DOXYGEN /** * Initialize GFC callback function. * @@ -103,7 +103,7 @@ CO_ReturnError_t CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, void CO_GFC_initCallbackEnterSafeState(CO_GFC_t* GFC, void* object, void (*pFunctSignalSafe)(void* object)); #endif -#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_PRODUCER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_PRODUCER) != 0) || defined CO_DOXYGEN /** * Send GFC message. * diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 9625e22f..82de4553 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -34,7 +34,7 @@ #define CO_CONFIG_SRDO_MINIMUM_DELAY 0U #endif -#if (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -92,19 +92,20 @@ typedef uint8_t CO_SRDO_size_t; * SRDO internal state */ typedef enum { - CO_SRDO_state_error_internal = -10, /**< internal software error */ + CO_SRDO_state_error_internal = -10, /**< internal software error */ CO_SRDO_state_error_configuration = -9, /**< error in parameters, emergency message was sent */ CO_SRDO_state_error_txNotInverted = -6, /**< Transmitting SRDO messages was not inverted */ - CO_SRDO_state_error_txFail = -5, /**< SRDO CAN message transmission failed */ + CO_SRDO_state_error_txFail = -5, /**< SRDO CAN message transmission failed */ CO_SRDO_state_error_rxTimeoutSRVT = -4, /**< SRDO message didn't receive inside SRVT time */ - CO_SRDO_state_error_rxTimeoutSCT = -3, /**< SRDO inverted message didn't receive inside SCT time */ + CO_SRDO_state_error_rxTimeoutSCT = -3, /**< SRDO inverted message didn't receive inside SCT time */ CO_SRDO_state_error_rxNotInverted = -2, /**< Received SRDO messages was not inverted */ - CO_SRDO_state_error_rxShort = -1, /**< Received SRDO message is too short */ - CO_SRDO_state_unknown = 0, /**< unknown state, set by @CO_SRDO_init */ - CO_SRDO_state_nmtNotOperational = 1, /**< Internal NMT operating state is not NMT operational */ - CO_SRDO_state_initializing = 2, /**< Just entered NMT operational state, SRDO message not yet received or transmitted */ + CO_SRDO_state_error_rxShort = -1, /**< Received SRDO message is too short */ + CO_SRDO_state_unknown = 0, /**< unknown state, set by @CO_SRDO_init */ + CO_SRDO_state_nmtNotOperational = 1, /**< Internal NMT operating state is not NMT operational */ + CO_SRDO_state_initializing = + 2, /**< Just entered NMT operational state, SRDO message not yet received or transmitted */ CO_SRDO_state_communicationEstablished = 3, /**< SRDO communication established, fully functional */ - CO_SRDO_state_deleted = 10 /**< informationDirection for this SRDO is set to 0 */ + CO_SRDO_state_deleted = 10 /**< informationDirection for this SRDO is set to 0 */ } CO_SRDO_state_t; /** @@ -124,10 +125,10 @@ typedef struct { /** Object for input / output on the OD variable 13FE:00. Configuration * of any of the the SRDO parameters will write 0 to that variable. */ OD_IO_t OD_IO_configurationValid; - + OD_entry_t* OD_13FE_entry; OD_entry_t* OD_13FF_entry; - + /** Extension for OD object */ OD_extension_t OD_13FE_extension; /** Extension for OD object */ @@ -138,15 +139,15 @@ typedef struct { * SRDO object. */ typedef struct { - CO_SRDOGuard_t* SRDOGuard; /**< From CO_SRDO_init() */ - OD_t *OD; /**< From CO_SRDO_init() */ - CO_EM_t* em; /**< From CO_SRDO_init() */ - uint16_t defaultCOB_ID; /**< From CO_SRDO_init() */ - uint8_t nodeId; /**< From CO_SRDO_init() */ - CO_CANmodule_t* CANdevTx[2]; /**< From CO_SRDO_init() */ - uint16_t CANdevTxIdx[2]; /**< From CO_SRDO_init() */ - CO_CANmodule_t* CANdevRx[2]; /**< From CO_SRDO_init() */ - uint16_t CANdevRxIdx[2]; /**< From CO_SRDO_init() */ + CO_SRDOGuard_t* SRDOGuard; /**< From CO_SRDO_init() */ + OD_t* OD; /**< From CO_SRDO_init() */ + CO_EM_t* em; /**< From CO_SRDO_init() */ + uint16_t defaultCOB_ID; /**< From CO_SRDO_init() */ + uint8_t nodeId; /**< From CO_SRDO_init() */ + CO_CANmodule_t* CANdevTx[2]; /**< From CO_SRDO_init() */ + uint16_t CANdevTxIdx[2]; /**< From CO_SRDO_init() */ + CO_CANmodule_t* CANdevRx[2]; /**< From CO_SRDO_init() */ + uint16_t CANdevRxIdx[2]; /**< From CO_SRDO_init() */ /** Internal state of this SRDO. */ CO_SRDO_state_t internalState; /** Copy of variable, internal usage. */ @@ -185,14 +186,14 @@ typedef struct { /** If true, next processed SRDO message is normal (not inverted) */ bool_t nextIsNormal; - OD_entry_t* OD_communicationParam_entry;/**< From CO_SRDO_init() */ - OD_entry_t* OD_mappingParam_entry;/**< From CO_SRDO_init() */ + OD_entry_t* OD_communicationParam_entry; /**< From CO_SRDO_init() */ + OD_entry_t* OD_mappingParam_entry; /**< From CO_SRDO_init() */ /** Extension for OD object */ OD_extension_t OD_communicationParam_ext; /** Extension for OD object */ OD_extension_t OD_mappingParam_extension; -#if (((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** From CO_SRDO_initCallbackPre() or NULL */ void (*pFunctSignalPre)(void* object); /** From CO_SRDO_initCallbackPre() or NULL */ @@ -215,8 +216,7 @@ typedef struct { * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ CO_ReturnError_t CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13FE_configurationValid, - OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo); - + OD_entry_t* OD_13FF_safetyConfigurationSignature, uint32_t* errInfo); /** * Initialize SRDO object. @@ -251,11 +251,12 @@ CO_ReturnError_t CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13F CO_ReturnError_t CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, OD_t* OD, CO_EM_t* em, uint8_t nodeId, uint16_t defaultCOB_ID, OD_entry_t* OD_130x_SRDOCommPar, OD_entry_t* OD_138x_SRDOMapPar, CO_CANmodule_t* CANdevRxNormal, - CO_CANmodule_t* CANdevRxInverted, uint16_t CANdevRxIdxNormal, uint16_t CANdevRxIdxInverted, - CO_CANmodule_t* CANdevTxNormal, CO_CANmodule_t* CANdevTxInverted, - uint16_t CANdevTxIdxNormal, uint16_t CANdevTxIdxInverted, uint32_t* errInfo); + CO_CANmodule_t* CANdevRxInverted, uint16_t CANdevRxIdxNormal, + uint16_t CANdevRxIdxInverted, CO_CANmodule_t* CANdevTxNormal, + CO_CANmodule_t* CANdevTxInverted, uint16_t CANdevTxIdxNormal, + uint16_t CANdevTxIdxInverted, uint32_t* errInfo); -#if (((CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize SRDO callback function. * @@ -282,8 +283,7 @@ void CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalP */ CO_ReturnError_t CO_SRDO_requestSend(CO_SRDO_t* SRDO); - -CO_ReturnError_t CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, uint32_t* errInfo); +CO_ReturnError_t CO_SRDO_config(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, uint32_t* errInfo); /** * Process transmitting/receiving individual SRDO message. @@ -295,7 +295,8 @@ CO_ReturnError_t CO_SRDO_config( CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGua * * @return CO_SRDO_state_t internal state */ -CO_SRDO_state_t CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext_us, bool_t NMTisOperational); +CO_SRDO_state_t CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext_us, + bool_t NMTisOperational); /** @} */ /* CO_SRDO */ diff --git a/305/CO_LSS.h b/305/CO_LSS.h index 02736399..4f630520 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -26,8 +26,7 @@ /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_LSS -#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \ - CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) +#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE) #endif #if (((CO_CONFIG_LSS) & (CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER)) != 0) || defined CO_DOXYGEN @@ -79,71 +78,72 @@ extern "C" { * * As identifying method only "LSS fastscan" is supported. */ -#define CO_LSS_SWITCH_STATE_GLOBAL 0x04U /**< Switch state global protocol */ -#define CO_LSS_SWITCH_STATE_SEL_VENDOR 0x40U /**< Switch state selective protocol - Vendor ID */ -#define CO_LSS_SWITCH_STATE_SEL_PRODUCT 0x41U /**< Switch state selective protocol - Product code */ -#define CO_LSS_SWITCH_STATE_SEL_REV 0x42U /**< Switch state selective protocol - Revision number */ -#define CO_LSS_SWITCH_STATE_SEL_SERIAL 0x43U /**< Switch state selective protocol - Serial number */ -#define CO_LSS_SWITCH_STATE_SEL 0x44U /**< Switch state selective protocol - Slave response */ -#define CO_LSS_CFG_NODE_ID 0x11U /**< Configure node ID protocol */ -#define CO_LSS_CFG_BIT_TIMING 0x13U /**< Configure bit timing parameter protocol */ -#define CO_LSS_CFG_ACTIVATE_BIT_TIMING 0x15U /**< Activate bit timing parameter protocol */ -#define CO_LSS_CFG_STORE 0x17U /**< Store configuration protocol */ -#define CO_LSS_IDENT_SLAVE 0x4FU /**< LSS Fastscan response */ -#define CO_LSS_IDENT_FASTSCAN 0x51U /**< LSS Fastscan protocol */ -#define CO_LSS_INQUIRE_VENDOR 0x5AU /**< Inquire identity vendor-ID protocol */ -#define CO_LSS_INQUIRE_PRODUCT 0x5BU /**< Inquire identity product-code protocol */ -#define CO_LSS_INQUIRE_REV 0x5CU /**< Inquire identity revision-number protocol */ -#define CO_LSS_INQUIRE_SERIAL 0x5DU /**< Inquire identity serial-number protocol */ -#define CO_LSS_INQUIRE_NODE_ID 0x5EU /**< Inquire node-ID protocol */ -/** @} */ /* CO_LSS_cs_t */ +#define CO_LSS_SWITCH_STATE_GLOBAL 0x04U /**< Switch state global protocol */ +#define CO_LSS_SWITCH_STATE_SEL_VENDOR 0x40U /**< Switch state selective protocol - Vendor ID */ +#define CO_LSS_SWITCH_STATE_SEL_PRODUCT 0x41U /**< Switch state selective protocol - Product code */ +#define CO_LSS_SWITCH_STATE_SEL_REV 0x42U /**< Switch state selective protocol - Revision number */ +#define CO_LSS_SWITCH_STATE_SEL_SERIAL 0x43U /**< Switch state selective protocol - Serial number */ +#define CO_LSS_SWITCH_STATE_SEL 0x44U /**< Switch state selective protocol - Slave response */ +#define CO_LSS_CFG_NODE_ID 0x11U /**< Configure node ID protocol */ +#define CO_LSS_CFG_BIT_TIMING 0x13U /**< Configure bit timing parameter protocol */ +#define CO_LSS_CFG_ACTIVATE_BIT_TIMING 0x15U /**< Activate bit timing parameter protocol */ +#define CO_LSS_CFG_STORE 0x17U /**< Store configuration protocol */ +#define CO_LSS_IDENT_SLAVE 0x4FU /**< LSS Fastscan response */ +#define CO_LSS_IDENT_FASTSCAN 0x51U /**< LSS Fastscan protocol */ +#define CO_LSS_INQUIRE_VENDOR 0x5AU /**< Inquire identity vendor-ID protocol */ +#define CO_LSS_INQUIRE_PRODUCT 0x5BU /**< Inquire identity product-code protocol */ +#define CO_LSS_INQUIRE_REV 0x5CU /**< Inquire identity revision-number protocol */ +#define CO_LSS_INQUIRE_SERIAL 0x5DU /**< Inquire identity serial-number protocol */ +#define CO_LSS_INQUIRE_NODE_ID 0x5EU /**< Inquire node-ID protocol */ +/** @} */ /* CO_LSS_cs_t */ /** * @defgroup CO_LSS_cfgNodeId_t Error codes for Configure node ID protocol * @{ */ -#define CO_LSS_CFG_NODE_ID_OK 0x00U /**< Protocol successfully completed */ -#define CO_LSS_CFG_NODE_ID_OUT_OF_RANGE 0x01U /**< NID out of range */ -#define CO_LSS_CFG_NODE_ID_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ -/** @} */ /* CO_LSS_cfgNodeId_t */ +#define CO_LSS_CFG_NODE_ID_OK 0x00U /**< Protocol successfully completed */ +#define CO_LSS_CFG_NODE_ID_OUT_OF_RANGE 0x01U /**< NID out of range */ +#define CO_LSS_CFG_NODE_ID_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ +/** @} */ /* CO_LSS_cfgNodeId_t */ /** * @defgroup CO_LSS_cfgBitTiming_t Error codes for Configure bit timing parameters protocol * @{ */ -#define CO_LSS_CFG_BIT_TIMING_OK 0x00U /**< Protocol successfully completed */ -#define CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE 0x01U /**< Bit timing / Bit rate not supported */ -#define CO_LSS_CFG_BIT_TIMING_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ -/** @} */ /* CO_LSS_cfgBitTiming_t */ +#define CO_LSS_CFG_BIT_TIMING_OK 0x00U /**< Protocol successfully completed */ +#define CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE 0x01U /**< Bit timing / Bit rate not supported */ +#define CO_LSS_CFG_BIT_TIMING_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ +/** @} */ /* CO_LSS_cfgBitTiming_t */ /** * @defgroup CO_LSS_cfgStore_t Error codes for Store configuration protocol * @{ */ -#define CO_LSS_CFG_STORE_OK 0x00U /**< Protocol successfully completed */ -#define CO_LSS_CFG_STORE_NOT_SUPPORTED 0x01U /**< Store configuration not supported */ -#define CO_LSS_CFG_STORE_FAILED 0x02U /**< Storage media access error */ -#define CO_LSS_CFG_STORE_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ -/** @} */ /* CO_LSS_cfgStore_t */ +#define CO_LSS_CFG_STORE_OK 0x00U /**< Protocol successfully completed */ +#define CO_LSS_CFG_STORE_NOT_SUPPORTED 0x01U /**< Store configuration not supported */ +#define CO_LSS_CFG_STORE_FAILED 0x02U /**< Storage media access error */ +#define CO_LSS_CFG_STORE_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ +/** @} */ /* CO_LSS_cfgStore_t */ /** * @defgroup CO_LSS_fastscan_bitcheck Fastscan BitCheck. BIT0 means all bits are checked for equality by slave * @{ */ -#define CO_LSS_FASTSCAN_BIT0 0x00U /**< Least significant bit of IDnumbners bit area to be checked */ - /* ... */ -#define CO_LSS_FASTSCAN_BIT31 0x1FU /**< dito */ -#define CO_LSS_FASTSCAN_CONFIRM 0x80U /**< All LSS slaves waiting for scan respond and previous scan is reset */ -/** @} */ /* CO_LSS_fastscan_bitcheck */ +#define CO_LSS_FASTSCAN_BIT0 0x00U /**< Least significant bit of IDnumbners bit area to be checked */ +/* ... */ +#define CO_LSS_FASTSCAN_BIT31 0x1FU /**< dito */ +#define CO_LSS_FASTSCAN_CONFIRM 0x80U /**< All LSS slaves waiting for scan respond and previous scan is reset */ +/** @} */ /* CO_LSS_fastscan_bitcheck */ /** * @defgroup CO_LSS_fastscan_lss_sub_next Fastscan LSSsub, LSSnext * @{ */ -#define CO_LSS_FASTSCAN_VENDOR_ID 0x00U /**< Vendor ID */ -#define CO_LSS_FASTSCAN_PRODUCT 0x01U /**< Product code */ -#define CO_LSS_FASTSCAN_REV 0x02U /**< Revision number */ -#define CO_LSS_FASTSCAN_SERIAL 0x03U /**< Serial number */ +#define CO_LSS_FASTSCAN_VENDOR_ID 0x00U /**< Vendor ID */ +#define CO_LSS_FASTSCAN_PRODUCT 0x01U /**< Product code */ +#define CO_LSS_FASTSCAN_REV 0x02U /**< Revision number */ +#define CO_LSS_FASTSCAN_SERIAL 0x03U /**< Serial number */ + /** @} */ /* CO_LSS_fastscan_lss_sub_next */ /** @@ -152,6 +152,7 @@ extern "C" { */ typedef union { uint32_t addr[4]; + struct { uint32_t vendorID; uint32_t productCode; @@ -170,42 +171,31 @@ typedef union { * - LSS configuration: In this state variables may be configured in the LSS slave. * - Final: Pseudo state, indicating the deactivation of the FSA. */ -#define CO_LSS_STATE_WAITING 0x00U /**< LSS FSA waiting for requests*/ -#define CO_LSS_STATE_CONFIGURATION 0x01U /**< LSS FSA waiting for configuration*/ -/** @} */ /* CO_LSS_state_t */ +#define CO_LSS_STATE_WAITING 0x00U /**< LSS FSA waiting for requests*/ +#define CO_LSS_STATE_CONFIGURATION 0x01U /**< LSS FSA waiting for configuration*/ +/** @} */ /* CO_LSS_state_t */ /** * @defgroup CO_LSS_bitTimingTable_t Definition of table_index for /CiA301/ bit timing table * @{ */ -#define CO_LSS_BIT_TIMING_1000 0U /**< 1000kbit/s */ -#define CO_LSS_BIT_TIMING_800 1U /**< 800kbit/s */ -#define CO_LSS_BIT_TIMING_500 2U /**< 500kbit/s */ -#define CO_LSS_BIT_TIMING_250 3U /**< 250kbit/s */ -#define CO_LSS_BIT_TIMING_125 4U /**< 125kbit/s */ - /* reserved 5U */ -#define CO_LSS_BIT_TIMING_50 6U /**< 50kbit/s */ -#define CO_LSS_BIT_TIMING_20 7U /**< 20kbit/s */ -#define CO_LSS_BIT_TIMING_10 8U /**< 10kbit/s */ -#define CO_LSS_BIT_TIMING_AUTO 9U /**< Automatic bit rate detection */ -/** @} */ /* CO_LSS_bitTimingTable_t */ +#define CO_LSS_BIT_TIMING_1000 0U /**< 1000kbit/s */ +#define CO_LSS_BIT_TIMING_800 1U /**< 800kbit/s */ +#define CO_LSS_BIT_TIMING_500 2U /**< 500kbit/s */ +#define CO_LSS_BIT_TIMING_250 3U /**< 250kbit/s */ +#define CO_LSS_BIT_TIMING_125 4U /**< 125kbit/s */ + /* reserved 5U */ +#define CO_LSS_BIT_TIMING_50 6U /**< 50kbit/s */ +#define CO_LSS_BIT_TIMING_20 7U /**< 20kbit/s */ +#define CO_LSS_BIT_TIMING_10 8U /**< 10kbit/s */ +#define CO_LSS_BIT_TIMING_AUTO 9U /**< Automatic bit rate detection */ +/** @} */ /* CO_LSS_bitTimingTable_t */ /** * Lookup table for conversion between bit timing table and numerical * bit rate */ -static const uint16_t CO_LSS_bitTimingTableLookup[] = { - 1000, - 800, - 500, - 250, - 125, - 0, - 50, - 20, - 10, - 0 -}; +static const uint16_t CO_LSS_bitTimingTableLookup[] = {1000, 800, 500, 250, 125, 0, 50, 20, 10, 0}; /** * Invalid node ID triggers node ID assignment @@ -220,11 +210,10 @@ static const uint16_t CO_LSS_bitTimingTableLookup[] = { /** * Macro to check if two LSS addresses are equal */ -#define CO_LSS_ADDRESS_EQUAL(/*CO_LSS_address_t*/ a1, /*CO_LSS_address_t*/ a2) \ - ((a1.identity.productCode == a2.identity.productCode) && \ - (a1.identity.revisionNumber == a2.identity.revisionNumber) && \ - (a1.identity.serialNumber == a2.identity.serialNumber) && \ - (a1.identity.vendorID == a2.identity.vendorID)) +#define CO_LSS_ADDRESS_EQUAL(/*CO_LSS_address_t*/ a1, /*CO_LSS_address_t*/ a2) \ + ((a1.identity.productCode == a2.identity.productCode) \ + && (a1.identity.revisionNumber == a2.identity.revisionNumber) \ + && (a1.identity.serialNumber == a2.identity.serialNumber) && (a1.identity.vendorID == a2.identity.vendorID)) /** @} */ /*@defgroup CO_LSS*/ diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 437ea97d..39c84792 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -24,7 +24,7 @@ #include "305/CO_LSS.h" -#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -82,44 +82,43 @@ extern "C" { * Return values of LSS master functions. */ typedef enum { - CO_LSSmaster_SCAN_FINISHED = 2, /**< Scanning finished successful */ - CO_LSSmaster_WAIT_SLAVE = 1, /**< No response arrived from slave yet */ - CO_LSSmaster_OK = 0, /**< Success, end of communication */ - CO_LSSmaster_TIMEOUT = -1, /**< No reply received */ - CO_LSSmaster_ILLEGAL_ARGUMENT = -2, /**< Invalid argument */ - CO_LSSmaster_INVALID_STATE = -3, /**< State machine not ready or already processing a request */ - CO_LSSmaster_SCAN_NOACK = -4, /**< No node found that matches scan request */ - CO_LSSmaster_SCAN_FAILED = -5, /**< An error occurred while scanning. Try again */ + CO_LSSmaster_SCAN_FINISHED = 2, /**< Scanning finished successful */ + CO_LSSmaster_WAIT_SLAVE = 1, /**< No response arrived from slave yet */ + CO_LSSmaster_OK = 0, /**< Success, end of communication */ + CO_LSSmaster_TIMEOUT = -1, /**< No reply received */ + CO_LSSmaster_ILLEGAL_ARGUMENT = -2, /**< Invalid argument */ + CO_LSSmaster_INVALID_STATE = -3, /**< State machine not ready or already processing a request */ + CO_LSSmaster_SCAN_NOACK = -4, /**< No node found that matches scan request */ + CO_LSSmaster_SCAN_FAILED = -5, /**< An error occurred while scanning. Try again */ CO_LSSmaster_OK_ILLEGAL_ARGUMENT = -101, /**< LSS success, node rejected argument because of non-supported value */ - CO_LSSmaster_OK_MANUFACTURER = -102, /**< LSS success, node rejected argument with manufacturer error code */ + CO_LSSmaster_OK_MANUFACTURER = -102, /**< LSS success, node rejected argument with manufacturer error code */ } CO_LSSmaster_return_t; - /** * LSS master object. */ -typedef struct{ - uint32_t timeout_us; /**< LSS response timeout in us */ - - uint8_t state; /**< Node is currently selected */ - uint8_t command; /**< Active command */ - uint32_t timeoutTimer; /**< Timeout timer for LSS communication */ - - uint8_t fsState; /**< Current state of fastscan master state machine */ - uint8_t fsLssSub; /**< Current state of node state machine */ - uint8_t fsBitChecked; /**< Current scan bit position */ - uint32_t fsIdNumber; /**< Current scan result */ - - volatile void *CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */ - uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ -#if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - void (*pFunctSignal)(void *object); /**< From CO_LSSmaster_initCallbackPre() or NULL */ - void *functSignalObject;/**< Pointer to object */ +typedef struct { + uint32_t timeout_us; /**< LSS response timeout in us */ + + uint8_t state; /**< Node is currently selected */ + uint8_t command; /**< Active command */ + uint32_t timeoutTimer; /**< Timeout timer for LSS communication */ + + uint8_t fsState; /**< Current state of fastscan master state machine */ + uint8_t fsLssSub; /**< Current state of node state machine */ + uint8_t fsBitChecked; /**< Current scan bit position */ + uint32_t fsIdNumber; /**< Current scan result */ + + volatile void* + CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */ + uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ +#if (((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN + void (*pFunctSignal)(void* object); /**< From CO_LSSmaster_initCallbackPre() or NULL */ + void* functSignalObject; /**< Pointer to object */ #endif - CO_CANmodule_t *CANdevTx; /**< From CO_LSSmaster_init() */ - CO_CANtx_t *TXbuff; /**< CAN transmit buffer */ -}CO_LSSmaster_t; - + CO_CANmodule_t* CANdevTx; /**< From CO_LSSmaster_init() */ + CO_CANtx_t* TXbuff; /**< CAN transmit buffer */ +} CO_LSSmaster_t; /** * Default timeout for LSS slave in ms. This is the same as for SDO. For more @@ -129,7 +128,6 @@ typedef struct{ #define CO_LSSmaster_DEFAULT_TIMEOUT 1000U /* ms */ #endif - /** * Initialize LSS object. * @@ -146,15 +144,9 @@ typedef struct{ * @param CANidLssMaster COB ID for transmission. * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_LSSmaster_init( - CO_LSSmaster_t *LSSmaster, - uint16_t timeout_ms, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - uint16_t CANidLssSlave, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint16_t CANidLssMaster); +CO_ReturnError_t CO_LSSmaster_init(CO_LSSmaster_t* LSSmaster, uint16_t timeout_ms, CO_CANmodule_t* CANdevRx, + uint16_t CANdevRxIdx, uint16_t CANidLssSlave, CO_CANmodule_t* CANdevTx, + uint16_t CANdevTxIdx, uint16_t CANidLssMaster); /** * Change LSS master timeout @@ -175,12 +167,9 @@ CO_ReturnError_t CO_LSSmaster_init( * @param LSSmaster This object. * @param timeout_ms timeout value in ms */ -void CO_LSSmaster_changeTimeout( - CO_LSSmaster_t *LSSmaster, - uint16_t timeout_ms); - +void CO_LSSmaster_changeTimeout(CO_LSSmaster_t* LSSmaster, uint16_t timeout_ms); -#if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize LSSmasterRx callback function. * @@ -193,13 +182,9 @@ void CO_LSSmaster_changeTimeout( * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ -void CO_LSSmaster_initCallbackPre( - CO_LSSmaster_t *LSSmaster, - void *object, - void (*pFunctSignal)(void *object)); +void CO_LSSmaster_initCallbackPre(CO_LSSmaster_t* LSSmaster, void* object, void (*pFunctSignal)(void* object)); #endif - /** * Request LSS switch state select * @@ -217,11 +202,8 @@ void CO_LSSmaster_initCallbackPre( * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ -CO_LSSmaster_return_t CO_LSSmaster_swStateSelect( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSS_address_t *lssAddress); - +CO_LSSmaster_return_t CO_LSSmaster_swStateSelect(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, + CO_LSS_address_t* lssAddress); /** * Request LSS switch state deselect @@ -235,9 +217,7 @@ CO_LSSmaster_return_t CO_LSSmaster_swStateSelect( * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_OK */ -CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect( - CO_LSSmaster_t *LSSmaster); - +CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect(CO_LSSmaster_t* LSSmaster); /** * Request LSS configure Bit Timing @@ -257,11 +237,8 @@ CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect( * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT, * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT */ -CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - uint16_t bit); - +CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, + uint16_t bit); /** * Request LSS configure node ID @@ -282,11 +259,8 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming( * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT, * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT */ -CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - uint8_t nodeId); - +CO_LSSmaster_return_t CO_LSSmaster_configureNodeId(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, + uint8_t nodeId); /** * Request LSS store configuration @@ -306,10 +280,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId( * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT, * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT */ -CO_LSSmaster_return_t CO_LSSmaster_configureStore( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us); - +CO_LSSmaster_return_t CO_LSSmaster_configureStore(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us); /** * Request LSS activate bit timing @@ -330,10 +301,7 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore( * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_OK */ -CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( - CO_LSSmaster_t *LSSmaster, - uint16_t switchDelay_ms); - +CO_LSSmaster_return_t CO_LSSmaster_ActivateBit(CO_LSSmaster_t* LSSmaster, uint16_t switchDelay_ms); /** * Request LSS inquire LSS address @@ -353,11 +321,8 @@ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit( * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ -CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSS_address_t *lssAddress); - +CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, + CO_LSS_address_t* lssAddress); /** * Request LSS inquire node ID or part of LSS address @@ -378,29 +343,25 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress( * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT */ -CO_LSSmaster_return_t CO_LSSmaster_Inquire( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - uint8_t lssInquireCs, - uint32_t *value); - +CO_LSSmaster_return_t CO_LSSmaster_Inquire(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint8_t lssInquireCs, + uint32_t* value); /** * Scan type for #CO_LSSmaster_fastscan_t scan */ typedef enum { - CO_LSSmaster_FS_SCAN = 0, /**< Do full 32 bit scan */ - CO_LSSmaster_FS_SKIP = 1, /**< Skip this value */ - CO_LSSmaster_FS_MATCH = 2, /**< Full 32 bit value is given as argument, just verify */ + CO_LSSmaster_FS_SCAN = 0, /**< Do full 32 bit scan */ + CO_LSSmaster_FS_SKIP = 1, /**< Skip this value */ + CO_LSSmaster_FS_MATCH = 2, /**< Full 32 bit value is given as argument, just verify */ } CO_LSSmaster_scantype_t; /** * Parameters for LSS fastscan #CO_LSSmaster_IdentifyFastscan */ -typedef struct{ - CO_LSSmaster_scantype_t scan[4]; /**< Scan type for each part of the LSS address */ - CO_LSS_address_t match; /**< Value to match in case of #CO_LSSmaster_FS_MATCH */ - CO_LSS_address_t found; /**< Scan result */ +typedef struct { + CO_LSSmaster_scantype_t scan[4]; /**< Scan type for each part of the LSS address */ + CO_LSS_address_t match; /**< Value to match in case of #CO_LSSmaster_FS_MATCH */ + CO_LSS_address_t found; /**< Scan result */ } CO_LSSmaster_fastscan_t; /** @@ -457,10 +418,8 @@ fastscan.scan[CO_LSS_FASTSCAN_SERIAL] = CO_LSSmaster_FS_SCAN; * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_SCAN_FINISHED, #CO_LSSmaster_SCAN_NOACK, * #CO_LSSmaster_SCAN_FAILED */ -CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan( - CO_LSSmaster_t *LSSmaster, - uint32_t timeDifference_us, - CO_LSSmaster_fastscan_t *fastscan); +CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, + CO_LSSmaster_fastscan_t* fastscan); /** @} */ /*@defgroup CO_LSSmaster*/ diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index e56ba443..26afea49 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -25,7 +25,7 @@ #include "305/CO_LSS.h" -#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -81,36 +81,40 @@ extern "C" { /** * LSS slave object. */ -typedef struct{ - CO_LSS_address_t lssAddress; /**< From #CO_LSSslave_init */ - uint8_t lssState; /**< #CO_LSS_state_t */ - CO_LSS_address_t lssSelect; /**< Received LSS Address by select */ +typedef struct { + CO_LSS_address_t lssAddress; /**< From #CO_LSSslave_init */ + uint8_t lssState; /**< #CO_LSS_state_t */ + CO_LSS_address_t lssSelect; /**< Received LSS Address by select */ - CO_LSS_address_t lssFastscan; /**< Received LSS Address by fastscan */ - uint8_t fastscanPos; /**< Current state of fastscan */ + CO_LSS_address_t lssFastscan; /**< Received LSS Address by fastscan */ + uint8_t fastscanPos; /**< Current state of fastscan */ - uint16_t *pendingBitRate; /**< Bit rate value that is temporarily configured */ - uint8_t *pendingNodeID; /**< Node ID that is temporarily configured */ - uint8_t activeNodeID; /**< Node ID used at the CAN interface */ + uint16_t* pendingBitRate; /**< Bit rate value that is temporarily configured */ + uint8_t* pendingNodeID; /**< Node ID that is temporarily configured */ + uint8_t activeNodeID; /**< Node ID used at the CAN interface */ - volatile void *sendResponse; /**< Variable indicates, if LSS response has to be sent by mainline processing function */ - uint8_t service; /**< Service, which will have to be processed by mainline processing function */ - uint8_t CANdata[8]; /**< Received CAN data, which will be processed by mainline processing function */ + volatile void* + sendResponse; /**< Variable indicates, if LSS response has to be sent by mainline processing function */ + uint8_t service; /**< Service, which will have to be processed by mainline processing function */ + uint8_t CANdata[8]; /**< Received CAN data, which will be processed by mainline processing function */ -#if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - void (*pFunctSignalPre)(void *object); /**< From CO_LSSslave_initCallbackPre() or NULL */ - void *functSignalObjectPre;/**< Pointer to object */ +#if (((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN + void (*pFunctSignalPre)(void* object); /**< From CO_LSSslave_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< Pointer to object */ #endif - bool_t (*pFunctLSScheckBitRate)(void *object, uint16_t bitRate); /**< From CO_LSSslave_initCkBitRateCall() or NULL */ - void *functLSScheckBitRateObject; /** Pointer to object */ - void (*pFunctLSSactivateBitRate)(void *object, uint16_t delay); /**< From CO_LSSslave_initActBitRateCall() or NULL. Delay is in ms */ - void *functLSSactivateBitRateObject; /** Pointer to object */ - bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate); /**< From CO_LSSslave_initCfgStoreCall() or NULL */ - void *functLSScfgStoreObject; /** Pointer to object */ + bool_t (*pFunctLSScheckBitRate)(void* object, + uint16_t bitRate); /**< From CO_LSSslave_initCkBitRateCall() or NULL */ + void* functLSScheckBitRateObject; /** Pointer to object */ + void (*pFunctLSSactivateBitRate)( + void* object, uint16_t delay); /**< From CO_LSSslave_initActBitRateCall() or NULL. Delay is in ms */ + void* functLSSactivateBitRateObject; /** Pointer to object */ + bool_t (*pFunctLSScfgStore)(void* object, uint8_t id, + uint16_t bitRate); /**< From CO_LSSslave_initCfgStoreCall() or NULL */ + void* functLSScfgStoreObject; /** Pointer to object */ - CO_CANmodule_t *CANdevTx; /**< From #CO_LSSslave_init() */ - CO_CANtx_t *TXbuff; /**< CAN transmit buffer */ -}CO_LSSslave_t; + CO_CANmodule_t* CANdevTx; /**< From #CO_LSSslave_init() */ + CO_CANtx_t* TXbuff; /**< CAN transmit buffer */ +} CO_LSSslave_t; /** * Initialize LSS object. @@ -151,17 +155,10 @@ typedef struct{ * @param CANidLssSlave COB ID for transmission. * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_LSSslave_init( - CO_LSSslave_t *LSSslave, - CO_LSS_address_t *lssAddress, - uint16_t *pendingBitRate, - uint8_t *pendingNodeID, - CO_CANmodule_t *CANdevRx, - uint16_t CANdevRxIdx, - uint16_t CANidLssMaster, - CO_CANmodule_t *CANdevTx, - uint16_t CANdevTxIdx, - uint16_t CANidLssSlave); +CO_ReturnError_t CO_LSSslave_init(CO_LSSslave_t* LSSslave, CO_LSS_address_t* lssAddress, uint16_t* pendingBitRate, + uint8_t* pendingNodeID, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, + uint16_t CANidLssMaster, CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, + uint16_t CANidLssSlave); /** * Process LSS communication @@ -176,7 +173,7 @@ CO_ReturnError_t CO_LSSslave_init( * @param LSSslave This object. * @return True, if #CO_NMT_RESET_COMMUNICATION is requested */ -bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave); +bool_t CO_LSSslave_process(CO_LSSslave_t* LSSslave); /** * Get current LSS state @@ -184,12 +181,12 @@ bool_t CO_LSSslave_process(CO_LSSslave_t *LSSslave); * @param LSSslave This object. * @return #CO_LSS_state_t */ -static inline uint8_t CO_LSSslave_getState(CO_LSSslave_t *LSSslave) { +static inline uint8_t +CO_LSSslave_getState(CO_LSSslave_t* LSSslave) { return (LSSslave == NULL) ? CO_LSS_STATE_WAITING : LSSslave->lssState; } - -#if (((CO_CONFIG_LSS) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize LSSslaveRx callback function. * @@ -202,13 +199,9 @@ static inline uint8_t CO_LSSslave_getState(CO_LSSslave_t *LSSslave) { * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ -void CO_LSSslave_initCallbackPre( - CO_LSSslave_t *LSSslave, - void *object, - void (*pFunctSignalPre)(void *object)); +void CO_LSSslave_initCallbackPre(CO_LSSslave_t* LSSslave, void* object, void (*pFunctSignalPre)(void* object)); #endif - /** * Initialize verify bit rate callback * @@ -222,10 +215,8 @@ void CO_LSSslave_initCallbackPre( * @param object Pointer to object, which will be passed to pFunctLSScheckBitRate(). Can be NULL * @param pFunctLSScheckBitRate Pointer to the callback function. Not called if NULL. */ -void CO_LSSslave_initCkBitRateCall( - CO_LSSslave_t *LSSslave, - void *object, - bool_t (*pFunctLSScheckBitRate)(void *object, uint16_t bitRate)); +void CO_LSSslave_initCkBitRateCall(CO_LSSslave_t* LSSslave, void* object, + bool_t (*pFunctLSScheckBitRate)(void* object, uint16_t bitRate)); /** * Initialize activate bit rate callback @@ -241,10 +232,8 @@ void CO_LSSslave_initCkBitRateCall( * @param object Pointer to object, which will be passed to pFunctLSSactivateBitRate(). Can be NULL * @param pFunctLSSactivateBitRate Pointer to the callback function. Not called if NULL. */ -void CO_LSSslave_initActBitRateCall( - CO_LSSslave_t *LSSslave, - void *object, - void (*pFunctLSSactivateBitRate)(void *object, uint16_t delay)); +void CO_LSSslave_initActBitRateCall(CO_LSSslave_t* LSSslave, void* object, + void (*pFunctLSSactivateBitRate)(void* object, uint16_t delay)); /** * Store configuration callback @@ -260,10 +249,8 @@ void CO_LSSslave_initActBitRateCall( * @param object Pointer to object, which will be passed to pFunctLSScfgStore(). Can be NULL * @param pFunctLSScfgStore Pointer to the callback function. Not called if NULL. */ -void CO_LSSslave_initCfgStoreCall( - CO_LSSslave_t *LSSslave, - void *object, - bool_t (*pFunctLSScfgStore)(void *object, uint8_t id, uint16_t bitRate)); +void CO_LSSslave_initCfgStoreCall(CO_LSSslave_t* LSSslave, void* object, + bool_t (*pFunctLSScfgStore)(void* object, uint8_t id, uint16_t bitRate)); /** @} */ /*@defgroup CO_LSSslave*/ diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 6e26260e..0aaa4592 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -34,7 +34,7 @@ #define CO_CONFIG_GTW (0) #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -140,84 +140,80 @@ lss_allnodes [ [ \\ * @} */ - /** Size of response string buffer. This is intermediate buffer. If there is * larger amount of data to transfer, then multiple transfers will occur. */ #ifndef CO_GTWA_RESP_BUF_SIZE #define CO_GTWA_RESP_BUF_SIZE 200U #endif - /** Timeout time in microseconds for some internal states. */ #ifndef CO_GTWA_STATE_TIMEOUT_TIME_US #define CO_GTWA_STATE_TIMEOUT_TIME_US 1200000U #endif - /** * Response error codes as specified by CiA 309-3. Values less or equal to 0 * are used for control for some functions and are not part of the standard. */ typedef enum { /** 0 - No error or idle */ - CO_GTWA_respErrorNone = 0, + CO_GTWA_respErrorNone = 0, /** 100 - Request not supported */ - CO_GTWA_respErrorReqNotSupported = 100, + CO_GTWA_respErrorReqNotSupported = 100, /** 101 - Syntax error */ - CO_GTWA_respErrorSyntax = 101, + CO_GTWA_respErrorSyntax = 101, /** 102 - Request not processed due to internal state */ - CO_GTWA_respErrorInternalState = 102, + CO_GTWA_respErrorInternalState = 102, /** 103 - Time-out (where applicable) */ - CO_GTWA_respErrorTimeOut = 103, + CO_GTWA_respErrorTimeOut = 103, /** 104 - No default net set */ - CO_GTWA_respErrorNoDefaultNetSet = 104, + CO_GTWA_respErrorNoDefaultNetSet = 104, /** 105 - No default node set */ - CO_GTWA_respErrorNoDefaultNodeSet = 105, + CO_GTWA_respErrorNoDefaultNodeSet = 105, /** 106 - Unsupported net */ - CO_GTWA_respErrorUnsupportedNet = 106, + CO_GTWA_respErrorUnsupportedNet = 106, /** 107 - Unsupported node */ - CO_GTWA_respErrorUnsupportedNode = 107, + CO_GTWA_respErrorUnsupportedNode = 107, /** 200 - Lost guarding message */ - CO_GTWA_respErrorLostGuardingMessage = 200, + CO_GTWA_respErrorLostGuardingMessage = 200, /** 201 - Lost connection */ - CO_GTWA_respErrorLostConnection = 201, + CO_GTWA_respErrorLostConnection = 201, /** 202 - Heartbeat started */ - CO_GTWA_respErrorHeartbeatStarted = 202, + CO_GTWA_respErrorHeartbeatStarted = 202, /** 203 - Heartbeat lost */ - CO_GTWA_respErrorHeartbeatLost = 203, + CO_GTWA_respErrorHeartbeatLost = 203, /** 204 - Wrong NMT state */ - CO_GTWA_respErrorWrongNMTstate = 204, + CO_GTWA_respErrorWrongNMTstate = 204, /** 205 - Boot-up */ - CO_GTWA_respErrorBootUp = 205, + CO_GTWA_respErrorBootUp = 205, /** 300 - Error passive */ - CO_GTWA_respErrorErrorPassive = 300, + CO_GTWA_respErrorErrorPassive = 300, /** 301 - Bus off */ - CO_GTWA_respErrorBusOff = 301, + CO_GTWA_respErrorBusOff = 301, /** 303 - CAN buffer overflow */ - CO_GTWA_respErrorCANbufferOverflow = 303, + CO_GTWA_respErrorCANbufferOverflow = 303, /** 304 - CAN init */ - CO_GTWA_respErrorCANinit = 304, + CO_GTWA_respErrorCANinit = 304, /** 305 - CAN active (at init or start-up) */ - CO_GTWA_respErrorCANactive = 305, + CO_GTWA_respErrorCANactive = 305, /** 400 - PDO already used */ - CO_GTWA_respErrorPDOalreadyUsed = 400, + CO_GTWA_respErrorPDOalreadyUsed = 400, /** 401 - PDO length exceeded */ - CO_GTWA_respErrorPDOlengthExceeded = 401, + CO_GTWA_respErrorPDOlengthExceeded = 401, /** 501 - LSS implementation- / manufacturer-specific error */ - CO_GTWA_respErrorLSSmanufacturer = 501, + CO_GTWA_respErrorLSSmanufacturer = 501, /** 502 - LSS node-ID not supported */ - CO_GTWA_respErrorLSSnodeIdNotSupported = 502, + CO_GTWA_respErrorLSSnodeIdNotSupported = 502, /** 503 - LSS bit-rate not supported */ - CO_GTWA_respErrorLSSbitRateNotSupported = 503, + CO_GTWA_respErrorLSSbitRateNotSupported = 503, /** 504 - LSS parameter storing failed */ - CO_GTWA_respErrorLSSparameterStoringFailed = 504, + CO_GTWA_respErrorLSSparameterStoringFailed = 504, /** 505 - LSS command failed because of media error */ - CO_GTWA_respErrorLSSmediaError = 505, + CO_GTWA_respErrorLSSmediaError = 505, /** 600 - Running out of memory */ - CO_GTWA_respErrorRunningOutOfMemory = 600 + CO_GTWA_respErrorRunningOutOfMemory = 600 } CO_GTWA_respErrorCode_t; - /** * Internal states of the Gateway-ascii state machine. */ @@ -257,8 +253,7 @@ typedef enum { CO_GTWA_ST_LED = 0x82U } CO_GTWA_state_t; - -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN /* * CANopen Gateway-ascii data types structure */ @@ -271,21 +266,15 @@ typedef struct { * writes them as corresponding ascii string. It is a pointer to * #CO_fifo_readU82a function or similar and is used with SDO upload. For * description of parameters see #CO_fifo_readU82a */ - size_t (*dataTypePrint)(CO_fifo_t *fifo, - char *buf, - size_t count, - bool_t end); + size_t (*dataTypePrint)(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Function, which reads ascii-data of specific data type from fifo buffer * and copies them to another fifo buffer as binary data. It is a pointer to * #CO_fifo_cpyTok2U8 function or similar and is used with SDO download. For * description of parameters see #CO_fifo_cpyTok2U8 */ - size_t (*dataTypeScan)(CO_fifo_t *dest, - CO_fifo_t *src, - uint8_t *status); + size_t (*dataTypeScan)(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); } CO_GTWA_dataType_t; #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */ - /** * CANopen Gateway-ascii object */ @@ -300,13 +289,10 @@ typedef struct { * * @return Count of bytes actually transferred. */ - size_t (*readCallback)(void *object, - const char *buf, - size_t count, - uint8_t *connectionOK); + size_t (*readCallback)(void* object, const char* buf, size_t count, uint8_t* connectionOK); /** Pointer to object, which will be used inside readCallback, from * CO_GTWA_init() */ - void *readCallbackObject; + void* readCallbackObject; /** Sequence number of the command */ uint32_t sequence; /** Default CANopen Net number is undefined (-1) at startup */ @@ -338,9 +324,9 @@ typedef struct { CO_GTWA_state_t state; /** Timeout timer for the current state */ uint32_t stateTimeoutTmr; -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN /** SDO client object from CO_GTWA_init() */ - CO_SDOclient_t *SDO_C; + CO_SDOclient_t* SDO_C; /** Timeout time for SDO transfer in milliseconds, if no response */ uint16_t SDOtimeoutTime; /** SDO block transfer enabled? */ @@ -350,15 +336,15 @@ typedef struct { * SDO buffer contains only part of data and more data will follow. */ bool_t SDOdataCopyStatus; /** Data type of variable in current SDO communication */ - const CO_GTWA_dataType_t *SDOdataType; + const CO_GTWA_dataType_t* SDOdataType; #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN /** NMT object from CO_GTWA_init() */ - CO_NMT_t *NMT; + CO_NMT_t* NMT; #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN /** LSSmaster object from CO_GTWA_init() */ - CO_LSSmaster_t *LSSmaster; + CO_LSSmaster_t* LSSmaster; /** 128 bit number, uniquely identifying each node */ CO_LSS_address_t lssAddress; /** LSS Node-ID parameter */ @@ -378,25 +364,24 @@ typedef struct { /** LSS allnodes timeout parameter */ uint16_t lssTimeout_ms; #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0) || defined CO_DOXYGEN /** Message log buffer of usable size @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */ uint8_t logBuf[CO_CONFIG_GTWA_LOG_BUF_SIZE + 1]; /** CO_fifo_t object for message log (not pointer) */ CO_fifo_t logFifo; #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0) || defined CO_DOXYGEN /** Offset, when printing help text */ - const char *helpString; + const char* helpString; size_t helpStringOffset; #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN /** CO_LEDs_t object for CANopen status LEDs imitation from CO_GTWA_init()*/ - CO_LEDs_t *LEDs; + CO_LEDs_t* LEDs; uint8_t ledStringPreviousIndex; #endif } CO_GTWA_t; - /** * Initialize Gateway-ascii object * @@ -412,23 +397,20 @@ typedef struct { * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT */ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN - CO_SDOclient_t* SDO_C, - uint16_t SDOclientTimeoutTime_ms, - bool_t SDOclientBlockTransfer, +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN + CO_SDOclient_t* SDO_C, uint16_t SDOclientTimeoutTime_ms, bool_t SDOclientBlockTransfer, #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN - CO_NMT_t *NMT, +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN + CO_NMT_t* NMT, #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN - CO_LSSmaster_t *LSSmaster, +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN + CO_LSSmaster_t* LSSmaster, #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN - CO_LEDs_t *LEDs, +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN + CO_LEDs_t* LEDs, #endif uint8_t dummy); - /** * Initialize read callback in Gateway-ascii object * @@ -444,12 +426,8 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, * readCallback */ void CO_GTWA_initRead(CO_GTWA_t* gtwa, - size_t (*readCallback)(void *object, - const char *buf, - size_t count, - uint8_t *connectionOK), - void *readCallbackObject); - + size_t (*readCallback)(void* object, const char* buf, size_t count, uint8_t* connectionOK), + void* readCallbackObject); /** * Get free write buffer space @@ -458,11 +436,11 @@ void CO_GTWA_initRead(CO_GTWA_t* gtwa, * * @return number of available bytes */ -static inline size_t CO_GTWA_write_getSpace(CO_GTWA_t* gtwa) { +static inline size_t +CO_GTWA_write_getSpace(CO_GTWA_t* gtwa) { return CO_fifo_getSpace(>wa->commFifo); } - /** * Write command into CO_GTWA_t object. * @@ -478,15 +456,12 @@ static inline size_t CO_GTWA_write_getSpace(CO_GTWA_t* gtwa) { * * @return number of bytes actually written. */ -static inline size_t CO_GTWA_write(CO_GTWA_t* gtwa, - const char *buf, - size_t count) -{ - return CO_fifo_write(>wa->commFifo, (const uint8_t *)buf, count, NULL); +static inline size_t +CO_GTWA_write(CO_GTWA_t* gtwa, const char* buf, size_t count) { + return CO_fifo_write(>wa->commFifo, (const uint8_t*)buf, count, NULL); } - -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0) || defined CO_DOXYGEN /** * Print message log string into fifo buffer * @@ -499,10 +474,9 @@ static inline size_t CO_GTWA_write(CO_GTWA_t* gtwa, * @param gtwa This object * @param message Null terminated string */ -void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message); +void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char* message); #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */ - /** * Process Gateway-ascii object * @@ -518,10 +492,7 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message); * * @return CO_ReturnError_t: CO_ERROR_NO on success or CO_ERROR_ILLEGAL_ARGUMENT */ -void CO_GTWA_process(CO_GTWA_t *gtwa, - bool_t enable, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +void CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint32_t* timerNext_us); /** @} */ /* CO_CANopen_309_3 */ @@ -529,6 +500,6 @@ void CO_GTWA_process(CO_GTWA_t *gtwa, } #endif /*__cplusplus*/ -#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ +#endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ #endif /* CO_GATEWAY_ASCII_H */ diff --git a/CANopen.h b/CANopen.h index ecbbd432..c4fa2028 100644 --- a/CANopen.h +++ b/CANopen.h @@ -19,7 +19,6 @@ * See the License for the specific language governing permissions and limitations under the License. */ - #ifndef CANopen_H #define CANopen_H @@ -42,7 +41,6 @@ #include "309/CO_gateway_ascii.h" #include "extra/CO_trace.h" - #ifdef __cplusplus extern "C" { #endif @@ -182,7 +180,6 @@ extern "C" { #define CO_USE_GLOBALS #endif - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN /** * CANopen configuration, used with @ref CO_new() @@ -196,68 +193,68 @@ typedef struct { * @ref CO_CONFIG_NMT. Start indexes inside CANrx and CANtx are always 0. * There must be one NMT object in the device. */ uint8_t CNT_NMT; - OD_entry_t *ENTRY_H1017; /**< OD entry for @ref CO_NMT_init() */ + OD_entry_t* ENTRY_H1017; /**< OD entry for @ref CO_NMT_init() */ /** Number of Heartbeat consumer objects, 0 or 1 */ uint8_t CNT_HB_CONS; /** Number of internal consumers (CANrx), used inside Heartbeat consumer * object, 1 to 127. */ uint8_t CNT_ARR_1016; - OD_entry_t *ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init()*/ + OD_entry_t* ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init()*/ /** OD entry for @ref CO_nodeGuardingSlave_init() */ - OD_entry_t *ENTRY_H100C; + OD_entry_t* ENTRY_H100C; /** OD entry for @ref CO_nodeGuardingSlave_init() */ - OD_entry_t *ENTRY_H100D; + OD_entry_t* ENTRY_H100D; /** Number of Emergency objects, 0 or 1: optional producer (CANtx) + * optional consumer (CANrx), configurable by @ref CO_CONFIG_EM. * There must be one Emergency object in the device. */ uint8_t CNT_EM; - const OD_entry_t *ENTRY_H1001; /**< OD entry for @ref CO_EM_init() */ - OD_entry_t *ENTRY_H1014; /**< OD entry for @ref CO_EM_init() */ - OD_entry_t *ENTRY_H1015; /**< OD entry for @ref CO_EM_init() */ + const OD_entry_t* ENTRY_H1001; /**< OD entry for @ref CO_EM_init() */ + OD_entry_t* ENTRY_H1014; /**< OD entry for @ref CO_EM_init() */ + OD_entry_t* ENTRY_H1015; /**< OD entry for @ref CO_EM_init() */ /** Size of the fifo buffer, which is used for intermediate storage of * emergency messages. Fifo is used by emergency producer and by error * history (OD object 0x1003). Size is usually equal to size of array in * OD object 0x1003. If later is not used, CNT_ARR_1003 must also be set to * value greater than 0, or emergency producer will not work. */ uint8_t CNT_ARR_1003; - OD_entry_t *ENTRY_H1003; /**< OD entry for @ref CO_EM_init() */ + OD_entry_t* ENTRY_H1003; /**< OD entry for @ref CO_EM_init() */ /** Number of SDO server objects, from 0 to 128 (CANrx + CANtx). There must * be at least one SDO server object in the device. */ uint8_t CNT_SDO_SRV; - OD_entry_t *ENTRY_H1200; /**< OD entry for @ref CO_SDOserver_init()*/ + OD_entry_t* ENTRY_H1200; /**< OD entry for @ref CO_SDOserver_init()*/ /** Number of SDO client objects, from 0 to 128 (CANrx + CANtx). */ uint8_t CNT_SDO_CLI; - OD_entry_t *ENTRY_H1280; /**< OD entry for @ref CO_SDOclient_init()*/ + OD_entry_t* ENTRY_H1280; /**< OD entry for @ref CO_SDOclient_init()*/ /** Number of TIME objects, 0 or 1: consumer (CANrx) + optional producer * (CANtx), configurable by @ref CO_CONFIG_TIME. */ uint8_t CNT_TIME; - OD_entry_t *ENTRY_H1012; /**< OD entry for @ref CO_TIME_init() */ + OD_entry_t* ENTRY_H1012; /**< OD entry for @ref CO_TIME_init() */ /** Number of SYNC objects, 0 or 1: consumer (CANrx) + optional producer * (CANtx), configurable by @ref CO_CONFIG_SYNC. */ uint8_t CNT_SYNC; - OD_entry_t *ENTRY_H1005; /**< OD entry for @ref CO_SYNC_init() */ - OD_entry_t *ENTRY_H1006; /**< OD entry for @ref CO_SYNC_init() */ - OD_entry_t *ENTRY_H1007; /**< OD entry for @ref CO_SYNC_init() */ - OD_entry_t *ENTRY_H1019; /**< OD entry for @ref CO_SYNC_init() */ + OD_entry_t* ENTRY_H1005; /**< OD entry for @ref CO_SYNC_init() */ + OD_entry_t* ENTRY_H1006; /**< OD entry for @ref CO_SYNC_init() */ + OD_entry_t* ENTRY_H1007; /**< OD entry for @ref CO_SYNC_init() */ + OD_entry_t* ENTRY_H1019; /**< OD entry for @ref CO_SYNC_init() */ /** Number of RPDO objects, from 0 to 512 consumers (CANrx) */ uint16_t CNT_RPDO; - OD_entry_t *ENTRY_H1400; /**< OD entry for @ref CO_RPDO_init() */ - OD_entry_t *ENTRY_H1600; /**< OD entry for @ref CO_RPDO_init() */ + OD_entry_t* ENTRY_H1400; /**< OD entry for @ref CO_RPDO_init() */ + OD_entry_t* ENTRY_H1600; /**< OD entry for @ref CO_RPDO_init() */ /** Number of TPDO objects, from 0 to 512 producers (CANtx) */ uint16_t CNT_TPDO; - OD_entry_t *ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */ - OD_entry_t *ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */ + OD_entry_t* ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */ + OD_entry_t* ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */ /** Number of LEDs objects, 0 or 1. */ uint8_t CNT_LEDS; /** Number of GFC objects, 0 or 1 (CANrx + CANtx). */ uint8_t CNT_GFC; - OD_entry_t *ENTRY_H1300; /**< OD entry for @ref CO_GFC_init() */ + OD_entry_t* ENTRY_H1300; /**< OD entry for @ref CO_GFC_init() */ /** Number of SRDO objects, from 0 to 64 (2*CANrx + 2*CANtx). */ uint8_t CNT_SRDO; - OD_entry_t *ENTRY_H1301; /**< OD entry for @ref CO_SRDO_init() */ - OD_entry_t *ENTRY_H1381; /**< OD entry for @ref CO_SRDO_init() */ - OD_entry_t *ENTRY_H13FE; /**< OD entry for @ref CO_SRDO_init() */ - OD_entry_t *ENTRY_H13FF; /**< OD entry for @ref CO_SRDO_init() */ + OD_entry_t* ENTRY_H1301; /**< OD entry for @ref CO_SRDO_init() */ + OD_entry_t* ENTRY_H1381; /**< OD entry for @ref CO_SRDO_init() */ + OD_entry_t* ENTRY_H13FE; /**< OD entry for @ref CO_SRDO_init() */ + OD_entry_t* ENTRY_H13FF; /**< OD entry for @ref CO_SRDO_init() */ /** Number of LSSslave objects, 0 or 1 (CANrx + CANtx). */ uint8_t CNT_LSS_SLV; /** Number of LSSmaster objects, 0 or 1 (CANrx + CANtx). */ @@ -271,162 +268,159 @@ typedef struct { typedef void CO_config_t; #endif /* CO_MULTIPLE_OD */ - /** * CANopen object - collection of all CANopenNode objects */ typedef struct { bool_t nodeIdUnconfigured; /**< True in un-configured LSS slave */ - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN - CO_config_t *config; /**< Remember the configuration parameters */ - #endif +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_config_t* config; /**< Remember the configuration parameters */ +#endif /** One CAN module object, initialised by @ref CO_CANmodule_init() */ - CO_CANmodule_t *CANmodule; - CO_CANrx_t *CANrx; /**< CAN receive message objects */ - CO_CANtx_t *CANtx; /**< CAN transmit message objects */ - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_CANmodule_t* CANmodule; + CO_CANrx_t* CANrx; /**< CAN receive message objects */ + CO_CANtx_t* CANtx; /**< CAN transmit message objects */ +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t CNT_ALL_RX_MSGS; /**< Number of all CAN receive message objects. */ uint16_t CNT_ALL_TX_MSGS; /**< Number of all CAN transmit message objects.*/ - #endif +#endif /** NMT and heartbeat object, initialised by @ref CO_NMT_init() */ - CO_NMT_t *NMT; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_NMT_t* NMT; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_NMT_SLV; /**< Start index in CANrx. */ uint16_t TX_IDX_NMT_MST; /**< Start index in CANtx. */ uint16_t TX_IDX_HB_PROD; /**< Start index in CANtx. */ - #endif -#if (((CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0) || defined CO_DOXYGEN /** Heartbeat consumer object, initialised by @ref CO_HBconsumer_init() */ - CO_HBconsumer_t *HBcons; + CO_HBconsumer_t* HBcons; /** Object for monitored nodes, initialised by @ref CO_HBconsumer_init() */ - CO_HBconsNode_t *HBconsMonitoredNodes; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_HBconsNode_t* HBconsMonitoredNodes; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_HB_CONS; /**< Start index in CANrx. */ - #endif #endif -#if (((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0) || defined CO_DOXYGEN /** Node guarding slave object, initialised by @ref CO_nodeGuardingSlave_init() */ - CO_nodeGuardingSlave_t *NGslave; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_nodeGuardingSlave_t* NGslave; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_NG_SLV; /**< Start index in CANrx. */ uint16_t TX_IDX_NG_SLV; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0) || defined CO_DOXYGEN /** Node guarding master object, initialised by @ref CO_nodeGuardingMaster_init() */ - CO_nodeGuardingMaster_t *NGmaster; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_nodeGuardingMaster_t* NGmaster; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_NG_MST; /**< Start index in CANrx. */ uint16_t TX_IDX_NG_MST; /**< Start index in CANtx. */ - #endif +#endif #endif /** Emergency object, initialised by @ref CO_EM_init() */ - CO_EM_t *em; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_EM_t* em; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_EM_CONS; /**< Start index in CANrx. */ uint16_t TX_IDX_EM_PROD; /**< Start index in CANtx. */ - #endif -#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) \ - || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) || defined CO_DOXYGEN /** FIFO for emergency object, initialised by @ref CO_EM_init() */ - CO_EM_fifo_t *em_fifo; + CO_EM_fifo_t* em_fifo; #endif /** SDO server objects, initialised by @ref CO_SDOserver_init() */ - CO_SDOserver_t *SDOserver; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_SDOserver_t* SDOserver; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SDO_SRV; /**< Start index in CANrx. */ uint16_t TX_IDX_SDO_SRV; /**< Start index in CANtx. */ - #endif -#if (((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN /** SDO client objects, initialised by @ref CO_SDOclient_init() */ - CO_SDOclient_t *SDOclient; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_SDOclient_t* SDOclient; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SDO_CLI; /**< Start index in CANrx. */ uint16_t TX_IDX_SDO_CLI; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN /** TIME object, initialised by @ref CO_TIME_init() */ - CO_TIME_t *TIME; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_TIME_t* TIME; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_TIME; /**< Start index in CANrx. */ uint16_t TX_IDX_TIME; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN /** SYNC object, initialised by @ref CO_SYNC_init() */ - CO_SYNC_t *SYNC; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_SYNC_t* SYNC; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SYNC; /**< Start index in CANrx. */ uint16_t TX_IDX_SYNC; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN /** RPDO objects, initialised by @ref CO_RPDO_init() */ - CO_RPDO_t *RPDO; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_RPDO_t* RPDO; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_RPDO; /**< Start index in CANrx. */ - #endif #endif -#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN /** TPDO objects, initialised by @ref CO_TPDO_init() */ - CO_TPDO_t *TPDO; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_TPDO_t* TPDO; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t TX_IDX_TPDO; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN /** LEDs object, initialised by @ref CO_LEDs_init() */ - CO_LEDs_t *LEDs; + CO_LEDs_t* LEDs; #endif -#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || defined CO_DOXYGEN /** GFC object, initialised by @ref CO_GFC_init() */ - CO_GFC_t *GFC; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_GFC_t* GFC; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_GFC; /**< Start index in CANrx. */ uint16_t TX_IDX_GFC; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN /** SRDO guard object, initialised by @ref CO_SRDO_init_start(), single * SRDOGuard object is included inside all SRDO objects */ - CO_SRDOGuard_t *SRDOGuard; + CO_SRDOGuard_t* SRDOGuard; /** SRDO objects, initialised by @ref CO_SRDO_init() */ - CO_SRDO_t *SRDO; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_SRDO_t* SRDO; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SRDO; /**< Start index in CANrx. */ uint16_t TX_IDX_SRDO; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN /** LSS slave object, initialised by @ref CO_LSSslave_init(). */ - CO_LSSslave_t *LSSslave; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_LSSslave_t* LSSslave; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_LSS_SLV; /**< Start index in CANrx. */ uint16_t TX_IDX_LSS_SLV; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0) || defined CO_DOXYGEN /** LSS master object, initialised by @ref CO_LSSmaster_init(). */ - CO_LSSmaster_t *LSSmaster; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN + CO_LSSmaster_t* LSSmaster; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_LSS_MST; /**< Start index in CANrx. */ uint16_t TX_IDX_LSS_MST; /**< Start index in CANtx. */ - #endif #endif -#if (((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) != 0) || defined CO_DOXYGEN +#endif +#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0) || defined CO_DOXYGEN /** Gateway-ascii object, initialised by @ref CO_GTWA_init(). */ - CO_GTWA_t *gtwa; - #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN - #endif + CO_GTWA_t* gtwa; +#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN #endif -#if ((CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE) || defined CO_DOXYGEN +#endif +#if ((CO_CONFIG_TRACE)&CO_CONFIG_TRACE_ENABLE) || defined CO_DOXYGEN /** Trace object, initialised by @ref CO_trace_init(). */ - CO_trace_t *trace; + CO_trace_t* trace; #endif } CO_t; - /** * Create new CANopen object * @@ -446,16 +440,14 @@ typedef struct { * * @return Successfully allocated and configured CO_t object or NULL. */ -CO_t *CO_new(CO_config_t *config, uint32_t *heapMemoryUsed); - +CO_t* CO_new(CO_config_t* config, uint32_t* heapMemoryUsed); /** * Delete CANopen object and free memory. Must be called at program exit. * * @param co CANopen object. */ -void CO_delete(CO_t *co); - +void CO_delete(CO_t* co); /** * Test if LSS slave is enabled @@ -464,8 +456,7 @@ void CO_delete(CO_t *co); * * @return True if enabled */ -bool_t CO_isLSSslaveEnabled(CO_t *co); - +bool_t CO_isLSSslaveEnabled(CO_t* co); /** * Initialize CAN driver @@ -478,10 +469,9 @@ bool_t CO_isLSSslaveEnabled(CO_t *co); * @param bitRate CAN bit rate. * @return CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_CANinit(CO_t *co, void *CANptr, uint16_t bitRate); +CO_ReturnError_t CO_CANinit(CO_t* co, void* CANptr, uint16_t bitRate); - -#if (((CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN /** * Initialize CANopen LSS slave * @@ -496,13 +486,9 @@ CO_ReturnError_t CO_CANinit(CO_t *co, void *CANptr, uint16_t bitRate); * * @return CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_LSSinit(CO_t *co, - CO_LSS_address_t *lssAddress, - uint8_t *pendingNodeID, - uint16_t *pendingBitRate); +CO_ReturnError_t CO_LSSinit(CO_t* co, CO_LSS_address_t* lssAddress, uint8_t* pendingNodeID, uint16_t* pendingBitRate); #endif - /** * Initialize CANopenNode except PDO objects. * @@ -534,19 +520,10 @@ CO_ReturnError_t CO_LSSinit(CO_t *co, * * @return CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_CANopenInit(CO_t *co, - CO_NMT_t *NMT, - CO_EM_t *em, - OD_t *od, - OD_entry_t *OD_statusBits, - uint16_t NMTcontrol, - uint16_t firstHBTime_ms, - uint16_t SDOserverTimeoutTime_ms, - uint16_t SDOclientTimeoutTime_ms, - bool_t SDOclientBlockTransfer, - uint8_t nodeId, - uint32_t *errInfo); - +CO_ReturnError_t CO_CANopenInit(CO_t* co, CO_NMT_t* NMT, CO_EM_t* em, OD_t* od, OD_entry_t* OD_statusBits, + uint16_t NMTcontrol, uint16_t firstHBTime_ms, uint16_t SDOserverTimeoutTime_ms, + uint16_t SDOclientTimeoutTime_ms, bool_t SDOclientBlockTransfer, uint8_t nodeId, + uint32_t* errInfo); /** * Initialize CANopenNode PDO objects. @@ -565,14 +542,7 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co, * * @return CO_ERROR_NO in case of success. */ -CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, - CO_EM_t *em, - OD_t *od, - uint8_t nodeId, - uint32_t *errInfo); - - - +CO_ReturnError_t CO_CANopenInitPDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo); /** * Initialize Safety related Data Objects. @@ -591,15 +561,10 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t *co, * * @return CO_ERROR_NO in case of success. */ -#if (((CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) -CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, - CO_EM_t *em, - OD_t *od, - uint8_t nodeId, - uint32_t *errInfo); +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) +CO_ReturnError_t CO_CANopenInitSRDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo); #endif - /** * Process CANopen objects. * @@ -622,13 +587,9 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t *co, * * @return Node or communication reset request, from @ref CO_NMT_process(). */ -CO_NMT_reset_cmd_t CO_process(CO_t *co, - bool_t enableGateway, - uint32_t timeDifference_us, - uint32_t *timerNext_us); - +CO_NMT_reset_cmd_t CO_process(CO_t* co, bool_t enableGateway, uint32_t timeDifference_us, uint32_t* timerNext_us); -#if (((CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN /** * Process CANopen SYNC objects. * @@ -643,13 +604,10 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co, * * @return True, if CANopen SYNC message was just received or transmitted. */ -bool_t CO_process_SYNC(CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +bool_t CO_process_SYNC(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us); #endif - -#if (((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN /** * Process CANopen RPDO objects. * @@ -664,14 +622,10 @@ bool_t CO_process_SYNC(CO_t *co, * microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_process_RPDO(CO_t *co, - bool_t syncWas, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +void CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us); #endif - -#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN /** * Process CANopen TPDO objects. * @@ -686,14 +640,10 @@ void CO_process_RPDO(CO_t *co, * microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ -void CO_process_TPDO(CO_t *co, - bool_t syncWas, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +void CO_process_TPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us); #endif - -#if (((CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN /** * Process CANopen SRDO objects. * @@ -708,9 +658,7 @@ void CO_process_TPDO(CO_t *co, * * @return @CO_SRDO_state_t lowest state of the SRDO objects. */ -CO_SRDO_state_t CO_process_SRDO(CO_t *co, - uint32_t timeDifference_us, - uint32_t *timerNext_us); +CO_SRDO_state_t CO_process_SRDO(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us); #endif /** @} */ /* CO_CANopen */ diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index d560f729..690f18c7 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and limitations under the License. */ - #ifndef CO_DRIVER_TARGET_H #define CO_DRIVER_TARGET_H @@ -40,7 +39,6 @@ extern "C" { /* Stack configuration override default values. * For more information see file CO_config.h. */ - /* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ #define CO_LITTLE_ENDIAN #define CO_SWAP_16(x) x @@ -49,22 +47,21 @@ extern "C" { /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ -typedef uint_fast8_t bool_t; -typedef float float32_t; -typedef double float64_t; - +typedef uint_fast8_t bool_t; +typedef float float32_t; +typedef double float64_t; /* Access to received CAN message */ #define CO_CANrxMsg_readIdent(msg) ((uint16_t)0) #define CO_CANrxMsg_readDLC(msg) ((uint8_t)0) -#define CO_CANrxMsg_readData(msg) ((const uint8_t *)NULL) +#define CO_CANrxMsg_readData(msg) ((const uint8_t*)NULL) /* Received message object */ typedef struct { uint16_t ident; uint16_t mask; - void *object; - void (*CANrx_callback)(void *object, void *message); + void* object; + void (*CANrx_callback)(void* object, void* message); } CO_CANrx_t; /* Transmit message object */ @@ -78,10 +75,10 @@ typedef struct { /* CAN module object */ typedef struct { - void *CANptr; - CO_CANrx_t *rxArray; + void* CANptr; + CO_CANrx_t* rxArray; uint16_t rxSize; - CO_CANtx_t *txArray; + CO_CANtx_t* txArray; uint16_t txSize; uint16_t CANerrorStatus; volatile bool_t CANnormal; @@ -92,18 +89,16 @@ typedef struct { uint32_t errOld; } CO_CANmodule_t; - /* Data storage object for one entry */ typedef struct { - void *addr; + void* addr; size_t len; uint8_t subIndexOD; uint8_t attr; /* Additional variables (target specific) */ - void *addrNV; + void* addrNV; } CO_storage_entry_t; - /* (un)lock critical section in CO_CANsend() */ #define CO_LOCK_CAN_SEND(CAN_MODULE) #define CO_UNLOCK_CAN_SEND(CAN_MODULE) @@ -119,9 +114,16 @@ typedef struct { /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) -#define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} -#define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} - +#define CO_FLAG_SET(rxNew) \ + { \ + CO_MemoryBarrier(); \ + rxNew = (void*)1L; \ + } +#define CO_FLAG_CLEAR(rxNew) \ + { \ + CO_MemoryBarrier(); \ + rxNew = NULL; \ + } #ifdef __cplusplus } diff --git a/example/CO_storageBlank.h b/example/CO_storageBlank.h index 2e1525df..811a4cca 100644 --- a/example/CO_storageBlank.h +++ b/example/CO_storageBlank.h @@ -22,7 +22,7 @@ #include "storage/CO_storage.h" -#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN +#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -38,16 +38,11 @@ extern "C" { * CANopenLinux/CO_storageLinux.h files. */ -CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, - CO_CANmodule_t *CANmodule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParam, - CO_storage_entry_t *entries, - uint8_t entriesCount, - uint32_t *storageInitError); +CO_ReturnError_t CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, + OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, + CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); -uint32_t CO_storageBlank_auto_process(CO_storage_t *storage, - bool_t closeFiles); +uint32_t CO_storageBlank_auto_process(CO_storage_t* storage, bool_t closeFiles); #ifdef __cplusplus } diff --git a/storage/CO_eeprom.h b/storage/CO_eeprom.h index c37c9a57..ce05df27 100644 --- a/storage/CO_eeprom.h +++ b/storage/CO_eeprom.h @@ -39,8 +39,7 @@ extern "C" { * * @return True on success */ -bool_t CO_eeprom_init(void *storageModule); - +bool_t CO_eeprom_init(void* storageModule); /** * Get free address inside eeprom, target system specific function. @@ -55,9 +54,7 @@ bool_t CO_eeprom_init(void *storageModule); * * @return Asigned eeprom address */ -size_t CO_eeprom_getAddr(void *storageModule, bool_t isAuto, - size_t len, bool_t *overflow); - +size_t CO_eeprom_getAddr(void* storageModule, bool_t isAuto, size_t len, bool_t* overflow); /** * Read block of data from the eeprom, target system specific function. @@ -67,9 +64,7 @@ size_t CO_eeprom_getAddr(void *storageModule, bool_t isAuto, * @param eepromAddr Address in eeprom, from where data will be read. * @param len Length of the data block to be read. */ -void CO_eeprom_readBlock(void *storageModule, uint8_t *data, - size_t eepromAddr, size_t len); - +void CO_eeprom_readBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len); /** * Write block of data to the eeprom, target system specific function. @@ -84,9 +79,7 @@ void CO_eeprom_readBlock(void *storageModule, uint8_t *data, * * @return true on success */ -bool_t CO_eeprom_writeBlock(void *storageModule, uint8_t *data, - size_t eepromAddr, size_t len); - +bool_t CO_eeprom_writeBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len); /** * Get CRC checksum of the block of data stored in the eeprom, target system @@ -98,9 +91,7 @@ bool_t CO_eeprom_writeBlock(void *storageModule, uint8_t *data, * * @return CRC checksum */ -uint16_t CO_eeprom_getCrcBlock(void *storageModule, - size_t eepromAddr, size_t len); - +uint16_t CO_eeprom_getCrcBlock(void* storageModule, size_t eepromAddr, size_t len); /** * Update one byte of data in the eeprom, target system specific function. @@ -115,9 +106,7 @@ uint16_t CO_eeprom_getCrcBlock(void *storageModule, * @return true if write was successful or false, if still waiting previous * data to finish writing. */ -bool_t CO_eeprom_updateByte(void *storageModule, uint8_t data, - size_t eepromAddr); - +bool_t CO_eeprom_updateByte(void* storageModule, uint8_t data, size_t eepromAddr); /** @} */ /* CO_storage_eeprom */ diff --git a/storage/CO_storage.h b/storage/CO_storage.h index ddfdfd30..7329ebd1 100644 --- a/storage/CO_storage.h +++ b/storage/CO_storage.h @@ -29,7 +29,7 @@ #define CO_CONFIG_STORAGE (CO_CONFIG_STORAGE_ENABLE) #endif -#if (((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -79,7 +79,6 @@ extern "C" { * corresponding data. */ - /** * Attributes (bit masks) for Data storage object. */ @@ -92,27 +91,23 @@ typedef enum { CO_storage_restore = 0x04 } CO_storage_attributes_t; - /** * Data storage object. * * Object is used with CANopen OD objects at index 1010 and 1011. */ typedef struct { - OD_extension_t OD_1010_extension; /**< Extension for OD object */ - OD_extension_t OD_1011_extension; /**< Extension for OD object */ - CO_CANmodule_t *CANmodule; /**< From CO_storage_init() */ - ODR_t (*store)(CO_storage_entry_t *entry, - CO_CANmodule_t *CANmodule); /**< From CO_storage_init() */ - ODR_t (*restore)(CO_storage_entry_t *entry, - CO_CANmodule_t *CANmodule); /**< From CO_storage_init() */ - CO_storage_entry_t *entries; /**< From CO_storage_init() */ - uint8_t entriesCount; /**< From CO_storage_init() */ + OD_extension_t OD_1010_extension; /**< Extension for OD object */ + OD_extension_t OD_1011_extension; /**< Extension for OD object */ + CO_CANmodule_t* CANmodule; /**< From CO_storage_init() */ + ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule); /**< From CO_storage_init() */ + ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule); /**< From CO_storage_init() */ + CO_storage_entry_t* entries; /**< From CO_storage_init() */ + uint8_t entriesCount; /**< From CO_storage_init() */ bool_t enabled; /**< true, if storage is enabled. Setting of this variable is implementation specific. */ } CO_storage_t; - /** * Initialize data storage object * @@ -142,16 +137,11 @@ typedef struct { * * @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ -CO_ReturnError_t CO_storage_init(CO_storage_t *storage, - CO_CANmodule_t *CANmodule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParameters, - ODR_t (*store)(CO_storage_entry_t *entry, - CO_CANmodule_t *CANmodule), - ODR_t (*restore)(CO_storage_entry_t *entry, - CO_CANmodule_t *CANmodule), - CO_storage_entry_t *entries, - uint8_t entriesCount); +CO_ReturnError_t CO_storage_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, + OD_entry_t* OD_1011_RestoreDefaultParameters, + ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), + ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), + CO_storage_entry_t* entries, uint8_t entriesCount); /** @} */ /* CO_storage */ diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h index 44cda6e7..52ec4777 100644 --- a/storage/CO_storageEeprom.h +++ b/storage/CO_storageEeprom.h @@ -27,7 +27,7 @@ #define CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT 5U #endif -#if (((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -71,7 +71,6 @@ extern "C" { * used. */ - /** * Initialize data storage object (block device (eeprom) specific) * @@ -102,15 +101,9 @@ extern "C" { * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if data can not be initialized, * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY. */ -CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, - CO_CANmodule_t *CANmodule, - void *storageModule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParam, - CO_storage_entry_t *entries, - uint8_t entriesCount, - uint32_t *storageInitError); - +CO_ReturnError_t CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* storageModule, + OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, + CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); /** * Automatically update data if differs inside eeprom. @@ -120,7 +113,7 @@ CO_ReturnError_t CO_storageEeprom_init(CO_storage_t *storage, * @param storage This object * @param saveAll If true, all bytes are updated, useful on program end. */ -void CO_storageEeprom_auto_process(CO_storage_t *storage, bool_t saveAll); +void CO_storageEeprom_auto_process(CO_storage_t* storage, bool_t saveAll); /** @} */ /* CO_storage_eeprom */ From f46f1e2733f9eea98d1be8165278c405f1a0073b Mon Sep 17 00:00:00 2001 From: Janez Date: Sun, 7 Jul 2024 01:05:10 +0200 Subject: [PATCH 478/520] clang-format: ReflowComments: true --- .clang-format | 2 +- 301/CO_Emergency.h | 12 +- 301/CO_NMT_Heartbeat.h | 2 +- 301/CO_ODinterface.h | 4 +- 301/CO_SDOclient.c | 2 +- 301/CO_SDOserver.c | 2 +- 301/CO_SDOserver.h | 332 ++++++++++++++++++++--------------------- 301/CO_fifo.h | 5 +- 303/CO_LEDs.h | 2 +- 304/CO_SRDO.c | 6 +- 304/CO_SRDO.h | 12 +- 305/CO_LSSmaster.h | 6 +- 305/CO_LSSslave.c | 2 +- 309/CO_gateway_ascii.c | 8 +- 14 files changed, 201 insertions(+), 196 deletions(-) diff --git a/.clang-format b/.clang-format index 3a8fd1e5..1e6be923 100644 --- a/.clang-format +++ b/.clang-format @@ -135,7 +135,7 @@ PenaltyIndentedWhitespace: 0 PointerAlignment: Left PPIndentWidth: -1 ReferenceAlignment: Pointer -ReflowComments: false +ReflowComments: true RemoveBracesLLVM: false SeparateDefinitionBlocks: Always ShortNamespaceLines: 1 diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 80791b19..4fd62e6e 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -210,7 +210,8 @@ extern "C" { #define CO_EM_10_unused 0x10U /**< 0x10 communication critical (unused) */ #define CO_EM_11_unused 0x11U /**< 0x11 communication critical (unused) */ #define CO_EM_CAN_TX_BUS_OFF 0x12U /**< 0x12 communication critical CAN transmit bus is off */ -#define CO_EM_CAN_RXB_OVERFLOW 0x13U /**< 0x13 communication critical CAN module receive buffer has overflowed */ +#define CO_EM_CAN_RXB_OVERFLOW 0x13U /**< 0x13 communication critical CAN module receive buffer has overflowed \ + */ #define CO_EM_CAN_TX_OVERFLOW 0x14U /**< 0x14 communication critical CAN transmit buffer has overflowed */ #define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /**< 0x15 communication critical TPDO is outside SYNC window */ #define CO_EM_16_unused 0x16U /**< 0x16 communication critical (unused) */ @@ -221,7 +222,8 @@ extern "C" { #define CO_EM_HEARTBEAT_CONSUMER 0x1BU /**< 0x1B communication critical Heartbeat consumer timeout */ #define CO_EM_HB_CONSUMER_REMOTE_RESET \ 0x1CU /**< 0x1C communication critical Heartbeat consumer detected remote node reset */ -#define CO_EM_SRDO_CONFIGURATION 0x1DU /**< 0x1D communication critical Error in SRDO configuration parameters. */ +#define CO_EM_SRDO_CONFIGURATION 0x1DU /**< 0x1D communication critical Error in SRDO configuration parameters. \ + */ #define CO_EM_1E_unused 0x1EU /**< 0x1E communication critical (unused) */ #define CO_EM_1F_unused 0x1FU /**< 0x1F communication critical (unused) */ @@ -233,9 +235,11 @@ extern "C" { #define CO_EM_24_unused 0x24U /**< 0x24 generic info (unused) */ #define CO_EM_25_unused 0x25U /**< 0x25 generic info (unused) */ #define CO_EM_26_unused 0x26U /**< 0x26 generic info (unused) */ -#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /**< 0x27 generic info Automatic store to non-volatile memory failed */ +#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /**< 0x27 generic info Automatic store to non-volatile memory failed \ + */ -#define CO_EM_WRONG_ERROR_REPORT 0x28U /**< 0x28 generic critical Wrong parameters to CO_errorReport() function*/ +#define CO_EM_WRONG_ERROR_REPORT 0x28U /**< 0x28 generic critical Wrong parameters to CO_errorReport() \ + function*/ #define CO_EM_ISR_TIMER_OVERFLOW 0x29U /**< 0x29 generic critical Timer task has overflowed */ #define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /**< 0x2A generic critical Unable to allocate memory for objects */ #define CO_EM_GENERIC_ERROR 0x2BU /**< 0x2B generic critical Generic error test usage */ diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index c95d9c5e..dad353b1 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -118,7 +118,7 @@ typedef enum { /** * @defgroup CO_NMT_control_t NMT control bitfield for NMT internal state. * @{ - * + * * * Variable of this type is passed to @ref CO_NMT_init() function. It * controls behavior of the @ref CO_NMT_internalState_t of the device according diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index d9034fbe..dcf07ce7 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -133,8 +133,8 @@ typedef enum { */ typedef enum { /* !!!! WARNING !!!! - * If changing these values, change also OD_getSDOabCode() function! - */ + * If changing these values, change also OD_getSDOabCode() function! + */ /** Read/write is only partial, make more calls */ ODR_PARTIAL = -1, /** SDO abort 0x00000000 - Read/write successfully finished */ diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index c86514ae..81146316 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -73,7 +73,7 @@ CO_SDOclient_receive(void* object, void* msg) { CO_FLAG_SET(SDO_C->CANrxNew); #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles - * SDO client processing. */ + * SDO client processing. */ if (SDO_C->pFunctSignal != NULL) { SDO_C->pFunctSignal(SDO_C->functSignalObject); } diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 511db99a..369168b8 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -79,7 +79,7 @@ CO_SDO_receive(void* object, void* msg) { SDO->block_seqno = seqno; /* Copy data. There is always enough space in buffer, - * because block_blksize was calculated before */ + * because block_blksize was calculated before */ (void)memcpy(SDO->buf + SDO->bufOffsetWr, &data[1], 7); SDO->bufOffsetWr += 7; SDO->sizeTran += 7; diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 3e29a9ea..5f87fddc 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -97,224 +97,224 @@ extern "C" { */ typedef enum { /** - * - SDO client may start new download to or upload from specified node, - * specified index and specified subindex. It can start normal or block - * communication. - * - SDO server is waiting for client request. */ + * - SDO client may start new download to or upload from specified node, + * specified index and specified subindex. It can start normal or block + * communication. + * - SDO server is waiting for client request. */ CO_SDO_ST_IDLE = 0x00U, /** - * - SDO client or server may send SDO abort message in case of error: - * - byte 0: @b 10000000 binary. - * - byte 1..3: Object index and subIndex. - * - byte 4..7: #CO_SDO_abortCode_t. */ + * - SDO client or server may send SDO abort message in case of error: + * - byte 0: @b 10000000 binary. + * - byte 1..3: Object index and subIndex. + * - byte 4..7: #CO_SDO_abortCode_t. */ CO_SDO_ST_ABORT = 0x01U, /** - * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, - * SDO client is the same device as SDO server. Transfer data directly without - * communication on CAN. - * - SDO server does not use this state. */ + * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, + * SDO client is the same device as SDO server. Transfer data directly without + * communication on CAN. + * - SDO server does not use this state. */ CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER = 0x10U, /** - * - SDO client initiates SDO download: - * - byte 0: @b 0010nnes binary: (nn: if e=s=1, number of data bytes, that do - * @b not contain data; e=1 for expedited transfer; s=1 if data size is - * indicated.) - * - byte 1..3: Object index and subIndex. - * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for - * segmented transfer is indicated here. - * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ + * - SDO client initiates SDO download: + * - byte 0: @b 0010nnes binary: (nn: if e=s=1, number of data bytes, that do + * @b not contain data; e=1 for expedited transfer; s=1 if data size is + * indicated.) + * - byte 1..3: Object index and subIndex. + * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for + * segmented transfer is indicated here. + * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ CO_SDO_ST_DOWNLOAD_INITIATE_REQ = 0x11U, /** - * - SDO client waits for response. - * - SDO server responses: - * - byte 0: @b 01100000 binary. - * - byte 1..3: Object index and subIndex. - * - byte 4..7: Reserved. - * - In case of expedited transfer communication ends here. */ + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 01100000 binary. + * - byte 1..3: Object index and subIndex. + * - byte 4..7: Reserved. + * - In case of expedited transfer communication ends here. */ CO_SDO_ST_DOWNLOAD_INITIATE_RSP = 0x12U, /** - * - SDO client sends SDO segment: - * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; - * nnn: number of data bytes, that do @b not contain data; c=1 if this is the - * last segment). - * - byte 1..7: Data segment. - * - SDO server waits for segment. */ + * - SDO client sends SDO segment: + * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; + * nnn: number of data bytes, that do @b not contain data; c=1 if this is the + * last segment). + * - byte 1..7: Data segment. + * - SDO server waits for segment. */ CO_SDO_ST_DOWNLOAD_SEGMENT_REQ = 0x13U, /** - * - SDO client waits for response. - * - SDO server responses: - * - byte 0: @b 001t0000 binary: (t: toggle bit, set to 0 in first segment). - * - byte 1..7: Reserved. - * - If c was set to 1, then communication ends here. */ + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 001t0000 binary: (t: toggle bit, set to 0 in first segment). + * - byte 1..7: Reserved. + * - If c was set to 1, then communication ends here. */ CO_SDO_ST_DOWNLOAD_SEGMENT_RSP = 0x14U, /** - * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, - * SDO client is the same device as SDO server. Transfer data directly without - * communication on CAN. - * - SDO server does not use this state. */ + * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, + * SDO client is the same device as SDO server. Transfer data directly without + * communication on CAN. + * - SDO server does not use this state. */ CO_SDO_ST_UPLOAD_LOCAL_TRANSFER = 0x20U, /** - * - SDO client initiates SDO upload: - * - byte 0: @b 01000000 binary. - * - byte 1..3: Object index and subIndex. - * - byte 4..7: Reserved. - * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ + * - SDO client initiates SDO upload: + * - byte 0: @b 01000000 binary. + * - byte 1..3: Object index and subIndex. + * - byte 4..7: Reserved. + * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ CO_SDO_ST_UPLOAD_INITIATE_REQ = 0x21U, /** - * - SDO client waits for response. - * - SDO server responses: - * - byte 0: @b 0100nnes binary: (nn: if e=s=1, number of data bytes, that do - * @b not contain data; e=1 for expedited transfer; s=1 if data size is - * indicated). - * - byte 1..3: Object index and subIndex. - * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for - * segmented transfer is indicated here. - * - In case of expedited transfer communication ends here. */ + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 0100nnes binary: (nn: if e=s=1, number of data bytes, that do + * @b not contain data; e=1 for expedited transfer; s=1 if data size is + * indicated). + * - byte 1..3: Object index and subIndex. + * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for + * segmented transfer is indicated here. + * - In case of expedited transfer communication ends here. */ CO_SDO_ST_UPLOAD_INITIATE_RSP = 0x22U, /** - * - SDO client requests SDO segment: - * - byte 0: @b 011t0000 binary: (t: toggle bit, set to 0 in first segment). - * - byte 1..7: Reserved. - * - SDO server waits for segment request. */ + * - SDO client requests SDO segment: + * - byte 0: @b 011t0000 binary: (t: toggle bit, set to 0 in first segment). + * - byte 1..7: Reserved. + * - SDO server waits for segment request. */ CO_SDO_ST_UPLOAD_SEGMENT_REQ = 0x23U, /** - * - SDO client waits for response. - * - SDO server responses with data: - * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; - * nnn: number of data bytes, that do @b not contain data; c=1 if this is the - * last segment). - * - byte 1..7: Data segment. - * - If c is set to 1, then communication ends here. */ + * - SDO client waits for response. + * - SDO server responses with data: + * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; + * nnn: number of data bytes, that do @b not contain data; c=1 if this is the + * last segment). + * - byte 1..7: Data segment. + * - If c is set to 1, then communication ends here. */ CO_SDO_ST_UPLOAD_SEGMENT_RSP = 0x24U, /** - * - SDO client initiates SDO block download: - * - byte 0: @b 11000rs0 binary: (r=1 if client supports generating CRC on - * data; s=1 if data size is indicated.) - * - byte 1..3: Object index and subIndex. - * - byte 4..7: If s=1, then size of data for block download is indicated here. - * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ + * - SDO client initiates SDO block download: + * - byte 0: @b 11000rs0 binary: (r=1 if client supports generating CRC on + * data; s=1 if data size is indicated.) + * - byte 1..3: Object index and subIndex. + * - byte 4..7: If s=1, then size of data for block download is indicated here. + * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ = 0x51U, /** - * - SDO client waits for response. - * - SDO server responses: - * - byte 0: @b 10100r00 binary: (r=1 if server supports generating CRC on - * data.) - * - byte 1..3: Object index and subIndex. - * - byte 4: blksize: Number of segments per block that shall be used by the - * client for the following block download with 0 < blksize < 128. - * - byte 5..7: Reserved. */ + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 10100r00 binary: (r=1 if server supports generating CRC on + * data.) + * - byte 1..3: Object index and subIndex. + * - byte 4: blksize: Number of segments per block that shall be used by the + * client for the following block download with 0 < blksize < 128. + * - byte 5..7: Reserved. */ CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP = 0x52U, /** - * - SDO client sends 'blksize' segments of data in sequence: - * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be downloaded, - * enter SDO block download end phase; nnnnnnn is sequence number of segment, - * 1..127. - * - byte 1..7: At most 7 bytes of segment data to be downloaded. - * - SDO server reads sequence of 'blksize' blocks. */ + * - SDO client sends 'blksize' segments of data in sequence: + * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be downloaded, + * enter SDO block download end phase; nnnnnnn is sequence number of segment, + * 1..127. + * - byte 1..7: At most 7 bytes of segment data to be downloaded. + * - SDO server reads sequence of 'blksize' blocks. */ CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x53U, /** - * - SDO client waits for response. - * - SDO server responses: - * - byte 0: @b 10100010 binary. - * - byte 1: ackseq: sequence number of last segment that was received - * successfully during the last block download. If ackseq is set to 0 the - * server indicates the client that the segment with the sequence number 1 - * was not received correctly and all segments shall be retransmitted by the - * client. - * - byte 2: Number of segments per block that shall be used by the client for - * the following block download with 0 < blksize < 128. - * - byte 3..7: Reserved. - * - If c was set to 1, then communication enters SDO block download end phase. - */ + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 10100010 binary. + * - byte 1: ackseq: sequence number of last segment that was received + * successfully during the last block download. If ackseq is set to 0 the + * server indicates the client that the segment with the sequence number 1 + * was not received correctly and all segments shall be retransmitted by the + * client. + * - byte 2: Number of segments per block that shall be used by the client for + * the following block download with 0 < blksize < 128. + * - byte 3..7: Reserved. + * - If c was set to 1, then communication enters SDO block download end phase. + */ CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP = 0x54U, /** - * - SDO client sends SDO block download end: - * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not - * contain data) - * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. - * - byte 3..7: Reserved. - * - SDO server waits for client request. */ + * - SDO client sends SDO block download end: + * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not + * contain data) + * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. + * - byte 3..7: Reserved. + * - SDO server waits for client request. */ CO_SDO_ST_DOWNLOAD_BLK_END_REQ = 0x55U, /** - * - SDO client waits for response. - * - SDO server responses: - * - byte 0: @b 10100001 binary. - * - byte 1..7: Reserved. - * - Block download successfully ends here. - */ + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 10100001 binary. + * - byte 1..7: Reserved. + * - Block download successfully ends here. + */ CO_SDO_ST_DOWNLOAD_BLK_END_RSP = 0x56U, /** - * - SDO client initiates SDO block upload: - * - byte 0: @b 10100r00 binary: (r=1 if client supports generating CRC on - * data.) - * - byte 1..3: Object index and subIndex. - * - byte 4: blksize: Number of segments per block with 0 < blksize < 128. - * - byte 5: pst - protocol switch threshold. If pst > 0 and size of the data - * in bytes is less or equal pst, then the server may switch to the SDO - * upload protocol #CO_SDO_ST_UPLOAD_INITIATE_RSP. - * - byte 6..7: Reserved. - * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ + * - SDO client initiates SDO block upload: + * - byte 0: @b 10100r00 binary: (r=1 if client supports generating CRC on + * data.) + * - byte 1..3: Object index and subIndex. + * - byte 4: blksize: Number of segments per block with 0 < blksize < 128. + * - byte 5: pst - protocol switch threshold. If pst > 0 and size of the data + * in bytes is less or equal pst, then the server may switch to the SDO + * upload protocol #CO_SDO_ST_UPLOAD_INITIATE_RSP. + * - byte 6..7: Reserved. + * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x61U, /** - * - SDO client waits for response. - * - SDO server responses: - * - byte 0: @b 11000rs0 binary: (r=1 if server supports generating CRC on - * data; s=1 if data size is indicated. ) - * - byte 1..3: Object index and subIndex. - * - byte 4..7: If s=1, then size of data for block upload is indicated here. - * - If enabled by pst, then server may alternatively response with - * #CO_SDO_ST_UPLOAD_INITIATE_RSP */ + * - SDO client waits for response. + * - SDO server responses: + * - byte 0: @b 11000rs0 binary: (r=1 if server supports generating CRC on + * data; s=1 if data size is indicated. ) + * - byte 1..3: Object index and subIndex. + * - byte 4..7: If s=1, then size of data for block upload is indicated here. + * - If enabled by pst, then server may alternatively response with + * #CO_SDO_ST_UPLOAD_INITIATE_RSP */ CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP = 0x62U, /** - * - SDO client sends second initiate for SDO block upload: - * - byte 0: @b 10100011 binary. - * - byte 1..7: Reserved. - * - SDO server waits for client request. */ + * - SDO client sends second initiate for SDO block upload: + * - byte 0: @b 10100011 binary. + * - byte 1..7: Reserved. + * - SDO server waits for client request. */ CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2 = 0x63U, /** - * - SDO client reads sequence of 'blksize' blocks. - * - SDO server sends 'blksize' segments of data in sequence: - * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be uploaded, - * enter SDO block upload end phase; nnnnnnn is sequence number of segment, - * 1..127. - * - byte 1..7: At most 7 bytes of segment data to be uploaded. */ + * - SDO client reads sequence of 'blksize' blocks. + * - SDO server sends 'blksize' segments of data in sequence: + * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be uploaded, + * enter SDO block upload end phase; nnnnnnn is sequence number of segment, + * 1..127. + * - byte 1..7: At most 7 bytes of segment data to be uploaded. */ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x64U, /** - * - SDO client responses: - * - byte 0: @b 10100010 binary. - * - byte 1: ackseq: sequence number of last segment that was received - * successfully during the last block upload. If ackseq is set to 0 the - * client indicates the server that the segment with the sequence number 1 - * was not received correctly and all segments shall be retransmitted by the - * server. - * - byte 2: Number of segments per block that shall be used by the server for - * the following block upload with 0 < blksize < 128. - * - byte 3..7: Reserved. - * - SDO server waits for response. - * - If c was set to 1 and all segments were successfull received, then - * communication enters SDO block upload end phase. */ + * - SDO client responses: + * - byte 0: @b 10100010 binary. + * - byte 1: ackseq: sequence number of last segment that was received + * successfully during the last block upload. If ackseq is set to 0 the + * client indicates the server that the segment with the sequence number 1 + * was not received correctly and all segments shall be retransmitted by the + * server. + * - byte 2: Number of segments per block that shall be used by the server for + * the following block upload with 0 < blksize < 128. + * - byte 3..7: Reserved. + * - SDO server waits for response. + * - If c was set to 1 and all segments were successfull received, then + * communication enters SDO block upload end phase. */ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x65U, /** - * - SDO client waits for server request. - * - SDO server sends SDO block upload end: - * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not - * contain data) - * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. - * - byte 3..7: Reserved. */ + * - SDO client waits for server request. + * - SDO server sends SDO block upload end: + * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not + * contain data) + * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. + * - byte 3..7: Reserved. */ CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x66U, /** - * - SDO client responses: - * - byte 0: @b 10100001 binary. - * - byte 1..7: Reserved. - * - SDO server waits for response. - * - Block download successfully ends here. Note that this communication ends - * with client response. Client may then start next SDO communication - * immediately. - */ + * - SDO client responses: + * - byte 0: @b 10100001 binary. + * - byte 1..7: Reserved. + * - SDO server waits for response. + * - Block download successfully ends here. Note that this communication ends + * with client response. Client may then start next SDO communication + * immediately. + */ CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x67U, } CO_SDO_state_t; diff --git a/301/CO_fifo.h b/301/CO_fifo.h index 8c1a9ca2..d588ea29 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -453,10 +453,11 @@ size_t CO_fifo_readB642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** * @defgroup uint8_t Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar * @{ - */ + */ #define CO_fifo_st_closed 0x01U /**< Bit is set, if command delimiter is reached in src */ #define CO_fifo_st_partial \ - 0x02U /**< Bit is set, if copy was partial and more data are available. If unset and no error, then all data was successfully copied. */ + 0x02U /**< Bit is set, if copy was partial and more data are available. If unset and no error, then all data was \ + successfully copied. */ #define CO_fifo_st_errTok 0x10U /**< Bit is set, if no valid token found */ #define CO_fifo_st_errVal 0x20U /**< Bit is set, if value is not valid or out of limits */ #define CO_fifo_st_errBuf 0x40U /**< Bit is set, if destination buffer is to small */ diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index 7cb4d9ac..39331ba1 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -70,7 +70,7 @@ extern "C" { /** * @defgroup CO_LED_BITFIELD_t Bitfield for combining with red or green led * @{ - * + * */ #define CO_LED_flicker 0x01U /**< LED flickering 10Hz */ #define CO_LED_blink 0x02U /**< LED blinking 2,5Hz */ diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index f8992f4c..2632084d 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -780,7 +780,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext } /* Set stream.dataOffset to zero, perform OD_IO.read() - * and store mappedLength back to stream.dataOffset */ + * and store mappedLength back to stream.dataOffset */ stream->dataOffset = 0; OD_size_t countRd; OD_IO->read(stream, dataSRDOCopy, ODdataLength, &countRd); @@ -905,7 +905,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext ODdataLength = CO_SRDO_MAX_SIZE; } /* Prepare data for writing into OD variable. If mappedLength - * is smaller than ODdataLength, then use auxiliary buffer */ + * is smaller than ODdataLength, then use auxiliary buffer */ uint8_t buf[CO_SRDO_MAX_SIZE]; uint8_t* dataOD; if (ODdataLength > mappedLength) { @@ -930,7 +930,7 @@ CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uint32_t* timerNext #endif /* Set stream.dataOffset to zero, perform OD_IO.write() - * and store mappedLength back to stream.dataOffset */ + * and store mappedLength back to stream.dataOffset */ *dataOffset = 0; OD_size_t countWritten; OD_IO->write(&OD_IO->stream, dataOD, ODdataLength, &countWritten); diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index 82de4553..a02f0866 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -47,10 +47,10 @@ extern "C" { * @ingroup CO_CANopen_304 * @{ * Safety Related Data Object protocol is specified by standard EN 50325-5:2010 (formerly CiA304). - * Its functionality is very similar to that of the PDOs. The main differences is every message is send and received twice. - * The second message must be bitwise inverted. The delay between the two messages and between each message pair is monitored. - * The distinction between sending and receiving SRDO is made at runtime (for PDO it is compile time). - * If the security protocol is used, at least one SRDO is mandatory. + * Its functionality is very similar to that of the PDOs. The main differences is every message is send and received + * twice. The second message must be bitwise inverted. The delay between the two messages and between each message pair + * is monitored. The distinction between sending and receiving SRDO is made at runtime (for PDO it is compile time). If + * the security protocol is used, at least one SRDO is mandatory. * * If there is erroneous structure of OD entries for SRDO parameters, then @CO_SRDO_init() function * returns error and CANopen device doesn't work. It is necessary to repair Object Dictionary and reprogram the device. @@ -65,8 +65,8 @@ extern "C" { * * @CO_SRDO_process() must be executed cyclically, similar as PDO processing. Function is fast, no time consuming tasks. * Function returns @CO_SRDO_state_t value, which may be used to determine working-state or safe-state of safety related - * device. If return values from all SRDO objects are >= CO_SRDO_state_communicationEstablished, then working state is allowed. - * Otherwise SR device must be in safe state. + * device. If return values from all SRDO objects are >= CO_SRDO_state_communicationEstablished, then working state is + * allowed. Otherwise SR device must be in safe state. * * Requirement for mapped objects: * - @OD_attributes_t must have set bit ODA_RSRDO or ODA_RSRDO or ODA_TRSRDO (by CANopenEditor). diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 39c84792..ef3456c6 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -109,9 +109,9 @@ typedef struct { uint8_t fsBitChecked; /**< Current scan bit position */ uint32_t fsIdNumber; /**< Current scan result */ - volatile void* - CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */ - uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ + volatile void* CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when + received message is completely processed. */ + uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ #if (((CO_CONFIG_LSS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN void (*pFunctSignal)(void* object); /**< From CO_LSSmaster_initCallbackPre() or NULL */ void* functSignalObject; /**< Pointer to object */ diff --git a/305/CO_LSSslave.c b/305/CO_LSSslave.c index 81d9aaec..fa74caa7 100644 --- a/305/CO_LSSslave.c +++ b/305/CO_LSSslave.c @@ -274,7 +274,7 @@ CO_LSSslave_process(CO_LSSslave_t* LSSslave) { switch (LSSslave->service) { case CO_LSS_SWITCH_STATE_GLOBAL: { /* Node-Id was unconfigured before, now it is configured, - * enter the NMT Reset communication autonomously. */ + * enter the NMT Reset communication autonomously. */ resetCommunication = true; break; } diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index b88d17c6..ed1a1fdc 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -591,8 +591,8 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint } /*************************************************************************** - * COMMAND PARSER - ***************************************************************************/ + * COMMAND PARSER + ***************************************************************************/ /* if idle, search for new command, skip comments or empty lines */ while (CO_fifo_CommSearch(>wa->commFifo, false) && (gtwa->state == CO_GTWA_ST_IDLE)) { char tok[20]; @@ -1531,8 +1531,8 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint } /* while CO_GTWA_ST_IDLE && CO_fifo_CommSearch */ /*************************************************************************** - * STATE MACHINE - ***************************************************************************/ + * STATE MACHINE + ***************************************************************************/ /* If error, generate error response */ if (err) { if (respErrorCode == CO_GTWA_respErrorNone) { From f41bfdcb5d0d432455e5d4df0a16cd5520a8fd57 Mon Sep 17 00:00:00 2001 From: Janez Date: Tue, 9 Jul 2024 00:17:15 +0200 Subject: [PATCH 479/520] Format comments in the .h files. --- 301/CO_Emergency.h | 473 ++++++++++++++------------------ 301/CO_HBconsumer.h | 149 ++++------ 301/CO_NMT_Heartbeat.h | 183 +++++-------- 301/CO_Node_Guarding.h | 127 +++------ 301/CO_ODinterface.h | 420 +++++++++++----------------- 301/CO_PDO.h | 312 ++++++++------------- 301/CO_SDOclient.h | 347 +++++++++-------------- 301/CO_SDOserver.h | 448 ++++++++++++------------------ 301/CO_SYNC.h | 144 ++++------ 301/CO_TIME.h | 89 +++--- 301/CO_driver.h | 544 +++++++++++++++---------------------- 301/CO_fifo.h | 175 +++++------- 301/crc16-ccitt.h | 14 +- 303/CO_LEDs.h | 16 +- 304/CO_GFC.h | 30 +- 304/CO_SRDO.h | 184 +++++-------- 305/CO_LSS.h | 45 ++- 305/CO_LSSmaster.h | 201 ++++++-------- 305/CO_LSSslave.h | 151 +++++----- 309/CO_gateway_ascii.h | 342 +++++++++-------------- CANopen.h | 351 +++++++++--------------- MISRA.md | 280 +++++++++---------- README.md | 5 +- codingStyle | 140 ---------- doc/CHANGELOG.md | 5 + doc/objectDictionary.md | 2 +- example/CO_driver_target.h | 8 +- example/CO_storageBlank.c | 182 ++++++------- example/CO_storageBlank.h | 104 ++++--- extra/CO_trace.h | 2 +- storage/CO_eeprom.h | 230 ++++++++-------- storage/CO_storage.c | 330 +++++++++++----------- storage/CO_storage.h | 296 ++++++++++---------- storage/CO_storageEeprom.c | 444 +++++++++++++++--------------- storage/CO_storageEeprom.h | 235 ++++++++-------- 35 files changed, 2898 insertions(+), 4110 deletions(-) delete mode 100644 codingStyle diff --git a/301/CO_Emergency.h b/301/CO_Emergency.h index 4fd62e6e..c449c7c9 100644 --- a/301/CO_Emergency.h +++ b/301/CO_Emergency.h @@ -53,28 +53,22 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * Error control and Emergency is used for control internal error state - * and for sending a CANopen Emergency message. - * - * In case of error condition stack or application calls CO_errorReport() - * function with indication of the error. Specific error condition is reported - * (with CANopen Emergency message) only the first time after it occurs. - * Internal state of specific error condition is indicated by internal bitfield - * variable, with space for maximum @ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - * bits. Meaning for each bit is described by @ref CO_EM_errorStatusBits_t. - * Specific error condition can be reset by CO_errorReset() function. In that - * case Emergency message is sent with CO_EM_NO_ERROR indication. - * - * Some error conditions are informative and some are critical. Critical error - * conditions set the corresponding bit in @ref CO_errorRegister_t. Critical - * error conditions for generic error are specified by - * @ref CO_CONFIG_ERR_CONDITION_GENERIC macro. Similar macros are defined for - * other error bits in in @ref CO_errorRegister_t. + * Error control and Emergency is used for control internal error state and for sending a CANopen Emergency message. + * + * In case of error condition stack or application calls CO_errorReport() function with indication of the error. + * Specific error condition is reported (with CANopen Emergency message) only the first time after it occurs. Internal + * state of specific error condition is indicated by internal bitfield variable, with space for maximum @ref + * CO_CONFIG_EM_ERR_STATUS_BITS_COUNT bits. Meaning for each bit is described by @ref CO_EM_errorStatusBits_t. Specific + * error condition can be reset by CO_errorReset() function. In that case Emergency message is sent with CO_EM_NO_ERROR + * indication. + * + * Some error conditions are informative and some are critical. Critical error conditions set the corresponding bit in + * @ref CO_errorRegister_t. Critical error conditions for generic error are specified by @ref + * CO_CONFIG_ERR_CONDITION_GENERIC macro. Similar macros are defined for other error bits in in @ref CO_errorRegister_t. * * ### Emergency producer - * If @ref CO_CONFIG_EM has CO_CONFIG_EM_PRODUCER enabled, then CANopen - * Emergency message will be sent on each change of any error condition. - * Emergency message contents are: + * If @ref CO_CONFIG_EM has CO_CONFIG_EM_PRODUCER enabled, then CANopen Emergency message will be sent on each change of + * any error condition. Emergency message contents are: * * Byte | Description * -----|----------------------------------------------------------- @@ -84,13 +78,12 @@ extern "C" { * 4..7 | Additional informative argument to CO_errorReport() function. * * ### Error history - * If @ref CO_CONFIG_EM has CO_CONFIG_EM_HISTORY enabled, then latest errors - * can be read from _Pre Defined Error Field_ (object dictionary, index 0x1003). - * Contents corresponds to bytes 0..3 from the Emergency message. + * If @ref CO_CONFIG_EM has CO_CONFIG_EM_HISTORY enabled, then latest errors can be read from _Pre Defined Error Field_ + * (object dictionary, index 0x1003). Contents corresponds to bytes 0..3 from the Emergency message. * * ### Emergency consumer - * If @ref CO_CONFIG_EM has CO_CONFIG_EM_CONSUMER enabled, then callback can be - * registered by @ref CO_EM_initCallbackRx() function. + * If @ref CO_CONFIG_EM has CO_CONFIG_EM_CONSUMER enabled, then callback can be registered by @ref + * CO_EM_initCallbackRx() function. */ /** @@ -99,21 +92,20 @@ extern "C" { * * Mandatory for CANopen, resides in object dictionary, index 0x1001. * - * Error register is calculated from internal bitfield variable, critical bits. - * See @ref CO_EM_errorStatusBits_t and @ref CO_STACK_CONFIG_EMERGENCY for error - * condition macros. + * Error register is calculated from internal bitfield variable, critical bits. See @ref CO_EM_errorStatusBits_t and + * @ref CO_STACK_CONFIG_EMERGENCY for error condition macros. * - * Internal errors may prevent device to stay in NMT Operational state and - * changes may switch between the states. See @ref CO_NMT_control_t for details. + * Internal errors may prevent device to stay in NMT Operational state and changes may switch between the states. See + * @ref CO_NMT_control_t for details. */ -#define CO_ERR_REG_GENERIC_ERR 0x01U /**< bit 0, generic error */ -#define CO_ERR_REG_CURRENT 0x02U /**< bit 1, current */ -#define CO_ERR_REG_VOLTAGE 0x04U /**< bit 2, voltage */ -#define CO_ERR_REG_TEMPERATURE 0x08U /**< bit 3, temperature */ -#define CO_ERR_REG_COMMUNICATION 0x10U /**< bit 4, communication error */ -#define CO_ERR_REG_DEV_PROFILE 0x20U /**< bit 5, device profile specific */ -#define CO_ERR_REG_RESERVED 0x40U /**< bit 6, reserved (always 0) */ -#define CO_ERR_REG_MANUFACTURER 0x80U /**< bit 7, manufacturer specific */ +#define CO_ERR_REG_GENERIC_ERR 0x01U /**< bit 0, generic error */ +#define CO_ERR_REG_CURRENT 0x02U /**< bit 1, current */ +#define CO_ERR_REG_VOLTAGE 0x04U /**< bit 2, voltage */ +#define CO_ERR_REG_TEMPERATURE 0x08U /**< bit 3, temperature */ +#define CO_ERR_REG_COMMUNICATION 0x10U /**< bit 4, communication error */ +#define CO_ERR_REG_DEV_PROFILE 0x20U /**< bit 5, device profile specific */ +#define CO_ERR_REG_RESERVED 0x40U /**< bit 6, reserved (always 0) */ +#define CO_ERR_REG_MANUFACTURER 0x80U /**< bit 7, manufacturer specific */ /** @} */ /* CO_errorRegister_t */ @@ -123,51 +115,51 @@ extern "C" { * * Standard error codes according to CiA DS-301 and DS-401. */ -#define CO_EMC_NO_ERROR 0x0000U /**< 0x00xx error Reset or No Error */ -#define CO_EMC_GENERIC 0x1000U /**< 0x10xx Generic Error */ -#define CO_EMC_CURRENT 0x2000U /**< 0x20xx Current */ -#define CO_EMC_CURRENT_INPUT 0x2100U /**< 0x21xx Current device input side */ -#define CO_EMC_CURRENT_INSIDE 0x2200U /**< 0x22xx Current inside the device */ -#define CO_EMC_CURRENT_OUTPUT 0x2300U /**< 0x23xx Current device output side */ -#define CO_EMC_VOLTAGE 0x3000U /**< 0x30xx Voltage */ -#define CO_EMC_VOLTAGE_MAINS 0x3100U /**< 0x31xx Mains Voltage */ -#define CO_EMC_VOLTAGE_INSIDE 0x3200U /**< 0x32xx Voltage inside the device */ -#define CO_EMC_VOLTAGE_OUTPUT 0x3300U /**< 0x33xx Output Voltage */ -#define CO_EMC_TEMPERATURE 0x4000U /**< 0x40xx Temperature */ -#define CO_EMC_TEMP_AMBIENT 0x4100U /**< 0x41xx Ambient Temperature */ -#define CO_EMC_TEMP_DEVICE 0x4200U /**< 0x42xx Device Temperature */ -#define CO_EMC_HARDWARE 0x5000U /**< 0x50xx Device Hardware */ -#define CO_EMC_SOFTWARE_DEVICE 0x6000U /**< 0x60xx Device Software */ -#define CO_EMC_SOFTWARE_INTERNAL 0x6100U /**< 0x61xx Internal Software */ -#define CO_EMC_SOFTWARE_USER 0x6200U /**< 0x62xx User Software */ -#define CO_EMC_DATA_SET 0x6300U /**< 0x63xx Data Set */ -#define CO_EMC_ADDITIONAL_MODUL 0x7000U /**< 0x70xx Additional Modules */ -#define CO_EMC_MONITORING 0x8000U /**< 0x80xx Monitoring */ -#define CO_EMC_COMMUNICATION 0x8100U /**< 0x81xx Communication */ -#define CO_EMC_CAN_OVERRUN 0x8110U /**< 0x8110 CAN Overrun (Objects lost) */ -#define CO_EMC_CAN_PASSIVE 0x8120U /**< 0x8120 CAN in Error Passive Mode */ -#define CO_EMC_HEARTBEAT 0x8130U /**< 0x8130 Life Guard Error or Heartbeat Error */ -#define CO_EMC_BUS_OFF_RECOVERED 0x8140U /**< 0x8140 recovered from bus off */ -#define CO_EMC_CAN_ID_COLLISION 0x8150U /**< 0x8150 CAN-ID collision */ -#define CO_EMC_PROTOCOL_ERROR 0x8200U /**< 0x82xx Protocol Error */ -#define CO_EMC_PDO_LENGTH 0x8210U /**< 0x8210 PDO not processed due to length error */ -#define CO_EMC_PDO_LENGTH_EXC 0x8220U /**< 0x8220 PDO length exceeded */ -#define CO_EMC_DAM_MPDO 0x8230U /**< 0x8230 DAM MPDO not processed destination object not available */ -#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /**< 0x8240 Unexpected SYNC data length */ -#define CO_EMC_RPDO_TIMEOUT 0x8250U /**< 0x8250 RPDO timeout */ -#define CO_EMC_EXTERNAL_ERROR 0x9000U /**< 0x90xx External Error */ -#define CO_EMC_ADDITIONAL_FUNC 0xF000U /**< 0xF0xx Additional Functions */ -#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /**< 0xFFxx Device specific */ - -#define CO_EMC401_OUT_CUR_HI 0x2310U /**< 0x2310 DS401 Current at outputs too high (overload) */ -#define CO_EMC401_OUT_SHORTED 0x2320U /**< 0x2320 DS401 Short circuit at outputs */ -#define CO_EMC401_OUT_LOAD_DUMP 0x2330U /**< 0x2330 DS401 Load dump at outputs */ -#define CO_EMC401_IN_VOLT_HI 0x3110U /**< 0x3110 DS401 Input voltage too high */ -#define CO_EMC401_IN_VOLT_LOW 0x3120U /**< 0x3120 DS401 Input voltage too low */ -#define CO_EMC401_INTERN_VOLT_HI 0x3210U /**< 0x3210 DS401 Internal voltage too high */ -#define CO_EMC401_INTERN_VOLT_LO 0x3220U /**< 0x3220 DS401 Internal voltage too low */ -#define CO_EMC401_OUT_VOLT_HIGH 0x3310U /**< 0x3310 DS401 Output voltage too high */ -#define CO_EMC401_OUT_VOLT_LOW 0x3320U /**< 0x3320 DS401 Output voltage too low */ +#define CO_EMC_NO_ERROR 0x0000U /**< 0x00xx error Reset or No Error */ +#define CO_EMC_GENERIC 0x1000U /**< 0x10xx Generic Error */ +#define CO_EMC_CURRENT 0x2000U /**< 0x20xx Current */ +#define CO_EMC_CURRENT_INPUT 0x2100U /**< 0x21xx Current device input side */ +#define CO_EMC_CURRENT_INSIDE 0x2200U /**< 0x22xx Current inside the device */ +#define CO_EMC_CURRENT_OUTPUT 0x2300U /**< 0x23xx Current device output side */ +#define CO_EMC_VOLTAGE 0x3000U /**< 0x30xx Voltage */ +#define CO_EMC_VOLTAGE_MAINS 0x3100U /**< 0x31xx Mains Voltage */ +#define CO_EMC_VOLTAGE_INSIDE 0x3200U /**< 0x32xx Voltage inside the device */ +#define CO_EMC_VOLTAGE_OUTPUT 0x3300U /**< 0x33xx Output Voltage */ +#define CO_EMC_TEMPERATURE 0x4000U /**< 0x40xx Temperature */ +#define CO_EMC_TEMP_AMBIENT 0x4100U /**< 0x41xx Ambient Temperature */ +#define CO_EMC_TEMP_DEVICE 0x4200U /**< 0x42xx Device Temperature */ +#define CO_EMC_HARDWARE 0x5000U /**< 0x50xx Device Hardware */ +#define CO_EMC_SOFTWARE_DEVICE 0x6000U /**< 0x60xx Device Software */ +#define CO_EMC_SOFTWARE_INTERNAL 0x6100U /**< 0x61xx Internal Software */ +#define CO_EMC_SOFTWARE_USER 0x6200U /**< 0x62xx User Software */ +#define CO_EMC_DATA_SET 0x6300U /**< 0x63xx Data Set */ +#define CO_EMC_ADDITIONAL_MODUL 0x7000U /**< 0x70xx Additional Modules */ +#define CO_EMC_MONITORING 0x8000U /**< 0x80xx Monitoring */ +#define CO_EMC_COMMUNICATION 0x8100U /**< 0x81xx Communication */ +#define CO_EMC_CAN_OVERRUN 0x8110U /**< 0x8110 CAN Overrun (Objects lost) */ +#define CO_EMC_CAN_PASSIVE 0x8120U /**< 0x8120 CAN in Error Passive Mode */ +#define CO_EMC_HEARTBEAT 0x8130U /**< 0x8130 Life Guard Error or Heartbeat Error */ +#define CO_EMC_BUS_OFF_RECOVERED 0x8140U /**< 0x8140 recovered from bus off */ +#define CO_EMC_CAN_ID_COLLISION 0x8150U /**< 0x8150 CAN-ID collision */ +#define CO_EMC_PROTOCOL_ERROR 0x8200U /**< 0x82xx Protocol Error */ +#define CO_EMC_PDO_LENGTH 0x8210U /**< 0x8210 PDO not processed due to length error */ +#define CO_EMC_PDO_LENGTH_EXC 0x8220U /**< 0x8220 PDO length exceeded */ +#define CO_EMC_DAM_MPDO 0x8230U /**< 0x8230 DAM MPDO not processed destination object not available */ +#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /**< 0x8240 Unexpected SYNC data length */ +#define CO_EMC_RPDO_TIMEOUT 0x8250U /**< 0x8250 RPDO timeout */ +#define CO_EMC_EXTERNAL_ERROR 0x9000U /**< 0x90xx External Error */ +#define CO_EMC_ADDITIONAL_FUNC 0xF000U /**< 0xF0xx Additional Functions */ +#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /**< 0xFFxx Device specific */ + +#define CO_EMC401_OUT_CUR_HI 0x2310U /**< 0x2310 DS401 Current at outputs too high (overload) */ +#define CO_EMC401_OUT_SHORTED 0x2320U /**< 0x2320 DS401 Short circuit at outputs */ +#define CO_EMC401_OUT_LOAD_DUMP 0x2330U /**< 0x2330 DS401 Load dump at outputs */ +#define CO_EMC401_IN_VOLT_HI 0x3110U /**< 0x3110 DS401 Input voltage too high */ +#define CO_EMC401_IN_VOLT_LOW 0x3120U /**< 0x3120 DS401 Input voltage too low */ +#define CO_EMC401_INTERN_VOLT_HI 0x3210U /**< 0x3210 DS401 Internal voltage too high */ +#define CO_EMC401_INTERN_VOLT_LO 0x3220U /**< 0x3220 DS401 Internal voltage too low */ +#define CO_EMC401_OUT_VOLT_HIGH 0x3310U /**< 0x3310 DS401 Output voltage too high */ +#define CO_EMC401_OUT_VOLT_LOW 0x3320U /**< 0x3320 DS401 Output voltage too low */ /** @} */ /* CO_EM_errorCode_t */ @@ -175,90 +167,77 @@ extern "C" { * @defgroup CO_EM_errorStatusBits_t Error status bits * @{ * - * Bits for internal indication of the error condition. Each error condition is - * specified by unique index from 0x00 up to 0xFF. + * Bits for internal indication of the error condition. Each error condition is specified by unique index from 0x00 up + * to 0xFF. * - * If specific error occurs in the stack or in the application, CO_errorReport() - * sets specific bit in the _errorStatusBit_ variable from @ref CO_EM_t. If bit - * was already set, function returns without any action. Otherwise it prepares - * emergency message. + * If specific error occurs in the stack or in the application, CO_errorReport() sets specific bit in the + * _errorStatusBit_ variable from @ref CO_EM_t. If bit was already set, function returns without any action. Otherwise + * it prepares emergency message. * - * Maximum size (in bits) of the _errorStatusBit_ variable is specified by - * @ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (set to 10*8 bits by default). Stack - * uses first 6 bytes. Additional 4 bytes are pre-defined for manufacturer - * or device specific error indications, by default. + * Maximum size (in bits) of the _errorStatusBit_ variable is specified by @ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT (set + * to 10*8 bits by default). Stack uses first 6 bytes. Additional 4 bytes are pre-defined for manufacturer or device + * specific error indications, by default. */ -#define CO_EM_NO_ERROR 0x00U /**< 0x00 Error Reset or No Error */ -#define CO_EM_CAN_BUS_WARNING 0x01U /**< 0x01 communication info CAN bus warning limit reached */ -#define CO_EM_RXMSG_WRONG_LENGTH \ - 0x02U /**< 0x02 communication info Wrong data length of the received CAN message */ -#define CO_EM_RXMSG_OVERFLOW \ - 0x03U /**< 0x03 communication info Previous received CAN message wasn't processed yet */ -#define CO_EM_RPDO_WRONG_LENGTH 0x04U /**< 0x04 communication info Wrong data length of received PDO */ -#define CO_EM_RPDO_OVERFLOW 0x05U /**< 0x05 communication info Previous received PDO wasn't processed yet */ -#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /**< 0x06 communication info CAN receive bus is passive */ -#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /**< 0x07 communication info CAN transmit bus is passive */ -#define CO_EM_NMT_WRONG_COMMAND 0x08U /**< 0x08 communication info Wrong NMT command received */ -#define CO_EM_TIME_TIMEOUT 0x09U /**< 0x09 communication info TIME message timeout */ -#define CO_EM_0A_unused 0x0AU /**< 0x0A communication info (unused) */ -#define CO_EM_0B_unused 0x0BU /**< 0x0B communication info (unused) */ -#define CO_EM_0C_unused 0x0CU /**< 0x0C communication info (unused) */ -#define CO_EM_0D_unused 0x0DU /**< 0x0D communication info (unused) */ -#define CO_EM_0E_unused 0x0EU /**< 0x0E communication info (unused) */ -#define CO_EM_0F_unused 0x0FU /**< 0x0F communication info (unused) */ - -#define CO_EM_10_unused 0x10U /**< 0x10 communication critical (unused) */ -#define CO_EM_11_unused 0x11U /**< 0x11 communication critical (unused) */ -#define CO_EM_CAN_TX_BUS_OFF 0x12U /**< 0x12 communication critical CAN transmit bus is off */ -#define CO_EM_CAN_RXB_OVERFLOW 0x13U /**< 0x13 communication critical CAN module receive buffer has overflowed \ - */ -#define CO_EM_CAN_TX_OVERFLOW 0x14U /**< 0x14 communication critical CAN transmit buffer has overflowed */ -#define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /**< 0x15 communication critical TPDO is outside SYNC window */ -#define CO_EM_16_unused 0x16U /**< 0x16 communication critical (unused) */ -#define CO_EM_RPDO_TIME_OUT 0x17U /**< 0x17 communication critical RPDO message timeout */ -#define CO_EM_SYNC_TIME_OUT 0x18U /**< 0x18 communication critical SYNC message timeout */ -#define CO_EM_SYNC_LENGTH 0x19U /**< 0x19 communication critical Unexpected SYNC data length */ -#define CO_EM_PDO_WRONG_MAPPING 0x1AU /**< 0x1A communication critical Error with PDO mapping */ -#define CO_EM_HEARTBEAT_CONSUMER 0x1BU /**< 0x1B communication critical Heartbeat consumer timeout */ -#define CO_EM_HB_CONSUMER_REMOTE_RESET \ - 0x1CU /**< 0x1C communication critical Heartbeat consumer detected remote node reset */ -#define CO_EM_SRDO_CONFIGURATION 0x1DU /**< 0x1D communication critical Error in SRDO configuration parameters. \ - */ -#define CO_EM_1E_unused 0x1EU /**< 0x1E communication critical (unused) */ -#define CO_EM_1F_unused 0x1FU /**< 0x1F communication critical (unused) */ - -#define CO_EM_EMERGENCY_BUFFER_FULL \ - 0x20U /**< 0x20 generic info Emergency buffer is full Emergency message wasn't sent */ -#define CO_EM_21_unused 0x21U /**< 0x21 generic info (unused) */ -#define CO_EM_MICROCONTROLLER_RESET 0x22U /**< 0x22 generic info Microcontroller has just started */ -#define CO_EM_23_unused 0x23U /**< 0x23 generic info (unused) */ -#define CO_EM_24_unused 0x24U /**< 0x24 generic info (unused) */ -#define CO_EM_25_unused 0x25U /**< 0x25 generic info (unused) */ -#define CO_EM_26_unused 0x26U /**< 0x26 generic info (unused) */ -#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /**< 0x27 generic info Automatic store to non-volatile memory failed \ - */ - -#define CO_EM_WRONG_ERROR_REPORT 0x28U /**< 0x28 generic critical Wrong parameters to CO_errorReport() \ - function*/ -#define CO_EM_ISR_TIMER_OVERFLOW 0x29U /**< 0x29 generic critical Timer task has overflowed */ -#define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /**< 0x2A generic critical Unable to allocate memory for objects */ -#define CO_EM_GENERIC_ERROR 0x2BU /**< 0x2B generic critical Generic error test usage */ -#define CO_EM_GENERIC_SOFTWARE_ERROR 0x2CU /**< 0x2C generic critical Software error */ -#define CO_EM_INCONSISTENT_OBJECT_DICT \ - 0x2DU /**< 0x2D generic critical Object dictionary does not match the software*/ -#define CO_EM_CALCULATION_OF_PARAMETERS \ - 0x2EU /**< 0x2E generic critical Error in calculation of device parameters */ -#define CO_EM_NON_VOLATILE_MEMORY \ - 0x2FU /**< 0x2F generic critical Error with access to non volatile device memory */ - -/** 0x30+ manufacturer info or critical Error status buts free to use by - * manufacturer. By default bits 0x30..0x3F are set as informational and - * bits 0x40..0x4F are set as critical. Manufacturer critical bits sets the - * error register as specified by @ref CO_CONFIG_ERR_CONDITION_MANUFACTURER +#define CO_EM_NO_ERROR 0x00U /**< 0x00 Error Reset or No Error */ +#define CO_EM_CAN_BUS_WARNING 0x01U /**< 0x01 communication info CAN bus warning limit reached */ +#define CO_EM_RXMSG_WRONG_LENGTH 0x02U /**< 0x02 communication info Wrong data length of the received CAN message */ +#define CO_EM_RXMSG_OVERFLOW 0x03U /**< 0x03 communication info Previous received CAN message wasn't processed */ +#define CO_EM_RPDO_WRONG_LENGTH 0x04U /**< 0x04 communication info Wrong data length of received PDO */ +#define CO_EM_RPDO_OVERFLOW 0x05U /**< 0x05 communication info Previous received PDO wasn't processed yet */ +#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /**< 0x06 communication info CAN receive bus is passive */ +#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /**< 0x07 communication info CAN transmit bus is passive */ +#define CO_EM_NMT_WRONG_COMMAND 0x08U /**< 0x08 communication info Wrong NMT command received */ +#define CO_EM_TIME_TIMEOUT 0x09U /**< 0x09 communication info TIME message timeout */ +#define CO_EM_0A_unused 0x0AU /**< 0x0A communication info (unused) */ +#define CO_EM_0B_unused 0x0BU /**< 0x0B communication info (unused) */ +#define CO_EM_0C_unused 0x0CU /**< 0x0C communication info (unused) */ +#define CO_EM_0D_unused 0x0DU /**< 0x0D communication info (unused) */ +#define CO_EM_0E_unused 0x0EU /**< 0x0E communication info (unused) */ +#define CO_EM_0F_unused 0x0FU /**< 0x0F communication info (unused) */ + +#define CO_EM_10_unused 0x10U /**< 0x10 communication critical (unused) */ +#define CO_EM_11_unused 0x11U /**< 0x11 communication critical (unused) */ +#define CO_EM_CAN_TX_BUS_OFF 0x12U /**< 0x12 communication critical CAN transmit bus is off */ +#define CO_EM_CAN_RXB_OVERFLOW 0x13U /**< 0x13 communication critical CAN module receive buffer overflowed */ +#define CO_EM_CAN_TX_OVERFLOW 0x14U /**< 0x14 communication critical CAN transmit buffer overflowed */ +#define CO_EM_TPDO_OUTSIDE_WINDOW 0x15U /**< 0x15 communication critical TPDO is outside SYNC window */ +#define CO_EM_16_unused 0x16U /**< 0x16 communication critical (unused) */ +#define CO_EM_RPDO_TIME_OUT 0x17U /**< 0x17 communication critical RPDO message timeout */ +#define CO_EM_SYNC_TIME_OUT 0x18U /**< 0x18 communication critical SYNC message timeout */ +#define CO_EM_SYNC_LENGTH 0x19U /**< 0x19 communication critical Unexpected SYNC data length */ +#define CO_EM_PDO_WRONG_MAPPING 0x1AU /**< 0x1A communication critical Error with PDO mapping */ +#define CO_EM_HEARTBEAT_CONSUMER 0x1BU /**< 0x1B communication critical Heartbeat consumer timeout */ +#define CO_EM_HB_CONSUMER_REMOTE_RESET 0x1CU /**< 0x1C comm. critical Heartbeat consumer detected remote node reset */ +#define CO_EM_SRDO_CONFIGURATION 0x1DU /**< 0x1D communication critical Error in SRDO configuration parameters */ +#define CO_EM_1E_unused 0x1EU /**< 0x1E communication critical (unused) */ +#define CO_EM_1F_unused 0x1FU /**< 0x1F communication critical (unused) */ + +#define CO_EM_EMERGENCY_BUFFER_FULL 0x20U /**< 0x20 generic info Emergency buffer is full or message wasn't sent */ +#define CO_EM_21_unused 0x21U /**< 0x21 generic info (unused) */ +#define CO_EM_MICROCONTROLLER_RESET 0x22U /**< 0x22 generic info Microcontroller has just started */ +#define CO_EM_23_unused 0x23U /**< 0x23 generic info (unused) */ +#define CO_EM_24_unused 0x24U /**< 0x24 generic info (unused) */ +#define CO_EM_25_unused 0x25U /**< 0x25 generic info (unused) */ +#define CO_EM_26_unused 0x26U /**< 0x26 generic info (unused) */ +#define CO_EM_NON_VOLATILE_AUTO_SAVE 0x27U /**< 0x27 generic info Automatic store to non-volatile memory failed */ + +#define CO_EM_WRONG_ERROR_REPORT 0x28U /**< 0x28 generic critical Wrong parameters to CO_errorReport() */ +#define CO_EM_ISR_TIMER_OVERFLOW 0x29U /**< 0x29 generic critical Timer task has overflowed */ +#define CO_EM_MEMORY_ALLOCATION_ERROR 0x2AU /**< 0x2A generic critical Unable to allocate memory for objects */ +#define CO_EM_GENERIC_ERROR 0x2BU /**< 0x2B generic critical Generic error test usage */ +#define CO_EM_GENERIC_SOFTWARE_ERROR 0x2CU /**< 0x2C generic critical Software error */ +#define CO_EM_INCONSISTENT_OBJECT_DICT 0x2DU /**< 0x2D generic critical Object dict. does not match the software */ +#define CO_EM_CALCULATION_OF_PARAMETERS 0x2EU /**< 0x2E generic critical Error in calculation of device parameters */ +#define CO_EM_NON_VOLATILE_MEMORY 0x2FU /**< 0x2F generic critical Error with access to non volatile memory */ + +/** + * 0x30+ manufacturer info or critical Error status buts free to use by manufacturer. By default bits 0x30..0x3F are set + * as informational and bits 0x40..0x4F are set as critical. Manufacturer critical bits sets the error register as + * specified by @ref CO_CONFIG_ERR_CONDITION_MANUFACTURER */ -#define CO_EM_MANUFACTURER_START 0x30U -/** (@ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1) largest value of the Error status bit. */ -#define CO_EM_MANUFACTURER_END (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1U) +#define CO_EM_MANUFACTURER_START 0x30U +/** (@ref CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1) largest value of the Error status bit. */ +#define CO_EM_MANUFACTURER_END (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT - 1U) /** @} */ /* CO_EM_errorStatusBits_t */ @@ -278,84 +257,59 @@ typedef struct { * Emergency object. */ typedef struct { - /** Bitfield for the internal indication of the error condition. */ - uint8_t errorStatusBits[CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U]; - /** Pointer to error register in object dictionary at 0x1001,00. */ - uint8_t* errorRegister; - /** Old CAN error status bitfield */ - uint16_t CANerrorStatusOld; - /** From CO_EM_init() */ - CO_CANmodule_t* CANdevTx; + uint8_t errorStatusBits[CO_CONFIG_EM_ERR_STATUS_BITS_COUNT / 8U]; /**< Bitfield for the internal indication of + the error condition. */ + uint8_t* errorRegister; /**< Pointer to error register in object dictionary at 0x1001,00. */ + uint16_t CANerrorStatusOld; /**< Old CAN error status bitfield */ + CO_CANmodule_t* CANdevTx; /**< From CO_EM_init() */ #if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) || defined CO_DOXYGEN - /** Internal circular FIFO buffer for storing pre-processed emergency - * messages. Messages are added by @ref CO_error() function. All messages - * are later post-processed by @ref CO_EM_process() function. In case of - * overflow, error is indicated but emergency message is not sent. Fifo is - * also used for error history, OD object 0x1003, "Pre-defined error field". - * Buffer is defined by @ref CO_EM_init(). */ - CO_EM_fifo_t* fifo; - /** Size of the above buffer, specified by @ref CO_EM_init(). */ - uint8_t fifoSize; - /** Pointer for the fifo buffer, where next emergency message will be - * written by @ref CO_error() function. */ - uint8_t fifoWrPtr; - /** Pointer for the fifo, where next emergency message has to be - * post-processed by @ref CO_EM_process() function. If equal to bufWrPtr, - * then all messages has been post-processed. */ - uint8_t fifoPpPtr; - /** Indication of overflow - messages in buffer are not post-processed */ - uint8_t fifoOverflow; - /** Count of emergency messages in fifo, used for OD object 0x1003 */ - uint8_t fifoCount; -#endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ + CO_EM_fifo_t* + fifo; /**< Internal circular FIFO buffer for storing pre-processed emergency messages. Messages are added by + @ref CO_error() function. All messages are later post-processed by @ref CO_EM_process() function. In + case of overflow, error is indicated but emergency message is not sent. Fifo is also used for error + history, OD object 0x1003, "Pre-defined error field". Buffer is defined by @ref CO_EM_init(). */ + uint8_t fifoSize; /**< Size of the above buffer, specified by @ref CO_EM_init(). */ + uint8_t fifoWrPtr; /**< Pointer for the fifo buffer, where next emergency message will be written by @ref CO_error() + function. */ + uint8_t fifoPpPtr; /**< Pointer for the fifo, where next emergency message has to be post-processed by @ref + CO_EM_process() function. If equal to bufWrPtr, then all messages has been post-processed. */ + uint8_t fifoOverflow; /**< Indication of overflow - messages in buffer are not post-processed */ + uint8_t fifoCount; /**< Count of emergency messages in fifo, used for OD object 0x1003 */ +#endif /* (CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY) */ #if (((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN - /** True, if emergency producer is enabled, from Object dictionary */ - bool_t producerEnabled; - /** Copy of CANopen node ID, from CO_EM_init() */ - uint8_t nodeId; - /** CAN transmit buffer */ - CO_CANtx_t* CANtxBuff; - /** Extension for OD object */ - OD_extension_t OD_1014_extension; + bool_t producerEnabled; /**< True, if emergency producer is enabled, from Object dictionary */ + uint8_t nodeId; /**< Copy of CANopen node ID, from CO_EM_init() */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer */ + OD_extension_t OD_1014_extension; /**< Extension for OD object */ #if (((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_CONFIGURABLE) != 0) || defined CO_DOXYGEN - /** COB ID of emergency message, from Object dictionary */ - uint16_t producerCanId; - /** From CO_EM_init() */ - uint16_t CANdevTxIdx; + uint16_t producerCanId; /**< COB ID of emergency message, from Object dictionary */ + uint16_t CANdevTxIdx; /**< From CO_EM_init() */ #endif #if (((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0) || defined CO_DOXYGEN - /** Inhibit time for emergency message, from Object dictionary */ - uint32_t inhibitEmTime_us; - /**< Internal timer for inhibit time */ - uint32_t inhibitEmTimer; - /** Extension for OD object */ - OD_extension_t OD_1015_extension; + uint32_t inhibitEmTime_us; /**< Inhibit time for emergency message, from Object dictionary */ + uint32_t inhibitEmTimer; /**< Internal timer for inhibit time */ + OD_extension_t OD_1015_extension; /**< Extension for OD object */ #endif #endif /* (CO_CONFIG_EM) & CO_CONFIG_EM_PRODUCER */ #if (((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0) || defined CO_DOXYGEN - /** Extension for OD object */ - OD_extension_t OD_1003_extension; + OD_extension_t OD_1003_extension; /**< Extension for OD object */ #endif #if (((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0) || defined CO_DOXYGEN - /** Extension for OD object */ - OD_extension_t OD_statusBits_extension; + OD_extension_t OD_statusBits_extension; /**< Extension for OD object */ #endif #if (((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN - /** From CO_EM_initCallbackRx() or NULL */ void (*pFunctSignalRx)(const uint16_t ident, const uint16_t errorCode, const uint8_t errorRegister, - const uint8_t errorBit, const uint32_t infoCode); + const uint8_t errorBit, const uint32_t infoCode); /**< From CO_EM_initCallbackRx() or NULL */ #endif #if (((CO_CONFIG_EM)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_EM_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void* object); - /** From CO_EM_initCallbackPre() or NULL */ - void* functSignalObjectPre; + void (*pFunctSignalPre)(void* object); /**< From CO_EM_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< From CO_EM_initCallbackPre() or NULL */ #endif } CO_EM_t; @@ -365,27 +319,22 @@ typedef struct { * Function must be called in the communication reset section. * * @param em This object will be initialized. - * @param fifo Fifo buffer for emergency producer and error history. It must be - * defined externally. Its size must be capacity+1. See also @ref CO_EM_t, fifo. - * @param fifoSize Size of the above fifo buffer. It is usually equal to the - * length of the OD array 0x1003 + 1. If fifoSize is smaller than 2, then - * emergency producer and error history will not work and 'fifo' may be NULL. + * @param fifo Fifo buffer for emergency producer and error history. It must be defined externally. Its size must be + * capacity+1. See also @ref CO_EM_t, fifo. + * @param fifoSize Size of the above fifo buffer. It is usually equal to the length of the OD array 0x1003 + 1. If + * fifoSize is smaller than 2, then emergency producer and error history will not work and 'fifo' may be NULL. * @param CANdevTx CAN device for Emergency transmission. - * @param OD_1001_errReg OD entry for 0x1001 - "Error register", entry is - * required, without IO extension. - * @param OD_1014_cobIdEm OD entry for 0x1014 - "COB-ID EMCY", entry is - * required, IO extension is required. + * @param OD_1001_errReg OD entry for 0x1001 - "Error register", entry is required, without IO extension. + * @param OD_1014_cobIdEm OD entry for 0x1014 - "COB-ID EMCY", entry is required, IO extension is required. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. - * @param OD_1015_InhTime OD entry for 0x1015 - "Inhibit time EMCY", entry is - * optional (can be NULL), IO extension is optional for runtime configuration. - * @param OD_1003_preDefErr OD entry for 0x1003 - "Pre-defined error field". - * Emergency object has own memory buffer for this entry. Entry is optional, - * IO extension is required. + * @param OD_1015_InhTime OD entry for 0x1015 - "Inhibit time EMCY", entry is optional (can be NULL), IO extension is + * optional for runtime configuration. + * @param OD_1003_preDefErr OD entry for 0x1003 - "Pre-defined error field". Emergency object has own memory buffer for + * this entry. Entry is optional, IO extension is required. * @param OD_statusBits Custom OD entry for accessing errorStatusBits from - * @ref CO_EM_t. Entry must have variable of size - * (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT/8) bytes available for read/write access - * on subindex 0. Emergency object has own memory buffer for this entry. Entry - * is optional, IO extension is required. + * @ref CO_EM_t. Entry must have variable of size (CO_CONFIG_EM_ERR_STATUS_BITS_COUNT/8) bytes available for read/write + * access on subindex 0. Emergency object has own memory buffer for this entry. Entry is optional, IO extension is + * required. * @param CANdevRx CAN device for Emergency consumer reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param nodeId CANopen node ID of this device (for default emergency producer) @@ -418,15 +367,12 @@ CO_ReturnError_t CO_EM_init(CO_EM_t* em, CO_CANmodule_t* CANdevTx, const OD_entr /** * Initialize Emergency callback function. * - * Function initializes optional callback function, which should immediately - * start processing of CO_EM_process() function. - * Callback is called from CO_errorReport() or CO_errorReset() function. Those - * functions are fast and may be called from any thread. Callback should - * immediately start mainline thread, which calls CO_EM_process() function. + * Function initializes optional callback function, which should immediately start processing of CO_EM_process() + * function. Callback is called from CO_errorReport() or CO_errorReset() function. Those functions are fast and may be + * called from any thread. Callback should immediately start mainline thread, which calls CO_EM_process() function. * * @param em This object. - * @param object Pointer to object, which will be passed to pFunctSignal(). Can - * be NULL + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_EM_initCallbackPre(CO_EM_t* em, void* object, void (*pFunctSignal)(void* object)); @@ -436,14 +382,13 @@ void CO_EM_initCallbackPre(CO_EM_t* em, void* object, void (*pFunctSignal)(void* /** * Initialize Emergency received callback function. * - * Function initializes optional callback function, which executes after - * error condition is received. + * Function initializes optional callback function, which executes after error condition is received. * - * _ident_ argument from callback contains CAN-ID of the emergency message. If - * _ident_ == 0, then emergency message was sent from this device. + * _ident_ argument from callback contains CAN-ID of the emergency message. If _ident_ == 0, then emergency message was + * sent from this device. * - * @remark Depending on the CAN driver implementation, this function is called - * inside an ISR or inside a mainline. Must be thread safe. + * @remark Depending on the CAN driver implementation, this function is called inside an ISR or inside a mainline. Must + * be thread safe. * * @param em This object. * @param pFunctSignalRx Pointer to the callback function. Not called if NULL. @@ -456,15 +401,12 @@ void CO_EM_initCallbackRx(CO_EM_t* em, void (*pFunctSignalRx)(const uint16_t ide /** * Process Error control and Emergency object. * - * Function must be called cyclically. It verifies some communication errors, - * calculates OD object 0x1001 - "Error register" and sends emergency message - * if necessary. + * Function must be called cyclically. It verifies some communication errors, calculates OD object 0x1001 - "Error + * register" and sends emergency message if necessary. * * @param em This object. - * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or - * NMT_OPERATIONAL state. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. + * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL state. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_EM_process(CO_EM_t* em, bool_t NMTisPreOrOperational, uint32_t timeDifference_us, uint32_t* timerNext_us); @@ -472,11 +414,10 @@ void CO_EM_process(CO_EM_t* em, bool_t NMTisPreOrOperational, uint32_t timeDiffe /** * Set or reset error condition. * - * Function can be called on any error condition inside CANopen stack or - * application. Function first checks change of error condition (setError is - * true and error bit wasn't set or setError is false and error bit was set - * before). If changed, then Emergency message is prepared and record in history - * is added. Emergency message is later sent by CO_EM_process() function. + * Function can be called on any error condition inside CANopen stack or application. Function first checks change of + * error condition (setError is true and error bit wasn't set or setError is false and error bit was set before). If + * changed, then Emergency message is prepared and record in history is added. Emergency message is later sent by + * CO_EM_process() function. * * Function is short and thread safe. * @@ -484,8 +425,8 @@ void CO_EM_process(CO_EM_t* em, bool_t NMTisPreOrOperational, uint32_t timeDiffe * @param setError True if error occurred or false if error resolved. * @param errorBit from @ref CO_EM_errorStatusBits_t. * @param errorCode from @ref CO_EM_errorCode_t. - * @param infoCode 32 bit value is passed to bytes 4...7 of the Emergency - * message. It contains optional additional information. + * @param infoCode 32 bit value is passed to bytes 4...7 of the Emergency message. It contains optional additional + * information. */ void CO_error(CO_EM_t* em, bool_t setError, const uint8_t errorBit, uint16_t errorCode, uint32_t infoCode); @@ -536,6 +477,6 @@ CO_getErrorRegister(CO_EM_t* em) { #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* CO_EMERGENCY_H */ diff --git a/301/CO_HBconsumer.h b/301/CO_HBconsumer.h index b3d1273b..904781e0 100644 --- a/301/CO_HBconsumer.h +++ b/301/CO_HBconsumer.h @@ -45,14 +45,12 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * Heartbeat consumer monitors Heartbeat messages from remote nodes. If any - * monitored node don't send his Heartbeat in specified time, Heartbeat consumer - * sends emergency message. If all monitored nodes are operational, then - * variable _allMonitoredOperational_ inside CO_HBconsumer_t is set to true. - * Monitoring starts after the reception of the first HeartBeat (not bootup). + * Heartbeat consumer monitors Heartbeat messages from remote nodes. If any monitored node don't send his Heartbeat in + * specified time, Heartbeat consumer sends emergency message. If all monitored nodes are operational, then variable + * _allMonitoredOperational_ inside CO_HBconsumer_t is set to true. Monitoring starts after the reception of the first + * HeartBeat (not bootup). * - * Heartbeat set up is done by writing to the OD registers 0x1016. - * To setup heartbeat consumer by application, use + * Heartbeat set up is done by writing to the OD registers 0x1016. To setup heartbeat consumer by application, use * @code ODR_t odRet = OD_set_u32(entry, subIndex, val, false); @endcode * * @see @ref CO_NMT_Heartbeat @@ -72,89 +70,61 @@ typedef enum { * One monitored node inside CO_HBconsumer_t. */ typedef struct { - /** Node Id of the monitored node */ - uint8_t nodeId; - /** NMT state of the remote node (Heartbeat payload) */ - CO_NMT_internalState_t NMTstate; - /** Current heartbeat monitoring state of the remote node */ - CO_HBconsumer_state_t HBstate; - /** Time since last heartbeat received */ - uint32_t timeoutTimer; - /** Consumer heartbeat time from OD */ - uint32_t time_us; - /** Indication if new Heartbeat message received from the CAN bus */ - volatile void* CANrxNew; + uint8_t nodeId; /**< Node Id of the monitored node */ + CO_NMT_internalState_t NMTstate; /**< NMT state of the remote node (Heartbeat payload) */ + CO_HBconsumer_state_t HBstate; /**< Current heartbeat monitoring state of the remote node */ + uint32_t timeoutTimer; /**< Time since last heartbeat received */ + uint32_t time_us; /**< Consumer heartbeat time from OD */ + volatile void* CANrxNew; /**< Indication if new Heartbeat message received from the CAN bus */ #if (((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_HBconsumer_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void* object); - /** From CO_HBconsumer_initCallbackPre() or NULL */ - void* functSignalObjectPre; + void (*pFunctSignalPre)(void* object); /**< From CO_HBconsumer_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< From CO_HBconsumer_initCallbackPre() or NULL */ #endif #if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) \ || (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN - /** Previous value of the remote node (Heartbeat payload) */ - CO_NMT_internalState_t NMTstatePrev; + CO_NMT_internalState_t NMTstatePrev; /**< Previous value of the remote node (Heartbeat payload) */ #endif #if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_MULTI) != 0) || defined CO_DOXYGEN - /** Callback for remote NMT changed event. - * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ + /** Callback for remote NMT changed event. From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t NMTstate, void* object); - /** Pointer to object */ - void* pFunctSignalObjectNmtChanged; - /** Callback for heartbeat state change to active event. - * From CO_HBconsumer_initCallbackHeartbeatStarted() or NULL. */ + void* pFunctSignalObjectNmtChanged; /**< Pointer to object */ + /** Callback for heartbeat state change to active event. From CO_HBconsumer_initCallbackHeartbeatStarted() or NULL. + */ void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void* object); - /** Pointer to object */ - void* functSignalObjectHbStarted; - /** Callback for consumer timeout event. - * From CO_HBconsumer_initCallbackTimeout() or NULL. */ + void* functSignalObjectHbStarted; /**< Pointer to object */ + /** Callback for consumer timeout event. From CO_HBconsumer_initCallbackTimeout() or NULL. */ void (*pFunctSignalTimeout)(uint8_t nodeId, uint8_t idx, void* object); - /** Pointer to object */ - void* functSignalObjectTimeout; - /** Callback for remote reset event. - * From CO_HBconsumer_initCallbackRemoteReset() or NULL. */ + void* functSignalObjectTimeout; /**< Pointer to object */ + /** Callback for remote reset event. From CO_HBconsumer_initCallbackRemoteReset() or NULL. */ void (*pFunctSignalRemoteReset)(uint8_t nodeId, uint8_t idx, void* object); - /** Pointer to object */ - void* functSignalObjectRemoteReset; + void* functSignalObjectRemoteReset; /**< Pointer to object */ #endif } CO_HBconsNode_t; /** * Heartbeat consumer object. * - * Object is initilaized by CO_HBconsumer_init(). It contains an array of - * CO_HBconsNode_t objects. + * Object is initilaized by CO_HBconsumer_init(). It contains an array of CO_HBconsNode_t objects. */ typedef struct { - /** From CO_HBconsumer_init() */ - CO_EM_t* em; - /** Array of monitored nodes, from CO_HBconsumer_init() */ - CO_HBconsNode_t* monitoredNodes; - /** Actual number of monitored nodes, size-of-the-above-array or - * number-of-array-elements-in-OD-0x1016, whichever is smaller. */ - uint8_t numberOfMonitoredNodes; - /** True, if all monitored nodes are active or no node is monitored. Can be - * read by the application */ - bool_t allMonitoredActive; - /** True, if all monitored nodes are NMT operational or no node is - * monitored. Can be read by the application */ - bool_t allMonitoredOperational; - /** previous state of the variable */ - bool_t NMTisPreOrOperationalPrev; - /** From CO_HBconsumer_init() */ - CO_CANmodule_t* CANdevRx; - /** From CO_HBconsumer_init() */ - uint16_t CANdevRxIdxStart; + CO_EM_t* em; /**< From CO_HBconsumer_init() */ + CO_HBconsNode_t* monitoredNodes; /**< Array of monitored nodes, from CO_HBconsumer_init() */ + uint8_t numberOfMonitoredNodes; /**< Actual number of monitored nodes, size-of-the-above-array or + number-of-array-elements-in-OD-0x1016, whichever is smaller. */ + bool_t allMonitoredActive; /**< True, if all monitored nodes are active or no node is monitored. Can be read + by the application */ + bool_t allMonitoredOperational; /**< True, if all monitored nodes are NMT operational or no node is monitored. Can + be read by the application */ + bool_t NMTisPreOrOperationalPrev; /**< previous state of the variable */ + CO_CANmodule_t* CANdevRx; /**< From CO_HBconsumer_init() */ + uint16_t CANdevRxIdxStart; /**< From CO_HBconsumer_init() */ #if (((CO_CONFIG_HB_CONS)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN - /** Extension for OD object */ - OD_extension_t OD_1016_extension; + OD_extension_t OD_1016_extension; /**< Extension for OD object */ #endif #if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN - /** Callback for remote NMT changed event. - * From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ + /** Callback for remote NMT changed event. From CO_HBconsumer_initCallbackNmtChanged() or NULL. */ void (*pFunctSignalNmtChanged)(uint8_t nodeId, uint8_t idx, CO_NMT_internalState_t NMTstate, void* object); - /** Pointer to object */ - void* pFunctSignalObjectNmtChanged; + void* pFunctSignalObjectNmtChanged; /**< Pointer to object */ #endif } CO_HBconsumer_t; @@ -166,13 +136,13 @@ typedef struct { * @param HBcons This object will be initialized. * @param em Emergency object. * @param monitoredNodes Array of monitored nodes, must be defined externally. - * @param monitoredNodesCount Size of the above array, usually equal to number - * of array elements in OD 0x1016, valid values are 1 to 127 - * @param OD_1016_HBcons OD entry for 0x1016 - "Consumer heartbeat time", entry - * is required, IO extension will be applied. + * @param monitoredNodesCount Size of the above array, usually equal to number of array elements in OD 0x1016, valid + * values are 1 to 127 + * @param OD_1016_HBcons OD entry for 0x1016 - "Consumer heartbeat time", entry is required, IO extension will be + * applied. * @param CANdevRx CAN device for Heartbeat reception. - * @param CANdevRxIdxStart Starting index of receive buffer in the above CAN - * device. Number of used indexes is equal to monitoredNodesCount. + * @param CANdevRxIdxStart Starting index of receive buffer in the above CAN device. Number of used indexes is equal to + * monitoredNodesCount. * @param [out] errInfo Additional information in case of error, may be NULL. * * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. @@ -185,9 +155,8 @@ CO_ReturnError_t CO_HBconsumer_init(CO_HBconsumer_t* HBcons, CO_EM_t* em, CO_HBc /** * Initialize Heartbeat consumer callback function. * - * Function initializes optional callback function, which should immediately - * start processing of CO_HBconsumer_process() function. - * Callback is called after HBconsumer message is received from the CAN bus. + * Function initializes optional callback function, which should immediately start processing of CO_HBconsumer_process() + * function. Callback is called after HBconsumer message is received from the CAN bus. * * @param HBcons This object. * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL @@ -201,14 +170,11 @@ void CO_HBconsumer_initCallbackPre(CO_HBconsumer_t* HBcons, void* object, void ( /** * Initialize Heartbeat consumer NMT changed callback function. * - * Function initializes optional callback function, which is called when NMT - * state from the remote node changes. + * Function initializes optional callback function, which is called when NMT state from the remote node changes. * * @param HBcons This object. - * @param idx index of the node in HBcons object (only when - * CO_CONFIG_HB_CONS_CALLBACK_MULTI is enabled) - * @param object Pointer to object, which will be passed to pFunctSignal(). - * Can be NULL. + * @param idx index of the node in HBcons object (only when CO_CONFIG_HB_CONS_CALLBACK_MULTI is enabled) + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL. * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_HBconsumer_initCallbackNmtChanged(CO_HBconsumer_t* HBcons, uint8_t idx, void* object, @@ -220,9 +186,8 @@ void CO_HBconsumer_initCallbackNmtChanged(CO_HBconsumer_t* HBcons, uint8_t idx, /** * Initialize Heartbeat consumer started callback function. * - * Function initializes optional callback function, which is called for the - * first received heartbeat after activating hb consumer or timeout. - * Function may wake up external task, which handles this event. + * Function initializes optional callback function, which is called for the first received heartbeat after activating hb + * consumer or timeout. Function may wake up external task, which handles this event. * * @param HBcons This object. * @param idx index of the node in HBcons object @@ -235,9 +200,8 @@ void CO_HBconsumer_initCallbackHeartbeatStarted(CO_HBconsumer_t* HBcons, uint8_t /** * Initialize Heartbeat consumer timeout callback function. * - * Function initializes optional callback function, which is called when the node - * state changes from active to timeout. Function may wake up external task, - * which handles this event. + * Function initializes optional callback function, which is called when the node state changes from active to timeout. + * Function may wake up external task, which handles this event. * * @param HBcons This object. * @param idx index of the node in HBcons object @@ -250,9 +214,8 @@ void CO_HBconsumer_initCallbackTimeout(CO_HBconsumer_t* HBcons, uint8_t idx, voi /** * Initialize Heartbeat consumer remote reset detected callback function. * - * Function initializes optional callback function, which is called when a bootup - * message is received from the remote node. Function may wake up external task, - * which handles this event. + * Function initializes optional callback function, which is called when a bootup message is received from the remote + * node. Function may wake up external task, which handles this event. * * @param HBcons This object. * @param idx index of the node in HBcons object @@ -314,7 +277,7 @@ int8_t CO_HBconsumer_getNmtState(CO_HBconsumer_t* HBcons, uint8_t idx, CO_NMT_in #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE */ diff --git a/301/CO_NMT_Heartbeat.h b/301/CO_NMT_Heartbeat.h index dad353b1..feff1865 100644 --- a/301/CO_NMT_Heartbeat.h +++ b/301/CO_NMT_Heartbeat.h @@ -46,8 +46,7 @@ extern "C" { * - Operational. Process data objects (PDOs) are active too. * - Stopped. Only Heartbeat producer and NMT consumer are active. * - * NMT master can change the internal state of the devices by sending - * @ref CO_NMT_command_t. + * NMT master can change the internal state of the devices by sending @ref CO_NMT_command_t. * * ### NMT message contents: * @@ -69,84 +68,64 @@ extern "C" { * Internal network state of the CANopen node */ typedef enum { - /** -1, Device state is unknown (for heartbeat consumer) */ - CO_NMT_UNKNOWN = -1, - /** 0, Device is initializing */ - CO_NMT_INITIALIZING = 0, - /** 127, Device is in pre-operational state */ - CO_NMT_PRE_OPERATIONAL = 127, - /** 5, Device is in operational state */ - CO_NMT_OPERATIONAL = 5, - /** 4, Device is stopped */ - CO_NMT_STOPPED = 4 + CO_NMT_UNKNOWN = -1, /**< -1, Device state is unknown (for heartbeat consumer) */ + CO_NMT_INITIALIZING = 0, /**< 0, Device is initializing */ + CO_NMT_PRE_OPERATIONAL = 127, /**< 127, Device is in pre-operational state */ + CO_NMT_OPERATIONAL = 5, /**< 5, Device is in operational state */ + CO_NMT_STOPPED = 4 /**< 4, Device is stopped */ } CO_NMT_internalState_t; /** * Commands from NMT master. */ typedef enum { - /** 0, No command */ - CO_NMT_NO_COMMAND = 0, - /** 1, Start device */ - CO_NMT_ENTER_OPERATIONAL = 1, - /** 2, Stop device */ - CO_NMT_ENTER_STOPPED = 2, - /** 128, Put device into pre-operational */ - CO_NMT_ENTER_PRE_OPERATIONAL = 128, - /** 129, Reset device */ - CO_NMT_RESET_NODE = 129, - /** 130, Reset CANopen communication on device */ - CO_NMT_RESET_COMMUNICATION = 130 + CO_NMT_NO_COMMAND = 0, /**< 0, No command */ + CO_NMT_ENTER_OPERATIONAL = 1, /**< 1, Start device */ + CO_NMT_ENTER_STOPPED = 2, /**< 2, Stop device */ + CO_NMT_ENTER_PRE_OPERATIONAL = 128, /**< 128, Put device into pre-operational */ + CO_NMT_RESET_NODE = 129, /**< 129, Reset device */ + CO_NMT_RESET_COMMUNICATION = 130 /**< 130, Reset CANopen communication on device */ } CO_NMT_command_t; /** - * Return code from CO_NMT_process() that tells application code what to - * reset. + * Return code from CO_NMT_process() that tells application code what to reset. */ typedef enum { - /** 0, Normal return, no action */ - CO_RESET_NOT = 0, - /** 1, Application must provide communication reset. */ - CO_RESET_COMM = 1, - /** 2, Application must provide complete device reset */ - CO_RESET_APP = 2, - /** 3, Application must quit, no reset of microcontroller (command is not - * requested by the stack.) */ - CO_RESET_QUIT = 3 + CO_RESET_NOT = 0, /**< 0, Normal return, no action */ + CO_RESET_COMM = 1, /**< 1, Application must provide communication reset. */ + CO_RESET_APP = 2, /**< 2, Application must provide complete device reset */ + CO_RESET_QUIT = 3 /**< 3, Application must quit, no reset of microcontroller (command is not requested by the + stack.) */ } CO_NMT_reset_cmd_t; /** * @defgroup CO_NMT_control_t NMT control bitfield for NMT internal state. * @{ * + * Variable of this type is passed to @ref CO_NMT_init() function. It controls behavior of the @ref + * CO_NMT_internalState_t of the device according to CANopen error register. * - * Variable of this type is passed to @ref CO_NMT_init() function. It - * controls behavior of the @ref CO_NMT_internalState_t of the device according - * to CANopen error register. - * - * Internal NMT state is controlled also with external NMT command, - * @ref CO_NMT_sendInternalCommand() or @ref CO_NMT_sendCommand() functions. + * Internal NMT state is controlled also with external NMT command, @ref CO_NMT_sendInternalCommand() or @ref + * CO_NMT_sendCommand() functions. */ -/** First 8 bits can be used to specify bitmask for the - * @ref CO_errorRegister_t to get relevant bits for the calculation. */ +/** First 8 bits can be used to specify bitmask for the @ref CO_errorRegister_t to get relevant bits for the + * calculation. */ #define CO_NMT_ERR_REG_MASK 0x00FFU -/** If bit is set then device enters NMT operational state after the - * initialization phase otherwise it enters NMT pre-operational state. */ +/** If bit is set then device enters NMT operational state after the initialization phase otherwise it enters NMT + * pre-operational state. */ #define CO_NMT_STARTUP_TO_OPERATIONAL 0x0100U -/** If bit is set and device is operational it enters NMT pre-operational - * or stopped state if CAN bus is off or heartbeat consumer timeout is - * detected. */ +/** If bit is set and device is operational it enters NMT pre-operational or stopped state if CAN bus is off or + * heartbeat consumer timeout is detected. */ #define CO_NMT_ERR_ON_BUSOFF_HB 0x1000U -/** If bit is set and device is operational it enters NMT pre-operational - * or stopped state if masked CANopen error register is different than - * zero. */ +/** If bit is set and device is operational it enters NMT pre-operational or stopped state if masked CANopen error + * register is different than zero. */ #define CO_NMT_ERR_ON_ERR_REG 0x2000U -/** If bit is set and CO_NMT_ERR_ON_xx condition is met then device will - * enter NMT stopped state otherwise it will enter NMT pre-op state. */ +/** If bit is set and CO_NMT_ERR_ON_xx condition is met then device will enter NMT stopped state otherwise it will enter + * NMT pre-op state. */ #define CO_NMT_ERR_TO_STOPPED 0x4000U -/** If bit is set and device is pre-operational it enters NMT operational - * state automatically if conditions from CO_NMT_ERR_ON_xx are all false.*/ +/** If bit is set and device is pre-operational it enters NMT operational state automatically if conditions from + * CO_NMT_ERR_ON_xx are all false. */ #define CO_NMT_ERR_FREE_TO_OPERATIONAL 0x8000U /** @} */ /* CO_NMT_control_t */ @@ -155,44 +134,28 @@ typedef enum { * NMT consumer and Heartbeat producer object */ typedef struct { - /** Current NMT operating state. */ - CO_NMT_internalState_t operatingState; - /** Previous NMT operating state. */ - CO_NMT_internalState_t operatingStatePrev; - /** NMT internal command from CO_NMT_receive() or CO_NMT_sendCommand(), - * processed in CO_NMT_process(). */ - CO_NMT_command_t internalCommand; - /** From CO_NMT_init() */ - uint8_t nodeId; - /** From CO_NMT_init() */ - uint16_t NMTcontrol; - /** Producer heartbeat time, calculated from OD 0x1017 */ - uint32_t HBproducerTime_us; - /** Internal timer for HB producer */ - uint32_t HBproducerTimer; - /** Extension for OD object */ - OD_extension_t OD_1017_extension; - /** From CO_NMT_init() */ - CO_EM_t* em; + CO_NMT_internalState_t operatingState; /**< Current NMT operating state. */ + CO_NMT_internalState_t operatingStatePrev; /**< Previous NMT operating state. */ + CO_NMT_command_t internalCommand; /**< NMT internal command from CO_NMT_receive() or CO_NMT_sendCommand(), processed + in CO_NMT_process(). */ + uint8_t nodeId; /**< From CO_NMT_init() */ + uint16_t NMTcontrol; /**< From CO_NMT_init() */ + uint32_t HBproducerTime_us; /**< Producer heartbeat time, calculated from OD 0x1017 */ + uint32_t HBproducerTimer; /**< Internal timer for HB producer */ + OD_extension_t OD_1017_extension; /**< Extension for OD object */ + CO_EM_t* em; /**< From CO_NMT_init() */ #if (((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0) || defined CO_DOXYGEN - /** From CO_NMT_init() */ - CO_CANmodule_t* NMT_CANdevTx; - /** CAN transmit buffer for NMT master message */ - CO_CANtx_t* NMT_TXbuff; + CO_CANmodule_t* NMT_CANdevTx; /**< From CO_NMT_init() */ + CO_CANtx_t* NMT_TXbuff; /**< CAN transmit buffer for NMT master message */ #endif - /** From CO_NMT_init() */ - CO_CANmodule_t* HB_CANdevTx; - /** CAN transmit buffer for heartbeat message */ - CO_CANtx_t* HB_TXbuff; + CO_CANmodule_t* HB_CANdevTx; /**< From CO_NMT_init() */ + CO_CANtx_t* HB_TXbuff; /**< CAN transmit buffer for heartbeat message */ #if (((CO_CONFIG_NMT)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_NMT_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void* object); - /** From CO_NMT_initCallbackPre() or NULL */ - void* functSignalObjectPre; + void (*pFunctSignalPre)(void* object); /**< From CO_NMT_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< From CO_NMT_initCallbackPre() or NULL */ #endif #if (((CO_CONFIG_NMT)&CO_CONFIG_NMT_CALLBACK_CHANGE) != 0) || defined CO_DOXYGEN - /** From CO_NMT_initCallbackChanged() or NULL */ - void (*pFunctNMT)(CO_NMT_internalState_t state); + void (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallbackChanged() or NULL */ #endif } CO_NMT_t; @@ -202,16 +165,15 @@ typedef struct { * Function must be called in the communication reset section. * * @param NMT This object will be initialized. - * @param OD_1017_ProducerHbTime OD entry for 0x1017 -"Producer heartbeat time", - * entry is required, IO extension is optional for runtime configuration. + * @param OD_1017_ProducerHbTime OD entry for 0x1017 -"Producer heartbeat time", entry is required, IO extension is + * optional for runtime configuration. * @param em Emergency object. * @param nodeId CANopen Node ID of this device. - * @param NMTcontrol Control variable for calculation of NMT internal state, - * based on error register, startup and runtime behavior. - * @param firstHBTime_ms Time between bootup and first heartbeat message in - * milliseconds. If firstHBTime_ms is greater than "Producer Heartbeat time" - * (OD object 0x1017), latter is used instead. Entry is required, IO extension - * is optional. + * @param NMTcontrol Control variable for calculation of NMT internal state, based on error register, startup and + * runtime behavior. + * @param firstHBTime_ms Time between bootup and first heartbeat message in milliseconds. If firstHBTime_ms is greater + * than "Producer Heartbeat time" (OD object 0x1017), latter is used instead. Entry is required, IO extension is + * optional. * @param NMT_CANdevRx CAN device for NMT reception. * @param NMT_rxIdx Index of receive buffer in above CAN device. * @param CANidRxNMT CAN identifier for NMT receive message. @@ -237,13 +199,11 @@ CO_ReturnError_t CO_NMT_init(CO_NMT_t* NMT, OD_entry_t* OD_1017_ProducerHbTime, /** * Initialize NMT callback function after message preprocessed. * - * Function initializes optional callback function, which should immediately - * start processing of CO_NMT_process() function. - * Callback is called after NMT message is received from the CAN bus. + * Function initializes optional callback function, which should immediately start processing of CO_NMT_process() + * function. Callback is called after NMT message is received from the CAN bus. * * @param NMT This object. - * @param object Pointer to object, which will be passed to pFunctSignal(). - * Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_NMT_initCallbackPre(CO_NMT_t* NMT, void* object, void (*pFunctSignal)(void* object)); @@ -253,10 +213,9 @@ void CO_NMT_initCallbackPre(CO_NMT_t* NMT, void* object, void (*pFunctSignal)(vo /** * Initialize NMT callback function. * - * Function initializes optional callback function, which is called after - * NMT State change has occurred. Function may wake up external task which - * handles NMT events. The first call is made immediately to give the consumer - * the current NMT state. + * Function initializes optional callback function, which is called after NMT State change has occurred. Function may + * wake up external task which handles NMT events. The first call is made immediately to give the consumer the current + * NMT state. * * @param NMT This object. * @param pFunctNMT Pointer to the callback function. Not called if NULL. @@ -271,8 +230,7 @@ void CO_NMT_initCallbackChanged(CO_NMT_t* NMT, void (*pFunctNMT)(CO_NMT_internal * * @param NMT This object. * @param [out] NMTstate If not NULL, CANopen NMT internal state is returned. - * @param timeDifference_us Time difference from previous function call in - * microseconds. + * @param timeDifference_us Time difference from previous function call in microseconds. * @param [out] timerNext_us info to OS - see CO_process(). * * @return #CO_NMT_reset_cmd_t @@ -311,11 +269,10 @@ CO_NMT_sendInternalCommand(CO_NMT_t* NMT, CO_NMT_command_t command) { /** * Send NMT master command. * - * This functionality may only be used from NMT master, as specified by - * standard CiA302-2. Standard provides one exception, where application from - * slave node may send NMT master command: "If CANopen object 0x1F80 has value - * of **0x2**, then NMT slave shall execute the NMT service start remote node - * (CO_NMT_ENTER_OPERATIONAL) with nodeID set to 0." + * This functionality may only be used from NMT master, as specified by standard CiA302-2. Standard provides one + * exception, where application from slave node may send NMT master command: "If CANopen object 0x1F80 has value of + * **0x2**, then NMT slave shall execute the NMT service start remote node (CO_NMT_ENTER_OPERATIONAL) with nodeID set to + * 0." * * @param NMT This object. * @param command NMT command from CO_NMT_command_t. @@ -331,6 +288,6 @@ CO_ReturnError_t CO_NMT_sendCommand(CO_NMT_t* NMT, CO_NMT_command_t command, uin #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* CO_NMT_HEARTBEAT_H */ diff --git a/301/CO_Node_Guarding.h b/301/CO_Node_Guarding.h index 1f7eba5c..467527da 100644 --- a/301/CO_Node_Guarding.h +++ b/301/CO_Node_Guarding.h @@ -41,16 +41,13 @@ extern "C" { #endif /** - * @defgroup CO_Node_Guarding Node Guarding - * CANopen Node Guarding, an older alternative to the Heartbeat protocol. + * @defgroup CO_Node_Guarding Node Guarding CANopen Node Guarding, an older alternative to the Heartbeat protocol. * * @ingroup CO_CANopen_301 * @{ - * Node guarding master pools each node guarding slave at time intervals, called - * guard time. Master sends a CAN RTR message, and slave responds. Slave also - * monitors presence of RTR message from master and indicates error, if it - * wasn't received within life time. ('Life time' is 'Guard time' multiplied by - * 'Life time factor'). + * Node guarding master pools each node guarding slave at time intervals, called guard time. Master sends a CAN RTR + * message, and slave responds. Slave also monitors presence of RTR message from master and indicates error, if it + * wasn't received within life time. ('Life time' is 'Guard time' multiplied by 'Life time factor'). * * Adding Node guarding to the project: * - Make sure, driver supports it. RTR bit should be part of CAN identifier. @@ -58,9 +55,8 @@ extern "C" { * - For slave add 0x100C and 0x100D objects to the Object dictionary. * - For master use CO_nodeGuardingMaster_initNode() to add monitored nodes. * - * @warning Usage of Node guarding is not recommended, as it is outdated and - * uses RTR CAN functionality, which is also not recommended. Use Heartbeat and - * Heartbeat consumer, if possible. + * @warning Usage of Node guarding is not recommended, as it is outdated and uses RTR CAN functionality, which is also + * not recommended. Use Heartbeat and Heartbeat consumer, if possible. * * ### Node Guarding slave response message contents: * @@ -76,30 +72,18 @@ extern "C" { * Node Guarding slave object */ typedef struct { - /** From CO_nodeGuardingSlave_init() */ - CO_EM_t* em; - /** Indicates, if new rtr message received from CAN bus */ - volatile void* CANrxNew; - /** Guard time in microseconds, calculated from OD_0x100C */ - uint32_t guardTime_us; - /** Life time in microseconds, calculated from guardTime_us * lifeTimeFactor */ - uint32_t lifeTime_us; - /** Timer for monitoring Life time, counting down from lifeTime_us. */ - uint32_t lifeTimer; - /** Life time factor, from OD_0x100D */ - uint8_t lifeTimeFactor; - /** Toggle bit for response */ - bool_t toggle; - /** True if rtr from master is missing */ - bool_t lifeTimeTimeout; - /** Extension for OD object */ - OD_extension_t OD_100C_extension; - /** Extension for OD object */ - OD_extension_t OD_100D_extension; - /** From CO_nodeGuardingSlave_init() */ - CO_CANmodule_t* CANdevTx; - /** CAN transmit buffer for the message */ - CO_CANtx_t* CANtxBuff; + CO_EM_t* em; /**< From CO_nodeGuardingSlave_init() */ + volatile void* CANrxNew; /**< Indicates, if new rtr message received from CAN bus */ + uint32_t guardTime_us; /**< Guard time in microseconds, calculated from OD_0x100C */ + uint32_t lifeTime_us; /**< Life time in microseconds, calculated from guardTime_us * lifeTimeFactor */ + uint32_t lifeTimer; /**< Timer for monitoring Life time, counting down from lifeTime_us. */ + uint8_t lifeTimeFactor; /**< Life time factor, from OD_0x100D */ + bool_t toggle; /**< Toggle bit for response */ + bool_t lifeTimeTimeout; /**< True if rtr from master is missing */ + OD_extension_t OD_100C_extension; /**< Extension for OD object */ + OD_extension_t OD_100D_extension; /**< Extension for OD object */ + CO_CANmodule_t* CANdevTx; /**< From CO_nodeGuardingSlave_init() */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer for the message */ } CO_nodeGuardingSlave_t; /** @@ -108,13 +92,11 @@ typedef struct { * Function must be called in the communication reset section. * * @param ngs This object will be initialized. - * @param OD_100C_GuardTime OD entry for 0x100C -"Guard time", - * entry is required. - * @param OD_100D_LifeTimeFactor OD entry for 0x100D -"Life time factor", - * entry is required. + * @param OD_100C_GuardTime OD entry for 0x100C -"Guard time", entry is required. + * @param OD_100D_LifeTimeFactor OD entry for 0x100D -"Life time factor", entry is required. * @param em Emergency object. - * @param CANidNodeGuarding CAN identifier for Node Guarding rtr and response - * message (usually CO_CAN_ID_HEARTBEAT + nodeId). + * @param CANidNodeGuarding CAN identifier for Node Guarding rtr and response message (usually CO_CAN_ID_HEARTBEAT + + * nodeId). * @param CANdevRx CAN device for Node Guarding rtr reception. * @param CANdevRxIdx Index of the receive buffer in the above CAN device. * @param CANdevTx CAN device for Node Guarding response transmission. @@ -136,8 +118,7 @@ CO_ReturnError_t CO_nodeGuardingSlave_init(CO_nodeGuardingSlave_t* ngs, OD_entry * @param ngs This object. * @param NMTstate NMT operating state. * @param slaveDisable If true, then Node guarding slave is disabled. - * @param timeDifference_us Time difference from previous function call in - * microseconds. + * @param timeDifference_us Time difference from previous function call in microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_nodeGuardingSlave_process(CO_nodeGuardingSlave_t* ngs, CO_NMT_internalState_t NMTstate, bool_t slaveDisable, @@ -161,7 +142,7 @@ CO_nodeGuardingSlave_isTimeout(CO_nodeGuardingSlave_t* ngs) { #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE */ @@ -184,44 +165,29 @@ extern "C" { * Node Guarding master - monitored node */ typedef struct { - /** Guard time in microseconds */ - uint32_t guardTime_us; - /** Guard timer in microseconds, counting down */ - uint32_t guardTimer; - /** CAN identifier (CO_CAN_ID_HEARTBEAT + Node Id) */ - uint16_t ident; - /** NMT operating state */ - CO_NMT_internalState_t NMTstate; - /** toggle bit7, expected from the next received message */ - uint8_t toggle; - /** True, if response was received since last rtr message */ - bool_t responseRecived; - /** True, if CANtxBuff was busy since last processing */ - bool_t CANtxWasBusy; - /** True, if monitoring is active (response within time). */ - bool_t monitoringActive; + uint32_t guardTime_us; /**< Guard time in microseconds */ + uint32_t guardTimer; /**< Guard timer in microseconds, counting down */ + uint16_t ident; /**< CAN identifier (CO_CAN_ID_HEARTBEAT + Node Id) */ + CO_NMT_internalState_t NMTstate; /**< NMT operating state */ + uint8_t toggle; /**< toggle bit7, expected from the next received message */ + bool_t responseRecived; /**< True, if response was received since last rtr message */ + bool_t CANtxWasBusy; /**< True, if CANtxBuff was busy since last processing */ + bool_t monitoringActive; /**< True, if monitoring is active (response within time). */ } CO_nodeGuardingMasterNode_t; /** * Node Guarding master object */ typedef struct { - /** From CO_nodeGuardingMaster_init() */ - CO_EM_t* em; - /** From CO_nodeGuardingMaster_init() */ - CO_CANmodule_t* CANdevTx; - /** From CO_nodeGuardingMaster_init() */ - uint16_t CANdevTxIdx; - /** CAN transmit buffer for the message */ - CO_CANtx_t* CANtxBuff; - /** True, if all monitored nodes are active or no node is monitored. Can be - * read by the application */ - bool_t allMonitoredActive; - /** True, if all monitored nodes are NMT operational or no node is - * monitored. Can be read by the application */ - bool_t allMonitoredOperational; - /** Array of monitored nodes */ - CO_nodeGuardingMasterNode_t nodes[CO_CONFIG_NODE_GUARDING_MASTER_COUNT]; + CO_EM_t* em; /**< From CO_nodeGuardingMaster_init() */ + CO_CANmodule_t* CANdevTx; /**< From CO_nodeGuardingMaster_init() */ + uint16_t CANdevTxIdx; /**< From CO_nodeGuardingMaster_init() */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer for the message */ + bool_t allMonitoredActive; /**< True, if all monitored nodes are active or no node is monitored. Can be read by the + application */ + bool_t allMonitoredOperational; /**< True, if all monitored nodes are NMT operational or no node is monitored. Can + be read by the application */ + CO_nodeGuardingMasterNode_t nodes[CO_CONFIG_NODE_GUARDING_MASTER_COUNT]; /**< Array of monitored nodes */ } CO_nodeGuardingMaster_t; /** @@ -244,12 +210,10 @@ CO_ReturnError_t CO_nodeGuardingMaster_init(CO_nodeGuardingMaster_t* ngm, CO_EM_ /** * Initialize node inside Node Guarding master object. * - * Function may be called any time after CO_nodeGuardingMaster_init(). It - * configures monitoring of the remote node. + * Function may be called any time after CO_nodeGuardingMaster_init(). It configures monitoring of the remote node. * * @param ngm Node Guarding master object. - * @param index Index of the slot, which will be configured. - * 0 <= index < CO_CONFIG_NODE_GUARDING_MASTER_COUNT. + * @param index Index of the slot, which will be configured. 0 <= index < CO_CONFIG_NODE_GUARDING_MASTER_COUNT. * @param nodeId Node Id of the monitored node. * @param guardTime_ms Guard time of the monitored node. * @@ -264,8 +228,7 @@ CO_ReturnError_t CO_nodeGuardingMaster_initNode(CO_nodeGuardingMaster_t* ngm, ui * Function must be called cyclically. * * @param ngm This object. - * @param timeDifference_us Time difference from previous function call in - * microseconds. + * @param timeDifference_us Time difference from previous function call in microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t* ngm, uint32_t timeDifference_us, uint32_t* timerNext_us); @@ -274,7 +237,7 @@ void CO_nodeGuardingMaster_process(CO_nodeGuardingMaster_t* ngm, uint32_t timeDi #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_NODE_GUARDING) & CO_CONFIG_NODE_GUARDING_MASTER_ENABLE */ diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index dcf07ce7..34faab21 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -37,20 +37,16 @@ extern "C" { */ #ifndef CO_OD_OWN_TYPES -/** Variable of type OD_size_t contains data length in bytes of OD variable */ -typedef uint32_t OD_size_t; -/** Type (and size) of Object Dictionary attribute */ -typedef uint8_t OD_attr_t; +typedef uint32_t OD_size_t; /**< Variable of type OD_size_t contains data length in bytes of OD variable */ +typedef uint8_t OD_attr_t; /**< Type (and size) of Object Dictionary attribute */ #endif #ifndef OD_FLAGS_PDO_SIZE -/** Size of of flagsPDO variable inside @ref OD_extension_t, from 0 to 32. */ -#define OD_FLAGS_PDO_SIZE 4U +#define OD_FLAGS_PDO_SIZE 4U /**< Size of of flagsPDO variable inside @ref OD_extension_t, from 0 to 32. */ #endif #ifndef CO_PROGMEM -/** Modifier for OD objects. This is large amount of data and is specified in - * Object Dictionary (OD.c file usually) */ +/** Modifier for OD objects. This is large amount of data and is specified in Object Dictionary (OD.c file usually) */ #define CO_PROGMEM const #endif @@ -74,7 +70,7 @@ typedef enum { OD_H100D_LIFETIME_FACTOR = 0x100DU, /**< Life time factor */ OD_H100E_RSV = 0x100EU, /**< Reserved */ OD_H100F_RSV = 0x100FU, /**< Reserved */ - OD_H1010_STORE_PARAMETERS = 0x1010U, /**< Store params in persistent mem.*/ + OD_H1010_STORE_PARAMETERS = 0x1010U, /**< Store params in persistent mem. */ OD_H1011_RESTORE_DEFAULT = 0x1011U, /**< Restore default parameters */ OD_H1012_COBID_TIME = 0x1012U, /**< Timestamp message cob-id */ OD_H1013_HIGH_RES_TIMESTAMP = 0x1013U, /**< High resolution timestamp */ @@ -121,9 +117,8 @@ typedef enum { ODA_RSRDO = 0x20U, /**< Variable is mappable into receiving SRDO */ ODA_TRSRDO = 0x30U, /**< Variable is mappable into tx or rx SRDO */ ODA_MB = 0x40U, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */ - ODA_STR = 0x80U /**< Shorter value, than specified variable size, may be - written to the variable. SDO write will fill remaining memory with zeroes. - Attribute is used for VISIBLE_STRING and UNICODE_STRING. */ + ODA_STR = 0x80U /**< Shorter value, than specified variable size, may be written to the variable. SDO write will + fill remaining memory with zeroes. Attribute is used for VISIBLE_STRING and UNICODE_STRING. */ } OD_attributes_t; /** @@ -132,160 +127,111 @@ typedef enum { * @ref OD_getSDOabCode() can be used to retrieve corresponding SDO abort code. */ typedef enum { - /* !!!! WARNING !!!! - * If changing these values, change also OD_getSDOabCode() function! - */ - /** Read/write is only partial, make more calls */ - ODR_PARTIAL = -1, - /** SDO abort 0x00000000 - Read/write successfully finished */ - ODR_OK = 0, - /** SDO abort 0x05040005 - Out of memory */ - ODR_OUT_OF_MEM = 1, - /** SDO abort 0x06010000 - Unsupported access to an object */ - ODR_UNSUPP_ACCESS = 2, - /** SDO abort 0x06010001 - Attempt to read a write only object */ - ODR_WRITEONLY = 3, - /** SDO abort 0x06010002 - Attempt to write a read only object */ - ODR_READONLY = 4, - /** SDO abort 0x06020000 - Object does not exist in the object dict. */ - ODR_IDX_NOT_EXIST = 5, - /** SDO abort 0x06040041 - Object cannot be mapped to the PDO */ - ODR_NO_MAP = 6, - /** SDO abort 0x06040042 - PDO length exceeded */ - ODR_MAP_LEN = 7, - /** SDO abort 0x06040043 - General parameter incompatibility reasons */ - ODR_PAR_INCOMPAT = 8, - /** SDO abort 0x06040047 - General internal incompatibility in device */ - ODR_DEV_INCOMPAT = 9, - /** SDO abort 0x06060000 - Access failed due to hardware error */ - ODR_HW = 10, - /** SDO abort 0x06070010 - Data type does not match */ - ODR_TYPE_MISMATCH = 11, - /** SDO abort 0x06070012 - Data type does not match, length too high */ - ODR_DATA_LONG = 12, - /** SDO abort 0x06070013 - Data type does not match, length too short */ - ODR_DATA_SHORT = 13, - /** SDO abort 0x06090011 - Sub index does not exist */ - ODR_SUB_NOT_EXIST = 14, - /** SDO abort 0x06090030 - Invalid value for parameter (download only) */ - ODR_INVALID_VALUE = 15, - /** SDO abort 0x06090031 - Value range of parameter written too high */ - ODR_VALUE_HIGH = 16, - /** SDO abort 0x06090032 - Value range of parameter written too low */ - ODR_VALUE_LOW = 17, - /** SDO abort 0x06090036 - Maximum value is less than minimum value */ - ODR_MAX_LESS_MIN = 18, - /** SDO abort 0x060A0023 - Resource not available: SDO connection */ - ODR_NO_RESOURCE = 19, - /** SDO abort 0x08000000 - General error */ - ODR_GENERAL = 20, - /** SDO abort 0x08000020 - Data cannot be transferred or stored to app */ - ODR_DATA_TRANSF = 21, - /** SDO abort 0x08000021 - Data can't be transferred (local control) */ - ODR_DATA_LOC_CTRL = 22, - /** SDO abort 0x08000022 - Data can't be transf. (present device state) */ - ODR_DATA_DEV_STATE = 23, - /** SDO abort 0x08000023 - Object dictionary not present */ - ODR_OD_MISSING = 24, - /** SDO abort 0x08000024 - No data available */ - ODR_NO_DATA = 25, - /** Last element, number of responses */ - ODR_COUNT = 26 + /* !!!! WARNING !!!! If changing these values, change also OD_getSDOabCode() function! */ + ODR_PARTIAL = -1, /**< Read/write is only partial, make more calls */ + ODR_OK = 0, /**< SDO abort 0x00000000 - Read/write successfully finished */ + ODR_OUT_OF_MEM = 1, /**< SDO abort 0x05040005 - Out of memory */ + ODR_UNSUPP_ACCESS = 2, /**< SDO abort 0x06010000 - Unsupported access to an object */ + ODR_WRITEONLY = 3, /**< SDO abort 0x06010001 - Attempt to read a write only object */ + ODR_READONLY = 4, /**< SDO abort 0x06010002 - Attempt to write a read only object */ + ODR_IDX_NOT_EXIST = 5, /**< SDO abort 0x06020000 - Object does not exist in the object dict. */ + ODR_NO_MAP = 6, /**< SDO abort 0x06040041 - Object cannot be mapped to the PDO */ + ODR_MAP_LEN = 7, /**< SDO abort 0x06040042 - PDO length exceeded */ + ODR_PAR_INCOMPAT = 8, /**< SDO abort 0x06040043 - General parameter incompatibility reasons */ + ODR_DEV_INCOMPAT = 9, /**< SDO abort 0x06040047 - General internal incompatibility in device */ + ODR_HW = 10, /**< SDO abort 0x06060000 - Access failed due to hardware error */ + ODR_TYPE_MISMATCH = 11, /**< SDO abort 0x06070010 - Data type does not match */ + ODR_DATA_LONG = 12, /**< SDO abort 0x06070012 - Data type does not match, length too high */ + ODR_DATA_SHORT = 13, /**< SDO abort 0x06070013 - Data type does not match, length too short */ + ODR_SUB_NOT_EXIST = 14, /**< SDO abort 0x06090011 - Sub index does not exist */ + ODR_INVALID_VALUE = 15, /**< SDO abort 0x06090030 - Invalid value for parameter (download only) */ + ODR_VALUE_HIGH = 16, /**< SDO abort 0x06090031 - Value range of parameter written too high */ + ODR_VALUE_LOW = 17, /**< SDO abort 0x06090032 - Value range of parameter written too low */ + ODR_MAX_LESS_MIN = 18, /**< SDO abort 0x06090036 - Maximum value is less than minimum value */ + ODR_NO_RESOURCE = 19, /**< SDO abort 0x060A0023 - Resource not available: SDO connection */ + ODR_GENERAL = 20, /**< SDO abort 0x08000000 - General error */ + ODR_DATA_TRANSF = 21, /**< SDO abort 0x08000020 - Data cannot be transferred or stored to app */ + ODR_DATA_LOC_CTRL = 22, /**< SDO abort 0x08000021 - Data can't be transferred (local control) */ + ODR_DATA_DEV_STATE = 23, /**< SDO abort 0x08000022 - Data can't be transf. (present device state) */ + ODR_OD_MISSING = 24, /**< SDO abort 0x08000023 - Object dictionary not present */ + ODR_NO_DATA = 25, /**< SDO abort 0x08000024 - No data available */ + ODR_COUNT = 26 /**< Last element, number of responses */ } ODR_t; /** - * IO stream structure, used for read/write access to OD variable, part of - * @ref OD_IO_t. + * IO stream structure, used for read/write access to OD variable, part of @ref OD_IO_t. */ typedef struct { - /** Pointer to original data object, defined by Object Dictionary. Default - * read/write functions operate on it. If memory for data object is not - * specified by Object Dictionary, then dataOrig is NULL. - */ - void* dataOrig; - /** Pointer to object, passed by @ref OD_extension_init(). Can be used - * inside read / write functions from IO extension. - */ - void* object; - /** Data length in bytes or 0, if length is not specified */ - OD_size_t dataLength; - /** In case of large data, dataOffset indicates position of already - * transferred data */ - OD_size_t dataOffset; - /** Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */ - OD_attr_t attribute; - /** Index of the OD object, informative */ - uint16_t index; - /** Sub index of the OD sub-object, informative */ - uint8_t subIndex; + void* dataOrig; /**< Pointer to original data object, defined by Object Dictionary. Default read/write functions + * operate on it. If memory for data object is not specified by Object Dictionary, then dataOrig is + * NULL. */ + void* object; /**< Pointer to object, passed by @ref OD_extension_init(). Can be used inside read / write functions + * from IO extension. */ + OD_size_t dataLength; /**< Data length in bytes or 0, if length is not specified */ + OD_size_t dataOffset; /**< In case of large data, dataOffset indicates position of already transferred data */ + OD_attr_t attribute; /**< Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */ + uint16_t index; /**< Index of the OD object, informative */ + uint8_t subIndex; /**< Sub index of the OD sub-object, informative */ } OD_stream_t; /** - * Structure for input / output on the OD variable. It is initialized with - * @ref OD_getSub() function. Access principle to OD variable is via read/write - * functions operating on stream, similar as standard read/write. + * Structure for input / output on the OD variable. It is initialized with @ref OD_getSub() function. Access principle + * to OD variable is via read/write functions operating on stream, similar as standard read/write. */ typedef struct { /** Object Dictionary stream object, passed to read or write */ OD_stream_t stream; /** - * Function pointer for reading value from specified variable from Object - * Dictionary. If OD variable is larger than buf, then this function must - * be called several times. After completed successful read function returns - * 'ODR_OK'. If read is partial, it returns 'ODR_PARTIAL'. In case of errors - * function returns code similar to SDO abort code. + * Function pointer for reading value from specified variable from Object Dictionary. If OD variable is larger than + * buf, then this function must be called several times. After completed successful read function returns 'ODR_OK'. + * If read is partial, it returns 'ODR_PARTIAL'. In case of errors function returns code similar to SDO abort code. * * Read can be restarted with @ref OD_rwRestart() function. * - * At the moment, when Object Dictionary is initialized, every variable has - * assigned the same "read" function. This default function simply copies - * data from Object Dictionary variable. Application can bind its own "read" - * function for specific object. In that case application is able to - * calculate data for reading from own internal state at the moment of - * "read" function call. Own "read" function on OD object can be initialized - * with @ref OD_extension_init() function. + * At the moment, when Object Dictionary is initialized, every variable has assigned the same "read" function. This + * default function simply copies data from Object Dictionary variable. Application can bind its own "read" function + * for specific object. In that case application is able to calculate data for reading from own internal state at + * the moment of "read" function call. Own "read" function on OD object can be initialized with @ref + * OD_extension_init() function. * - * "read" function must always copy all own data to buf, except if "buf" is - * not large enough. ("*returnCode" must not return 'ODR_PARTIAL', if there - * is still space in "buf".) + * "read" function must always copy all own data to buf, except if "buf" is not large enough. ("*returnCode" must + * not return 'ODR_PARTIAL', if there is still space in "buf".) * - * @warning Do not use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros - * inside the read() function. See also @ref CO_critical_sections. + * @warning Do not use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros inside the read() function. See also @ref + * CO_critical_sections. * * @param stream Object Dictionary stream object. * @param buf Pointer to external buffer, where to data will be copied. * @param count Size of the external buffer in bytes. - * @param [out] countRead If return value is "ODR_OK" or "ODR_PARTIAL", - * then number of bytes successfully read must be returned here. + * @param [out] countRead If return value is "ODR_OK" or "ODR_PARTIAL", then number of bytes successfully read must + * be returned here. * * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ ODR_t (*read)(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead); /** - * Function pointer for writing value into specified variable inside Object - * Dictionary. If OD variable is larger than buf, then this function must - * be called several times. After completed successful write function - * returns 'ODR_OK'. If write is partial, it returns 'ODR_PARTIAL'. In case - * of errors function returns code similar to SDO abort code. + * Function pointer for writing value into specified variable inside Object Dictionary. If OD variable is larger + * than buf, then this function must be called several times. After completed successful write function returns + * 'ODR_OK'. If write is partial, it returns 'ODR_PARTIAL'. In case of errors function returns code similar to SDO + * abort code. * * Write can be restarted with @ref OD_rwRestart() function. * - * At the moment, when Object Dictionary is initialized, every variable has - * assigned the same "write" function, which simply copies data to Object - * Dictionary variable. Application can bind its own "write" function, - * similar as it can bind "read" function. + * At the moment, when Object Dictionary is initialized, every variable has assigned the same "write" function, + * which simply copies data to Object Dictionary variable. Application can bind its own "write" function, similar as + * it can bind "read" function. * - * "write" function must always copy all available data from buf. If OD - * variable expect more data, then "*returnCode" must return 'ODR_PARTIAL'. + * "write" function must always copy all available data from buf. If OD variable expect more data, then + * "*returnCode" must return 'ODR_PARTIAL'. * - * @warning Do not use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros - * inside the write() function. See also @ref CO_critical_sections. + * @warning Do not use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros inside the write() function. See also @ref + * CO_critical_sections. * * @param stream Object Dictionary stream object. * @param buf Pointer to external buffer, from where data will be copied. * @param count Size of the external buffer in bytes. - * @param [out] countWritten If return value is "ODR_OK" or "ODR_PARTIAL", - * then number of bytes successfully written must be returned here. + * @param [out] countWritten If return value is "ODR_OK" or "ODR_PARTIAL", then number of bytes successfully written + * must be returned here. * * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ @@ -293,31 +239,25 @@ typedef struct { } OD_IO_t; /** - * Extension of OD object, which can optionally be specified by application in - * initialization phase with @ref OD_extension_init() function. + * Extension of OD object, which can optionally be specified by application in initialization phase with @ref + * OD_extension_init() function. */ typedef struct { /** Object on which read and write will operate, part of @ref OD_stream_t */ void* object; - /** Application specified read function pointer. If NULL, then read will be - * disabled. @ref OD_readOriginal can be used here to keep the original read - * function. For function description see @ref OD_IO_t. */ + /** Application specified read function pointer. If NULL, then read will be disabled. @ref OD_readOriginal can be + * used here to keep the original read function. For function description see @ref OD_IO_t. */ ODR_t (*read)(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead); - /** Application specified write function pointer. If NULL, then write will - * be disabled. @ref OD_writeOriginal can be used here to keep the original - * write function. For function description see @ref OD_IO_t. */ + /** Application specified write function pointer. If NULL, then write will be disabled. @ref OD_writeOriginal can be + * used here to keep the original write function. For function description see @ref OD_IO_t. */ ODR_t (*write)(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten); #if OD_FLAGS_PDO_SIZE > 0 - /**PDO flags bit-field provides one bit for each OD variable, which exist - * inside OD object at specific sub index. If application clears that bit, - * and OD variable is mapped to an event driven TPDO, then TPDO will be - * sent. + /** PDO flags bit-field provides one bit for each OD variable, which exist inside OD object at specific sub index. + * If application clears that bit, and OD variable is mapped to an event driven TPDO, then TPDO will be sent. * - * @ref OD_FLAGS_PDO_SIZE can have a value from 0 to 32 bytes, which - * corresponds to 0 to 256 available bits. If, for example, - * @ref OD_FLAGS_PDO_SIZE has value 4, then OD variables with sub index up - * to 31 will have the TPDO requesting functionality. - * See also @ref OD_requestTPDO and @ref OD_TPDOtransmitted. */ + * @ref OD_FLAGS_PDO_SIZE can have a value from 0 to 32 bytes, which corresponds to 0 to 256 available bits. If, for + * example, @ref OD_FLAGS_PDO_SIZE has value 4, then OD variables with sub index up to 31 will have the TPDO + * requesting functionality. See also @ref OD_requestTPDO and @ref OD_TPDOtransmitted. */ uint8_t flagsPDO[OD_FLAGS_PDO_SIZE]; #endif } OD_extension_t; @@ -325,54 +265,42 @@ typedef struct { /** * Object Dictionary entry for one OD object. * - * OD entries are collected inside OD_t as array (list). Each OD entry contains - * basic information about OD object (index and subEntriesCount), pointer to - * odObject with additional information about var, array or record entry and - * pointer to extension, configurable by application. + * OD entries are collected inside OD_t as array (list). Each OD entry contains basic information about OD object (index + * and subEntriesCount), pointer to odObject with additional information about var, array or record entry and pointer to + * extension, configurable by application. */ typedef struct { - /** Object Dictionary index */ - uint16_t index; - /** Number of all sub-entries, including sub-entry at sub-index 0 */ - uint8_t subEntriesCount; - /** Type of the odObject, indicated by @ref OD_objectTypes_t enumerator. */ - uint8_t odObjectType; - /** OD object of type indicated by odObjectType, from which @ref OD_getSub() - * fetches the information */ - CO_PROGMEM void* odObject; - /** Extension to OD, specified by application */ - OD_extension_t* extension; + uint16_t index; /**< Object Dictionary index */ + uint8_t subEntriesCount; /**< Number of all sub-entries, including sub-entry at sub-index 0 */ + uint8_t odObjectType; /**< Type of the odObject, indicated by @ref OD_objectTypes_t enumerator. */ + CO_PROGMEM void* odObject; /**< OD object of type indicated by odObjectType, from which @ref OD_getSub() fetches the + information */ + OD_extension_t* extension; /**< Extension to OD, specified by application */ } OD_entry_t; /** * Object Dictionary */ typedef struct { - /** Number of elements in the list, without last element, which is blank */ - uint16_t size; - /** List OD entries (table of contents), ordered by index */ - OD_entry_t* list; + uint16_t size; /**< Number of elements in the list, without last element, which is blank */ + OD_entry_t* list; /**< List OD entries (table of contents), ordered by index */ } OD_t; /** * Read value from original OD location * - * This function can be used inside read / write functions, specified by - * @ref OD_extension_init(). It reads data directly from memory location - * specified by Object dictionary. If no IO extension is used on OD entry, then - * io->read returned by @ref OD_getSub() equals to this function. See - * also @ref OD_IO_t. + * This function can be used inside read / write functions, specified by @ref OD_extension_init(). It reads data + * directly from memory location specified by Object dictionary. If no IO extension is used on OD entry, then io->read + * returned by @ref OD_getSub() equals to this function. See also @ref OD_IO_t. */ ODR_t OD_readOriginal(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead); /** * Write value to original OD location * - * This function can be used inside read / write functions, specified by - * @ref OD_extension_init(). It writes data directly to memory location - * specified by Object dictionary. If no IO extension is used on OD entry, then - * io->write returned by @ref OD_getSub() equals to this function. See - * also @ref OD_IO_t. + * This function can be used inside read / write functions, specified by @ref OD_extension_init(). It writes data + * directly to memory location specified by Object dictionary. If no IO extension is used on OD entry, then io->write + * returned by @ref OD_getSub() equals to this function. See also @ref OD_IO_t. */ ODR_t OD_writeOriginal(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten); @@ -387,18 +315,18 @@ ODR_t OD_writeOriginal(OD_stream_t* stream, const void* buf, OD_size_t count, OD OD_entry_t* OD_find(OD_t* od, uint16_t index); /** - * Find sub-object with specified sub-index on OD entry returned by OD_find. - * Function populates io structure with sub-object data. + * Find sub-object with specified sub-index on OD entry returned by OD_find. Function populates io structure with + * sub-object data. * * @warning - * Read and write functions may be called from different threads, so critical - * sections in custom functions must be observed, see @ref CO_critical_sections. + * Read and write functions may be called from different threads, so critical sections in custom functions must be + * observed, see @ref CO_critical_sections. * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. * @param [out] io Structure will be populated on success. - * @param odOrig If true, then potential IO extension on entry will be - * ignored and access to data entry in the original OD location will be returned + * @param odOrig If true, then potential IO extension on entry will be ignored and access to data entry in the original + * OD location will be returned * * @return Value from @ref ODR_t, "ODR_OK" in case of success. */ @@ -419,8 +347,8 @@ OD_getIndex(const OD_entry_t* entry) { /** * Check, if OD variable is mappable to PDO or SRDO. * - * If OD variable is mappable, then it may be necessary to protect read/write - * access from mainline function. See @ref CO_critical_sections. + * If OD variable is mappable, then it may be necessary to protect read/write access from mainline function. See @ref + * CO_critical_sections. * * @param stream Object Dictionary stream object. * @@ -434,9 +362,8 @@ OD_mappable(OD_stream_t* stream) { /** * Restart read or write operation on OD variable * - * It is not necessary to call this function, if stream was initialized by - * @ref OD_getSub(). It is also not necessary to call this function, if - * previous read or write was successfully finished. + * It is not necessary to call this function, if stream was initialized by @ref OD_getSub(). It is also not necessary to + * call this function, if previous read or write was successfully finished. * * @param stream Object Dictionary stream object. */ @@ -469,16 +396,13 @@ OD_getFlagsPDO(OD_entry_t* entry) { /** * Request TPDO, to which OD variable is mapped * - * Function clears the flagPDO bit, which corresponds to OD variable at specific - * OD index and subindex. For this functionality to work, @ref OD_extension_t - * must be enabled on OD variable. If OD variable is mapped to any TPDO with - * event driven transmission, then TPDO will be transmitted after this function - * call. If OD variable is mapped to more than one TPDO with event driven - * transmission, only the first matched TPDO will be transmitted. + * Function clears the flagPDO bit, which corresponds to OD variable at specific OD index and subindex. For this + * functionality to work, @ref OD_extension_t must be enabled on OD variable. If OD variable is mapped to any TPDO with + * event driven transmission, then TPDO will be transmitted after this function call. If OD variable is mapped to more + * than one TPDO with event driven transmission, only the first matched TPDO will be transmitted. * - * TPDO event driven transmission is enabled, if TPDO communication parameter, - * transmission type is set to 0, 254 or 255. For other transmission types - * (synchronous) flagPDO bit is ignored. + * TPDO event driven transmission is enabled, if TPDO communication parameter, transmission type is set to 0, 254 or + * 255. For other transmission types (synchronous) flagPDO bit is ignored. * * @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO. * @param subIndex subIndex of the OD variable. @@ -500,10 +424,9 @@ OD_requestTPDO(uint8_t* flagsPDO, uint8_t subIndex) { * @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO. * @param subIndex subIndex of the OD variable. * - * @return Return true if event driven TPDO with mapping to OD variable, - * indicated by flagsPDO and subIndex, was transmitted since last - * @ref OD_requestTPDO call. If there was no @ref OD_requestTPDO call yet and - * TPDO was transmitted by other event, function also returns true. + * @return Return true if event driven TPDO with mapping to OD variable, indicated by flagsPDO and subIndex, was + * transmitted since last @ref OD_requestTPDO call. If there was no @ref OD_requestTPDO call yet and TPDO was + * transmitted by other event, function also returns true. */ static inline bool_t OD_TPDOtransmitted(uint8_t* flagsPDO, uint8_t subIndex) { @@ -531,32 +454,27 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); /** * Extend OD object with own read/write functions and/or flagsPDO * - * This function gives application very powerful tool: definition of own IO - * access on OD object. Structure and attributes are the same as defined in - * original OD object, but data are read directly from (or written directly to) + * This function gives application very powerful tool: definition of own IO access on OD object. Structure and + * attributes are the same as defined in original OD object, but data are read directly from (or written directly to) * application specified object via custom function calls. * - * Before this function specifies extension, OD variables are accessed from - * original OD location. After this function specifies extension OD variables - * are accessed from read/write functions specified by extension. (Except when - * "odOrig" argument to @ref OD_getSub() is set to true.) + * Before this function specifies extension, OD variables are accessed from original OD location. After this function + * specifies extension OD variables are accessed from read/write functions specified by extension. (Except when "odOrig" + * argument to @ref OD_getSub() is set to true.) * - * This function must also be used, when flagsPDO needs to be enabled for - * specific entry. + * This function must also be used, when flagsPDO needs to be enabled for specific entry. * * @warning - * Object dictionary storage works only directly on OD variables. It does not - * access read function specified here. So, if extended OD objects needs to be - * preserved, then @ref OD_writeOriginal can be used inside custom write - * function. + * Object dictionary storage works only directly on OD variables. It does not access read function specified here. So, + * if extended OD objects needs to be preserved, then @ref OD_writeOriginal can be used inside custom write function. * * @warning - * Read and write functions may be called from different threads, so critical - * sections in custom functions must be observed, see @ref CO_critical_sections. + * Read and write functions may be called from different threads, so critical sections in custom functions must be + * observed, see @ref CO_critical_sections. * * @param entry OD entry returned by @ref OD_find(). - * @param extension Extension object, which must be initialized externally. - * Extension object must exist permanently. If NULL, extension will be removed. + * @param extension Extension object, which must be initialized externally. Extension object must exist permanently. If + * NULL, extension will be removed. * * @return "ODR_OK" on success, "ODR_IDX_NOT_EXIST" if OD object doesn't exist. */ @@ -573,8 +491,7 @@ OD_extension_init(OD_entry_t* entry, OD_extension_t* extension) { * @defgroup CO_ODgetSetters Getters and setters * @{ * - * Getter and setter helper functions for accessing different types of Object - * Dictionary variables. + * Getter and setter helper functions for accessing different types of Object Dictionary variables. */ /** * Get variable from Object Dictionary @@ -583,12 +500,11 @@ OD_extension_init(OD_entry_t* entry, OD_extension_t* extension) { * @param subIndex Sub-index of the variable from the OD object. * @param [out] val Value will be written here. * @param len Size of value to retrieve from OD. - * @param odOrig If true, then potential IO extension on entry will be - * ignored and data in the original OD location will be returned. + * @param odOrig If true, then potential IO extension on entry will be ignored and data in the original OD location will + * be returned. * - * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if - * variable does not exist in object dictionary or it does not have the correct - * length or other reason. + * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if variable does not exist in object dictionary or + * it does not have the correct length or other reason. */ ODR_t OD_get_value(const OD_entry_t* entry, uint8_t subIndex, void* val, OD_size_t len, bool_t odOrig); @@ -659,12 +575,11 @@ OD_get_f64(const OD_entry_t* entry, uint8_t subIndex, float64_t* val, bool_t odO * @param subIndex Sub-index of the variable from the OD object. * @param val Pointer to value to write. * @param len Size of value to write. - * @param odOrig If true, then potential IO extension on entry will be - * ignored and data in the original OD location will be written. + * @param odOrig If true, then potential IO extension on entry will be ignored and data in the original OD location will + * be written. * - * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if - * variable does not exist in object dictionary or it does not have the correct - * length or other reason. + * @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if variable does not exist in object dictionary or + * it does not have the correct length or other reason. */ ODR_t OD_set_value(const OD_entry_t* entry, uint8_t subIndex, void* val, OD_size_t len, bool_t odOrig); @@ -731,14 +646,13 @@ OD_set_f64(const OD_entry_t* entry, uint8_t subIndex, float64_t val, bool_t odOr /** * Get pointer to memory which holds data variable from Object Dictionary * - * Function always returns "dataOrig" pointer, which points to data - * in the original OD location. Take care, if IO extension is enabled on OD - * entry. Take also care that "dataOrig" could be not aligned to data type. + * Function always returns "dataOrig" pointer, which points to data in the original OD location. Take care, if IO + * extension is enabled on OD entry. Take also care that "dataOrig" could be not aligned to data type. * * @param entry OD entry returned by @ref OD_find(). * @param subIndex Sub-index of the variable from the OD object. - * @param len Required length of the variable. If len is different than zero, - * then actual length of the variable must match len or error is returned. + * @param len Required length of the variable. If len is different than zero, then actual length of the variable must + * match len or error is returned. * @param [out] err Error reason is written here in case of error (allow NULL). * * @return Pointer to variable in Object Dictionary or NULL in case of error. @@ -757,26 +671,19 @@ void* OD_getPtr(const OD_entry_t* entry, uint8_t subIndex, OD_size_t len, ODR_t* * Types for OD object. */ typedef enum { - /** This type corresponds to CANopen Object Dictionary object with object - * code equal to VAR. OD object is type of @ref OD_obj_var_t and represents - * single variable of any type (any length), located on sub-index 0. Other - * sub-indexes are not used. */ - ODT_VAR = 0x01, - /** This type corresponds to CANopen Object Dictionary object with object - * code equal to ARRAY. OD object is type of @ref OD_obj_array_t and - * represents array of variables with the same type, located on sub-indexes - * above 0. Sub-index 0 is of type uint8_t and usually represents length of - * the array. */ - ODT_ARR = 0x02, - /** This type corresponds to CANopen Object Dictionary object with object - * code equal to RECORD. This type of OD object represents structure of - * the variables. Each variable from the structure can have own type and - * own attribute. OD object is an array of elements of type - * @ref OD_obj_var_t. Variable at sub-index 0 is of type uint8_t and usually - * represents number of sub-elements in the structure. */ - ODT_REC = 0x03, - /** Mask for basic type */ - ODT_TYPE_MASK = 0x0F, + ODT_VAR = 0x01, /**< This type corresponds to CANopen Object Dictionary object with object code equal to VAR. OD + object is type of @ref OD_obj_var_t and represents single variable of any type (any length), + located on sub-index 0. Other sub-indexes are not used. */ + ODT_ARR = 0x02, /**< This type corresponds to CANopen Object Dictionary object with object code equal to ARRAY. OD + object is type of @ref OD_obj_array_t and represents array of variables with the same type, + located on sub-indexes above 0. Sub-index 0 is of type uint8_t and usually represents length of + the array. */ + ODT_REC = 0x03, /**< This type corresponds to CANopen Object Dictionary object with object code equal to RECORD. + This type of OD object represents structure of the variables. Each variable from the structure + can have own type and own attribute. OD object is an array of elements of type @ref OD_obj_var_t. + Variable at sub-index 0 is of type uint8_t and usually represents number of sub-elements in the + structure. */ + ODT_TYPE_MASK = 0x0F, /**< Mask for basic type */ } OD_objectTypes_t; /** @@ -794,8 +701,7 @@ typedef struct { typedef struct { uint8_t* dataOrig0; /**< Pointer to data for sub-index 0 */ void* dataOrig; /**< Pointer to array of data */ - OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see - @ref OD_attributes_t */ + OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see @ref OD_attributes_t */ OD_attr_t attribute; /**< Attribute bitfield for array elements */ OD_size_t dataElementLength; /**< Data length of array elements in bytes */ OD_size_t dataElementSizeof; /**< Sizeof one array element in bytes */ @@ -819,6 +725,6 @@ typedef struct { #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* CO_OD_INTERFACE_H */ diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 55d1ad48..3ce6390e 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -45,82 +45,62 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * Process data objects are used for real-time data transfer with no protocol - * overhead. + * Process data objects are used for real-time data transfer with no protocol overhead. * - * TPDO with specific identifier is transmitted by one device and recieved by - * zero or more devices as RPDO. PDO communication parameters(COB-ID, - * transmission type, etc.) are in the Object Dictionary at index 0x1400+ and - * 0x1800+. PDO mapping parameters (size and contents of the PDO) are in the - * Object Dictionary at index 0x1600+ and 0x1A00+. + * TPDO with specific identifier is transmitted by one device and recieved by zero or more devices as RPDO. PDO + * communication parameters(COB-ID, transmission type, etc.) are in the Object Dictionary at index 0x1400+ and 0x1800+. + * PDO mapping parameters (size and contents of the PDO) are in the Object Dictionary at index 0x1600+ and 0x1A00+. * * Features of the PDO as implemented in CANopenNode: * - Dynamic PDO mapping. * - Map granularity of one byte. - * - Data from OD variables are accessed via @ref OD_IO_t read()/write() - * functions, which gives a great usefulness to the application. - * - For systems with very low memory and processing capabilities there is a - * simplified @ref CO_CONFIG_PDO option, where instead of read()/write() - * access, PDO data are copied directly to/from memory locations of - * OD variables. - * - After RPDO is received from CAN bus, its data are copied to internal - * buffer (inside fast CAN receive interrupt). Function CO_RPDO_process() - * (called by application) copies data to the mapped objects in the Object - * Dictionary. Synchronous RPDOs are processed AFTER reception of the next - * SYNC message. - * - Function CO_TPDO_process() (called by application) sends TPDO when - * necessary. There are different transmission types possible, controlled by: - * SYNC message, event timer, @ref CO_TPDOsendRequest() by application or - * @ref OD_requestTPDO(), where application can request TPDO for OD - * variable mapped to any of them. In later case application may, for - * example, monitor change of state of the OD variable and indicate TPDO - * request on it. + * - Data from OD variables are accessed via @ref OD_IO_t read()/write() functions, which gives a great usefulness to + * the application. + * - For systems with very low memory and processing capabilities there is a simplified @ref CO_CONFIG_PDO option, + * where instead of read()/write() access, PDO data are copied directly to/from memory locations of OD variables. + * - After RPDO is received from CAN bus, its data are copied to internal buffer (inside fast CAN receive interrupt). + * Function CO_RPDO_process() (called by application) copies data to the mapped objects in the Object Dictionary. + * Synchronous RPDOs are processed AFTER reception of the next SYNC message. + * - Function CO_TPDO_process() (called by application) sends TPDO when necessary. There are different transmission + * types possible, controlled by: SYNC message, event timer, @ref CO_TPDOsendRequest() by application or @ref + * OD_requestTPDO(), where application can request TPDO for OD variable mapped to any of them. In later case + * application may, for example, monitor change of state of the OD variable and indicate TPDO request on it. * * @anchor CO_PDO_CAN_ID * ### CAN identifiers for PDO - - * Each PDO can be configured with any valid 11-bit CAN identifier. Lower - * numbers have higher priorities on CAN bus. As a general rule, each CAN - * message is identified with own CAN-ID, which must be unique and produced by - * single source. The same is with PDO objects: Any TPDO produced on the CANopen - * network must have unique CAN-ID and there can be zero to many RPDOs (from - * different devices) configured to match the CAN-ID of the TPDO of interest. * - * CANopen standard provides pre-defined connection sets for four RPDOs and four - * TPDOs on each device with specific 7-bit Node-ID. These are default values - * and are usable in configuration, where CANopen network contains a master - * device, which directly communicates with many slaves. In de-centralized - * systems, where devices operate without a master, it makes sense to configure - * CAN-IDs of the RPDOs to the non-default values. + * Each PDO can be configured with any valid 11-bit CAN identifier. Lower numbers have higher priorities on CAN bus. As + * a general rule, each CAN message is identified with own CAN-ID, which must be unique and produced by single source. + * The same is with PDO objects: Any TPDO produced on the CANopen network must have unique CAN-ID and there can be zero + * to many RPDOs (from different devices) configured to match the CAN-ID of the TPDO of interest. + * + * CANopen standard provides pre-defined connection sets for four RPDOs and four TPDOs on each device with specific + * 7-bit Node-ID. These are default values and are usable in configuration, where CANopen network contains a master + * device, which directly communicates with many slaves. In de-centralized systems, where devices operate without a + * master, it makes sense to configure CAN-IDs of the RPDOs to the non-default values. * - * Default CAN identifiers for first four TPDOs on device with specific CANopen - * Node-Id are: 0x180+NodeId, 0x280+NodeId, 0x380+NodeId and 0x480+NodeId. + * Default CAN identifiers for first four TPDOs on device with specific CANopen Node-Id are: 0x180+NodeId, 0x280+NodeId, + * 0x380+NodeId and 0x480+NodeId. * - * Default CAN identifiers for first four RPDOs on device with specific CANopen - * Node-Id are: 0x200+NodeId, 0x300+NodeId, 0x400+NodeId and 0x500+NodeId. + * Default CAN identifiers for first four RPDOs on device with specific CANopen Node-Id are: 0x200+NodeId, 0x300+NodeId, + * 0x400+NodeId and 0x500+NodeId. * - * CANopenNode handles default (pre-defined) CAN-IDs. If it is detected, that - * PDO is configured with default CAN-ID (when writing to OD variable PDO - * communication parameter, COB-ID), then COB-ID is stored without Node-Id to - * the Object Dictionary. If Node-ID is changed, then COB-ID will always contain - * correct default CAN-ID (default CAN-ID + Node-ID). If PDO is configured with - * non-default CAN-ID, then it will be stored to the Object Dictionary as is. + * CANopenNode handles default (pre-defined) CAN-IDs. If it is detected, that PDO is configured with default CAN-ID + * (when writing to OD variable PDO communication parameter, COB-ID), then COB-ID is stored without Node-Id to the + * Object Dictionary. If Node-ID is changed, then COB-ID will always contain correct default CAN-ID (default CAN-ID + + * Node-ID). If PDO is configured with non-default CAN-ID, then it will be stored to the Object Dictionary as is. * - * If configuration CO_CONFIG_FLAG_OD_DYNAMIC is enabled in @ref CO_CONFIG_PDO, - * then PDOs can be configured dynamically, also in NMT operational state. - * Otherwise PDOs are configured only in reset communication section and also - * default CAN-IDs are always stored to OD as is, no default node-id is handled. + * If configuration CO_CONFIG_FLAG_OD_DYNAMIC is enabled in @ref CO_CONFIG_PDO, then PDOs can be configured dynamically, + * also in NMT operational state. Otherwise PDOs are configured only in reset communication section and also default + * CAN-IDs are always stored to OD as is, no default node-id is handled. * * Configure PDO by writing to the OD variables in the following procedure: - * - Disable the PDO by setting bit-31 to 1 in PDO communication parameter, - * COB-ID + * - Disable the PDO by setting bit-31 to 1 in PDO communication parameter, COB-ID * - Node-Id can be configured only when PDO is disabled. * - Disable mapping by setting PDO mapping parameter, sub index 0 to 0 * - Configure mapping - * - Enable mapping by setting PDO mapping param, sub 0 to number of mapped - * objects - * - Enable the PDO by setting bit-31 to 0 in PDO communication parameter, - * COB-ID + * - Enable mapping by setting PDO mapping param, sub 0 to number of mapped objects + * - Enable the PDO by setting bit-31 to 0 in PDO communication parameter, COB-ID */ /** Maximum size of PDO message, 8 for standard CAN */ @@ -128,28 +108,23 @@ extern "C" { #define CO_PDO_MAX_SIZE 8U #endif -/** Maximum number of entries, which can be mapped to PDO, 8 for standard CAN, - * may be less to preserve RAM usage */ +/** Maximum number of entries, which can be mapped to PDO, 8 for standard CAN, may be less to preserve RAM usage */ #ifndef CO_PDO_MAX_MAPPED_ENTRIES #define CO_PDO_MAX_MAPPED_ENTRIES 8U #endif -/** Number of CANopen RPDO objects, which uses default CAN indentifiers. - * By default first four RPDOs have pre-defined CAN identifiers, which depends - * on node-id. This constant may be set to 0 to disable functionality or set - * to any other value. For example, if there are several logical devices inside - * single CANopen device, then more than four RPDOs may have pre-defined CAN - * identifiers. In that case RPDO5 has CAN_ID=0x200+NodeId+1, RPDO6 has - * CAN_ID=0x300+NodeId+1, RPDO9 has CAN_ID=0x200+NodeId+2 and so on. */ +/** Number of CANopen RPDO objects, which uses default CAN indentifiers. By default first four RPDOs have pre-defined + * CAN identifiers, which depends on node-id. This constant may be set to 0 to disable functionality or set to any other + * value. For example, if there are several logical devices inside single CANopen device, then more than four RPDOs may + * have pre-defined CAN identifiers. In that case RPDO5 has CAN_ID=0x200+NodeId+1, RPDO6 has CAN_ID=0x300+NodeId+1, + * RPDO9 has CAN_ID=0x200+NodeId+2 and so on. */ #ifndef CO_RPDO_DEFAULT_CANID_COUNT #define CO_RPDO_DEFAULT_CANID_COUNT 4U #endif -/** Number of CANopen TPDO objects, which uses default CAN indentifiers. - * If value is more than four, then pre-defined pre-defined CAN identifiers are: - * TPDO5 has CAN_ID=0x180+NodeId+1, TPDO6 has CAN_ID=0x280+NodeId+1, - * TPDO9 has CAN_ID=0x180+NodeId+2 and so on. - * For description see @ref CO_RPDO_DEFAULT_CANID_COUNT. */ +/** Number of CANopen TPDO objects, which uses default CAN indentifiers. If value is more than four, then pre-defined + * pre-defined CAN identifiers are: TPDO5 has CAN_ID=0x180+NodeId+1, TPDO6 has CAN_ID=0x280+NodeId+1, TPDO9 has + * CAN_ID=0x180+NodeId+2 and so on. For description see @ref CO_RPDO_DEFAULT_CANID_COUNT. */ #ifndef CO_TPDO_DEFAULT_CANID_COUNT #define CO_TPDO_DEFAULT_CANID_COUNT 4U #endif @@ -165,41 +140,33 @@ typedef uint8_t CO_PDO_size_t; typedef enum { CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC = 0U, /**< synchronous (acyclic) */ CO_PDO_TRANSM_TYPE_SYNC_1 = 1U, /**< synchronous (cyclic every sync) */ - CO_PDO_TRANSM_TYPE_SYNC_240 = 0xF0U, /**< synchronous (cyclic every 240-th - sync) */ - CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO = 0xFEU, /**< event-driven, lower value - (manufacturer specific), */ - CO_PDO_TRANSM_TYPE_SYNC_EVENT_HI = 0xFFU /**< event-driven, higher value - (device profile and application profile specific) */ + CO_PDO_TRANSM_TYPE_SYNC_240 = 0xF0U, /**< synchronous (cyclic every 240-th sync) */ + CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO = 0xFEU, /**< event-driven, lower value (manufacturer specific), */ + CO_PDO_TRANSM_TYPE_SYNC_EVENT_HI = 0xFFU /**< event-driven, higher value (device profile and application profile + specific) */ } CO_PDO_transmissionTypes_t; /** * PDO object, common properties */ typedef struct { - /** From CO_xPDO_init() */ - CO_EM_t* em; - /** From CO_xPDO_init() */ - CO_CANmodule_t* CANdev; - /** True, if PDO is enabled and valid */ - bool_t valid; - /** Data length of the received PDO message. Calculated from mapping */ - CO_PDO_size_t dataLength; - /** Number of mapped objects in PDO */ - uint8_t mappedObjectsCount; + CO_EM_t* em; /**< From CO_xPDO_init() */ + CO_CANmodule_t* CANdev; /**< From CO_xPDO_init() */ + bool_t valid; /**< True, if PDO is enabled and valid */ + CO_PDO_size_t dataLength; /**< Data length of the received PDO message. Calculated from mapping */ + uint8_t mappedObjectsCount; /**< Number of mapped objects in PDO */ #if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) != 0) || defined CO_DOXYGEN - /** Object dictionary interface for all mapped entries. OD_IO.dataOffset has - * special usage with PDO. It stores information about mappedLength of - * the variable. mappedLength can be less or equal to the OD_IO.dataLength. - * mappedLength greater than OD_IO.dataLength indicates erroneous mapping. - * OD_IO.dataOffset is set to 0 before read/write function call and after - * the call OD_IO.dataOffset is set back to mappedLength. */ - OD_IO_t OD_IO[CO_PDO_MAX_MAPPED_ENTRIES]; + OD_IO_t OD_IO[CO_PDO_MAX_MAPPED_ENTRIES]; /**< Object dictionary interface for all mapped entries. OD_IO.dataOffset + has special usage with PDO. It stores information about mappedLength + of the variable. mappedLength can be less or equal to the + OD_IO.dataLength. mappedLength greater than OD_IO.dataLength indicates + erroneous mapping. OD_IO.dataOffset is set to 0 before read/write + function call and after the call OD_IO.dataOffset is set back to + mappedLength. */ #if OD_FLAGS_PDO_SIZE > 0 - /** Pointer to byte, which contains PDO flag bit from @ref OD_extension_t */ - uint8_t* flagPDObyte[CO_PDO_MAX_MAPPED_ENTRIES]; - /** Bitmask for the flagPDObyte */ - uint8_t flagPDObitmask[CO_PDO_MAX_MAPPED_ENTRIES]; + uint8_t* flagPDObyte[CO_PDO_MAX_MAPPED_ENTRIES]; /**< Pointer to byte, which contains PDO flag bit from @ref + OD_extension_t */ + uint8_t flagPDObitmask[CO_PDO_MAX_MAPPED_ENTRIES]; /**< Bitmask for the flagPDObyte */ #endif #else /* Pointers to data objects inside OD, where PDO will be copied */ @@ -210,20 +177,13 @@ typedef struct { #endif #endif #if (((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN - /** True for RPDO, false for TPDO */ - bool_t isRPDO; - /** From CO_xPDO_init() */ - OD_t* OD; - /** From CO_xPDO_init() */ - uint16_t CANdevIdx; - /** From CO_xPDO_init() */ - uint16_t preDefinedCanId; - /** Currently configured CAN identifier */ - uint16_t configuredCanId; - /** Extension for OD object */ - OD_extension_t OD_communicationParam_ext; - /** Extension for OD object */ - OD_extension_t OD_mappingParam_extension; + bool_t isRPDO; /**< True for RPDO, false for TPDO */ + OD_t* OD; /**< From CO_xPDO_init() */ + uint16_t CANdevIdx; /**< From CO_xPDO_init() */ + uint16_t preDefinedCanId; /**< From CO_xPDO_init() */ + uint16_t configuredCanId; /**< Currently configured CAN identifier */ + OD_extension_t OD_communicationParam_ext; /**< Extension for OD object */ + OD_extension_t OD_mappingParam_extension; /**< Extension for OD object */ #endif } CO_PDO_common_t; @@ -244,52 +204,40 @@ typedef struct { * RPDO object. */ typedef struct { - /** PDO common properties, must be first element in this object */ - CO_PDO_common_t PDO_common; - /** Variable indicates, if new PDO message received from CAN bus. */ - volatile void* CANrxNew[CO_RPDO_CAN_BUFFERS_COUNT]; - /** CO_PDO_MAX_SIZE data bytes of the received message. */ - uint8_t CANrxData[CO_RPDO_CAN_BUFFERS_COUNT][CO_PDO_MAX_SIZE]; - /** Indication of RPDO length errors, use with CO_PDO_receiveErrors_t */ - uint8_t receiveError; + CO_PDO_common_t PDO_common; /**< PDO common properties, must be first element in this object */ + volatile void* CANrxNew[CO_RPDO_CAN_BUFFERS_COUNT]; /**< Variable indicates, if new PDO message received from CAN */ + uint8_t CANrxData[CO_RPDO_CAN_BUFFERS_COUNT][CO_PDO_MAX_SIZE]; /**< CO_PDO_MAX_SIZE data bytes of the received + message. */ + uint8_t receiveError; /**< Indication of RPDO length errors, use with CO_PDO_receiveErrors_t */ #if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN - /** From CO_RPDO_init() */ - CO_SYNC_t* SYNC; - /** True if transmissionType <= 240 */ - bool_t synchronous; + CO_SYNC_t* SYNC; /**< From CO_RPDO_init() */ + bool_t synchronous; /**< True if transmissionType <= 240 */ #endif #if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN - /** Maximum timeout time between received PDOs in microseconds. Configurable - * by OD variable RPDO communication parameter, event-timer. */ - uint32_t timeoutTime_us; - /** Timeout timer variable in microseconds */ - uint32_t timeoutTimer; + uint32_t timeoutTime_us; /**< Maximum timeout time between received PDOs in microseconds. Configurable by OD + variable RPDO communication parameter, event-timer. */ + uint32_t timeoutTimer; /**< Timeout timer variable in microseconds */ #endif #if (((CO_CONFIG_PDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_RPDO_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void* object); - /** From CO_RPDO_initCallbackPre() or NULL */ - void* functSignalObjectPre; + void (*pFunctSignalPre)(void* object); /**< From CO_RPDO_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< From CO_RPDO_initCallbackPre() or NULL */ #endif } CO_RPDO_t; /** * Initialize RPDO object. * - * Function must be called in the end of the communication reset section, after - * all application initialization. Otherwise mapping to application OD variables - * will not be correct. + * Function must be called in the end of the communication reset section, after all application initialization. + * Otherwise mapping to application OD variables will not be correct. * * @param RPDO This object will be initialized. * @param OD Object Dictionary. * @param em Emergency object. * @param SYNC SYNC object, may be NULL. - * @param preDefinedCanId CAN identifier from pre-defined connection set, - * including node-id for first four PDOs, or 0 otherwise, see @ref CO_PDO_CAN_ID - * @param OD_14xx_RPDOCommPar OD entry for 0x1400+ - "RPDO communication - * parameter", entry is required. - * @param OD_16xx_RPDOMapPar OD entry for 0x1600+ - "RPDO mapping parameter", - * entry is required. + * @param preDefinedCanId CAN identifier from pre-defined connection set, including node-id for first four PDOs, or 0 + * otherwise, see @ref CO_PDO_CAN_ID + * @param OD_14xx_RPDOCommPar OD entry for 0x1400+ - "RPDO communication parameter", entry is required. + * @param OD_16xx_RPDOMapPar OD entry for 0x1600+ - "RPDO mapping parameter", entry is required. * @param CANdevRx CAN device for PDO reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param [out] errInfo Additional information in case of error, may be NULL. @@ -307,9 +255,8 @@ CO_ReturnError_t CO_RPDO_init(CO_RPDO_t* RPDO, OD_t* OD, CO_EM_t* em, /** * Initialize RPDO callback function. * - * Function initializes optional callback function, which should immediately - * start processing of CO_RPDO_process() function. - * Callback is called after RPDO message is received from the CAN bus. + * Function initializes optional callback function, which should immediately start processing of CO_RPDO_process() + * function. Callback is called after RPDO message is received from the CAN bus. * * @param RPDO This object. * @param object Pointer to object, which will be passed to pFunctSignalPre(). @@ -321,17 +268,15 @@ void CO_RPDO_initCallbackPre(CO_RPDO_t* RPDO, void* object, void (*pFunctSignalP /** * Process received PDO messages. * - * Function must be called cyclically in any NMT state. It copies data from RPDO - * to Object Dictionary variables if: new PDO receives and PDO is valid and NMT - * operating state is operational. Synchronous RPDOs are processed after next - * SYNC message. + * Function must be called cyclically in any NMT state. It copies data from RPDO to Object Dictionary variables if: new + * PDO receives and PDO is valid and NMT operating state is operational. Synchronous RPDOs are processed after next SYNC + * message. * * @param RPDO This object. * @param timeDifference_us Time difference from previous function call. * @param [out] timerNext_us info to OS - see CO_process(). * @param NMTisOperational True if this node is in NMT_OPERATIONAL state. - * @param syncWas True, if CANopen SYNC message was just received or - * transmitted. + * @param syncWas True, if CANopen SYNC message was just received or transmitted. */ void CO_RPDO_process(CO_RPDO_t* RPDO, #if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN @@ -348,52 +293,38 @@ void CO_RPDO_process(CO_RPDO_t* RPDO, * TPDO object. */ typedef struct { - /** PDO common properties, must be first element in this object */ - CO_PDO_common_t PDO_common; - /** CAN transmit buffer inside CANdev */ - CO_CANtx_t* CANtxBuff; - /** Copy of the variable from object dictionary */ - uint8_t transmissionType; - /** If this flag is set and TPDO is event driven (transmission type is 0, - * 254 or 255), then PDO will be sent by CO_TPDO_process(). */ - bool_t sendRequest; + CO_PDO_common_t PDO_common; /**< PDO common properties, must be first element in this object */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdev */ + uint8_t transmissionType; /**< Copy of the variable from object dictionary */ + bool_t sendRequest; /**< If this flag is set and TPDO is event driven (transmission type is 0, 254 or 255), + then PDO will be sent by CO_TPDO_process(). */ #if (((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0) || defined CO_DOXYGEN - /** From CO_TPDO_init() */ - CO_SYNC_t* SYNC; - /** Copy of the variable from object dictionary */ - uint8_t syncStartValue; - /** SYNC counter used for PDO sending */ - uint8_t syncCounter; + CO_SYNC_t* SYNC; /**< From CO_TPDO_init() */ + uint8_t syncStartValue; /**< Copy of the variable from object dictionary */ + uint8_t syncCounter; /**< SYNC counter used for PDO sending */ #endif #if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN - /** Inhibit time from object dictionary translated to microseconds */ - uint32_t inhibitTime_us; - /** Event time from object dictionary translated to microseconds */ - uint32_t eventTime_us; - /** Inhibit timer variable in microseconds */ - uint32_t inhibitTimer; - /** Event timer variable in microseconds */ - uint32_t eventTimer; + uint32_t inhibitTime_us; /**< Inhibit time from object dictionary translated to microseconds */ + uint32_t eventTime_us; /**< Event time from object dictionary translated to microseconds */ + uint32_t inhibitTimer; /**< Inhibit timer variable in microseconds */ + uint32_t eventTimer; /**< Event timer variable in microseconds */ #endif } CO_TPDO_t; /** * Initialize TPDO object. * - * Function must be called in the end of the communication reset section, after - * all application initialization. Otherwise mapping to application OD variables - * will not be correct. + * Function must be called in the end of the communication reset section, after all application initialization. + * Otherwise mapping to application OD variables will not be correct. * * @param TPDO This object will be initialized. * @param OD Object Dictionary. * @param em Emergency object. * @param SYNC SYNC object, may be NULL. - * @param preDefinedCanId CAN identifier from pre-defined connection set, - * including node-id for first four PDOs, or 0 otherwise, see @ref CO_PDO_CAN_ID - * @param OD_18xx_TPDOCommPar OD entry for 0x1800+ - "TPDO communication - * parameter", entry is required. - * @param OD_1Axx_TPDOMapPar OD entry for 0x1A00+ - "TPDO mapping parameter", - * entry is required. + * @param preDefinedCanId CAN identifier from pre-defined connection set, including node-id for first four PDOs, or 0 + * otherwise, see @ref CO_PDO_CAN_ID + * @param OD_18xx_TPDOCommPar OD entry for 0x1800+ - "TPDO communication parameter", entry is required. + * @param OD_1Axx_TPDOMapPar OD entry for 0x1A00+ - "TPDO mapping parameter", entry is required. * @param CANdevTx CAN device used for PDO transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. * @param [out] errInfo Additional information in case of error, may be NULL. @@ -410,9 +341,8 @@ CO_ReturnError_t CO_TPDO_init(CO_TPDO_t* TPDO, OD_t* OD, CO_EM_t* em, /** * Request transmission of TPDO message. * - * If TPDO transmission type is 0, 254 or 255, then TPDO will be sent by - * @ref CO_TPDO_process() after inhibit timer expires. See also - * @ref OD_requestTPDO() and @ref OD_TPDOtransmitted(). + * If TPDO transmission type is 0, 254 or 255, then TPDO will be sent by @ref CO_TPDO_process() after inhibit timer + * expires. See also @ref OD_requestTPDO() and @ref OD_TPDOtransmitted(). * * @param TPDO TPDO object. */ @@ -426,15 +356,13 @@ CO_TPDOsendRequest(CO_TPDO_t* TPDO) { /** * Process transmitting PDO messages. * - * Function must be called cyclically in any NMT state. It prepares and sends - * TPDO if necessary. + * Function must be called cyclically in any NMT state. It prepares and sends TPDO if necessary. * * @param TPDO This object. * @param timeDifference_us Time difference from previous function call. * @param [out] timerNext_us info to OS - see CO_process(). * @param NMTisOperational True if this node is in NMT_OPERATIONAL state. - * @param syncWas True, if CANopen SYNC message was just received or - * transmitted. + * @param syncWas True, if CANopen SYNC message was just received or transmitted. */ void CO_TPDO_process(CO_TPDO_t* TPDO, #if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN @@ -447,7 +375,7 @@ void CO_TPDO_process(CO_TPDO_t* TPDO, #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE) */ diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index df096cdf..2b1b4bee 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -51,30 +51,24 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * SDO client is able to access Object Dictionary variables from remote nodes. - * Usually there is one SDO client on CANopen network, which is able to - * configure other CANopen nodes. It is also possible to establish individual - * SDO client-server communication channels between devices. + * SDO client is able to access Object Dictionary variables from remote nodes. Usually there is one SDO client on + * CANopen network, which is able to configure other CANopen nodes. It is also possible to establish individual SDO + * client-server communication channels between devices. * - * SDO client is used in CANopenNode from CO_gateway_ascii.c with default SDO - * CAN identifiers. There is quite advanced usage in non-blocking function. + * SDO client is used in CANopenNode from CO_gateway_ascii.c with default SDO CAN identifiers. There is quite advanced + * usage in non-blocking function. * - * If enabled, SDO client is initialized in CANopen.c file with - * @ref CO_SDOclient_init() function. + * If enabled, SDO client is initialized in CANopen.c file with @ref CO_SDOclient_init() function. * * Basic usage: * @code{.c} -CO_SDO_abortCode_t read_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, - uint16_t index, uint8_t subIndex, - uint8_t *buf, size_t bufSize, size_t *readSize) -{ +CO_SDO_abortCode_t +read_SDO(CO_SDOclient_t* SDO_C, uint8_t nodeId, uint16_t index, uint8_t subIndex, uint8_t* buf, size_t bufSize, + size_t* readSize) { CO_SDO_return_t SDO_ret; // setup client (this can be skipped, if remote device don't change) - SDO_ret = CO_SDOclient_setup(SDO_C, - CO_CAN_ID_SDO_CLI + nodeId, - CO_CAN_ID_SDO_SRV + nodeId, - nodeId); + SDO_ret = CO_SDOclient_setup(SDO_C, CO_CAN_ID_SDO_CLI + nodeId, CO_CAN_ID_SDO_SRV + nodeId, nodeId); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { return CO_SDO_AB_GENERAL; } @@ -90,44 +84,33 @@ CO_SDO_abortCode_t read_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, uint32_t timeDifference_us = 10000; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; - SDO_ret = CO_SDOclientUpload(SDO_C, - timeDifference_us, - false, - &abortCode, - NULL, NULL, NULL); + SDO_ret = CO_SDOclientUpload(SDO_C, timeDifference_us, false, &abortCode, NULL, NULL, NULL); if (SDO_ret < 0) { return abortCode; } sleep_us(timeDifference_us); - } while(SDO_ret > 0); + } while (SDO_ret > 0); - // copy data to the user buffer (for long data function must be called - // several times inside the loop) + // copy data to the user buffer (for long data function must be called several times inside the loop) *readSize = CO_SDOclientUploadBufRead(SDO_C, buf, bufSize); return CO_SDO_AB_NONE; } -CO_SDO_abortCode_t write_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, - uint16_t index, uint8_t subIndex, - uint8_t *data, size_t dataSize) -{ +CO_SDO_abortCode_t +write_SDO(CO_SDOclient_t* SDO_C, uint8_t nodeId, uint16_t index, uint8_t subIndex, uint8_t* data, size_t dataSize) { CO_SDO_return_t SDO_ret; bool_t bufferPartial = false; // setup client (this can be skipped, if remote device is the same) - SDO_ret = CO_SDOclient_setup(SDO_C, - CO_CAN_ID_SDO_CLI + nodeId, - CO_CAN_ID_SDO_SRV + nodeId, - nodeId); + SDO_ret = CO_SDOclient_setup(SDO_C, CO_CAN_ID_SDO_CLI + nodeId, CO_CAN_ID_SDO_SRV + nodeId, nodeId); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { return -1 } // initiate download - SDO_ret = CO_SDOclientDownloadInitiate(SDO_C, index, subIndex, - dataSize, 1000, false); + SDO_ret = CO_SDOclientDownloadInitiate(SDO_C, index, subIndex, dataSize, 1000, false); if (SDO_ret != CO_SDO_RT_ok_communicationEnd) { return -1 } @@ -139,23 +122,18 @@ CO_SDO_abortCode_t write_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, // If SDO Fifo buffer is too small, data can be refilled in the loop. } - //download data + // download data do { uint32_t timeDifference_us = 10000; CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE; - SDO_ret = CO_SDOclientDownload(SDO_C, - timeDifference_us, - false, - bufferPartial, - &abortCode, - NULL, NULL); + SDO_ret = CO_SDOclientDownload(SDO_C, timeDifference_us, false, bufferPartial, &abortCode, NULL, NULL); if (SDO_ret < 0) { return abortCode; } sleep_us(timeDifference_us); - } while(SDO_ret > 0); + } while (SDO_ret > 0); return CO_SDO_AB_NONE; } @@ -169,92 +147,57 @@ CO_SDO_abortCode_t write_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId, */ typedef struct { #if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_LOCAL) != 0) || defined CO_DOXYGEN - /** From CO_SDOclient_init() */ - OD_t* OD; - /** From CO_SDOclient_init() */ - uint8_t nodeId; - /** Object dictionary interface for locally transferred object */ - OD_IO_t OD_IO; + OD_t* OD; /**< From CO_SDOclient_init() */ + uint8_t nodeId; /**< From CO_SDOclient_init() */ + OD_IO_t OD_IO; /**< Object dictionary interface for locally transferred object */ #endif - /** From CO_SDOclient_init() */ - CO_CANmodule_t* CANdevRx; - /** From CO_SDOclient_init() */ - uint16_t CANdevRxIdx; - /** From CO_SDOclient_init() */ - CO_CANmodule_t* CANdevTx; - /** From CO_SDOclient_init() */ - uint16_t CANdevTxIdx; - /** CAN transmit buffer inside CANdevTx for CAN tx message */ - CO_CANtx_t* CANtxBuff; + CO_CANmodule_t* CANdevRx; /**< From CO_SDOclient_init() */ + uint16_t CANdevRxIdx; /**< From CO_SDOclient_init() */ + CO_CANmodule_t* CANdevTx; /**< From CO_SDOclient_init() */ + uint16_t CANdevTxIdx; /**< From CO_SDOclient_init() */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx for CAN tx message */ #if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN - /** Copy of CANopen COB_ID Client -> Server, meaning of the specific bits: - - Bit 0...10: 11-bit CAN identifier. - - Bit 11..30: reserved, must be 0. - - Bit 31: if 1, SDO client object is not used. */ - uint32_t COB_IDClientToServer; - /** Copy of CANopen COB_ID Server -> Client, similar as above */ - uint32_t COB_IDServerToClient; - /** Extension for OD object */ - OD_extension_t OD_1280_extension; + + uint32_t COB_IDClientToServer; /**< Copy of CANopen COB_ID Client -> Server, meaning of the specific bits: + - Bit 0...10: 11-bit CAN identifier. + - Bit 11..30: reserved, must be 0. + - Bit 31: if 1, SDO client object is not used. */ + uint32_t COB_IDServerToClient; /**< Copy of CANopen COB_ID Server -> Client, similar as above */ + OD_extension_t OD_1280_extension; /**< Extension for OD object */ #endif - /** Node-ID of the SDO server */ - uint8_t nodeIDOfTheSDOServer; - /* If true, SDO channel is valid */ - bool_t valid; - /** Index of current object in Object Dictionary */ - uint16_t index; - /** Subindex of current object in Object Dictionary */ - uint8_t subIndex; - /* If true, then data transfer is finished */ - bool_t finished; - /** Size of data, which will be transferred. It is optionally indicated by - * client in case of download or by server in case of upload. */ - size_t sizeInd; - /** Size of data which is actually transferred. */ - size_t sizeTran; - /** Internal state of the SDO client */ - volatile CO_SDO_state_t state; - /** Maximum timeout time between request and response in microseconds */ - uint32_t SDOtimeoutTime_us; - /** Timeout timer for SDO communication */ - uint32_t timeoutTimer; - /** CO_fifo_t object for data buffer (not pointer) */ - CO_fifo_t bufFifo; - /** Data buffer of usable size @ref CO_CONFIG_SDO_CLI_BUFFER_SIZE, used - * inside bufFifo. Must be one byte larger for fifo usage. */ - uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U]; - /** Indicates, if new SDO message received from CAN bus. It is not cleared, - * until received message is completely processed. */ - volatile void* CANrxNew; - /** 8 data bytes of the received message */ - uint8_t CANrxData[8]; + uint8_t nodeIDOfTheSDOServer; /**< Node-ID of the SDO server */ + bool_t valid; /**< If true, SDO channel is valid */ + uint16_t index; /**< Index of current object in Object Dictionary */ + uint8_t subIndex; /**< Subindex of current object in Object Dictionary */ + bool_t finished; /**< If true, then data transfer is finished */ + size_t sizeInd; /**< Size of data, which will be transferred. It is optionally indicated by client + in case of download or by server in case of upload. */ + size_t sizeTran; /**< Size of data which is actually transferred. */ + volatile CO_SDO_state_t state; /**< Internal state of the SDO client */ + uint32_t SDOtimeoutTime_us; /**< Maximum timeout time between request and response in microseconds */ + uint32_t timeoutTimer; /**< Timeout timer for SDO communication */ + CO_fifo_t bufFifo; /**< CO_fifo_t object for data buffer (not pointer) */ + uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U]; /**< Data buffer of usable size @ref CO_CONFIG_SDO_CLI_BUFFER_SIZE, + used inside bufFifo. Must be one byte larger for fifo usage. */ + volatile void* CANrxNew; /**< Indicates, if new SDO message received from CAN bus. It is not cleared, until received + message is completely processed. */ + uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ #if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_SDOclient_initCallbackPre() or NULL */ - void (*pFunctSignal)(void* object); - /** From CO_SDOclient_initCallbackPre() or NULL */ - void* functSignalObject; + void (*pFunctSignal)(void* object); /**< From CO_SDOclient_initCallbackPre() or NULL */ + void* functSignalObject; /**< From CO_SDOclient_initCallbackPre() or NULL */ #endif #if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_SEGMENTED) != 0) || defined CO_DOXYGEN - /** Toggle bit toggled in each segment in segmented transfer */ - uint8_t toggle; + uint8_t toggle; /**< Toggle bit toggled in each segment in segmented transfer */ #endif #if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0) || defined CO_DOXYGEN - /** Timeout time for SDO sub-block upload, half of #SDOtimeoutTime_us */ - uint32_t block_SDOtimeoutTime_us; - /** Timeout timer for SDO sub-block upload */ - uint32_t block_timeoutTimer; - /** Sequence number of segment in block, 1..127 */ - uint8_t block_seqno; - /** Number of segments per block, 1..127 */ - uint8_t block_blksize; - /** Number of bytes in last segment that do not contain data */ - uint8_t block_noData; - /** Server CRC support in block transfer */ - bool_t block_crcEnabled; - /** Last 7 bytes of data at block upload */ - uint8_t block_dataUploadLast[7]; - /** Calculated CRC checksum */ - uint16_t block_crc; + uint32_t block_SDOtimeoutTime_us; /**< Timeout time for SDO sub-block upload, half of #SDOtimeoutTime_us */ + uint32_t block_timeoutTimer; /**< Timeout timer for SDO sub-block upload */ + uint8_t block_seqno; /**< Sequence number of segment in block, 1..127 */ + uint8_t block_blksize; /**< Number of segments per block, 1..127 */ + uint8_t block_noData; /**< Number of bytes in last segment that do not contain data */ + bool_t block_crcEnabled; /**< Server CRC support in block transfer */ + uint8_t block_dataUploadLast[7]; /**< Last 7 bytes of data at block upload */ + uint16_t block_crc; /**< Calculated CRC checksum */ #endif } CO_SDOclient_t; @@ -264,13 +207,13 @@ typedef struct { * Function must be called in the communication reset section. * * @param SDO_C This object will be initialized. - * @param OD Object Dictionary. It is used in case, if client is accessing - * object dictionary from its own device. If NULL, it will be ignored. - * @param OD_1280_SDOcliPar OD entry for SDO client parameter (0x1280+). It - * may have IO extension enabled to allow dynamic configuration (see also + * @param OD Object Dictionary. It is used in case, if client is accessing object dictionary from its own device. If + * NULL, it will be ignored. + * @param OD_1280_SDOcliPar OD entry for SDO client parameter (0x1280+). It may have IO extension enabled to allow + * dynamic configuration (see also * @ref CO_CONFIG_FLAG_OD_DYNAMIC). Entry is required. - * @param nodeId CANopen Node ID of this device. It is used in case, if client - * is accessing object dictionary from its own device. If 0, it will be ignored. + * @param nodeId CANopen Node ID of this device. It is used in case, if client is accessing object dictionary from its + * own device. If 0, it will be ignored. * @param CANdevRx CAN device for SDO client reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for SDO client transmission. @@ -287,15 +230,12 @@ CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t* SDO_C, OD_t* OD, OD_entry_t* /** * Initialize SDOclient callback function. * - * Function initializes optional callback function, which should immediately - * start processing of CO_SDOclientDownload() or CO_SDOclientUpload() function. - * Callback is called after SDOclient message is received from the CAN bus or - * when new call without delay is necessary (exchange data with own SDO server - * or SDO block transfer is in progress). + * Function initializes optional callback function, which should immediately start processing of CO_SDOclientDownload() + * or CO_SDOclientUpload() function. Callback is called after SDOclient message is received from the CAN bus or when new + * call without delay is necessary (exchange data with own SDO server or SDO block transfer is in progress). * * @param SDOclient This object. - * @param object Pointer to object, which will be passed to pFunctSignal(). Can - * be NULL. + * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL. * @param pFunctSignal Pointer to the callback function. Not called if NULL. */ void CO_SDOclient_initCallbackPre(CO_SDOclient_t* SDOclient, void* object, void (*pFunctSignal)(void* object)); @@ -304,20 +244,17 @@ void CO_SDOclient_initCallbackPre(CO_SDOclient_t* SDOclient, void* object, void /** * Setup SDO client object. * - * Function is called in from CO_SDOclient_init() and each time when - * "SDO client parameter" is written. Application can call this function before - * new SDO communication. If parameters to this function are the same as before, - * then CAN is not reconfigured. + * Function is called in from CO_SDOclient_init() and each time when "SDO client parameter" is written. Application can + * call this function before new SDO communication. If parameters to this function are the same as before, then CAN is + * not reconfigured. * * @param SDO_C This object. * @param COB_IDClientToServer See @ref CO_SDOclient_t. * @param COB_IDServerToClient See @ref CO_SDOclient_t. - * @param nodeIDOfTheSDOServer Node-ID of the SDO server. If it is the same as - * node-ID of this node, then data will be exchanged with this node - * (without CAN communication). + * @param nodeIDOfTheSDOServer Node-ID of the SDO server. If it is the same as node-ID of this node, then data will be + * exchanged with this node (without CAN communication). * - * @return #CO_SDO_return_t, CO_SDO_RT_ok_communicationEnd or - * CO_SDO_RT_wrongArguments + * @return #CO_SDO_return_t, CO_SDO_RT_ok_communicationEnd or CO_SDO_RT_wrongArguments */ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t* SDO_C, uint32_t COB_IDClientToServer, uint32_t COB_IDServerToClient, uint8_t nodeIDOfTheSDOServer); @@ -325,21 +262,17 @@ CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t* SDO_C, uint32_t COB_IDClientT /** * Initiate SDO download communication. * - * Function initiates SDO download communication with server specified in - * CO_SDOclient_init() function. Data will be written to remote node. - * Function is non-blocking. + * Function initiates SDO download communication with server specified in CO_SDOclient_init() function. Data will be + * written to remote node. Function is non-blocking. * * @param SDO_C This object. * @param index Index of object in object dictionary in remote node. * @param subIndex Subindex of object in object dictionary in remote node. - * @param sizeIndicated Optionally indicate size of data to be downloaded. - * Actual data are written with one or multiple CO_SDOclientDownloadBufWrite() - * calls. - * - If sizeIndicated is different than 0, then total number of data - * written by CO_SDOclientDownloadBufWrite() will be compared against - * sizeIndicated. Also sizeIndicated info will be passed to the server, which - * will compare actual data size downloaded. In case of mismatch, SDO abort - * message will be generated. + * @param sizeIndicated Optionally indicate size of data to be downloaded. Actual data are written with one or multiple + * CO_SDOclientDownloadBufWrite() calls. + * - If sizeIndicated is different than 0, then total number of data written by CO_SDOclientDownloadBufWrite() will be + * compared against sizeIndicated. Also sizeIndicated info will be passed to the server, which will compare actual + * data size downloaded. In case of mismatch, SDO abort message will be generated. * - If sizeIndicated is 0, then actual data size will not be verified. * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param blockEnable Try to initiate block transfer. @@ -352,9 +285,8 @@ CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t* SDO_C, uint16_t ind /** * Initiate SDO download communication - update size. * - * This is optional function, which updates sizeIndicated, if it was not known - * in the CO_SDOclientDownloadInitiate() function call. This function can be - * used after CO_SDOclientDownloadBufWrite(), but must be used before + * This is optional function, which updates sizeIndicated, if it was not known in the CO_SDOclientDownloadInitiate() + * function call. This function can be used after CO_SDOclientDownloadBufWrite(), but must be used before * CO_SDOclientDownload(). * * @param SDO_C This object. @@ -365,15 +297,13 @@ void CO_SDOclientDownloadInitSize(CO_SDOclient_t* SDO_C, size_t sizeIndicated); /** * Write data into SDO client buffer * - * This function copies data from buf into internal SDO client fifo buffer. - * Function returns number of bytes successfully copied. If there is not enough - * space in destination, not all bytes will be copied. Additional data can be - * copied in next cycles. If there is enough space in destination and - * sizeIndicated is different than zero, then all data must be written at once. + * This function copies data from buf into internal SDO client fifo buffer. Function returns number of bytes + * successfully copied. If there is not enough space in destination, not all bytes will be copied. Additional data can + * be copied in next cycles. If there is enough space in destination and sizeIndicated is different than zero, then all + * data must be written at once. * - * This function is basically a wrapper for CO_fifo_write() function. As - * alternative, other functions from CO_fifo can be used directly, for example - * CO_fifo_cpyTok2U8() or similar. + * This function is basically a wrapper for CO_fifo_write() function. As alternative, other functions from CO_fifo can + * be used directly, for example CO_fifo_cpyTok2U8() or similar. * * @param SDO_C This object. * @param buf Buffer which will be copied @@ -386,30 +316,24 @@ size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t* SDO_C, const uint8_t* buf, s /** * Process SDO download communication. * - * Function must be called cyclically until it returns <=0. It Proceeds SDO - * download communication initiated with CO_SDOclientDownloadInitiate(). - * Function is non-blocking. + * Function must be called cyclically until it returns <=0. It Proceeds SDO download communication initiated with + * CO_SDOclientDownloadInitiate(). Function is non-blocking. * - * If function returns #CO_SDO_RT_blockDownldInProgress and OS has buffer for - * CAN tx messages, then this function may be called multiple times within own - * loop. This can speed-up SDO block transfer. + * If function returns #CO_SDO_RT_blockDownldInProgress and OS has buffer for CAN tx messages, then this function may be + * called multiple times within own loop. This can speed-up SDO block transfer. * * @param SDO_C This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. - * @param send_abort If true, SDO client will send abort message from SDOabortCode - * and transmission will be aborted. - * @param bufferPartial True indicates, not all data were copied to internal - * buffer yet. Buffer will be refilled later with #CO_SDOclientDownloadBufWrite. - * @param [out] SDOabortCode In case of error in communication, SDO abort code - * contains reason of error. Ignored if NULL. + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param send_abort If true, SDO client will send abort message from SDOabortCode and transmission will be aborted. + * @param bufferPartial True indicates, not all data were copied to internal buffer yet. Buffer will be refilled later + * with #CO_SDOclientDownloadBufWrite. + * @param [out] SDOabortCode In case of error in communication, SDO abort code contains reason of error. Ignored if + * NULL. * @param [out] sizeTransferred Actual size of data transferred. Ignored if NULL * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * - * @return #CO_SDO_return_t. If less than 0, then error occurred, - * SDOabortCode contains reason and state becomes idle. If 0, communication - * ends successfully and state becomes idle. If greater than 0, then - * communication is in progress. + * @return #CO_SDO_return_t. If less than 0, then error occurred, SDOabortCode contains reason and state becomes idle. + * If 0, communication ends successfully and state becomes idle. If greater than 0, then communication is in progress. */ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t send_abort, bool_t bufferPartial, CO_SDO_abortCode_t* SDOabortCode, size_t* sizeTransferred, @@ -418,9 +342,8 @@ CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDiffere /** * Initiate SDO upload communication. * - * Function initiates SDO upload communication with server specified in - * CO_SDOclient_init() function. Data will be read from remote node. - * Function is non-blocking. + * Function initiates SDO upload communication with server specified in CO_SDOclient_init() function. Data will be read + * from remote node. Function is non-blocking. * * @param SDO_C This object. * @param index Index of object in object dictionary in remote node. @@ -436,32 +359,25 @@ CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t* SDO_C, uint16_t index /** * Process SDO upload communication. * - * Function must be called cyclically until it returns <=0. It Proceeds SDO - * upload communication initiated with CO_SDOclientUploadInitiate(). - * Function is non-blocking. + * Function must be called cyclically until it returns <=0. It Proceeds SDO upload communication initiated with + * CO_SDOclientUploadInitiate(). Function is non-blocking. * - * If this function returns #CO_SDO_RT_uploadDataBufferFull, then data must be - * read from fifo buffer to make it empty. This function can then be called - * once again immediately to speed-up block transfer. Note also, that remaining - * data must be read after function returns #CO_SDO_RT_ok_communicationEnd. - * Data must not be read, if function returns #CO_SDO_RT_blockUploadInProgress. + * If this function returns #CO_SDO_RT_uploadDataBufferFull, then data must be read from fifo buffer to make it empty. + * This function can then be called once again immediately to speed-up block transfer. Note also, that remaining data + * must be read after function returns #CO_SDO_RT_ok_communicationEnd. Data must not be read, if function returns + * #CO_SDO_RT_blockUploadInProgress. * * @param SDO_C This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. - * @param send_abort If true, SDO client will send abort message from SDOabortCode - * and reception will be aborted. - * @param [out] SDOabortCode In case of error in communication, SDO abort code - * contains reason of error. Ignored if NULL. - * @param [out] sizeIndicated If larger than 0, then SDO server has indicated - * size of data transfer. Ignored if NULL. + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param send_abort If true, SDO client will send abort message from SDOabortCode and reception will be aborted. + * @param [out] SDOabortCode In case of error in communication, SDO abort code contains reason of error. Ignored if + * NULL. + * @param [out] sizeIndicated If larger than 0, then SDO server has indicated size of data transfer. Ignored if NULL. * @param [out] sizeTransferred Actual size of data transferred. Ignored if NULL * @param [out] timerNext_us info to OS - see CO_process(). Ignored if NULL. * - * @return #CO_SDO_return_t. If less than 0, then error occurred, - * SDOabortCode contains reason and state becomes idle. If 0, communication - * ends successfully and state becomes idle. If greater than 0, then - * communication is in progress. + * @return #CO_SDO_return_t. If less than 0, then error occurred, SDOabortCode contains reason and state becomes idle. + * If 0, communication ends successfully and state becomes idle. If greater than 0, then communication is in progress. */ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t send_abort, CO_SDO_abortCode_t* SDOabortCode, size_t* sizeIndicated, size_t* sizeTransferred, @@ -470,16 +386,14 @@ CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifferenc /** * Read data from SDO client buffer. * - * This function copies data from internal fifo buffer of SDO client into buf. - * Function returns number of bytes successfully copied. It can be called in - * multiple cycles, if data length is large. + * This function copies data from internal fifo buffer of SDO client into buf. Function returns number of bytes + * successfully copied. It can be called in multiple cycles, if data length is large. * - * This function is basically a wrapper for CO_fifo_read() function. As - * alternative, other functions from CO_fifo can be used directly, for example - * CO_fifo_readU82a() or similar. + * This function is basically a wrapper for CO_fifo_read() function. As alternative, other functions from CO_fifo can be + * used directly, for example CO_fifo_readU82a() or similar. * - * @warning This function (or similar) must NOT be called when - * CO_SDOclientUpload() returns #CO_SDO_RT_blockUploadInProgress! + * @warning This function (or similar) must NOT be called when CO_SDOclientUpload() returns + * #CO_SDO_RT_blockUploadInProgress! * * @param SDO_C This object. * @param buf Buffer into which data will be copied @@ -492,9 +406,8 @@ size_t CO_SDOclientUploadBufRead(CO_SDOclient_t* SDO_C, uint8_t* buf, size_t cou /** * Close SDO communication temporary. * - * Function must be called after finish of each SDO client communication cycle. - * It disables reception of SDO client CAN messages. It is necessary, because - * CO_SDOclient_receive function may otherwise write into undefined SDO buffer. + * Function must be called after finish of each SDO client communication cycle. It disables reception of SDO client CAN + * messages. It is necessary, because CO_SDOclient_receive function may otherwise write into undefined SDO buffer. * * @param SDO_C This object. */ @@ -504,7 +417,7 @@ void CO_SDOclientClose(CO_SDOclient_t* SDO_C); #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE */ diff --git a/301/CO_SDOserver.h b/301/CO_SDOserver.h index 5f87fddc..5193aac4 100644 --- a/301/CO_SDOserver.h +++ b/301/CO_SDOserver.h @@ -44,33 +44,25 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ + * Service data objects (SDOs) allow the access to any entry of the CANopen Object dictionary. By SDO a peer-to-peer + * communication channel between two CANopen devices is established. In addition, the SDO protocol enables to transfer + * any amount of data in a segmented way. Therefore the SDO protocol is mainly used in order to communicate + * configuration data. * - * Service data objects (SDOs) allow the access to any entry of the CANopen - * Object dictionary. By SDO a peer-to-peer communication channel between two - * CANopen devices is established. In addition, the SDO protocol enables to - * transfer any amount of data in a segmented way. Therefore the SDO protocol is - * mainly used in order to communicate configuration data. + * All CANopen devices must have implemented SDO server and first SDO server channel. Servers serves data from Object + * dictionary. Object dictionary is a collection of variables, arrays or records (structures), which can be used by the + * stack or by the application. This file (CO_SDOserver.h) implements SDO server. * - * All CANopen devices must have implemented SDO server and first SDO server - * channel. Servers serves data from Object dictionary. Object dictionary - * is a collection of variables, arrays or records (structures), which can be - * used by the stack or by the application. This file (CO_SDOserver.h) - * implements SDO server. + * SDO client can be (optionally) implemented on one (or multiple, if multiple SDO channels are used) device in CANopen + * network. Usually this is master device and provides also some kind of user interface, so configuration of the network + * is possible. Code for the SDO client is in file CO_SDOclient.h. * - * SDO client can be (optionally) implemented on one (or multiple, if multiple - * SDO channels are used) device in CANopen network. Usually this is master - * device and provides also some kind of user interface, so configuration of - * the network is possible. Code for the SDO client is in file CO_SDOclient.h. - * - * SDO communication cycle is initiated by the client. Client can upload (read) - * data from device or can download (write) data to device. If data size is less - * or equal to 4 bytes, communication is finished by one server response - * (expedited transfer). If data size is longer, data are split into multiple - * segments of request/response pairs (normal or segmented transfer). For longer - * data there is also a block transfer protocol, which transfers larger block of - * data in secure way with little protocol overhead. If error occurs during SDO - * transfer #CO_SDO_abortCode_t is send by client or server and transfer is - * terminated. For more details see #CO_SDO_state_t. + * SDO communication cycle is initiated by the client. Client can upload (read) data from device or can download (write) + * data to device. If data size is less or equal to 4 bytes, communication is finished by one server response (expedited + * transfer). If data size is longer, data are split into multiple segments of request/response pairs (normal or + * segmented transfer). For longer data there is also a block transfer protocol, which transfers larger block of data in + * secure way with little protocol overhead. If error occurs during SDO transfer #CO_SDO_abortCode_t is send by client + * or server and transfer is terminated. For more details see #CO_SDO_state_t. * * Access to Object dictionary is specified in @ref CO_ODinterface. */ @@ -78,8 +70,8 @@ extern "C" { /** * Internal state flags indicate type of transfer * - * These flags correspond to the upper nibble of the SDO state machine states - * and can be used to determine the type of state an SDO object is in. + * These flags correspond to the upper nibble of the SDO state machine states and can be used to determine the type of + * state an SDO object is in. */ #define CO_SDO_ST_FLAG_DOWNLOAD 0x10U #define CO_SDO_ST_FLAG_UPLOAD 0x20U @@ -97,9 +89,8 @@ extern "C" { */ typedef enum { /** - * - SDO client may start new download to or upload from specified node, - * specified index and specified subindex. It can start normal or block - * communication. + * - SDO client may start new download to or upload from specified node, specified index and specified subindex. It + * can start normal or block communication. * - SDO server is waiting for client request. */ CO_SDO_ST_IDLE = 0x00U, /** @@ -110,19 +101,16 @@ typedef enum { CO_SDO_ST_ABORT = 0x01U, /** - * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, - * SDO client is the same device as SDO server. Transfer data directly without - * communication on CAN. + * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, SDO client is the same device as + * SDO server. Transfer data directly without communication on CAN. * - SDO server does not use this state. */ CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER = 0x10U, /** * - SDO client initiates SDO download: - * - byte 0: @b 0010nnes binary: (nn: if e=s=1, number of data bytes, that do - * @b not contain data; e=1 for expedited transfer; s=1 if data size is - * indicated.) + * - byte 0: @b 0010nnes binary: (nn: if e=s=1, number of data bytes, that do @b not contain data; e=1 for + * expedited transfer; s=1 if data size is indicated.) * - byte 1..3: Object index and subIndex. - * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for - * segmented transfer is indicated here. + * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for segmented transfer is indicated here. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ CO_SDO_ST_DOWNLOAD_INITIATE_REQ = 0x11U, /** @@ -135,9 +123,8 @@ typedef enum { CO_SDO_ST_DOWNLOAD_INITIATE_RSP = 0x12U, /** * - SDO client sends SDO segment: - * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; - * nnn: number of data bytes, that do @b not contain data; c=1 if this is the - * last segment). + * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; nnn: number of data bytes, that do + * @b not contain data; c=1 if this is the last segment). * - byte 1..7: Data segment. * - SDO server waits for segment. */ CO_SDO_ST_DOWNLOAD_SEGMENT_REQ = 0x13U, @@ -150,9 +137,8 @@ typedef enum { CO_SDO_ST_DOWNLOAD_SEGMENT_RSP = 0x14U, /** - * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, - * SDO client is the same device as SDO server. Transfer data directly without - * communication on CAN. + * - SDO client: Node-ID of the SDO server is the same as node-ID of this node, SDO client is the same device as + * SDO server. Transfer data directly without communication on CAN. * - SDO server does not use this state. */ CO_SDO_ST_UPLOAD_LOCAL_TRANSFER = 0x20U, /** @@ -165,12 +151,10 @@ typedef enum { /** * - SDO client waits for response. * - SDO server responses: - * - byte 0: @b 0100nnes binary: (nn: if e=s=1, number of data bytes, that do - * @b not contain data; e=1 for expedited transfer; s=1 if data size is - * indicated). + * - byte 0: @b 0100nnes binary: (nn: if e=s=1, number of data bytes, that do @b not contain data; e=1 for + * expedited transfer; s=1 if data size is indicated). * - byte 1..3: Object index and subIndex. - * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for - * segmented transfer is indicated here. + * - byte 4..7: If e=1, expedited data are here. If e=0 s=1, size of data for segmented transfer is indicated here. * - In case of expedited transfer communication ends here. */ CO_SDO_ST_UPLOAD_INITIATE_RSP = 0x22U, /** @@ -182,17 +166,15 @@ typedef enum { /** * - SDO client waits for response. * - SDO server responses with data: - * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; - * nnn: number of data bytes, that do @b not contain data; c=1 if this is the - * last segment). + * - byte 0: @b 000tnnnc binary: (t: toggle bit, set to 0 in first segment; nnn: number of data bytes, that do + * @b not contain data; c=1 if this is the last segment). * - byte 1..7: Data segment. * - If c is set to 1, then communication ends here. */ CO_SDO_ST_UPLOAD_SEGMENT_RSP = 0x24U, /** * - SDO client initiates SDO block download: - * - byte 0: @b 11000rs0 binary: (r=1 if client supports generating CRC on - * data; s=1 if data size is indicated.) + * - byte 0: @b 11000rs0 binary: (r=1 if client supports generating CRC on data; s=1 if data size is indicated.) * - byte 1..3: Object index and subIndex. * - byte 4..7: If s=1, then size of data for block download is indicated here. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ @@ -200,18 +182,16 @@ typedef enum { /** * - SDO client waits for response. * - SDO server responses: - * - byte 0: @b 10100r00 binary: (r=1 if server supports generating CRC on - * data.) + * - byte 0: @b 10100r00 binary: (r=1 if server supports generating CRC on data.) * - byte 1..3: Object index and subIndex. - * - byte 4: blksize: Number of segments per block that shall be used by the - * client for the following block download with 0 < blksize < 128. + * - byte 4: blksize: Number of segments per block that shall be used by the client for the following block + * download with 0 < blksize < 128. * - byte 5..7: Reserved. */ CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP = 0x52U, /** * - SDO client sends 'blksize' segments of data in sequence: - * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be downloaded, - * enter SDO block download end phase; nnnnnnn is sequence number of segment, - * 1..127. + * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be downloaded, enter SDO block download end phase; + * nnnnnnn is sequence number of segment, 1..127. * - byte 1..7: At most 7 bytes of segment data to be downloaded. * - SDO server reads sequence of 'blksize' blocks. */ CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ = 0x53U, @@ -219,21 +199,18 @@ typedef enum { * - SDO client waits for response. * - SDO server responses: * - byte 0: @b 10100010 binary. - * - byte 1: ackseq: sequence number of last segment that was received - * successfully during the last block download. If ackseq is set to 0 the - * server indicates the client that the segment with the sequence number 1 - * was not received correctly and all segments shall be retransmitted by the - * client. - * - byte 2: Number of segments per block that shall be used by the client for - * the following block download with 0 < blksize < 128. + * - byte 1: ackseq: sequence number of last segment that was received successfully during the last block + * download. If ackseq is set to 0 the server indicates the client that the segment with the sequence number 1 + * was not received correctly and all segments shall be retransmitted by the client. + * - byte 2: Number of segments per block that shall be used by the client for the following block download with + * 0 < blksize < 128. * - byte 3..7: Reserved. * - If c was set to 1, then communication enters SDO block download end phase. */ CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP = 0x54U, /** * - SDO client sends SDO block download end: - * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not - * contain data) + * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not contain data) * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. * - byte 3..7: Reserved. * - SDO server waits for client request. */ @@ -249,25 +226,21 @@ typedef enum { /** * - SDO client initiates SDO block upload: - * - byte 0: @b 10100r00 binary: (r=1 if client supports generating CRC on - * data.) + * - byte 0: @b 10100r00 binary: (r=1 if client supports generating CRC on data.) * - byte 1..3: Object index and subIndex. * - byte 4: blksize: Number of segments per block with 0 < blksize < 128. - * - byte 5: pst - protocol switch threshold. If pst > 0 and size of the data - * in bytes is less or equal pst, then the server may switch to the SDO - * upload protocol #CO_SDO_ST_UPLOAD_INITIATE_RSP. + * - byte 5: pst - protocol switch threshold. If pst > 0 and size of the data in bytes is less or equal pst, + * then the server may switch to the SDO upload protocol #CO_SDO_ST_UPLOAD_INITIATE_RSP. * - byte 6..7: Reserved. * - SDO server is in #CO_SDO_ST_IDLE state and waits for client request. */ CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ = 0x61U, /** * - SDO client waits for response. * - SDO server responses: - * - byte 0: @b 11000rs0 binary: (r=1 if server supports generating CRC on - * data; s=1 if data size is indicated. ) + * - byte 0: @b 11000rs0 binary: (r=1 if server supports generating CRC on data; s=1 if data size is indicated.) * - byte 1..3: Object index and subIndex. * - byte 4..7: If s=1, then size of data for block upload is indicated here. - * - If enabled by pst, then server may alternatively response with - * #CO_SDO_ST_UPLOAD_INITIATE_RSP */ + * - If enabled by pst, then server may alternatively response with #CO_SDO_ST_UPLOAD_INITIATE_RSP */ CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP = 0x62U, /** * - SDO client sends second initiate for SDO block upload: @@ -278,31 +251,27 @@ typedef enum { /** * - SDO client reads sequence of 'blksize' blocks. * - SDO server sends 'blksize' segments of data in sequence: - * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be uploaded, - * enter SDO block upload end phase; nnnnnnn is sequence number of segment, - * 1..127. + * - byte 0: @b cnnnnnnn binary: (c=1 if no more segments to be uploaded, enter SDO block upload end phase; + * nnnnnnn is sequence number of segment, 1..127. * - byte 1..7: At most 7 bytes of segment data to be uploaded. */ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ = 0x64U, /** * - SDO client responses: * - byte 0: @b 10100010 binary. - * - byte 1: ackseq: sequence number of last segment that was received - * successfully during the last block upload. If ackseq is set to 0 the - * client indicates the server that the segment with the sequence number 1 - * was not received correctly and all segments shall be retransmitted by the - * server. - * - byte 2: Number of segments per block that shall be used by the server for - * the following block upload with 0 < blksize < 128. + * - byte 1: ackseq: sequence number of last segment that was received successfully during the last block + * upload. If ackseq is set to 0 the client indicates the server that the segment with the sequence number 1 was + * not received correctly and all segments shall be retransmitted by the server. + * - byte 2: Number of segments per block that shall be used by the server for the following block upload with + * 0 < blksize < 128. * - byte 3..7: Reserved. * - SDO server waits for response. - * - If c was set to 1 and all segments were successfull received, then - * communication enters SDO block upload end phase. */ + * - If c was set to 1 and all segments were successfull received, then communication enters SDO block upload end + * phase. */ CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP = 0x65U, /** * - SDO client waits for server request. * - SDO server sends SDO block upload end: - * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not - * contain data) + * - byte 0: @b 110nnn01 binary: (nnn: number of data bytes, that do @b not contain data) * - byte 1..2: 16 bit CRC for the data set, if enabled by client and server. * - byte 3..7: Reserved. */ CO_SDO_ST_UPLOAD_BLK_END_SREQ = 0x66U, @@ -311,9 +280,8 @@ typedef enum { * - byte 0: @b 10100001 binary. * - byte 1..7: Reserved. * - SDO server waits for response. - * - Block download successfully ends here. Note that this communication ends - * with client response. Client may then start next SDO communication - * immediately. + * - Block download successfully ends here. Note that this communication ends with client response. Client may + * then start next SDO communication immediately. */ CO_SDO_ST_UPLOAD_BLK_END_CRSP = 0x67U, } CO_SDO_state_t; @@ -326,193 +294,118 @@ typedef enum { * The abort codes not listed here are reserved. */ typedef enum { - /** 0x00000000, No abort */ - CO_SDO_AB_NONE = 0x00000000UL, - /** 0x05030000, Toggle bit not altered */ - CO_SDO_AB_TOGGLE_BIT = 0x05030000UL, - /** 0x05040000, SDO protocol timed out */ - CO_SDO_AB_TIMEOUT = 0x05040000UL, - /** 0x05040001, Command specifier not valid or unknown */ - CO_SDO_AB_CMD = 0x05040001UL, - /** 0x05040002, Invalid block size in block mode */ - CO_SDO_AB_BLOCK_SIZE = 0x05040002UL, - /** 0x05040003, Invalid sequence number in block mode */ - CO_SDO_AB_SEQ_NUM = 0x05040003UL, - /** 0x05040004, CRC error (block mode only) */ - CO_SDO_AB_CRC = 0x05040004UL, - /** 0x05040005, Out of memory */ - CO_SDO_AB_OUT_OF_MEM = 0x05040005UL, - /** 0x06010000, Unsupported access to an object */ - CO_SDO_AB_UNSUPPORTED_ACCESS = 0x06010000UL, - /** 0x06010001, Attempt to read a write only object */ - CO_SDO_AB_WRITEONLY = 0x06010001UL, - /** 0x06010002, Attempt to write a read only object */ - CO_SDO_AB_READONLY = 0x06010002UL, - /** 0x06020000, Object does not exist in the object dictionary */ - CO_SDO_AB_NOT_EXIST = 0x06020000UL, - /** 0x06040041, Object cannot be mapped to the PDO */ - CO_SDO_AB_NO_MAP = 0x06040041UL, - /** 0x06040042, Number and length of object to be mapped exceeds PDO - * length */ - CO_SDO_AB_MAP_LEN = 0x06040042UL, - /** 0x06040043, General parameter incompatibility reasons */ - CO_SDO_AB_PRAM_INCOMPAT = 0x06040043UL, - /** 0x06040047, General internal incompatibility in device */ - CO_SDO_AB_DEVICE_INCOMPAT = 0x06040047UL, - /** 0x06060000, Access failed due to hardware error */ - CO_SDO_AB_HW = 0x06060000UL, - /** 0x06070010, Data type does not match, length of service parameter does - * not match */ - CO_SDO_AB_TYPE_MISMATCH = 0x06070010UL, - /** 0x06070012, Data type does not match, length of service parameter too - * high */ - CO_SDO_AB_DATA_LONG = 0x06070012UL, - /** 0x06070013, Data type does not match, length of service parameter too - * short */ - CO_SDO_AB_DATA_SHORT = 0x06070013UL, - /** 0x06090011, Sub index does not exist */ - CO_SDO_AB_SUB_UNKNOWN = 0x06090011UL, - /** 0x06090030, Invalid value for parameter (download only). */ - CO_SDO_AB_INVALID_VALUE = 0x06090030UL, - /** 0x06090031, Value range of parameter written too high */ - CO_SDO_AB_VALUE_HIGH = 0x06090031UL, - /** 0x06090032, Value range of parameter written too low */ - CO_SDO_AB_VALUE_LOW = 0x06090032UL, - /** 0x06090036, Maximum value is less than minimum value. */ - CO_SDO_AB_MAX_LESS_MIN = 0x06090036UL, - /** 0x060A0023, Resource not available: SDO connection */ - CO_SDO_AB_NO_RESOURCE = 0x060A0023UL, - /** 0x08000000, General error */ - CO_SDO_AB_GENERAL = 0x08000000UL, - /** 0x08000020, Data cannot be transferred or stored to application */ - CO_SDO_AB_DATA_TRANSF = 0x08000020UL, - /** 0x08000021, Data cannot be transferred or stored to application because - * of local control */ - CO_SDO_AB_DATA_LOC_CTRL = 0x08000021UL, - /** 0x08000022, Data cannot be transferred or stored to application because - * of present device state */ - CO_SDO_AB_DATA_DEV_STATE = 0x08000022UL, - /** 0x08000023, Object dictionary not present or dynamic generation fails */ - CO_SDO_AB_DATA_OD = 0x08000023UL, - /** 0x08000024, No data available */ - CO_SDO_AB_NO_DATA = 0x08000024UL + CO_SDO_AB_NONE = 0x00000000UL, /**< 0x00000000, No abort */ + CO_SDO_AB_TOGGLE_BIT = 0x05030000UL, /**< 0x05030000, Toggle bit not altered */ + CO_SDO_AB_TIMEOUT = 0x05040000UL, /**< 0x05040000, SDO protocol timed out */ + CO_SDO_AB_CMD = 0x05040001UL, /**< 0x05040001, Command specifier not valid or unknown */ + CO_SDO_AB_BLOCK_SIZE = 0x05040002UL, /**< 0x05040002, Invalid block size in block mode */ + CO_SDO_AB_SEQ_NUM = 0x05040003UL, /**< 0x05040003, Invalid sequence number in block mode */ + CO_SDO_AB_CRC = 0x05040004UL, /**< 0x05040004, CRC error (block mode only) */ + CO_SDO_AB_OUT_OF_MEM = 0x05040005UL, /**< 0x05040005, Out of memory */ + CO_SDO_AB_UNSUPPORTED_ACCESS = 0x06010000UL, /**< 0x06010000, Unsupported access to an object */ + CO_SDO_AB_WRITEONLY = 0x06010001UL, /**< 0x06010001, Attempt to read a write only object */ + CO_SDO_AB_READONLY = 0x06010002UL, /**< 0x06010002, Attempt to write a read only object */ + CO_SDO_AB_NOT_EXIST = 0x06020000UL, /**< 0x06020000, Object does not exist in the object dictionary */ + CO_SDO_AB_NO_MAP = 0x06040041UL, /**< 0x06040041, Object cannot be mapped to the PDO */ + CO_SDO_AB_MAP_LEN = 0x06040042UL, /**< 0x06040042, Number and length of object to be mapped exceeds PDO + length */ + CO_SDO_AB_PRAM_INCOMPAT = 0x06040043UL, /**< 0x06040043, General parameter incompatibility reasons */ + CO_SDO_AB_DEVICE_INCOMPAT = 0x06040047UL, /**< 0x06040047, General internal incompatibility in device */ + CO_SDO_AB_HW = 0x06060000UL, /**< 0x06060000, Access failed due to hardware error */ + CO_SDO_AB_TYPE_MISMATCH = 0x06070010UL, /**< 0x06070010, Data type does not match, length of service parameter + does not match */ + CO_SDO_AB_DATA_LONG = 0x06070012UL, /**< 0x06070012, Data type does not match, length of service parameter + too high */ + CO_SDO_AB_DATA_SHORT = 0x06070013UL, /**< 0x06070013, Data type does not match, length of service parameter + too short */ + CO_SDO_AB_SUB_UNKNOWN = 0x06090011UL, /**< 0x06090011, Sub index does not exist */ + CO_SDO_AB_INVALID_VALUE = 0x06090030UL, /**< 0x06090030, Invalid value for parameter (download only). */ + CO_SDO_AB_VALUE_HIGH = 0x06090031UL, /**< 0x06090031, Value range of parameter written too high */ + CO_SDO_AB_VALUE_LOW = 0x06090032UL, /**< 0x06090032, Value range of parameter written too low */ + CO_SDO_AB_MAX_LESS_MIN = 0x06090036UL, /**< 0x06090036, Maximum value is less than minimum value. */ + CO_SDO_AB_NO_RESOURCE = 0x060A0023UL, /**< 0x060A0023, Resource not available: SDO connection */ + CO_SDO_AB_GENERAL = 0x08000000UL, /**< 0x08000000, General error */ + CO_SDO_AB_DATA_TRANSF = 0x08000020UL, /**< 0x08000020, Data cannot be transferred or stored to application */ + CO_SDO_AB_DATA_LOC_CTRL = 0x08000021UL, /**< 0x08000021, Data cannot be transferred or stored to application + because of local control */ + CO_SDO_AB_DATA_DEV_STATE = 0x08000022UL, /**< 0x08000022, Data cannot be transferred or stored to application + because of present device state */ + CO_SDO_AB_DATA_OD = 0x08000023UL, /**< 0x08000023, Object dictionary not present or dynamic generation + fails */ + CO_SDO_AB_NO_DATA = 0x08000024UL /**< 0x08000024, No data available */ } CO_SDO_abortCode_t; /** * Return values from SDO server or client functions. */ typedef enum { - /** Waiting in client local transfer. */ - CO_SDO_RT_waitingLocalTransfer = 6, - /** Data buffer is full. - * SDO client: data must be read before next upload cycle begins. */ - CO_SDO_RT_uploadDataBufferFull = 5, - /** CAN transmit buffer is full. Waiting. */ - CO_SDO_RT_transmittBufferFull = 4, - /** Block download is in progress. Sending train of messages. */ - CO_SDO_RT_blockDownldInProgress = 3, - /** Block upload is in progress. Receiving train of messages. - * SDO client: Data must not be read in this state. */ - CO_SDO_RT_blockUploadInProgress = 2, - /** Waiting server or client response. */ - CO_SDO_RT_waitingResponse = 1, - /** Success, end of communication. SDO client: uploaded data must be read.*/ - CO_SDO_RT_ok_communicationEnd = 0, - /** Error in arguments */ - CO_SDO_RT_wrongArguments = -2, - /** Communication ended with client abort */ - CO_SDO_RT_endedWithClientAbort = -9, - /** Communication ended with server abort */ - CO_SDO_RT_endedWithServerAbort = -10, + CO_SDO_RT_waitingLocalTransfer = 6, /**< Waiting in client local transfer. */ + CO_SDO_RT_uploadDataBufferFull = 5, /**< Data buffer is full. SDO client: data must be read before next upload + cycle begins. */ + CO_SDO_RT_transmittBufferFull = 4, /**< CAN transmit buffer is full. Waiting. */ + CO_SDO_RT_blockDownldInProgress = 3, /**< Block download is in progress. Sending train of messages. */ + CO_SDO_RT_blockUploadInProgress = 2, /**< Block upload is in progress. Receiving train of messages. SDO client: Data + must not be read in this state. */ + CO_SDO_RT_waitingResponse = 1, /**< Waiting server or client response. */ + CO_SDO_RT_ok_communicationEnd = 0, /**< Success, end of communication. SDO client: uploaded data must be read. */ + CO_SDO_RT_wrongArguments = -2, /**< Error in arguments */ + CO_SDO_RT_endedWithClientAbort = -9, /**< Communication ended with client abort */ + CO_SDO_RT_endedWithServerAbort = -10, /**< Communication ended with server abort */ } CO_SDO_return_t; /** * SDO server object. */ typedef struct { - /** From CO_SDOserver_init() */ - CO_CANmodule_t* CANdevTx; - /** CAN transmit buffer inside CANdevTx for CAN tx message */ - CO_CANtx_t* CANtxBuff; - /** From CO_SDOserver_init() */ - OD_t* OD; - /** From CO_SDOserver_init() */ - uint8_t nodeId; - /* If true, SDO channel is valid */ - bool_t valid; - /** Internal state of the SDO server */ - volatile CO_SDO_state_t state; - /** Object dictionary interface for current object. */ - OD_IO_t OD_IO; - /** Index of the current object in Object Dictionary */ - uint16_t index; - /** Subindex of the current object in Object Dictionary */ - uint8_t subIndex; - /** Indicates, if new SDO message received from CAN bus. It is not cleared, - * until received message is completely processed. */ - volatile void* CANrxNew; - /** 8 data bytes of the received message */ - uint8_t CANrxData[8]; + CO_CANmodule_t* CANdevTx; /**< From CO_SDOserver_init() */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx for CAN tx message */ + OD_t* OD; /**< From CO_SDOserver_init() */ + uint8_t nodeId; /**< From CO_SDOserver_init() */ + bool_t valid; /**< If true, SDO channel is valid */ + volatile CO_SDO_state_t state; /**< Internal state of the SDO server */ + OD_IO_t OD_IO; /**< Object dictionary interface for current object. */ + uint16_t index; /**< Index of the current object in Object Dictionary */ + uint8_t subIndex; /**< Subindex of the current object in Object Dictionary */ + volatile void* CANrxNew; /**< Indicates, if new SDO message received from CAN bus. It is not cleared, + until received message is completely processed. */ + uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ #if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN - /** From CO_SDOserver_init() */ - CO_CANmodule_t* CANdevRx; - /** From CO_SDOserver_init() */ - uint16_t CANdevRxIdx; - /** From CO_SDOserver_init() */ - uint16_t CANdevTxIdx; - /** Copy of CANopen COB_ID Client -> Server, meaning of the specific bits: - - Bit 0...10: 11-bit CAN identifier. - - Bit 11..30: reserved, must be 0. - - Bit 31: if 1, SDO client object is not used. */ - uint32_t COB_IDClientToServer; - /** Copy of CANopen COB_ID Server -> Client, similar as above */ - uint32_t COB_IDServerToClient; - /** Extension for OD object */ - OD_extension_t OD_1200_extension; + CO_CANmodule_t* CANdevRx; /**< From CO_SDOserver_init() */ + uint16_t CANdevRxIdx; /**< From CO_SDOserver_init() */ + uint16_t CANdevTxIdx; /**< From CO_SDOserver_init() */ + uint32_t COB_IDClientToServer; /**< Copy of CANopen COB_ID Client -> Server, meaning of the specific bits: + - Bit 0...10: 11-bit CAN identifier. + - Bit 11..30: reserved, must be 0. + - Bit 31: if 1, SDO client object is not used. */ + uint32_t COB_IDServerToClient; /**< Copy of CANopen COB_ID Server -> Client, similar as above */ + OD_extension_t OD_1200_extension; /**< Extension for OD object */ #endif #if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0) || defined CO_DOXYGEN - /** Size of data, which will be transferred. It is optionally indicated by - * client in case of download or by server in case of upload. */ - OD_size_t sizeInd; - /** Size of data which is actually transferred. */ - OD_size_t sizeTran; - /** Toggle bit toggled in each segment in segmented transfer */ - uint8_t toggle; - /** If true, then: data transfer is finished (by download) or read from OD - * variable is finished (by upload) */ - bool_t finished; - /** Maximum timeout time between request and response in microseconds */ - uint32_t SDOtimeoutTime_us; - /** Timeout timer for SDO communication */ - uint32_t timeoutTimer; - /** Interim data buffer for segmented or block transfer + byte for '\0' */ - uint8_t buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE + 1U]; - /** Offset of next free data byte available for write in the buffer. */ - OD_size_t bufOffsetWr; - /** Offset of first data available for read in the buffer */ - OD_size_t bufOffsetRd; + OD_size_t sizeInd; /**< Size of data, which will be transferred. It is optionally indicated by client + in case of download or by server in case of upload. */ + OD_size_t sizeTran; /**< Size of data which is actually transferred. */ + uint8_t toggle; /**< Toggle bit toggled in each segment in segmented transfer */ + bool_t finished; /**< If true, then: data transfer is finished (by download) or read from OD variable + is finished (by upload) */ + uint32_t SDOtimeoutTime_us; /**< Maximum timeout time between request and response in microseconds */ + uint32_t timeoutTimer; /**< Timeout timer for SDO communication */ + uint8_t buf[CO_CONFIG_SDO_SRV_BUFFER_SIZE + 1U]; /**< Interim data buffer for segmented or + block transfer + byte for '\0' */ + OD_size_t bufOffsetWr; /**< Offset of next free data byte available for write in the buffer. */ + OD_size_t bufOffsetRd; /**< Offset of first data available for read in the buffer */ #endif #if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0) || defined CO_DOXYGEN - /** Timeout time for SDO sub-block download, half of #SDOtimeoutTime_us */ - uint32_t block_SDOtimeoutTime_us; - /** Timeout timer for SDO sub-block download */ - uint32_t block_timeoutTimer; - /** Sequence number of segment in block, 1..127 */ - uint8_t block_seqno; - /** Number of segments per block, 1..127 */ - uint8_t block_blksize; - /** Number of bytes in last segment that do not contain data */ - uint8_t block_noData; - /** Client CRC support in block transfer */ - bool_t block_crcEnabled; - /** Calculated CRC checksum */ - uint16_t block_crc; + uint32_t block_SDOtimeoutTime_us; /**< Timeout time for SDO sub-block download, half of #SDOtimeoutTime_us */ + uint32_t block_timeoutTimer; /**< Timeout timer for SDO sub-block download */ + uint8_t block_seqno; /**< Sequence number of segment in block, 1..127 */ + uint8_t block_blksize; /**< Number of segments per block, 1..127 */ + uint8_t block_noData; /**< Number of bytes in last segment that do not contain data */ + bool_t block_crcEnabled; /**< Client CRC support in block transfer */ + uint16_t block_crc; /**< Calculated CRC checksum */ #endif #if (((CO_CONFIG_SDO_SRV)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_SDOserver_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void* object); - /** From CO_SDOserver_initCallbackPre() or NULL */ - void* functSignalObjectPre; + void (*pFunctSignalPre)(void* object); /**< From CO_SDOserver_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< From CO_SDOserver_initCallbackPre() or NULL */ #endif } CO_SDOserver_t; @@ -523,12 +416,11 @@ typedef struct { * * @param SDO This object will be initialized. * @param OD Object Dictionary. - * @param OD_1200_SDOsrvPar OD entry for SDO server parameter (0x1200+), can be - * NULL for default single SDO server and must not be NULL for additional SDO - * servers. With additional SDO servers it may also have IO extension enabled, - * to allow dynamic configuration (see also @ref CO_CONFIG_FLAG_OD_DYNAMIC). - * @param nodeId If this is first SDO channel, then "nodeId" is CANopen Node ID - * of this device. In all additional channels "nodeId" is ignored. + * @param OD_1200_SDOsrvPar OD entry for SDO server parameter (0x1200+), can be NULL for default single SDO server and + * must not be NULL for additional SDO servers. With additional SDO servers it may also have IO extension enabled, to + * allow dynamic configuration (see also @ref CO_CONFIG_FLAG_OD_DYNAMIC). + * @param nodeId If this is first SDO channel, then "nodeId" is CANopen Node ID of this device. In all additional + * channels "nodeId" is ignored. * @param SDOtimeoutTime_ms Timeout time for SDO communication in milliseconds. * @param CANdevRx CAN device for SDO server reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. @@ -546,14 +438,12 @@ CO_ReturnError_t CO_SDOserver_init(CO_SDOserver_t* SDO, OD_t* OD, OD_entry_t* OD /** * Initialize SDOrx callback function. * - * Function initializes optional callback function, which should immediately - * start processing of CO_SDOserver_process() function. - * Callback is called after SDOserver message is received from the CAN bus or - * when new call without delay is necessary (SDO block transfer is in progress). + * Function initializes optional callback function, which should immediately start processing of CO_SDOserver_process() + * function. Callback is called after SDOserver message is received from the CAN bus or when new call without delay is + * necessary (SDO block transfer is in progress). * * @param SDO This object. - * @param object Pointer to object, which will be passed to pFunctSignalPre(). - * Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ void CO_SDOserver_initCallbackPre(CO_SDOserver_t* SDO, void* object, void (*pFunctSignalPre)(void* object)); @@ -565,10 +455,8 @@ void CO_SDOserver_initCallbackPre(CO_SDOserver_t* SDO, void* object, void (*pFun * Function must be called cyclically. * * @param SDO This object. - * @param NMTisPreOrOperational True if #CO_NMT_internalState_t is - * NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. + * @param NMTisPreOrOperational True if #CO_NMT_internalState_t is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). * * @return #CO_SDO_return_t @@ -580,6 +468,6 @@ CO_SDO_return_t CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOpera #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* CO_SDO_SERVER_H */ diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 080f0f8f..2d2ab94c 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -46,101 +46,71 @@ extern "C" { * @{ * For CAN identifier see #CO_Default_CAN_ID_t * - * SYNC message is used for synchronization of the nodes on network. One node - * can be SYNC producer, others can be SYNC consumers. Synchronous TPDOs are - * transmitted after the CANopen SYNC message. Synchronous received PDOs are - * accepted(copied to OD) immediatelly after the reception of the next SYNC - * message. + * SYNC message is used for synchronization of the nodes on network. One node can be SYNC producer, others can be SYNC + * consumers. Synchronous TPDOs are transmitted after the CANopen SYNC message. Synchronous received PDOs are + * accepted(copied to OD) immediatelly after the reception of the next SYNC message. * * ####Contents of SYNC message - * By default SYNC message has no data. If _Synchronous counter overflow value_ - * from Object dictionary (index 0x1019) is different than 0, SYNC message has - * one data byte: _counter_ incremented by 1 with every SYNC transmission. + * By default SYNC message has no data. If _Synchronous counter overflow value_ from Object dictionary (index 0x1019) is + * different than 0, SYNC message has one data byte: _counter_ incremented by 1 with every SYNC transmission. * * ####SYNC in CANopenNode - * According to CANopen, synchronous RPDOs must be processed after reception of - * the next sync messsage. For that reason, there is a double receive buffer - * for each synchronous RPDO. At the moment, when SYNC is received or - * transmitted, internal variable CANrxToggle toggles. That variable is then - * used by synchronous RPDO to determine, which of the two buffers is used for - * RPDO reception and which for RPDO processing. + * According to CANopen, synchronous RPDOs must be processed after reception of the next sync messsage. For that reason, + * there is a double receive buffer for each synchronous RPDO. At the moment, when SYNC is received or transmitted, + * internal variable CANrxToggle toggles. That variable is then used by synchronous RPDO to determine, which of the two + * buffers is used for RPDO reception and which for RPDO processing. */ /** * SYNC producer and consumer object. */ typedef struct { - /** From CO_SYNC_init() */ - CO_EM_t* em; - /** Indicates, if new SYNC message received from CAN bus */ - volatile void* CANrxNew; - /** Set to nonzero value, if SYNC with wrong data length is received */ - uint8_t receiveError; - /** Variable toggles, if new SYNC message received from CAN bus */ - bool_t CANrxToggle; - /** Sync timeout monitoring: 0 = not started; 1 = started; 2 = sync timeout - * error state */ - uint8_t timeoutError; - /** Value from _Synchronous counter overflow value_ variable from Object - dictionary (index 0x1019) */ - uint8_t counterOverflowValue; - /** Counter of the SYNC message if counterOverflowValue is different than - * zero */ - uint8_t counter; - /** True, if current time is outside "synchronous window" (OD 1007) */ - bool_t syncIsOutsideWindow; - /** Timer for the SYNC message in [microseconds]. - Set to zero after received or transmitted SYNC message */ - uint32_t timer; - /**Pointer to variable in OD, "Communication cycle period" in microseconds*/ - uint32_t* OD_1006_period; - /** Pointer to variable in OD, "Synchronous window length" in microseconds*/ - uint32_t* OD_1007_window; + CO_EM_t* em; /**< From CO_SYNC_init() */ + volatile void* CANrxNew; /**< Indicates, if new SYNC message received from CAN bus */ + uint8_t receiveError; /**< Set to nonzero value, if SYNC with wrong data length is received */ + bool_t CANrxToggle; /**< Variable toggles, if new SYNC message received from CAN bus */ + uint8_t timeoutError; /**< Sync timeout monitoring: 0 = not started; 1 = started; 2 = sync timeout error state */ + uint8_t counterOverflowValue; /**< Value from _Synchronous counter overflow value_ variable from Object dictionary + (index 0x1019) */ + uint8_t counter; /**< Counter of the SYNC message if counterOverflowValue is different than zero */ + bool_t syncIsOutsideWindow; /**< True, if current time is outside "synchronous window" (OD 1007) */ + uint32_t timer; /**< Timer for the SYNC message in [microseconds]. Set to zero after received or + transmitted SYNC message */ + uint32_t* OD_1006_period; /**< Pointer to variable in OD, "Communication cycle period" in microseconds */ + uint32_t* OD_1007_window; /**< Pointer to variable in OD, "Synchronous window length" in microseconds */ #if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN - /** True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ - variable from Object dictionary (index 0x1005). */ - bool_t isProducer; - /** CAN transmit buffer inside CANdevTx */ - CO_CANtx_t* CANtxBuff; + bool_t isProducer; /**< True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ variable from + Object dictionary(index 0x1005).*/ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ #endif #if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN - /** From CO_SYNC_init() */ - CO_CANmodule_t* CANdevRx; - /** From CO_SYNC_init() */ - uint16_t CANdevRxIdx; - /** Extension for OD object */ - OD_extension_t OD_1005_extension; - /** CAN ID of the SYNC message. Calculated from _COB ID SYNC Message_ - variable from Object dictionary (index 0x1005). */ - uint16_t CAN_ID; + CO_CANmodule_t* CANdevRx; /**< From CO_SYNC_init() */ + uint16_t CANdevRxIdx; /**< From CO_SYNC_init() */ + OD_extension_t OD_1005_extension; /**< Extension for OD object */ + uint16_t CAN_ID; /**< CAN ID of the SYNC message. Calculated from _COB ID SYNC Message_ variable + from Object dictionary (index 0x1005). */ #if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN - /** From CO_SYNC_init() */ - CO_CANmodule_t* CANdevTx; - /** From CO_SYNC_init() */ - uint16_t CANdevTxIdx; - /** Extension for OD object */ - OD_extension_t OD_1019_extension; + CO_CANmodule_t* CANdevTx; /**< From CO_SYNC_init() */ + uint16_t CANdevTxIdx; /**< From CO_SYNC_init() */ + OD_extension_t OD_1019_extension; /**< Extension for OD object */ #endif #endif #if (((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_SYNC_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void* object); - /** From CO_SYNC_initCallbackPre() or NULL */ - void* functSignalObjectPre; + void (*pFunctSignalPre)(void* object); /**< From CO_SYNC_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< From CO_SYNC_initCallbackPre() or NULL */ #endif } CO_SYNC_t; -/** Return value for @ref CO_SYNC_process */ +/** + * Return value for @ref CO_SYNC_process + */ typedef enum { - /** No SYNC event in last cycle */ - CO_SYNC_NONE = 0, - /** SYNC message was received or transmitted in last cycle */ - CO_SYNC_RX_TX = 1, - /** Time has just passed SYNC window (OD_1007) in last cycle */ - CO_SYNC_PASSED_WINDOW = 2 + CO_SYNC_NONE = 0, /**< No SYNC event in last cycle */ + CO_SYNC_RX_TX = 1, /**< SYNC message was received or transmitted in last cycle */ + CO_SYNC_PASSED_WINDOW = 2 /**< Time has just passed SYNC window (OD_1007) in last cycle */ } CO_SYNC_status_t; /** @@ -150,14 +120,12 @@ typedef enum { * * @param SYNC This object will be initialized. * @param em Emergency object. - * @param OD_1005_cobIdSync OD entry for 0x1005 - "COB-ID SYNC message", - * entry is required. - * @param OD_1006_commCyclePeriod OD entry for 0x1006 - "Communication cycle - * period", entry is required if device is sync producer. - * @param OD_1007_syncWindowLen OD entry for 0x1007 - "Synchronous window - * length", entry is optional, may be NULL. - * @param OD_1019_syncCounterOvf OD entry for 0x1019 - "Synchronous counter - * overflow value", entry is optional, may be NULL. + * @param OD_1005_cobIdSync OD entry for 0x1005 - "COB-ID SYNC message", entry is required. + * @param OD_1006_commCyclePeriod OD entry for 0x1006 - "Communication cycle period", entry is required if device is + * sync producer. + * @param OD_1007_syncWindowLen OD entry for 0x1007 - "Synchronous window length", entry is optional, may be NULL. + * @param OD_1019_syncCounterOvf OD entry for 0x1019 - "Synchronous counter overflow value", entry is optional, may be + * NULL. * @param CANdevRx CAN device for SYNC reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for SYNC transmission. @@ -178,9 +146,8 @@ CO_ReturnError_t CO_SYNC_init(CO_SYNC_t* SYNC, CO_EM_t* em, OD_entry_t* OD_1005_ /** * Initialize SYNC callback function. * - * Function initializes optional callback function, which should immediately - * start processing of CO_SYNC_process() function. - * Callback is called after SYNC message is received from the CAN bus. + * Function initializes optional callback function, which should immediately start processing of CO_SYNC_process() + * function. Callback is called after SYNC message is received from the CAN bus. * * @param SYNC This object. * @param object Pointer to object, which will be passed to pFunctSignalPre(). @@ -193,9 +160,8 @@ void CO_SYNC_initCallbackPre(CO_SYNC_t* SYNC, void* object, void (*pFunctSignalP /** * Send SYNC message. * - * This function prepares and sends a SYNC object. The application should only - * call this if direct control of SYNC transmission is needed, otherwise use - * CO_SYNC_process(). + * This function prepares and sends a SYNC object. The application should only call this if direct control of SYNC + * transmission is needed, otherwise use CO_SYNC_process(). * * @param SYNC SYNC object. * @@ -219,10 +185,8 @@ CO_SYNCsend(CO_SYNC_t* SYNC) { * Function must be called cyclically. * * @param SYNC This object. - * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or - * NMT_OPERATIONAL state. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. + * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL state. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). * * @return @ref CO_SYNC_status_t @@ -234,7 +198,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t* SYNC, bool_t NMTisPreOrOperational, #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE */ diff --git a/301/CO_TIME.h b/301/CO_TIME.h index cf7e3522..86a2b9e7 100644 --- a/301/CO_TIME.h +++ b/301/CO_TIME.h @@ -42,68 +42,50 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * For CAN identifier see @ref CO_Default_CAN_ID_t + * For CAN identifier see @ref CO_Default_CAN_ID_t * - * TIME message is used for time synchronization of the nodes on the network. - * One node should be TIME producer, others can be TIME consumers. This is - * configured by COB_ID_TIME object 0x1012: + * TIME message is used for time synchronization of the nodes on the network. One node should be TIME producer, others + * can be TIME consumers. This is configured by COB_ID_TIME object 0x1012: * * - bit 31 should be set for a consumer * - bit 30 should be set for a producer * - bits 0..10 is CAN-ID, 0x100 by default * - * Current time can be read from @p CO_TIME_t->ms (milliseconds after midnight) - * and @p CO_TIME_t->days (number of days since January 1, 1984). Those values - * are updated on each @ref CO_TIME_process() call, either from internal timer - * or from received time stamp message. + * Current time can be read from @p CO_TIME_t->ms (milliseconds after midnight) and @p CO_TIME_t->days (number of days + * since January 1, 1984). Those values are updated on each @ref CO_TIME_process() call, either from internal timer or + * from received time stamp message. * - * Current time can be set with @ref CO_TIME_set() function, which is necessary - * at least once, if time producer. If configured, time stamp message is - * send from @ref CO_TIME_process() in intervals specified by @ref CO_TIME_set() + * Current time can be set with @ref CO_TIME_set() function, which is necessary at least once, if time producer. If + * configured, time stamp message is send from @ref CO_TIME_process() in intervals specified by @ref CO_TIME_set() */ -/** Length of the TIME message */ -#define CO_TIME_MSG_LENGTH 6U +#define CO_TIME_MSG_LENGTH 6U /**< Length of the TIME message */ /** * TIME producer and consumer object. */ typedef struct { - /** Received timestamp data */ - uint8_t timeStamp[CO_TIME_MSG_LENGTH]; - /** Milliseconds after midnight */ - uint32_t ms; - /** Number of days since January 1, 1984 */ - uint16_t days; - /** Residual microseconds calculated inside CO_TIME_process() */ - uint16_t residual_us; - /** True, if device is TIME consumer. Calculated from _COB ID TIME Message_ - variable from Object dictionary (index 0x1012). */ - bool_t isConsumer; - /** True, if device is TIME producer. Calculated from _COB ID TIME Message_ - variable from Object dictionary (index 0x1012). */ - bool_t isProducer; - /** Variable indicates, if new TIME message received from CAN bus */ - volatile void* CANrxNew; + uint8_t timeStamp[CO_TIME_MSG_LENGTH]; /**< Received timestamp data */ + uint32_t ms; /**< Milliseconds after midnight */ + uint16_t days; /**< Number of days since January 1, 1984 */ + uint16_t residual_us; /**< Residual microseconds calculated inside CO_TIME_process() */ + bool_t isConsumer; /**< True, if device is TIME consumer. Calculated from _COB ID TIME Message_ + variable from Object dictionary (index 0x1012). */ + bool_t isProducer; /**< True, if device is TIME producer. Calculated from _COB ID TIME Message_ + variable from Object dictionary (index 0x1012). */ + volatile void* CANrxNew; /**< Variable indicates, if new TIME message received from CAN bus */ #if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN - /** Interval for time producer in milli seconds */ - uint32_t producerInterval_ms; - /** Sync producer timer */ - uint32_t producerTimer_ms; - /** From CO_TIME_init() */ - CO_CANmodule_t* CANdevTx; - /** CAN transmit buffer */ - CO_CANtx_t* CANtxBuff; + uint32_t producerInterval_ms; /**< Interval for time producer in milli seconds */ + uint32_t producerTimer_ms; /**< Sync producer timer */ + CO_CANmodule_t* CANdevTx; /**< From CO_TIME_init() */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer */ #endif #if (((CO_CONFIG_TIME)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_TIME_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void* object); - /** From CO_TIME_initCallbackPre() or NULL */ - void* functSignalObjectPre; + void (*pFunctSignalPre)(void* object); /**< From CO_TIME_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< From CO_TIME_initCallbackPre() or NULL */ #endif #if (((CO_CONFIG_TIME)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN - /** Extension for OD object */ - OD_extension_t OD_1012_extension; + OD_extension_t OD_1012_extension; /**< Extension for OD object */ #endif } CO_TIME_t; @@ -113,8 +95,7 @@ typedef struct { * Function must be called in the communication reset section. * * @param TIME This object will be initialized. - * @param OD_1012_cobIdTimeStamp OD entry for 0x1012 - "COB-ID time stamp", - * entry is required. + * @param OD_1012_cobIdTimeStamp OD entry for 0x1012 - "COB-ID time stamp", entry is required. * @param CANdevRx CAN device for TIME reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for TIME transmission. @@ -134,9 +115,8 @@ CO_ReturnError_t CO_TIME_init(CO_TIME_t* TIME, OD_entry_t* OD_1012_cobIdTimeStam /** * Initialize TIME callback function. * - * Function initializes optional callback function, which should immediately - * start processing of CO_TIME_process() function. - * Callback is called after TIME message is received from the CAN bus. + * Function initializes optional callback function, which should immediately start processing of CO_TIME_process() + * function. Callback is called after TIME message is received from the CAN bus. * * @param TIME This object. * @param object Pointer to object, which will be passed to pFunctSignalPre(). @@ -170,15 +150,12 @@ CO_TIME_set(CO_TIME_t* TIME, uint32_t ms, uint16_t days, uint32_t producerInterv /** * Process TIME object. * - * Function must be called cyclically. It updates internal time from received - * time stamp message or from timeDifference_us. It also sends produces - * timestamp message, if producer and producerInterval_ms is set. + * Function must be called cyclically. It updates internal time from received time stamp message or from + * timeDifference_us. It also sends produces timestamp message, if producer and producerInterval_ms is set. * * @param TIME This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. - * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or - * NMT_OPERATIONAL state. + * @param timeDifference_us Time difference from previous function call in [microseconds]. + * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL state. * * @return True if new TIME stamp message recently received (consumer). */ @@ -188,7 +165,7 @@ bool_t CO_TIME_process(CO_TIME_t* TIME, bool_t NMTisPreOrOperational, uint32_t t #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE */ diff --git a/301/CO_driver.h b/301/CO_driver.h index 834e3697..e48c98f0 100644 --- a/301/CO_driver.h +++ b/301/CO_driver.h @@ -30,8 +30,7 @@ extern "C" { #endif -/* Stack configuration default global values. - * For more information see file CO_config.h. */ +/* Stack configuration default global values. For more information see file CO_config.h. */ #ifndef CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE #define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0) #endif @@ -59,50 +58,40 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * CANopenNode is designed for speed and portability. It runs efficiently on - * devices from simple 16-bit microcontrollers to PC computers. It can run in - * multiple threads. Reception of CAN messages is pre-processed with very fast - * functions. Time critical objects, such as PDO or SYNC are processed in - * real-time thread and other objects are processed in normal thread. See - * Flowchart in [README.md](index.html) for more information. + * CANopenNode is designed for speed and portability. It runs efficiently on devices from simple 16-bit microcontrollers + * to PC computers. It can run in multiple threads. Reception of CAN messages is pre-processed with very fast functions. + * Time critical objects, such as PDO or SYNC are processed in real-time thread and other objects are processed in + * normal thread. See Flowchart in [README.md](index.html) for more information. * * @anchor CO_obj * #### CANopenNode Object - * CANopenNode is implemented as a collection of different objects, for example - * SDO, SYNC, Emergency, PDO, NMT, Heartbeat, etc. Code is written in C language - * and tries to be object oriented. So each CANopenNode Object is implemented in - * a pair of .h/.c files. It basically contains a structure with all necessary - * variables and some functions which operates on it. CANopenNode Object is - * usually connected with one or more CAN receive or transmit Message Objects. - * (CAN message Object is a CAN message with specific 11-bit CAN identifier - * (usually one fixed or a range).) + * CANopenNode is implemented as a collection of different objects, for example SDO, SYNC, Emergency, PDO, NMT, + * Heartbeat, etc. Code is written in C language and tries to be object oriented. So each CANopenNode Object is + * implemented in a pair of .h/.c files. It basically contains a structure with all necessary variables and some + * functions which operates on it. CANopenNode Object is usually connected with one or more CAN receive or transmit + * Message Objects. (CAN message Object is a CAN message with specific 11-bit CAN identifier (usually one fixed or a + * range).) * * #### Hardware interface of CANopenNode * It consists of minimum three files: - * - **CO_driver.h** file declares common functions. This file is part of the - * CANopenNode. It is included from each .c file from CANopenNode. - * - **CO_driver_target.h** file declares microcontroller specific type - * declarations and defines some macros, which are necessary for CANopenNode. - * This file is included from CO_driver.h. + * - **CO_driver.h** file declares common functions. This file is part of the CANopenNode. It is included from each .c + * file from CANopenNode. + * - **CO_driver_target.h** file declares microcontroller specific type declarations and defines some macros, which are + * necessary for CANopenNode. This file is included from CO_driver.h. * - **CO_driver.c** file defines functions declared in CO_driver.h. * - * **CO_driver_target.h** and **CO_driver.c** files are specific for each - * different microcontroller and are not part of CANopenNode. There are separate - * projects for different microcontrollers, which usually include CANopenNode as - * a git submodule. CANopenNode only includes those two files in the `example` - * directory and they are basically empty. It should be possible to compile the - * `CANopenNode/example` on any system, however compiled program is not usable. - * CO_driver.h contains documentation for all necessary macros, types and - * functions. - * - * See [CANopenNode/Wiki](https://github.com/CANopenNode/CANopenNode/wiki) for a - * known list of available implementations of CANopenNode on different systems - * and microcontrollers. Everybody is welcome to extend the list with a link to - * his own implementation. - * - * Implementation of the hardware interface for specific microcontroller is not - * always an easy task. For reliable and efficient operation it is necessary to - * know some parts of the target microcontroller in detail (for example threads + * **CO_driver_target.h** and **CO_driver.c** files are specific for each different microcontroller and are not part of + * CANopenNode. There are separate projects for different microcontrollers, which usually include CANopenNode as a git + * submodule. CANopenNode only includes those two files in the `example` directory and they are basically empty. It + * should be possible to compile the `CANopenNode/example` on any system, however compiled program is not usable. + * CO_driver.h contains documentation for all necessary macros, types and functions. + * + * See [CANopenNode/Wiki](https://github.com/CANopenNode/CANopenNode/wiki) for a known list of available implementations + * of CANopenNode on different systems and microcontrollers. Everybody is welcome to extend the list with a link to his + * own implementation. + * + * Implementation of the hardware interface for specific microcontroller is not always an easy task. For reliable and + * efficient operation it is necessary to know some parts of the target microcontroller in detail (for example threads * (or interrupts), CAN module, etc.). */ @@ -121,50 +110,30 @@ extern "C" { * * Must be defined in the **CO_driver_target.h** file. * - * Depending on processor or compiler architecture, one of the two macros must - * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little - * endian. + * Depending on processor or compiler architecture, one of the two macros must be defined: CO_LITTLE_ENDIAN or + * CO_BIG_ENDIAN. CANopen itself is little endian. * - * Basic data types may be specified differently on different architectures. - * Usually `true` and `false` are defined in ``, `NULL` is defined in - * ``, `int8_t` to `uint64_t` are defined in ``. + * Basic data types may be specified differently on different architectures. Usually `true` and `false` are defined in + * ``, `NULL` is defined in ``, `int8_t` to `uint64_t` are defined in ``. */ -/** CO_LITTLE_ENDIAN or CO_BIG_ENDIAN must be defined */ -#define CO_LITTLE_ENDIAN -/** Macro must swap bytes, if CO_BIG_ENDIAN is defined */ -#define CO_SWAP_16(x) x -/** Macro must swap bytes, if CO_BIG_ENDIAN is defined */ -#define CO_SWAP_32(x) x -/** Macro must swap bytes, if CO_BIG_ENDIAN is defined */ -#define CO_SWAP_64(x) x -/** NULL, for general usage */ -#define NULL (0) -/** Logical true, for general use */ -#define true 1 -/** Logical false, for general use */ -#define false 0 -/** Boolean data type for general use */ -typedef uint_fast8_t bool_t; -/** INTEGER8 in CANopen (0002h), 8-bit signed integer */ -typedef signed char int8_t; -/** INTEGER16 in CANopen (0003h), 16-bit signed integer */ -typedef signed int int16_t; -/** INTEGER32 in CANopen (0004h), 32-bit signed integer */ -typedef signed long int int32_t; -/** INTEGER64 in CANopen (0015h), 64-bit signed integer */ -typedef signed long long int int64_t; -/** UNSIGNED8 in CANopen (0005h), 8-bit unsigned integer */ -typedef unsigned char uint8_t; -/** UNSIGNED16 in CANopen (0006h), 16-bit unsigned integer */ -typedef unsigned int uint16_t; -/** UNSIGNED32 in CANopen (0007h), 32-bit unsigned integer */ -typedef unsigned long int uint32_t; -/** UNSIGNED64 in CANopen (001Bh), 64-bit unsigned integer */ -typedef unsigned long long int uint64_t; -/** REAL32 in CANopen (0008h), single precision floating point value, 32-bit */ -typedef float float32_t; -/** REAL64 in CANopen (0011h), double precision floating point value, 64-bit */ -typedef double float64_t; +#define CO_LITTLE_ENDIAN /**< CO_LITTLE_ENDIAN or CO_BIG_ENDIAN must be defined */ +#define CO_SWAP_16(x) x /**< Macro must swap bytes, if CO_BIG_ENDIAN is defined */ +#define CO_SWAP_32(x) x /**< Macro must swap bytes, if CO_BIG_ENDIAN is defined */ +#define CO_SWAP_64(x) x /**< Macro must swap bytes, if CO_BIG_ENDIAN is defined */ +#define NULL (0) /**< NULL, for general usage */ +#define true 1 /**< Logical true, for general use */ +#define false 0 /**< Logical false, for general use */ +typedef uint_fast8_t bool_t; /**< Boolean data type for general use */ +typedef signed char int8_t; /**< INTEGER8 in CANopen (0002h), 8-bit signed integer */ +typedef signed int int16_t; /**< INTEGER16 in CANopen (0003h), 16-bit signed integer */ +typedef signed long int int32_t; /**< INTEGER32 in CANopen (0004h), 32-bit signed integer */ +typedef signed long long int int64_t; /**< INTEGER64 in CANopen (0015h), 64-bit signed integer */ +typedef unsigned char uint8_t; /**< UNSIGNED8 in CANopen (0005h), 8-bit unsigned integer */ +typedef unsigned int uint16_t; /**< UNSIGNED16 in CANopen (0006h), 16-bit unsigned integer */ +typedef unsigned long int uint32_t; /**< UNSIGNED32 in CANopen (0007h), 32-bit unsigned integer */ +typedef unsigned long long int uint64_t; /**< UNSIGNED64 in CANopen (001Bh), 64-bit unsigned integer */ +typedef float float32_t; /**< REAL32 in CANopen (0008h), single precision floating point value, 32-bit */ +typedef double float64_t; /**< REAL64 in CANopen (0011h), double precision floating point value, 64-bit */ /** @} */ /** @@ -173,29 +142,24 @@ typedef double float64_t; * * Target specific definitions and description of CAN message reception * - * CAN messages in CANopenNode are usually received by its own thread or higher - * priority interrupt. Received CAN messages are first filtered by hardware or - * by software. Thread then examines its 11-bit CAN-id and mask and determines, - * to which \ref CO_obj "CANopenNode Object" it belongs to. After that it calls - * predefined CANrx_callback() function, which quickly pre-processes the message - * and fetches the relevant data. CANrx_callback() function is defined by each - * \ref CO_obj "CANopenNode Object" separately. Pre-processed fetched data are - * later processed in another thread. - * - * If \ref CO_obj "CANopenNode Object" reception of specific CAN message, it - * must first configure its own CO_CANrx_t object with the CO_CANrxBufferInit() - * function. + * CAN messages in CANopenNode are usually received by its own thread or higher priority interrupt. Received CAN + * messages are first filtered by hardware or by software. Thread then examines its 11-bit CAN-id and mask and + * determines, to which \ref CO_obj "CANopenNode Object" it belongs to. After that it calls predefined CANrx_callback() + * function, which quickly pre-processes the message and fetches the relevant data. CANrx_callback() function is defined + * by each \ref CO_obj "CANopenNode Object" separately. Pre-processed fetched data are later processed in another + * thread. + * + * If \ref CO_obj "CANopenNode Object" reception of specific CAN message, it must first configure its own CO_CANrx_t + * object with the CO_CANrxBufferInit() function. */ /** * CAN receive callback function which pre-processes received CAN message * - * It is called by fast CAN receive thread. Each \ref CO_obj "CANopenNode - * Object" defines its own and registers it with CO_CANrxBufferInit(), by - * passing function pointer. + * It is called by fast CAN receive thread. Each \ref CO_obj "CANopenNode Object" defines its own and registers it with + * CO_CANrxBufferInit(), by passing function pointer. * - * @param object pointer to specific \ref CO_obj "CANopenNode Object", - * registered with CO_CANrxBufferInit() + * @param object pointer to specific \ref CO_obj "CANopenNode Object", registered with CO_CANrxBufferInit() * @param rxMsg pointer to received CAN message */ void CANrx_callback(void* object, void* rxMsg); @@ -205,11 +169,9 @@ void CANrx_callback(void* object, void* rxMsg); * * Must be defined in the **CO_driver_target.h** file. * - * This is target specific function and is specific for specific - * microcontroller. It is best to implement it by using inline function or - * macro. `rxMsg` parameter should cast to a pointer to structure. For best - * efficiency structure may have the same alignment as CAN registers inside CAN - * module. + * This is target specific function and is specific for specific microcontroller. It is best to implement it by using + * inline function or macro. `rxMsg` parameter should cast to a pointer to structure. For best efficiency structure may + * have the same alignment as CAN registers inside CAN module. * * @param rxMsg Pointer to received message * @return 11-bit CAN standard identifier. @@ -246,24 +208,19 @@ CO_CANrxMsg_readData(void* rxMsg) { } /** - * Configuration object for CAN received message for specific \ref CO_obj - * "CANopenNode Object". + * Configuration object for CAN received message for specific \ref CO_obj "CANopenNode Object". * * Must be defined in the **CO_driver_target.h** file. * - * Data fields of this structure are used exclusively by the driver. Usually it - * has the following data fields, but they may differ for different - * microcontrollers. Array of multiple CO_CANrx_t objects is included inside - * CO_CANmodule_t. + * Data fields of this structure are used exclusively by the driver. Usually it has the following data fields, but they + * may differ for different microcontrollers. Array of multiple CO_CANrx_t objects is included inside CO_CANmodule_t. */ typedef struct { - uint16_t ident; /**< Standard CAN Identifier (bits 0..10) + RTR (bit 11) */ - uint16_t mask; /**< Standard CAN Identifier mask with the same alignment as - ident */ - void* object; /**< \ref CO_obj "CANopenNode Object" initialized in from - CO_CANrxBufferInit() */ - void (*pCANrx_callback)(void* object, void* message); /**< Pointer to CANrx_callback() - initialized in CO_CANrxBufferInit() */ + uint16_t ident; /**< Standard CAN Identifier (bits 0..10) + RTR (bit 11) */ + uint16_t mask; /**< Standard CAN Identifier mask with the same alignment as ident */ + void* object; /**< \ref CO_obj "CANopenNode Object" initialized in from CO_CANrxBufferInit() */ + void (*pCANrx_callback)(void* object, + void* message); /**< Pointer to CANrx_callback() initialized in CO_CANrxBufferInit() */ } CO_CANrx_t; /** @} */ @@ -274,37 +231,29 @@ typedef struct { * * Target specific definitions and description of CAN message transmission * - * If \ref CO_obj "CANopenNode Object" needs transmitting CAN message, it must - * first configure its own CO_CANtx_t object with the CO_CANtxBufferInit() - * function. CAN message can then be sent with CO_CANsend() function. If at that - * moment CAN transmit buffer inside microcontroller's CAN module is free, - * message is copied directly to the CAN module. Otherwise CO_CANsend() function - * sets _bufferFull_ flag to true. Message will be then sent by CAN TX interrupt - * as soon as CAN module is freed. Until message is not copied to CAN module, - * its contents must not change. If there are multiple CO_CANtx_t objects with - * _bufferFull_ flag set to true, then CO_CANtx_t with lower index will be sent - * first. + * If \ref CO_obj "CANopenNode Object" needs transmitting CAN message, it must first configure its own CO_CANtx_t object + * with the CO_CANtxBufferInit() function. CAN message can then be sent with CO_CANsend() function. If at that moment + * CAN transmit buffer inside microcontroller's CAN module is free, message is copied directly to the CAN module. + * Otherwise CO_CANsend() function sets _bufferFull_ flag to true. Message will be then sent by CAN TX interrupt as soon + * as CAN module is freed. Until message is not copied to CAN module, its contents must not change. If there are + * multiple CO_CANtx_t objects with _bufferFull_ flag set to true, then CO_CANtx_t with lower index will be sent first. */ /** - * Configuration object for CAN transmit message for specific \ref CO_obj - * "CANopenNode Object". + * Configuration object for CAN transmit message for specific \ref CO_obj "CANopenNode Object". * * Must be defined in the **CO_driver_target.h** file. * - * Data fields of this structure are used exclusively by the driver. Usually it - * has the following data fields, but they may differ for different - * microcontrollers. Array of multiple CO_CANtx_t objects is included inside - * CO_CANmodule_t. + * Data fields of this structure are used exclusively by the driver. Usually it has the following data fields, but they + * may differ for different microcontrollers. Array of multiple CO_CANtx_t objects is included inside CO_CANmodule_t. */ typedef struct { uint32_t ident; /**< CAN identifier as aligned in CAN module */ uint8_t DLC; /**< Length of CAN message */ uint8_t data[8]; /**< 8 data bytes */ - volatile bool_t bufferFull; /**< True if previous message is still in the - buffer */ - volatile bool_t syncFlag; /**< Synchronous PDO messages has this flag set. - It prevents them to be sent outside the synchronous window */ + volatile bool_t bufferFull; /**< True if previous message is still in the buffer */ + volatile bool_t syncFlag; /**< Synchronous PDO messages has this flag set. It prevents them to be sent outside the + synchronous window */ } CO_CANtx_t; /** @} */ @@ -314,31 +263,27 @@ typedef struct { * * Must be defined in the **CO_driver_target.h** file. * - * Usually it has the following data fields, but they may differ for different - * microcontrollers. + * Usually it has the following data fields, but they may differ for different microcontrollers. */ typedef struct { - void* CANptr; /**< From CO_CANmodule_init() */ - CO_CANrx_t* rxArray; /**< From CO_CANmodule_init() */ - uint16_t rxSize; /**< From CO_CANmodule_init() */ - CO_CANtx_t* txArray; /**< From CO_CANmodule_init() */ - uint16_t txSize; /**< From CO_CANmodule_init() */ - uint16_t CANerrorStatus; /**< CAN error status bitfield, - see @ref CO_CAN_ERR_status_t */ - volatile bool_t CANnormal; /**< CAN module is in normal mode */ - volatile bool_t useCANrxFilters; /**< Value different than zero indicates, - that CAN module hardware filters are used for CAN reception. If - there is not enough hardware filters, they won't be used. In this - case will be *all* received CAN messages processed by software. */ - volatile bool_t bufferInhibitFlag; /**< If flag is true, then message in - transmit buffer is synchronous PDO message, which will be aborted, - if CO_clearPendingSyncPDOs() function will be called by application. - This may be necessary if Synchronous window time was expired. */ - volatile bool_t firstCANtxMessage; /**< Equal to 1, when the first - transmitted message (bootup message) is in CAN TX buffers */ - volatile uint16_t CANtxCount; /**< Number of messages in transmit - buffer, which are waiting to be copied to the CAN module */ - uint32_t errOld; /**< Previous state of CAN errors */ + void* CANptr; /**< From CO_CANmodule_init() */ + CO_CANrx_t* rxArray; /**< From CO_CANmodule_init() */ + uint16_t rxSize; /**< From CO_CANmodule_init() */ + CO_CANtx_t* txArray; /**< From CO_CANmodule_init() */ + uint16_t txSize; /**< From CO_CANmodule_init() */ + uint16_t CANerrorStatus; /**< CAN error status bitfield, see @ref CO_CAN_ERR_status_t */ + volatile bool_t CANnormal; /**< CAN module is in normal mode */ + volatile bool_t useCANrxFilters; /**< Value different than zero indicates, that CAN module hardware filters are used + for CAN reception. If there is not enough hardware filters, they won't be used. + In this case will be *all* received CAN messages processed by software. */ + volatile bool_t bufferInhibitFlag; /**< If flag is true, then message in transmit buffer is synchronous PDO message, + which will be aborted, if CO_clearPendingSyncPDOs() function will be called by + application. This may be necessary if Synchronous window time was expired. */ + volatile bool_t + firstCANtxMessage; /**< Equal to 1, when the first transmitted message (bootup message) is in CAN TX buffers */ + volatile uint16_t + CANtxCount; /**< Number of messages in transmit buffer, which are waiting to be copied to the CAN module */ + uint32_t errOld; /**< Previous state of CAN errors */ } CO_CANmodule_t; /** @@ -346,40 +291,25 @@ typedef struct { * * Must be defined in the **CO_driver_target.h** file. * - * For more information on Data storage see @ref CO_storage or **CO_storage.h** - * file. Structure members documented here are always required or required with - * @ref CO_storage_eeprom. Target system may add own additional, hardware - * specific variables. + * For more information on Data storage see @ref CO_storage or **CO_storage.h** file. Structure members documented here + * are always required or required with @ref CO_storage_eeprom. Target system may add own additional, hardware specific + * variables. */ typedef struct { - /** Address of data to store, always required. */ - void* addr; - /** Length of data to store, always required. */ - size_t len; - /** Sub index in OD objects 1010 and 1011, from 2 to 127. Writing - * 0x65766173 to 1010,subIndexOD will store data to non-volatile memory. - * Writing 0x64616F6C to 1011,subIndexOD will restore default data, always - * required. */ - uint8_t subIndexOD; - /** Attribute from @ref CO_storage_attributes_t, always required. */ - uint8_t attr; - /** Pointer to storage module, target system specific usage, required with - * @ref CO_storage_eeprom. */ - void* storageModule; - /** CRC checksum of the data stored in eeprom, set on store, required with - * @ref CO_storage_eeprom. */ - uint16_t crc; - /** Address of entry signature inside eeprom, set by init, required with - * @ref CO_storage_eeprom. */ - size_t eepromAddrSignature; - /** Address of data inside eeprom, set by init, required with - * @ref CO_storage_eeprom. */ - size_t eepromAddr; - /** Offset of next byte being updated by automatic storage, required with - * @ref CO_storage_eeprom. */ - size_t offset; - /** Additional target specific parameters, optional. */ - void* additionalParameters; + void* addr; /**< Address of data to store, always required. */ + size_t len; /**< Length of data to store, always required. */ + uint8_t subIndexOD; /**< Sub index in OD objects 1010 and 1011, from 2 to 127. Writing 0x65766173 to 1010,subIndexOD + will store data to non-volatile memory Writing 0x64616F6C to 1011,subIndexOD will restore + default data, always required. */ + uint8_t attr; /**< Attribute from @ref CO_storage_attributes_t, always required. */ + void* storageModule; /**< Pointer to storage module, target system specific usage, required with @ref + CO_storage_eeprom. */ + uint16_t crc; /**< CRC checksum of the data stored in eeprom, set on store, required with @ref CO_storage_eeprom. */ + size_t eepromAddrSignature; /**< Address of entry signature inside eeprom, set by init, required with @ref + CO_storage_eeprom. */ + size_t eepromAddr; /**< Address of data inside eeprom, set by init, required with @ref CO_storage_eeprom. */ + size_t offset; /**< Offset of next byte being updated by automatic storage, required with @ref CO_storage_eeprom. */ + void* additionalParameters; /**< Additional target specific parameters, optional. */ } CO_storage_entry_t; /** @@ -388,70 +318,52 @@ typedef struct { * * Protection of critical sections in multi-threaded operation. * - * CANopenNode is designed to run in different threads, as described in - * [README.md](index.html). Threads are implemented differently in different - * systems. In microcontrollers threads are interrupts with different - * priorities, for example. It is necessary to protect sections, where different - * threads access to the same resource. In simple systems interrupts or - * scheduler may be temporary disabled between access to the shared resource. - * Otherwise mutexes or semaphores can be used. + * CANopenNode is designed to run in different threads, as described in [README.md](index.html). Threads are implemented + * differently in different systems. In microcontrollers threads are interrupts with different priorities, for example. + * It is necessary to protect sections, where different threads access to the same resource. In simple systems + * interrupts or scheduler may be temporary disabled between access to the shared resource. Otherwise mutexes or + * semaphores can be used. * * #### Reentrant functions - * Functions CO_CANsend() from C_driver.h, and CO_error() from CO_Emergency.h - * may be called from different threads. Critical sections must be protected. - * Either by disabling scheduler or interrupts or by mutexes or semaphores. - * Lock/unlock macro is called with pointer to CAN module, which may be used - * inside. + * Functions CO_CANsend() from C_driver.h, and CO_error() from CO_Emergency.h may be called from different threads. + * Critical sections must be protected. Either by disabling scheduler or interrupts or by mutexes or semaphores. + * Lock/unlock macro is called with pointer to CAN module, which may be used inside. * * #### Object Dictionary variables - * In general, there are two threads, which accesses OD variables: mainline - * (initialization, storage, SDO access) and timer (PDO access). CANopenNode - * uses locking mechanism, where SDO server (or other mainline code) prevents - * execution of the real-time thread at the moment it reads or writes OD - * variable. CO_LOCK_OD(CAN_MODULE) and CO_UNLOCK_OD(CAN_MODULE) macros - * are used to protect: + * In general, there are two threads, which accesses OD variables: mainline (initialization, storage, SDO access) and + * timer (PDO access). CANopenNode uses locking mechanism, where SDO server (or other mainline code) prevents execution + * of the real-time thread at the moment it reads or writes OD variable. CO_LOCK_OD(CAN_MODULE) and + * CO_UNLOCK_OD(CAN_MODULE) macros are used to protect: * - Whole real-time thread, - * - SDO server protects read/write access to OD variable. - * Locking of long OD variables, not accessible from real-time thread, may - * block RT thread. - * - Any mainline code, which accesses PDO-mappable OD variable, must protect - * read/write with locking macros. Use @ref OD_mappable() for check. - * - Other cases, where non-PDO-mappable OD variable is used inside real-time - * thread by some other part of the user application must be considered with - * special care. Also when there are multiple threads accessing the OD (e.g. - * when using a RTOS), you should always lock the OD. + * - SDO server protects read/write access to OD variable. Locking of long OD variables, not accessible from real-time + * thread, may block RT thread. + * - Any mainline code, which accesses PDO-mappable OD variable, must protect read/write with locking macros. Use @ref + * OD_mappable() for check. + * - Other cases, where non-PDO-mappable OD variable is used inside real-time thread by some other part of the user + * application must be considered with special care. Also when there are multiple threads accessing the OD + * (e.g. when using a RTOS), you should always lock the OD. * * #### Synchronization functions for CAN receive - * After CAN message is received, it is pre-processed in CANrx_callback(), which - * copies some data into appropriate object and at the end sets **new_message** - * flag. This flag is then pooled in another thread, which further processes the - * message. The problem is, that compiler optimization may shuffle memory - * operations, so it is necessary to ensure, that **new_message** flag is surely - * set at the end. It is necessary to use [Memory + * After CAN message is received, it is pre-processed in CANrx_callback(), which copies some data into appropriate + * object and at the end sets **new_message** flag. This flag is then pooled in another thread, which further processes + * the message. The problem is, that compiler optimization may shuffle memory operations, so it is necessary to ensure, + * that **new_message** flag is surely set at the end. It is necessary to use [Memory * barrier](https://en.wikipedia.org/wiki/Memory_barrier). * - * If receive function runs inside IRQ, no further synchronization is needed. - * Otherwise, some kind of synchronization has to be included. The following - * example uses GCC builtin memory barrier `__sync_synchronize()`. More - * information can be found - * [here](https://stackoverflow.com/questions/982129/what-does-sync-synchronize-do#982179). + * If receive function runs inside IRQ, no further synchronization is needed. Otherwise, some kind of synchronization + * has to be included. The following example uses GCC builtin memory barrier `__sync_synchronize()`. More information + * can be found [here](https://stackoverflow.com/questions/982129/what-does-sync-synchronize-do#982179). */ -/** Lock critical section in CO_CANsend() */ -#define CO_LOCK_CAN_SEND(CAN_MODULE) -/** Unlock critical section in CO_CANsend() */ -#define CO_UNLOCK_CAN_SEND(CAN_MODULE) -/** Lock critical section in CO_errorReport() or CO_errorReset() */ -#define CO_LOCK_EMCY(CAN_MODULE) -/** Unlock critical section in CO_errorReport() or CO_errorReset() */ -#define CO_UNLOCK_EMCY(CAN_MODULE) -/** Lock critical section when accessing Object Dictionary */ -#define CO_LOCK_OD(CAN_MODULE) -/** Unock critical section when accessing Object Dictionary */ -#define CO_UNLOCK_OD(CAN_MODULE) +#define CO_LOCK_CAN_SEND(CAN_MODULE) /**< Lock critical section in CO_CANsend() */ +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) /**< Unlock critical section in CO_CANsend() */ +#define CO_LOCK_EMCY(CAN_MODULE) /**< Lock critical section in CO_errorReport() or CO_errorReset() */ +#define CO_UNLOCK_EMCY(CAN_MODULE) /**< Unlock critical section in CO_errorReport() or CO_errorReset() */ +#define CO_LOCK_OD(CAN_MODULE) /**< Lock critical section when accessing Object Dictionary */ +#define CO_UNLOCK_OD(CAN_MODULE) /**< Unock critical section when accessing Object Dictionary */ /** Check if new message has arrived */ -#define CO_FLAG_READ(rxNew) ((rxNew) != NULL) +#define CO_FLAG_READ(rxNew) ((rxNew) != NULL) /** Set new message flag */ #define CO_FLAG_SET(rxNew) \ { \ @@ -472,10 +384,9 @@ typedef struct { * @defgroup CO_Default_CAN_ID_t Default CANopen identifiers * @{ * - * Default CANopen identifiers for CANopen communication objects. Same as - * 11-bit addresses of CAN messages. These are default identifiers and - * can be changed in CANopen. Especially PDO identifiers are configured - * in PDO linking phase of the CANopen network configuration. + * Default CANopen identifiers for CANopen communication objects. Same as 11-bit addresses of CAN messages. These are + * default identifiers and can be changed in CANopen. Especially PDO identifiers are configured in PDO linking phase of + * the CANopen network configuration. */ #define CO_CAN_ID_NMT_SERVICE 0x000U /**< 0x000 Network management */ #define CO_CAN_ID_GFC 0x001U /**< 0x001 Global fail-safe command */ @@ -502,8 +413,8 @@ typedef struct { /** * Restricted CAN-IDs * - * Macro for verifying 'Restricted CAN-IDs', as specified by standard CiA301. - * They shall not be used for SYNC, TIME, EMCY, PDO and SDO. + * Macro for verifying 'Restricted CAN-IDs', as specified by standard CiA301. They shall not be used for SYNC, TIME, + * EMCY, PDO and SDO. */ #ifndef CO_IS_RESTRICTED_CAN_ID #define CO_IS_RESTRICTED_CAN_ID(CAN_ID) \ @@ -516,10 +427,9 @@ typedef struct { * @defgroup CO_CAN_ERR_status_t CAN error status bitmasks * @{ * - * CAN warning level is reached, if CAN transmit or receive error counter is - * more or equal to 96. CAN passive level is reached, if counters are more or - * equal to 128. Transmitter goes in error state 'bus off' if transmit error - * counter is more or equal to 256. + * CAN warning level is reached, if CAN transmit or receive error counter is more or equal to 96. CAN passive level is + * reached, if counters are more or equal to 128. Transmitter goes in error state 'bus off' if transmit error counter is + * more or equal to 256. */ #define CO_CAN_ERRTX_WARNING 0x0001U /**< 0x0001 CAN transmitter warning */ #define CO_CAN_ERRTX_PASSIVE 0x0002U /**< 0x0002 CAN transmitter passive */ @@ -534,38 +444,30 @@ typedef struct { /** @} */ /* CO_CAN_ERR_status_t */ /** - * Return values of some CANopen functions. If function was executed - * successfully it returns 0 otherwise it returns <0. + * Return values of some CANopen functions. If function was executed successfully it returns 0 otherwise it returns <0. */ typedef enum { - CO_ERROR_NO = 0, /**< Operation completed successfully */ - CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ - CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ - CO_ERROR_TIMEOUT = -3, /**< Function timeout */ - CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function - CO_CANmodule_init() */ - CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed - yet */ - CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ - CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ - CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ - CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, - buffer full */ - CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ - CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not configured - properly */ - CO_ERROR_OD_PARAMETERS = -12, /**< Error in Object Dictionary parameters*/ - CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ - CO_ERROR_CRC = -14, /**< CRC does not match */ - CO_ERROR_TX_BUSY = -15, /**< Sending rejected because driver is - busy. Try again */ - CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current - state */ - CO_ERROR_SYSCALL = -17, /**< Syscall failed */ - CO_ERROR_INVALID_STATE = -18, /**< Driver not ready */ - CO_ERROR_NODE_ID_UNCONFIGURED_LSS = -19 /**< Node-id is in LSS unconfigured - state. If objects are handled properly, - this may not be an error. */ + CO_ERROR_NO = 0, /**< Operation completed successfully */ + CO_ERROR_ILLEGAL_ARGUMENT = -1, /**< Error in function arguments */ + CO_ERROR_OUT_OF_MEMORY = -2, /**< Memory allocation failed */ + CO_ERROR_TIMEOUT = -3, /**< Function timeout */ + CO_ERROR_ILLEGAL_BAUDRATE = -4, /**< Illegal baudrate passed to function CO_CANmodule_init() */ + CO_ERROR_RX_OVERFLOW = -5, /**< Previous message was not processed yet */ + CO_ERROR_RX_PDO_OVERFLOW = -6, /**< previous PDO was not processed yet */ + CO_ERROR_RX_MSG_LENGTH = -7, /**< Wrong receive message length */ + CO_ERROR_RX_PDO_LENGTH = -8, /**< Wrong receive PDO length */ + CO_ERROR_TX_OVERFLOW = -9, /**< Previous message is still waiting, buffer full */ + CO_ERROR_TX_PDO_WINDOW = -10, /**< Synchronous TPDO is outside window */ + CO_ERROR_TX_UNCONFIGURED = -11, /**< Transmit buffer was not configured properly */ + CO_ERROR_OD_PARAMETERS = -12, /**< Error in Object Dictionary parameters */ + CO_ERROR_DATA_CORRUPT = -13, /**< Stored data are corrupt */ + CO_ERROR_CRC = -14, /**< CRC does not match */ + CO_ERROR_TX_BUSY = -15, /**< Sending rejected because driver is busy. Try again */ + CO_ERROR_WRONG_NMT_STATE = -16, /**< Command can't be processed in current state */ + CO_ERROR_SYSCALL = -17, /**< Syscall failed */ + CO_ERROR_INVALID_STATE = -18, /**< Driver not ready */ + CO_ERROR_NODE_ID_UNCONFIGURED_LSS = + -19 /**< Node-id is in LSS unconfigured state. If objects are handled properly, this may not be an error. */ } CO_ReturnError_t; /** @@ -585,19 +487,16 @@ void CO_CANsetNormalMode(CO_CANmodule_t* CANmodule); /** * Initialize CAN module object. * - * Function must be called in the communication reset section. CAN module must - * be in Configuration Mode before. + * 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 CANptr Pointer to CAN device. * @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 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 Valid values are (in kbps): 10, 20, 50, 125, 250, 500, 800, - * 1000. If value is illegal, bitrate defaults to 125. + * @param txSize Size of the above array. Must be equal to number of transmitting CAN objects. + * @param CANbitRate Valid values are (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. If value is illegal, bitrate + * defaults to 125. * * Return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. */ @@ -614,27 +513,23 @@ void CO_CANmodule_disable(CO_CANmodule_t* CANmodule); /** * 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. + * 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. If two or more CANrx buffers - * have the same _ident_, then buffer with lowest _index_ has precedence and - * other CANrx buffers will be ignored. - * @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 ident 11-bit standard CAN Identifier. If two or more CANrx buffers have the same _ident_, then buffer with + * lowest _index_ has precedence and other CANrx buffers will be ignored. + * @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 CANrx_callback. Its type is (void), CANrx_callback will - * change its type back to the correct object type. - * @param CANrx_callback 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). + * @param object CANopen object, to which buffer is connected. It will be used as an argument to CANrx_callback. Its + * type is (void), CANrx_callback will change its type back to the correct object type. + * @param CANrx_callback 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, uint16_t index, uint16_t ident, uint16_t mask, bool_t rtr, void* object, void (*CANrx_callback)(void* object, void* message)); @@ -642,20 +537,19 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, u /** * Configure CAN message transmit buffer. * - * Function configures specific CAN transmit buffer. Function must be called for - * each member in _txArray_ from CO_CANmodule_t. + * 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 This flag bit is used for synchronous TPDO messages. If it is - * set, message will not be sent, if current time is outside synchronous window. + * @param syncFlag This flag bit is used for synchronous TPDO messages. If it is set, message will not be sent, if + * current time is outside synchronous window. * - * @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. + * @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, uint16_t index, uint16_t ident, bool_t rtr, uint8_t noOfBytes, bool_t syncFlag); @@ -664,25 +558,23 @@ CO_CANtx_t* CO_CANtxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16 * 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. + * @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). + * @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); /** * Clear all synchronous TPDOs from CAN module transmit buffers. * - * CANopen allows synchronous PDO communication only inside time between SYNC - * message and SYNC Window. If time is outside this window, new synchronous PDOs - * must not be sent and all pending sync TPDOs, which may be on CAN TX buffers, - * may optionally be cleared. + * CANopen allows synchronous PDO communication only inside time between SYNC message and SYNC Window. If time is + * outside this window, new synchronous PDOs must not be sent and all pending sync TPDOs, which may be on CAN TX + * buffers, may optionally be cleared. * - * This function checks (and aborts transmission if necessary) CAN TX buffers - * when it is called. Function should be called by the stack in the moment, - * when SYNC time was just passed out of synchronous window. + * This function checks (and aborts transmission if necessary) CAN TX buffers when it is called. Function should be + * called by the stack in the moment, when SYNC time was just passed out of synchronous window. * * @param CANmodule This object. */ @@ -691,8 +583,8 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t* CANmodule); /** * Process can module - verify CAN errors * - * Function must be called cyclically. It should calculate CANerrorStatus - * bitfield for CAN errors defined in @ref CO_CAN_ERR_status_t. + * Function must be called cyclically. It should calculate CANerrorStatus bitfield for CAN errors defined in @ref + * CO_CAN_ERR_status_t. * * @param CANmodule This object. */ diff --git a/301/CO_fifo.h b/301/CO_fifo.h index d588ea29..0b88809e 100644 --- a/301/CO_fifo.h +++ b/301/CO_fifo.h @@ -35,44 +35,34 @@ extern "C" { #endif /** - * @defgroup CO_CANopen_301_fifo FIFO circular buffer - * FIFO circular buffer for continuous data flow. + * @defgroup CO_CANopen_301_fifo FIFO circular buffer FIFO circular buffer for continuous data flow. * * @ingroup CO_CANopen_301 * @{ + * FIFO is organized as circular buffer with predefined capacity. It must be initialized by CO_fifo_init(). Functions + * are not not thread safe. * - * FIFO is organized as circular buffer with predefined capacity. It must be - * initialized by CO_fifo_init(). Functions are not not thread safe. + * It can be used as general purpose FIFO circular buffer for any data. Data can be written by CO_fifo_write() and read + * by CO_fifo_read() functions. * - * It can be used as general purpose FIFO circular buffer for any data. Data can - * be written by CO_fifo_write() and read by CO_fifo_read() functions. - * - * Buffer has additional functions for usage with CiA309-3 standard. It acts as - * circular buffer for storing ascii commands and fetching tokens from them. + * Buffer has additional functions for usage with CiA309-3 standard. It acts as circular buffer for storing ascii + * commands and fetching tokens from them. */ /** * Fifo object */ typedef struct { - /** Buffer of size bufSize. Initialized by CO_fifo_init() */ - uint8_t* buf; - /** Initialized by CO_fifo_init() */ - size_t bufSize; - /** Location in the buffer, which will be next written. */ - size_t writePtr; - /** Location in the buffer, which will be next read. */ - size_t readPtr; + uint8_t* buf; /**< Buffer of size bufSize. Initialized by CO_fifo_init() */ + size_t bufSize; /**< Initialized by CO_fifo_init() */ + size_t writePtr; /**< Location in the buffer, which will be next written. */ + size_t readPtr; /**< Location in the buffer, which will be next read. */ #if (((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ALT_READ) != 0) || defined CO_DOXYGEN - /** Location in the buffer, which will be next read. */ - size_t altReadPtr; + size_t altReadPtr; /**< Location in the buffer, which will be next read. */ #endif #if (((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_DATATYPES) != 0) || defined CO_DOXYGEN - /** helper variable, set to false in CO_fifo_reset(), used in some - * functions. */ - bool_t started; - /** auxiliary variable, used in some functions. */ - uint32_t aux; + bool_t started; /**< helper variable, set to false in CO_fifo_reset(), used in some functions. */ + uint32_t aux; /**< auxiliary variable, used in some functions. */ #endif } CO_fifo_t; @@ -81,8 +71,8 @@ typedef struct { * * @param fifo This object will be initialized * @param buf Pointer to externally defined buffer - * @param bufSize Size of the above buffer. Usable size of the buffer will be - * one byte less than bufSize, it is used for operation of the circular buffer. + * @param bufSize Size of the above buffer. Usable size of the buffer will be one byte less than bufSize, it is used for + * operation of the circular buffer. */ void CO_fifo_init(CO_fifo_t* fifo, uint8_t* buf, size_t bufSize); @@ -224,15 +214,13 @@ CO_fifo_getc(CO_fifo_t* fifo, uint8_t* buf) { /** * Write data into CO_fifo_t object. * - * This function copies data from buf into internal buffer of CO_fifo_t - * object. Function returns number of bytes successfully copied. - * If there is not enough space in destination, not all bytes will be copied. + * This function copies data from buf into internal buffer of CO_fifo_t object. Function returns number of bytes + * successfully copied. If there is not enough space in destination, not all bytes will be copied. * * @param fifo This object * @param buf Buffer which will be copied * @param count Number of bytes in buf - * @param [in,out] crc Externally defined variable for CRC checksum, ignored if - * NULL + * @param [in,out] crc Externally defined variable for CRC checksum, ignored if NULL * * @return number of bytes actually written. */ @@ -241,16 +229,14 @@ size_t CO_fifo_write(CO_fifo_t* fifo, const uint8_t* buf, size_t count, uint16_t /** * Read data from CO_fifo_t object. * - * This function copies data from internal buffer of CO_fifo_t object into - * buf. Function returns number of bytes successfully copied. Function also - * writes true into eof argument, if command delimiter character is reached. + * This function copies data from internal buffer of CO_fifo_t object into buf. Function returns number of bytes + * successfully copied. Function also writes true into eof argument, if command delimiter character is reached. * * @param fifo This object * @param buf Buffer into which data will be copied * @param count Copy up to count bytes into buffer - * @param [out] eof If different than NULL, then search for delimiter character. - * If found, then read up to (including) that character and set *eof to true. - * Otherwise set *eof to false. + * @param [out] eof If different than NULL, then search for delimiter character. If found, then read up to (including) + * that character and set *eof to true. Otherwise set *eof to false. * * @return number of bytes actually read. */ @@ -271,8 +257,7 @@ size_t CO_fifo_altBegin(CO_fifo_t* fifo, size_t offset); * Ends alternate read with #CO_fifo_altRead and calculate crc checksum * * @param fifo This object - * @param [in,out] crc Externally defined variable for CRC checksum, ignored if - * NULL + * @param [in,out] crc Externally defined variable for CRC checksum, ignored if NULL */ void CO_fifo_altFinish(CO_fifo_t* fifo, uint16_t* crc); @@ -296,12 +281,10 @@ CO_fifo_altGetOccupied(CO_fifo_t* fifo) { /** * Alternate read data from CO_fifo_t object. * - * This function is similar as CO_fifo_read(), but uses alternate read pointer - * inside circular buffer. It reads data from the buffer and data remains in it. - * This function uses alternate read pointer and keeps original read pointer - * unchanged. Before using this function, alternate read pointer must be - * initialized with CO_fifo_altBegin(). CO_fifo_altFinish() sets original read - * pointer to alternate read pointer and so empties the buffer. + * This function is similar as CO_fifo_read(), but uses alternate read pointer inside circular buffer. It reads data + * from the buffer and data remains in it. This function uses alternate read pointer and keeps original read pointer + * unchanged. Before using this function, alternate read pointer must be initialized with CO_fifo_altBegin(). + * CO_fifo_altFinish() sets original read pointer to alternate read pointer and so empties the buffer. * * @param fifo This object * @param buf Buffer into which data will be copied @@ -318,22 +301,18 @@ size_t CO_fifo_altRead(CO_fifo_t* fifo, uint8_t* buf, size_t count); * * If there are some data inside the FIFO, then search for command delimiter. * - * If command is long, then in the buffer may not be enough space for it. - * In that case buffer is full and no delimiter is present. Function then - * returns true and command should be processed for the starting tokens. - * Buffer can later be refilled multiple times, until command is closed by - * command delimiter. + * If command is long, then in the buffer may not be enough space for it. In that case buffer is full and no delimiter + * is present. Function then returns true and command should be processed for the starting tokens. Buffer can later be + * refilled multiple times, until command is closed by command delimiter. * - * If this function returns different than 0, then buffer is usually read - * by multiple CO_fifo_readToken() calls. If reads was successful, then - * delimiter is reached and fifo->readPtr is set after the command. If any - * CO_fifo_readToken() returns nonzero *err, then there is an error and command - * should be cleared. All this procedure must be implemented inside single - * function call. + * If this function returns different than 0, then buffer is usually read by multiple CO_fifo_readToken() calls. If + * reads was successful, then delimiter is reached and fifo->readPtr is set after the command. If any + * CO_fifo_readToken() returns nonzero *err, then there is an error and command should be cleared. All this procedure + * must be implemented inside single function call. * * @param fifo This object. - * @param clear If true, then command will be cleared from the - * buffer. If there is no delimiter, buffer will be cleared entirely. + * @param clear If true, then command will be cleared from the buffer. If there is no delimiter, buffer will be cleared + * entirely. * * @return true if command with delimiter found or buffer full. */ @@ -342,14 +321,12 @@ bool_t CO_fifo_CommSearch(CO_fifo_t* fifo, bool_t clear); /** * Trim spaces inside FIFO * - * Function removes all non graphical characters and comments from fifo - * buffer. It stops on first graphical character or on command delimiter (later - * is also removed). + * Function removes all non graphical characters and comments from fifo buffer. It stops on first graphical character or + * on command delimiter (later is also removed). * * @param fifo This object. - * @param [in, out] insideComment if set to true as input, it skips all - * characters and searches only for delimiter. As output it is set to true, if - * fifo is empty, is inside comment and command delimiter is not found. + * @param [in, out] insideComment if set to true as input, it skips all characters and searches only for delimiter. As + * output it is set to true, if fifo is empty, is inside comment and command delimiter is not found. * * @return true if command delimiter was found. */ @@ -358,19 +335,17 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t* fifo, bool_t* insideComment); /** * Get token from FIFO buffer * - * Function search FIFO buffer for token. Token is string of only graphical - * characters. Graphical character is any printable character except space with - * acsii code within limits: 0x20 < code < 0x7F (see isgraph() function). + * Function search FIFO buffer for token. Token is string of only graphical characters. Graphical character is any + * printable character except space with acsii code within limits: 0x20 < code < 0x7F (see isgraph() function). * - * If token is found, then copy it to the buf, if count is large enough. On - * success also set readPtr to point to the next graphical character. + * If token is found, then copy it to the buf, if count is large enough. On success also set readPtr to point to the + * next graphical character. * - * Each token must have at least one empty space after it (space, command - * delimiter, '\0', etc.). Delimiter must not be graphical character. + * Each token must have at least one empty space after it (space, command delimiter, '\0', etc.). Delimiter must not be + * graphical character. * - * If comment delimiter (delimComment, see #CO_fifo_init) character is found, - * then all string till command delimiter (delimCommand, see #CO_fifo_init) will - * be erased from the buffer. + * If comment delimiter (delimComment, see #CO_fifo_init) character is found, then all string till command delimiter + * (delimCommand, see #CO_fifo_init) will be erased from the buffer. * * See also #CO_fifo_CommSearch(). * @@ -378,17 +353,14 @@ bool_t CO_fifo_trimSpaces(CO_fifo_t* fifo, bool_t* insideComment); * @param buf Buffer into which data will be copied. Will be terminated by '\0'. * @param count Copy up to count bytes into buffer * @param [in,out] closed This is input/output variable. Not used if NULL. - * - As output variable it is set to 1, if command delimiter (delimCommand, - * see #CO_fifo_init) is found after the token and set to 0 otherwise. + * - As output variable it is set to 1, if command delimiter (delimCommand, see #CO_fifo_init) is found after the token + * and set to 0 otherwise. * - As input variable it is used for verifying error condition: - * - *closed = 0: Set *err to true if token is empty or command delimiter - * is found. - * - *closed = 1: Set *err to true if token is empty or command delimiter - * is NOT found. + * - *closed = 0: Set *err to true if token is empty or command delimiter is found. + * - *closed = 1: Set *err to true if token is empty or command delimiter is NOT found. * - *closed = any other value: No checking of token size or command delimiter. - * @param [out] err If not NULL, it is set to true if token is larger than buf - * or in matching combination in 'closed' argument. If it is already true, then - * function returns immediately. + * @param [out] err If not NULL, it is set to true if token is larger than buf or in matching combination in 'closed' + * argument. If it is already true, then function returns immediately. * * @return Number of bytes read. */ @@ -436,20 +408,15 @@ size_t CO_fifo_readR642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); /** Read data from fifo and output as space separated two digit ascii string, * see also CO_fifo_readU82a */ size_t CO_fifo_readHex2a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); -/** Read data from fifo and output as visible string. A visible string is - * enclosed with double quotes. If a double quote is used within the string, - * the quotes are escaped by a second quotes, e.g. “Hello “”World””, CANopen - * is great”. UTF-8 characters and also line breaks works with this function. - * Function removes all NULL and CR characters from output string. - * See also CO_fifo_readU82a */ +/** Read data from fifo and output as visible string. A visible string is enclosed with double quotes. If a double quote + * is used within the string, the quotes are escaped by a second quotes, e.g. “Hello “”World””, CANopen is great”. UTF-8 + * characters and also line breaks works with this function. Function removes all NULL and CR characters from output + * string. See also CO_fifo_readU82a */ size_t CO_fifo_readVs2a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); -/** Read data from fifo and output as mime-base64 encoded string. Encoding is as - * specified in RFC 2045, without CR-LF, but one long string. See also - * CO_fifo_readU82a */ +/** Read data from fifo and output as mime-base64 encoded string. Encoding is as specified in RFC 2045, without CR-LF, + * but one long string. See also CO_fifo_readU82a */ size_t CO_fifo_readB642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); -/** Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar */ - /** * @defgroup uint8_t Bitfields for status argument from CO_fifo_cpyTok2U8 function and similar * @{ @@ -463,7 +430,7 @@ size_t CO_fifo_readB642a(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); #define CO_fifo_st_errBuf 0x40U /**< Bit is set, if destination buffer is to small */ #define CO_fifo_st_errInt 0x80U /**< Bit is set, if internal error */ #define CO_fifo_st_errMask 0xF0U /**< Bitmask for error bits */ -/** @} */ /* uint8_t */ +/** @} */ /* uint8_t Bitfields */ /** * Read ascii string from src fifo and copy as uint8_t variable to dest fifo. @@ -493,17 +460,15 @@ size_t CO_fifo_cpyTok2I64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); size_t CO_fifo_cpyTok2R32(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); /** Copy ascii string to float64_t variable, see CO_fifo_cpyTok2U8 */ size_t CO_fifo_cpyTok2R64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); -/** Copy bytes written as two hex digits into to data. Bytes may be space - * separated. See CO_fifo_cpyTok2U8 for parameters. */ +/** Copy bytes written as two hex digits into to data. Bytes may be space separated. See CO_fifo_cpyTok2U8 for + * parameters. */ size_t CO_fifo_cpyTok2Hex(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); -/** Copy visible string to data. A visible string must be enclosed with double - * quotes, if it contains space. If a double quote is used within the string, - * the quotes are escaped by a second quotes. Input string can not contain - * newline characters. See CO_fifo_cpyTok2U8 */ +/** Copy visible string to data. A visible string must be enclosed with double quotes, if it contains space. If a double + * quote is used within the string, the quotes are escaped by a second quotes. Input string can not contain newline + * characters. See CO_fifo_cpyTok2U8 */ size_t CO_fifo_cpyTok2Vs(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); -/** Read ascii mime-base64 encoded string from src fifo and copy as binary data - * to dest fifo. Encoding is as specified in RFC 2045, without CR-LF, but one - * long string in single line. See also CO_fifo_readU82a */ +/** Read ascii mime-base64 encoded string from src fifo and copy as binary data to dest fifo. Encoding is as specified + * in RFC 2045, without CR-LF, but one long string in single line. See also CO_fifo_readU82a */ size_t CO_fifo_cpyTok2B64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES */ @@ -512,7 +477,7 @@ size_t CO_fifo_cpyTok2B64(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE */ diff --git a/301/crc16-ccitt.h b/301/crc16-ccitt.h index 8643d6d7..5712ad5b 100644 --- a/301/crc16-ccitt.h +++ b/301/crc16-ccitt.h @@ -41,7 +41,6 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * * Equation: * * `x^16 + x^12 + x^5 + 1` @@ -50,11 +49,10 @@ extern "C" { /** * Update crc16_ccitt variable with one data byte * - * This function updates crc variable for one data byte using crc16 ccitt - * algorithm. + * This function updates crc variable for one data byte using crc16 ccitt algorithm. * - * @param [in,out] crc Externally defined variable for CRC checksum. Before - * start of new CRC calculation, variable must be initialized (zero for xmodem). + * @param [in,out] crc Externally defined variable for CRC checksum. Before start of new CRC calculation, variable must + * be initialized (zero for xmodem). * @param chr One byte of data */ void crc16_ccitt_single(uint16_t* crc, const uint8_t chr); @@ -64,8 +62,8 @@ void crc16_ccitt_single(uint16_t* crc, const uint8_t chr); * * @param block Pointer to block of data. * @param blockLength Length of data in bytes; - * @param crc Initial value (zero for xmodem). If block is split into - * multiple segments, previous CRC is used as initial. + * @param crc Initial value (zero for xmodem). If block is split into multiple segments, previous CRC is used as + * initial. * * @return Calculated CRC. */ @@ -75,7 +73,7 @@ uint16_t crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc); #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE */ diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index 39331ba1..93bfe5cb 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -41,9 +41,8 @@ extern "C" { * * @ingroup CO_CANopen_303 * @{ - * - * CIA 303-3 standard specifies indicator LED diodes, which reflects state of - * the CANopen device. Green and red leds or bi-color led can be used. + * CIA 303-3 standard specifies indicator LED diodes, which reflects state of the CANopen device. Green and red leds or + * bi-color led can be used. * * CANopen green led - run led: * - flickering: LSS configuration state is active @@ -62,15 +61,13 @@ extern "C" { * - quadruple flash: PDO has not been received before the event timer elapsed * - on: CAN bus off * - * To apply on/off state to led diode, use #CO_LED_RED and #CO_LED_GREEN macros. - * For CANopen leds use CO_LED_BITFIELD_t CO_LED_CANopen. Other bitfields are - * available for implementing custom leds. + * To apply on/off state to led diode, use #CO_LED_RED and #CO_LED_GREEN macros. For CANopen leds use CO_LED_BITFIELD_t + * CO_LED_CANopen. Other bitfields are available for implementing custom leds. */ /** * @defgroup CO_LED_BITFIELD_t Bitfield for combining with red or green led * @{ - * */ #define CO_LED_flicker 0x01U /**< LED flickering 10Hz */ #define CO_LED_blink 0x02U /**< LED blinking 2,5Hz */ @@ -118,8 +115,7 @@ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t* LEDs); * Function must be called cyclically. * * @param LEDs This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param NMTstate NMT operating state. * @param LSSconfig Node is in LSS configuration state indication. * @param ErrCANbusOff CAN bus off indication (highest priority). @@ -139,7 +135,7 @@ void CO_LEDs_process(CO_LEDs_t* LEDs, uint32_t timeDifference_us, CO_NMT_interna #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE */ diff --git a/304/CO_GFC.h b/304/CO_GFC.h index 5f7ebeca..a7a58168 100644 --- a/304/CO_GFC.h +++ b/304/CO_GFC.h @@ -42,11 +42,9 @@ extern "C" { * * @ingroup CO_CANopen_304 * @{ - * Very simple consumer/producer protocol. - * A net can have multiple GFC producer and multiple GFC consumer. - * On a safety-relevant the producer can send a GFC message (ID 1, DLC 0). - * The consumer can use this message to start the transition to a safe state. - * The GFC is optional for the security protocol and is not monitored (timed). + * Very simple consumer/producer protocol. A net can have multiple GFC producer and multiple GFC consumer. On a + * safety-relevant the producer can send a GFC message (ID 1, DLC 0). The consumer can use this message to start the + * transition to a safe state. The GFC is optional for the security protocol and is not monitored (timed). */ /** @@ -60,10 +58,8 @@ typedef struct { CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ #endif #if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_CONSUMER) != 0) || defined CO_DOXYGEN - /** From CO_GFC_initCallbackEnterSafeState() or NULL */ - void (*pFunctSignalSafe)(void* object); - /** From CO_GFC_initCallbackEnterSafeState() or NULL */ - void* functSignalObjectSafe; + void (*pFunctSignalSafe)(void* object); /**< From CO_GFC_initCallbackEnterSafeState() or NULL */ + void* functSignalObjectSafe; /**< From CO_GFC_initCallbackEnterSafeState() or NULL */ #endif } CO_GFC_t; @@ -73,8 +69,8 @@ typedef struct { * Function must be called in the communication reset section. * * @param GFC This object will be initialized. - * @param OD_1300_gfcParameter Pointer to _Global fail-safe command parameter_ - * variable from Object dictionary (index 0x1300). + * @param OD_1300_gfcParameter Pointer to _Global fail-safe command parameter_ variable from Object dictionary (index + * 0x1300). * @param GFC_CANdevRx CAN device used for SRDO reception. * @param GFC_rxIdx Index of receive buffer in the above CAN device. * @param CANidRxGFC GFC CAN ID for reception @@ -92,12 +88,11 @@ CO_ReturnError_t CO_GFC_init(CO_GFC_t* GFC, OD_entry_t* OD_1300_gfcParameter, CO /** * Initialize GFC callback function. * - * Function initializes optional callback function, that is called when GFC is - * received. Callback is called from receive function (interrupt). + * Function initializes optional callback function, that is called when GFC is received. Callback is called from receive + * function (interrupt). * * @param GFC This object. - * @param object Pointer to object, which will be passed to pFunctSignalSafe(). - * Can be NULL + * @param object Pointer to object, which will be passed to pFunctSignalSafe(). Can be NULL * @param pFunctSignalSafe Pointer to the callback function. Not called if NULL. */ void CO_GFC_initCallbackEnterSafeState(CO_GFC_t* GFC, void* object, void (*pFunctSignalSafe)(void* object)); @@ -107,8 +102,7 @@ void CO_GFC_initCallbackEnterSafeState(CO_GFC_t* GFC, void* object, void (*pFunc /** * Send GFC message. * - * It should be called by application, for example after a safety-relevant - * change. + * It should be called by application, for example after a safety-relevant change. * * @param GFC GFC object. * @@ -121,7 +115,7 @@ CO_ReturnError_t CO_GFCsend(CO_GFC_t* GFC); #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE */ diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index a02f0866..d720e815 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -46,22 +46,22 @@ extern "C" { * * @ingroup CO_CANopen_304 * @{ - * Safety Related Data Object protocol is specified by standard EN 50325-5:2010 (formerly CiA304). - * Its functionality is very similar to that of the PDOs. The main differences is every message is send and received - * twice. The second message must be bitwise inverted. The delay between the two messages and between each message pair - * is monitored. The distinction between sending and receiving SRDO is made at runtime (for PDO it is compile time). If - * the security protocol is used, at least one SRDO is mandatory. + * Safety Related Data Object protocol is specified by standard EN 50325-5:2010 (formerly CiA304). Its functionality is + * very similar to that of the PDOs. The main differences is every message is send and received twice. The second + * message must be bitwise inverted. The delay between the two messages and between each message pair is monitored. The + * distinction between sending and receiving SRDO is made at runtime (for PDO it is compile time). If the security + * protocol is used, at least one SRDO is mandatory. * - * If there is erroneous structure of OD entries for SRDO parameters, then @CO_SRDO_init() function - * returns error and CANopen device doesn't work. It is necessary to repair Object Dictionary and reprogram the device. + * If there is erroneous structure of OD entries for SRDO parameters, then @CO_SRDO_init() function returns error and + * CANopen device doesn't work. It is necessary to repair Object Dictionary and reprogram the device. * - * If there are erroneous values inside SRDO parameters, then Emergency message CO_EM_SRDO_CONFIGURATION is sent. - * Info code (32bit) contains OD index, subindex and additional byte, which helps to determine erroneous OD object. + * If there are erroneous values inside SRDO parameters, then Emergency message CO_EM_SRDO_CONFIGURATION is sent. Info + * code (32bit) contains OD index, subindex and additional byte, which helps to determine erroneous OD object. * * SRDO configuration consists of one @CO_SRDO_init_start(), @CO_SRDO_init() for each SRDO and one @CO_SRDO_init_end(). - * These may be called in CANopen initialization section after all other CANopen objects are initialized. - * If SRDO OD parameters are edited (in NMT pre-operational state), NMT communication reset is necessary. - * Alternatively SRDO configuration may be executed just after transition to NMT operational state. + * These may be called in CANopen initialization section after all other CANopen objects are initialized. If SRDO OD + * parameters are edited (in NMT pre-operational state), NMT communication reset is necessary. Alternatively SRDO + * configuration may be executed just after transition to NMT operational state. * * @CO_SRDO_process() must be executed cyclically, similar as PDO processing. Function is fast, no time consuming tasks. * Function returns @CO_SRDO_state_t value, which may be used to determine working-state or safe-state of safety related @@ -77,8 +77,8 @@ extern "C" { #define CO_SRDO_MAX_SIZE 8U #endif -/** Maximum number of entries, which can be mapped to SRDO, 2*8 for standard - * CAN, may be less to preserve RAM usage. Must be multiple of 2. */ +/** Maximum number of entries, which can be mapped to SRDO, 2*8 for standard CAN, may be less to preserve RAM usage. + * Must be multiple of 2. */ #ifndef CO_SRDO_MAX_MAPPED_ENTRIES #define CO_SRDO_MAX_MAPPED_ENTRIES 16U #endif @@ -102,8 +102,8 @@ typedef enum { CO_SRDO_state_error_rxShort = -1, /**< Received SRDO message is too short */ CO_SRDO_state_unknown = 0, /**< unknown state, set by @CO_SRDO_init */ CO_SRDO_state_nmtNotOperational = 1, /**< Internal NMT operating state is not NMT operational */ - CO_SRDO_state_initializing = - 2, /**< Just entered NMT operational state, SRDO message not yet received or transmitted */ + CO_SRDO_state_initializing = 2, /**< Just entered NMT operational state, SRDO message not yet received or + transmitted */ CO_SRDO_state_communicationEstablished = 3, /**< SRDO communication established, fully functional */ CO_SRDO_state_deleted = 10 /**< informationDirection for this SRDO is set to 0 */ } CO_SRDO_state_t; @@ -117,87 +117,59 @@ typedef enum { * - change in operation state */ typedef struct { - /** True if NMT operating state is operational */ - bool_t NMTisOperational; - /** True if all SRDO objects are properly configured. Set after successful - * finish of all @CO_SRDO_init() functions. Cleared on configuration change. */ - bool_t configurationValid; - /** Object for input / output on the OD variable 13FE:00. Configuration - * of any of the the SRDO parameters will write 0 to that variable. */ - OD_IO_t OD_IO_configurationValid; - - OD_entry_t* OD_13FE_entry; - OD_entry_t* OD_13FF_entry; - - /** Extension for OD object */ - OD_extension_t OD_13FE_extension; - /** Extension for OD object */ - OD_extension_t OD_13FF_extension; + bool_t NMTisOperational; /**< True if NMT operating state is operational */ + bool_t configurationValid; /**< True if all SRDO objects are properly configured. Set after successful finish of all + @CO_SRDO_init() functions. Cleared on configuration change. */ + OD_IO_t OD_IO_configurationValid; /**< Object for input / output on the OD variable 13FE:00. Configuration of any of + the the SRDO parameters will write 0 to that variable. */ + OD_entry_t* OD_13FE_entry; /**< From CO_SRDOGuard_init() */ + OD_entry_t* OD_13FF_entry; /**< From CO_SRDOGuard_init() */ + OD_extension_t OD_13FE_extension; /**< Extension for OD object */ + OD_extension_t OD_13FF_extension; /**< Extension for OD object */ } CO_SRDOGuard_t; /** * SRDO object. */ typedef struct { - CO_SRDOGuard_t* SRDOGuard; /**< From CO_SRDO_init() */ - OD_t* OD; /**< From CO_SRDO_init() */ - CO_EM_t* em; /**< From CO_SRDO_init() */ - uint16_t defaultCOB_ID; /**< From CO_SRDO_init() */ - uint8_t nodeId; /**< From CO_SRDO_init() */ - CO_CANmodule_t* CANdevTx[2]; /**< From CO_SRDO_init() */ - uint16_t CANdevTxIdx[2]; /**< From CO_SRDO_init() */ - CO_CANmodule_t* CANdevRx[2]; /**< From CO_SRDO_init() */ - uint16_t CANdevRxIdx[2]; /**< From CO_SRDO_init() */ - /** Internal state of this SRDO. */ - CO_SRDO_state_t internalState; - /** Copy of variable, internal usage. */ - bool_t NMTisOperationalPrevious; - /** 0 - SRDO is disabled; 1 - SRDO is producer (tx); 2 - SRDO is consumer (rx) */ - uint8_t informationDirection; - /** Safety Cycle Time from object dictionary translated to microseconds */ - uint32_t cycleTime_us; - /** Safety related validation time from object dictionary translated to microseconds */ - uint32_t validationTime_us; - /** cycle timer variable in microseconds */ - uint32_t cycleTimer; - /** inverted delay timer variable in microseconds */ - uint32_t invertedDelay; - /** validation timer variable in microseconds */ - uint32_t validationTimer; - /** Data length of the received SRDO message. Calculated from mapping */ - CO_SRDO_size_t dataLength; - /** Number of mapped objects in SRDO */ - uint8_t mappedObjectsCount; - /** Object dictionary interface for all mapped entries. OD_IO.dataOffset has - * special usage with SRDO. It stores information about mappedLength of - * the variable. mappedLength can be less or equal to the OD_IO.dataLength. - * mappedLength greater than OD_IO.dataLength indicates erroneous mapping. - * OD_IO.dataOffset is set to 0 before read/write function call and after - * the call OD_IO.dataOffset is set back to mappedLength. */ - OD_IO_t OD_IO[CO_SRDO_MAX_MAPPED_ENTRIES]; - /** CAN transmit buffers inside CANdevTx */ - CO_CANtx_t* CANtxBuff[2]; - /** Variable indicates, if new SRDO message received from CAN bus. */ - volatile void* CANrxNew[2]; - /** true, if received SRDO is too short */ - bool_t rxSrdoShort; - /** two buffers of data bytes for the received message. */ - uint8_t CANrxData[2][CO_SRDO_MAX_SIZE]; - /** If true, next processed SRDO message is normal (not inverted) */ - bool_t nextIsNormal; - - OD_entry_t* OD_communicationParam_entry; /**< From CO_SRDO_init() */ - OD_entry_t* OD_mappingParam_entry; /**< From CO_SRDO_init() */ - - /** Extension for OD object */ - OD_extension_t OD_communicationParam_ext; - /** Extension for OD object */ - OD_extension_t OD_mappingParam_extension; + CO_SRDOGuard_t* SRDOGuard; /**< From CO_SRDO_init() */ + OD_t* OD; /**< From CO_SRDO_init() */ + CO_EM_t* em; /**< From CO_SRDO_init() */ + uint16_t defaultCOB_ID; /**< From CO_SRDO_init() */ + uint8_t nodeId; /**< From CO_SRDO_init() */ + CO_CANmodule_t* CANdevTx[2]; /**< From CO_SRDO_init() */ + uint16_t CANdevTxIdx[2]; /**< From CO_SRDO_init() */ + CO_CANmodule_t* CANdevRx[2]; /**< From CO_SRDO_init() */ + uint16_t CANdevRxIdx[2]; /**< From CO_SRDO_init() */ + CO_SRDO_state_t internalState; /**< Internal state of this SRDO. */ + bool_t NMTisOperationalPrevious; /**< Copy of variable, internal usage. */ + uint8_t informationDirection; /**< 0 - SRDO is disabled; 1 - SRDO is producer (tx); 2 - SRDO is consumer (rx) */ + uint32_t cycleTime_us; /**< Safety Cycle Time from object dictionary translated to microseconds */ + uint32_t validationTime_us; /**< Safety related validation time from object dictionary translated to microseconds */ + uint32_t cycleTimer; /**< cycle timer variable in microseconds */ + uint32_t invertedDelay; /**< inverted delay timer variable in microseconds */ + uint32_t validationTimer; /**< validation timer variable in microseconds */ + CO_SRDO_size_t dataLength; /**< Data length of the received SRDO message. Calculated from mapping */ + uint8_t mappedObjectsCount; /**< Number of mapped objects in SRDO */ + OD_IO_t OD_IO[CO_SRDO_MAX_MAPPED_ENTRIES]; /**< Object dictionary interface for all mapped entries. OD_IO.dataOffset + has special usage with SRDO. It stores information about mappedLength + of the variable. mappedLength can be less or equal to the + OD_IO.dataLength. mappedLength greater than OD_IO.dataLength indicates + erroneous mapping. OD_IO.dataOffset is set to 0 before read/write + function call and after the call OD_IO.dataOffset is set back to + mappedLength. */ + CO_CANtx_t* CANtxBuff[2]; /**< CAN transmit buffers inside CANdevTx */ + volatile void* CANrxNew[2]; /**< Variable indicates, if new SRDO message received from CAN bus. */ + bool_t rxSrdoShort; /**< true, if received SRDO is too short */ + uint8_t CANrxData[2][CO_SRDO_MAX_SIZE]; /**< two buffers of data bytes for the received message. */ + bool_t nextIsNormal; /**< If true, next processed SRDO message is normal (not inverted) */ + OD_entry_t* OD_communicationParam_entry; /**< From CO_SRDO_init() */ + OD_entry_t* OD_mappingParam_entry; /**< From CO_SRDO_init() */ + OD_extension_t OD_communicationParam_ext; /**< Extension for OD object */ + OD_extension_t OD_mappingParam_extension; /**< Extension for OD object */ #if (((CO_CONFIG_SRDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN - /** From CO_SRDO_initCallbackPre() or NULL */ - void (*pFunctSignalPre)(void* object); - /** From CO_SRDO_initCallbackPre() or NULL */ - void* functSignalObjectPre; + void (*pFunctSignalPre)(void* object); /**< From CO_SRDO_initCallbackPre() or NULL */ + void* functSignalObjectPre; /**< From CO_SRDO_initCallbackPre() or NULL */ #endif } CO_SRDO_t; @@ -207,10 +179,9 @@ typedef struct { * Function must be called in the communication reset section before @CO_SRDO_init functions. * * @param SRDOGuard This object will be initialized. - * @param OD_13FE_configurationValid Pointer to _Configuration valid_ variable from Object - * dictionary (index 0x13FE). - * @param OD_13FF_safetyConfigurationSignature Pointer to _Safety configuration signature_ variable - * from Object dictionary (index 0x13FF). + * @param OD_13FE_configurationValid Pointer to _Configuration valid_ variable from Object dictionary (index 0x13FE). + * @param OD_13FF_safetyConfigurationSignature Pointer to _Safety configuration signature_ variable from Object + * dictionary (index 0x13FF). * @param [out] errInfo Additional information in case of error, may be NULL. * * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. @@ -230,14 +201,11 @@ CO_ReturnError_t CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13F * @param em Emergency object. * @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added. * @param defaultCOB_ID Default COB ID for this SRDO for plain data (without NodeId). - * @param OD_130x_SRDOCommPar Pointer to _SRDO communication parameter_ record from Object - * dictionary (index 0x1301+). - * @param OD_138x_SRDOMapPar Pointer to _SRDO mapping parameter_ record from Object - * dictionary (index 0x1381+). - * @param OD_13FE_configurationValid Pointer to _Configuration valid_ variable from Object - * dictionary (index 0x13FE). - * @param OD_13FF_safetyConfigurationSignature Pointer to _Safety configuration signature_ variable - * from Object dictionary (index 0x13FF). + * @param OD_130x_SRDOCommPar Pointer to _SRDO communication parameter_ record from Object dictionary (index 0x1301+). + * @param OD_138x_SRDOMapPar Pointer to _SRDO mapping parameter_ record from Object dictionary (index 0x1381+). + * @param OD_13FE_configurationValid Pointer to _Configuration valid_ variable from Object dictionary (index 0x13FE). + * @param OD_13FF_safetyConfigurationSignature Pointer to _Safety configuration signature_ variable from Object + * dictionary (index 0x13FF). * @param CANdevRx CAN device used for SRDO reception. * @param CANdevRxIdxNormal Index of receive buffer in the above CAN device. * @param CANdevRxIdxInverted Index of receive buffer in the above CAN device. @@ -260,9 +228,8 @@ CO_ReturnError_t CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_ /** * Initialize SRDO callback function. * - * Function initializes optional callback function, which should immediately - * start processing of CO_SRDO_process() function. - * Callback is called after SRDO message is received from the CAN bus. + * Function initializes optional callback function, which should immediately start processing of CO_SRDO_process() + * function. Callback is called after SRDO message is received from the CAN bus. * * @param SRDO This object. * @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL @@ -274,9 +241,8 @@ void CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalP /** * Send SRDO on event * - * Sends SRDO before the next refresh timer tiggers. The message itself is send - * in @CO_SRDO_process(). Note that RTOS have to trigger its processing quickly. - * After the transmission the timer is reset to the full refresh time. + * Sends SRDO before the next refresh timer tiggers. The message itself is send in @CO_SRDO_process(). Note that RTOS + * have to trigger its processing quickly. After the transmission the timer is reset to the full refresh time. * * @param SRDO This object. * @return CO_ReturnError_t CO_ERROR_NO if request is granted @@ -302,7 +268,7 @@ CO_SRDO_state_t CO_SRDO_process(CO_SRDO_t* SRDO, uint32_t timeDifference_us, uin #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE */ diff --git a/305/CO_LSS.h b/305/CO_LSS.h index 4f630520..aec0b634 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -43,10 +43,9 @@ extern "C" { * @{ * LSS protocol is according to CiA DSP 305 V3.0.0. * - * LSS services and protocols are used to inquire or to change the settings - * of three parameters of the physical layer, data link layer, and application - * layer on a CANopen device with LSS slave capability by a CANopen device - * with LSS master capability via the CAN network. + * LSS services and protocols are used to inquire or to change the settings of three parameters of the physical layer, + * data link layer, and application layer on a CANopen device with LSS slave capability by a CANopen device with LSS + * master capability via the CAN network. * * The following parameters may be inquired or changed: * - Node-ID of the CANopen device @@ -54,16 +53,13 @@ extern "C" { * - LSS address compliant to the identity object (1018h) * * The connection is established in one of two ways: - * - addressing a node by it's 128 bit LSS address. This requires that the - * master already knows the node's LSS address. - * - scanning the network for unknown nodes (Fastscan). Using this method, - * unknown devices can be found and configured one by one. + * - addressing a node by it's 128 bit LSS address. This requires that the master already knows the node's LSS address. + * - scanning the network for unknown nodes (Fastscan). Using this method, unknown devices can be found and configured + * one by one. * - * Be aware that changing the bit rate is a critical step for the network. A - * failure will render the network unusable! + * Be aware that changing the bit rate is a critical step for the network. A failure will render the network unusable! * - * Using this implementation, only master or slave can be included in one - * node at a time. + * Using this implementation, only master or slave can be included in one node at a time. * * For CAN identifiers see #CO_Default_CAN_ID_t */ @@ -72,9 +68,8 @@ extern "C" { * @defgroup CO_LSS_cs_t LSS protocol command specifiers * @{ * - * The LSS protocols are executed between the LSS master device and the LSS - * slave device(s) to implement the LSS services. Some LSS protocols require - * a sequence of CAN messages. + * The LSS protocols are executed between the LSS master device and the LSS slave device(s) to implement the LSS + * services. Some LSS protocols require a sequence of CAN messages. * * As identifying method only "LSS fastscan" is supported. */ @@ -147,8 +142,7 @@ extern "C" { /** @} */ /* CO_LSS_fastscan_lss_sub_next */ /** - * The LSS address is a 128 bit number, uniquely identifying each node. It - * consists of the values in object 0x1018. + * The LSS address is a 128 bit number, uniquely identifying each node. It consists of the values in object 0x1018. */ typedef union { uint32_t addr[4]; @@ -171,8 +165,8 @@ typedef union { * - LSS configuration: In this state variables may be configured in the LSS slave. * - Final: Pseudo state, indicating the deactivation of the FSA. */ -#define CO_LSS_STATE_WAITING 0x00U /**< LSS FSA waiting for requests*/ -#define CO_LSS_STATE_CONFIGURATION 0x01U /**< LSS FSA waiting for configuration*/ +#define CO_LSS_STATE_WAITING 0x00U /**< LSS FSA waiting for requests */ +#define CO_LSS_STATE_CONFIGURATION 0x01U /**< LSS FSA waiting for configuration */ /** @} */ /* CO_LSS_state_t */ /** @@ -184,7 +178,7 @@ typedef union { #define CO_LSS_BIT_TIMING_500 2U /**< 500kbit/s */ #define CO_LSS_BIT_TIMING_250 3U /**< 250kbit/s */ #define CO_LSS_BIT_TIMING_125 4U /**< 125kbit/s */ - /* reserved 5U */ + /* 5U - reserved */ #define CO_LSS_BIT_TIMING_50 6U /**< 50kbit/s */ #define CO_LSS_BIT_TIMING_20 7U /**< 20kbit/s */ #define CO_LSS_BIT_TIMING_10 8U /**< 10kbit/s */ @@ -192,8 +186,7 @@ typedef union { /** @} */ /* CO_LSS_bitTimingTable_t */ /** - * Lookup table for conversion between bit timing table and numerical - * bit rate + * Lookup table for conversion between bit timing table and numerical bit rate */ static const uint16_t CO_LSS_bitTimingTableLookup[] = {1000, 800, 500, 250, 125, 0, 50, 20, 10, 0}; @@ -210,17 +203,17 @@ static const uint16_t CO_LSS_bitTimingTableLookup[] = {1000, 800, 500, 250, 125, /** * Macro to check if two LSS addresses are equal */ -#define CO_LSS_ADDRESS_EQUAL(/*CO_LSS_address_t*/ a1, /*CO_LSS_address_t*/ a2) \ +#define CO_LSS_ADDRESS_EQUAL(/* CO_LSS_address_t */ a1, /* CO_LSS_address_t */ a2) \ ((a1.identity.productCode == a2.identity.productCode) \ && (a1.identity.revisionNumber == a2.identity.revisionNumber) \ && (a1.identity.serialNumber == a2.identity.serialNumber) && (a1.identity.vendorID == a2.identity.vendorID)) -/** @} */ /*@defgroup CO_LSS*/ +/** @} */ /* @defgroup CO_LSS */ #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_LSS) & (CO_CONFIG_LSS_SLAVE | CO_CONFIG_LSS_MASTER) */ -#endif /*CO_LSS_H*/ +#endif /* CO_LSS_H */ diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index ef3456c6..47405229 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -46,13 +46,11 @@ extern "C" { * - Activate bit timing parameters * - Store configuration * - * The LSS master is initalized during the CANopenNode initialization process. - * Except for enabling the LSS master in the configurator, no further - * run-time configuration is needed for basic operation. - * The LSS master does basic checking of commands and command sequence. + * The LSS master is initalized during the CANopenNode initialization process. Except for enabling the LSS master in the + * configurator, no further run-time configuration is needed for basic operation. The LSS master does basic checking of + * commands and command sequence. * * ###Usage - * * Usage of the CANopen LSS master is demonstrated in file 309/CO_gateway_ascii.c * * It essentially is always as following: @@ -63,19 +61,16 @@ extern "C" { * * All commands need to be run cyclically, e.g. like this * \code{.c} +interval = 0; +do { + ret = CO_LSSmaster_InquireNodeId(LSSmaster, interval, &outval); - interval = 0; - do { - ret = CO_LSSmaster_InquireNodeId(LSSmaster, interval, &outval); - - interval = 1; ms - sleep(interval); - } while (ret == CO_LSSmaster_WAIT_SLAVE); - + interval = 1; + ms sleep(interval); +} while (ret == CO_LSSmaster_WAIT_SLAVE); * \endcode * - * A more advanced implementation can make use of the callback function to - * shorten waiting times. + * A more advanced implementation can make use of the callback function to shorten waiting times. */ /** @@ -98,17 +93,14 @@ typedef enum { * LSS master object. */ typedef struct { - uint32_t timeout_us; /**< LSS response timeout in us */ - - uint8_t state; /**< Node is currently selected */ - uint8_t command; /**< Active command */ - uint32_t timeoutTimer; /**< Timeout timer for LSS communication */ - - uint8_t fsState; /**< Current state of fastscan master state machine */ - uint8_t fsLssSub; /**< Current state of node state machine */ - uint8_t fsBitChecked; /**< Current scan bit position */ - uint32_t fsIdNumber; /**< Current scan result */ - + uint32_t timeout_us; /**< LSS response timeout in us */ + uint8_t state; /**< Node is currently selected */ + uint8_t command; /**< Active command */ + uint32_t timeoutTimer; /**< Timeout timer for LSS communication */ + uint8_t fsState; /**< Current state of fastscan master state machine */ + uint8_t fsLssSub; /**< Current state of node state machine */ + uint8_t fsBitChecked; /**< Current scan bit position */ + uint32_t fsIdNumber; /**< Current scan result */ volatile void* CANrxNew; /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */ uint8_t CANrxData[8]; /**< 8 data bytes of the received message */ @@ -121,8 +113,8 @@ typedef struct { } CO_LSSmaster_t; /** - * Default timeout for LSS slave in ms. This is the same as for SDO. For more - * info about LSS timeout see #CO_LSSmaster_changeTimeout() + * Default timeout for LSS slave in ms. This is the same as for SDO. For more info about LSS timeout see + * #CO_LSSmaster_changeTimeout() */ #ifndef CO_LSSmaster_DEFAULT_TIMEOUT #define CO_LSSmaster_DEFAULT_TIMEOUT 1000U /* ms */ @@ -134,8 +126,7 @@ typedef struct { * Function must be called in the communication reset section. * * @param LSSmaster This object will be initialized. - * @param timeout_ms slave response timeout in ms, for more detail see - * #CO_LSSmaster_changeTimeout() + * @param timeout_ms slave response timeout in ms, for more detail see #CO_LSSmaster_changeTimeout() * @param CANdevRx CAN device for LSS master reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANidLssSlave COB ID for reception. @@ -151,18 +142,15 @@ CO_ReturnError_t CO_LSSmaster_init(CO_LSSmaster_t* LSSmaster, uint16_t timeout_m /** * Change LSS master timeout * - * On LSS, a "negative ack" is signaled by the slave not answering. Because of - * that, a low timeout value can significantly increase protocol speed in some - * cases (e.g. fastscan). However, as soon as there is activity on the bus, - * LSS messages can be delayed because of their low CAN network priority (see - * #CO_Default_CAN_ID_t). + * On LSS, a "negative ack" is signaled by the slave not answering. Because of that, a low timeout value can + * significantly increase protocol speed in some cases (e.g. fastscan). However, as soon as there is activity on the + * bus, LSS messages can be delayed because of their low CAN network priority (see #CO_Default_CAN_ID_t). * - * @remark Be aware that a "late response" will seriously mess up LSS, so this - * value must be selected "as high as necessary and as low as possible". CiA does - * neither specify nor recommend a value. + * @remark Be aware that a "late response" will seriously mess up LSS, so this value must be selected "as high as + * necessary and as low as possible". CiA does neither specify nor recommend a value. * - * @remark This timeout is per-transfer. If a command internally needs multiple - * transfers to complete, this timeout is applied on each transfer. + * @remark This timeout is per-transfer. If a command internally needs multiple transfers to complete, this timeout is + * applied on each transfer. * * @param LSSmaster This object. * @param timeout_ms timeout value in ms @@ -173,10 +161,8 @@ void CO_LSSmaster_changeTimeout(CO_LSSmaster_t* LSSmaster, uint16_t timeout_ms); /** * Initialize LSSmasterRx callback function. * - * Function initializes optional callback function, which should immediately - * start further LSS processing. Callback is called after LSS message is - * received from the CAN bus. It should signal the RTOS to resume corresponding - * task. + * Function initializes optional callback function, which should immediately start further LSS processing. Callback is + * called after LSS message is received from the CAN bus. It should signal the RTOS to resume corresponding task. * * @param LSSmaster This object. * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL @@ -190,17 +176,15 @@ void CO_LSSmaster_initCallbackPre(CO_LSSmaster_t* LSSmaster, void* object, void * * This function can select one specific or all nodes. * - * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE - * Function is non-blocking. + * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE Function is non-blocking. * * @remark Only one selection can be active at any time. * * @param LSSmaster This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in [microseconds]. Zero when request is started. * @param lssAddress LSS target address. If NULL, all nodes are selected - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, + * #CO_LSSmaster_TIMEOUT */ CO_LSSmaster_return_t CO_LSSmaster_swStateSelect(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSS_address_t* lssAddress); @@ -208,14 +192,12 @@ CO_LSSmaster_return_t CO_LSSmaster_swStateSelect(CO_LSSmaster_t* LSSmaster, uint /** * Request LSS switch state deselect * - * This function deselects all nodes, so it doesn't matter if a specific - * node is selected. + * This function deselects all nodes, so it doesn't matter if a specific node is selected. * * This function also resets the LSS master state machine to a clean state * * @param LSSmaster This object. - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_OK + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_OK */ CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect(CO_LSSmaster_t* LSSmaster); @@ -226,16 +208,13 @@ CO_LSSmaster_return_t CO_LSSmaster_swStateDeselect(CO_LSSmaster_t* LSSmaster); * * This function needs one specific node to be selected. * - * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. - * Function is non-blocking. + * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in [microseconds]. Zero when request is started. * @param bit new bit rate - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT, - * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, + * #CO_LSSmaster_TIMEOUT, #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT */ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint16_t bit); @@ -247,17 +226,13 @@ CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming(CO_LSSmaster_t* LSSmaster, * * This function needs one specific node to be selected. * - * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. - * Function is non-blocking. + * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. Zero when request is started. - * @param nodeId new node ID. Special value #CO_LSS_NODE_ID_ASSIGNMENT can be - * used to invalidate node ID. - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT, - * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT + * @param timeDifference_us Time difference from previous function call in [microseconds]. Zero when request is started. + * @param nodeId new node ID. Special value #CO_LSS_NODE_ID_ASSIGNMENT can be used to invalidate node ID. + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, + * #CO_LSSmaster_TIMEOUT, #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT */ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint8_t nodeId); @@ -265,20 +240,16 @@ CO_LSSmaster_return_t CO_LSSmaster_configureNodeId(CO_LSSmaster_t* LSSmaster, ui /** * Request LSS store configuration * - * The current "pending" values for bit rate and node ID in LSS slave are - * stored as "permanent" values. + * The current "pending" values for bit rate and node ID in LSS slave are stored as "permanent" values. * * This function needs one specific node to be selected. * - * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. - * Function is non-blocking. + * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. Zero when request is started. - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT, - * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT + * @param timeDifference_us Time difference from previous function call in [microseconds]. Zero when request is started. + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, + * #CO_LSSmaster_TIMEOUT, #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT */ CO_LSSmaster_return_t CO_LSSmaster_configureStore(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us); @@ -287,39 +258,33 @@ CO_LSSmaster_return_t CO_LSSmaster_configureStore(CO_LSSmaster_t* LSSmaster, uin * * The current "pending" bit rate in LSS slave is applied. * - * Be aware that changing the bit rate is a critical step for the network. A - * failure will render the network unusable! Therefore, this function only - * should be called if the following conditions are met: + * Be aware that changing the bit rate is a critical step for the network. A failure will render the network unusable! + * Therefore, this function only should be called if the following conditions are met: * - all nodes support changing bit timing * - new bit timing is successfully set as "pending" in all nodes - * - all nodes have to activate the new bit timing roughly at the same time. - * Therefore this function needs all nodes to be selected. + * - all nodes have to activate the new bit timing roughly at the same time. Therefore this function needs all nodes + * to be selected. * * @param LSSmaster This object. - * @param switchDelay_ms delay that is applied by the slave once before and - * once after switching in ms. - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_OK + * @param switchDelay_ms delay that is applied by the slave once before and once after switching in ms. + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_OK */ CO_LSSmaster_return_t CO_LSSmaster_ActivateBit(CO_LSSmaster_t* LSSmaster, uint16_t switchDelay_ms); /** * Request LSS inquire LSS address * - * The LSS address value is read from the node. This is useful when the node - * was selected by fastscan. + * The LSS address value is read from the node. This is useful when the node was selected by fastscan. * * This function needs one specific node to be selected. * - * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. - * Function is non-blocking. + * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in [microseconds]. Zero when request is started. * @param [out] lssAddress read result when function returns successfully - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, + * #CO_LSSmaster_TIMEOUT */ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSS_address_t* lssAddress); @@ -327,21 +292,18 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(CO_LSSmaster_t* LSSmaster, /** * Request LSS inquire node ID or part of LSS address * - * The node-ID, identity vendor-ID, product-code, revision-number or - * serial-number value is read from the node. + * The node-ID, identity vendor-ID, product-code, revision-number or serial-number value is read from the node. * * This function needs one specific node to be selected. * - * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. - * Function is non-blocking. + * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in [microseconds]. Zero when request is started. * @param lssInquireCs One of CO_LSS_INQUIRE_xx commands from #CO_LSS_cs_t. * @param [out] value read result when function returns successfully - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, + * #CO_LSSmaster_TIMEOUT */ CO_LSSmaster_return_t CO_LSSmaster_Inquire(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint8_t lssInquireCs, uint32_t* value); @@ -367,14 +329,13 @@ typedef struct { /** * Select a node by LSS identify fastscan * - * This initiates searching for a unconfigured node by the means of LSS fastscan - * mechanism. When this function is finished + * This initiates searching for a unconfigured node by the means of LSS fastscan mechanism. When this function is + * finished * - a (more or less) arbitrary node is selected and ready for node ID assingment * - no node is selected because the given criteria do not match a node * - no node is selected because all nodes are already configured * - * There are multiple ways to scan for a node. Depending on those, the scan - * will take different amounts of time: + * There are multiple ways to scan for a node. Depending on those, the scan will take different amounts of time: * - full scan * - partial scan * - verification @@ -395,38 +356,34 @@ fastscan.scan[CO_LSS_FASTSCAN_REV] = CO_LSSmaster_FS_SKIP; fastscan.scan[CO_LSS_FASTSCAN_SERIAL] = CO_LSSmaster_FS_SCAN; * \endcode * - * This example will take 2 scan cyles for verifying vendor ID and product code - * and 33 scan cycles to find the serial number. + * This example will take 2 scan cyles for verifying vendor ID and product code and 33 scan cycles to find the serial + * number. * * For scanning, the following limitations apply: * - No more than two values can be skipped * - Vendor ID cannot be skipped * - * @remark When doing partial scans, it is in the responsibility of the user - * that the LSS address is unique. + * @remark When doing partial scans, it is in the responsibility of the user that the LSS address is unique. * * This function needs that no node is selected when starting the scan process. * - * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. - * Function is non-blocking. + * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE. Function is non-blocking. * * @param LSSmaster This object. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. Zero when request is started. + * @param timeDifference_us Time difference from previous function call in [microseconds]. Zero when request is started. * @param fastscan struct according to #CO_LSSmaster_fastscan_t. - * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, - * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_SCAN_FINISHED, #CO_LSSmaster_SCAN_NOACK, - * #CO_LSSmaster_SCAN_FAILED + * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_WAIT_SLAVE, + * #CO_LSSmaster_SCAN_FINISHED, #CO_LSSmaster_SCAN_NOACK, #CO_LSSmaster_SCAN_FAILED */ CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, CO_LSSmaster_fastscan_t* fastscan); -/** @} */ /*@defgroup CO_LSSmaster*/ +/** @} */ /* @defgroup CO_LSSmaster */ #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_MASTER */ -#endif /*CO_LSSmaster_H*/ +#endif /* CO_LSSmaster_H */ diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index 26afea49..850d4a17 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -47,52 +47,41 @@ extern "C" { * - Activate bit timing parameters * - Store configuration (bit rate and node ID) * - * After CAN module start, the LSS slave and NMT slave are started and then - * coexist alongside each other. To achieve this behaviour, the CANopen node - * startup process has to be controlled more detailed. Therefore, CO_LSSinit() - * must be invoked between CO_CANinit() and CO_CANopenInit() in the - * communication reset section. - * - * Moreover, the LSS slave needs to pause the NMT slave initialization in case - * no valid node ID is available at start up. In that case CO_CANopenInit() - * skips initialization of other CANopen modules and CO_process() skips - * processing of other modules than LSS slave automatically. - * - * Variables for CAN-bitrate and CANopen node-id must be initialized by - * application from non-volatile memory or dip switches. Pointers to them are - * passed to CO_LSSinit() function. Those variables represents pending values. - * If node-id is valid in the moment it enters CO_LSSinit(), it also becomes - * active node-id and the stack initialises normally. Otherwise, node-id must be - * configured by lss and after successful configuration stack passes reset - * communication autonomously. - * - * Device with all threads can be normally initialized and running despite that - * node-id is not valid. Application must take care, because CANopen is not - * initialized. In that case CO_CANopenInit() returns error condition - * CO_ERROR_NODE_ID_UNCONFIGURED_LSS which must be handled properly. Status can - * also be checked with CO->nodeIdUnconfigured variable. - * - * Some callback functions may be initialized by application with - * CO_LSSslave_initCkBitRateCall(), - * CO_LSSslave_initActBitRateCall() and - * CO_LSSslave_initCfgStoreCall(). + * After CAN module start, the LSS slave and NMT slave are started and then coexist alongside each other. To achieve + * this behaviour, the CANopen node startup process has to be controlled more detailed. Therefore, CO_LSSinit() must be + * invoked between CO_CANinit() and CO_CANopenInit() in the communication reset section. + * + * Moreover, the LSS slave needs to pause the NMT slave initialization in case no valid node ID is available at start + * up. In that case CO_CANopenInit() skips initialization of other CANopen modules and CO_process() skips processing of + * other modules than LSS slave automatically. + * + * Variables for CAN-bitrate and CANopen node-id must be initialized by application from non-volatile memory or dip + * switches. Pointers to them are passed to CO_LSSinit() function. Those variables represents pending values. If node-id + * is valid in the moment it enters CO_LSSinit(), it also becomes active node-id and the stack initialises normally. + * Otherwise, node-id must be configured by lss and after successful configuration stack passes reset communication + * autonomously. + * + * Device with all threads can be normally initialized and running despite that node-id is not valid. Application must + * take care, because CANopen is not initialized. In that case CO_CANopenInit() returns error condition + * CO_ERROR_NODE_ID_UNCONFIGURED_LSS which must be handled properly. Status can also be checked with + * CO->nodeIdUnconfigured variable. + * + * Some callback functions may be initialized by application with CO_LSSslave_initCkBitRateCall(), + * CO_LSSslave_initActBitRateCall() and CO_LSSslave_initCfgStoreCall(). */ /** * LSS slave object. */ typedef struct { - CO_LSS_address_t lssAddress; /**< From #CO_LSSslave_init */ - uint8_t lssState; /**< #CO_LSS_state_t */ - CO_LSS_address_t lssSelect; /**< Received LSS Address by select */ - + CO_LSS_address_t lssAddress; /**< From #CO_LSSslave_init */ + uint8_t lssState; /**< #CO_LSS_state_t */ + CO_LSS_address_t lssSelect; /**< Received LSS Address by select */ CO_LSS_address_t lssFastscan; /**< Received LSS Address by fastscan */ uint8_t fastscanPos; /**< Current state of fastscan */ - - uint16_t* pendingBitRate; /**< Bit rate value that is temporarily configured */ - uint8_t* pendingNodeID; /**< Node ID that is temporarily configured */ - uint8_t activeNodeID; /**< Node ID used at the CAN interface */ - + uint16_t* pendingBitRate; /**< Bit rate value that is temporarily configured */ + uint8_t* pendingNodeID; /**< Node ID that is temporarily configured */ + uint8_t activeNodeID; /**< Node ID used at the CAN interface */ volatile void* sendResponse; /**< Variable indicates, if LSS response has to be sent by mainline processing function */ uint8_t service; /**< Service, which will have to be processed by mainline processing function */ @@ -111,9 +100,8 @@ typedef struct { bool_t (*pFunctLSScfgStore)(void* object, uint8_t id, uint16_t bitRate); /**< From CO_LSSslave_initCfgStoreCall() or NULL */ void* functLSScfgStoreObject; /** Pointer to object */ - - CO_CANmodule_t* CANdevTx; /**< From #CO_LSSslave_init() */ - CO_CANtx_t* TXbuff; /**< CAN transmit buffer */ + CO_CANmodule_t* CANdevTx; /**< From #CO_LSSslave_init() */ + CO_CANtx_t* TXbuff; /**< CAN transmit buffer */ } CO_LSSslave_t; /** @@ -121,27 +109,22 @@ typedef struct { * * Function must be called in the communication reset section. * - * pendingBitRate and pendingNodeID must be pointers to external variables. Both - * variables must be initialized on program startup (after #CO_NMT_RESET_NODE) - * from non-volatile memory, dip switches or similar. They must not change - * during #CO_NMT_RESET_COMMUNICATION. Both variables can be changed by - * CO_LSSslave_process(), depending on commands from the LSS master. + * pendingBitRate and pendingNodeID must be pointers to external variables. Both variables must be initialized on + * program startup (after #CO_NMT_RESET_NODE) from non-volatile memory, dip switches or similar. They must not change + * during #CO_NMT_RESET_COMMUNICATION. Both variables can be changed by CO_LSSslave_process(), depending on commands + * from the LSS master. * - * If pendingNodeID is valid (1 <= pendingNodeID <= 0x7F), then this becomes - * valid active nodeId just after exit of this function. In that case all other - * CANopen objects may be initialized and processed in run time. + * If pendingNodeID is valid (1 <= pendingNodeID <= 0x7F), then this becomes valid active nodeId just after exit of this + * function. In that case all other CANopen objects may be initialized and processed in run time. * - * If pendingNodeID is not valid (pendingNodeID == 0xFF), then only LSS slave is - * initialized and processed in run time. In that state pendingNodeID can be - * configured and after successful configuration reset communication with all - * CANopen object is activated automatically. + * If pendingNodeID is not valid (pendingNodeID == 0xFF), then only LSS slave is initialized and processed in run time. + * In that state pendingNodeID can be configured and after successful configuration reset communication with all CANopen + * object is activated automatically. * - * @remark The LSS address needs to be unique on the network. For this, the 128 - * bit wide identity object (1018h) is used. Therefore, this object has to be - * fully initialized before passing it to this function (vendorID, product - * code, revisionNo, serialNo are set to 0 by default). Otherwise, if - * non-configured devices are present on CANopen network, LSS configuration may - * behave unpredictable. + * @remark The LSS address needs to be unique on the network. For this, the 128 bit wide identity object (1018h) is + * used. Therefore, this object has to be fully initialized before passing it to this function (vendorID, product code, + * revisionNo, serialNo are set to 0 by default). Otherwise, if non-configured devices are present on CANopen network, + * LSS configuration may behave unpredictable. * * @param LSSslave This object will be initialized. * @param lssAddress LSS address @@ -163,12 +146,10 @@ CO_ReturnError_t CO_LSSslave_init(CO_LSSslave_t* LSSslave, CO_LSS_address_t* lss /** * Process LSS communication * - * Object is partially pre-processed after LSS message received. Further - * processing is inside this function. + * Object is partially pre-processed after LSS message received. Further processing is inside this function. * - * In case that Node-Id is unconfigured, then this function may request CANopen - * communication reset. This happens, when valid node-id is configured by LSS - * master. + * In case that Node-Id is unconfigured, then this function may request CANopen communication reset. This happens, when + * valid node-id is configured by LSS master. * * @param LSSslave This object. * @return True, if #CO_NMT_RESET_COMMUNICATION is requested @@ -190,10 +171,8 @@ CO_LSSslave_getState(CO_LSSslave_t* LSSslave) { /** * Initialize LSSslaveRx callback function. * - * Function initializes optional callback function, which should immediately - * start further LSS processing. Callback is called after LSS message is - * received from the CAN bus. It should signal the RTOS to resume corresponding - * task. + * Function initializes optional callback function, which should immediately start further LSS processing. Callback is + * called after LSS message is received from the CAN bus. It should signal the RTOS to resume corresponding task. * * @param LSSslave This object. * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL @@ -205,11 +184,10 @@ void CO_LSSslave_initCallbackPre(CO_LSSslave_t* LSSslave, void* object, void (*p /** * Initialize verify bit rate callback * - * Function initializes callback function, which is called when "config bit - * timing parameters" is used. The callback function needs to check if the new bit - * rate is supported by the CANopen device. Callback returns "true" if supported. - * When no callback is set the LSS slave will no-ack the request, indicating to - * the master that bit rate change is not supported. + * Function initializes callback function, which is called when "config bit timing parameters" is used. The callback + * function needs to check if the new bit rate is supported by the CANopen device. Callback returns "true" if supported. + * When no callback is set the LSS slave will no-ack the request, indicating to the master that bit rate change is not + * supported. * * @param LSSslave This object. * @param object Pointer to object, which will be passed to pFunctLSScheckBitRate(). Can be NULL @@ -221,12 +199,10 @@ void CO_LSSslave_initCkBitRateCall(CO_LSSslave_t* LSSslave, void* object, /** * Initialize activate bit rate callback * - * Function initializes callback function, which is called when "activate bit - * timing parameters" is used. The callback function gives the user an event to - * allow setting a timer or do calculations based on the exact time the request - * arrived. - * According to DSP 305 6.4.4, the delay has to be applied once before and once after - * switching bit rates. During this time, a device mustn't send any messages. + * Function initializes callback function, which is called when "activate bit timing parameters" is used. The callback + * function gives the user an event to allow setting a timer or do calculations based on the exact time the request + * arrived. According to DSP 305 6.4.4, the delay has to be applied once before and once after switching bit rates. + * During this time, a device mustn't send any messages. * * @param LSSslave This object. * @param object Pointer to object, which will be passed to pFunctLSSactivateBitRate(). Can be NULL @@ -238,12 +214,11 @@ void CO_LSSslave_initActBitRateCall(CO_LSSslave_t* LSSslave, void* object, /** * Store configuration callback * - * Function initializes callback function, which is called when "store configuration" is used. - * The callback function gives the user an event to store the corresponding node id and bit rate - * to NVM. Those values have to be supplied to the init function as "persistent values" - * after reset. If callback returns "true", success is send to the LSS master. When no - * callback is set the LSS slave will no-ack the request, indicating to the master - * that storing is not supported. + * Function initializes callback function, which is called when "store configuration" is used. The callback function + * gives the user an event to store the corresponding node id and bit rate to NVM. Those values have to be supplied to + * the init function as "persistent values" after reset. If callback returns "true", success is send to the LSS master. + * When no callback is set the LSS slave will no-ack the request, indicating to the master that storing is not + * supported. * * @param LSSslave This object. * @param object Pointer to object, which will be passed to pFunctLSScfgStore(). Can be NULL @@ -252,12 +227,12 @@ void CO_LSSslave_initActBitRateCall(CO_LSSslave_t* LSSslave, void* object, void CO_LSSslave_initCfgStoreCall(CO_LSSslave_t* LSSslave, void* object, bool_t (*pFunctLSScfgStore)(void* object, uint8_t id, uint16_t bitRate)); -/** @} */ /*@defgroup CO_LSSslave*/ +/** @} */ /* @defgroup CO_LSSslave */ #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_LSS) & CO_CONFIG_LSS_SLAVE */ -#endif /*CO_LSSslave_H*/ +#endif /* CO_LSSslave_H */ diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 0aaa4592..f416f5ec 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -46,20 +46,16 @@ extern "C" { * * @ingroup CO_CANopen_309 * @{ - * This module enables ascii command interface (CAN gateway), which can be used - * for master interaction with CANopen network. Some sort of string input/output - * stream can be used, for example serial port + terminal on microcontroller or - * stdio in OS or sockets, etc. + * This module enables ascii command interface (CAN gateway), which can be used for master interaction with CANopen + * network. Some sort of string input/output stream can be used, for example serial port + terminal on microcontroller + * or stdio in OS or sockets, etc. * - * For example, one wants to read 'Heartbeat producer time' parameter (0x1017,0) - * on remote node (with id=4). Parameter is 16-bit integer. He can can enter - * command string: `[1] 4 read 0x1017 0 i16`. CANopenNode will use SDO client, - * send request to remote node via CAN, wait for response via CAN and prints - * `[1] OK` to output stream on success. + * For example, one wants to read 'Heartbeat producer time' parameter (0x1017,0) on remote node (with id=4). Parameter + * is 16-bit integer. He can can enter command string: `[1] 4 read 0x1017 0 i16`. CANopenNode will use SDO client, send + * request to remote node via CAN, wait for response via CAN and prints `[1] OK` to output stream on success. * - * This module is usually initialized and processed in CANopen.c file. - * Application should register own callback function for reading the output - * stream. Application writes new commands with CO_GTWA_write(). + * This module is usually initialized and processed in CANopen.c file. Application should register own callback function + * for reading the output stream. Application writes new commands with CO_GTWA_write(). */ /** @@ -140,8 +136,8 @@ lss_allnodes [ [ \\ * @} */ -/** Size of response string buffer. This is intermediate buffer. If there is - * larger amount of data to transfer, then multiple transfers will occur. */ +/** Size of response string buffer. This is intermediate buffer. If there is larger amount of data to transfer, then + * multiple transfers will occur. */ #ifndef CO_GTWA_RESP_BUF_SIZE #define CO_GTWA_RESP_BUF_SIZE 200U #endif @@ -152,105 +148,61 @@ lss_allnodes [ [ \\ #endif /** - * Response error codes as specified by CiA 309-3. Values less or equal to 0 - * are used for control for some functions and are not part of the standard. + * Response error codes as specified by CiA 309-3. Values less or equal to 0 are used for control for some functions and + * are not part of the standard. */ typedef enum { - /** 0 - No error or idle */ - CO_GTWA_respErrorNone = 0, - /** 100 - Request not supported */ - CO_GTWA_respErrorReqNotSupported = 100, - /** 101 - Syntax error */ - CO_GTWA_respErrorSyntax = 101, - /** 102 - Request not processed due to internal state */ - CO_GTWA_respErrorInternalState = 102, - /** 103 - Time-out (where applicable) */ - CO_GTWA_respErrorTimeOut = 103, - /** 104 - No default net set */ - CO_GTWA_respErrorNoDefaultNetSet = 104, - /** 105 - No default node set */ - CO_GTWA_respErrorNoDefaultNodeSet = 105, - /** 106 - Unsupported net */ - CO_GTWA_respErrorUnsupportedNet = 106, - /** 107 - Unsupported node */ - CO_GTWA_respErrorUnsupportedNode = 107, - /** 200 - Lost guarding message */ - CO_GTWA_respErrorLostGuardingMessage = 200, - /** 201 - Lost connection */ - CO_GTWA_respErrorLostConnection = 201, - /** 202 - Heartbeat started */ - CO_GTWA_respErrorHeartbeatStarted = 202, - /** 203 - Heartbeat lost */ - CO_GTWA_respErrorHeartbeatLost = 203, - /** 204 - Wrong NMT state */ - CO_GTWA_respErrorWrongNMTstate = 204, - /** 205 - Boot-up */ - CO_GTWA_respErrorBootUp = 205, - /** 300 - Error passive */ - CO_GTWA_respErrorErrorPassive = 300, - /** 301 - Bus off */ - CO_GTWA_respErrorBusOff = 301, - /** 303 - CAN buffer overflow */ - CO_GTWA_respErrorCANbufferOverflow = 303, - /** 304 - CAN init */ - CO_GTWA_respErrorCANinit = 304, - /** 305 - CAN active (at init or start-up) */ - CO_GTWA_respErrorCANactive = 305, - /** 400 - PDO already used */ - CO_GTWA_respErrorPDOalreadyUsed = 400, - /** 401 - PDO length exceeded */ - CO_GTWA_respErrorPDOlengthExceeded = 401, - /** 501 - LSS implementation- / manufacturer-specific error */ - CO_GTWA_respErrorLSSmanufacturer = 501, - /** 502 - LSS node-ID not supported */ - CO_GTWA_respErrorLSSnodeIdNotSupported = 502, - /** 503 - LSS bit-rate not supported */ - CO_GTWA_respErrorLSSbitRateNotSupported = 503, - /** 504 - LSS parameter storing failed */ - CO_GTWA_respErrorLSSparameterStoringFailed = 504, - /** 505 - LSS command failed because of media error */ - CO_GTWA_respErrorLSSmediaError = 505, - /** 600 - Running out of memory */ - CO_GTWA_respErrorRunningOutOfMemory = 600 + CO_GTWA_respErrorNone = 0, /**< 0 - No error or idle */ + CO_GTWA_respErrorReqNotSupported = 100, /**< 100 - Request not supported */ + CO_GTWA_respErrorSyntax = 101, /**< 101 - Syntax error */ + CO_GTWA_respErrorInternalState = 102, /**< 102 - Request not processed due to internal state */ + CO_GTWA_respErrorTimeOut = 103, /**< 103 - Time-out (where applicable) */ + CO_GTWA_respErrorNoDefaultNetSet = 104, /**< 104 - No default net set */ + CO_GTWA_respErrorNoDefaultNodeSet = 105, /**< 105 - No default node set */ + CO_GTWA_respErrorUnsupportedNet = 106, /**< 106 - Unsupported net */ + CO_GTWA_respErrorUnsupportedNode = 107, /**< 107 - Unsupported node */ + CO_GTWA_respErrorLostGuardingMessage = 200, /**< 200 - Lost guarding message */ + CO_GTWA_respErrorLostConnection = 201, /**< 201 - Lost connection */ + CO_GTWA_respErrorHeartbeatStarted = 202, /**< 202 - Heartbeat started */ + CO_GTWA_respErrorHeartbeatLost = 203, /**< 203 - Heartbeat lost */ + CO_GTWA_respErrorWrongNMTstate = 204, /**< 204 - Wrong NMT state */ + CO_GTWA_respErrorBootUp = 205, /**< 205 - Boot-up */ + CO_GTWA_respErrorErrorPassive = 300, /**< 300 - Error passive */ + CO_GTWA_respErrorBusOff = 301, /**< 301 - Bus off */ + CO_GTWA_respErrorCANbufferOverflow = 303, /**< 303 - CAN buffer overflow */ + CO_GTWA_respErrorCANinit = 304, /**< 304 - CAN init */ + CO_GTWA_respErrorCANactive = 305, /**< 305 - CAN active (at init or start-up) */ + CO_GTWA_respErrorPDOalreadyUsed = 400, /**< 400 - PDO already used */ + CO_GTWA_respErrorPDOlengthExceeded = 401, /**< 401 - PDO length exceeded */ + CO_GTWA_respErrorLSSmanufacturer = 501, /**< 501 - LSS implementation- / manufacturer-specific error */ + CO_GTWA_respErrorLSSnodeIdNotSupported = 502, /**< 502 - LSS node-ID not supported */ + CO_GTWA_respErrorLSSbitRateNotSupported = 503, /**< 503 - LSS bit-rate not supported */ + CO_GTWA_respErrorLSSparameterStoringFailed = 504, /**< 504 - LSS parameter storing failed */ + CO_GTWA_respErrorLSSmediaError = 505, /**< 505 - LSS command failed because of media error */ + CO_GTWA_respErrorRunningOutOfMemory = 600 /**< 600 - Running out of memory */ } CO_GTWA_respErrorCode_t; /** * Internal states of the Gateway-ascii state machine. */ typedef enum { - /** Gateway is idle, no command is processing. This state is starting point - * for new commands, which are parsed here. */ - CO_GTWA_ST_IDLE = 0x00U, - /** SDO 'read' (upload) */ - CO_GTWA_ST_READ = 0x10U, - /** SDO 'write' (download) */ - CO_GTWA_ST_WRITE = 0x11U, - /** SDO 'write' (download) - aborted, purging remaining data */ - CO_GTWA_ST_WRITE_ABORTED = 0x12U, - /** LSS 'lss_switch_glob' */ - CO_GTWA_ST_LSS_SWITCH_GLOB = 0x20U, - /** LSS 'lss_switch_sel' */ - CO_GTWA_ST_LSS_SWITCH_SEL = 0x21U, - /** LSS 'lss_set_node' */ - CO_GTWA_ST_LSS_SET_NODE = 0x22U, - /** LSS 'lss_conf_bitrate' */ - CO_GTWA_ST_LSS_CONF_BITRATE = 0x23U, - /** LSS 'lss_store' */ - CO_GTWA_ST_LSS_STORE = 0x24U, - /** LSS 'lss_inquire_addr' or 'lss_get_node' */ - CO_GTWA_ST_LSS_INQUIRE = 0x25U, - /** LSS 'lss_inquire_addr', all parameters */ - CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL = 0x26U, - /** LSS '_lss_fastscan' */ - CO_GTWA_ST__LSS_FASTSCAN = 0x30U, - /** LSS 'lss_allnodes' */ - CO_GTWA_ST_LSS_ALLNODES = 0x31U, - /** print message 'log' */ - CO_GTWA_ST_LOG = 0x80U, - /** print 'help' text */ - CO_GTWA_ST_HELP = 0x81U, - /** print 'status' of the node */ - CO_GTWA_ST_LED = 0x82U + CO_GTWA_ST_IDLE = 0x00U, /**< Gateway is idle, no command is processing. This state is starting point for new + commands, which are parsed here. */ + CO_GTWA_ST_READ = 0x10U, /**< SDO 'read' (upload) */ + CO_GTWA_ST_WRITE = 0x11U, /**< SDO 'write' (download) */ + CO_GTWA_ST_WRITE_ABORTED = 0x12U, /**< SDO 'write' (download) - aborted, purging remaining data */ + CO_GTWA_ST_LSS_SWITCH_GLOB = 0x20U, /**< LSS 'lss_switch_glob' */ + CO_GTWA_ST_LSS_SWITCH_SEL = 0x21U, /**< LSS 'lss_switch_sel' */ + CO_GTWA_ST_LSS_SET_NODE = 0x22U, /**< LSS 'lss_set_node' */ + CO_GTWA_ST_LSS_CONF_BITRATE = 0x23U, /**< LSS 'lss_conf_bitrate' */ + CO_GTWA_ST_LSS_STORE = 0x24U, /**< LSS 'lss_store' */ + CO_GTWA_ST_LSS_INQUIRE = 0x25U, /**< LSS 'lss_inquire_addr' or 'lss_get_node' */ + CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL = 0x26U, /**< LSS 'lss_inquire_addr', all parameters */ + CO_GTWA_ST__LSS_FASTSCAN = 0x30U, /**< LSS '_lss_fastscan' */ + CO_GTWA_ST_LSS_ALLNODES = 0x31U, /**< LSS 'lss_allnodes' */ + CO_GTWA_ST_LOG = 0x80U, /**< print message 'log' */ + CO_GTWA_ST_HELP = 0x81U, /**< print 'help' text */ + CO_GTWA_ST_LED = 0x82U /**< print 'status' of the node */ } CO_GTWA_state_t; #if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN @@ -258,18 +210,14 @@ typedef enum { * CANopen Gateway-ascii data types structure */ typedef struct { - /** Data type syntax, as defined in CiA309-3 */ - char* syntax; - /** Data type length in bytes, 0 if size is not known */ - size_t length; - /** Function, which reads data of specific data type from fifo buffer and - * writes them as corresponding ascii string. It is a pointer to - * #CO_fifo_readU82a function or similar and is used with SDO upload. For - * description of parameters see #CO_fifo_readU82a */ + char* syntax; /**< Data type syntax, as defined in CiA309-3 */ + size_t length; /**< Data type length in bytes, 0 if size is not known */ + /** Function, which reads data of specific data type from fifo buffer and writes them as corresponding ascii string. + * It is a pointer to #CO_fifo_readU82a function or similar and is used with SDO upload. For description of + * parameters see #CO_fifo_readU82a */ size_t (*dataTypePrint)(CO_fifo_t* fifo, char* buf, size_t count, bool_t end); - /** Function, which reads ascii-data of specific data type from fifo buffer - * and copies them to another fifo buffer as binary data. It is a pointer to - * #CO_fifo_cpyTok2U8 function or similar and is used with SDO download. For + /** Function, which reads ascii-data of specific data type from fifo buffer and copies them to another fifo buffer + * as binary data. It is a pointer to #CO_fifo_cpyTok2U8 function or similar and is used with SDO download. For * description of parameters see #CO_fifo_cpyTok2U8 */ size_t (*dataTypeScan)(CO_fifo_t* dest, CO_fifo_t* src, uint8_t* status); } CO_GTWA_dataType_t; @@ -279,8 +227,8 @@ typedef struct { * CANopen Gateway-ascii object */ typedef struct { - /** Pointer to external function for reading response from Gateway-ascii - * object. Pointer is initialized in CO_GTWA_initRead(). + /** Pointer to external function for reading response from Gateway-ascii object. Pointer is initialized in + * CO_GTWA_initRead(). * * @param object Void pointer to custom object * @param buf Buffer from which data can be read @@ -290,94 +238,60 @@ typedef struct { * @return Count of bytes actually transferred. */ size_t (*readCallback)(void* object, const char* buf, size_t count, uint8_t* connectionOK); - /** Pointer to object, which will be used inside readCallback, from - * CO_GTWA_init() */ - void* readCallbackObject; - /** Sequence number of the command */ - uint32_t sequence; - /** Default CANopen Net number is undefined (-1) at startup */ - int32_t net_default; - /** Default CANopen Node ID number is undefined (-1) at startup */ - int16_t node_default; - /** Current CANopen Net number */ - uint16_t net; - /** Current CANopen Node ID */ - uint8_t node; - /** CO_fifo_t object for command (not pointer) */ - CO_fifo_t commFifo; - /** Command buffer of usable size @ref CO_CONFIG_GTWA_COMM_BUF_SIZE */ - uint8_t commBuf[CO_CONFIG_GTWA_COMM_BUF_SIZE + 1]; - /** Response buffer of usable size @ref CO_GTWA_RESP_BUF_SIZE */ - char respBuf[CO_GTWA_RESP_BUF_SIZE]; - /** Actual size of data in respBuf */ - size_t respBufCount; - /** If only part of data has been successfully written into external - * application (with readCallback()), then Gateway-ascii object will stay - * in current state. This situation is indicated with respHold variable and - * respBufOffset indicates offset to untransferred data inside respBuf. */ - size_t respBufOffset; - /** See respBufOffset above */ - bool_t respHold; - /** Sum of time difference from CO_GTWA_process() in case of respHold */ - uint32_t timeDifference_us_cumulative; - /** Current state of the gateway object */ - CO_GTWA_state_t state; - /** Timeout timer for the current state */ - uint32_t stateTimeoutTmr; + void* readCallbackObject; /**< Pointer to object, which will be used inside readCallback, from CO_GTWA_init() */ + uint32_t sequence; /**< Sequence number of the command */ + int32_t net_default; /**< Default CANopen Net number is undefined (-1) at startup */ + int16_t node_default; /**< Default CANopen Node ID number is undefined (-1) at startup */ + uint16_t net; /**< Current CANopen Net number */ + uint8_t node; /**< Current CANopen Node ID */ + CO_fifo_t commFifo; /**< CO_fifo_t object for command (not pointer) */ + uint8_t commBuf[CO_CONFIG_GTWA_COMM_BUF_SIZE + 1]; /**< Command buffer of usable size + @ref CO_CONFIG_GTWA_COMM_BUF_SIZE */ + char respBuf[CO_GTWA_RESP_BUF_SIZE]; /**< Response buffer of usable size @ref CO_GTWA_RESP_BUF_SIZE */ + size_t respBufCount; /**< Actual size of data in respBuf */ + size_t respBufOffset; /**< If only part of data has been successfully written into external application (with + readCallback()), then Gateway-ascii object will stay in current state. This situation is + indicated with respHold variable and respBufOffset indicates offset to untransferred data + inside respBuf. */ + bool_t respHold; /**< See respBufOffset above */ + uint32_t timeDifference_us_cumulative; /**< Sum of time difference from CO_GTWA_process() in case of respHold */ + CO_GTWA_state_t state; /**< Current state of the gateway object */ + uint32_t stateTimeoutTmr; /**< Timeout timer for the current state */ #if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_SDO) != 0) || defined CO_DOXYGEN - /** SDO client object from CO_GTWA_init() */ - CO_SDOclient_t* SDO_C; - /** Timeout time for SDO transfer in milliseconds, if no response */ - uint16_t SDOtimeoutTime; - /** SDO block transfer enabled? */ - bool_t SDOblockTransferEnable; - /** Indicate status of data copy from / to SDO buffer. If reading, true - * indicates, that response has started. If writing, true indicates, that - * SDO buffer contains only part of data and more data will follow. */ - bool_t SDOdataCopyStatus; - /** Data type of variable in current SDO communication */ - const CO_GTWA_dataType_t* SDOdataType; + CO_SDOclient_t* SDO_C; /**< SDO client object from CO_GTWA_init() */ + uint16_t SDOtimeoutTime; /**< Timeout time for SDO transfer in milliseconds, if no response */ + bool_t SDOblockTransferEnable; /**< SDO block transfer enabled? */ + bool_t SDOdataCopyStatus; /**< Indicate status of data copy from / to SDO buffer. If reading, true indicates, that + response has started. If writing, true indicates, that SDO buffer contains only part of + data and more data will follow. */ + const CO_GTWA_dataType_t* SDOdataType; /**< Data type of variable in current SDO communication */ #endif #if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_NMT) != 0) || defined CO_DOXYGEN - /** NMT object from CO_GTWA_init() */ - CO_NMT_t* NMT; + CO_NMT_t* NMT; /**< NMT object from CO_GTWA_init() */ #endif #if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LSS) != 0) || defined CO_DOXYGEN - /** LSSmaster object from CO_GTWA_init() */ - CO_LSSmaster_t* LSSmaster; - /** 128 bit number, uniquely identifying each node */ - CO_LSS_address_t lssAddress; - /** LSS Node-ID parameter */ - uint8_t lssNID; - /** LSS bitrate parameter */ - uint16_t lssBitrate; - /** LSS inquire parameter */ - uint8_t lssInquireCs; - /** LSS fastscan parameter */ - CO_LSSmaster_fastscan_t lssFastscan; - /** LSS allnodes sub state parameter */ - uint8_t lssSubState; - /** LSS allnodes node count parameter */ - uint8_t lssNodeCount; - /** LSS allnodes store parameter */ - bool_t lssStore; - /** LSS allnodes timeout parameter */ - uint16_t lssTimeout_ms; + CO_LSSmaster_t* LSSmaster; /**< LSSmaster object from CO_GTWA_init() */ + CO_LSS_address_t lssAddress; /**< 128 bit number, uniquely identifying each node */ + uint8_t lssNID; /**< LSS Node-ID parameter */ + uint16_t lssBitrate; /**< LSS bitrate parameter */ + uint8_t lssInquireCs; /**< LSS inquire parameter */ + CO_LSSmaster_fastscan_t lssFastscan; /**< LSS fastscan parameter */ + uint8_t lssSubState; /**< LSS allnodes sub state parameter */ + uint8_t lssNodeCount; /**< LSS allnodes node count parameter */ + bool_t lssStore; /**< LSS allnodes store parameter */ + uint16_t lssTimeout_ms; /**< LSS allnodes timeout parameter */ #endif #if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0) || defined CO_DOXYGEN - /** Message log buffer of usable size @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */ - uint8_t logBuf[CO_CONFIG_GTWA_LOG_BUF_SIZE + 1]; - /** CO_fifo_t object for message log (not pointer) */ - CO_fifo_t logFifo; + uint8_t logBuf[CO_CONFIG_GTWA_LOG_BUF_SIZE + 1]; /**< Message log buffer of usable size + @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */ + CO_fifo_t logFifo; /**< CO_fifo_t object for message log (not pointer) */ #endif #if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_HELP) != 0) || defined CO_DOXYGEN - /** Offset, when printing help text */ - const char* helpString; + const char* helpString; /**< Offset, when printing help text */ size_t helpStringOffset; #endif #if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_PRINT_LEDS) != 0) || defined CO_DOXYGEN - /** CO_LEDs_t object for CANopen status LEDs imitation from CO_GTWA_init()*/ - CO_LEDs_t* LEDs; + CO_LEDs_t* LEDs; /**< CO_LEDs_t object for CANopen status LEDs imitation from CO_GTWA_init() */ uint8_t ledStringPreviousIndex; #endif } CO_GTWA_t; @@ -414,16 +328,14 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa, /** * Initialize read callback in Gateway-ascii object * - * Callback will be used for transfer data to output stream of the application. - * It will be called from CO_GTWA_process() zero or multiple times, depending on - * the data available. If readCallback is uninitialized or NULL, then output - * data will be purged. + * Callback will be used for transfer data to output stream of the application. It will be called from CO_GTWA_process() + * zero or multiple times, depending on the data available. If readCallback is uninitialized or NULL, then output data + * will be purged. * * @param gtwa This object will be initialized - * @param readCallback Pointer to external function for reading response from - * Gateway-ascii object. See #CO_GTWA_t for parameters. - * @param readCallbackObject Pointer to object, which will be used inside - * readCallback + * @param readCallback Pointer to external function for reading response from Gateway-ascii object. See #CO_GTWA_t for + * parameters. + * @param readCallbackObject Pointer to object, which will be used inside readCallback */ void CO_GTWA_initRead(CO_GTWA_t* gtwa, size_t (*readCallback)(void* object, const char* buf, size_t count, uint8_t* connectionOK), @@ -444,11 +356,9 @@ CO_GTWA_write_getSpace(CO_GTWA_t* gtwa) { /** * Write command into CO_GTWA_t object. * - * This function copies ascii command from buf into internal fifo buffer. - * Command must be closed with '\n' character. Function returns number of bytes - * successfully copied. If there is not enough space in destination, not all - * bytes will be copied and data can be refilled later (in case of large SDO - * download). + * This function copies ascii command from buf into internal fifo buffer. Command must be closed with '\n' character. + * Function returns number of bytes successfully copied. If there is not enough space in destination, not all bytes will + * be copied and data can be refilled later (in case of large SDO download). * * @param gtwa This object * @param buf Buffer which will be copied @@ -465,11 +375,9 @@ CO_GTWA_write(CO_GTWA_t* gtwa, const char* buf, size_t count) { /** * Print message log string into fifo buffer * - * This function enables recording of system log messages including CANopen - * events. Function can be called by application for recording any message. - * Message is copied to internal fifo buffer. In case fifo is full, old messages - * will be owerwritten. Message log fifo can be read with non-standard command - * "log". After log is read, it is emptied. + * This function enables recording of system log messages including CANopen events. Function can be called by + * application for recording any message. Message is copied to internal fifo buffer. In case fifo is full, old messages + * will be owerwritten. Message log fifo can be read with non-standard command "log". After log is read, it is emptied. * * @param gtwa This object * @param message Null terminated string @@ -483,11 +391,9 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char* message); * This is non-blocking function and must be called cyclically * * @param gtwa This object will be initialized. - * @param enable If true, gateway operates normally. If false, gateway is - * completely disabled and no command interaction is possible. Can be connected - * to hardware switch, for example. - * @param timeDifference_us Time difference from previous function call in - * [microseconds]. + * @param enable If true, gateway operates normally. If false, gateway is completely disabled and no command interaction + * is possible. Can be connected to hardware switch, for example. + * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). * * @return CO_ReturnError_t: CO_ERROR_NO on success or CO_ERROR_ILLEGAL_ARGUMENT @@ -498,7 +404,7 @@ void CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */ diff --git a/CANopen.h b/CANopen.h index c4fa2028..493fd447 100644 --- a/CANopen.h +++ b/CANopen.h @@ -51,30 +51,24 @@ extern "C" { * * CANopenNode is free and open source CANopen communication protocol stack. * - * CANopen is the internationally standardized (EN 50325-4) (CiA DS-301) - * CAN-based higher-layer protocol for embedded control system. For more - * information on CANopen see http://www.can-cia.org/ + * CANopen is the internationally standardized (EN 50325-4) (CiA DS-301) CAN-based higher-layer protocol for embedded + * control system. For more information on CANopen see http://www.can-cia.org/ * * CANopenNode homepage is https://github.com/CANopenNode/CANopenNode * - * CANopen.h file combines all CANopenNode source files. @ref CO_STACK_CONFIG - * is first defined in "CO_config.h" file. Number of different CANopenNode - * objects used is configured with @ref CO_config_t structure or is read - * directly from "OD.h" file, if single object dictionary definition is used. - * "OD.h" and "OD.c" files defines CANopen Object Dictionary and are generated - * by external tool. + * CANopen.h file combines all CANopenNode source files. @ref CO_STACK_CONFIG is first defined in "CO_config.h" file. + * Number of different CANopenNode objects used is configured with @ref CO_config_t structure or is read directly from + * "OD.h" file, if single object dictionary definition is used. "OD.h" and "OD.c" files defines CANopen Object + * Dictionary and are generated by external tool. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. * @} */ @@ -84,8 +78,8 @@ extern "C" { * * CANopen application layer and communication profile (CiA 301 v4.2.0) * - * Definitions of data types, encoding rules, object dictionary objects and - * CANopen communication services and protocols. + * Definitions of data types, encoding rules, object dictionary objects and CANopen communication services and + * protocols. * @} */ @@ -105,9 +99,8 @@ extern "C" { * * CANopen Safety (EN 50325­-5:2010 (formerly CiA 304)) * - * Standard defines the usage of Safety Related Data Objects (SRDO) and the GFC. - * This is an additional protocol (to SDO, PDO) to exchange data. The meaning of - * "security" here refers not to security (crypto) but to data consistency. + * Standard defines the usage of Safety Related Data Objects (SRDO) and the GFC. This is an additional protocol (to SDO, + * PDO) to exchange data. The meaning of "security" here refers not to security (crypto) but to data consistency. * @} */ @@ -117,11 +110,9 @@ extern "C" { * * CANopen layer setting services (LSS) and protocols (CiA 305 DSP v3.0.0) * - * Inquire or change three parameters on a CANopen device with LSS slave - * capability by a CANopen device with LSS master capability via the CAN - * network: the settings of Node-ID of the CANopen device, bit timing - * parameters of the physical layer (bit rate) or LSS address compliant to the - * identity object (1018h). + * Inquire or change three parameters on a CANopen device with LSS slave capability by a CANopen device with LSS master + * capability via the CAN network: the settings of Node-ID of the CANopen device, bit timing parameters of the physical + * layer (bit rate) or LSS address compliant to the identity object (1018h). * @} */ @@ -131,8 +122,8 @@ extern "C" { * * CANopen access from other networks (CiA 309) * - * Standard defines the services and protocols to interface CANopen networks to - * other networks. Standard is organized as follows: + * Standard defines the services and protocols to interface CANopen networks to other networks. Standard is organized as + * follows: * - Part 1: General principles and services * - Part 2: Modbus/TCP mapping * - Part 3: ASCII mapping @@ -162,9 +153,8 @@ extern "C" { */ /** - * If macro is defined externally, then configuration with multiple object - * dictionaries will be possible. If macro is not defined, default "OD.h" file - * with necessary definitions, such as OD_CNT_xxx, will be used, and also memory + * If macro is defined externally, then configuration with multiple object dictionaries will be possible. If macro is + * not defined, default "OD.h" file with necessary definitions, such as OD_CNT_xxx, will be used, and also memory * consumption and startup time will be lower. */ #ifdef CO_DOXYGEN @@ -184,85 +174,61 @@ extern "C" { /** * CANopen configuration, used with @ref CO_new() * - * This structure is used only, if @ref CO_MULTIPLE_OD is enabled. Otherwise - * parameters are retrieved from default "OD.h" file. + * This structure is used only, if @ref CO_MULTIPLE_OD is enabled. Otherwise parameters are retrieved from default + * "OD.h" file. */ typedef struct { - /** Number of NMT objects, 0 or 1: NMT slave (CANrx) + Heartbeat producer - * (CANtx) + optional NMT master (CANtx), configurable by - * @ref CO_CONFIG_NMT. Start indexes inside CANrx and CANtx are always 0. - * There must be one NMT object in the device. */ - uint8_t CNT_NMT; + uint8_t CNT_NMT; /**< Number of NMT objects, 0 or 1: NMT slave (CANrx) + Heartbeat producer (CANtx) + + optional NMT master (CANtx), configurable by @ref CO_CONFIG_NMT. Start indexes inside + CANrx and CANtx are always 0. There must be one NMT object in the device. */ OD_entry_t* ENTRY_H1017; /**< OD entry for @ref CO_NMT_init() */ - /** Number of Heartbeat consumer objects, 0 or 1 */ - uint8_t CNT_HB_CONS; - /** Number of internal consumers (CANrx), used inside Heartbeat consumer - * object, 1 to 127. */ - uint8_t CNT_ARR_1016; - OD_entry_t* ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init()*/ - /** OD entry for @ref CO_nodeGuardingSlave_init() */ - OD_entry_t* ENTRY_H100C; - /** OD entry for @ref CO_nodeGuardingSlave_init() */ - OD_entry_t* ENTRY_H100D; - /** Number of Emergency objects, 0 or 1: optional producer (CANtx) + - * optional consumer (CANrx), configurable by @ref CO_CONFIG_EM. - * There must be one Emergency object in the device. */ - uint8_t CNT_EM; + uint8_t CNT_HB_CONS; /**< Number of Heartbeat consumer objects, 0 or 1 */ + uint8_t CNT_ARR_1016; /**< Number of internal consumers (CANrx), used inside Heartbeat consumer object, 1 to 127. */ + OD_entry_t* ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init() */ + OD_entry_t* ENTRY_H100C; /**< OD entry for @ref CO_nodeGuardingSlave_init() */ + OD_entry_t* ENTRY_H100D; /**< OD entry for @ref CO_nodeGuardingSlave_init() */ + uint8_t CNT_EM; /**< Number of Emergency objects, 0 or 1: optional producer (CANtx) + optional consumer (CANrx), + configurable by @ref CO_CONFIG_EM. There must be one Emergency object in the device. */ const OD_entry_t* ENTRY_H1001; /**< OD entry for @ref CO_EM_init() */ OD_entry_t* ENTRY_H1014; /**< OD entry for @ref CO_EM_init() */ OD_entry_t* ENTRY_H1015; /**< OD entry for @ref CO_EM_init() */ - /** Size of the fifo buffer, which is used for intermediate storage of - * emergency messages. Fifo is used by emergency producer and by error - * history (OD object 0x1003). Size is usually equal to size of array in - * OD object 0x1003. If later is not used, CNT_ARR_1003 must also be set to - * value greater than 0, or emergency producer will not work. */ - uint8_t CNT_ARR_1003; + uint8_t CNT_ARR_1003; /**< Size of the fifo buffer, which is used for intermediate storage of emergency messages. + Fifo is used by emergency producer and by error history (OD object 0x1003). Size is usually + equal to size of array in OD object 0x1003. If later is not used, CNT_ARR_1003 must also be + set to value greater than 0, or emergency producer will not work. */ OD_entry_t* ENTRY_H1003; /**< OD entry for @ref CO_EM_init() */ - /** Number of SDO server objects, from 0 to 128 (CANrx + CANtx). There must - * be at least one SDO server object in the device. */ - uint8_t CNT_SDO_SRV; - OD_entry_t* ENTRY_H1200; /**< OD entry for @ref CO_SDOserver_init()*/ - /** Number of SDO client objects, from 0 to 128 (CANrx + CANtx). */ - uint8_t CNT_SDO_CLI; - OD_entry_t* ENTRY_H1280; /**< OD entry for @ref CO_SDOclient_init()*/ - /** Number of TIME objects, 0 or 1: consumer (CANrx) + optional producer - * (CANtx), configurable by @ref CO_CONFIG_TIME. */ - uint8_t CNT_TIME; + uint8_t CNT_SDO_SRV; /**< Number of SDO server objects, from 0 to 128 (CANrx + CANtx). There must be at least + one SDO server object in the device. */ + OD_entry_t* ENTRY_H1200; /**< OD entry for @ref CO_SDOserver_init() */ + uint8_t CNT_SDO_CLI; /**< Number of SDO client objects, from 0 to 128 (CANrx + CANtx). */ + OD_entry_t* ENTRY_H1280; /**< OD entry for @ref CO_SDOclient_init() */ + uint8_t CNT_TIME; /**< Number of TIME objects, 0 or 1: consumer (CANrx) + optional producer (CANtx), + configurable by @ref CO_CONFIG_TIME. */ OD_entry_t* ENTRY_H1012; /**< OD entry for @ref CO_TIME_init() */ - /** Number of SYNC objects, 0 or 1: consumer (CANrx) + optional producer - * (CANtx), configurable by @ref CO_CONFIG_SYNC. */ - uint8_t CNT_SYNC; + uint8_t CNT_SYNC; /**< Number of SYNC objects, 0 or 1: consumer (CANrx) + optional producer (CANtx), + configurable by @ref CO_CONFIG_SYNC. */ OD_entry_t* ENTRY_H1005; /**< OD entry for @ref CO_SYNC_init() */ OD_entry_t* ENTRY_H1006; /**< OD entry for @ref CO_SYNC_init() */ OD_entry_t* ENTRY_H1007; /**< OD entry for @ref CO_SYNC_init() */ OD_entry_t* ENTRY_H1019; /**< OD entry for @ref CO_SYNC_init() */ - /** Number of RPDO objects, from 0 to 512 consumers (CANrx) */ - uint16_t CNT_RPDO; + uint16_t CNT_RPDO; /**< Number of RPDO objects, from 0 to 512 consumers (CANrx) */ OD_entry_t* ENTRY_H1400; /**< OD entry for @ref CO_RPDO_init() */ OD_entry_t* ENTRY_H1600; /**< OD entry for @ref CO_RPDO_init() */ - /** Number of TPDO objects, from 0 to 512 producers (CANtx) */ - uint16_t CNT_TPDO; + uint16_t CNT_TPDO; /**< Number of TPDO objects, from 0 to 512 producers (CANtx) */ OD_entry_t* ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */ OD_entry_t* ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */ - /** Number of LEDs objects, 0 or 1. */ - uint8_t CNT_LEDS; - /** Number of GFC objects, 0 or 1 (CANrx + CANtx). */ - uint8_t CNT_GFC; + uint8_t CNT_LEDS; /**< Number of LEDs objects, 0 or 1. */ + uint8_t CNT_GFC; /**< Number of GFC objects, 0 or 1 (CANrx + CANtx). */ OD_entry_t* ENTRY_H1300; /**< OD entry for @ref CO_GFC_init() */ - /** Number of SRDO objects, from 0 to 64 (2*CANrx + 2*CANtx). */ - uint8_t CNT_SRDO; + uint8_t CNT_SRDO; /**< Number of SRDO objects, from 0 to 64 (2*CANrx + 2*CANtx). */ OD_entry_t* ENTRY_H1301; /**< OD entry for @ref CO_SRDO_init() */ OD_entry_t* ENTRY_H1381; /**< OD entry for @ref CO_SRDO_init() */ OD_entry_t* ENTRY_H13FE; /**< OD entry for @ref CO_SRDO_init() */ OD_entry_t* ENTRY_H13FF; /**< OD entry for @ref CO_SRDO_init() */ - /** Number of LSSslave objects, 0 or 1 (CANrx + CANtx). */ - uint8_t CNT_LSS_SLV; - /** Number of LSSmaster objects, 0 or 1 (CANrx + CANtx). */ - uint8_t CNT_LSS_MST; - /** Number of gateway ascii objects, 0 or 1. */ - uint8_t CNT_GTWA; - /** Number of trace objects, 0 or more. */ - uint16_t CNT_TRACE; + uint8_t CNT_LSS_SLV; /**< Number of LSSslave objects, 0 or 1 (CANrx + CANtx). */ + uint8_t CNT_LSS_MST; /**< Number of LSSmaster objects, 0 or 1 (CANrx + CANtx). */ + uint8_t CNT_GTWA; /**< Number of gateway ascii objects, 0 or 1. */ + uint16_t CNT_TRACE; /**< Number of trace objects, 0 or more. */ } CO_config_t; #else typedef void CO_config_t; @@ -276,167 +242,142 @@ typedef struct { #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN CO_config_t* config; /**< Remember the configuration parameters */ #endif - /** One CAN module object, initialised by @ref CO_CANmodule_init() */ - CO_CANmodule_t* CANmodule; - CO_CANrx_t* CANrx; /**< CAN receive message objects */ - CO_CANtx_t* CANtx; /**< CAN transmit message objects */ + CO_CANmodule_t* CANmodule; /**< One CAN module object, initialised by @ref CO_CANmodule_init() */ + CO_CANrx_t* CANrx; /**< CAN receive message objects */ + CO_CANtx_t* CANtx; /**< CAN transmit message objects */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t CNT_ALL_RX_MSGS; /**< Number of all CAN receive message objects. */ - uint16_t CNT_ALL_TX_MSGS; /**< Number of all CAN transmit message objects.*/ + uint16_t CNT_ALL_TX_MSGS; /**< Number of all CAN transmit message objects. */ #endif - /** NMT and heartbeat object, initialised by @ref CO_NMT_init() */ - CO_NMT_t* NMT; + CO_NMT_t* NMT; /**< NMT and heartbeat object, initialised by @ref CO_NMT_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_NMT_SLV; /**< Start index in CANrx. */ uint16_t TX_IDX_NMT_MST; /**< Start index in CANtx. */ uint16_t TX_IDX_HB_PROD; /**< Start index in CANtx. */ #endif #if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0) || defined CO_DOXYGEN - /** Heartbeat consumer object, initialised by @ref CO_HBconsumer_init() */ - CO_HBconsumer_t* HBcons; - /** Object for monitored nodes, initialised by @ref CO_HBconsumer_init() */ - CO_HBconsNode_t* HBconsMonitoredNodes; + CO_HBconsumer_t* HBcons; /**< Heartbeat consumer object, initialised by @ref CO_HBconsumer_init() */ + CO_HBconsNode_t* HBconsMonitoredNodes; /**< Object for monitored nodes, initialised by @ref CO_HBconsumer_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_HB_CONS; /**< Start index in CANrx. */ #endif #endif #if (((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0) || defined CO_DOXYGEN - /** Node guarding slave object, initialised by @ref CO_nodeGuardingSlave_init() */ - CO_nodeGuardingSlave_t* NGslave; + CO_nodeGuardingSlave_t* NGslave; /**< Node guarding slave object, initialised by @ref CO_nodeGuardingSlave_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_NG_SLV; /**< Start index in CANrx. */ uint16_t TX_IDX_NG_SLV; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0) || defined CO_DOXYGEN - /** Node guarding master object, initialised by @ref CO_nodeGuardingMaster_init() */ - CO_nodeGuardingMaster_t* NGmaster; + CO_nodeGuardingMaster_t* + NGmaster; /**< Node guarding master object, initialised by @ref CO_nodeGuardingMaster_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_NG_MST; /**< Start index in CANrx. */ uint16_t TX_IDX_NG_MST; /**< Start index in CANtx. */ #endif #endif - /** Emergency object, initialised by @ref CO_EM_init() */ - CO_EM_t* em; + CO_EM_t* em; /**< Emergency object, initialised by @ref CO_EM_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_EM_CONS; /**< Start index in CANrx. */ uint16_t TX_IDX_EM_PROD; /**< Start index in CANtx. */ #endif #if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) || defined CO_DOXYGEN - /** FIFO for emergency object, initialised by @ref CO_EM_init() */ - CO_EM_fifo_t* em_fifo; + CO_EM_fifo_t* em_fifo; /**< FIFO for emergency object, initialised by @ref CO_EM_init() */ #endif - /** SDO server objects, initialised by @ref CO_SDOserver_init() */ - CO_SDOserver_t* SDOserver; + CO_SDOserver_t* SDOserver; /**< SDO server objects, initialised by @ref CO_SDOserver_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SDO_SRV; /**< Start index in CANrx. */ uint16_t TX_IDX_SDO_SRV; /**< Start index in CANtx. */ #endif #if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN - /** SDO client objects, initialised by @ref CO_SDOclient_init() */ - CO_SDOclient_t* SDOclient; + CO_SDOclient_t* SDOclient; /**< SDO client objects, initialised by @ref CO_SDOclient_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SDO_CLI; /**< Start index in CANrx. */ uint16_t TX_IDX_SDO_CLI; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN - /** TIME object, initialised by @ref CO_TIME_init() */ - CO_TIME_t* TIME; + CO_TIME_t* TIME; /**< TIME object, initialised by @ref CO_TIME_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_TIME; /**< Start index in CANrx. */ uint16_t TX_IDX_TIME; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN - /** SYNC object, initialised by @ref CO_SYNC_init() */ - CO_SYNC_t* SYNC; + CO_SYNC_t* SYNC; /**< SYNC object, initialised by @ref CO_SYNC_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SYNC; /**< Start index in CANrx. */ uint16_t TX_IDX_SYNC; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN - /** RPDO objects, initialised by @ref CO_RPDO_init() */ - CO_RPDO_t* RPDO; + CO_RPDO_t* RPDO; /**< RPDO objects, initialised by @ref CO_RPDO_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_RPDO; /**< Start index in CANrx. */ #endif #endif #if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN - /** TPDO objects, initialised by @ref CO_TPDO_init() */ - CO_TPDO_t* TPDO; + CO_TPDO_t* TPDO; /**< TPDO objects, initialised by @ref CO_TPDO_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t TX_IDX_TPDO; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN - /** LEDs object, initialised by @ref CO_LEDs_init() */ - CO_LEDs_t* LEDs; + CO_LEDs_t* LEDs; /**< LEDs object, initialised by @ref CO_LEDs_init() */ #endif #if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || defined CO_DOXYGEN - /** GFC object, initialised by @ref CO_GFC_init() */ - CO_GFC_t* GFC; + CO_GFC_t* GFC; /**< GFC object, initialised by @ref CO_GFC_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_GFC; /**< Start index in CANrx. */ uint16_t TX_IDX_GFC; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN - /** SRDO guard object, initialised by @ref CO_SRDO_init_start(), single - * SRDOGuard object is included inside all SRDO objects */ - CO_SRDOGuard_t* SRDOGuard; - /** SRDO objects, initialised by @ref CO_SRDO_init() */ - CO_SRDO_t* SRDO; + CO_SRDOGuard_t* SRDOGuard; /**< SRDO guard object, initialised by @ref CO_SRDO_init_start(), single SRDOGuard object + is included inside all SRDO objects */ + CO_SRDO_t* SRDO; /**< SRDO objects, initialised by @ref CO_SRDO_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SRDO; /**< Start index in CANrx. */ uint16_t TX_IDX_SRDO; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN - /** LSS slave object, initialised by @ref CO_LSSslave_init(). */ - CO_LSSslave_t* LSSslave; + CO_LSSslave_t* LSSslave; /**< LSS slave object, initialised by @ref CO_LSSslave_init(). */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_LSS_SLV; /**< Start index in CANrx. */ uint16_t TX_IDX_LSS_SLV; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0) || defined CO_DOXYGEN - /** LSS master object, initialised by @ref CO_LSSmaster_init(). */ - CO_LSSmaster_t* LSSmaster; + CO_LSSmaster_t* LSSmaster; /**< LSS master object, initialised by @ref CO_LSSmaster_init(). */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_LSS_MST; /**< Start index in CANrx. */ uint16_t TX_IDX_LSS_MST; /**< Start index in CANtx. */ #endif #endif #if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0) || defined CO_DOXYGEN - /** Gateway-ascii object, initialised by @ref CO_GTWA_init(). */ - CO_GTWA_t* gtwa; + CO_GTWA_t* gtwa; /**< Gateway-ascii object, initialised by @ref CO_GTWA_init(). */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN #endif #endif #if ((CO_CONFIG_TRACE)&CO_CONFIG_TRACE_ENABLE) || defined CO_DOXYGEN - /** Trace object, initialised by @ref CO_trace_init(). */ - CO_trace_t* trace; + CO_trace_t* trace; /**< Trace object, initialised by @ref CO_trace_init(). */ #endif } CO_t; /** * Create new CANopen object * - * If CO_USE_GLOBALS is defined, then function uses global static variables for - * all the CANopenNode objects. Otherwise it allocates all objects from heap. + * If CO_USE_GLOBALS is defined, then function uses global static variables for all the CANopenNode objects. Otherwise + * it allocates all objects from heap. * * @remark - * With some microcontrollers it is necessary to specify Heap size within - * linker configuration, if heap is used. + * With some microcontrollers it is necessary to specify Heap size within linker configuration, if heap is used. * - * @param config Configuration structure, used if @ref CO_MULTIPLE_OD is - * defined. It must stay in memory permanently. If CO_MULTIPLE_OD is not - * defined, config should be NULL and parameters are retrieved from default - * "OD.h" file. - * @param [out] heapMemoryUsed Information about heap memory used. Ignored if - * NULL. + * @param config Configuration structure, used if @ref CO_MULTIPLE_OD is defined. It must stay in memory permanently. If + * CO_MULTIPLE_OD is not defined, config should be NULL and parameters are retrieved from default "OD.h" file. + * @param [out] heapMemoryUsed Information about heap memory used. Ignored if NULL. * * @return Successfully allocated and configured CO_t object or NULL. */ @@ -464,8 +405,7 @@ bool_t CO_isLSSslaveEnabled(CO_t* co); * Function must be called in the communication reset section. * * @param co CANopen object. - * @param CANptr Pointer to the user-defined CAN base structure, passed to - * CO_CANmodule_init(). + * @param CANptr Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init(). * @param bitRate CAN bit rate. * @return CO_ERROR_NO in case of success. */ @@ -495,28 +435,24 @@ CO_ReturnError_t CO_LSSinit(CO_t* co, CO_LSS_address_t* lssAddress, uint8_t* pen * Function must be called in the communication reset section. * * @param co CANopen object. - * @param em Emergency object, which is used inside different CANopen objects, - * usually for error reporting. If NULL, then 'co->em' will be used. - * if NULL and 'co->CNT_EM' is 0, then function returns with error. - * @param NMT If 'co->CNT_NMT' is 0, this object must be specified, If - * 'co->CNT_NMT' is 1,then it is ignored and can be NULL. NMT object is used for - * retrieving NMT internal state inside CO_process(). + * @param em Emergency object, which is used inside different CANopen objects, usually for error reporting. If NULL, + * then 'co->em' will be used. if NULL and 'co->CNT_EM' is 0, then function returns with error. + * @param NMT If 'co->CNT_NMT' is 0, this object must be specified, If 'co->CNT_NMT' is 1,then it is ignored and can be + * NULL. NMT object is used for retrieving NMT internal state inside CO_process(). * @param od CANopen Object dictionary * @param OD_statusBits Argument passed to @ref CO_EM_init(). May be NULL. * @param NMTcontrol Argument passed to @ref CO_NMT_init(). * @param firstHBTime_ms Argument passed to @ref CO_NMT_init(). * @param SDOserverTimeoutTime_ms Argument passed to @ref CO_SDOserver_init(). - * @param SDOclientTimeoutTime_ms Default timeout in milliseconds for SDO - * client, 500 typically. SDO client is configured from CO_GTWA_init(). - * @param SDOclientBlockTransfer If true, block transfer will be set in SDO - * client by default. SDO client is configured from by CO_GTWA_init(). - * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). In the - * CANopen initialization it is the same as pendingBitRate from CO_LSSinit(). - * If it is unconfigured, then some CANopen objects will not be initialized nor + * @param SDOclientTimeoutTime_ms Default timeout in milliseconds for SDO client, 500 typically. SDO client is + * configured from CO_GTWA_init(). + * @param SDOclientBlockTransfer If true, block transfer will be set in SDO client by default. SDO client is configured + * from by CO_GTWA_init(). + * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). In the CANopen initialization it is the same as + * pendingBitRate from CO_LSSinit(). If it is unconfigured, then some CANopen objects will not be initialized nor * processed. - * @param [out] errInfo Additional information in case of error, may be NULL. - * errInfo can also be set in noncritical errors, where function returns - * CO_ERROR_NO. For example, if OD parameter contains wrong value. + * @param [out] errInfo Additional information in case of error, may be NULL. errInfo can also be set in noncritical + * errors, where function returns CO_ERROR_NO. For example, if OD parameter contains wrong value. * * @return CO_ERROR_NO in case of success. */ @@ -528,16 +464,14 @@ CO_ReturnError_t CO_CANopenInit(CO_t* co, CO_NMT_t* NMT, CO_EM_t* em, OD_t* od, /** * Initialize CANopenNode PDO objects. * - * Function must be called in the end of communication reset section after all - * CANopen and application initialization, otherwise some OD variables wont be - * mapped into PDO correctly. + * Function must be called in the end of communication reset section after all CANopen and application initialization, + * otherwise some OD variables wont be mapped into PDO correctly. * * @param co CANopen object. - * @param em Emergency object, which is used inside PDO objects for error - * reporting. + * @param em Emergency object, which is used inside PDO objects for error reporting. * @param od CANopen Object dictionary - * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). If - * unconfigured, then PDO will not be initialized nor processed. + * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). If unconfigured, then PDO will not be initialized + * nor processed. * @param [out] errInfo Additional information in case of error, may be NULL. * * @return CO_ERROR_NO in case of success. @@ -547,16 +481,14 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t node /** * Initialize Safety related Data Objects. * - * Function must be called in the end of communication reset section after all - * CANopen and application initialization, otherwise some OD variables wont be - * mapped into SRDO correctly. + * Function must be called in the end of communication reset section after all CANopen and application initialization, + * otherwise some OD variables wont be mapped into SRDO correctly. * * @param co CANopen object. - * @param em Emergency object, which is used inside PDO objects for error - * reporting. + * @param em Emergency object, which is used inside PDO objects for error reporting. * @param od CANopen Object dictionary - * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). If - * unconfigured, then PDO will not be initialized nor processed. + * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). If unconfigured, then PDO will not be initialized + * nor processed. * @param [out] errInfo Additional information in case of error, may be NULL. * * @return CO_ERROR_NO in case of success. @@ -568,22 +500,17 @@ CO_ReturnError_t CO_CANopenInitSRDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nod /** * Process CANopen objects. * - * Function must be called cyclically. It processes all "asynchronous" CANopen - * objects. + * Function must be called cyclically. It processes all "asynchronous" CANopen objects. * * @param co CANopen object. * @param enableGateway If true, gateway to external world will be enabled. - * @param timeDifference_us Time difference from previous function call in - * microseconds. - * @param [out] timerNext_us info to OS - maximum delay time after this function - * should be called next time in [microseconds]. Value can be used for OS - * sleep time. Initial value must be set to maximum interval time. - * Output will be equal or lower to initial value. Calculation is based - * on various timers which expire in known time. Parameter should be - * used in combination with callbacks configured with - * CO_***_initCallbackPre() functions. Those callbacks should also - * trigger calling of CO_process() function. Parameter is ignored if - * NULL. See also @ref CO_CONFIG_FLAG_CALLBACK_PRE configuration macro. + * @param timeDifference_us Time difference from previous function call in microseconds. + * @param [out] timerNext_us info to OS - maximum delay time after this function should be called next time in + * [microseconds]. Value can be used for OS sleep time. Initial value must be set to maximum interval time. Output will + * be equal or lower to initial value. Calculation is based on various timers which expire in known time. Parameter + * should be used in combination with callbacks configured with CO_***_initCallbackPre() functions. Those callbacks + * should also trigger calling of CO_process() function. Parameter is ignored if NULL. See also @ref + * CO_CONFIG_FLAG_CALLBACK_PRE configuration macro. * * @return Node or communication reset request, from @ref CO_NMT_process(). */ @@ -593,13 +520,11 @@ CO_NMT_reset_cmd_t CO_process(CO_t* co, bool_t enableGateway, uint32_t timeDiffe /** * Process CANopen SYNC objects. * - * Function must be called cyclically. For time critical applications it may be - * called from real time thread with constant interval (1ms typically). It - * processes SYNC CANopen objects. + * Function must be called cyclically. For time critical applications it may be called from real time thread with + * constant interval (1ms typically). It processes SYNC CANopen objects. * * @param co CANopen object. - * @param timeDifference_us Time difference from previous function call in - * microseconds. + * @param timeDifference_us Time difference from previous function call in microseconds. * @param [out] timerNext_us info to OS - see CO_process(). * * @return True, if CANopen SYNC message was just received or transmitted. @@ -611,15 +536,12 @@ bool_t CO_process_SYNC(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext /** * Process CANopen RPDO objects. * - * Function must be called cyclically. For time critical applications it may be - * called from real time thread with constant interval (1ms typically). It - * processes receive PDO CANopen objects. + * Function must be called cyclically. For time critical applications it may be called from real time thread with + * constant interval (1ms typically). It processes receive PDO CANopen objects. * * @param co CANopen object. - * @param syncWas True, if CANopen SYNC message was just received or - * transmitted. - * @param timeDifference_us Time difference from previous function call in - * microseconds. + * @param syncWas True, if CANopen SYNC message was just received or transmitted. + * @param timeDifference_us Time difference from previous function call in microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us); @@ -629,15 +551,12 @@ void CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint3 /** * Process CANopen TPDO objects. * - * Function must be called cyclically. For time critical applications it may be - * called from real time thread with constant interval (1ms typically). It - * processes transmit PDO CANopen objects. + * Function must be called cyclically. For time critical applications it may be called from real time thread with + * constant interval (1ms typically). It processes transmit PDO CANopen objects. * * @param co CANopen object. - * @param syncWas True, if CANopen SYNC message was just received or - * transmitted. - * @param timeDifference_us Time difference from previous function call in - * microseconds. + * @param syncWas True, if CANopen SYNC message was just received or transmitted. + * @param timeDifference_us Time difference from previous function call in microseconds. * @param [out] timerNext_us info to OS - see CO_process(). */ void CO_process_TPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us); @@ -647,13 +566,11 @@ void CO_process_TPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint3 /** * Process CANopen SRDO objects. * - * Function must be called cyclically. For time critical applications it may be - * called from real time thread with constant interval (1ms typically). It - * processes SRDO CANopen objects. + * Function must be called cyclically. For time critical applications it may be called from real time thread with + * constant interval (1ms typically). It processes SRDO CANopen objects. * * @param co CANopen object. - * @param timeDifference_us Time difference from previous function call in - * microseconds. + * @param timeDifference_us Time difference from previous function call in microseconds. * @param [out] timerNext_us info to OS - see CO_process(). * * @return @CO_SRDO_state_t lowest state of the SRDO objects. diff --git a/MISRA.md b/MISRA.md index 38c9cb68..45af92f6 100644 --- a/MISRA.md +++ b/MISRA.md @@ -1,140 +1,140 @@ -# MISRA Compliance - -The CANopenNode files conform to the [MISRA C:2012](https://www.misra.org.uk) -guidelines, with some noted exceptions. Compliance is checked with [PC Lint Plus](https://pclintplus.com/). - -A recommendation for MISRA: memory allocation and deallocation functions should not be used. -You must define the macro CO_USE_GLOBALS in your driver configuration. - - -## Configuration Inhibits Control - -### Inhibits: Excluded the OD.c and OD.h files from the check because there are configuration parameters (not source code execution) -``` --efile( *, CANopenNode\OD.c ) --efile( *, CANopenNode\OD.h ) -``` - -### Inhibits: Excluded the CO_gateway_ascii and CO_fifo (currently static analysis not completed) -``` --efile( *, CANopenNode\309\CO_gateway_ascii.c ) --efile( *, CANopenNode\309\CO_gateway_ascii.h ) --efile( *, CANopenNode\301\CO_fifo.c ) --efile( *, CANopenNode\301\CO_fifo.h ) -``` - -### Inhibits: C comment contains '://' sequence -ref.: MISRA C 2012 Rule 3.1 -``` --efile( 9259, CANopenNode* ) -``` - -### Inhibits: unknown preprocessor directive 'string' in conditionally excluded region -ref.: MISRA C 2012 Rule 20.13 -``` --efile( 9160, CANopenNode* ) -``` - -### Inhibits: conversion from pointer to void to other pointer type (type) -ref.: MISRA C 2012 Rule 11.5 -``` --efile( 9079, CANopenNode* ) -``` - -### Inhibits: C comment contains C++ comment -ref.: MISRA C 2012 Rule 3.1 -``` --efile( 9059, CANopenNode* ) -``` - -### Inhibits: complete definition of symbol is unnecessary in this translation unit -ref.: MISRA C 2012 Dir 4.8 -``` --efile( 9045, CANopenNode* ) -``` - -### Inhibits: function parameter symbol modified -ref.: MISRA C 2012 Rule 17.8 -``` --efile( 9044, CANopenNode* ) -``` - -### Inhibits: cannot cast essential-type value to essential-type type -ref.: MISRA C 2012 Rule 10.5 -``` --efile( 9030, CANopenNode* ) -``` - -### Inhibits: function-like macro, 'macro', defined -ref.: MISRA C 2012 Dir 4.9 -``` --efile( 9026, CANopenNode* ) -``` - -### Inhibits: pasting/stringize operator used in definition of object-like/function-like macro 'string' -ref.: MISRA C 2012 Rule 20.10 -``` --efile( 9024, CANopenNode* ) -``` - -### Inhibits: performing pointer arithmetic via addition/subtraction -ref.: MISRA C 2012 Rule 18.4 -``` --efile( 9016, CANopenNode* ) -``` - -### Inhibits: local variable symbol could be pointer to const -ref.: MISRA C 2012 Rule 8.13 -``` --efile( 954, CANopenNode* ) -``` - -### Inhibits: return statement before end of function symbol -ref.: MISRA C 2012 Rule 15.5 -``` --efile( 904, CANopenNode* ) -``` - -### Inhibits: the left/right operand to operator always evaluates to 0 -ref.: MISRA C 2004 Rule 13.7 -``` --efile( 845, CANopenNode* ) -``` - -### Inhibits: previous value assigned to symbol not used -``` --efile( 838, CANopenNode* ) -``` - -### Inhibits: zero given as string argument to operator context -``` --efile( 835, CANopenNode* ) -``` - -### Inhibits: parameter symbol of function symbol could be pointer to const -ref.: MISRA C 2012 Rule 8.13 -``` --efile( 818, CANopenNode* ) -``` - -### Inhibits: constant expression evaluates to 0 in 'unary/binary' operation 'operator' -``` --efile( 778, CANopenNode* ) -``` - -### Inhibits: boolean condition for 'detail' always evaluates to 'detail' -ref.: MISRA C 2012 Rule 2.2 and Rule 14.3 -``` --efile( 774, CANopenNode* ) -``` - -### Inhibits: local macro 'string' not referenced -ref.: MISRA C 2012 Rule 2.5 -``` --efile( 750, CANopenNode* ) -``` - -### Inhibits: constant value used in Boolean context (string) -``` --efile( 506, CANopenNode* ) -``` +# MISRA Compliance + +The CANopenNode files conform to the [MISRA C:2012](https://www.misra.org.uk) +guidelines, with some noted exceptions. Compliance is checked with [PC Lint Plus](https://pclintplus.com/). + +A recommendation for MISRA: memory allocation and deallocation functions should not be used. +You must define the macro CO_USE_GLOBALS in your driver configuration. + + +## Configuration Inhibits Control + +### Inhibits: Excluded the OD.c and OD.h files from the check because there are configuration parameters (not source code execution) +``` +-efile( *, CANopenNode\OD.c ) +-efile( *, CANopenNode\OD.h ) +``` + +### Inhibits: Excluded the CO_gateway_ascii and CO_fifo (currently static analysis not completed) +``` +-efile( *, CANopenNode\309\CO_gateway_ascii.c ) +-efile( *, CANopenNode\309\CO_gateway_ascii.h ) +-efile( *, CANopenNode\301\CO_fifo.c ) +-efile( *, CANopenNode\301\CO_fifo.h ) +``` + +### Inhibits: C comment contains '://' sequence +ref.: MISRA C 2012 Rule 3.1 +``` +-efile( 9259, CANopenNode* ) +``` + +### Inhibits: unknown preprocessor directive 'string' in conditionally excluded region +ref.: MISRA C 2012 Rule 20.13 +``` +-efile( 9160, CANopenNode* ) +``` + +### Inhibits: conversion from pointer to void to other pointer type (type) +ref.: MISRA C 2012 Rule 11.5 +``` +-efile( 9079, CANopenNode* ) +``` + +### Inhibits: C comment contains C++ comment +ref.: MISRA C 2012 Rule 3.1 +``` +-efile( 9059, CANopenNode* ) +``` + +### Inhibits: complete definition of symbol is unnecessary in this translation unit +ref.: MISRA C 2012 Dir 4.8 +``` +-efile( 9045, CANopenNode* ) +``` + +### Inhibits: function parameter symbol modified +ref.: MISRA C 2012 Rule 17.8 +``` +-efile( 9044, CANopenNode* ) +``` + +### Inhibits: cannot cast essential-type value to essential-type type +ref.: MISRA C 2012 Rule 10.5 +``` +-efile( 9030, CANopenNode* ) +``` + +### Inhibits: function-like macro, 'macro', defined +ref.: MISRA C 2012 Dir 4.9 +``` +-efile( 9026, CANopenNode* ) +``` + +### Inhibits: pasting/stringize operator used in definition of object-like/function-like macro 'string' +ref.: MISRA C 2012 Rule 20.10 +``` +-efile( 9024, CANopenNode* ) +``` + +### Inhibits: performing pointer arithmetic via addition/subtraction +ref.: MISRA C 2012 Rule 18.4 +``` +-efile( 9016, CANopenNode* ) +``` + +### Inhibits: local variable symbol could be pointer to const +ref.: MISRA C 2012 Rule 8.13 +``` +-efile( 954, CANopenNode* ) +``` + +### Inhibits: return statement before end of function symbol +ref.: MISRA C 2012 Rule 15.5 +``` +-efile( 904, CANopenNode* ) +``` + +### Inhibits: the left/right operand to operator always evaluates to 0 +ref.: MISRA C 2004 Rule 13.7 +``` +-efile( 845, CANopenNode* ) +``` + +### Inhibits: previous value assigned to symbol not used +``` +-efile( 838, CANopenNode* ) +``` + +### Inhibits: zero given as string argument to operator context +``` +-efile( 835, CANopenNode* ) +``` + +### Inhibits: parameter symbol of function symbol could be pointer to const +ref.: MISRA C 2012 Rule 8.13 +``` +-efile( 818, CANopenNode* ) +``` + +### Inhibits: constant expression evaluates to 0 in 'unary/binary' operation 'operator' +``` +-efile( 778, CANopenNode* ) +``` + +### Inhibits: boolean condition for 'detail' always evaluates to 'detail' +ref.: MISRA C 2012 Rule 2.2 and Rule 14.3 +``` +-efile( 774, CANopenNode* ) +``` + +### Inhibits: local macro 'string' not referenced +ref.: MISRA C 2012 Rule 2.5 +``` +-efile( 750, CANopenNode* ) +``` + +### Inhibits: constant value used in Boolean context (string) +``` +-efile( 506, CANopenNode* ) +``` diff --git a/README.md b/README.md index 78f43d03..e118728e 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,9 @@ Report issues on https://github.com/CANopenNode/CANopenNode/issues Older discussion group is on Sourceforge: http://sourceforge.net/p/canopennode/discussion/387151/ -Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Please follow the [Recommended C style and coding rules](https://github.com/MaJerle/c-code-style), like indentation of 4 spaces, etc. There is also a `codingStyle` file with example. +Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Please follow the [Recommended C style and coding rules](https://github.com/MaJerle/c-code-style), use .clang-format file for automatic code formatting. +The CANopenNode files conform to the [MISRA C:2012](https://www.misra.org.uk) guidelines, with some noted exceptions, as indicated in [MISRA.md](MISRA.md). CANopenNode flowchart --------------------- @@ -168,9 +169,9 @@ File structure - **CANopenNode.png** - Little icon. - **html** - Directory with documentation - must be generated by Doxygen. - **CANopen.h/.c** - Initialization and processing of CANopen objects, suitable for common configurations. - - **codingStyle** - Example of the coding style. - **Doxyfile** - Configuration file for the documentation generator *doxygen*. - **LICENSE** - License. + - **MISRA.md** - MISRA C:2012 conformance information. - **README.md** - This file. diff --git a/codingStyle b/codingStyle deleted file mode 100644 index d6923a3e..00000000 --- a/codingStyle +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Description of the coding style for the source files. - * - * @file codingStyle - * @ingroup codingStyle - * @author name - * @copyright 2020 name - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef XYZ_H -#define XYZ_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup codingStyle Description of coding style - * @ingroup parentGroup - * @{ - * - * Contents of this file should be the base for .h source file, except function - * body at the end. - * - * ###Style - * - Style is based on https://github.com/MaJerle/c-code-style - * - Indent size is 4 spaces, no tabs. - * - Line width is 80 characters. - * - Some (old) code may not be formatted according to the rules. Try to avoid - * unnecessary changes based on individual taste. - * - * ###Doxygen - * Documentation is generated by doxygen. - * Doxygen comment starts with /**. /**< is used after member. - * Documentation is usually in header. - * Doxygen settings: - * - JAVADOC_AUTOBRIEF = YES. - * - See doxyfile for other settings. - * - * Doxygen specifics: If description of the structure member is one sentence - * only, don't use period after the sentence. - */ - -/** - * Brief description of the object ends at this dot. Details follow - * here. - */ -typedef struct { - int8_t member1; /**< Short description of the member 1 */ - uint16_t member2; /**< Note the '/**<' sequence after the member 2 */ - /** Long description of the variable stringMember. More description. */ - char_t stringMember[5]; -} object1_t; - -/** - * Function example 1. - * - * This is global function. Local functions (and variables) used inside one file - * are declared as static and not documented by Doxygen. - * - * @param thisObj Pointer to object. Function operates on this object (not on - * global variables). - * @param argument_2 Description of the argument. - * @param argument_2 Description of the argument. - * @param argument_4 Description of the argument. - * - * @return Some value. - */ -int32_t -foo1(object1_t* thisObj, int32_t argument_2, uint16_t argument_3, float32_t argument_4, bool_t argument_5, - int32_t argument_6) { - /* Comment */ - - /* Multiline - * comment. - */ - - /* All if and else statement must have use { } around their bodies - * (MISRA C 2004 rule 14.9) - */ - if (xy == yz) { /* Comment. '//' comments are not allowed */ - a = b; - } else if (xy < yz) { - a = c; - } else { - /* To stay compliant with MISRA C 2004 14.10 - * all else if statements need a final else even if empty - */ - } - - /* Assignment operators shall not be used in expressions which return - * boolean values (MISRA C 2004 rule 13.1) - * This is true for: 'if' and 'while' statements. - * For instance: - */ - if (xy = yz) {} - while (xy = yz) {} - - switch (zx) { - case 1: - a = b; - break default : - /* To stay compliant with MISRA C 2004 15.3 - * the default case must be present */ - break; - } -} - -/* MISRA C 2004 Rule E14.4.3 - * There should be no more than one break or goto statement used to terminate - * any iteration statement. - */ - -/* MISRA C 2004 Rule 14.5 - * The continue statement shall not be used. - */ - -/* More about MISRA C - * https://www.ibm.com/docs/en/devops-test-embedded/9.0.0?topic=review-code-misra-2004-rules - */ - -/** @} */ - -#ifdef __cplusplus -} -#endif /*__cplusplus */ - -#endif /* XYZ_H */ diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 99b3631d..fee8b0c0 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -5,6 +5,11 @@ v4.0 - current -------------- - [Source Code](https://github.com/CANopenNode/CANopenNode/tree/master) - [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/v2.0-master...master) +### Latest changes +- 2024-07-08: Code reforamtted according to .clang-format +- 2024-07-05: Static analysis for Misra C:2012 +- 2024-05-31: SRDO updated to current CANopenNode +- 2023-09-07: Node guarding added ### Removed - Driver for Linux (socketCAN directory) moved to own repository https://github.com/CANopenNode/CANopenLinux. ### Changed diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index d6656c6b..5e344637 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -45,7 +45,7 @@ void myFunc(OD_t *od) { /* Locking is necessary from mainline thread, but must not be used from * timer interval (real-time) thread. Locking is not necessary in the * CANoopen initialization section. Locking is also not necessary, if - * OD variable is not mappable to PDO and not accessed from RT thread.*/ + * OD variable is not mappable to PDO and not accessed from RT thread. */ CO_LOCK_OD(CANmodule); odRet = io1008.read(&io1008.stream, &buf[0], sizeof(buf), &bytesRd); CO_UNLOCK_OD(CANmodule); diff --git a/example/CO_driver_target.h b/example/CO_driver_target.h index 690f18c7..a4023579 100644 --- a/example/CO_driver_target.h +++ b/example/CO_driver_target.h @@ -20,9 +20,8 @@ #ifndef CO_DRIVER_TARGET_H #define CO_DRIVER_TARGET_H -/* This file contains device and application specific definitions. - * It is included from CO_driver.h, which contains documentation - * for common definitions below. */ +/* This file contains device and application specific definitions. It is included from CO_driver.h, which contains + * documentation for common definitions below. */ #include #include @@ -36,8 +35,7 @@ extern "C" { #endif -/* Stack configuration override default values. - * For more information see file CO_config.h. */ +/* Stack configuration override default values. For more information see file CO_config.h. */ /* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ #define CO_LITTLE_ENDIAN diff --git a/example/CO_storageBlank.c b/example/CO_storageBlank.c index e7795550..c56b0d00 100644 --- a/example/CO_storageBlank.c +++ b/example/CO_storageBlank.c @@ -1,91 +1,91 @@ -/* - * CANopen Object Dictionary storage object (blank example). - * - * @file CO_storageBlank.c - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ - -#include "CO_storageBlank.h" - -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - -/* - * Function for writing data on "Store parameters" command - OD object 1010 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t -storeBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { - - /* Open a file and write data to it */ - /* file = open(entry->pathToFileOrPointerToMemory); */ - CO_LOCK_OD(CANmodule); - /* write(entry->addr, entry->len, file); */ - CO_UNLOCK_OD(CANmodule); - - return ODR_OK; -} - -/* - * Function for restoring data on "Restore default parameters" command - OD 1011 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t -restoreBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { - - /* disable (delete) the file, so default values will stay after startup */ - - return ODR_OK; -} - -CO_ReturnError_t -CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, - OD_entry_t* OD_1011_RestoreDefaultParam, CO_storage_entry_t* entries, uint8_t entriesCount, - uint32_t* storageInitError) { - CO_ReturnError_t ret; - - /* verify arguments */ - if (storage == NULL || entries == NULL || entriesCount == 0 || storageInitError == NULL) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* initialize storage and OD extensions */ - ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeBlank, - restoreBlank, entries, entriesCount); - if (ret != CO_ERROR_NO) { - return ret; - } - - /* initialize entries */ - *storageInitError = 0; - for (uint8_t i = 0; i < entriesCount; i++) { - CO_storage_entry_t* entry = &entries[i]; - - /* verify arguments */ - if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { - *storageInitError = i; - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Open a file and read data from file to entry->addr */ - /* file = open(entry->pathToFileOrPointerToMemory); */ - /* read(entry->addr, entry->len, file); */ - } - - return ret; -} - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ +/* + * CANopen Object Dictionary storage object (blank example). + * + * @file CO_storageBlank.c + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#include "CO_storageBlank.h" + +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + +/* + * Function for writing data on "Store parameters" command - OD object 1010 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t +storeBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { + + /* Open a file and write data to it */ + /* file = open(entry->pathToFileOrPointerToMemory); */ + CO_LOCK_OD(CANmodule); + /* write(entry->addr, entry->len, file); */ + CO_UNLOCK_OD(CANmodule); + + return ODR_OK; +} + +/* + * Function for restoring data on "Restore default parameters" command - OD 1011 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t +restoreBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { + + /* disable (delete) the file, so default values will stay after startup */ + + return ODR_OK; +} + +CO_ReturnError_t +CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, + OD_entry_t* OD_1011_RestoreDefaultParam, CO_storage_entry_t* entries, uint8_t entriesCount, + uint32_t* storageInitError) { + CO_ReturnError_t ret; + + /* verify arguments */ + if (storage == NULL || entries == NULL || entriesCount == 0 || storageInitError == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* initialize storage and OD extensions */ + ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeBlank, + restoreBlank, entries, entriesCount); + if (ret != CO_ERROR_NO) { + return ret; + } + + /* initialize entries */ + *storageInitError = 0; + for (uint8_t i = 0; i < entriesCount; i++) { + CO_storage_entry_t* entry = &entries[i]; + + /* verify arguments */ + if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { + *storageInitError = i; + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* Open a file and read data from file to entry->addr */ + /* file = open(entry->pathToFileOrPointerToMemory); */ + /* read(entry->addr, entry->len, file); */ + } + + return ret; +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/example/CO_storageBlank.h b/example/CO_storageBlank.h index 811a4cca..48813ea9 100644 --- a/example/CO_storageBlank.h +++ b/example/CO_storageBlank.h @@ -1,53 +1,51 @@ -/* - * CANopen data storage object (blank example) - * - * @file CO_storageBlank.h - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ - -#ifndef CO_STORAGE_BLANK_H -#define CO_STORAGE_BLANK_H - -#include "storage/CO_storage.h" - -#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is very basic example of implementing (object dictionary) data storage. - * Data storage is target specific. CO_storageBlank.h and .c files only shows - * the basic principle, but does nothing. For complete example of storage see: - * - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c, - * CANopenNode/storage/CO_storageEeprom.h/.c, CANopenNode/storage/CO_eeprom.h - * and CANopenPIC/PIC32/CO_eepromPIC32.c files. - * - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and - * CANopenLinux/CO_storageLinux.h files. - */ - -CO_ReturnError_t CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, - OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, - CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); - -uint32_t CO_storageBlank_auto_process(CO_storage_t* storage, bool_t closeFiles); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ - -#endif /* CO_STORAGE_BLANK_H */ +/* + * CANopen data storage object (blank example) + * + * @file CO_storageBlank.h + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#ifndef CO_STORAGE_BLANK_H +#define CO_STORAGE_BLANK_H + +#include "storage/CO_storage.h" + +#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This is very basic example of implementing (object dictionary) data storage. Data storage is target specific. + * CO_storageBlank.h and .c files only shows the basic principle, but does nothing. For complete example of storage see: + * - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c, CANopenNode/storage/CO_storageEeprom.h/.c, + * CANopenNode/storage/CO_eeprom.h and CANopenPIC/PIC32/CO_eepromPIC32.c files. + * - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and CANopenLinux/CO_storageLinux.h files. + */ + +CO_ReturnError_t CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, + OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, + CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); + +uint32_t CO_storageBlank_auto_process(CO_storage_t* storage, bool_t closeFiles); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +#endif /* CO_STORAGE_BLANK_H */ diff --git a/extra/CO_trace.h b/extra/CO_trace.h index 370e85c1..ac3cc6f0 100644 --- a/extra/CO_trace.h +++ b/extra/CO_trace.h @@ -166,7 +166,7 @@ void CO_trace_process(CO_trace_t *trace, uint32_t timestamp); #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif /* __cplusplus */ #endif /* (CO_CONFIG_TRACE) & CO_CONFIG_TRACE_ENABLE */ diff --git a/storage/CO_eeprom.h b/storage/CO_eeprom.h index ce05df27..f28e4fd6 100644 --- a/storage/CO_eeprom.h +++ b/storage/CO_eeprom.h @@ -1,117 +1,113 @@ -/** - * Eeprom interface for use with CO_storageEeprom - * - * @file CO_eeprom.h - * @ingroup CO_storage_eeprom - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ - -#ifndef CO_EEPROM_H -#define CO_EEPROM_H - -#include "301/CO_driver.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @addtogroup CO_storage_eeprom - * @{ - */ - -/** - * Initialize eeprom device, target system specific function. - * - * @param storageModule Pointer to storage module. - * - * @return True on success - */ -bool_t CO_eeprom_init(void* storageModule); - -/** - * Get free address inside eeprom, target system specific function. - * - * Function is called several times for each storage block in the initialization - * phase after CO_eeprom_init(). - * - * @param storageModule Pointer to storage module. - * @param isAuto True, if variable is auto stored or false if protected - * @param len Length of data, which will be stored to that location - * @param [out] overflow set to true, if not enough eeprom memory - * - * @return Asigned eeprom address - */ -size_t CO_eeprom_getAddr(void* storageModule, bool_t isAuto, size_t len, bool_t* overflow); - -/** - * Read block of data from the eeprom, target system specific function. - * - * @param storageModule Pointer to storage module. - * @param data Pointer to data buffer, where data will be stored. - * @param eepromAddr Address in eeprom, from where data will be read. - * @param len Length of the data block to be read. - */ -void CO_eeprom_readBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len); - -/** - * Write block of data to the eeprom, target system specific function. - * - * It is blocking function, so it waits, until all data is written. - * - * @param storageModule Pointer to storage module. - * @param data Pointer to data buffer which will be written. - * @param eepromAddr Address in eeprom, where data will be written. If data is - * stored accross multiple pages, address must be aligned with page. - * @param len Length of the data block. - * - * @return true on success - */ -bool_t CO_eeprom_writeBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len); - -/** - * Get CRC checksum of the block of data stored in the eeprom, target system - * specific function. - * - * @param storageModule Pointer to storage module. - * @param eepromAddr Address of data in eeprom. - * @param len Length of the data. - * - * @return CRC checksum - */ -uint16_t CO_eeprom_getCrcBlock(void* storageModule, size_t eepromAddr, size_t len); - -/** - * Update one byte of data in the eeprom, target system specific function. - * - * Function is used by automatic storage. It updates byte in eeprom only if - * differs from data. - * - * @param storageModule Pointer to storage module. - * @param data Data byte to be written - * @param eepromAddr Address in eeprom, from where data will be updated. - * - * @return true if write was successful or false, if still waiting previous - * data to finish writing. - */ -bool_t CO_eeprom_updateByte(void* storageModule, uint8_t data, size_t eepromAddr); - -/** @} */ /* CO_storage_eeprom */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CO_EEPROM_H */ +/** + * Eeprom interface for use with CO_storageEeprom + * + * @file CO_eeprom.h + * @ingroup CO_storage_eeprom + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#ifndef CO_EEPROM_H +#define CO_EEPROM_H + +#include "301/CO_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup CO_storage_eeprom + * @{ + */ + +/** + * Initialize eeprom device, target system specific function. + * + * @param storageModule Pointer to storage module. + * + * @return True on success + */ +bool_t CO_eeprom_init(void* storageModule); + +/** + * Get free address inside eeprom, target system specific function. + * + * Function is called several times for each storage block in the initialization phase after CO_eeprom_init(). + * + * @param storageModule Pointer to storage module. + * @param isAuto True, if variable is auto stored or false if protected + * @param len Length of data, which will be stored to that location + * @param [out] overflow set to true, if not enough eeprom memory + * + * @return Asigned eeprom address + */ +size_t CO_eeprom_getAddr(void* storageModule, bool_t isAuto, size_t len, bool_t* overflow); + +/** + * Read block of data from the eeprom, target system specific function. + * + * @param storageModule Pointer to storage module. + * @param data Pointer to data buffer, where data will be stored. + * @param eepromAddr Address in eeprom, from where data will be read. + * @param len Length of the data block to be read. + */ +void CO_eeprom_readBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len); + +/** + * Write block of data to the eeprom, target system specific function. + * + * It is blocking function, so it waits, until all data is written. + * + * @param storageModule Pointer to storage module. + * @param data Pointer to data buffer which will be written. + * @param eepromAddr Address in eeprom, where data will be written. If data is stored across multiple pages, address + * must be aligned with page. + * @param len Length of the data block. + * + * @return true on success + */ +bool_t CO_eeprom_writeBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len); + +/** + * Get CRC checksum of the block of data stored in the eeprom, target system specific function. + * + * @param storageModule Pointer to storage module. + * @param eepromAddr Address of data in eeprom. + * @param len Length of the data. + * + * @return CRC checksum + */ +uint16_t CO_eeprom_getCrcBlock(void* storageModule, size_t eepromAddr, size_t len); + +/** + * Update one byte of data in the eeprom, target system specific function. + * + * Function is used by automatic storage. It updates byte in eeprom only if differs from data. + * + * @param storageModule Pointer to storage module. + * @param data Data byte to be written + * @param eepromAddr Address in eeprom, from where data will be updated. + * + * @return true if write was successful or false, if still waiting previous data to finish writing. + */ +bool_t CO_eeprom_updateByte(void* storageModule, uint8_t data, size_t eepromAddr); + +/** @} */ /* CO_storage_eeprom */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CO_EEPROM_H */ diff --git a/storage/CO_storage.c b/storage/CO_storage.c index 089738ee..4a1ffff1 100644 --- a/storage/CO_storage.c +++ b/storage/CO_storage.c @@ -1,165 +1,165 @@ -/* - * CANopen data storage base object - * - * @file CO_storage.c - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ - -#include "storage/CO_storage.h" - -#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0 - -/* - * Custom function for writing OD object "Store parameters" - * - * For more information see file CO_ODinterface.h, OD_IO_t. - */ -static ODR_t -OD_write_1010(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { - /* verify arguments */ - if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL)) { - return ODR_DEV_INCOMPAT; - } - - CO_storage_t* storage = stream->object; - - if ((stream->subIndex == 0U) || (storage->store == NULL) || !storage->enabled) { - return ODR_READONLY; - } - - uint32_t val = CO_getUint32(buf); - if (val != 0x65766173U) { - return ODR_DATA_TRANSF; - } - - /* loop through entries and store relevant */ - uint8_t found = 0; - ODR_t returnCode = ODR_OK; - - for (uint8_t i = 0; i < storage->entriesCount; i++) { - CO_storage_entry_t* entry = &storage->entries[i]; - - if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { - if (found == 0U) { - found = 1; - } - if ((entry->attr & (uint8_t)CO_storage_cmd) != 0U) { - ODR_t code = storage->store(entry, storage->CANmodule); - if (code != ODR_OK) { - returnCode = code; - } - found = 2; - } - } - } - - if (found != 2U) { - returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY; - } - - if (returnCode == ODR_OK) { - *countWritten = sizeof(uint32_t); - } - return returnCode; -} - -/* - * Custom function for writing OD object "Restore default parameters" - * - * For more information see file CO_ODinterface.h, OD_IO_t. - */ -static ODR_t -OD_write_1011(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { - /* verify arguments */ - if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL)) { - return ODR_DEV_INCOMPAT; - } - - CO_storage_t* storage = stream->object; - - if ((stream->subIndex == 0U) || (storage->restore == NULL) || !storage->enabled) { - return ODR_READONLY; - } - - uint32_t val = CO_getUint32(buf); - if (val != 0x64616F6CU) { - return ODR_DATA_TRANSF; - } - - /* loop through entries and store relevant */ - uint8_t found = 0; - ODR_t returnCode = ODR_OK; - - for (uint8_t i = 0; i < storage->entriesCount; i++) { - CO_storage_entry_t* entry = &storage->entries[i]; - - if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { - if (found == 0U) { - found = 1; - } - if ((entry->attr & (uint8_t)CO_storage_restore) != 0U) { - ODR_t code = storage->restore(entry, storage->CANmodule); - if (code != ODR_OK) { - returnCode = code; - } - found = 2; - } - } - } - - if (found != 2U) { - returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY; - } - - if (returnCode == ODR_OK) { - *countWritten = sizeof(uint32_t); - } - return returnCode; -} - -CO_ReturnError_t -CO_storage_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, - OD_entry_t* OD_1011_RestoreDefaultParameters, - ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), - ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), CO_storage_entry_t* entries, - uint8_t entriesCount) { - /* verify arguments */ - if ((storage == NULL) || (CANmodule == NULL) || (OD_1010_StoreParameters == NULL) - || (OD_1011_RestoreDefaultParameters == NULL) || (store == NULL) || (restore == NULL) || (entries == NULL)) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - storage->CANmodule = CANmodule; - storage->store = store; - storage->restore = restore; - storage->entries = entries; - storage->entriesCount = entriesCount; - - /* configure extensions */ - storage->OD_1010_extension.object = storage; - storage->OD_1010_extension.read = OD_readOriginal; - storage->OD_1010_extension.write = OD_write_1010; - (void)OD_extension_init(OD_1010_StoreParameters, &storage->OD_1010_extension); - - storage->OD_1011_extension.object = storage; - storage->OD_1011_extension.read = OD_readOriginal; - storage->OD_1011_extension.write = OD_write_1011; - (void)OD_extension_init(OD_1011_RestoreDefaultParameters, &storage->OD_1011_extension); - - return CO_ERROR_NO; -} - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ +/* + * CANopen data storage base object + * + * @file CO_storage.c + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#include "storage/CO_storage.h" + +#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0 + +/* + * Custom function for writing OD object "Store parameters" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static ODR_t +OD_write_1010(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + /* verify arguments */ + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL)) { + return ODR_DEV_INCOMPAT; + } + + CO_storage_t* storage = stream->object; + + if ((stream->subIndex == 0U) || (storage->store == NULL) || !storage->enabled) { + return ODR_READONLY; + } + + uint32_t val = CO_getUint32(buf); + if (val != 0x65766173U) { + return ODR_DATA_TRANSF; + } + + /* loop through entries and store relevant */ + uint8_t found = 0; + ODR_t returnCode = ODR_OK; + + for (uint8_t i = 0; i < storage->entriesCount; i++) { + CO_storage_entry_t* entry = &storage->entries[i]; + + if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { + if (found == 0U) { + found = 1; + } + if ((entry->attr & (uint8_t)CO_storage_cmd) != 0U) { + ODR_t code = storage->store(entry, storage->CANmodule); + if (code != ODR_OK) { + returnCode = code; + } + found = 2; + } + } + } + + if (found != 2U) { + returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY; + } + + if (returnCode == ODR_OK) { + *countWritten = sizeof(uint32_t); + } + return returnCode; +} + +/* + * Custom function for writing OD object "Restore default parameters" + * + * For more information see file CO_ODinterface.h, OD_IO_t. + */ +static ODR_t +OD_write_1011(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + /* verify arguments */ + if ((stream == NULL) || (stream->subIndex == 0U) || (buf == NULL) || (count != 4U) || (countWritten == NULL)) { + return ODR_DEV_INCOMPAT; + } + + CO_storage_t* storage = stream->object; + + if ((stream->subIndex == 0U) || (storage->restore == NULL) || !storage->enabled) { + return ODR_READONLY; + } + + uint32_t val = CO_getUint32(buf); + if (val != 0x64616F6CU) { + return ODR_DATA_TRANSF; + } + + /* loop through entries and store relevant */ + uint8_t found = 0; + ODR_t returnCode = ODR_OK; + + for (uint8_t i = 0; i < storage->entriesCount; i++) { + CO_storage_entry_t* entry = &storage->entries[i]; + + if ((stream->subIndex == 1U) || (entry->subIndexOD == stream->subIndex)) { + if (found == 0U) { + found = 1; + } + if ((entry->attr & (uint8_t)CO_storage_restore) != 0U) { + ODR_t code = storage->restore(entry, storage->CANmodule); + if (code != ODR_OK) { + returnCode = code; + } + found = 2; + } + } + } + + if (found != 2U) { + returnCode = (found == 0U) ? ODR_SUB_NOT_EXIST : ODR_READONLY; + } + + if (returnCode == ODR_OK) { + *countWritten = sizeof(uint32_t); + } + return returnCode; +} + +CO_ReturnError_t +CO_storage_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, + OD_entry_t* OD_1011_RestoreDefaultParameters, + ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), + ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), CO_storage_entry_t* entries, + uint8_t entriesCount) { + /* verify arguments */ + if ((storage == NULL) || (CANmodule == NULL) || (OD_1010_StoreParameters == NULL) + || (OD_1011_RestoreDefaultParameters == NULL) || (store == NULL) || (restore == NULL) || (entries == NULL)) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* Configure object variables */ + storage->CANmodule = CANmodule; + storage->store = store; + storage->restore = restore; + storage->entries = entries; + storage->entriesCount = entriesCount; + + /* configure extensions */ + storage->OD_1010_extension.object = storage; + storage->OD_1010_extension.read = OD_readOriginal; + storage->OD_1010_extension.write = OD_write_1010; + (void)OD_extension_init(OD_1010_StoreParameters, &storage->OD_1010_extension); + + storage->OD_1011_extension.object = storage; + storage->OD_1011_extension.read = OD_readOriginal; + storage->OD_1011_extension.write = OD_write_1011; + (void)OD_extension_init(OD_1011_RestoreDefaultParameters, &storage->OD_1011_extension); + + return CO_ERROR_NO; +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/storage/CO_storage.h b/storage/CO_storage.h index 7329ebd1..28c7f687 100644 --- a/storage/CO_storage.h +++ b/storage/CO_storage.h @@ -1,154 +1,142 @@ -/** - * CANopen data storage base object - * - * @file CO_storage.h - * @ingroup CO_storage - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ - -#ifndef CO_STORAGE_H -#define CO_STORAGE_H - -#include "301/CO_driver.h" -#include "301/CO_ODinterface.h" - -/* default configuration, see CO_config.h */ -#ifndef CO_CONFIG_STORAGE -#define CO_CONFIG_STORAGE (CO_CONFIG_STORAGE_ENABLE) -#endif - -#if (((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_storage Data storage base - * Base module for Data storage. - * - * @ingroup CO_CANopen_storage - * @{ - * - * CANopen provides OD objects 0x1010 and 0x1011 for control of storing and - * restoring data. Data source is usually a group of variables inside object - * dictionary, but it is not limited to OD. - * - * When object dictionary is generated (OD.h and OD.c files), OD variables are - * grouped into structures according to 'Storage group' parameter. - * - * Autonomous data storing must be implemented target specific, if in use. - * - * ### OD object 0x1010 - Store parameters: - * - Sub index 0: Highest sub-index supported - * - Sub index 1: Save all parameters, UNSIGNED32 - * - Sub index 2: Save communication parameters, UNSIGNED32 - * - Sub index 3: Save application parameters, UNSIGNED32 - * - Sub index 4 - 127: Manufacturer specific, UNSIGNED32 - * - * Sub-indexes 1 and above: - * - Reading provides information about its storage functionality: - * - bit 0: If set, CANopen device saves parameters on command - * - bit 1: If set, CANopen device saves parameters autonomously - * - Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores - * corresponding data. - * - * ### OD object 0x1011 - Restore default parameters - * - Sub index 0: Highest sub-index supported - * - Sub index 1: Restore all default parameters, UNSIGNED32 - * - Sub index 2: Restore communication default parameters, UNSIGNED32 - * - Sub index 3: Restore application default parameters, UNSIGNED32 - * - Sub index 4 - 127: Manufacturer specific, UNSIGNED32 - * - * Sub-indexes 1 and above: - * - Reading provides information about its restoring capability: - * - bit 0: If set, CANopen device restores parameters - * - Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) restores - * corresponding data. - */ - -/** - * Attributes (bit masks) for Data storage object. - */ -typedef enum { - /** CANopen device saves parameters on OD 1010 command */ - CO_storage_cmd = 0x01, - /** CANopen device saves parameters autonomously */ - CO_storage_auto = 0x02, - /** CANopen device restores parameters on OD 1011 command */ - CO_storage_restore = 0x04 -} CO_storage_attributes_t; - -/** - * Data storage object. - * - * Object is used with CANopen OD objects at index 1010 and 1011. - */ -typedef struct { - OD_extension_t OD_1010_extension; /**< Extension for OD object */ - OD_extension_t OD_1011_extension; /**< Extension for OD object */ - CO_CANmodule_t* CANmodule; /**< From CO_storage_init() */ - ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule); /**< From CO_storage_init() */ - ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule); /**< From CO_storage_init() */ - CO_storage_entry_t* entries; /**< From CO_storage_init() */ - uint8_t entriesCount; /**< From CO_storage_init() */ - bool_t enabled; /**< true, if storage is enabled. Setting of this variable - is implementation specific. */ -} CO_storage_t; - -/** - * Initialize data storage object - * - * This function should be called by application after the program startup, - * before @ref CO_CANopenInit(). This function initializes storage object and - * OD extensions on objects 1010 and 1011. Function does not load stored data - * on startup, because loading data is target specific. - * - * @param storage This object will be initialized. It must be defined by - * application and must exist permanently. - * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. - * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". - * Entry is optional, may be NULL. - * @param OD_1011_RestoreDefaultParameters OD entry for 0x1011 -"Restore default - * parameters". Entry is optional, may be NULL. - * @param store Pointer to externally defined function, which will store data - * specified by @ref CO_storage_entry_t. Function will be called when - * OD variable 0x1010 will be written. Argument to function is entry, where - * 'entry->subIndexOD' equals accessed subIndex. Function returns value from - * @ref ODR_t : "ODR_OK" in case of success, "ODR_HW" in case of hardware error. - * @param restore Same as 'store', but for restoring default data. - * @param entries Pointer to array of storage entries. Array must be defined and - * initialized by application and must exist permanently. - * Structure @ref CO_storage_entry_t is target specific and must be defined by - * CO_driver_target.h. See CO_driver.h for required parameters. - * @param entriesCount Count of storage entries - * - * @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. - */ -CO_ReturnError_t CO_storage_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, - OD_entry_t* OD_1011_RestoreDefaultParameters, - ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), - ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), - CO_storage_entry_t* entries, uint8_t entriesCount); - -/** @} */ /* CO_storage */ - -#ifdef __cplusplus -} -#endif /*__cplusplus*/ - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ - -#endif /* CO_STORAGE_H */ +/** + * CANopen data storage base object + * + * @file CO_storage.h + * @ingroup CO_storage + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#ifndef CO_STORAGE_H +#define CO_STORAGE_H + +#include "301/CO_driver.h" +#include "301/CO_ODinterface.h" + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_STORAGE +#define CO_CONFIG_STORAGE (CO_CONFIG_STORAGE_ENABLE) +#endif + +#if (((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_storage Data storage base + * Base module for Data storage. + * + * @ingroup CO_CANopen_storage + * @{ + * + * CANopen provides OD objects 0x1010 and 0x1011 for control of storing and restoring data. Data source is usually a + * group of variables inside object dictionary, but it is not limited to OD. + * + * When object dictionary is generated (OD.h and OD.c files), OD variables are grouped into structures according to + * 'Storage group' parameter. + * + * Autonomous data storing must be implemented target specific, if in use. + * + * ### OD object 0x1010 - Store parameters: + * - Sub index 0: Highest sub-index supported + * - Sub index 1: Save all parameters, UNSIGNED32 + * - Sub index 2: Save communication parameters, UNSIGNED32 + * - Sub index 3: Save application parameters, UNSIGNED32 + * - Sub index 4 - 127: Manufacturer specific, UNSIGNED32 + * + * Sub-indexes 1 and above: + * - Reading provides information about its storage functionality: + * - bit 0: If set, CANopen device saves parameters on command + * - bit 1: If set, CANopen device saves parameters autonomously + * - Writing value 0x65766173 ('s','a','v','e' from LSB to MSB) stores corresponding data. + * + * ### OD object 0x1011 - Restore default parameters + * - Sub index 0: Highest sub-index supported + * - Sub index 1: Restore all default parameters, UNSIGNED32 + * - Sub index 2: Restore communication default parameters, UNSIGNED32 + * - Sub index 3: Restore application default parameters, UNSIGNED32 + * - Sub index 4 - 127: Manufacturer specific, UNSIGNED32 + * + * Sub-indexes 1 and above: + * - Reading provides information about its restoring capability: + * - bit 0: If set, CANopen device restores parameters + * - Writing value 0x64616F6C ('l','o','a','d' from LSB to MSB) restores corresponding data. + */ + +/** + * Attributes (bit masks) for Data storage object. + */ +typedef enum { + CO_storage_cmd = 0x01, /**< CANopen device saves parameters on OD 1010 command */ + CO_storage_auto = 0x02, /**< CANopen device saves parameters autonomously */ + CO_storage_restore = 0x04 /**< CANopen device restores parameters on OD 1011 command */ +} CO_storage_attributes_t; + +/** + * Data storage object. + * + * Object is used with CANopen OD objects at index 1010 and 1011. + */ +typedef struct { + OD_extension_t OD_1010_extension; /**< Extension for OD object */ + OD_extension_t OD_1011_extension; /**< Extension for OD object */ + CO_CANmodule_t* CANmodule; /**< From CO_storage_init() */ + ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule); /**< From CO_storage_init() */ + ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule); /**< From CO_storage_init() */ + CO_storage_entry_t* entries; /**< From CO_storage_init() */ + uint8_t entriesCount; /**< From CO_storage_init() */ + bool_t enabled; /**< true, if storage is enabled. Setting of this variable is implementation specific. */ +} CO_storage_t; + +/** + * Initialize data storage object + * + * This function should be called by application after the program startup, before @ref CO_CANopenInit(). This function + * initializes storage object and OD extensions on objects 1010 and 1011. Function does not load stored data on startup, + * because loading data is target specific. + * + * @param storage This object will be initialized. It must be defined by application and must exist permanently. + * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. + * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". Entry is optional, may be NULL. + * @param OD_1011_RestoreDefaultParameters OD entry for 0x1011 -"Restore default parameters". Entry is optional, may be + * NULL. + * @param store Pointer to externally defined function, which will store data specified by @ref CO_storage_entry_t. + * Function will be called when OD variable 0x1010 will be written. Argument to function is entry, where + * 'entry->subIndexOD' equals accessed subIndex. Function returns value from + * @ref ODR_t : "ODR_OK" in case of success, "ODR_HW" in case of hardware error. + * @param restore Same as 'store', but for restoring default data. + * @param entries Pointer to array of storage entries. Array must be defined and initialized by application and must + * exist permanently. Structure @ref CO_storage_entry_t is target specific and must be defined by CO_driver_target.h. + * See CO_driver.h for required parameters. + * @param entriesCount Count of storage entries + * + * @return CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. + */ +CO_ReturnError_t CO_storage_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, + OD_entry_t* OD_1011_RestoreDefaultParameters, + ODR_t (*store)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), + ODR_t (*restore)(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule), + CO_storage_entry_t* entries, uint8_t entriesCount); + +/** @} */ /* CO_storage */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +#endif /* CO_STORAGE_H */ diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 397594ad..045d6281 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -1,222 +1,222 @@ -/* - * CANopen data storage object for storing data into block device (eeprom) - * - * @file CO_storageEeprom.c - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ - -#include "storage/CO_storageEeprom.h" -#include "storage/CO_eeprom.h" -#include "301/crc16-ccitt.h" - -#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0 - -/* - * Function for writing data on "Store parameters" command - OD object 1010 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t -storeEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { - (void)CANmodule; - bool_t writeOk; - - /* save data to the eeprom */ - writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len); - entry->crc = crc16_ccitt(entry->addr, entry->len, 0); - - /* Verify, if data in eeprom are equal */ - uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, entry->eepromAddr, entry->len); - if ((entry->crc != crc_read) || !writeOk) { - return ODR_HW; - } - - /* Write signature (see CO_storageEeprom_init() for info) */ - uint16_t signatureOfEntry = (uint16_t)entry->len; - uint32_t signature = (((uint32_t)entry->crc) << 16) | signatureOfEntry; - writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t*)&signature, entry->eepromAddrSignature, - sizeof(signature)); - - /* verify signature and write */ - uint32_t signatureRead; - CO_eeprom_readBlock(entry->storageModule, (uint8_t*)&signatureRead, entry->eepromAddrSignature, - sizeof(signatureRead)); - if ((signature != signatureRead) || !writeOk) { - return ODR_HW; - } - - return ODR_OK; -} - -/* - * Function for restoring data on "Restore default parameters" command - OD 1011 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t -restoreEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { - (void)CANmodule; - bool_t writeOk; - - /* Write empty signature */ - uint32_t signature = 0xFFFFFFFFU; - writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t*)&signature, entry->eepromAddrSignature, - sizeof(signature)); - - /* verify signature and protection */ - uint32_t signatureRead; - CO_eeprom_readBlock(entry->storageModule, (uint8_t*)&signatureRead, entry->eepromAddrSignature, - sizeof(signatureRead)); - if ((signature != signatureRead) || !writeOk) { - return ODR_HW; - } - - return ODR_OK; -} - -CO_ReturnError_t -CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* storageModule, - OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, - CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError) { - CO_ReturnError_t ret; - bool_t eepromOvf = false; - - /* verify arguments */ - if ((storage == NULL) || (entries == NULL) || (entriesCount == 0U) - || (entriesCount > CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT) || (storageInitError == NULL)) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - storage->enabled = false; - - /* Initialize storage hardware */ - if (!CO_eeprom_init(storageModule)) { - *storageInitError = 0xFFFFFFFFU; - return CO_ERROR_DATA_CORRUPT; - } - - /* initialize storage and OD extensions */ - ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeEeprom, - restoreEeprom, entries, entriesCount); - if (ret != CO_ERROR_NO) { - return ret; - } - - /* Read entry signatures from the eeprom */ - uint32_t signatures[CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT]; - size_t signaturesAddress = CO_eeprom_getAddr(storageModule, false, sizeof(signatures), &eepromOvf); - CO_eeprom_readBlock(storageModule, (uint8_t*)signatures, signaturesAddress, sizeof(signatures)); - - /* initialize entries */ - *storageInitError = 0; - for (uint8_t i = 0; i < entriesCount; i++) { - CO_storage_entry_t* entry = &entries[i]; - bool_t isAuto = (entry->attr & (uint8_t)CO_storage_auto) != 0U; - - /* verify arguments */ - if ((entry->addr == NULL) || (entry->len == 0U) || (entry->subIndexOD < 2U)) { - *storageInitError = i; - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* calculate addresses inside eeprom */ - entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); - entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); - entry->offset = 0; - - /* verify if eeprom is too small */ - if (eepromOvf) { - *storageInitError = i; - return CO_ERROR_OUT_OF_MEMORY; - } - - /* 32bit signature (which was stored in eeprom) is combined from - * 16bit signature of the entry and 16bit CRC checksum of the data - * block. 16bit signature of the entry is entry->len. */ - uint32_t signature = signatures[i]; - uint16_t signatureInEeprom = (uint16_t)signature; - entry->crc = (uint16_t)(signature >> 16); - uint16_t signatureOfEntry = (uint16_t)entry->len; - - /* Verify two signatures */ - bool_t dataCorrupt = false; - if (signatureInEeprom != signatureOfEntry) { - dataCorrupt = true; - } else { - /* Read data into storage location */ - CO_eeprom_readBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len); - - /* Verify CRC, except for auto storage variables */ - if (!isAuto) { - uint16_t crc = crc16_ccitt(entry->addr, entry->len, 0); - if (crc != entry->crc) { - dataCorrupt = true; - } - } - } - - /* additional info in case of error */ - if (dataCorrupt) { - uint32_t errorBit = entry->subIndexOD; - if (errorBit > 31U) { - errorBit = 31; - } - *storageInitError |= ((uint32_t)1) << errorBit; - ret = CO_ERROR_DATA_CORRUPT; - } - } /* for (entries) */ - - storage->enabled = true; - return ret; -} - -void -CO_storageEeprom_auto_process(CO_storage_t* storage, bool_t saveAll) { - /* verify arguments */ - if ((storage == NULL) || !storage->enabled) { - return; - } - - /* loop through entries */ - for (uint8_t n = 0; n < storage->entriesCount; n++) { - CO_storage_entry_t* entry = &storage->entries[n]; - - if ((entry->attr & (uint8_t)CO_storage_auto) == 0U) { - continue; - } - - if (saveAll) { - /* update all bytes */ - for (size_t i = 0; i < entry->len;) { - uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[i]; - size_t eepromAddr = entry->eepromAddr + i; - if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, eepromAddr)) { - i++; - } - } - } else { - /* update one data byte and if successful increment to next */ - uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[entry->offset]; - size_t eepromAddr = entry->eepromAddr + entry->offset; - if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, eepromAddr)) { - if (++entry->offset >= entry->len) { - entry->offset = 0; - } - } - } - } -} - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ +/* + * CANopen data storage object for storing data into block device (eeprom) + * + * @file CO_storageEeprom.c + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#include "storage/CO_storageEeprom.h" +#include "storage/CO_eeprom.h" +#include "301/crc16-ccitt.h" + +#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0 + +/* + * Function for writing data on "Store parameters" command - OD object 1010 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t +storeEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { + (void)CANmodule; + bool_t writeOk; + + /* save data to the eeprom */ + writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len); + entry->crc = crc16_ccitt(entry->addr, entry->len, 0); + + /* Verify, if data in eeprom are equal */ + uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, entry->eepromAddr, entry->len); + if ((entry->crc != crc_read) || !writeOk) { + return ODR_HW; + } + + /* Write signature (see CO_storageEeprom_init() for info) */ + uint16_t signatureOfEntry = (uint16_t)entry->len; + uint32_t signature = (((uint32_t)entry->crc) << 16) | signatureOfEntry; + writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t*)&signature, entry->eepromAddrSignature, + sizeof(signature)); + + /* verify signature and write */ + uint32_t signatureRead; + CO_eeprom_readBlock(entry->storageModule, (uint8_t*)&signatureRead, entry->eepromAddrSignature, + sizeof(signatureRead)); + if ((signature != signatureRead) || !writeOk) { + return ODR_HW; + } + + return ODR_OK; +} + +/* + * Function for restoring data on "Restore default parameters" command - OD 1011 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t +restoreEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { + (void)CANmodule; + bool_t writeOk; + + /* Write empty signature */ + uint32_t signature = 0xFFFFFFFFU; + writeOk = CO_eeprom_writeBlock(entry->storageModule, (uint8_t*)&signature, entry->eepromAddrSignature, + sizeof(signature)); + + /* verify signature and protection */ + uint32_t signatureRead; + CO_eeprom_readBlock(entry->storageModule, (uint8_t*)&signatureRead, entry->eepromAddrSignature, + sizeof(signatureRead)); + if ((signature != signatureRead) || !writeOk) { + return ODR_HW; + } + + return ODR_OK; +} + +CO_ReturnError_t +CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* storageModule, + OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, + CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError) { + CO_ReturnError_t ret; + bool_t eepromOvf = false; + + /* verify arguments */ + if ((storage == NULL) || (entries == NULL) || (entriesCount == 0U) + || (entriesCount > CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT) || (storageInitError == NULL)) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + storage->enabled = false; + + /* Initialize storage hardware */ + if (!CO_eeprom_init(storageModule)) { + *storageInitError = 0xFFFFFFFFU; + return CO_ERROR_DATA_CORRUPT; + } + + /* initialize storage and OD extensions */ + ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeEeprom, + restoreEeprom, entries, entriesCount); + if (ret != CO_ERROR_NO) { + return ret; + } + + /* Read entry signatures from the eeprom */ + uint32_t signatures[CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT]; + size_t signaturesAddress = CO_eeprom_getAddr(storageModule, false, sizeof(signatures), &eepromOvf); + CO_eeprom_readBlock(storageModule, (uint8_t*)signatures, signaturesAddress, sizeof(signatures)); + + /* initialize entries */ + *storageInitError = 0; + for (uint8_t i = 0; i < entriesCount; i++) { + CO_storage_entry_t* entry = &entries[i]; + bool_t isAuto = (entry->attr & (uint8_t)CO_storage_auto) != 0U; + + /* verify arguments */ + if ((entry->addr == NULL) || (entry->len == 0U) || (entry->subIndexOD < 2U)) { + *storageInitError = i; + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* calculate addresses inside eeprom */ + entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); + entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); + entry->offset = 0; + + /* verify if eeprom is too small */ + if (eepromOvf) { + *storageInitError = i; + return CO_ERROR_OUT_OF_MEMORY; + } + + /* 32bit signature (which was stored in eeprom) is combined from + * 16bit signature of the entry and 16bit CRC checksum of the data + * block. 16bit signature of the entry is entry->len. */ + uint32_t signature = signatures[i]; + uint16_t signatureInEeprom = (uint16_t)signature; + entry->crc = (uint16_t)(signature >> 16); + uint16_t signatureOfEntry = (uint16_t)entry->len; + + /* Verify two signatures */ + bool_t dataCorrupt = false; + if (signatureInEeprom != signatureOfEntry) { + dataCorrupt = true; + } else { + /* Read data into storage location */ + CO_eeprom_readBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len); + + /* Verify CRC, except for auto storage variables */ + if (!isAuto) { + uint16_t crc = crc16_ccitt(entry->addr, entry->len, 0); + if (crc != entry->crc) { + dataCorrupt = true; + } + } + } + + /* additional info in case of error */ + if (dataCorrupt) { + uint32_t errorBit = entry->subIndexOD; + if (errorBit > 31U) { + errorBit = 31; + } + *storageInitError |= ((uint32_t)1) << errorBit; + ret = CO_ERROR_DATA_CORRUPT; + } + } /* for (entries) */ + + storage->enabled = true; + return ret; +} + +void +CO_storageEeprom_auto_process(CO_storage_t* storage, bool_t saveAll) { + /* verify arguments */ + if ((storage == NULL) || !storage->enabled) { + return; + } + + /* loop through entries */ + for (uint8_t n = 0; n < storage->entriesCount; n++) { + CO_storage_entry_t* entry = &storage->entries[n]; + + if ((entry->attr & (uint8_t)CO_storage_auto) == 0U) { + continue; + } + + if (saveAll) { + /* update all bytes */ + for (size_t i = 0; i < entry->len;) { + uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[i]; + size_t eepromAddr = entry->eepromAddr + i; + if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, eepromAddr)) { + i++; + } + } + } else { + /* update one data byte and if successful increment to next */ + uint8_t dataByteToUpdate = ((uint8_t*)(entry->addr))[entry->offset]; + size_t eepromAddr = entry->eepromAddr + entry->offset; + if (CO_eeprom_updateByte(entry->storageModule, dataByteToUpdate, eepromAddr)) { + if (++entry->offset >= entry->len) { + entry->offset = 0; + } + } + } + } +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h index 52ec4777..96c41d9a 100644 --- a/storage/CO_storageEeprom.h +++ b/storage/CO_storageEeprom.h @@ -1,126 +1,109 @@ -/** - * CANopen data storage object for storing data into block device (eeprom) - * - * @file CO_storageEeprom.h - * @ingroup CO_storage_eeprom - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ - -#ifndef CO_STORAGE_EEPROM_H -#define CO_STORAGE_EEPROM_H - -#include "storage/CO_storage.h" - -#ifndef CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT -#define CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT 5U -#endif - -#if (((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup CO_storage_eeprom Data storage in eeprom - * Eeprom specific data storage functions. - * - * @ingroup CO_CANopen_storage - * @{ - * - * This is an interface into generic CANopenNode @ref CO_storage for usage with - * eeprom chip like 25LC256. Functions @ref CO_storageEeprom_init() and - * @ref CO_storageEeprom_auto_process are target system independent. Functions - * specified by @ref CO_eeprom.h file, must be defined by target system. - * For example implementation see CANopenPIC/PIC32. - * - * Storage principle: - * This function first reads 'signatures' for all entries from the known address - * from the eeprom. If signature for each entry is correct, then data is read - * from correct address from the eeprom into storage location. If signature is - * wrong, then data for that entry is indicated as corrupt and CANopen - * emergency message is sent. - * - * Signature also includes 16-bit CRC checksum of the data stored in eeprom. If - * it differs from CRC checksum calculated from the data actually loaded (on - * program startup), then entry is indicated as corrupt and CANopen emergency - * message is sent. - * - * Signature is written to eeprom, when data block is stored via CANopen SDO - * write command to object 0x1010. Signature is erased, with CANopen SDO write - * command to object 0x1011. If signature is not valid or is erased for any - * entry, emergency message is sent. If eeprom is new, then all signatures are - * wrong, so it is best to store all parameters by writing to 0x1010, sub 1. - * - * If entry attribute has CO_storage_auto set, then data block is stored - * autonomously, byte by byte, on change, during program run. Those data blocks - * are stored into write unprotected location. For auto storage to work, - * its signature in eeprom must be correct. CRC checksum for the data is not - * used. - */ - -/** - * Initialize data storage object (block device (eeprom) specific) - * - * This function should be called by application after the program startup, - * before @ref CO_CANopenInit(). This function initializes storage object, - * OD extensions on objects 1010 and 1011, reads data from file, verifies them - * and writes data to addresses specified inside entries. This function - * internally calls @ref CO_storage_init(). - * - * @param storage This object will be initialized. It must be defined by - * application and must exist permanently. - * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. - * @param storageModule Pointer to storage module passed to CO_eeprom functions. - * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". - * Entry is optional, may be NULL. - * @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default - * parameters". Entry is optional, may be NULL. - * @param entries Pointer to array of storage entries, see @ref CO_storage_init. - * @param entriesCount Count of storage entries, must not be larger than - * CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT. - * @param [out] storageInitError If function returns CO_ERROR_DATA_CORRUPT, - * then this variable contains a bit mask from subIndexOD values, where data - * was not properly initialized. If other error, then this variable contains - * index or erroneous entry. If there is hardware error like missing eeprom, - * then storageInitError is 0xFFFFFFFF and function returns - * CO_ERROR_DATA_CORRUPT. - * - * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if data can not be initialized, - * CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OUT_OF_MEMORY. - */ -CO_ReturnError_t CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* storageModule, - OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, - CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); - -/** - * Automatically update data if differs inside eeprom. - * - * Should be called cyclically by program. Each interval it updates one byte. - * - * @param storage This object - * @param saveAll If true, all bytes are updated, useful on program end. - */ -void CO_storageEeprom_auto_process(CO_storage_t* storage, bool_t saveAll); - -/** @} */ /* CO_storage_eeprom */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ - -#endif /* CO_STORAGE_EEPROM_H */ +/** + * CANopen data storage object for storing data into block device (eeprom) + * + * @file CO_storageEeprom.h + * @ingroup CO_storage_eeprom + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#ifndef CO_STORAGE_EEPROM_H +#define CO_STORAGE_EEPROM_H + +#include "storage/CO_storage.h" + +#ifndef CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT +#define CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT 5U +#endif + +#if (((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup CO_storage_eeprom Data storage in eeprom + * Eeprom specific data storage functions. + * + * @ingroup CO_CANopen_storage + * @{ + * This is an interface into generic CANopenNode @ref CO_storage for usage with eeprom chip like 25LC256. Functions @ref + * CO_storageEeprom_init() and @ref CO_storageEeprom_auto_process are target system independent. Functions specified by + * @ref CO_eeprom.h file, must be defined by target system. For example implementation see CANopenPIC/PIC32. + * + * Storage principle: + * This function first reads 'signatures' for all entries from the known address from the eeprom. If signature for each + * entry is correct, then data is read from correct address from the eeprom into storage location. If signature is + * wrong, then data for that entry is indicated as corrupt and CANopen emergency message is sent. + * + * Signature also includes 16-bit CRC checksum of the data stored in eeprom. If it differs from CRC checksum calculated + * from the data actually loaded (on program startup), then entry is indicated as corrupt and CANopen emergency message + * is sent. + * + * Signature is written to eeprom, when data block is stored via CANopen SDO write command to object 0x1010. Signature + * is erased, with CANopen SDO write command to object 0x1011. If signature is not valid or is erased for any entry, + * emergency message is sent. If eeprom is new, then all signatures are wrong, so it is best to store all parameters by + * writing to 0x1010, sub 1. + * + * If entry attribute has CO_storage_auto set, then data block is stored autonomously, byte by byte, on change, during + * program run. Those data blocks are stored into write unprotected location. For auto storage to work, its signature in + * eeprom must be correct. CRC checksum for the data is not used. + */ + +/** + * Initialize data storage object (block device (eeprom) specific) + * + * This function should be called by application after the program startup, before @ref CO_CANopenInit(). This function + * initializes storage object, OD extensions on objects 1010 and 1011, reads data from file, verifies them and writes + * data to addresses specified inside entries. This function internally calls @ref CO_storage_init(). + * + * @param storage This object will be initialized. It must be defined by application and must exist permanently. + * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. + * @param storageModule Pointer to storage module passed to CO_eeprom functions. + * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". Entry is optional, may be NULL. + * @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default parameters". Entry is optional, may be NULL. + * @param entries Pointer to array of storage entries, see @ref CO_storage_init. + * @param entriesCount Count of storage entries, must not be larger than CO_CONFIG_STORAGE_MAX_ENTRIES_COUNT. + * @param [out] storageInitError If function returns CO_ERROR_DATA_CORRUPT, then this variable contains a bit mask from + * subIndexOD values, where data was not properly initialized. If other error, then this variable contains index or + * erroneous entry. If there is hardware error like missing eeprom, then storageInitError is 0xFFFFFFFF and function + * returns CO_ERROR_DATA_CORRUPT. + * + * @return CO_ERROR_NO, CO_ERROR_DATA_CORRUPT if data can not be initialized, CO_ERROR_ILLEGAL_ARGUMENT or + * CO_ERROR_OUT_OF_MEMORY. + */ +CO_ReturnError_t CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* storageModule, + OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, + CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); + +/** + * Automatically update data if differs inside eeprom. + * + * Should be called cyclically by program. Each interval it updates one byte. + * + * @param storage This object + * @param saveAll If true, all bytes are updated, useful on program end. + */ +void CO_storageEeprom_auto_process(CO_storage_t* storage, bool_t saveAll); + +/** @} */ /* CO_storage_eeprom */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +#endif /* CO_STORAGE_EEPROM_H */ From e85410e923004402e583350380efdf3c902f4d34 Mon Sep 17 00:00:00 2001 From: Janez Date: Fri, 12 Jul 2024 15:56:19 +0200 Subject: [PATCH 480/520] CO_PDO.c: additional safety check. --- 301/CO_PDO.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index c57e01a1..47c538d1 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -740,6 +740,7 @@ CO_RPDO_process(CO_RPDO_t* RPDO, while (CO_FLAG_READ(RPDO->CANrxNew[bufNo])) { rpdoReceived = true; uint8_t* dataRPDO = RPDO->CANrxData[bufNo]; + OD_size_t verifyLength = 0U; /* Clear the flag. If between the copy operation CANrxNew is set * by receive thread, then copy the latest data again. */ @@ -753,6 +754,12 @@ CO_RPDO_process(CO_RPDO_t* RPDO, OD_size_t* dataOffset = &OD_IO->stream.dataOffset; uint8_t mappedLength = (uint8_t)(*dataOffset); + /* additional safety check. */ + verifyLength += (OD_size_t)mappedLength; + if (verifyLength > CO_PDO_MAX_SIZE) { + break; + } + /* length of OD variable may be larger than mappedLength */ OD_size_t ODdataLength = OD_IO->stream.dataLength; if (ODdataLength > CO_PDO_MAX_SIZE) { @@ -794,11 +801,17 @@ CO_RPDO_process(CO_RPDO_t* RPDO, } #else + verifyLength = (OD_size_t)PDO->dataLength; for (uint8_t i = 0; i < PDO->dataLength; i++) { *PDO->mapPointer[i] = dataRPDO[i]; } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ + if (verifyLength > CO_PDO_MAX_SIZE || verifyLength != (OD_size_t)PDO->dataLength) { + /* bug in software, should not happen */ + CO_errorReport(PDO->em, CO_EM_GENERIC_SOFTWARE_ERROR, CO_EMC_SOFTWARE_INTERNAL, + (0x100000 | verifyLength)); + } } /* while (CO_FLAG_READ(RPDO->CANrxNew[bufNo])) */ /* verify RPDO timeout */ @@ -1114,6 +1127,8 @@ static CO_ReturnError_t CO_TPDOsend(CO_TPDO_t* TPDO) { CO_PDO_common_t* PDO = &TPDO->PDO_common; uint8_t* dataTPDO = &TPDO->CANtxBuff->data[0]; + OD_size_t verifyLength = 0U; + #if OD_FLAGS_PDO_SIZE > 0 bool_t eventDriven = ((TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)); @@ -1127,6 +1142,12 @@ CO_TPDOsend(CO_TPDO_t* TPDO) { /* get mappedLength from temporary storage */ uint8_t mappedLength = (uint8_t)stream->dataOffset; + /* additional safety check */ + verifyLength += (OD_size_t)mappedLength; + if (verifyLength > CO_PDO_MAX_SIZE) { + break; + } + /* length of OD variable may be larger than mappedLength */ OD_size_t ODdataLength = stream->dataLength; if (ODdataLength > CO_PDO_MAX_SIZE) { @@ -1177,6 +1198,7 @@ CO_TPDOsend(CO_TPDO_t* TPDO) { dataTPDO += mappedLength; } #else + verifyLength = (OD_size_t)PDO->dataLength; for (uint8_t i = 0; i < PDO->dataLength; i++) { dataTPDO[i] = *PDO->mapPointer[i]; @@ -1190,6 +1212,12 @@ CO_TPDOsend(CO_TPDO_t* TPDO) { } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ + if (verifyLength > CO_PDO_MAX_SIZE || verifyLength != (OD_size_t)PDO->dataLength) { + /* bug in software, should not happen */ + CO_errorReport(PDO->em, CO_EM_GENERIC_SOFTWARE_ERROR, CO_EMC_SOFTWARE_INTERNAL, (0x200000 | verifyLength)); + return CO_ERROR_DATA_CORRUPT; + } + TPDO->sendRequest = false; #if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->eventTimer = TPDO->eventTime_us; From 835bae566475e79d0f2c2f0fd35153e1a092be11 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 13 Jul 2024 15:29:58 +0200 Subject: [PATCH 481/520] CO_SYNC: bugfix, if CO_CONFIG_FLAG_OD_DYNAMIC is disabled. --- 301/CO_SYNC.c | 2 +- 301/CO_SYNC.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/301/CO_SYNC.c b/301/CO_SYNC.c index a9062380..bc2f49d5 100644 --- a/301/CO_SYNC.c +++ b/301/CO_SYNC.c @@ -269,13 +269,13 @@ CO_SYNC_init(CO_SYNC_t* SYNC, CO_EM_t* em, OD_entry_t* OD_1005_cobIdSync, OD_ent SYNC->em = em; #if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 SYNC->isProducer = (cobIdSync & 0x40000000U) != 0U; + SYNC->CANdevTx = CANdevTx; #endif #if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 SYNC->CAN_ID = (uint16_t)(cobIdSync & 0x7FFU); SYNC->CANdevRx = CANdevRx; SYNC->CANdevRxIdx = CANdevRxIdx; #if ((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0 - SYNC->CANdevTx = CANdevTx; SYNC->CANdevTxIdx = CANdevTxIdx; #endif #endif diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 2d2ab94c..5db6e155 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -80,9 +80,10 @@ typedef struct { uint32_t* OD_1007_window; /**< Pointer to variable in OD, "Synchronous window length" in microseconds */ #if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN - bool_t isProducer; /**< True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ variable from - Object dictionary(index 0x1005).*/ - CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ + bool_t isProducer; /**< True, if device is SYNC producer. Calculated from _COB ID SYNC Message_ variable + from Object dictionary(index 0x1005).*/ + CO_CANmodule_t* CANdevTx; /**< From CO_SYNC_init() */ + CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer inside CANdevTx */ #endif #if ((CO_CONFIG_SYNC)&CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN @@ -92,7 +93,6 @@ typedef struct { uint16_t CAN_ID; /**< CAN ID of the SYNC message. Calculated from _COB ID SYNC Message_ variable from Object dictionary (index 0x1005). */ #if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_PRODUCER) != 0) || defined CO_DOXYGEN - CO_CANmodule_t* CANdevTx; /**< From CO_SYNC_init() */ uint16_t CANdevTxIdx; /**< From CO_SYNC_init() */ OD_extension_t OD_1019_extension; /**< Extension for OD object */ #endif From 076557a4850ce47787321d84a6dde82e2c22f3f3 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 5 Aug 2024 22:35:06 +0200 Subject: [PATCH 482/520] Update README.md Description for Object Dictionary Editor - binaries --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e118728e..3fa9db48 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ Object dictionary editor ------------------------ Object Dictionary is one of the most essential parts of CANopen. -To customize the Object Dictionary it is necessary to use external application: [CANopenEditor](https://github.com/CANopenNode/CANopenEditor). Latest pre-compiled [binaries](https://github.com/CANopenNode/CANopenEditor/archive/refs/heads/build.zip) are also available. Just extract the zip file and run the `EDSEditor.exe`. In Linux it runs with mono, which is available by default on Ubuntu. Just set file permissions to "executable" and then execute the program. +To customize the Object Dictionary it is necessary to use external application: [CANopenEditor](https://github.com/CANopenNode/CANopenEditor). Binaries are also available there. In Linux it runs with mono, which is available by default on Ubuntu. In program, in preferences, set exporter to "CANopenNode_V4". Then start new project or open the existing project file. From 05931a6b763299cc1bff2eb8c6926f086bc55131 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 7 Aug 2024 00:17:39 +0200 Subject: [PATCH 483/520] Fix and update doxygen documentation. --- 301/CO_Emergency.c | 12 +- 301/CO_NMT_Heartbeat.c | 2 +- 301/CO_ODinterface.h | 2 +- 301/CO_SDOclient.h | 3 + 301/CO_SYNC.h | 2 +- 303/CO_LEDs.h | 22 +- 304/CO_SRDO.c | 2 +- 304/CO_SRDO.h | 70 ++-- 305/CO_LSS.h | 40 ++- 305/CO_LSSmaster.c | 8 +- 305/CO_LSSmaster.h | 4 +- 305/CO_LSSslave.h | 4 +- 309/CO_gateway_ascii.h | 2 - CANopen.h | 11 +- Doxyfile | 719 +++++++++++++++++++++++++++------------- README.md | 4 +- doc/objectDictionary.md | 20 +- extra/CO_trace.h | 4 - 18 files changed, 592 insertions(+), 339 deletions(-) diff --git a/301/CO_Emergency.c b/301/CO_Emergency.c index d0b1ada3..614b4d3c 100644 --- a/301/CO_Emergency.c +++ b/301/CO_Emergency.c @@ -298,22 +298,22 @@ CO_EM_receive(void* object, void* msg) { CO_ReturnError_t CO_EM_init(CO_EM_t* em, CO_CANmodule_t* CANdevTx, const OD_entry_t* OD_1001_errReg, -#if ((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0 +#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) || defined CO_DOXYGEN CO_EM_fifo_t* fifo, uint8_t fifoSize, #endif -#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0 +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_PRODUCER) != 0) || defined CO_DOXYGEN OD_entry_t* OD_1014_cobIdEm, uint16_t CANdevTxIdx, -#if ((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0 +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_PROD_INHIBIT) != 0) || defined CO_DOXYGEN OD_entry_t* OD_1015_InhTime, #endif #endif -#if ((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0 +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_HISTORY) != 0) || defined CO_DOXYGEN OD_entry_t* OD_1003_preDefErr, #endif -#if ((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0 +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_STATUS_BITS) != 0) || defined CO_DOXYGEN OD_entry_t* OD_statusBits, #endif -#if ((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0 +#if (((CO_CONFIG_EM)&CO_CONFIG_EM_CONSUMER) != 0) || defined CO_DOXYGEN CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, #endif const uint8_t nodeId, uint32_t* errInfo) { diff --git a/301/CO_NMT_Heartbeat.c b/301/CO_NMT_Heartbeat.c index b4505cde..e3a420c2 100644 --- a/301/CO_NMT_Heartbeat.c +++ b/301/CO_NMT_Heartbeat.c @@ -72,7 +72,7 @@ OD_write_1017(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* CO_ReturnError_t CO_NMT_init(CO_NMT_t* NMT, OD_entry_t* OD_1017_ProducerHbTime, CO_EM_t* em, uint8_t nodeId, uint16_t NMTcontrol, uint16_t firstHBTime_ms, CO_CANmodule_t* NMT_CANdevRx, uint16_t NMT_rxIdx, uint16_t CANidRxNMT, -#if ((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0 +#if (((CO_CONFIG_NMT)&CO_CONFIG_NMT_MASTER) != 0) || defined CO_DOXYGEN CO_CANmodule_t* NMT_CANdevTx, uint16_t NMT_txIdx, uint16_t CANidTxNMT, #endif CO_CANmodule_t* HB_CANdevTx, uint16_t HB_txIdx, uint16_t CANidTxHB, uint32_t* errInfo) { diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index 34faab21..d4a6b743 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -33,7 +33,7 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * See @ref doc/objectDictionary.md + * See @ref md_doc_2objectDictionary */ #ifndef CO_OD_OWN_TYPES diff --git a/301/CO_SDOclient.h b/301/CO_SDOclient.h index 2b1b4bee..c12f6c24 100644 --- a/301/CO_SDOclient.h +++ b/301/CO_SDOclient.h @@ -31,6 +31,8 @@ #ifndef CO_CONFIG_SDO_CLI #define CO_CONFIG_SDO_CLI (0) #endif + +#ifndef CO_DOXYGEN #ifndef CO_CONFIG_SDO_CLI_BUFFER_SIZE #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_BLOCK) != 0 #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 1000U @@ -38,6 +40,7 @@ #define CO_CONFIG_SDO_CLI_BUFFER_SIZE 32U #endif #endif +#endif #if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN diff --git a/301/CO_SYNC.h b/301/CO_SYNC.h index 5db6e155..e281fe67 100644 --- a/301/CO_SYNC.h +++ b/301/CO_SYNC.h @@ -44,7 +44,7 @@ extern "C" { * * @ingroup CO_CANopen_301 * @{ - * For CAN identifier see #CO_Default_CAN_ID_t + * For CAN identifier see @ref CO_Default_CAN_ID_t * * SYNC message is used for synchronization of the nodes on network. One node can be SYNC producer, others can be SYNC * consumers. Synchronous TPDOs are transmitted after the CANopen SYNC message. Synchronous received PDOs are diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index 93bfe5cb..10d15ad7 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -61,13 +61,14 @@ extern "C" { * - quadruple flash: PDO has not been received before the event timer elapsed * - on: CAN bus off * - * To apply on/off state to led diode, use #CO_LED_RED and #CO_LED_GREEN macros. For CANopen leds use CO_LED_BITFIELD_t - * CO_LED_CANopen. Other bitfields are available for implementing custom leds. + * To apply on/off state to the led diode, use #CO_LED_RED or #CO_LED_GREEN macros with one of the @ref CO_LED_bitmasks. + * For CANopen leds use #CO_LED_CANopen bitmask. */ /** - * @defgroup CO_LED_BITFIELD_t Bitfield for combining with red or green led + * @defgroup CO_LED_bitmasks CO_LED bitmasks * @{ + * Bitmasks for the LED indicators */ #define CO_LED_flicker 0x01U /**< LED flickering 10Hz */ #define CO_LED_blink 0x02U /**< LED blinking 2,5Hz */ @@ -76,13 +77,12 @@ extern "C" { #define CO_LED_flash_3 0x10U /**< LED triple flash */ #define CO_LED_flash_4 0x20U /**< LED quadruple flash */ #define CO_LED_CANopen 0x80U /**< LED CANopen according to CiA 303-3 */ +/** @} */ -/** @} */ /* CO_LED_BITFIELD_t */ - -/** Get on/off state for green led for specified bitfield */ -#define CO_LED_RED(LEDs, BITFIELD) ((((LEDs)->LEDred & BITFIELD) != 0U) ? 1U : 0U) -/** Get on/off state for green led for specified bitfield */ -#define CO_LED_GREEN(LEDs, BITFIELD) ((((LEDs)->LEDgreen & BITFIELD) != 0U) ? 1U : 0U) +/** Get on/off state for red led for one of the @ref CO_LED_bitmasks */ +#define CO_LED_RED(LEDs, BITMASK) ((((LEDs)->LEDred & BITMASK) != 0U) ? 1U : 0U) +/** Get on/off state for green led for one of the @ref CO_LED_bitmasks */ +#define CO_LED_GREEN(LEDs, BITMASK) ((((LEDs)->LEDgreen & BITMASK) != 0U) ? 1U : 0U) /** * LEDs object, initialized by CO_LEDs_init() @@ -94,8 +94,8 @@ typedef struct { uint8_t LEDtmrflash_2; /**< double flash led timer */ uint8_t LEDtmrflash_3; /**< triple flash led timer */ uint8_t LEDtmrflash_4; /**< quadruple flash led timer */ - uint8_t LEDred; /**< red led #CO_LED_BITFIELD_t */ - uint8_t LEDgreen; /**< green led #CO_LED_BITFIELD_t */ + uint8_t LEDred; /**< red led bitfield, to be combined with @ref CO_LED_bitmasks */ + uint8_t LEDgreen; /**< green led bitfield, to be combined with @ref CO_LED_bitmasks */ } CO_LEDs_t; /** diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index 2632084d..ef0b2bb9 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -5,7 +5,7 @@ * @ingroup CO_SRDO * @author Robert Grüning * @copyright 2020 Robert Grüning - * @copyright 2024 temi54c1l8@github + * @copyright 2024 temi54c1l8(at)github * @copyright 2024 Janez Paternoster * * This file is part of , a CANopen Stack. diff --git a/304/CO_SRDO.h b/304/CO_SRDO.h index d720e815..e25e7861 100644 --- a/304/CO_SRDO.h +++ b/304/CO_SRDO.h @@ -5,7 +5,7 @@ * @ingroup CO_SRDO * @author Robert Grüning * @copyright 2020 Robert Grüning - * @copyright 2024 temi54c1l8@github + * @copyright 2024 temi54c1l8(at)github * @copyright 2024 Janez Paternoster * * This file is part of , a CANopen Stack. @@ -52,24 +52,23 @@ extern "C" { * distinction between sending and receiving SRDO is made at runtime (for PDO it is compile time). If the security * protocol is used, at least one SRDO is mandatory. * - * If there is erroneous structure of OD entries for SRDO parameters, then @CO_SRDO_init() function returns error and + * If there is erroneous structure of OD entries for SRDO parameters, then CO_SRDO_init() function returns error and * CANopen device doesn't work. It is necessary to repair Object Dictionary and reprogram the device. * - * If there are erroneous values inside SRDO parameters, then Emergency message CO_EM_SRDO_CONFIGURATION is sent. Info - * code (32bit) contains OD index, subindex and additional byte, which helps to determine erroneous OD object. + * If there are erroneous values inside SRDO parameters, then Emergency message @ref CO_EM_SRDO_CONFIGURATION is sent. + * Info code (32bit) contains OD index, subindex and additional byte, which helps to determine erroneous OD object. * - * SRDO configuration consists of one @CO_SRDO_init_start(), @CO_SRDO_init() for each SRDO and one @CO_SRDO_init_end(). - * These may be called in CANopen initialization section after all other CANopen objects are initialized. If SRDO OD - * parameters are edited (in NMT pre-operational state), NMT communication reset is necessary. Alternatively SRDO - * configuration may be executed just after transition to NMT operational state. + * SRDO is first configured in CANopen in CANopen initialization section after all other CANopen objects are + * initialized. It consists of one CO_SRDOGuard_init() and CO_SRDO_init() for each SRDO. On transition to NMT + * operational CO_SRDO_config() must be called for each SRDO. * - * @CO_SRDO_process() must be executed cyclically, similar as PDO processing. Function is fast, no time consuming tasks. - * Function returns @CO_SRDO_state_t value, which may be used to determine working-state or safe-state of safety related - * device. If return values from all SRDO objects are >= CO_SRDO_state_communicationEstablished, then working state is - * allowed. Otherwise SR device must be in safe state. + * CO_SRDO_process() must be executed cyclically, similar as PDO processing. Function is fast, no time consuming tasks. + * Function returns @ref CO_SRDO_state_t value, which may be used to determine working-state or safe-state of safety + * related device. If return values from all SRDO objects are >= @ref CO_SRDO_state_communicationEstablished, then + * working state is allowed. Otherwise SR device must be in safe state. * * Requirement for mapped objects: - * - @OD_attributes_t must have set bit ODA_RSRDO or ODA_RSRDO or ODA_TRSRDO (by CANopenEditor). + * - @ref OD_attributes_t must have set bit ODA_RSRDO or ODA_RSRDO or ODA_TRSRDO (by CANopenEditor). */ /** Maximum size of SRDO message, 8 for standard CAN */ @@ -84,7 +83,7 @@ extern "C" { #endif #ifndef CO_SRDO_OWN_TYPES -/** Variable of type CO_SRDO_size_t contains data length in bytes of SRDO */ +/** Variable of type @ref CO_SRDO_size_t contains data length in bytes of SRDO */ typedef uint8_t CO_SRDO_size_t; #endif @@ -100,7 +99,7 @@ typedef enum { CO_SRDO_state_error_rxTimeoutSCT = -3, /**< SRDO inverted message didn't receive inside SCT time */ CO_SRDO_state_error_rxNotInverted = -2, /**< Received SRDO messages was not inverted */ CO_SRDO_state_error_rxShort = -1, /**< Received SRDO message is too short */ - CO_SRDO_state_unknown = 0, /**< unknown state, set by @CO_SRDO_init */ + CO_SRDO_state_unknown = 0, /**< unknown state, set by CO_SRDO_init() */ CO_SRDO_state_nmtNotOperational = 1, /**< Internal NMT operating state is not NMT operational */ CO_SRDO_state_initializing = 2, /**< Just entered NMT operational state, SRDO message not yet received or transmitted */ @@ -119,7 +118,7 @@ typedef enum { typedef struct { bool_t NMTisOperational; /**< True if NMT operating state is operational */ bool_t configurationValid; /**< True if all SRDO objects are properly configured. Set after successful finish of all - @CO_SRDO_init() functions. Cleared on configuration change. */ + CO_SRDO_init() functions. Cleared on configuration change. */ OD_IO_t OD_IO_configurationValid; /**< Object for input / output on the OD variable 13FE:00. Configuration of any of the the SRDO parameters will write 0 to that variable. */ OD_entry_t* OD_13FE_entry; /**< From CO_SRDOGuard_init() */ @@ -176,7 +175,7 @@ typedef struct { /** * Initialize SRDOGuard object. * - * Function must be called in the communication reset section before @CO_SRDO_init functions. + * Function must be called in the communication reset section before CO_SRDO_init() functions. * * @param SRDOGuard This object will be initialized. * @param OD_13FE_configurationValid Pointer to _Configuration valid_ variable from Object dictionary (index 0x13FE). @@ -203,15 +202,14 @@ CO_ReturnError_t CO_SRDOGuard_init(CO_SRDOGuard_t* SRDOGuard, OD_entry_t* OD_13F * @param defaultCOB_ID Default COB ID for this SRDO for plain data (without NodeId). * @param OD_130x_SRDOCommPar Pointer to _SRDO communication parameter_ record from Object dictionary (index 0x1301+). * @param OD_138x_SRDOMapPar Pointer to _SRDO mapping parameter_ record from Object dictionary (index 0x1381+). - * @param OD_13FE_configurationValid Pointer to _Configuration valid_ variable from Object dictionary (index 0x13FE). - * @param OD_13FF_safetyConfigurationSignature Pointer to _Safety configuration signature_ variable from Object - * dictionary (index 0x13FF). - * @param CANdevRx CAN device used for SRDO reception. - * @param CANdevRxIdxNormal Index of receive buffer in the above CAN device. - * @param CANdevRxIdxInverted Index of receive buffer in the above CAN device. - * @param CANdevTx CAN device used for SRDO transmission. - * @param CANdevTxIdxNormal Index of transmit buffer in the above CAN device. - * @param CANdevTxIdxInverted Index of transmit buffer in the above CAN device. + * @param CANdevRxNormal CAN device used for SRDO reception for normal object. + * @param CANdevRxInverted CAN device used for SRDO reception for inverted object. + * @param CANdevRxIdxNormal Index of receive buffer in the above CAN device (normal). + * @param CANdevRxIdxInverted Index of receive buffer in the above CAN device (inverted). + * @param CANdevTxNormal CAN device used for SRDO transmission for normal object. + * @param CANdevTxInverted CAN device used for SRDO transmission for inverted object. + * @param CANdevTxIdxNormal Index of transmit buffer in the above CAN device (normal). + * @param CANdevTxIdxInverted Index of transmit buffer in the above CAN device (inverted). * @param [out] errInfo Additional information in case of error, may be NULL. * * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OD_PARAMETERS. @@ -238,19 +236,31 @@ CO_ReturnError_t CO_SRDO_init(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_ void CO_SRDO_initCallbackPre(CO_SRDO_t* SRDO, void* object, void (*pFunctSignalPre)(void* object)); #endif +/** + * Configure SRDO object. + * + * Function must be called in on transition to NMT operational. Function is also called from CO_SRDO_init() function. + * + * @param SRDO This object will be configured. + * @param SRDO_Index OD index of this SRDO, 0 for the first. + * @param SRDOGuard SRDOGuard object. + * @param [out] errInfo Additional information in case of error, may be NULL. + * + * @return #CO_ReturnError_t: CO_ERROR_NO, CO_ERROR_ILLEGAL_ARGUMENT or CO_ERROR_OD_PARAMETERS. + */ +CO_ReturnError_t CO_SRDO_config(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, uint32_t* errInfo); + /** * Send SRDO on event * - * Sends SRDO before the next refresh timer tiggers. The message itself is send in @CO_SRDO_process(). Note that RTOS + * Sends SRDO before the next refresh timer tiggers. The message itself is send in CO_SRDO_process(). Note that RTOS * have to trigger its processing quickly. After the transmission the timer is reset to the full refresh time. * * @param SRDO This object. - * @return CO_ReturnError_t CO_ERROR_NO if request is granted + * @return #CO_ReturnError_t: CO_ERROR_NO if request is granted */ CO_ReturnError_t CO_SRDO_requestSend(CO_SRDO_t* SRDO); -CO_ReturnError_t CO_SRDO_config(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, uint32_t* errInfo); - /** * Process transmitting/receiving individual SRDO message. * diff --git a/305/CO_LSS.h b/305/CO_LSS.h index aec0b634..4430de37 100644 --- a/305/CO_LSS.h +++ b/305/CO_LSS.h @@ -61,11 +61,11 @@ extern "C" { * * Using this implementation, only master or slave can be included in one node at a time. * - * For CAN identifiers see #CO_Default_CAN_ID_t + * For CAN identifiers see @ref CO_Default_CAN_ID_t */ /** - * @defgroup CO_LSS_cs_t LSS protocol command specifiers + * @defgroup CO_LSS_command_specifiers CO_LSS command specifiers * @{ * * The LSS protocols are executed between the LSS master device and the LSS slave device(s) to implement the LSS @@ -90,56 +90,59 @@ extern "C" { #define CO_LSS_INQUIRE_REV 0x5CU /**< Inquire identity revision-number protocol */ #define CO_LSS_INQUIRE_SERIAL 0x5DU /**< Inquire identity serial-number protocol */ #define CO_LSS_INQUIRE_NODE_ID 0x5EU /**< Inquire node-ID protocol */ -/** @} */ /* CO_LSS_cs_t */ +/** @} */ /** - * @defgroup CO_LSS_cfgNodeId_t Error codes for Configure node ID protocol + * @defgroup CO_LSS_CFG_NODE_ID_status CO_LSS_CFG_NODE_ID status * @{ + * Error codes for Configure node ID protocol */ #define CO_LSS_CFG_NODE_ID_OK 0x00U /**< Protocol successfully completed */ #define CO_LSS_CFG_NODE_ID_OUT_OF_RANGE 0x01U /**< NID out of range */ #define CO_LSS_CFG_NODE_ID_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ -/** @} */ /* CO_LSS_cfgNodeId_t */ +/** @} */ /** - * @defgroup CO_LSS_cfgBitTiming_t Error codes for Configure bit timing parameters protocol + * @defgroup CO_LSS_CFG_BIT_TIMING_status CO_LSS_CFG_BIT_TIMING status * @{ + * Error codes for Configure bit timing parameters protocol */ #define CO_LSS_CFG_BIT_TIMING_OK 0x00U /**< Protocol successfully completed */ #define CO_LSS_CFG_BIT_TIMING_OUT_OF_RANGE 0x01U /**< Bit timing / Bit rate not supported */ #define CO_LSS_CFG_BIT_TIMING_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ -/** @} */ /* CO_LSS_cfgBitTiming_t */ +/** @} */ /** - * @defgroup CO_LSS_cfgStore_t Error codes for Store configuration protocol + * @defgroup CO_LSS_CFG_STORE_status CO_LSS_CFG_STORE status * @{ + * Error codes for Store configuration protocol */ #define CO_LSS_CFG_STORE_OK 0x00U /**< Protocol successfully completed */ #define CO_LSS_CFG_STORE_NOT_SUPPORTED 0x01U /**< Store configuration not supported */ #define CO_LSS_CFG_STORE_FAILED 0x02U /**< Storage media access error */ #define CO_LSS_CFG_STORE_MANUFACTURER 0xFFU /**< Manufacturer specific error. No further support */ -/** @} */ /* CO_LSS_cfgStore_t */ +/** @} */ /** - * @defgroup CO_LSS_fastscan_bitcheck Fastscan BitCheck. BIT0 means all bits are checked for equality by slave + * @defgroup CO_LSS_FASTSCAN_bitcheck CO_LSS_FASTSCAN bitcheck * @{ + * Fastscan BitCheck. BIT0 means all bits are checked for equality by slave */ #define CO_LSS_FASTSCAN_BIT0 0x00U /**< Least significant bit of IDnumbners bit area to be checked */ /* ... */ #define CO_LSS_FASTSCAN_BIT31 0x1FU /**< dito */ #define CO_LSS_FASTSCAN_CONFIRM 0x80U /**< All LSS slaves waiting for scan respond and previous scan is reset */ -/** @} */ /* CO_LSS_fastscan_bitcheck */ +/** @} */ /** - * @defgroup CO_LSS_fastscan_lss_sub_next Fastscan LSSsub, LSSnext + * @defgroup CO_LSS_FASTSCAN_lssSub_lssNext CO_LSS_FASTSCAN lssSub lssNext * @{ */ #define CO_LSS_FASTSCAN_VENDOR_ID 0x00U /**< Vendor ID */ #define CO_LSS_FASTSCAN_PRODUCT 0x01U /**< Product code */ #define CO_LSS_FASTSCAN_REV 0x02U /**< Revision number */ #define CO_LSS_FASTSCAN_SERIAL 0x03U /**< Serial number */ - -/** @} */ /* CO_LSS_fastscan_lss_sub_next */ +/** @} */ /** * The LSS address is a 128 bit number, uniquely identifying each node. It consists of the values in object 0x1018. @@ -156,7 +159,7 @@ typedef union { } CO_LSS_address_t; /** - * @defgroup CO_LSS_state_t LSS finite state automaton + * @defgroup CO_LSS_STATE_state CO_LSS_STATE state * @{ * * The LSS FSA shall provide the following states: @@ -167,11 +170,12 @@ typedef union { */ #define CO_LSS_STATE_WAITING 0x00U /**< LSS FSA waiting for requests */ #define CO_LSS_STATE_CONFIGURATION 0x01U /**< LSS FSA waiting for configuration */ -/** @} */ /* CO_LSS_state_t */ +/** @} */ /** - * @defgroup CO_LSS_bitTimingTable_t Definition of table_index for /CiA301/ bit timing table + * @defgroup CO_LSS_BIT_TIMING_table CO_LSS_BIT_TIMING table * @{ + * Definition of table_index for /CiA301/ bit timing table */ #define CO_LSS_BIT_TIMING_1000 0U /**< 1000kbit/s */ #define CO_LSS_BIT_TIMING_800 1U /**< 800kbit/s */ @@ -183,7 +187,7 @@ typedef union { #define CO_LSS_BIT_TIMING_20 7U /**< 20kbit/s */ #define CO_LSS_BIT_TIMING_10 8U /**< 10kbit/s */ #define CO_LSS_BIT_TIMING_AUTO 9U /**< Automatic bit rate detection */ -/** @} */ /* CO_LSS_bitTimingTable_t */ +/** @} */ /** * Lookup table for conversion between bit timing table and numerical bit rate diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 35df2390..73a1b834 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -28,7 +28,7 @@ /* * @defgroup CO_LSSmaster_state_t * @{ - * LSS master slave select state machine. Compared to #CO_LSS_state_t this has information if we + * LSS master slave select state machine. Compared to @ref CO_LSS_STATE_state this has information if we * currently have selected one or all slaves. This allows for some basic error checking. */ #define CO_LSSmaster_STATE_WAITING 0x00U @@ -306,9 +306,9 @@ CO_LSSmaster_swStateDeselect(CO_LSSmaster_t* LSSmaster) { * - byte 2 -> Manufacturer Error, currently not used * * enums for the errorCode are - * - CO_LSS_cfgNodeId_t - * - CO_LSS_cfgBitTiming_t - * - CO_LSS_cfgStore_t + * - CO_LSS_CFG_NODE_ID_status + * - CO_LSS_CFG_BIT_TIMING + * - CO_LSS_CFG_STORE_status */ static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference_us, uint8_t csWait) { diff --git a/305/CO_LSSmaster.h b/305/CO_LSSmaster.h index 47405229..05cd2bf8 100644 --- a/305/CO_LSSmaster.h +++ b/305/CO_LSSmaster.h @@ -144,7 +144,7 @@ CO_ReturnError_t CO_LSSmaster_init(CO_LSSmaster_t* LSSmaster, uint16_t timeout_m * * On LSS, a "negative ack" is signaled by the slave not answering. Because of that, a low timeout value can * significantly increase protocol speed in some cases (e.g. fastscan). However, as soon as there is activity on the - * bus, LSS messages can be delayed because of their low CAN network priority (see #CO_Default_CAN_ID_t). + * bus, LSS messages can be delayed because of their low CAN network priority (see @ref CO_Default_CAN_ID_t). * * @remark Be aware that a "late response" will seriously mess up LSS, so this value must be selected "as high as * necessary and as low as possible". CiA does neither specify nor recommend a value. @@ -300,7 +300,7 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(CO_LSSmaster_t* LSSmaster, * * @param LSSmaster This object. * @param timeDifference_us Time difference from previous function call in [microseconds]. Zero when request is started. - * @param lssInquireCs One of CO_LSS_INQUIRE_xx commands from #CO_LSS_cs_t. + * @param lssInquireCs One of CO_LSS_INQUIRE_xx commands from @ref CO_LSS_command_specifiers. * @param [out] value read result when function returns successfully * @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE, #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, * #CO_LSSmaster_TIMEOUT diff --git a/305/CO_LSSslave.h b/305/CO_LSSslave.h index 850d4a17..6727bfd8 100644 --- a/305/CO_LSSslave.h +++ b/305/CO_LSSslave.h @@ -75,7 +75,7 @@ extern "C" { */ typedef struct { CO_LSS_address_t lssAddress; /**< From #CO_LSSslave_init */ - uint8_t lssState; /**< #CO_LSS_state_t */ + uint8_t lssState; /**< @ref CO_LSS_STATE_state */ CO_LSS_address_t lssSelect; /**< Received LSS Address by select */ CO_LSS_address_t lssFastscan; /**< Received LSS Address by fastscan */ uint8_t fastscanPos; /**< Current state of fastscan */ @@ -160,7 +160,7 @@ bool_t CO_LSSslave_process(CO_LSSslave_t* LSSslave); * Get current LSS state * * @param LSSslave This object. - * @return #CO_LSS_state_t + * @return @ref CO_LSS_STATE_state */ static inline uint8_t CO_LSSslave_getState(CO_LSSslave_t* LSSslave) { diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index f416f5ec..7c3947ba 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -395,8 +395,6 @@ void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char* message); * is possible. Can be connected to hardware switch, for example. * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param [out] timerNext_us info to OS - see CO_process(). - * - * @return CO_ReturnError_t: CO_ERROR_NO on success or CO_ERROR_ILLEGAL_ARGUMENT */ void CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint32_t* timerNext_us); diff --git a/CANopen.h b/CANopen.h index 493fd447..53627179 100644 --- a/CANopen.h +++ b/CANopen.h @@ -334,8 +334,8 @@ typedef struct { #endif #endif #if (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN - CO_SRDOGuard_t* SRDOGuard; /**< SRDO guard object, initialised by @ref CO_SRDO_init_start(), single SRDOGuard object - is included inside all SRDO objects */ + CO_SRDOGuard_t* SRDOGuard; /**< SRDO guard object, initialised by CO_SRDOGuard_init(), single SRDOGuard object is + included inside all SRDO objects */ CO_SRDO_t* SRDO; /**< SRDO objects, initialised by @ref CO_SRDO_init() */ #if defined CO_MULTIPLE_OD || defined CO_DOXYGEN uint16_t RX_IDX_SRDO; /**< Start index in CANrx. */ @@ -491,9 +491,10 @@ CO_ReturnError_t CO_CANopenInitPDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t node * nor processed. * @param [out] errInfo Additional information in case of error, may be NULL. * - * @return CO_ERROR_NO in case of success. + * @return #CO_ERROR_NO in case of success. */ -#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) +#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) \ + || defined CO_DOXYGEN CO_ReturnError_t CO_CANopenInitSRDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo); #endif @@ -573,7 +574,7 @@ void CO_process_TPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint3 * @param timeDifference_us Time difference from previous function call in microseconds. * @param [out] timerNext_us info to OS - see CO_process(). * - * @return @CO_SRDO_state_t lowest state of the SRDO objects. + * @return #CO_SRDO_state_t: lowest state of the SRDO objects. */ CO_SRDO_state_t CO_process_SRDO(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us); #endif diff --git a/Doxyfile b/Doxyfile index 07892a8a..14668951 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.1 +# Doxyfile 1.11.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -53,6 +63,12 @@ PROJECT_BRIEF = "CANopen protocol stack" PROJECT_LOGO = doc/CANopenNode.png +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = doc/CANopenNode.png + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If @@ -60,16 +76,28 @@ PROJECT_LOGO = doc/CANopenNode.png OUTPUT_DIRECTORY = doc -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,26 +109,18 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -258,16 +278,16 @@ TAB_SIZE = 4 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = @@ -312,8 +332,8 @@ OPTIMIZE_OUTPUT_SLICE = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files @@ -344,10 +364,21 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. +# Minimum value: 0, maximum value: 99, default value: 6. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 6 + +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. -TOC_INCLUDE_HEADINGS = 5 +MARKDOWN_ID_STYLE = DOXYGEN # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can @@ -361,8 +392,8 @@ AUTOLINK_SUPPORT = YES # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO @@ -374,9 +405,9 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO @@ -460,19 +491,27 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, -# which efficively disables parallel processing. Please report any issues you +# which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -554,7 +593,8 @@ HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = YES @@ -585,14 +625,15 @@ INTERNAL_DOCS = NO # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with +# are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. -# The default value is: system dependent. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = YES @@ -610,6 +651,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -767,7 +814,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -813,27 +861,50 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -844,13 +915,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -865,6 +950,7 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = README.md \ + MISRA.md \ doc \ example/DS301_profile.md \ CANopen.h \ @@ -881,10 +967,21 @@ INPUT = README.md \ # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -896,18 +993,22 @@ INPUT_ENCODING = UTF-8 # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, -# *.ucf, *.qsf and *.ice. +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ + *.cxxm \ *.cpp \ + *.cppm \ + *.ccm \ *.c++ \ + *.c++m \ *.java \ *.ii \ *.ixx \ @@ -922,6 +1023,8 @@ FILE_PATTERNS = *.c \ *.hxx \ *.hpp \ *.h++ \ + *.ixx \ + *.l \ *.cs \ *.d \ *.php \ @@ -934,8 +1037,6 @@ FILE_PATTERNS = *.c \ *.md \ *.mm \ *.dox \ - *.doc \ - *.txt \ *.py \ *.pyw \ *.f90 \ @@ -986,10 +1087,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test EXCLUDE_SYMBOLS = @@ -1034,6 +1132,11 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -1075,6 +1178,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = ./README.md +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1089,7 +1201,8 @@ USE_MDFILE_AS_MAINPAGE = ./README.md SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO @@ -1172,9 +1285,11 @@ VERBATIM_HEADERS = YES CLANG_ASSISTED_PARSING = NO -# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to -# YES then doxygen will add the directory of each input to the include path. +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. # The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_ADD_INC_PATHS = YES @@ -1210,10 +1325,11 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1292,7 +1408,12 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = @@ -1307,9 +1428,22 @@ HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1319,7 +1453,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1337,15 +1471,6 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1365,6 +1490,33 @@ HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = YES +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1401,6 +1553,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1426,8 +1585,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: -# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1484,6 +1647,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1586,16 +1759,28 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1620,6 +1805,13 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for @@ -1640,17 +1832,6 @@ HTML_FORMULA_FORMAT = png FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. @@ -1668,11 +1849,29 @@ FORMULA_MACROFILE = USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1685,15 +1884,21 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = @@ -1873,29 +2078,31 @@ PAPER_TYPE = a4 EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1938,10 +2145,16 @@ PDF_HYPERLINKS = YES USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1954,16 +2167,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -1972,14 +2175,6 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2044,15 +2239,13 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. +# The RTF_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the RTF_OUTPUT output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_SOURCE_CODE = NO +RTF_EXTRA_FILES = #--------------------------------------------------------------------------- # Configuration options related to the man page output @@ -2150,27 +2343,44 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2245,7 +2455,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2312,15 +2523,15 @@ TAGFILES = GENERATE_TAGFILE = doc/html/CANopenNode.tag -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2334,25 +2545,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2361,10 +2556,10 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO -# The default value is: YES. +# The default value is: NO. HAVE_DOT = YES @@ -2378,49 +2573,77 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" + +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2462,8 +2685,8 @@ DOT_UML_DETAILS = NO # The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters # to display on a single line. If the actual line length exceeds this threshold -# significantly it will wrapped across multiple lines. Some heuristics are apply -# to avoid ugly line breaks. +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. # Minimum value: 0, maximum value: 1000, default value: 17. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2480,7 +2703,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2489,7 +2714,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2529,22 +2757,30 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, -# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, -# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, # png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and # png:gdiplus:gdiplus. # The default value is: png. @@ -2577,11 +2813,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2590,10 +2827,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2610,7 +2847,7 @@ PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized -# by representing a node as a red box. Note that doxygen if the number of direct +# by representing a node as a red box. Note that if the number of direct # children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. @@ -2631,18 +2868,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2655,6 +2880,8 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2663,8 +2890,24 @@ GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. # -# Note: This setting is not only used for dot files but also for msc and -# plantuml temporary files. +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/README.md b/README.md index 3fa9db48..dfddc409 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Documentation, support and contributions ---------------------------------------- All code is documented in the source header files. Some additional documents are in `doc` directory. -To generate complete html documentation, run [doxygen](http://www.doxygen.nl/) in the project base directory: `sudo apt install doxygen graphviz pdf2svg; doxygen > /dev/null` +To generate complete html documentation, run [doxygen](https://www.doxygen.nl/index.html) in the project base directory: `sudo apt install doxygen graphviz pdf2svg; doxygen > /dev/null` Complete generated documentation is also available online: https://canopennode.github.io @@ -65,8 +65,6 @@ Tutorial, demo device and tests are available in [CANopenDemo](https://github.co Report issues on https://github.com/CANopenNode/CANopenNode/issues -Older discussion group is on Sourceforge: http://sourceforge.net/p/canopennode/discussion/387151/ - Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Please follow the [Recommended C style and coding rules](https://github.com/MaJerle/c-code-style), use .clang-format file for automatic code formatting. The CANopenNode files conform to the [MISRA C:2012](https://www.misra.org.uk) guidelines, with some noted exceptions, as indicated in [MISRA.md](MISRA.md). diff --git a/doc/objectDictionary.md b/doc/objectDictionary.md index 5e344637..77e02048 100644 --- a/doc/objectDictionary.md +++ b/doc/objectDictionary.md @@ -1,8 +1,8 @@ Object Dictionary ================= -Definitions from CiA 301 {#definitions-from-cia-301} ----------------------------------------------------- +Definitions from CiA 301 +------------------------ The **Object Dictionary** is a collection of all the data items which have an influence on the behavior of the application objects, the communication objects and the state machine used on this device. It serves as an interface between the communication and the application. The object dictionary is essentially a grouping of objects accessible via the network in an ordered pre-defined fashion. Each object within the object dictionary is addressed using a 16-bit index and a 8-bit sub-index. @@ -11,8 +11,8 @@ A **SDO** (Service Data Object) is providing direct access to object entries of A **PDO** (Process Data Object) is providing real-time data transfer of object entries of a CANopen device's object dictionary. The transfer of PDO is performed with no protocol overhead. The PDO correspond to objects in the object dictionary and provide the interface to the application objects. Data type and mapping of application objects into a PDO is determined by a corresponding PDO mapping structure within the object dictionary. -Operation {#operation} ----------------------- +Operation +--------- ### Terms The term **OD object** means object from object dictionary located at specific 16-bit index. There are different types of OD objects in CANopen: variables, arrays and records (structures). Each OD object contains pointer to actual data, data length(s) and attribute(s). See @ref OD_objectTypes_t. @@ -85,8 +85,8 @@ void myFuncGlob(void) { ``` -Object Dictionary Example {#object-dictionary-example} ------------------------------------------------------- +Object Dictionary Example +------------------------- Actual Object dictionary for one CANopen device is defined by pair of OD_xyz.h and ODxyz.c files. Suffix "xyz" is unique name of the object dictionary. If single default object dictionary is used, suffix is omitted. Such way configuration with multiple object dictionaries is possible. @@ -239,8 +239,8 @@ OD_t *ODxyz = &_ODxyz; ``` -XML Device Description {#xml-device-description} ------------------------------------------------- +XML Device Description +---------------------- CANopen device description - XML schema definition - is specified by CiA 311 standard. CiA 311 complies with standard ISO 15745-1:2005/Amd1 (Industrial automation systems and integration - Open systems application integration framework). @@ -450,8 +450,8 @@ Other elements listed in the above XML example are required by the standard. The (4) Default value for DOMAIN is stored as empty string. -Object Dictionary Requirements By CANopenNode {#object-dictionary-requirements-by-canopennode} ----------------------------------------------------------------------------------------------- +Object Dictionary Requirements By CANopenNode +--------------------------------------------- * **Used by** column indicates CANopenNode object or its part, which uses the OD object. It also indicates, if OD object is required or optional for actual configuration. For the configuration of the CANopenNode objects see [Stack configuration](301/CO_config.h). If CANopenNode object or its part is disabled in stack configuration, then OD object is not used. Note that OD objects: 1000, 1001 and 1017 and 1018 are mandatory for CANopen. * **CO_countLabel** column indicates, which value must have property "CO_countLabel" inside OD object. diff --git a/extra/CO_trace.h b/extra/CO_trace.h index ac3cc6f0..096784f3 100644 --- a/extra/CO_trace.h +++ b/extra/CO_trace.h @@ -128,8 +128,6 @@ typedef struct { * @param triggerTime Pointer to variable, which will show last trigger time of the variable. * @param idx_OD_traceConfig Index in Object Dictionary. * @param idx_OD_trace Index in Object Dictionary. - * - * @return 0 on success, -1 on error. */ void CO_trace_init( CO_trace_t *trace, @@ -157,8 +155,6 @@ void CO_trace_init( * * @param trace This object. * @param timestamp Timestamp (usually in millisecond resolution). - * - * @return 0 on success, -1 on error. */ void CO_trace_process(CO_trace_t *trace, uint32_t timestamp); From 58012aae34928d823abed5a2556bdab91ed3f4a2 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 14 Aug 2024 16:49:01 +0200 Subject: [PATCH 484/520] Fix links --- 301/CO_ODinterface.h | 4 ++-- README.md | 26 +++++++++++++------------- doc/deviceSupport.md | 4 +++- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index d4a6b743..dcc11082 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -401,8 +401,8 @@ OD_getFlagsPDO(OD_entry_t* entry) { * event driven transmission, then TPDO will be transmitted after this function call. If OD variable is mapped to more * than one TPDO with event driven transmission, only the first matched TPDO will be transmitted. * - * TPDO event driven transmission is enabled, if TPDO communication parameter, transmission type is set to 0, 254 or - * 255. For other transmission types (synchronous) flagPDO bit is ignored. + * TPDO event driven transmission is enabled, if TPDO communication parameter, transmission type is set to 0, 254 + * or 255. For other transmission types (synchronous) flagPDO bit is ignored. * * @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO. * @param subIndex subIndex of the OD variable. diff --git a/README.md b/README.md index dfddc409..34b18dd4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ CANopenNode CANopenNode is free and open source CANopen protocol stack. -CANopen is the internationally standardized (EN 50325-4) ([CiA301](http://can-cia.org/standardization/technical-documents)) higher-layer protocol for embedded control system built on top of CAN. For more information on CANopen see http://www.can-cia.org/ +CANopen is the internationally standardized (EN 50325-4) ([CiA301](https://www.can-cia.org/cia-groups/technical-documents)) higher-layer protocol for embedded control system built on top of CAN. For more information on CANopen see http://www.can-cia.org/ CANopenNode is written in ANSI C in object-oriented way. It runs on different microcontrollers, as standalone application or with RTOS. @@ -17,19 +17,19 @@ This is version 4 of CANopenNode with new Object Dictionary implementation. For Characteristics --------------- ### CANopen - - [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen/device-architecture/) offers clear and flexible organisation of any variables. Variables can be accessed directly or via read/write functions. - - [NMT](https://www.can-cia.org/can-knowledge/canopen/network-management/) slave to start, stop, reset device. Simple NMT master. - - [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/) producer/consumer error control for monitoring of CANopen devices. An older alternative, 'node guarding', is also available. - - [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) for broadcasting process data with high priority and no protocol overhead. Variables from Object Dictionary can be dynamically mapped to the TPDO, which is then transmitted according to communication rules and received as RPDO by another device. - - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) server enables expedited, segmented and block transfer access to all Object Dictionary variables inside CANopen device. - - [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client can access any Object Dictionary variable on any CANopen device inside the network. - - [Emergency](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) message producer/consumer. - - [Sync](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) producer/consumer enables network synchronized transmission of the PDO objects, etc. - - [Time-stamp](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/) producer/consumer enables date and time synchronization in millisecond resolution. - - [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) CANopen node-id and bitrate setup, master and slave, LSS fastscan. - - [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. + - [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen-internal-device-architecture/) offers clear and flexible organisation of any variables. Variables can be accessed directly or via read/write functions. + - [NMT](https://www.can-cia.org/can-knowledge/network-management/) slave to start, stop, reset device. Simple NMT master. + - [Heartbeat](https://www.can-cia.org/can-knowledge/error-control-protocols) producer/consumer error control for monitoring of CANopen devices. An older alternative, 'node guarding', is also available. + - [PDO](https://www.can-cia.org/can-knowledge/pdo-protocol/) for broadcasting process data with high priority and no protocol overhead. Variables from Object Dictionary can be dynamically mapped to the TPDO, which is then transmitted according to communication rules and received as RPDO by another device. + - [SDO](https://www.can-cia.org/can-knowledge/sdo-protocol/) server enables expedited, segmented and block transfer access to all Object Dictionary variables inside CANopen device. + - [SDO](https://www.can-cia.org/can-knowledge/sdo-protocol/) client can access any Object Dictionary variable on any CANopen device inside the network. + - [Emergency](https://www.can-cia.org/can-knowledge/special-function-protocols/) message producer/consumer. + - [Sync](https://www.can-cia.org/can-knowledge/special-function-protocols/) producer/consumer enables network synchronized transmission of the PDO objects, etc. + - [Time-stamp](https://www.can-cia.org/can-knowledge/special-function-protocols/) producer/consumer enables date and time synchronization in millisecond resolution. + - [LSS](https://www.can-cia.org/can-knowledge/cia-305-layer-setting-services-lss/) CANopen node-id and bitrate setup, master and slave, LSS fastscan. + - [CANopen gateway](https://www.can-cia.org/can-knowledge/cia-309-series-accessing-canopen-via-tcp/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. - [CANopen Safety](https://standards.globalspec.com/std/1284438/en-50325-5), EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks - - [CANopen Conformance Test Tool](https://www.can-cia.org/services/test-center/conformance-test-tool/) passed. + - [CANopen Conformance Test Tool](https://www.can-cia.org/services/canopen-conformance-test-tool/) passed. ### Other - [Suitable for 16-bit microcontrollers and above](#device-support) diff --git a/doc/deviceSupport.md b/doc/deviceSupport.md index e49b7522..c9950735 100644 --- a/doc/deviceSupport.md +++ b/doc/deviceSupport.md @@ -35,6 +35,7 @@ STM32 * https://github.com/CANopenNode/CanOpenSTM32 * CANopenNode version: (v4.0) + PIC32, dsPIC30, dsPIC33 ----------------------- * CANopenNode integration with 16 and 32 bit PIC microcontrollers from Microchip. @@ -43,6 +44,7 @@ PIC32, dsPIC30, dsPIC33 * Features: OD storage for PIC32, SDO client demo for PIC32, error counters * Development tools: MPLAB X * Demo hardware: Explorer 16 from Microchip, [Max32 board](https://reference.digilentinc.com/reference/microprocessor/max32/start) +* Example with smallest resuorces (less than 2kb RAM), 4TPDO+4RPDO: 16-bit dsPIC30F4011 [Analog Devices Inc](https://www.analog.com): MAX32662, MAX32690 @@ -54,7 +56,7 @@ PIC32, dsPIC30, dsPIC33 * Features: LED indicators, error counters * Development tools: Maxim Micros SDK * Demo hardware: MAX32662-EVKIT and MAX32690-EVKIT -* Information updated 2023-02-17 +* Information updated 2023-02-17 Zephyr RTOS From 29c5b64131654b6f6f2171c64a1d5ce8031bcaa0 Mon Sep 17 00:00:00 2001 From: Janez Date: Thu, 10 Oct 2024 16:08:54 +0200 Subject: [PATCH 485/520] Fix example/CO_storageBlank.c. CO_LOCK_OD(CANmodule) must not be used, because lock is already applied by SDO server. --- example/CO_storageBlank.c | 2 -- storage/CO_storage.h | 2 +- storage/CO_storageEeprom.h | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/example/CO_storageBlank.c b/example/CO_storageBlank.c index c56b0d00..a2306a5c 100644 --- a/example/CO_storageBlank.c +++ b/example/CO_storageBlank.c @@ -31,9 +31,7 @@ storeBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { /* Open a file and write data to it */ /* file = open(entry->pathToFileOrPointerToMemory); */ - CO_LOCK_OD(CANmodule); /* write(entry->addr, entry->len, file); */ - CO_UNLOCK_OD(CANmodule); return ODR_OK; } diff --git a/storage/CO_storage.h b/storage/CO_storage.h index 28c7f687..d11302d6 100644 --- a/storage/CO_storage.h +++ b/storage/CO_storage.h @@ -109,7 +109,7 @@ typedef struct { * because loading data is target specific. * * @param storage This object will be initialized. It must be defined by application and must exist permanently. - * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. + * @param CANmodule CAN device, for optional usage. * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". Entry is optional, may be NULL. * @param OD_1011_RestoreDefaultParameters OD entry for 0x1011 -"Restore default parameters". Entry is optional, may be * NULL. diff --git a/storage/CO_storageEeprom.h b/storage/CO_storageEeprom.h index 96c41d9a..f964f512 100644 --- a/storage/CO_storageEeprom.h +++ b/storage/CO_storageEeprom.h @@ -70,7 +70,7 @@ extern "C" { * data to addresses specified inside entries. This function internally calls @ref CO_storage_init(). * * @param storage This object will be initialized. It must be defined by application and must exist permanently. - * @param CANmodule CAN device, used for @ref CO_LOCK_OD() macro. + * @param CANmodule CAN device, for optional usage. * @param storageModule Pointer to storage module passed to CO_eeprom functions. * @param OD_1010_StoreParameters OD entry for 0x1010 -"Store parameters". Entry is optional, may be NULL. * @param OD_1011_RestoreDefaultParam OD entry for 0x1011 -"Restore default parameters". Entry is optional, may be NULL. From 9e9aaf5f8def7b3cb18bb9378a5c583c645ada0c Mon Sep 17 00:00:00 2001 From: Vincent Chatelain Date: Sat, 19 Oct 2024 00:51:48 +0200 Subject: [PATCH 486/520] CO_ODinterface: fix unreachable statement (#548) Using a `break` after a `return` triggers warning 111 of Arm Compiler 5. To fix this warning while respecting MISRA rules, the return mechanism of OD_getSub() function was changed to only exit at the end. --- 301/CO_ODinterface.c | 50 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/301/CO_ODinterface.c b/301/CO_ODinterface.c index 605b88b6..8b961152 100644 --- a/301/CO_ODinterface.c +++ b/301/CO_ODinterface.c @@ -182,13 +182,15 @@ OD_getSub(const OD_entry_t* entry, uint8_t subIndex, OD_IO_t* io, bool_t odOrig) return ODR_DEV_INCOMPAT; } + ODR_t ret = ODR_OK; OD_stream_t* stream = &io->stream; /* attribute, dataOrig and dataLength, depends on object type */ switch (entry->odObjectType & (uint8_t)ODT_TYPE_MASK) { case ODT_VAR: { if (subIndex > 0U) { - return ODR_SUB_NOT_EXIST; + ret = ODR_SUB_NOT_EXIST; + break; } CO_PROGMEM OD_obj_var_t* odo = entry->odObject; @@ -199,7 +201,8 @@ OD_getSub(const OD_entry_t* entry, uint8_t subIndex, OD_IO_t* io, bool_t odOrig) } case ODT_ARR: { if (subIndex >= entry->subEntriesCount) { - return ODR_SUB_NOT_EXIST; + ret = ODR_SUB_NOT_EXIST; + break; } CO_PROGMEM OD_obj_array_t* odo = entry->odObject; @@ -225,7 +228,8 @@ OD_getSub(const OD_entry_t* entry, uint8_t subIndex, OD_IO_t* io, bool_t odOrig) } } if (odo == NULL) { - return ODR_SUB_NOT_EXIST; + ret = ODR_SUB_NOT_EXIST; + break; } stream->attribute = odo->attribute; @@ -234,32 +238,34 @@ OD_getSub(const OD_entry_t* entry, uint8_t subIndex, OD_IO_t* io, bool_t odOrig) break; } default: { - return ODR_DEV_INCOMPAT; + ret = ODR_DEV_INCOMPAT; break; } } - /* Access data from the original OD location */ - if ((entry->extension == NULL) || odOrig) { - io->read = OD_readOriginal; - io->write = OD_writeOriginal; - stream->object = NULL; - } - /* Access data from extension specified by application */ - else { - io->read = (entry->extension->read != NULL) ? entry->extension->read : OD_readDisabled; - io->write = (entry->extension->write != NULL) ? entry->extension->write : OD_writeDisabled; - stream->object = entry->extension->object; - } + if (ret == ODR_OK) { + /* Access data from the original OD location */ + if ((entry->extension == NULL) || odOrig) { + io->read = OD_readOriginal; + io->write = OD_writeOriginal; + stream->object = NULL; + } + /* Access data from extension specified by application */ + else { + io->read = (entry->extension->read != NULL) ? entry->extension->read : OD_readDisabled; + io->write = (entry->extension->write != NULL) ? entry->extension->write : OD_writeDisabled; + stream->object = entry->extension->object; + } - /* Reset stream data offset */ - stream->dataOffset = 0; + /* Reset stream data offset */ + stream->dataOffset = 0; - /* Add informative data */ - stream->index = entry->index; - stream->subIndex = subIndex; + /* Add informative data */ + stream->index = entry->index; + stream->subIndex = subIndex; + } - return ODR_OK; + return ret; } uint32_t From fbd42d46a280b957c530c65ee6981c172fd6f635 Mon Sep 17 00:00:00 2001 From: Janez Date: Sat, 19 Oct 2024 12:42:36 +0200 Subject: [PATCH 487/520] Make OD_requestTPDO() more clear, remove OD_getFlagsPDO(). --- 301/CO_ODinterface.h | 49 ++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/301/CO_ODinterface.h b/301/CO_ODinterface.h index dcc11082..6c6bd65e 100644 --- a/301/CO_ODinterface.h +++ b/301/CO_ODinterface.h @@ -322,7 +322,7 @@ OD_entry_t* OD_find(OD_t* od, uint16_t index); * Read and write functions may be called from different threads, so critical sections in custom functions must be * observed, see @ref CO_critical_sections. * - * @param entry OD entry returned by @ref OD_find(). + * @param entry Object Dictionary entry. * @param subIndex Sub-index of the variable from the OD object. * @param [out] io Structure will be populated on success. * @param odOrig If true, then potential IO extension on entry will be ignored and access to data entry in the original @@ -335,7 +335,7 @@ ODR_t OD_getSub(const OD_entry_t* entry, uint8_t subIndex, OD_IO_t* io, bool_t o /** * Return index from OD entry * - * @param entry OD entry returned by @ref OD_find(). + * @param entry Object Dictionary entry. * * @return OD index */ @@ -374,25 +374,6 @@ OD_rwRestart(OD_stream_t* stream) { } } -/** - * Get TPDO request flags for OD entry. - * - * flagsPDO can be used for @ref OD_requestTPDO() or @ref OD_TPDOtransmitted(). - * - * @param entry OD entry returned by @ref OD_find(). - * - * @return pointer to flagsPDO - */ -static inline uint8_t* -OD_getFlagsPDO(OD_entry_t* entry) { -#if OD_FLAGS_PDO_SIZE > 0 - if ((entry != NULL) && (entry->extension != NULL)) { - return &entry->extension->flagsPDO[0]; - } -#endif - return NULL; -} - /** * Request TPDO, to which OD variable is mapped * @@ -404,16 +385,16 @@ OD_getFlagsPDO(OD_entry_t* entry) { * TPDO event driven transmission is enabled, if TPDO communication parameter, transmission type is set to 0, 254 * or 255. For other transmission types (synchronous) flagPDO bit is ignored. * - * @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO. + * @param entry Object Dictionary entry. * @param subIndex subIndex of the OD variable. */ static inline void -OD_requestTPDO(uint8_t* flagsPDO, uint8_t subIndex) { +OD_requestTPDO(OD_entry_t* entry, uint8_t subIndex) { #if OD_FLAGS_PDO_SIZE > 0 - if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) { + if ((entry != NULL) && (entry->extension != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) { /* clear subIndex-th bit */ uint8_t mask = ~(1U << (subIndex & 0x07U)); - flagsPDO[subIndex >> 3] &= mask; + entry->extension->flagsPDO[subIndex >> 3] &= mask; } #endif } @@ -421,20 +402,20 @@ OD_requestTPDO(uint8_t* flagsPDO, uint8_t subIndex) { /** * Check if requested TPDO was transmitted * - * @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO. + * @param entry Object Dictionary entry. * @param subIndex subIndex of the OD variable. * - * @return Return true if event driven TPDO with mapping to OD variable, indicated by flagsPDO and subIndex, was + * @return Return true if event driven TPDO with mapping to OD variable, indicated by entry and subIndex, was * transmitted since last @ref OD_requestTPDO call. If there was no @ref OD_requestTPDO call yet and TPDO was * transmitted by other event, function also returns true. */ static inline bool_t -OD_TPDOtransmitted(uint8_t* flagsPDO, uint8_t subIndex) { +OD_TPDOtransmitted(OD_entry_t* entry, uint8_t subIndex) { #if OD_FLAGS_PDO_SIZE > 0 - if ((flagsPDO != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) { + if ((entry != NULL) && (entry->extension != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) { /* return true, if subIndex-th bit is set */ uint8_t mask = 1U << (subIndex & 0x07U); - if ((flagsPDO[subIndex >> 3] & mask) != 0U) { + if ((entry->extension->flagsPDO[subIndex >> 3] & mask) != 0U) { return true; } } @@ -472,7 +453,7 @@ uint32_t OD_getSDOabCode(ODR_t returnCode); * Read and write functions may be called from different threads, so critical sections in custom functions must be * observed, see @ref CO_critical_sections. * - * @param entry OD entry returned by @ref OD_find(). + * @param entry Object Dictionary entry. * @param extension Extension object, which must be initialized externally. Extension object must exist permanently. If * NULL, extension will be removed. * @@ -496,7 +477,7 @@ OD_extension_init(OD_entry_t* entry, OD_extension_t* extension) { /** * Get variable from Object Dictionary * - * @param entry OD entry returned by @ref OD_find(). + * @param entry Object Dictionary entry. * @param subIndex Sub-index of the variable from the OD object. * @param [out] val Value will be written here. * @param len Size of value to retrieve from OD. @@ -571,7 +552,7 @@ OD_get_f64(const OD_entry_t* entry, uint8_t subIndex, float64_t* val, bool_t odO /** * Set variable in Object Dictionary * - * @param entry OD entry returned by @ref OD_find(). + * @param entry Object Dictionary entry. * @param subIndex Sub-index of the variable from the OD object. * @param val Pointer to value to write. * @param len Size of value to write. @@ -649,7 +630,7 @@ OD_set_f64(const OD_entry_t* entry, uint8_t subIndex, float64_t val, bool_t odOr * Function always returns "dataOrig" pointer, which points to data in the original OD location. Take care, if IO * extension is enabled on OD entry. Take also care that "dataOrig" could be not aligned to data type. * - * @param entry OD entry returned by @ref OD_find(). + * @param entry Object Dictionary entry. * @param subIndex Sub-index of the variable from the OD object. * @param len Required length of the variable. If len is different than zero, then actual length of the variable must * match len or error is returned. From 6ef8956ff92b28c2ede330f6f60c37b4b43c58e2 Mon Sep 17 00:00:00 2001 From: Hannu Korhonen Date: Wed, 13 Nov 2024 09:36:17 +0200 Subject: [PATCH 488/520] Fixed LSS master message byteswapping for big endian system (#554) --- 305/CO_LSSmaster.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/305/CO_LSSmaster.c b/305/CO_LSSmaster.c index 73a1b834..1fb87426 100644 --- a/305/CO_LSSmaster.c +++ b/305/CO_LSSmaster.c @@ -182,16 +182,16 @@ CO_LSSmaster_switchStateSelectInitiate(CO_LSSmaster_t* LSSmaster, CO_LSS_address CO_FLAG_CLEAR(LSSmaster->CANrxNew); (void)memset(&LSSmaster->TXbuff->data[6], 0, sizeof(LSSmaster->TXbuff->data) - 6U); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], CO_SWAP_32(lssAddress->identity.vendorID)); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_PRODUCT; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.productCode); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], CO_SWAP_32(lssAddress->identity.productCode)); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_REV; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.revisionNumber); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], CO_SWAP_32(lssAddress->identity.revisionNumber)); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_SERIAL; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.serialNumber); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], CO_SWAP_32(lssAddress->identity.serialNumber)); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); ret = CO_LSSmaster_WAIT_SLAVE; @@ -480,7 +480,7 @@ CO_LSSmaster_ActivateBit(CO_LSSmaster_t* LSSmaster, uint16_t switchDelay_ms) { CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING; - (void)CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms); + (void)CO_setUint16(&LSSmaster->TXbuff->data[1], CO_SWAP_16(switchDelay_ms)); (void)memset(&LSSmaster->TXbuff->data[3], 0, sizeof(LSSmaster->TXbuff->data) - 3U); (void)CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff); @@ -514,6 +514,7 @@ CO_LSSmaster_inquireCheckWait(CO_LSSmaster_t* LSSmaster, uint32_t timeDifference if (CO_FLAG_READ(LSSmaster->CANrxNew)) { uint8_t cs = LSSmaster->CANrxData[0]; *value = CO_getUint32(&LSSmaster->CANrxData[1]); + *value = CO_SWAP_32(*value); CO_FLAG_CLEAR(LSSmaster->CANrxNew); if (cs == csWait) { @@ -645,7 +646,7 @@ CO_LSSmaster_FsSendMsg(CO_LSSmaster_t* LSSmaster, uint32_t idNumber, uint8_t bit CO_FLAG_CLEAR(LSSmaster->CANrxNew); LSSmaster->TXbuff->data[0] = CO_LSS_IDENT_FASTSCAN; - (void)CO_setUint32(&LSSmaster->TXbuff->data[1], idNumber); + (void)CO_setUint32(&LSSmaster->TXbuff->data[1], CO_SWAP_32(idNumber)); LSSmaster->TXbuff->data[5] = bitCheck; LSSmaster->TXbuff->data[6] = lssSub; LSSmaster->TXbuff->data[7] = lssNext; From a9e2b3c2b048b8eac1735f1d4fd73d2135c780d4 Mon Sep 17 00:00:00 2001 From: temi54c1l8 <163388497+temi54c1l8@users.noreply.github.com> Date: Sat, 1 Mar 2025 16:54:23 +0100 Subject: [PATCH 489/520] add conformance test adaptation for obj: 13FEh and 13FFh (#563) --- 304/CO_SRDO.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index ef0b2bb9..d3d36730 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -311,6 +311,12 @@ OD_write_13FE(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* return ODR_DATA_DEV_STATE; } +#ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION + if (OD_not_write_same_value(stream, buf, count)) { + return ODR_OK; + } +#endif + uint8_t configurationValid = CO_getUint8(buf); if (configurationValid == CO_SRDO_VALID_MAGIC) { SRDOGuard->configurationValid = true; @@ -335,6 +341,12 @@ OD_write_13FF(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* return ODR_DATA_DEV_STATE; } +#ifdef CO_CONFORMANCE_TEST_TOOL_ADAPTATION + if (OD_not_write_same_value(stream, buf, count)) { + return ODR_OK; + } +#endif + /* set OD object 13FE:00 to CO_SRDO_INVALID */ configurationValidUnset(SRDOGuard); From f454a3d82dca058cc64e441fbaefa68a391e4757 Mon Sep 17 00:00:00 2001 From: temi54c1l8 <163388497+temi54c1l8@users.noreply.github.com> Date: Sat, 1 Mar 2025 16:54:38 +0100 Subject: [PATCH 490/520] change for static analysis for CO_RPDO_process function (#564) --- 301/CO_PDO.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 47c538d1..527618b3 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -807,10 +807,10 @@ CO_RPDO_process(CO_RPDO_t* RPDO, } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ - if (verifyLength > CO_PDO_MAX_SIZE || verifyLength != (OD_size_t)PDO->dataLength) { + if ((verifyLength > CO_PDO_MAX_SIZE) || (verifyLength != (OD_size_t)PDO->dataLength)) { /* bug in software, should not happen */ CO_errorReport(PDO->em, CO_EM_GENERIC_SOFTWARE_ERROR, CO_EMC_SOFTWARE_INTERNAL, - (0x100000 | verifyLength)); + (0x100000U | verifyLength)); } } /* while (CO_FLAG_READ(RPDO->CANrxNew[bufNo])) */ @@ -1212,9 +1212,9 @@ CO_TPDOsend(CO_TPDO_t* TPDO) { } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ - if (verifyLength > CO_PDO_MAX_SIZE || verifyLength != (OD_size_t)PDO->dataLength) { + if ((verifyLength > CO_PDO_MAX_SIZE) || (verifyLength != (OD_size_t)PDO->dataLength)) { /* bug in software, should not happen */ - CO_errorReport(PDO->em, CO_EM_GENERIC_SOFTWARE_ERROR, CO_EMC_SOFTWARE_INTERNAL, (0x200000 | verifyLength)); + CO_errorReport(PDO->em, CO_EM_GENERIC_SOFTWARE_ERROR, CO_EMC_SOFTWARE_INTERNAL, (0x200000U | verifyLength)); return CO_ERROR_DATA_CORRUPT; } From 145a15d9449a701c911caa19e98b2f029286da53 Mon Sep 17 00:00:00 2001 From: Janez Date: Wed, 7 May 2025 09:39:51 +0200 Subject: [PATCH 491/520] Update CANopen.c (#577), Issue #576 --- CANopen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CANopen.c b/CANopen.c index 39eeac7c..8306da29 100644 --- a/CANopen.c +++ b/CANopen.c @@ -728,7 +728,7 @@ CO_delete(CO_t* co) { #endif #if ((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0 - free(co->SDOclient); + CO_free(co->SDOclient); #endif /* SDOserver */ From 6dfd4ed7f22ae4b23097cf76c66a909ace5f3622 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 8 Jun 2025 17:43:26 +0200 Subject: [PATCH 492/520] define variable before it is being assigned (#582) --- 301/CO_SDOclient.c | 6 ++++-- 301/CO_SDOserver.c | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/301/CO_SDOclient.c b/301/CO_SDOclient.c index 81146316..8318e60c 100644 --- a/301/CO_SDOclient.c +++ b/301/CO_SDOclient.c @@ -524,10 +524,11 @@ CO_SDOclientDownload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t s if (abortCode == CO_SDO_AB_NONE) { OD_size_t countWritten = 0; + ODR_t odRet; /* write data to Object Dictionary */ CO_LOCK_OD(SDO_C->CANdevTx); - ODR_t odRet = SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, (OD_size_t)count, &countWritten); + odRet = SDO_C->OD_IO.write(&SDO_C->OD_IO.stream, buf, (OD_size_t)count, &countWritten); CO_UNLOCK_OD(SDO_C->CANdevTx); /* verify for errors in write */ @@ -1135,10 +1136,11 @@ CO_SDOclientUpload(CO_SDOclient_t* SDO_C, uint32_t timeDifference_us, bool_t sen OD_size_t countBuf = ((countData > 0U) && (countData <= countFifo)) ? countData : (OD_size_t)countFifo; OD_size_t countRd = 0; uint8_t buf[CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1U]; + ODR_t odRet; /* load data from OD variable into the buffer */ CO_LOCK_OD(SDO_C->CANdevTx); - ODR_t odRet = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, buf, countBuf, &countRd); + odRet = SDO_C->OD_IO.read(&SDO_C->OD_IO.stream, buf, countBuf, &countRd); CO_UNLOCK_OD(SDO_C->CANdevTx); if ((odRet != ODR_OK) && (odRet != ODR_PARTIAL)) { diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 369168b8..728ea3fd 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -469,9 +469,10 @@ validateAndWriteToOD(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, uint8_t /* write data */ OD_size_t countWritten = 0; + ODR_t odRet; CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, SDO->bufOffsetWr, &countWritten); + odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, SDO->buf, SDO->bufOffsetWr, &countWritten); CO_UNLOCK_OD(SDO->CANdevTx); SDO->bufOffsetWr = 0; @@ -523,9 +524,10 @@ readFromOd(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, OD_size_t countMi /* load data from OD variable into the buffer */ OD_size_t countRd = 0; + ODR_t odRet; CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->buf[countRemain], countRdRequest, &countRd); + odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->buf[countRemain], countRdRequest, &countRd); CO_UNLOCK_OD(SDO->CANdevTx); if ((odRet != ODR_OK) && (odRet != ODR_PARTIAL)) { @@ -742,9 +744,10 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t /* Copy data */ OD_size_t countWritten = 0; + ODR_t odRet; CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, dataSizeToWrite, &countWritten); + odRet = SDO->OD_IO.write(&SDO->OD_IO.stream, buf, dataSizeToWrite, &countWritten); CO_UNLOCK_OD(SDO->CANdevTx); if (odRet != ODR_OK) { @@ -1194,9 +1197,10 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t #else /* Expedited transfer only */ /* load data from OD variable */ OD_size_t count = 0; + ODR_t odRet; CO_LOCK_OD(SDO->CANdevTx); - ODR_t odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->CANtxBuff->data[4], 4, &count); + odRet = SDO->OD_IO.read(&SDO->OD_IO.stream, &SDO->CANtxBuff->data[4], 4, &count); CO_UNLOCK_OD(SDO->CANdevTx); /* strings are allowed to be shorter */ From c7a4d26b387a598b1c7973b205229dfa4d32e93e Mon Sep 17 00:00:00 2001 From: Cory Van Beek Date: Tue, 15 Jul 2025 07:00:55 -0600 Subject: [PATCH 493/520] Fix dereference before NULL check (#585) You are right, thank you. --- 301/CO_HBconsumer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 1c361dbc..3430dfa1 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -75,7 +75,10 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t* HBcons, uint8_t */ static ODR_t OD_write_1016(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { - CO_HBconsumer_t* HBcons = stream->object; + CO_HBconsumer_t* HBcons; + if (stream != NULL) { + HBcons = stream->object; + } if ((stream == NULL) || (buf == NULL) || (stream->subIndex < 1U) || (stream->subIndex > HBcons->numberOfMonitoredNodes) || (count != sizeof(uint32_t)) From c804f7de47f5f77faad57cad3879e1a7f059cc62 Mon Sep 17 00:00:00 2001 From: Janez Date: Sun, 27 Jul 2025 01:00:04 +0200 Subject: [PATCH 494/520] Update example/main_blank.c, fix problems with LSS. Other microcontrollers should fix this too, see https://github.com/CANopenNode/CanOpenSTM32/pull/67 --- example/main_blank.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/main_blank.c b/example/main_blank.c index f4c0253b..90dd2936 100644 --- a/example/main_blank.c +++ b/example/main_blank.c @@ -146,7 +146,7 @@ main(void) { } err = CO_CANopenInitPDO(CO, CO->em, OD, activeNodeId, &errInfo); - if (err != CO_ERROR_NO) { + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { if (err == CO_ERROR_OD_PARAMETERS) { log_printf("Error: Object Dictionary entry 0x%X\n", errInfo); } else { From b6e9107a9a32181d715cb45c2c4de0a1bf0a7d2c Mon Sep 17 00:00:00 2001 From: Stefan Tauner Date: Tue, 29 Jul 2025 15:12:44 +0200 Subject: [PATCH 495/520] Refine #585 (#593) In MR #585 the initialization of HBcons has been protected from dereferencing stream if it's NULL. However, the logic is now twisted enough to provoke a maybe-uninitialized warning in GCC 13. While this is strictly a false positive since the generated code would never dereference HBcons if stream == NULL this patch refines the code to be easier to read for compilers and humans alike by returning early if stream == NULL. --- 301/CO_HBconsumer.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/301/CO_HBconsumer.c b/301/CO_HBconsumer.c index 3430dfa1..2216f9c9 100644 --- a/301/CO_HBconsumer.c +++ b/301/CO_HBconsumer.c @@ -76,11 +76,13 @@ static CO_ReturnError_t CO_HBconsumer_initEntry(CO_HBconsumer_t* HBcons, uint8_t static ODR_t OD_write_1016(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { CO_HBconsumer_t* HBcons; - if (stream != NULL) { - HBcons = stream->object; + + if (stream == NULL) { + return ODR_DEV_INCOMPAT; } + HBcons = stream->object; - if ((stream == NULL) || (buf == NULL) || (stream->subIndex < 1U) + if ((buf == NULL) || (stream->subIndex < 1U) || (stream->subIndex > HBcons->numberOfMonitoredNodes) || (count != sizeof(uint32_t)) || (countWritten == NULL)) { return ODR_DEV_INCOMPAT; From ef9ac3a2279e34855a20c787fc1bc48bc995ec22 Mon Sep 17 00:00:00 2001 From: Janez Date: Mon, 4 Aug 2025 18:01:26 +0200 Subject: [PATCH 496/520] CO_gateway_ascii: function CO_GTWA_log_print() fixed. "log" inquiry now works. --- 309/CO_gateway_ascii.c | 6 ++++++ 309/CO_gateway_ascii.h | 1 + 2 files changed, 7 insertions(+) diff --git a/309/CO_gateway_ascii.c b/309/CO_gateway_ascii.c index ed1a1fdc..4e3213a2 100644 --- a/309/CO_gateway_ascii.c +++ b/309/CO_gateway_ascii.c @@ -125,6 +125,10 @@ CO_GTWA_log_print(CO_GTWA_t* gtwa, const char* message) { if ((gtwa != NULL) && (message != NULL)) { const char* c; + /* add newline between messages */ + if (CO_fifo_getOccupied(>wa->logFifo) > 0U) { + CO_fifo_putc_ov(>wa->logFifo, '\n'); + } for (c = &message[0]; *c != '\0'; c++) { CO_fifo_putc_ov(>wa->logFifo, (const uint8_t)*c); } @@ -1918,6 +1922,8 @@ CO_GTWA_process(CO_GTWA_t* gtwa, bool_t enable, uint32_t timeDifference_us, uint #if ((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII_LOG) != 0 /* print message log */ case CO_GTWA_ST_LOG: { + CO_fifo_putc_ov(>wa->logFifo, '\r'); + CO_fifo_putc_ov(>wa->logFifo, '\n'); do { gtwa->respBufCount = CO_fifo_read(>wa->logFifo, (uint8_t*)gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE, NULL); diff --git a/309/CO_gateway_ascii.h b/309/CO_gateway_ascii.h index 7c3947ba..1c1da6d5 100644 --- a/309/CO_gateway_ascii.h +++ b/309/CO_gateway_ascii.h @@ -378,6 +378,7 @@ CO_GTWA_write(CO_GTWA_t* gtwa, const char* buf, size_t count) { * This function enables recording of system log messages including CANopen events. Function can be called by * application for recording any message. Message is copied to internal fifo buffer. In case fifo is full, old messages * will be owerwritten. Message log fifo can be read with non-standard command "log". After log is read, it is emptied. + * Message must not contain "\r\n" inside. Newline character '\n' will be added between the messages automatically. * * @param gtwa This object * @param message Null terminated string From 97f0c4d511cfe90df5c880ce61ed9ee432cd9d4a Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 6 Aug 2025 11:04:52 -0400 Subject: [PATCH 497/520] Adds CANopenNode module Introduces the CANopenNode module, enabling CANopen protocol stack support within the Zephyr RTOS environment. This integration includes: - Kconfig options for configuring CANopenNode features like SDO buffer size, trace buffer size, workqueue parameters, storage, LED indicators, SYNC thread, and program download. - A module.yml file to define the module and its build process. - Zephyr-specific driver and storage implementations (CO_driver_zephyr.c, CO_storage_zephyr.c, CO_driver_target.h, CO_storage_zephyr.h) to interface with Zephyr's CAN driver and settings API. - Configuration option to use Zephyr settings API for object dictionary storage. --- Kconfig | 115 +++++++++ module.yml | 4 + zephyr/CO_driver_target.h | 130 ++++++++++ zephyr/CO_driver_zephyr.c | 514 +++++++++++++++++++++++++++++++++++++ zephyr/CO_storage_zephyr.c | 89 +++++++ zephyr/CO_storage_zephyr.h | 51 ++++ zephyr/Kconfig.zephyr | 15 ++ 7 files changed, 918 insertions(+) create mode 100644 Kconfig create mode 100644 module.yml create mode 100644 zephyr/CO_driver_target.h create mode 100644 zephyr/CO_driver_zephyr.c create mode 100644 zephyr/CO_storage_zephyr.c create mode 100644 zephyr/CO_storage_zephyr.h create mode 100644 zephyr/Kconfig.zephyr diff --git a/Kconfig b/Kconfig new file mode 100644 index 00000000..82910310 --- /dev/null +++ b/Kconfig @@ -0,0 +1,115 @@ +# CANopenNode CANopen protocol stack configuration options + +# Copyright (c) 2019 Vestas Wind Systems A/S +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_CANOPENNODE_MODULE + bool + +config CANOPENNODE + bool "CANopenNode support" + select CRC + depends on CAN && !CAN_FD_MODE + help + This option enables the CANopenNode library. + +if CANOPENNODE + +config CANOPENNODE_SDO_BUFFER_SIZE + int "CANopen SDO buffer size" + default 32 + range 7 889 + help + Size of the internal CANopen SDO buffer in bytes. Size must + be at least equal to the size of the largest variable in the + object dictionary. If data type is DOMAIN, data length is + not limited to the SDO buffer size. If block transfer is + implemented, value should be set to 889. + +config CANOPENNODE_TRACE_BUFFER_SIZE + int "CANopen trace buffer size" + default 100 + help + Size of the CANopen trace buffer in bytes. + +config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE + int "Stack size for the CANopen transmit workqueue" + default 512 + help + Size of the stack used for the internal CANopen transmit + workqueue. + +config CANOPENNODE_TX_WORKQUEUE_PRIORITY + int "Priority for CANopen transmit workqueue" + default 0 if !COOP_ENABLED + default -1 + help + Priority level of the internal CANopen transmit workqueue. + +config CANOPENNODE_STORAGE + bool "CANopen object dictionary storage" + depends on SETTINGS + default y + help + Enable support for storing the CANopen object dictionary to + non-volatile storage. + +config CANOPENNODE_STORAGE_HANDLER_ERASES_EEPROM + bool "Erase CANopen object dictionary EEPROM entries in storage handler" + depends on CANOPENNODE_STORAGE + help + Erase CANopen object dictionary EEPROM entries upon write to + object dictionary index 0x1011 subindex 1. + +config CANOPENNODE_LEDS + bool "CANopen LED indicators" + default y + help + Enable support for CANopen LED indicators according to the CiA + 303-3 specification. + +config CANOPENNODE_LEDS_BICOLOR + bool "CANopen bicolor LED indicator" + depends on CANOPENNODE_LEDS + help + Handle CANopen LEDs as one bicolor LED, favoring the red LED + over the green LED in accordance with the CiA 303-3 + specification. + +config CANOPENNODE_SYNC_THREAD + bool "CANopen SYNC thread" + default y + help + Enable internal thread for processing CANopen SYNC RPDOs and + TPDOs. Application layer must take care of SYNC RPDO and + TPDO processing on its own if this is disabled. + +config CANOPENNODE_SYNC_THREAD_STACK_SIZE + int "Stack size for the CANopen SYNC thread" + depends on CANOPENNODE_SYNC_THREAD + default 512 + help + Size of the stack used for the internal thread which + processes CANopen SYNC RPDOs and TPDOs. + +config CANOPENNODE_SYNC_THREAD_PRIORITY + int "Priority for CANopen SYNC thread" + depends on CANOPENNODE_SYNC_THREAD + default 0 if !COOP_ENABLED + default -5 + help + Priority level of the internal thread which processes + CANopen SYNC RPDOs and TPDOs. + +config CANOPENNODE_PROGRAM_DOWNLOAD + bool "CANopen program download" + depends on BOOTLOADER_MCUBOOT + select IMG_MANAGER + default y + help + Enable support for program download over CANopen according + to the CiA 302-3 (draft) specification. + +endif # CANOPENNODE + +source "zephyr/Kconfig.zephyr" diff --git a/module.yml b/module.yml new file mode 100644 index 00000000..0bb04b6b --- /dev/null +++ b/module.yml @@ -0,0 +1,4 @@ +# modules/canopennode/module.yml +name: canopennode +build: + cmake: . diff --git a/zephyr/CO_driver_target.h b/zephyr/CO_driver_target.h new file mode 100644 index 00000000..a4023579 --- /dev/null +++ b/zephyr/CO_driver_target.h @@ -0,0 +1,130 @@ +/* + * Device and application specific definitions for CANopenNode. + * + * @file CO_driver_target.h + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#ifndef CO_DRIVER_TARGET_H +#define CO_DRIVER_TARGET_H + +/* This file contains device and application specific definitions. It is included from CO_driver.h, which contains + * documentation for common definitions below. */ + +#include +#include +#include + +#ifdef CO_DRIVER_CUSTOM +#include "CO_driver_custom.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Stack configuration override default values. For more information see file CO_config.h. */ + +/* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ +#define CO_LITTLE_ENDIAN +#define CO_SWAP_16(x) x +#define CO_SWAP_32(x) x +#define CO_SWAP_64(x) x +/* NULL is defined in stddef.h */ +/* true and false are defined in stdbool.h */ +/* int8_t to uint64_t are defined in stdint.h */ +typedef uint_fast8_t bool_t; +typedef float float32_t; +typedef double float64_t; + +/* Access to received CAN message */ +#define CO_CANrxMsg_readIdent(msg) ((uint16_t)0) +#define CO_CANrxMsg_readDLC(msg) ((uint8_t)0) +#define CO_CANrxMsg_readData(msg) ((const uint8_t*)NULL) + +/* Received message object */ +typedef struct { + uint16_t ident; + uint16_t mask; + void* object; + void (*CANrx_callback)(void* object, void* message); +} CO_CANrx_t; + +/* Transmit message object */ +typedef struct { + uint32_t ident; + uint8_t DLC; + uint8_t data[8]; + volatile bool_t bufferFull; + volatile bool_t syncFlag; +} CO_CANtx_t; + +/* CAN module object */ +typedef struct { + void* CANptr; + CO_CANrx_t* rxArray; + uint16_t rxSize; + CO_CANtx_t* txArray; + uint16_t txSize; + uint16_t CANerrorStatus; + volatile bool_t CANnormal; + volatile bool_t useCANrxFilters; + volatile bool_t bufferInhibitFlag; + volatile bool_t firstCANtxMessage; + volatile uint16_t CANtxCount; + uint32_t errOld; +} CO_CANmodule_t; + +/* Data storage object for one entry */ +typedef struct { + void* addr; + size_t len; + uint8_t subIndexOD; + uint8_t attr; + /* Additional variables (target specific) */ + void* addrNV; +} CO_storage_entry_t; + +/* (un)lock critical section in CO_CANsend() */ +#define CO_LOCK_CAN_SEND(CAN_MODULE) +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) + +/* (un)lock critical section in CO_errorReport() or CO_errorReset() */ +#define CO_LOCK_EMCY(CAN_MODULE) +#define CO_UNLOCK_EMCY(CAN_MODULE) + +/* (un)lock critical section when accessing Object Dictionary */ +#define CO_LOCK_OD(CAN_MODULE) +#define CO_UNLOCK_OD(CAN_MODULE) + +/* Synchronization between CAN receive and message processing threads. */ +#define CO_MemoryBarrier() +#define CO_FLAG_READ(rxNew) ((rxNew) != NULL) +#define CO_FLAG_SET(rxNew) \ + { \ + CO_MemoryBarrier(); \ + rxNew = (void*)1L; \ + } +#define CO_FLAG_CLEAR(rxNew) \ + { \ + CO_MemoryBarrier(); \ + rxNew = NULL; \ + } + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CO_DRIVER_TARGET_H */ diff --git a/zephyr/CO_driver_zephyr.c b/zephyr/CO_driver_zephyr.c new file mode 100644 index 00000000..0154d042 --- /dev/null +++ b/zephyr/CO_driver_zephyr.c @@ -0,0 +1,514 @@ +/* + * CAN module object for generic microcontroller. + * + * This file is a template for other microcontrollers. + * + * @file CO_driver.c + * @ingroup CO_driver + * @author Janez Paternoster + * @copyright 2004 - 2020 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#include "301/CO_driver.h" + +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_CANOPEN_LOG_LEVEL +#include +LOG_MODULE_REGISTER(canopen_driver); + +struct k_work_q canopen_tx_workq; + +struct canopen_tx_work_container { + struct k_work work; + CO_CANmodule_t *CANmodule; +}; + +struct canopen_tx_work_container canopen_tx_queue; + +K_MUTEX_DEFINE(canopen_send_mutex); +K_MUTEX_DEFINE(canopen_emcy_mutex); +K_MUTEX_DEFINE(canopen_co_mutex); + +static canopen_rxmsg_callback_t rxmsg_callback; + +void canopen_set_rxmsg_callback(canopen_rxmsg_callback_t callback) +{ + rxmsg_callback = callback; +} + +static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule) +{ + uint16_t i; + + if (!CANmodule || !CANmodule->rx_array || !CANmodule->configured) { + return; + } + + for (i = 0U; i < CANmodule->rx_size; i++) { + if (CANmodule->rx_array[i].filter_id != -ENOSPC) { + can_remove_rx_filter(CANmodule->dev, + CANmodule->rx_array[i].filter_id); + CANmodule->rx_array[i].filter_id = -ENOSPC; + } + } +} + +static void canopen_rx_callback(const struct device *dev, struct can_frame *frame, void *user_data) +{ + CO_CANmodule_t *CANmodule = (CO_CANmodule_t *)user_data; + CO_CANrxMsg_t rxMsg; + CO_CANrx_t *buffer; + canopen_rxmsg_callback_t callback = rxmsg_callback; + int i; + + ARG_UNUSED(dev); + + /* Loop through registered rx buffers in priority order */ + for (i = 0; i < CANmodule->rx_size; i++) { + buffer = &CANmodule->rx_array[i]; + + if (buffer->filter_id == -ENOSPC || buffer->pFunct == NULL) { + continue; + } + + if (((frame->id ^ buffer->ident) & buffer->mask) == 0U) { +#ifdef CONFIG_CAN_ACCEPT_RTR + if (buffer->rtr && ((frame->flags & CAN_FRAME_RTR) == 0U)) { + continue; + } +#endif /* CONFIG_CAN_ACCEPT_RTR */ + rxMsg.ident = frame->id; + rxMsg.DLC = frame->dlc; + memcpy(rxMsg.data, frame->data, frame->dlc); + buffer->pFunct(buffer->object, &rxMsg); + if (callback != NULL) { + callback(); + } + break; + } + } +} + +static void canopen_tx_callback(const struct device *dev, int error, void *arg) +{ + CO_CANmodule_t *CANmodule = arg; + + ARG_UNUSED(dev); + + if (!CANmodule) { + LOG_ERR("failed to process CAN tx callback"); + return; + } + + if (error == 0) { + CANmodule->first_tx_msg = false; + } + + k_work_submit_to_queue(&canopen_tx_workq, &canopen_tx_queue.work); +} + +static void canopen_tx_retry(struct k_work *item) +{ + struct canopen_tx_work_container *container = + CONTAINER_OF(item, struct canopen_tx_work_container, work); + CO_CANmodule_t *CANmodule = container->CANmodule; + struct can_frame frame; + CO_CANtx_t *buffer; + int err; + uint16_t i; + + memset(&frame, 0, sizeof(frame)); + + CO_LOCK_CAN_SEND(); + + for (i = 0; i < CANmodule->tx_size; i++) { + buffer = &CANmodule->tx_array[i]; + if (buffer->bufferFull) { + frame.id = buffer->ident; + frame.dlc = buffer->DLC; + frame.flags |= (buffer->rtr ? CAN_FRAME_RTR : 0); + memcpy(frame.data, buffer->data, buffer->DLC); + + err = can_send(CANmodule->dev, &frame, K_NO_WAIT, + canopen_tx_callback, CANmodule); + if (err == -EAGAIN) { + break; + } else if (err != 0) { + LOG_ERR("failed to send CAN frame (err %d)", + err); + CO_errorReport(CANmodule->em, + CO_EM_GENERIC_SOFTWARE_ERROR, + CO_EMC_COMMUNICATION, 0); + + } + + buffer->bufferFull = false; + } + } + + CO_UNLOCK_CAN_SEND(); +} + + +void +CO_CANsetConfigurationMode(void* CANptr) { + struct canopen_context *ctx = (struct canopen_context *)CANdriverState; + int err; + + err = can_stop(ctx->dev); + if (err != 0 && err != -EALREADY) { + LOG_ERR("failed to stop CAN interface (err %d)", err); + } +} + +void +CO_CANsetNormalMode(CO_CANmodule_t* CANmodule) { + int err; + + err = can_start(CANmodule->dev); + if (err != 0 && err != -EALREADY) { + LOG_ERR("failed to start CAN interface (err %d)", err); + return; + } + + CANmodule->CANnormal = true; +} + +CO_ReturnError_t +CO_CANmodule_init(CO_CANmodule_t* CANmodule, void* CANptr, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], + uint16_t txSize, uint16_t CANbitRate) { + uint16_t i; + + /* verify arguments */ + if (CANmodule == NULL || rxArray == NULL || txArray == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* Configure object variables */ + CANmodule->CANptr = CANptr; + CANmodule->rxArray = rxArray; + CANmodule->rxSize = rxSize; + CANmodule->txArray = txArray; + CANmodule->txSize = txSize; + CANmodule->CANerrorStatus = 0; + CANmodule->CANnormal = false; + CANmodule->useCANrxFilters = (rxSize <= 32U) ? true : false; /* microcontroller dependent */ + CANmodule->bufferInhibitFlag = false; + CANmodule->firstCANtxMessage = true; + CANmodule->CANtxCount = 0U; + CANmodule->errOld = 0U; + + for (i = 0U; i < rxSize; i++) { + rxArray[i].ident = 0U; + rxArray[i].mask = 0xFFFFU; + rxArray[i].object = NULL; + rxArray[i].CANrx_callback = NULL; + } + for (i = 0U; i < txSize; i++) { + txArray[i].bufferFull = false; + } + + /* Configure CAN module registers */ + + /* Configure CAN timing */ + + /* Configure CAN module hardware filters */ + if (CANmodule->useCANrxFilters) { + /* CAN module filters are used, they will be configured with */ + /* CO_CANrxBufferInit() functions, called by separate CANopen */ + /* init functions. */ + /* Configure all masks so, that received message must match filter */ + } else { + /* CAN module filters are not used, all messages with standard 11-bit */ + /* identifier will be received */ + /* Configure mask 0 so, that all messages with standard identifier are accepted */ + } + + /* configure CAN interrupt registers */ + + return CO_ERROR_NO; +} + +void +CO_CANmodule_disable(CO_CANmodule_t* CANmodule) { + int err; + + if (!CANmodule || !CANmodule->dev) { + return; + } + + canopen_detach_all_rx_filters(CANmodule); + + err = can_stop(CANmodule->dev); + if (err != 0 && err != -EALREADY) { + LOG_ERR("failed to disable CAN interface (err %d)", err); + } +} + +CO_ReturnError_t +CO_CANrxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, uint16_t mask, bool_t rtr, void* object, + void (*CANrx_callback)(void* object, void* message)) { + CO_ReturnError_t ret = CO_ERROR_NO; + + if ((CANmodule != NULL) && (object != NULL) && (CANrx_callback != NULL) && (index < CANmodule->rxSize)) { + /* buffer, which will be configured */ + CO_CANrx_t* buffer = &CANmodule->rxArray[index]; + + /* Configure object variables */ + buffer->object = object; + buffer->CANrx_callback = CANrx_callback; + + /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */ + buffer->ident = ident & 0x07FFU; + if (rtr) { + buffer->ident |= 0x0800U; + } + buffer->mask = (mask & 0x07FFU) | 0x0800U; + + /* Set CAN hardware module filter and mask. */ + if (CANmodule->useCANrxFilters) {} + } else { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; +} + +CO_CANtx_t* +CO_CANtxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, bool_t rtr, uint8_t noOfBytes, + bool_t syncFlag) { + CO_CANtx_t* buffer = NULL; + + if ((CANmodule != NULL) && (index < CANmodule->txSize)) { + /* get specific buffer */ + buffer = &CANmodule->txArray[index]; + + /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer, microcontroller specific. */ + buffer->ident = ((uint32_t)ident & 0x07FFU) | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) + | ((uint32_t)(rtr ? 0x8000U : 0U)); + + buffer->bufferFull = false; + buffer->syncFlag = syncFlag; + } + + return buffer; +} + +CO_ReturnError_t +CO_CANsend(CO_CANmodule_t* CANmodule, CO_CANtx_t* buffer) { + CO_ReturnError_t err = CO_ERROR_NO; + + /* Verify overflow */ + if (buffer->bufferFull) { + if (!CANmodule->firstCANtxMessage) { + /* don't set error, if bootup message is still on buffers */ + CANmodule->CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; + } + err = CO_ERROR_TX_OVERFLOW; + } + + CO_LOCK_CAN_SEND(CANmodule); + /* if CAN TX buffer is free, copy message to it */ + if (1 && CANmodule->CANtxCount == 0) { + CANmodule->bufferInhibitFlag = buffer->syncFlag; + /* copy message and txRequest */ + } + /* if no buffer is free, message will be sent by interrupt */ + else { + buffer->bufferFull = true; + CANmodule->CANtxCount++; + } + CO_UNLOCK_CAN_SEND(CANmodule); + + return err; +} + +void +CO_CANclearPendingSyncPDOs(CO_CANmodule_t* CANmodule) { + uint32_t tpdoDeleted = 0U; + + CO_LOCK_CAN_SEND(CANmodule); + /* Abort message from CAN module, if there is synchronous TPDO. + * Take special care with this functionality. */ + if (/* messageIsOnCanBuffer && */ CANmodule->bufferInhibitFlag) { + /* clear TXREQ */ + CANmodule->bufferInhibitFlag = false; + tpdoDeleted = 1U; + } + /* delete also pending synchronous TPDOs in TX buffers */ + if (CANmodule->CANtxCount != 0U) { + uint16_t i; + CO_CANtx_t* buffer = &CANmodule->txArray[0]; + for (i = CANmodule->txSize; i > 0U; i--) { + if (buffer->bufferFull) { + if (buffer->syncFlag) { + buffer->bufferFull = false; + CANmodule->CANtxCount--; + tpdoDeleted = 2U; + } + } + buffer++; + } + } + CO_UNLOCK_CAN_SEND(CANmodule); + + if (tpdoDeleted != 0U) { + CANmodule->CANerrorStatus |= CO_CAN_ERRTX_PDO_LATE; + } +} + +/* Get error counters from the module. If necessary, function may use different way to determine errors. */ +static uint16_t rxErrors = 0, txErrors = 0, overflow = 0; + +void +CO_CANmodule_process(CO_CANmodule_t* CANmodule) { + uint32_t err; + + err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; + + if (CANmodule->errOld != err) { + uint16_t status = CANmodule->CANerrorStatus; + + CANmodule->errOld = err; + + if (txErrors >= 256U) { + /* bus off */ + status |= CO_CAN_ERRTX_BUS_OFF; + } else { + /* recalculate CANerrorStatus, first clear some flags */ + status &= 0xFFFF + ^ (CO_CAN_ERRTX_BUS_OFF | CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE | CO_CAN_ERRTX_WARNING + | CO_CAN_ERRTX_PASSIVE); + + /* rx bus warning or passive */ + if (rxErrors >= 128) { + status |= CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE; + } else if (rxErrors >= 96) { + status |= CO_CAN_ERRRX_WARNING; + } + + /* tx bus warning or passive */ + if (txErrors >= 128) { + status |= CO_CAN_ERRTX_WARNING | CO_CAN_ERRTX_PASSIVE; + } else if (txErrors >= 96) { + status |= CO_CAN_ERRTX_WARNING; + } + + /* if not tx passive clear also overflow */ + if ((status & CO_CAN_ERRTX_PASSIVE) == 0) { + status &= 0xFFFF ^ CO_CAN_ERRTX_OVERFLOW; + } + } + + if (overflow != 0) { + /* CAN RX bus overflow */ + status |= CO_CAN_ERRRX_OVERFLOW; + } + + CANmodule->CANerrorStatus = status; + } +} + +typedef struct { + uint32_t ident; + uint8_t DLC; + uint8_t data[8]; +} CO_CANrxMsg_t; + +void +CO_CANinterrupt(CO_CANmodule_t* CANmodule) { + + /* receive interrupt */ + if (1) { + CO_CANrxMsg_t* rcvMsg; /* pointer to received message in CAN module */ + uint16_t index; /* index of received message */ + uint32_t rcvMsgIdent; /* identifier of the received message */ + CO_CANrx_t* buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ + bool_t msgMatched = false; + + rcvMsg = 0; /* get message from module here */ + rcvMsgIdent = rcvMsg->ident; + if (CANmodule->useCANrxFilters) { + /* CAN module filters are used. Message with known 11-bit identifier has been received */ + index = 0; /* get index of the received message here. Or something similar */ + if (index < CANmodule->rxSize) { + buffer = &CANmodule->rxArray[index]; + /* verify also RTR */ + if (((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) { + msgMatched = true; + } + } + } else { + /* CAN module filters are not used, message with any standard 11-bit identifier */ + /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ + buffer = &CANmodule->rxArray[0]; + for (index = CANmodule->rxSize; index > 0U; index--) { + if (((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) { + msgMatched = true; + break; + } + buffer++; + } + } + + /* Call specific function, which will process the message */ + if (msgMatched && (buffer != NULL) && (buffer->CANrx_callback != NULL)) { + buffer->CANrx_callback(buffer->object, (void*)rcvMsg); + } + + /* Clear interrupt flag */ + } + + /* transmit interrupt */ + else if (0) { + /* Clear interrupt flag */ + + /* First CAN message (bootup) was sent successfully */ + CANmodule->firstCANtxMessage = false; + /* clear flag from previous message */ + CANmodule->bufferInhibitFlag = false; + /* Are there any new messages waiting to be send */ + if (CANmodule->CANtxCount > 0U) { + uint16_t i; /* index of transmitting message */ + + /* first buffer */ + CO_CANtx_t* buffer = &CANmodule->txArray[0]; + /* search through whole array of pointers to transmit message buffers. */ + for (i = CANmodule->txSize; i > 0U; i--) { + /* if message buffer is full, send it. */ + if (buffer->bufferFull) { + buffer->bufferFull = false; + CANmodule->CANtxCount--; + + /* Copy message to CAN buffer */ + CANmodule->bufferInhibitFlag = buffer->syncFlag; + /* canSend... */ + break; /* exit for loop */ + } + buffer++; + } /* end of for loop */ + + /* Clear counter if no more messages */ + if (i == 0U) { + CANmodule->CANtxCount = 0U; + } + } + } else { + /* some other interrupt reason */ + } +} diff --git a/zephyr/CO_storage_zephyr.c b/zephyr/CO_storage_zephyr.c new file mode 100644 index 00000000..a2306a5c --- /dev/null +++ b/zephyr/CO_storage_zephyr.c @@ -0,0 +1,89 @@ +/* + * CANopen Object Dictionary storage object (blank example). + * + * @file CO_storageBlank.c + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#include "CO_storageBlank.h" + +#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE + +/* + * Function for writing data on "Store parameters" command - OD object 1010 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t +storeBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { + + /* Open a file and write data to it */ + /* file = open(entry->pathToFileOrPointerToMemory); */ + /* write(entry->addr, entry->len, file); */ + + return ODR_OK; +} + +/* + * Function for restoring data on "Restore default parameters" command - OD 1011 + * + * For more information see file CO_storage.h, CO_storage_entry_t. + */ +static ODR_t +restoreBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { + + /* disable (delete) the file, so default values will stay after startup */ + + return ODR_OK; +} + +CO_ReturnError_t +CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, + OD_entry_t* OD_1011_RestoreDefaultParam, CO_storage_entry_t* entries, uint8_t entriesCount, + uint32_t* storageInitError) { + CO_ReturnError_t ret; + + /* verify arguments */ + if (storage == NULL || entries == NULL || entriesCount == 0 || storageInitError == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* initialize storage and OD extensions */ + ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeBlank, + restoreBlank, entries, entriesCount); + if (ret != CO_ERROR_NO) { + return ret; + } + + /* initialize entries */ + *storageInitError = 0; + for (uint8_t i = 0; i < entriesCount; i++) { + CO_storage_entry_t* entry = &entries[i]; + + /* verify arguments */ + if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { + *storageInitError = i; + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* Open a file and read data from file to entry->addr */ + /* file = open(entry->pathToFileOrPointerToMemory); */ + /* read(entry->addr, entry->len, file); */ + } + + return ret; +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/zephyr/CO_storage_zephyr.h b/zephyr/CO_storage_zephyr.h new file mode 100644 index 00000000..48813ea9 --- /dev/null +++ b/zephyr/CO_storage_zephyr.h @@ -0,0 +1,51 @@ +/* + * CANopen data storage object (blank example) + * + * @file CO_storageBlank.h + * @author Janez Paternoster + * @copyright 2021 Janez Paternoster + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#ifndef CO_STORAGE_BLANK_H +#define CO_STORAGE_BLANK_H + +#include "storage/CO_storage.h" + +#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This is very basic example of implementing (object dictionary) data storage. Data storage is target specific. + * CO_storageBlank.h and .c files only shows the basic principle, but does nothing. For complete example of storage see: + * - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c, CANopenNode/storage/CO_storageEeprom.h/.c, + * CANopenNode/storage/CO_eeprom.h and CANopenPIC/PIC32/CO_eepromPIC32.c files. + * - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and CANopenLinux/CO_storageLinux.h files. + */ + +CO_ReturnError_t CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, + OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, + CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); + +uint32_t CO_storageBlank_auto_process(CO_storage_t* storage, bool_t closeFiles); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +#endif /* CO_STORAGE_BLANK_H */ diff --git a/zephyr/Kconfig.zephyr b/zephyr/Kconfig.zephyr new file mode 100644 index 00000000..fd574c45 --- /dev/null +++ b/zephyr/Kconfig.zephyr @@ -0,0 +1,15 @@ +config CANOPENNODE_TARGET_ZEPHYR + bool "Enable Zephyr CANopen backend" + depends on CANOPENNODE + default y + help + Use Zephyr RTOS-specific CANopenNode interface for CAN and storage. + This enables CO_driver_zephyr.c and CO_storage_zephyr.c. + +# Optional override for storage backend +config CANOPENNODE_ZEPHYR_STORAGE_SETTINGS + bool "Use Zephyr settings API for OD storage" + depends on CANOPENNODE_TARGET_ZEPHYR && CANOPENNODE_STORAGE + default y + help + Use Zephyr's settings subsystem to persist CANopen Object Dictionary parameters. From 456c8a48c41ea5771221d5093a7cd65a66774ae9 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 6 Aug 2025 13:07:51 -0400 Subject: [PATCH 498/520] Adds CANopenNode module Adds a CANopenNode module with Zephyr RTOS support. This commit introduces a new module for CANopenNode, a CANopen stack, integrated with the Zephyr RTOS. It includes the core CANopen stack (CiA 301) and optional features like Heartbeat consumer & LSS (CiA 305), LEDs (CiA 303-3), SYNC thread (CiA 303-6), Storage (OD persistence), Program download (CiA 302-3 draft), ASCII gateway (CiA 309), and extra utilities. A Zephyr-specific CAN driver glue is also included. Also add .clang-format file, and target specific device driver definition. --- CMakeLists.txt | 66 +++++ zephyr/.clang-format | 116 ++++++++ zephyr/CO_driver_target.h | 140 +++++---- zephyr/CO_driver_zephyr.c | 581 ++++++++++++++++++-------------------- 4 files changed, 533 insertions(+), 370 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 zephyr/.clang-format diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..166e8173 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_CANOPENNODE) + + set(CANOPENNODE_DIR ${ZEPHYR_CURRENT_MODULE_DIR}) + + zephyr_library() + + zephyr_include_directories( + ${CANOPENNODE_DIR} + ${CANOPENNODE_DIR}/301 + ${CANOPENNODE_DIR}/303 + ${CANOPENNODE_DIR}/304 + ${CANOPENNODE_DIR}/305 + ${CANOPENNODE_DIR}/309 + ${CANOPENNODE_DIR}/extra + ${CANOPENNODE_DIR}/storage + ${CANOPENNODE_DIR}/zephyr + ) + + # === Core CANopen Stack (CiA 301) === + zephyr_library_sources( + ${CANOPENNODE_DIR}/CANopen.c + ${CANOPENNODE_DIR}/301/CO_Emergency.c + ${CANOPENNODE_DIR}/301/CO_NMT_Heartbeat.c + ${CANOPENNODE_DIR}/301/CO_PDO.c + ${CANOPENNODE_DIR}/301/CO_SDO.c + ${CANOPENNODE_DIR}/301/CO_SYNC.c + ${CANOPENNODE_DIR}/301/CO_TIME.c + ${CANOPENNODE_DIR}/301/CO_driver.c + ${CANOPENNODE_DIR}/301/CO_ODinterface.c + ${CANOPENNODE_DIR}/301/CO_fifo.c + ${CANOPENNODE_DIR}/301/CO_trace.c + ) + + # === Optional Features === + + # Heartbeat consumer & LSS (CiA 305) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_305 ${CANOPENNODE_DIR}/305/CO_HBconsumer.c) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_305 ${CANOPENNODE_DIR}/305/CO_LSSmaster.c) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_305 ${CANOPENNODE_DIR}/305/CO_LSSslave.c) + + # LEDs (CiA 303-3) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_LEDS ${CANOPENNODE_DIR}/303/CO_LEDs.c) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_LEDS ${CANOPENNODE_DIR}/zephyr/canopen_leds.c) + + # SYNC thread (CiA 303-6) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD ${CANOPENNODE_DIR}/zephyr/canopen_sync.c) + + # Storage (OD persistence) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_STORAGE ${CANOPENNODE_DIR}/storage/CO_storageBlank.c) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_STORAGE ${CANOPENNODE_DIR}/zephyr/canopen_storage.c) + + # Program download (CiA 302-3 draft) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_PROGRAM_DOWNLOAD ${CANOPENNODE_DIR}/zephyr/canopen_program.c) + + # ASCII gateway (CiA 309) + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_309 ${CANOPENNODE_DIR}/309/CO_gateway_ascii.c) + + # Extra utilities + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_EXTRA ${CANOPENNODE_DIR}/extra/CO_extra.c) + + # Zephyr-specific CAN driver glue + zephyr_library_sources(${CANOPENNODE_DIR}/zephyr/CO_driver_blank.c) + +endif() diff --git a/zephyr/.clang-format b/zephyr/.clang-format new file mode 100644 index 00000000..e0982b80 --- /dev/null +++ b/zephyr/.clang-format @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Note: The list of ForEachMacros can be obtained using: +# +# git grep -h '^#define [^[:space:]]*FOR_EACH[^[:space:]]*(' include/ \ +# | sed "s,^#define \([^[:space:]]*FOR_EACH[^[:space:]]*\)(.*$, - '\1'," \ +# | sort | uniq +# +# References: +# - https://clang.llvm.org/docs/ClangFormatStyleOptions.html + +--- +BasedOnStyle: LLVM +AlignConsecutiveMacros: AcrossComments +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AttributeMacros: + - __aligned + - __deprecated + - __packed + - __printf_like + - __syscall + - __syscall_always_inline + - __subsystem +BitFieldColonSpacing: After +BreakBeforeBraces: Linux +ColumnLimit: 100 +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +ForEachMacros: + - 'ARRAY_FOR_EACH' + - 'ARRAY_FOR_EACH_PTR' + - 'FOR_EACH' + - 'FOR_EACH_FIXED_ARG' + - 'FOR_EACH_IDX' + - 'FOR_EACH_IDX_FIXED_ARG' + - 'FOR_EACH_NONEMPTY_TERM' + - 'FOR_EACH_FIXED_ARG_NONEMPTY_TERM' + - 'RB_FOR_EACH' + - 'RB_FOR_EACH_CONTAINER' + - 'SYS_DLIST_FOR_EACH_CONTAINER' + - 'SYS_DLIST_FOR_EACH_CONTAINER_SAFE' + - 'SYS_DLIST_FOR_EACH_NODE' + - 'SYS_DLIST_FOR_EACH_NODE_SAFE' + - 'SYS_SEM_LOCK' + - 'SYS_SFLIST_FOR_EACH_CONTAINER' + - 'SYS_SFLIST_FOR_EACH_CONTAINER_SAFE' + - 'SYS_SFLIST_FOR_EACH_NODE' + - 'SYS_SFLIST_FOR_EACH_NODE_SAFE' + - 'SYS_SLIST_FOR_EACH_CONTAINER' + - 'SYS_SLIST_FOR_EACH_CONTAINER_SAFE' + - 'SYS_SLIST_FOR_EACH_NODE' + - 'SYS_SLIST_FOR_EACH_NODE_SAFE' + - '_WAIT_Q_FOR_EACH' + - 'Z_FOR_EACH' + - 'Z_FOR_EACH_ENGINE' + - 'Z_FOR_EACH_EXEC' + - 'Z_FOR_EACH_FIXED_ARG' + - 'Z_FOR_EACH_FIXED_ARG_EXEC' + - 'Z_FOR_EACH_IDX' + - 'Z_FOR_EACH_IDX_EXEC' + - 'Z_FOR_EACH_IDX_FIXED_ARG' + - 'Z_FOR_EACH_IDX_FIXED_ARG_EXEC' + - 'Z_GENLIST_FOR_EACH_CONTAINER' + - 'Z_GENLIST_FOR_EACH_CONTAINER_SAFE' + - 'Z_GENLIST_FOR_EACH_NODE' + - 'Z_GENLIST_FOR_EACH_NODE_SAFE' + - 'STRUCT_SECTION_FOREACH' + - 'STRUCT_SECTION_FOREACH_ALTERNATE' + - 'TYPE_SECTION_FOREACH' + - 'K_SPINLOCK' + - 'COAP_RESOURCE_FOREACH' + - 'COAP_SERVICE_FOREACH' + - 'COAP_SERVICE_FOREACH_RESOURCE' + - 'HTTP_RESOURCE_FOREACH' + - 'HTTP_SERVER_CONTENT_TYPE_FOREACH' + - 'HTTP_SERVICE_FOREACH' + - 'HTTP_SERVICE_FOREACH_RESOURCE' + - 'I3C_BUS_FOR_EACH_I3CDEV' + - 'I3C_BUS_FOR_EACH_I2CDEV' + - 'MIN_HEAP_FOREACH' +IfMacros: + - 'CHECKIF' +# Disabled for now, see bug https://github.com/zephyrproject-rtos/zephyr/issues/48520 +#IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^".*\.h"$' + Priority: 0 + - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|limits|locale|math|setjmp|signal|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|wchar|wctype)\.h>$' + Priority: 1 + - Regex: '^\$' + Priority: 2 + - Regex: '.*' + Priority: 3 +IndentCaseLabels: false +IndentGotoLabels: false +IndentWidth: 8 +InsertBraces: true +InsertNewlineAtEOF: true +SpaceBeforeInheritanceColon: False +SpaceBeforeParens: ControlStatementsExceptControlMacros +SortIncludes: Never +UseTab: ForContinuationAndIndentation +WhitespaceSensitiveMacros: + - COND_CODE_0 + - COND_CODE_1 + - IF_DISABLED + - IF_ENABLED + - LISTIFY + - STRINGIFY + - Z_STRINGIFY + - DT_FOREACH_PROP_ELEM_SEP diff --git a/zephyr/CO_driver_target.h b/zephyr/CO_driver_target.h index a4023579..6015bdd8 100644 --- a/zephyr/CO_driver_target.h +++ b/zephyr/CO_driver_target.h @@ -12,36 +12,54 @@ * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ -#ifndef CO_DRIVER_TARGET_H -#define CO_DRIVER_TARGET_H - -/* This file contains device and application specific definitions. It is included from CO_driver.h, which contains - * documentation for common definitions below. */ +/* + * Copyright (c) 2019 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ -#include -#include -#include +#ifndef ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_H +#define ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_H -#ifdef CO_DRIVER_CUSTOM -#include "CO_driver_custom.h" -#endif +/* + * Zephyr RTOS CAN driver interface and configuration for CANopenNode + * CANopen protocol stack. + * + * See CANopenNode/example/CO_driver_blank.h for API description. + */ #ifdef __cplusplus extern "C" { #endif +#include +#include +#include +#include +#include +#include /* float32_t, float64_t */ + /* Stack configuration override default values. For more information see file CO_config.h. */ /* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ +#ifdef CONFIG_LITTLE_ENDIAN #define CO_LITTLE_ENDIAN #define CO_SWAP_16(x) x #define CO_SWAP_32(x) x #define CO_SWAP_64(x) x +#else +#define CO_BIG_ENDIAN +#define CO_SWAP_16(x) sys_cpu_to_be16(x) +#define CO_SWAP_32(x) sys_cpu_to_be32(x) +#define CO_SWAP_64(x) sys_cpu_to_be64(x) +#endif + /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ @@ -49,82 +67,86 @@ typedef uint_fast8_t bool_t; typedef float float32_t; typedef double float64_t; +// typedef char char_t; +// typedef unsigned char oChar_t; +// typedef unsigned char domain_t; + + /* Access to received CAN message */ #define CO_CANrxMsg_readIdent(msg) ((uint16_t)0) #define CO_CANrxMsg_readDLC(msg) ((uint8_t)0) -#define CO_CANrxMsg_readData(msg) ((const uint8_t*)NULL) +#define CO_CANrxMsg_readData(msg) ((const uint8_t *)NULL) /* Received message object */ typedef struct { - uint16_t ident; - uint16_t mask; - void* object; - void (*CANrx_callback)(void* object, void* message); + int filter_id; + uint16_t ident; + uint16_t mask; + void *object; + void (*CANrx_callback)(void *object, void *message); } CO_CANrx_t; /* Transmit message object */ typedef struct { - uint32_t ident; - uint8_t DLC; - uint8_t data[8]; - volatile bool_t bufferFull; - volatile bool_t syncFlag; + uint32_t ident; + uint8_t DLC; + uint8_t data[8]; + volatile bool_t bufferFull; + volatile bool_t syncFlag; } CO_CANtx_t; /* CAN module object */ typedef struct { - void* CANptr; - CO_CANrx_t* rxArray; - uint16_t rxSize; - CO_CANtx_t* txArray; - uint16_t txSize; - uint16_t CANerrorStatus; - volatile bool_t CANnormal; - volatile bool_t useCANrxFilters; - volatile bool_t bufferInhibitFlag; - volatile bool_t firstCANtxMessage; - volatile uint16_t CANtxCount; - uint32_t errOld; + void *CANptr; + CO_CANrx_t *rxArray; + uint16_t rxSize; + CO_CANtx_t *txArray; + uint16_t txSize; + uint16_t CANerrorStatus; + volatile bool_t CANnormal; + volatile bool_t useCANrxFilters; + volatile bool_t firstCANtxMessage; + uint32_t errOld; } CO_CANmodule_t; /* Data storage object for one entry */ typedef struct { - void* addr; - size_t len; - uint8_t subIndexOD; - uint8_t attr; - /* Additional variables (target specific) */ - void* addrNV; + void *addr; + size_t len; + uint8_t subIndexOD; + uint8_t attr; + /* Additional variables (target specific) */ + void *addrNV; } CO_storage_entry_t; /* (un)lock critical section in CO_CANsend() */ -#define CO_LOCK_CAN_SEND(CAN_MODULE) -#define CO_UNLOCK_CAN_SEND(CAN_MODULE) +#define CO_LOCK_CAN_SEND(CAN_MODULE) canopen_send_lock() +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) canopen_send_unlock() /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ -#define CO_LOCK_EMCY(CAN_MODULE) -#define CO_UNLOCK_EMCY(CAN_MODULE) +#define CO_LOCK_EMCY(CAN_MODULE) canopen_emcy_lock() +#define CO_UNLOCK_EMCY(CAN_MODULE) canopen_emcy_unlock() /* (un)lock critical section when accessing Object Dictionary */ -#define CO_LOCK_OD(CAN_MODULE) -#define CO_UNLOCK_OD(CAN_MODULE) +#define CO_LOCK_OD(CAN_MODULE) canopen_od_lock() +#define CO_UNLOCK_OD(CAN_MODULE) canopen_od_unlock() /* Synchronization between CAN receive and message processing threads. */ #define CO_MemoryBarrier() #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) -#define CO_FLAG_SET(rxNew) \ - { \ - CO_MemoryBarrier(); \ - rxNew = (void*)1L; \ - } -#define CO_FLAG_CLEAR(rxNew) \ - { \ - CO_MemoryBarrier(); \ - rxNew = NULL; \ - } +#define CO_FLAG_SET(rxNew) \ + { \ + CO_MemoryBarrier(); \ + rxNew = (void *)1L; \ + } +#define CO_FLAG_CLEAR(rxNew) \ + { \ + CO_MemoryBarrier(); \ + rxNew = NULL; \ + } #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* CO_DRIVER_TARGET_H */ +#endif /* ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_H */ diff --git a/zephyr/CO_driver_zephyr.c b/zephyr/CO_driver_zephyr.c index 0154d042..71c822dd 100644 --- a/zephyr/CO_driver_zephyr.c +++ b/zephyr/CO_driver_zephyr.c @@ -15,9 +15,10 @@ * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ #include "301/CO_driver.h" @@ -31,6 +32,12 @@ #include LOG_MODULE_REGISTER(canopen_driver); +typedef struct { + uint32_t ident; + uint8_t DLC; + uint8_t data[8]; +} CO_CANrxMsg_t; + struct k_work_q canopen_tx_workq; struct canopen_tx_work_container { @@ -61,8 +68,7 @@ static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule) for (i = 0U; i < CANmodule->rx_size; i++) { if (CANmodule->rx_array[i].filter_id != -ENOSPC) { - can_remove_rx_filter(CANmodule->dev, - CANmodule->rx_array[i].filter_id); + can_remove_rx_filter(CANmodule->dev, CANmodule->rx_array[i].filter_id); CANmodule->rx_array[i].filter_id = -ENOSPC; } } @@ -95,9 +101,8 @@ static void canopen_rx_callback(const struct device *dev, struct can_frame *fram rxMsg.ident = frame->id; rxMsg.DLC = frame->dlc; memcpy(rxMsg.data, frame->data, frame->dlc); - buffer->pFunct(buffer->object, &rxMsg); - if (callback != NULL) { - callback(); + if (buffer->CANrx_callback != NULL) { + buffer->CANrx_callback(buffer->object, &rxMsg); } break; } @@ -144,17 +149,12 @@ static void canopen_tx_retry(struct k_work *item) frame.flags |= (buffer->rtr ? CAN_FRAME_RTR : 0); memcpy(frame.data, buffer->data, buffer->DLC); - err = can_send(CANmodule->dev, &frame, K_NO_WAIT, - canopen_tx_callback, CANmodule); + err = can_send(CANmodule->dev, &frame, K_NO_WAIT, canopen_tx_callback, + CANmodule); if (err == -EAGAIN) { break; } else if (err != 0) { - LOG_ERR("failed to send CAN frame (err %d)", - err); - CO_errorReport(CANmodule->em, - CO_EM_GENERIC_SOFTWARE_ERROR, - CO_EMC_COMMUNICATION, 0); - + LOG_ERR("failed to send CAN frame (err %d)", err); } buffer->bufferFull = false; @@ -164,9 +164,8 @@ static void canopen_tx_retry(struct k_work *item) CO_UNLOCK_CAN_SEND(); } - -void -CO_CANsetConfigurationMode(void* CANptr) { +void CO_CANsetConfigurationMode(void *CANptr) +{ struct canopen_context *ctx = (struct canopen_context *)CANdriverState; int err; @@ -176,8 +175,8 @@ CO_CANsetConfigurationMode(void* CANptr) { } } -void -CO_CANsetNormalMode(CO_CANmodule_t* CANmodule) { +void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) +{ int err; err = can_start(CANmodule->dev); @@ -189,63 +188,91 @@ CO_CANsetNormalMode(CO_CANmodule_t* CANmodule) { CANmodule->CANnormal = true; } -CO_ReturnError_t -CO_CANmodule_init(CO_CANmodule_t* CANmodule, void* CANptr, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], - uint16_t txSize, uint16_t CANbitRate) { - uint16_t i; - - /* verify arguments */ - if (CANmodule == NULL || rxArray == NULL || txArray == NULL) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Configure object variables */ - CANmodule->CANptr = CANptr; - CANmodule->rxArray = rxArray; - CANmodule->rxSize = rxSize; - CANmodule->txArray = txArray; - CANmodule->txSize = txSize; - CANmodule->CANerrorStatus = 0; - CANmodule->CANnormal = false; - CANmodule->useCANrxFilters = (rxSize <= 32U) ? true : false; /* microcontroller dependent */ - CANmodule->bufferInhibitFlag = false; - CANmodule->firstCANtxMessage = true; - CANmodule->CANtxCount = 0U; - CANmodule->errOld = 0U; - - for (i = 0U; i < rxSize; i++) { - rxArray[i].ident = 0U; - rxArray[i].mask = 0xFFFFU; - rxArray[i].object = NULL; - rxArray[i].CANrx_callback = NULL; - } - for (i = 0U; i < txSize; i++) { - txArray[i].bufferFull = false; - } - - /* Configure CAN module registers */ - - /* Configure CAN timing */ - - /* Configure CAN module hardware filters */ - if (CANmodule->useCANrxFilters) { - /* CAN module filters are used, they will be configured with */ - /* CO_CANrxBufferInit() functions, called by separate CANopen */ - /* init functions. */ - /* Configure all masks so, that received message must match filter */ - } else { - /* CAN module filters are not used, all messages with standard 11-bit */ - /* identifier will be received */ - /* Configure mask 0 so, that all messages with standard identifier are accepted */ - } - - /* configure CAN interrupt registers */ - - return CO_ERROR_NO; +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) +{ + struct canopen_context *ctx = (struct canopen_context *)CANdriverState; + uint16_t i; + int err; + int max_filters; + + LOG_DBG("rxSize = %d, txSize = %d", rxSize, txSize); + + /* verify arguments */ + if (CANmodule == NULL || rxArray == NULL || txArray == NULL || CANdriverState == NULL) { + LOG_ERR("failed to initialize CAN module"); + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + max_filters = can_get_max_filters(ctx->dev, false); + if (max_filters != -ENOSYS) { + if (max_filters < 0) { + LOG_ERR("unable to determine number of CAN RX filters"); + return CO_ERROR_SYSCALL; + } + + if (rxSize > max_filters) { + LOG_ERR("insufficient number of concurrent CAN RX filters" + " (needs %d, %d available)", + rxSize, max_filters); + return CO_ERROR_OUT_OF_MEMORY; + } else if (rxSize < max_filters) { + LOG_DBG("excessive number of concurrent CAN RX filters enabled" + " (needs %d, %d available)", + rxSize, max_filters); + } + } + + canopen_detach_all_rx_filters(CANmodule); + canopen_tx_queue.CANmodule = CANmodule; + + /* Configure object variables */ + CANmodule->CANptr = ctx->dev; + CANmodule->rxArray = rxArray; + CANmodule->rxSize = rxSize; + CANmodule->txArray = txArray; + CANmodule->txSize = txSize; + CANmodule->CANerrorStatus = 0; + CANmodule->CANnormal = false; + CANmodule->useCANrxFilters = (rxSize <= max_filters) ? true : false; + CANmodule->firstCANtxMessage = true; + CANmodule->errOld = 0U; + + if (CANmodule->useCANrxFilters) { + /* CAN module filters are used, they will be configured with */ + /* CO_CANrxBufferInit() functions, called by separate CANopen */ + /* init functions. */ + for (i = 0U; i < rxSize; i++) { + rxArray[i].ident = 0U; + rxArray[i].pFunct = NULL; + rxArray[i].filter_id = -ENOSPC; + } + } else { + /* CAN module filters are not used, all messages with standard 11-bit */ + /* identifier will be received */ + } + for (i = 0U; i < txSize; i++) { + txArray[i].bufferFull = false; + } + + err = can_set_bitrate(CANmodule->dev, KHZ(CANbitRate)); + if (err) { + LOG_ERR("failed to configure CAN bitrate (err %d)", err); + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + err = can_set_mode(CANmodule->dev, CAN_MODE_NORMAL); + if (err) { + LOG_ERR("failed to configure CAN interface (err %d)", err); + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + return CO_ERROR_NO; } -void -CO_CANmodule_disable(CO_CANmodule_t* CANmodule) { +void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) +{ int err; if (!CANmodule || !CANmodule->dev) { @@ -260,255 +287,187 @@ CO_CANmodule_disable(CO_CANmodule_t* CANmodule) { } } -CO_ReturnError_t -CO_CANrxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, uint16_t mask, bool_t rtr, void* object, - void (*CANrx_callback)(void* object, void* message)) { - CO_ReturnError_t ret = CO_ERROR_NO; - - if ((CANmodule != NULL) && (object != NULL) && (CANrx_callback != NULL) && (index < CANmodule->rxSize)) { - /* buffer, which will be configured */ - CO_CANrx_t* buffer = &CANmodule->rxArray[index]; - - /* Configure object variables */ - buffer->object = object; - buffer->CANrx_callback = CANrx_callback; - - /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */ - buffer->ident = ident & 0x07FFU; - if (rtr) { - buffer->ident |= 0x0800U; - } - buffer->mask = (mask & 0x07FFU) | 0x0800U; - - /* Set CAN hardware module filter and mask. */ - if (CANmodule->useCANrxFilters) {} - } else { - ret = CO_ERROR_ILLEGAL_ARGUMENT; - } - - return ret; +CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, uint16_t ident, + uint16_t mask, bool_t rtr, void *object, + void (*CANrx_callback)(void *object, void *message)) +{ + struct can_filter filter; + CO_ReturnError_t ret = CO_ERROR_NO; + + if ((CANmodule != NULL) && (object != NULL) && (CANrx_callback != NULL) && + (index < CANmodule->rxSize)) { + /* buffer, which will be configured */ + CO_CANrx_t *buffer = &CANmodule->rxArray[index]; + + /* Configure object variables */ + buffer->object = object; + buffer->CANrx_callback = CANrx_callback; + + /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different + * microcontrollers. */ + buffer->ident = ident & 0x07FFU; + buffer->mask = (mask & 0x07FFU) | 0x0800U; + +#ifndef CONFIG_CAN_ACCEPT_RTR + if (rtr) { + LOG_ERR("request for RTR frames, but RTR frames are rejected"); + return CO_ERROR_ILLEGAL_ARGUMENT; + } +#else /* !CONFIG_CAN_ACCEPT_RTR */ + if (rtr) { + buffer->ident |= 0x0800U; + } +#endif /* CONFIG_CAN_ACCEPT_RTR */ + + /* Set CAN hardware module filter and mask. */ + if (CANmodule->useCANrxFilters) { + filter.flags = 0U; + filter.id = ident; + filter.mask = mask; + + if (buffer->filter_id != -ENOSPC) { + can_remove_rx_filter(CANmodule->dev, buffer->filter_id); + } + buffer->filter_id = can_add_rx_filter(CANmodule->dev, canopen_rx_callback, + CANmodule, &filter); + if (buffer->filter_id == -ENOSPC) { + LOG_ERR("failed to add CAN rx callback, no free filter"); + ret = CO_ERROR_OUT_OF_MEMORY; + } + } + } else { + ret = CO_ERROR_ILLEGAL_ARGUMENT; + } + + return ret; } -CO_CANtx_t* -CO_CANtxBufferInit(CO_CANmodule_t* CANmodule, uint16_t index, uint16_t ident, bool_t rtr, uint8_t noOfBytes, - bool_t syncFlag) { - CO_CANtx_t* buffer = NULL; +CO_CANtx_t *CO_CANtxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, uint16_t ident, + bool_t rtr, uint8_t noOfBytes, bool_t syncFlag) +{ + CO_CANtx_t *buffer = NULL; - if ((CANmodule != NULL) && (index < CANmodule->txSize)) { - /* get specific buffer */ - buffer = &CANmodule->txArray[index]; + if ((CANmodule != NULL) && (index < CANmodule->txSize)) { + /* get specific buffer */ + buffer = &CANmodule->txArray[index]; - /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer, microcontroller specific. */ - buffer->ident = ((uint32_t)ident & 0x07FFU) | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) - | ((uint32_t)(rtr ? 0x8000U : 0U)); + /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer, + * microcontroller specific. */ + buffer->ident = ((uint32_t)ident & 0x07FFU) | + ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) | + ((uint32_t)(rtr ? 0x8000U : 0U)); - buffer->bufferFull = false; - buffer->syncFlag = syncFlag; - } + buffer->bufferFull = false; + buffer->syncFlag = syncFlag; + } - return buffer; + return buffer; } -CO_ReturnError_t -CO_CANsend(CO_CANmodule_t* CANmodule, CO_CANtx_t* buffer) { - CO_ReturnError_t err = CO_ERROR_NO; - - /* Verify overflow */ - if (buffer->bufferFull) { - if (!CANmodule->firstCANtxMessage) { - /* don't set error, if bootup message is still on buffers */ - CANmodule->CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; - } - err = CO_ERROR_TX_OVERFLOW; - } - - CO_LOCK_CAN_SEND(CANmodule); - /* if CAN TX buffer is free, copy message to it */ - if (1 && CANmodule->CANtxCount == 0) { - CANmodule->bufferInhibitFlag = buffer->syncFlag; - /* copy message and txRequest */ - } - /* if no buffer is free, message will be sent by interrupt */ - else { - buffer->bufferFull = true; - CANmodule->CANtxCount++; - } - CO_UNLOCK_CAN_SEND(CANmodule); - - return err; +CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) +{ + CO_ReturnError_t err = CO_ERROR_NO; + struct can_frame frame; + + if (!CANmodule || !CANmodule->dev || !buffer) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + memset(&frame, 0, sizeof(frame)); + frame.id = buffer->ident; + frame.dlc = buffer->DLC; + frame.flags = (buffer->rtr ? CAN_FRAME_RTR : 0); + memcpy(frame.data, buffer->data, buffer->DLC); + + CO_LOCK_CAN_SEND(CANmodule); + + err = can_send(CANmodule->dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); + if (err == -EAGAIN) { + LOG_ERR("failed to send CAN frame, tx overflow"); + err = CO_ERROR_TX_OVERFLOW; + buffer->bufferFull = true; + } else if (err != 0) { + LOG_ERR("failed to send CAN frame (err %d)", err); + err = CO_ERROR_TX_UNCONFIGURED; + } + + CO_UNLOCK_CAN_SEND(CANmodule); + + return err; } -void -CO_CANclearPendingSyncPDOs(CO_CANmodule_t* CANmodule) { - uint32_t tpdoDeleted = 0U; - - CO_LOCK_CAN_SEND(CANmodule); - /* Abort message from CAN module, if there is synchronous TPDO. - * Take special care with this functionality. */ - if (/* messageIsOnCanBuffer && */ CANmodule->bufferInhibitFlag) { - /* clear TXREQ */ - CANmodule->bufferInhibitFlag = false; - tpdoDeleted = 1U; - } - /* delete also pending synchronous TPDOs in TX buffers */ - if (CANmodule->CANtxCount != 0U) { - uint16_t i; - CO_CANtx_t* buffer = &CANmodule->txArray[0]; - for (i = CANmodule->txSize; i > 0U; i--) { - if (buffer->bufferFull) { - if (buffer->syncFlag) { - buffer->bufferFull = false; - CANmodule->CANtxCount--; - tpdoDeleted = 2U; - } - } - buffer++; - } - } - CO_UNLOCK_CAN_SEND(CANmodule); - - if (tpdoDeleted != 0U) { - CANmodule->CANerrorStatus |= CO_CAN_ERRTX_PDO_LATE; - } +void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) +{ + bool_t tpdoDeleted = false; + CO_CANtx_t *buffer; + uint16_fast_t i; + + CO_LOCK_CAN_SEND(CANmodule); + + for (i = 0; i < CANmodule->tx_size; i++) { + buffer = &CANmodule->tx_array[i]; + if (buffer->bufferFull && buffer->syncFlag) { + buffer->bufferFull = false; + tpdoDeleted = true; + } + } + + CO_UNLOCK_CAN_SEND(CANmodule); + + if (tpdoDeleted == true) { + CANmodule->CANerrorStatus |= CO_CAN_ERRTX_PDO_LATE; + } } -/* Get error counters from the module. If necessary, function may use different way to determine errors. */ +/* Get error counters from the module. If necessary, function may use different way to determine + * errors. */ static uint16_t rxErrors = 0, txErrors = 0, overflow = 0; -void -CO_CANmodule_process(CO_CANmodule_t* CANmodule) { - uint32_t err; - - err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; - - if (CANmodule->errOld != err) { - uint16_t status = CANmodule->CANerrorStatus; - - CANmodule->errOld = err; - - if (txErrors >= 256U) { - /* bus off */ - status |= CO_CAN_ERRTX_BUS_OFF; - } else { - /* recalculate CANerrorStatus, first clear some flags */ - status &= 0xFFFF - ^ (CO_CAN_ERRTX_BUS_OFF | CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE | CO_CAN_ERRTX_WARNING - | CO_CAN_ERRTX_PASSIVE); - - /* rx bus warning or passive */ - if (rxErrors >= 128) { - status |= CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE; - } else if (rxErrors >= 96) { - status |= CO_CAN_ERRRX_WARNING; - } - - /* tx bus warning or passive */ - if (txErrors >= 128) { - status |= CO_CAN_ERRTX_WARNING | CO_CAN_ERRTX_PASSIVE; - } else if (txErrors >= 96) { - status |= CO_CAN_ERRTX_WARNING; - } - - /* if not tx passive clear also overflow */ - if ((status & CO_CAN_ERRTX_PASSIVE) == 0) { - status &= 0xFFFF ^ CO_CAN_ERRTX_OVERFLOW; - } - } - - if (overflow != 0) { - /* CAN RX bus overflow */ - status |= CO_CAN_ERRRX_OVERFLOW; - } - - CANmodule->CANerrorStatus = status; - } -} +void CO_CANmodule_process(CO_CANmodule_t *CANmodule) +{ + uint32_t err; -typedef struct { - uint32_t ident; - uint8_t DLC; - uint8_t data[8]; -} CO_CANrxMsg_t; + err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; + + if (CANmodule->errOld != err) { + uint16_t status = CANmodule->CANerrorStatus; + + CANmodule->errOld = err; + + if (txErrors >= 256U) { + /* bus off */ + status |= CO_CAN_ERRTX_BUS_OFF; + } else { + /* recalculate CANerrorStatus, first clear some flags */ + status &= 0xFFFF ^ (CO_CAN_ERRTX_BUS_OFF | CO_CAN_ERRRX_WARNING | + CO_CAN_ERRRX_PASSIVE | CO_CAN_ERRTX_WARNING | + CO_CAN_ERRTX_PASSIVE); -void -CO_CANinterrupt(CO_CANmodule_t* CANmodule) { - - /* receive interrupt */ - if (1) { - CO_CANrxMsg_t* rcvMsg; /* pointer to received message in CAN module */ - uint16_t index; /* index of received message */ - uint32_t rcvMsgIdent; /* identifier of the received message */ - CO_CANrx_t* buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ - bool_t msgMatched = false; - - rcvMsg = 0; /* get message from module here */ - rcvMsgIdent = rcvMsg->ident; - if (CANmodule->useCANrxFilters) { - /* CAN module filters are used. Message with known 11-bit identifier has been received */ - index = 0; /* get index of the received message here. Or something similar */ - if (index < CANmodule->rxSize) { - buffer = &CANmodule->rxArray[index]; - /* verify also RTR */ - if (((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) { - msgMatched = true; - } - } - } else { - /* CAN module filters are not used, message with any standard 11-bit identifier */ - /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ - buffer = &CANmodule->rxArray[0]; - for (index = CANmodule->rxSize; index > 0U; index--) { - if (((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) { - msgMatched = true; - break; - } - buffer++; - } - } - - /* Call specific function, which will process the message */ - if (msgMatched && (buffer != NULL) && (buffer->CANrx_callback != NULL)) { - buffer->CANrx_callback(buffer->object, (void*)rcvMsg); - } - - /* Clear interrupt flag */ - } - - /* transmit interrupt */ - else if (0) { - /* Clear interrupt flag */ - - /* First CAN message (bootup) was sent successfully */ - CANmodule->firstCANtxMessage = false; - /* clear flag from previous message */ - CANmodule->bufferInhibitFlag = false; - /* Are there any new messages waiting to be send */ - if (CANmodule->CANtxCount > 0U) { - uint16_t i; /* index of transmitting message */ - - /* first buffer */ - CO_CANtx_t* buffer = &CANmodule->txArray[0]; - /* search through whole array of pointers to transmit message buffers. */ - for (i = CANmodule->txSize; i > 0U; i--) { - /* if message buffer is full, send it. */ - if (buffer->bufferFull) { - buffer->bufferFull = false; - CANmodule->CANtxCount--; - - /* Copy message to CAN buffer */ - CANmodule->bufferInhibitFlag = buffer->syncFlag; - /* canSend... */ - break; /* exit for loop */ - } - buffer++; - } /* end of for loop */ - - /* Clear counter if no more messages */ - if (i == 0U) { - CANmodule->CANtxCount = 0U; - } - } - } else { - /* some other interrupt reason */ - } + /* rx bus warning or passive */ + if (rxErrors >= 128) { + status |= CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE; + } else if (rxErrors >= 96) { + status |= CO_CAN_ERRRX_WARNING; + } + + /* tx bus warning or passive */ + if (txErrors >= 128) { + status |= CO_CAN_ERRTX_WARNING | CO_CAN_ERRTX_PASSIVE; + } else if (txErrors >= 96) { + status |= CO_CAN_ERRTX_WARNING; + } + + /* if not tx passive clear also overflow */ + if ((status & CO_CAN_ERRTX_PASSIVE) == 0) { + status &= 0xFFFF ^ CO_CAN_ERRTX_OVERFLOW; + } + } + + if (overflow != 0) { + /* CAN RX bus overflow */ + status |= CO_CAN_ERRRX_OVERFLOW; + } + + CANmodule->CANerrorStatus = status; + } } From 08e1a6c01a70320100f09be27409221132e91dde Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 6 Aug 2025 16:43:02 -0400 Subject: [PATCH 499/520] Refactors CANopenNode module for Zephyr Migrates the CANopenNode module to leverage Zephyr's build system and Kconfig more effectively. This involves: - Restructuring Kconfig files for role selection, core features, and optional components. - Implementing object dictionary generation via an EDS file using `eds-utils`. - Removing the custom CMake build and instead using Zephyr's native `zephyr_library` function. - Improving configurability and integration within Zephyr RTOS, and fixing various build issues. --- CMakeLists.txt | 66 - Kconfig | 110 +- Kconfig.core | 38 + Kconfig.optional | 65 + Kconfig.roles | 67 + module.yml | 4 - tools/CMakeLists.txt | 59 + tools/eds2c_wrapper.py | 29 + tools/example.eds | 1806 ++++++++++++++++++++ zephyr/CMakeLists.txt | 85 + zephyr/{CO_driver_zephyr.c => CO_driver.c} | 5 +- zephyr/CO_driver_target.h | 9 +- zephyr/CO_storage_zephyr.c | 100 +- zephyr/CO_storage_zephyr.h | 32 +- zephyr/Kconfig.zephyr | 20 + zephyr/module.yml | 9 + zephyr/requirements.txt | 1 + 17 files changed, 2268 insertions(+), 237 deletions(-) delete mode 100644 CMakeLists.txt create mode 100644 Kconfig.core create mode 100644 Kconfig.optional create mode 100644 Kconfig.roles delete mode 100644 module.yml create mode 100644 tools/CMakeLists.txt create mode 100644 tools/eds2c_wrapper.py create mode 100644 tools/example.eds create mode 100644 zephyr/CMakeLists.txt rename zephyr/{CO_driver_zephyr.c => CO_driver.c} (99%) create mode 100644 zephyr/module.yml create mode 100644 zephyr/requirements.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 166e8173..00000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,66 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_CANOPENNODE) - - set(CANOPENNODE_DIR ${ZEPHYR_CURRENT_MODULE_DIR}) - - zephyr_library() - - zephyr_include_directories( - ${CANOPENNODE_DIR} - ${CANOPENNODE_DIR}/301 - ${CANOPENNODE_DIR}/303 - ${CANOPENNODE_DIR}/304 - ${CANOPENNODE_DIR}/305 - ${CANOPENNODE_DIR}/309 - ${CANOPENNODE_DIR}/extra - ${CANOPENNODE_DIR}/storage - ${CANOPENNODE_DIR}/zephyr - ) - - # === Core CANopen Stack (CiA 301) === - zephyr_library_sources( - ${CANOPENNODE_DIR}/CANopen.c - ${CANOPENNODE_DIR}/301/CO_Emergency.c - ${CANOPENNODE_DIR}/301/CO_NMT_Heartbeat.c - ${CANOPENNODE_DIR}/301/CO_PDO.c - ${CANOPENNODE_DIR}/301/CO_SDO.c - ${CANOPENNODE_DIR}/301/CO_SYNC.c - ${CANOPENNODE_DIR}/301/CO_TIME.c - ${CANOPENNODE_DIR}/301/CO_driver.c - ${CANOPENNODE_DIR}/301/CO_ODinterface.c - ${CANOPENNODE_DIR}/301/CO_fifo.c - ${CANOPENNODE_DIR}/301/CO_trace.c - ) - - # === Optional Features === - - # Heartbeat consumer & LSS (CiA 305) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_305 ${CANOPENNODE_DIR}/305/CO_HBconsumer.c) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_305 ${CANOPENNODE_DIR}/305/CO_LSSmaster.c) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_305 ${CANOPENNODE_DIR}/305/CO_LSSslave.c) - - # LEDs (CiA 303-3) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_LEDS ${CANOPENNODE_DIR}/303/CO_LEDs.c) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_LEDS ${CANOPENNODE_DIR}/zephyr/canopen_leds.c) - - # SYNC thread (CiA 303-6) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD ${CANOPENNODE_DIR}/zephyr/canopen_sync.c) - - # Storage (OD persistence) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_STORAGE ${CANOPENNODE_DIR}/storage/CO_storageBlank.c) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_STORAGE ${CANOPENNODE_DIR}/zephyr/canopen_storage.c) - - # Program download (CiA 302-3 draft) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_PROGRAM_DOWNLOAD ${CANOPENNODE_DIR}/zephyr/canopen_program.c) - - # ASCII gateway (CiA 309) - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_309 ${CANOPENNODE_DIR}/309/CO_gateway_ascii.c) - - # Extra utilities - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_EXTRA ${CANOPENNODE_DIR}/extra/CO_extra.c) - - # Zephyr-specific CAN driver glue - zephyr_library_sources(${CANOPENNODE_DIR}/zephyr/CO_driver_blank.c) - -endif() diff --git a/Kconfig b/Kconfig index 82910310..73802401 100644 --- a/Kconfig +++ b/Kconfig @@ -1,115 +1,23 @@ # CANopenNode CANopen protocol stack configuration options - +# # Copyright (c) 2019 Vestas Wind Systems A/S # SPDX-License-Identifier: Apache-2.0 -config ZEPHYR_CANOPENNODE_MODULE - bool - config CANOPENNODE bool "CANopenNode support" - select CRC - depends on CAN && !CAN_FD_MODE + depends on CAN help This option enables the CANopenNode library. if CANOPENNODE -config CANOPENNODE_SDO_BUFFER_SIZE - int "CANopen SDO buffer size" - default 32 - range 7 889 - help - Size of the internal CANopen SDO buffer in bytes. Size must - be at least equal to the size of the largest variable in the - object dictionary. If data type is DOMAIN, data length is - not limited to the SDO buffer size. If block transfer is - implemented, value should be set to 889. +source "modules/canopennode/Kconfig.roles" +source "modules/canopennode/Kconfig.core" +source "modules/canopennode/Kconfig.optional" -config CANOPENNODE_TRACE_BUFFER_SIZE - int "CANopen trace buffer size" - default 100 - help - Size of the CANopen trace buffer in bytes. - -config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE - int "Stack size for the CANopen transmit workqueue" - default 512 - help - Size of the stack used for the internal CANopen transmit - workqueue. - -config CANOPENNODE_TX_WORKQUEUE_PRIORITY - int "Priority for CANopen transmit workqueue" - default 0 if !COOP_ENABLED - default -1 - help - Priority level of the internal CANopen transmit workqueue. - -config CANOPENNODE_STORAGE - bool "CANopen object dictionary storage" - depends on SETTINGS - default y - help - Enable support for storing the CANopen object dictionary to - non-volatile storage. - -config CANOPENNODE_STORAGE_HANDLER_ERASES_EEPROM - bool "Erase CANopen object dictionary EEPROM entries in storage handler" - depends on CANOPENNODE_STORAGE - help - Erase CANopen object dictionary EEPROM entries upon write to - object dictionary index 0x1011 subindex 1. - -config CANOPENNODE_LEDS - bool "CANopen LED indicators" - default y - help - Enable support for CANopen LED indicators according to the CiA - 303-3 specification. - -config CANOPENNODE_LEDS_BICOLOR - bool "CANopen bicolor LED indicator" - depends on CANOPENNODE_LEDS - help - Handle CANopen LEDs as one bicolor LED, favoring the red LED - over the green LED in accordance with the CiA 303-3 - specification. - -config CANOPENNODE_SYNC_THREAD - bool "CANopen SYNC thread" - default y - help - Enable internal thread for processing CANopen SYNC RPDOs and - TPDOs. Application layer must take care of SYNC RPDO and - TPDO processing on its own if this is disabled. - -config CANOPENNODE_SYNC_THREAD_STACK_SIZE - int "Stack size for the CANopen SYNC thread" - depends on CANOPENNODE_SYNC_THREAD - default 512 - help - Size of the stack used for the internal thread which - processes CANopen SYNC RPDOs and TPDOs. - -config CANOPENNODE_SYNC_THREAD_PRIORITY - int "Priority for CANopen SYNC thread" - depends on CANOPENNODE_SYNC_THREAD - default 0 if !COOP_ENABLED - default -5 - help - Priority level of the internal thread which processes - CANopen SYNC RPDOs and TPDOs. - -config CANOPENNODE_PROGRAM_DOWNLOAD - bool "CANopen program download" - depends on BOOTLOADER_MCUBOOT - select IMG_MANAGER - default y - help - Enable support for program download over CANopen according - to the CiA 302-3 (draft) specification. +# Conditionally include Zephyr-specific config +if ZEPHYR_BASE +source "modules/canopennode/zephyr/Kconfig.zephyr" +endif endif # CANOPENNODE - -source "zephyr/Kconfig.zephyr" diff --git a/Kconfig.core b/Kconfig.core new file mode 100644 index 00000000..229293ce --- /dev/null +++ b/Kconfig.core @@ -0,0 +1,38 @@ +config CANOPENNODE_EDS_FILE_PATH + string "EDS file used to generate Object Dictionary" + default "modules/canopennode/tools/example.eds" + help + Path to the EDS (Electronic Data Sheet) file used to generate the + CANopenNode object dictionary files (OD.h, OD.c). + + This file is passed into the eds2c.py code generator. You may override + this to use a board-specific or application-specific EDS file. + + The path may be relative to the workspace root. + +config CANOPENNODE_SDO_BUFFER_SIZE + int "CANopen SDO buffer size" + default 32 + range 7 889 + help + Size of the internal CANopen SDO buffer in bytes. Must be large enough to hold the + largest variable in the object dictionary. + +config CANOPENNODE_TRACE_BUFFER_SIZE + int "CANopen trace buffer size" + default 100 + help + Size of the CANopen trace buffer in bytes. + +config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE + int "Stack size for the CANopen transmit workqueue" + default 512 + help + Stack size used for the internal CANopen transmit workqueue. + +config CANOPENNODE_TX_WORKQUEUE_PRIORITY + int "Priority for CANopen transmit workqueue" + default 0 if !COOP_ENABLED + default -1 + help + Priority of the CANopen transmit workqueue. diff --git a/Kconfig.optional b/Kconfig.optional new file mode 100644 index 00000000..cb3c9271 --- /dev/null +++ b/Kconfig.optional @@ -0,0 +1,65 @@ +config CANOPENNODE_STORAGE + bool "CANopen object dictionary storage" + depends on SETTINGS + default y + help + Enable storing the CANopen object dictionary to non-volatile storage. + +config CANOPENNODE_STORAGE_HANDLER_ERASES_EEPROM + bool "Erase CANopen object dictionary EEPROM entries in storage handler" + depends on CANOPENNODE_STORAGE + help + Erase EEPROM entries upon write to OD index 0x1011 subindex 1. + +config CANOPENNODE_LEDS + bool "CANopen LED indicators" + default y + help + Enable support for CANopen LED indicators (CiA 303-3). + +config CANOPENNODE_LEDS_BICOLOR + bool "CANopen bicolor LED indicator" + depends on CANOPENNODE_LEDS + help + Treat LEDs as one bicolor LED, favoring red per CiA 303-3. + +config CANOPENNODE_SYNC_THREAD + bool "CANopen SYNC thread" + default y + help + Use an internal thread to process SYNC RPDOs and TPDOs. + +config CANOPENNODE_SYNC_THREAD_STACK_SIZE + int "Stack size for the CANopen SYNC thread" + depends on CANOPENNODE_SYNC_THREAD + default 512 + help + Stack size for the internal SYNC processing thread. + +config CANOPENNODE_SYNC_THREAD_PRIORITY + int "Priority for CANopen SYNC thread" + depends on CANOPENNODE_SYNC_THREAD + default 0 if !COOP_ENABLED + default -5 + help + Thread priority for SYNC processing. + +config CANOPENNODE_PROGRAM_DOWNLOAD + bool "CANopen program download" + depends on BOOTLOADER_MCUBOOT + select IMG_MANAGER + default y if CANOPENNODE_ROLE_COMBINED + help + Enable CiA 302-3 based program download over CANopen. + +config CANOPENNODE_LOG_LEVEL + int "CANopenNode log level" + default 0 if LOG_DEFAULT_LEVEL_OFF + default 1 if LOG_DEFAULT_LEVEL_ERR + default 2 if LOG_DEFAULT_LEVEL_WRN + default 3 if LOG_DEFAULT_LEVEL_INF + default 4 if LOG_DEFAULT_LEVEL_DBG + default 5 if LOG_DEFAULT_LEVEL_DBG + range 0 5 + help + Set the log level for the CANopenNode module. diff --git a/Kconfig.roles b/Kconfig.roles new file mode 100644 index 00000000..4f2ed88e --- /dev/null +++ b/Kconfig.roles @@ -0,0 +1,67 @@ +comment "CANopen Communication Role Selection" + +choice CANOPENNODE_ROLE + prompt "CANopen node communication role" + default CANOPENNODE_ROLE_SERVER + +config CANOPENNODE_ROLE_CLIENT + bool "Client (initiates SDO requests)" + help + CANopen node acting as a client (e.g., NMT master, network manager, update tool). + Enables SDO client and LSS master functionality. + +config CANOPENNODE_ROLE_SERVER + bool "Server (responds to SDO requests)" + help + Typical CANopen node acting as a device/slave, responding to SDO client transfers. + +config CANOPENNODE_ROLE_COMBINED + bool "Combined (Client + Server)" + help + Gateway or dual-role device (e.g., bootloader host and target). Enables both roles. + +endchoice + +config CANOPENNODE_ROLE_CONTROLLER + bool "CANopen Controller (Client/Master)" + select CANOPENNODE_SDO_CLIENT + select CANOPENNODE_LSS_CLIENT + +config CANOPENNODE_ROLE_DEVICE + bool "CANopen Device (Server/Slave)" + select CANOPENNODE_SDO_SERVER + select CANOPENNODE_LSS_SERVER + +config CANOPENNODE_LSS + bool "Enable Layer Setting Services (LSS)" + depends on CANOPENNODE + help + Enable support for CiA 305 LSS functionality. + +config CANOPENNODE_LSS_CLIENT + bool "Enable LSS Client (master role)" + depends on CANOPENNODE_LSS + help + Enable the LSS client role. Used in tools that configure other nodes. + +config CANOPENNODE_LSS_SERVER + bool "Enable LSS Server (slave role)" + depends on CANOPENNODE_LSS + help + Enable the LSS server role. Used in nodes that are being configured. + +config CANOPENNODE_SDO_CLIENT + bool + default y if CANOPENNODE_ROLE_CLIENT || CANOPENNODE_ROLE_COMBINED + +config CANOPENNODE_SDO_SERVER + bool + default y if CANOPENNODE_ROLE_SERVER || CANOPENNODE_ROLE_COMBINED + +config CANOPENNODE_LSS_MASTER + bool + default y if CANOPENNODE_ROLE_CLIENT || CANOPENNODE_ROLE_COMBINED + +config CANOPENNODE_LSS_SLAVE + bool + default y if CANOPENNODE_ROLE_SERVER || CANOPENNODE_ROLE_COMBINED diff --git a/module.yml b/module.yml deleted file mode 100644 index 0bb04b6b..00000000 --- a/module.yml +++ /dev/null @@ -1,4 +0,0 @@ -# modules/canopennode/module.yml -name: canopennode -build: - cmake: . diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 00000000..ea0aceae --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,59 @@ +# COPYRIGHT (C) 2025 INDUCTOHEAT, INC. ALL RIGHTS RESERVED. +# +# THIS SOURCE CODE DISTRIBUTION IS THE SOLE PROPERTY OF INDUCTOHEAT, INC. ANY +# REPRODUCTION IN PART OR AS A WHOLE IS STRICTLY PROHIBITED WITHOUT THE WRITTEN +# PERMISSION OF INDUCTOHEAT, INC. + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Python3 REQUIRED COMPONENTS Interpreter) + +# Set default value for CANOPEN_DIR if it wasn't set externally +if(NOT DEFINED CANOPEN_DIR) + set(CANOPEN_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +set(EDS2C_SCRIPT "${CANOPEN_DIR}/eds2c_wrapper.py") +set(EDS_UTILS_PY "eds-utils==0.3.1") +set(EDS_FILE "${CANOPEN_DIR}/ismart-fanout-board.eds") +set(GENERATED_HEADER "${CMAKE_CURRENT_BINARY_DIR}/OD.h") +set(GENERATED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/OD.c") + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +# Check if eds-utils is installed +execute_process( + COMMAND pip show eds-utils + RESULT_VARIABLE EDS_UTILS_FOUND + OUTPUT_QUIET + ERROR_QUIET +) + +if(NOT EDS_UTILS_FOUND EQUAL 0) + message(STATUS "eds-utils not found. Installing with pip...") + execute_process( + COMMAND pip install ${EDS_UTILS_PY} + RESULT_VARIABLE PIP_INSTALL_RESULT + ) + if(NOT PIP_INSTALL_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to install eds-utils via pip") + endif() +endif() + +# Generate if EDS file changed or outputs missing +add_custom_command( + OUTPUT ${GENERATED_HEADER} ${GENERATED_SOURCE} + COMMAND ${Python3_EXECUTABLE} ${EDS2C_SCRIPT} ${EDS_FILE} -o ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${EDS_FILE} + COMMENT "Generating CANopenNode object dictionary from ${EDS_FILE} using eds-utils" + VERBATIM +) + +add_custom_target(generate_od + DEPENDS ${GENERATED_HEADER} ${GENERATED_SOURCE} +) + +# Export variables so parent scope can use +set(CO_OD_H ${GENERATED_HEADER} PARENT_SCOPE) +set(CO_OD_C ${GENERATED_SOURCE} PARENT_SCOPE) +set(CO_OD_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) diff --git a/tools/eds2c_wrapper.py b/tools/eds2c_wrapper.py new file mode 100644 index 00000000..e0757413 --- /dev/null +++ b/tools/eds2c_wrapper.py @@ -0,0 +1,29 @@ +""" +EDS to C Conversion Script (CLI Wrapper) + +This script provides a minimal command-line interface (CLI) for invoking the +`eds2c` module from the `eds-utils` Python package. It allows Windows users +to generate C source files from an EDS (Electronic Data Sheet) file without +requiring GTK or other GUI dependencies, which are typically only supported +on Linux or macOS. + +Usage: + python eds2c_wrapper.py + +Arguments are passed directly to the `eds2c` entry point. For example: + python eds2c_wrapper.py generate path/to/file.eds -o output/dir + +Note: +- This bypasses GUI-related modules like `gi` and `eds_editor.main`, which + often cause issues in Windows environments lacking GTK. +- Make sure `eds-utils` is installed in your Python environment. +""" + +import sys +from eds_utils import eds2c + + +# Entry point for script execution +if __name__ == "__main__": + # Pass command-line arguments to the eds2c CLI function + eds2c.eds2c(sys.argv[1:]) diff --git a/tools/example.eds b/tools/example.eds new file mode 100644 index 00000000..7476becb --- /dev/null +++ b/tools/example.eds @@ -0,0 +1,1806 @@ +[FileInfo] +FileName=objdict.eds +FileVersion=1 +FileRevision=1 +LastEDS= +EDSVersion=4.0 +Description= +CreationTime=2:52PM +CreationDate=09-18-2019 +CreatedBy= +ModificationTime=12:28PM +ModificationDate=02-20-2020 +ModifiedBy= + +[DeviceInfo] +VendorName= +VendorNumber=0 +ProductName=Zephyr RTOS CANopen sample +ProductNumber=0 +RevisionNumber=0 +BaudRate_10=1 +BaudRate_20=1 +BaudRate_50=1 +BaudRate_125=1 +BaudRate_250=1 +BaudRate_500=1 +BaudRate_800=1 +BaudRate_1000=1 +SimpleBootUpMaster=0 +SimpleBootUpSlave=0 +Granularity=0 +DynamicChannelsSupported=0 +CompactPDO=0 +GroupMessaging=0 +NrOfRXPDO=4 +NrOfTXPDO=4 +LSS_Supported=0 +;LSS_Type=Server + +[DummyUsage] +Dummy0001=0 +Dummy0002=0 +Dummy0003=0 +Dummy0004=0 +Dummy0005=0 +Dummy0006=0 +Dummy0007=0 + +[Comments] +Lines=0 + +[MandatoryObjects] +SupportedObjects=3 +1=0x1000 +2=0x1001 +3=0x1018 + +[1000] +ParameterName=Device type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1001] +ParameterName=Error register +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=0 +PDOMapping=1 + +[1018] +ParameterName=Identity +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x5 + +[1018sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=4 +PDOMapping=0 + +[1018sub1] +ParameterName=Vendor-ID +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1018sub2] +ParameterName=Product code +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1018sub3] +ParameterName=Revision number +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[1018sub4] +ParameterName=Serial number +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000000 +PDOMapping=0 + +[OptionalObjects] +SupportedObjects=39 +1=0x1002 +2=0x1003 +3=0x1005 +4=0x1006 +5=0x1007 +6=0x1008 +7=0x1009 +8=0x100A +9=0x1010 +10=0x1011 +11=0x1012 +12=0x1014 +13=0x1015 +14=0x1016 +15=0x1017 +16=0x1019 +17=0x1029 +18=0x1200 +19=0x1400 +20=0x1401 +21=0x1402 +22=0x1403 +23=0x1600 +24=0x1601 +25=0x1602 +26=0x1603 +27=0x1800 +28=0x1801 +29=0x1802 +30=0x1803 +31=0x1A00 +32=0x1A01 +33=0x1A02 +34=0x1A03 +35=0x1F50 +36=0x1F51 +37=0x1F56 +38=0x1F57 +39=0x1F80 + +[1002] +ParameterName=Manufacturer status register +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=1 + +[1003] +ParameterName=Pre-defined error field +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x9 + +[1003sub0] +ParameterName=Number of errors +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue=0x00 +PDOMapping=0 + +[1003sub1] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1003sub2] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1003sub3] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1003sub4] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1003sub5] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1003sub6] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1003sub7] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1003sub8] +ParameterName=Standard error field +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1005] +ParameterName=COB-ID SYNC message +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000080 +PDOMapping=0 + +[1006] +ParameterName=Communication cycle period +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1007] +ParameterName=Synchronous window length +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1008] +ParameterName=Manufacturer device name +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0009 +AccessType=const +DefaultValue=Zephyr RTOS/CANopenNode +PDOMapping=0 + +[1009] +ParameterName=Manufacturer hardware version +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0009 +AccessType=const +DefaultValue=3.00 +PDOMapping=0 + +[100A] +ParameterName=Manufacturer software version +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0009 +AccessType=const +DefaultValue=3.00 +PDOMapping=0 + +[1010] +ParameterName=Store parameters +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x2 + +[1010sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[1010sub1] +ParameterName=save all parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000003 +PDOMapping=0 + +[1011] +ParameterName=Restore default parameters +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x2 + +[1011sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[1011sub1] +ParameterName=restore all default parameters +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000001 +PDOMapping=0 + +[1012] +ParameterName=COB-ID TIME +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1014] +ParameterName=COB-ID EMCY +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue=$NODEID+0x80 +PDOMapping=0 + +[1015] +ParameterName=inhibit time EMCY +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=100 +PDOMapping=0 + +[1016] +ParameterName=Consumer heartbeat time +ObjectType=0x8 +;StorageLocation=ROM +SubNumber=0x5 + +[1016sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=4 +PDOMapping=0 + +[1016sub1] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub2] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub3] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1016sub4] +ParameterName=Consumer heartbeat time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1017] +ParameterName=Producer heartbeat time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=1000 +PDOMapping=0 + +[1019] +ParameterName=Synchronous counter overflow value +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1029] +ParameterName=Error behavior +ObjectType=0x8 +;StorageLocation=ROM +SubNumber=0x7 + +[1029sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=6 +PDOMapping=0 + +[1029sub1] +ParameterName=Communication +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0x00 +PDOMapping=0 + +[1029sub2] +ParameterName=Communication other +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0x00 +PDOMapping=0 + +[1029sub3] +ParameterName=Communication passive +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0x01 +PDOMapping=0 + +[1029sub4] +ParameterName=Generic +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0x00 +PDOMapping=0 + +[1029sub5] +ParameterName=Device profile +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0x00 +PDOMapping=0 + +[1029sub6] +ParameterName=Manufacturer specific +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0x00 +PDOMapping=0 + +[1200] +ParameterName=SDO server parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x3 + +[1200sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1200sub1] +ParameterName=COB-ID client to server +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue=$NODEID+0x600 +PDOMapping=0 + +[1200sub2] +ParameterName=COB-ID server to client +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=ro +DefaultValue=$NODEID+0x580 +PDOMapping=0 + +[1400] +ParameterName=RPDO communication parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x3 + +[1400sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1400sub1] +ParameterName=COB-ID used by RPDO +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x200 +PDOMapping=0 + +[1400sub2] +ParameterName=transmission type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1401] +ParameterName=RPDO communication parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x3 + +[1401sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1401sub1] +ParameterName=COB-ID used by RPDO +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x300 +PDOMapping=0 + +[1401sub2] +ParameterName=transmission type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1402] +ParameterName=RPDO communication parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x3 + +[1402sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1402sub1] +ParameterName=COB-ID used by RPDO +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x400 +PDOMapping=0 + +[1402sub2] +ParameterName=transmission type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1403] +ParameterName=RPDO communication parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x3 + +[1403sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1403sub1] +ParameterName=COB-ID used by RPDO +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x500 +PDOMapping=0 + +[1403sub2] +ParameterName=transmission type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1600] +ParameterName=RPDO mapping parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x9 + +[1600sub0] +ParameterName=Number of mapped objects +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1600sub1] +ParameterName=mapped object 1 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub2] +ParameterName=mapped object 2 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub3] +ParameterName=mapped object 3 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub4] +ParameterName=mapped object 4 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub5] +ParameterName=mapped object 5 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub6] +ParameterName=mapped object 6 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub7] +ParameterName=mapped object 7 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1600sub8] +ParameterName=mapped object 8 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601] +ParameterName=RPDO mapping parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x9 + +[1601sub0] +ParameterName=Number of mapped objects +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1601sub1] +ParameterName=mapped object 1 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub2] +ParameterName=mapped object 2 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub3] +ParameterName=mapped object 3 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub4] +ParameterName=mapped object 4 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub5] +ParameterName=mapped object 5 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub6] +ParameterName=mapped object 6 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub7] +ParameterName=mapped object 7 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1601sub8] +ParameterName=mapped object 8 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602] +ParameterName=RPDO mapping parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x9 + +[1602sub0] +ParameterName=Number of mapped objects +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1602sub1] +ParameterName=mapped object 1 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub2] +ParameterName=mapped object 2 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub3] +ParameterName=mapped object 3 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub4] +ParameterName=mapped object 4 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub5] +ParameterName=mapped object 5 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub6] +ParameterName=mapped object 6 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub7] +ParameterName=mapped object 7 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1602sub8] +ParameterName=mapped object 8 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603] +ParameterName=RPDO mapping parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x9 + +[1603sub0] +ParameterName=Number of mapped objects +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1603sub1] +ParameterName=mapped object 1 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub2] +ParameterName=mapped object 2 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub3] +ParameterName=mapped object 3 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub4] +ParameterName=mapped object 4 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub5] +ParameterName=mapped object 5 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub6] +ParameterName=mapped object 6 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub7] +ParameterName=mapped object 7 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1603sub8] +ParameterName=mapped object 8 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1800] +ParameterName=TPDO communication parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x7 + +[1800sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=6 +PDOMapping=0 + +[1800sub1] +ParameterName=COB-ID used by TPDO +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x180 +PDOMapping=0 + +[1800sub2] +ParameterName=transmission type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1800sub3] +ParameterName=inhibit time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1800sub4] +ParameterName=compatibility entry +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1800sub5] +ParameterName=event timer +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1800sub6] +ParameterName=SYNC start value +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1801] +ParameterName=TPDO communication parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x7 + +[1801sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=6 +PDOMapping=0 + +[1801sub1] +ParameterName=COB-ID used by TPDO +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x280 +PDOMapping=0 + +[1801sub2] +ParameterName=transmission type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1801sub3] +ParameterName=inhibit time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1801sub4] +ParameterName=compatibility entry +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1801sub5] +ParameterName=event timer +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1801sub6] +ParameterName=SYNC start value +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1802] +ParameterName=TPDO communication parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x7 + +[1802sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=6 +PDOMapping=0 + +[1802sub1] +ParameterName=COB-ID used by TPDO +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x380 +PDOMapping=0 + +[1802sub2] +ParameterName=transmission type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1802sub3] +ParameterName=inhibit time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1802sub4] +ParameterName=compatibility entry +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1802sub5] +ParameterName=event timer +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1802sub6] +ParameterName=SYNC start value +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1803] +ParameterName=TPDO communication parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x7 + +[1803sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=6 +PDOMapping=0 + +[1803sub1] +ParameterName=COB-ID used by TPDO +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x480 +PDOMapping=0 + +[1803sub2] +ParameterName=transmission type +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=254 +PDOMapping=0 + +[1803sub3] +ParameterName=inhibit time +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1803sub4] +ParameterName=compatibility entry +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1803sub5] +ParameterName=event timer +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1803sub6] +ParameterName=SYNC start value +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A00] +ParameterName=TPDO mapping parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x9 + +[1A00sub0] +ParameterName=Number of mapped objects +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A00sub1] +ParameterName=mapped object 1 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub2] +ParameterName=mapped object 2 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub3] +ParameterName=mapped object 3 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub4] +ParameterName=mapped object 4 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub5] +ParameterName=mapped object 5 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub6] +ParameterName=mapped object 6 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub7] +ParameterName=mapped object 7 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A00sub8] +ParameterName=mapped object 8 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01] +ParameterName=TPDO mapping parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x9 + +[1A01sub0] +ParameterName=Number of mapped objects +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A01sub1] +ParameterName=mapped object 1 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub2] +ParameterName=mapped object 2 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub3] +ParameterName=mapped object 3 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub4] +ParameterName=mapped object 4 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub5] +ParameterName=mapped object 5 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub6] +ParameterName=mapped object 6 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub7] +ParameterName=mapped object 7 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A01sub8] +ParameterName=mapped object 8 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02] +ParameterName=TPDO mapping parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x9 + +[1A02sub0] +ParameterName=Number of mapped objects +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A02sub1] +ParameterName=mapped object 1 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub2] +ParameterName=mapped object 2 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub3] +ParameterName=mapped object 3 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub4] +ParameterName=mapped object 4 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub5] +ParameterName=mapped object 5 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub6] +ParameterName=mapped object 6 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub7] +ParameterName=mapped object 7 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A02sub8] +ParameterName=mapped object 8 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03] +ParameterName=TPDO mapping parameter +ObjectType=0x9 +;StorageLocation=ROM +SubNumber=0x9 + +[1A03sub0] +ParameterName=Number of mapped objects +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1A03sub1] +ParameterName=mapped object 1 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub2] +ParameterName=mapped object 2 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub3] +ParameterName=mapped object 3 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub4] +ParameterName=mapped object 4 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub5] +ParameterName=mapped object 5 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub6] +ParameterName=mapped object 6 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub7] +ParameterName=mapped object 7 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1A03sub8] +ParameterName=mapped object 8 +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[1F50] +ParameterName=Program data +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x2 + +[1F50sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[1F50sub1] +ParameterName= +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x000F +AccessType=wo +DefaultValue= +PDOMapping=0 + +[1F51] +ParameterName=Program control +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x2 + +[1F51sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[1F51sub1] +ParameterName= +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=rw +DefaultValue= +PDOMapping=0 + +[1F56] +ParameterName=Program software identification +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x2 + +[1F56sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[1F56sub1] +ParameterName= +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1F57] +ParameterName=Flash status identification +ObjectType=0x8 +;StorageLocation=RAM +SubNumber=0x2 + +[1F57sub0] +ParameterName=max sub-index +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[1F57sub1] +ParameterName= +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=ro +DefaultValue= +PDOMapping=0 + +[1F80] +ParameterName=NMT startup +ObjectType=0x7 +;StorageLocation=ROM +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000000 +PDOMapping=0 + +[ManufacturerObjects] +SupportedObjects=3 +1=0x2100 +2=0x2101 +3=0x2102 + +[2100] +ParameterName=Error status bits +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x000A +AccessType=ro +DefaultValue=00000000000000000000 +PDOMapping=1 + +[2101] +ParameterName=Power-on counter +ObjectType=0x7 +;StorageLocation=EEPROM +DataType=0x0007 +AccessType=ro +DefaultValue=0 +PDOMapping=1 + +[2102] +ParameterName=Button press counter +ObjectType=0x7 +;StorageLocation=RAM +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=1 + diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt new file mode 100644 index 00000000..01bf4195 --- /dev/null +++ b/zephyr/CMakeLists.txt @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_CANOPENNODE) + + set(CANOPENNODE_DIR "${ZEPHYR_CURRENT_MODULE_DIR}") + set(CANOPENNODE_BINARY_DIR "${CMAKE_BINARY_DIR}/modules/${ZEPHYR_CURRENT_MODULE_NAME}") + + set(CANOPENNODE_OD_GEN_SCRIPT "${CANOPENNODE_DIR}/tools/eds2c_wrapper.py") + set(CANOPENNODE_OD_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") + set(CANOPENNODE_OD_GEN_C "${CANOPENNODE_OD_GEN_DIR}/OD.c") + set(CANOPENNODE_OD_GEN_H "${CANOPENNODE_OD_GEN_DIR}/OD.h") + + # Resolve EDS file path + set(CANOPENNODE_EDS_FILE_REL "${CONFIG_CANOPENNODE_EDS_FILE_PATH}") + set(CANOPENNODE_EDS_FILE "${APPLICATION_SOURCE_DIR}/${CANOPENNODE_EDS_FILE_REL}") + file(TO_CMAKE_PATH "${CANOPENNODE_EDS_FILE}" CANOPENNODE_EDS_FILE) + + file(MAKE_DIRECTORY "${CANOPENNODE_OD_GEN_DIR}") + + message(STATUS "CANopenNode: Using EDS file: ${CANOPENNODE_EDS_FILE}") + message(STATUS "CANopenNode: Will generate OD headers to: ${CANOPENNODE_OD_GEN_H}") + message(STATUS "CANopenNode: Will generate OD sources to: ${CANOPENNODE_OD_GEN_C}") + + # Generate OD files from EDS + add_custom_command( + OUTPUT "${CANOPENNODE_OD_GEN_H}" "${CANOPENNODE_OD_GEN_C}" + COMMAND ${PYTHON_EXECUTABLE} "${CANOPENNODE_OD_GEN_SCRIPT}" + "${CANOPENNODE_EDS_FILE}" + -o "${CANOPENNODE_OD_GEN_DIR}" + DEPENDS "${CANOPENNODE_OD_GEN_SCRIPT}" "${CANOPENNODE_EDS_FILE}" + COMMENT "CANopenNode: Generating Object Dictionary from ${CANOPENNODE_EDS_FILE_REL}" + VERBATIM + ) + + add_custom_target(canopennode_od_gen + DEPENDS "${CANOPENNODE_OD_GEN_H}" "${CANOPENNODE_OD_GEN_C}" + ) + + zephyr_library() + + zephyr_include_directories( + "${CANOPENNODE_DIR}" + "${CANOPENNODE_DIR}/301" + "${CANOPENNODE_DIR}/303" + "${CANOPENNODE_DIR}/304" + "${CANOPENNODE_DIR}/305" + "${CANOPENNODE_DIR}/309" + "${CANOPENNODE_DIR}/extra" + "${CANOPENNODE_DIR}/storage" + "${CANOPENNODE_DIR}/zephyr" + "${CANOPENNODE_OD_GEN_DIR}" + ) + + zephyr_library_sources( + "${CANOPENNODE_DIR}/CANopen.c" + "${CANOPENNODE_DIR}/301/CO_Emergency.c" + "${CANOPENNODE_DIR}/301/CO_fifo.c" + "${CANOPENNODE_DIR}/301/CO_HBconsumer.c" + "${CANOPENNODE_DIR}/301/CO_NMT_Heartbeat.c" + "${CANOPENNODE_DIR}/301/CO_Node_Guarding.c" + "${CANOPENNODE_DIR}/301/CO_ODinterface.c" + "${CANOPENNODE_DIR}/301/CO_PDO.c" + "${CANOPENNODE_DIR}/301/CO_SDOclient.c" + "${CANOPENNODE_DIR}/301/CO_SDOserver.c" + "${CANOPENNODE_DIR}/301/CO_SYNC.c" + "${CANOPENNODE_DIR}/301/CO_TIME.c" + "${CANOPENNODE_DIR}/301/crc16-ccitt.c" + "${CANOPENNODE_OD_GEN_C}" + ) + + zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_driver.c") + + # Optional modules + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_LEDS "${CANOPENNODE_DIR}/303/CO_LEDs.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_304 "${CANOPENNODE_DIR}/304/CO_GFC.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_304 "${CANOPENNODE_DIR}/304/CO_SRDO.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/305/CO_LSSmaster.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/305/CO_LSSslave.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_309 "${CANOPENNODE_DIR}/309/CO_gateway_ascii.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/extra/CO_trace.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_STORAGE "${CANOPENNODE_DIR}/storage/CO_storage.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_STORAGE "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_PROGRAM_DOWNLOAD "${CANOPENNODE_DIR}/zephyr/canopen_program.c") + +endif() diff --git a/zephyr/CO_driver_zephyr.c b/zephyr/CO_driver.c similarity index 99% rename from zephyr/CO_driver_zephyr.c rename to zephyr/CO_driver.c index 71c822dd..591f9e4e 100644 --- a/zephyr/CO_driver_zephyr.c +++ b/zephyr/CO_driver.c @@ -27,10 +27,9 @@ #include #include #include - -#define LOG_LEVEL CONFIG_CANOPEN_LOG_LEVEL #include -LOG_MODULE_REGISTER(canopen_driver); + +LOG_MODULE_REGISTER(canopen_driver, CONFIG_CANOPENNODE_LOG_LEVEL); typedef struct { uint32_t ident; diff --git a/zephyr/CO_driver_target.h b/zephyr/CO_driver_target.h index 6015bdd8..033c5d94 100644 --- a/zephyr/CO_driver_target.h +++ b/zephyr/CO_driver_target.h @@ -38,7 +38,7 @@ extern "C" { #endif -#include +#include #include #include #include @@ -71,7 +71,6 @@ typedef double float64_t; // typedef unsigned char oChar_t; // typedef unsigned char domain_t; - /* Access to received CAN message */ #define CO_CANrxMsg_readIdent(msg) ((uint16_t)0) #define CO_CANrxMsg_readDLC(msg) ((uint8_t)0) @@ -120,14 +119,20 @@ typedef struct { } CO_storage_entry_t; /* (un)lock critical section in CO_CANsend() */ +void canopen_send_lock(void); +void canopen_send_unlock(void); #define CO_LOCK_CAN_SEND(CAN_MODULE) canopen_send_lock() #define CO_UNLOCK_CAN_SEND(CAN_MODULE) canopen_send_unlock() /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ +void canopen_emcy_lock(void); +void canopen_emcy_unlock(void); #define CO_LOCK_EMCY(CAN_MODULE) canopen_emcy_lock() #define CO_UNLOCK_EMCY(CAN_MODULE) canopen_emcy_unlock() /* (un)lock critical section when accessing Object Dictionary */ +void canopen_od_lock(void); +void canopen_od_unlock(void); #define CO_LOCK_OD(CAN_MODULE) canopen_od_lock() #define CO_UNLOCK_OD(CAN_MODULE) canopen_od_unlock() diff --git a/zephyr/CO_storage_zephyr.c b/zephyr/CO_storage_zephyr.c index a2306a5c..ae70eaba 100644 --- a/zephyr/CO_storage_zephyr.c +++ b/zephyr/CO_storage_zephyr.c @@ -12,9 +12,10 @@ * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ #include "CO_storageBlank.h" @@ -26,14 +27,14 @@ * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t -storeBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { +static ODR_t storeBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) +{ - /* Open a file and write data to it */ - /* file = open(entry->pathToFileOrPointerToMemory); */ - /* write(entry->addr, entry->len, file); */ + /* Open a file and write data to it */ + /* file = open(entry->pathToFileOrPointerToMemory); */ + /* write(entry->addr, entry->len, file); */ - return ODR_OK; + return ODR_OK; } /* @@ -41,49 +42,52 @@ storeBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { * * For more information see file CO_storage.h, CO_storage_entry_t. */ -static ODR_t -restoreBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { +static ODR_t restoreBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) +{ - /* disable (delete) the file, so default values will stay after startup */ + /* disable (delete) the file, so default values will stay after startup */ - return ODR_OK; + return ODR_OK; } -CO_ReturnError_t -CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, - OD_entry_t* OD_1011_RestoreDefaultParam, CO_storage_entry_t* entries, uint8_t entriesCount, - uint32_t* storageInitError) { - CO_ReturnError_t ret; - - /* verify arguments */ - if (storage == NULL || entries == NULL || entriesCount == 0 || storageInitError == NULL) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* initialize storage and OD extensions */ - ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeBlank, - restoreBlank, entries, entriesCount); - if (ret != CO_ERROR_NO) { - return ret; - } - - /* initialize entries */ - *storageInitError = 0; - for (uint8_t i = 0; i < entriesCount; i++) { - CO_storage_entry_t* entry = &entries[i]; - - /* verify arguments */ - if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { - *storageInitError = i; - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Open a file and read data from file to entry->addr */ - /* file = open(entry->pathToFileOrPointerToMemory); */ - /* read(entry->addr, entry->len, file); */ - } - - return ret; +CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, uint8_t entriesCount, + uint32_t *storageInitError) +{ + CO_ReturnError_t ret; + + /* verify arguments */ + if (storage == NULL || entries == NULL || entriesCount == 0 || storageInitError == NULL) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* initialize storage and OD extensions */ + ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, + OD_1011_RestoreDefaultParam, storeBlank, restoreBlank, entries, + entriesCount); + if (ret != CO_ERROR_NO) { + return ret; + } + + /* initialize entries */ + *storageInitError = 0; + for (uint8_t i = 0; i < entriesCount; i++) { + CO_storage_entry_t *entry = &entries[i]; + + /* verify arguments */ + if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { + *storageInitError = i; + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + /* Open a file and read data from file to entry->addr */ + /* file = open(entry->pathToFileOrPointerToMemory); */ + /* read(entry->addr, entry->len, file); */ + } + + return ret; } #endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/zephyr/CO_storage_zephyr.h b/zephyr/CO_storage_zephyr.h index 48813ea9..9b97268d 100644 --- a/zephyr/CO_storage_zephyr.h +++ b/zephyr/CO_storage_zephyr.h @@ -12,9 +12,10 @@ * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ #ifndef CO_STORAGE_BLANK_H @@ -22,25 +23,30 @@ #include "storage/CO_storage.h" -#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { #endif /* - * This is very basic example of implementing (object dictionary) data storage. Data storage is target specific. - * CO_storageBlank.h and .c files only shows the basic principle, but does nothing. For complete example of storage see: - * - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c, CANopenNode/storage/CO_storageEeprom.h/.c, - * CANopenNode/storage/CO_eeprom.h and CANopenPIC/PIC32/CO_eepromPIC32.c files. - * - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and CANopenLinux/CO_storageLinux.h files. + * This is very basic example of implementing (object dictionary) data storage. Data storage is + * target specific. CO_storageBlank.h and .c files only shows the basic principle, but does nothing. + * For complete example of storage see: + * - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c, + * CANopenNode/storage/CO_storageEeprom.h/.c, CANopenNode/storage/CO_eeprom.h and + * CANopenPIC/PIC32/CO_eepromPIC32.c files. + * - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and + * CANopenLinux/CO_storageLinux.h files. */ -CO_ReturnError_t CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, - OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, - CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); +CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, uint8_t entriesCount, + uint32_t *storageInitError); -uint32_t CO_storageBlank_auto_process(CO_storage_t* storage, bool_t closeFiles); +uint32_t CO_storageBlank_auto_process(CO_storage_t *storage, bool_t closeFiles); #ifdef __cplusplus } diff --git a/zephyr/Kconfig.zephyr b/zephyr/Kconfig.zephyr index fd574c45..ba29156a 100644 --- a/zephyr/Kconfig.zephyr +++ b/zephyr/Kconfig.zephyr @@ -1,3 +1,6 @@ +config ZEPHYR_CANOPENNODE_MODULE + bool + config CANOPENNODE_TARGET_ZEPHYR bool "Enable Zephyr CANopen backend" depends on CANOPENNODE @@ -13,3 +16,20 @@ config CANOPENNODE_ZEPHYR_STORAGE_SETTINGS default y help Use Zephyr's settings subsystem to persist CANopen Object Dictionary parameters. + + +# ------------------------------------------------------------------------------ +# Logging +# ------------------------------------------------------------------------------ + +# CANOPEN_LOG_LEVEL_DBG +config CANOPENNODE_LOG_LEVEL + int "CANopenNode log level" + default 0 if LOG_DEFAULT_LEVEL_OFF + default 1 if LOG_DEFAULT_LEVEL_ERR + default 2 if LOG_DEFAULT_LEVEL_WRN + default 3 if LOG_DEFAULT_LEVEL_INF + default 4 if LOG_DEFAULT_LEVEL_DBG + range 0 5 + help + Set the log level for CANopenNode (overrides LOG_DEFAULT_LEVEL). diff --git a/zephyr/module.yml b/zephyr/module.yml new file mode 100644 index 00000000..18106843 --- /dev/null +++ b/zephyr/module.yml @@ -0,0 +1,9 @@ +# modules/canopennode/zephyr/module.yml +name: canopennode +build: + cmake: zephyr + kconfig: Kconfig +package-managers: + pip: + requirement-files: + - zephyr/requirements.txt diff --git a/zephyr/requirements.txt b/zephyr/requirements.txt new file mode 100644 index 00000000..35861f0a --- /dev/null +++ b/zephyr/requirements.txt @@ -0,0 +1 @@ +eds-utils From 5b58767fa0b1b896d41016fb18bbf4c7bb926774 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 6 Aug 2025 19:00:28 -0400 Subject: [PATCH 500/520] Improves CANopenNode Zephyr integration This commit enhances the CANopenNode integration with the Zephyr RTOS by addressing several issues and incorporating improvements. - Fixes an issue where the EDS file path was not correctly handled when empty, defaulting to the example EDS file. - Removes the CANOPENNODE_LOG_LEVEL Kconfig option and uses the generic CANOPEN_LOG_LEVEL. - Updates the CAN driver to use the device pointer directly, instead of relying on a global context. - Corrects a type mismatch, using `uint_fast16_t` instead of `uint16_t` for loop counters and other variables where performance is critical. - Adds a system initialization function to start the CANopen TX workqueue. - Standardizes on CAN_STD_ID_MASK --- CANopen.c | 2 +- Kconfig.core | 2 +- Kconfig.optional | 12 +--- zephyr/CMakeLists.txt | 12 ++-- zephyr/CO_driver.c | 155 ++++++++++++++++++++++++++---------------- 5 files changed, 106 insertions(+), 77 deletions(-) diff --git a/CANopen.c b/CANopen.c index 8306da29..67c6d5cc 100644 --- a/CANopen.c +++ b/CANopen.c @@ -134,7 +134,7 @@ #if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0 #if !defined OD_CNT_TIME #define OD_CNT_TIME 0 -#define OD_ENTRY_H1012 NULL +// #define OD_ENTRY_H1012 NULL #elif OD_CNT_TIME < 0 || OD_CNT_TIME > 1 #error OD_CNT_TIME from OD.h not correct! #endif diff --git a/Kconfig.core b/Kconfig.core index 229293ce..3b5fa9a0 100644 --- a/Kconfig.core +++ b/Kconfig.core @@ -1,6 +1,6 @@ config CANOPENNODE_EDS_FILE_PATH string "EDS file used to generate Object Dictionary" - default "modules/canopennode/tools/example.eds" + default "" help Path to the EDS (Electronic Data Sheet) file used to generate the CANopenNode object dictionary files (OD.h, OD.c). diff --git a/Kconfig.optional b/Kconfig.optional index cb3c9271..94e33dc8 100644 --- a/Kconfig.optional +++ b/Kconfig.optional @@ -52,14 +52,4 @@ config CANOPENNODE_PROGRAM_DOWNLOAD help Enable CiA 302-3 based program download over CANopen. -config CANOPENNODE_LOG_LEVEL - int "CANopenNode log level" - default 0 if LOG_DEFAULT_LEVEL_OFF - default 1 if LOG_DEFAULT_LEVEL_ERR - default 2 if LOG_DEFAULT_LEVEL_WRN - default 3 if LOG_DEFAULT_LEVEL_INF - default 4 if LOG_DEFAULT_LEVEL_DBG - default 5 if LOG_DEFAULT_LEVEL_DBG - range 0 5 - help - Set the log level for the CANopenNode module. + diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 01bf4195..f5fa448c 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -10,10 +10,14 @@ if(CONFIG_CANOPENNODE) set(CANOPENNODE_OD_GEN_C "${CANOPENNODE_OD_GEN_DIR}/OD.c") set(CANOPENNODE_OD_GEN_H "${CANOPENNODE_OD_GEN_DIR}/OD.h") - # Resolve EDS file path - set(CANOPENNODE_EDS_FILE_REL "${CONFIG_CANOPENNODE_EDS_FILE_PATH}") - set(CANOPENNODE_EDS_FILE "${APPLICATION_SOURCE_DIR}/${CANOPENNODE_EDS_FILE_REL}") - file(TO_CMAKE_PATH "${CANOPENNODE_EDS_FILE}" CANOPENNODE_EDS_FILE) + # Handle empty CONFIG_CANOPENNODE_EDS_FILE_PATH by defaulting to example EDS + if("${CONFIG_CANOPENNODE_EDS_FILE_PATH}" STREQUAL "") + set(CANOPENNODE_EDS_FILE "${CANOPENNODE_DIR}/example/DS301_profile.eds") + else() + set(CANOPENNODE_EDS_FILE_REL "${CONFIG_CANOPENNODE_EDS_FILE_PATH}") + set(CANOPENNODE_EDS_FILE "${APPLICATION_SOURCE_DIR}/${CANOPENNODE_EDS_FILE_REL}") + file(TO_CMAKE_PATH "${CANOPENNODE_EDS_FILE}" CANOPENNODE_EDS_FILE) + endif() file(MAKE_DIRECTORY "${CANOPENNODE_OD_GEN_DIR}") diff --git a/zephyr/CO_driver.c b/zephyr/CO_driver.c index 591f9e4e..62c1f5e3 100644 --- a/zephyr/CO_driver.c +++ b/zephyr/CO_driver.c @@ -29,7 +29,9 @@ #include #include -LOG_MODULE_REGISTER(canopen_driver, CONFIG_CANOPENNODE_LOG_LEVEL); +LOG_MODULE_REGISTER(canopennode_driver, CONFIG_CANOPEN_LOG_LEVEL); + +#define CANPTR_TO_DEV(ptr) ((const struct device *)(ptr)) typedef struct { uint32_t ident; @@ -37,6 +39,8 @@ typedef struct { uint8_t data[8]; } CO_CANrxMsg_t; +K_KERNEL_STACK_DEFINE(canopen_tx_workq_stack, CONFIG_CANOPENNODE_TX_WORKQUEUE_STACK_SIZE); + struct k_work_q canopen_tx_workq; struct canopen_tx_work_container { @@ -50,25 +54,20 @@ K_MUTEX_DEFINE(canopen_send_mutex); K_MUTEX_DEFINE(canopen_emcy_mutex); K_MUTEX_DEFINE(canopen_co_mutex); -static canopen_rxmsg_callback_t rxmsg_callback; - -void canopen_set_rxmsg_callback(canopen_rxmsg_callback_t callback) -{ - rxmsg_callback = callback; -} - static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule) { - uint16_t i; + uint_fast16_t i; - if (!CANmodule || !CANmodule->rx_array || !CANmodule->configured) { + if (!CANmodule || !CANmodule->CANptr || !CANmodule->rxArray) { return; } - for (i = 0U; i < CANmodule->rx_size; i++) { - if (CANmodule->rx_array[i].filter_id != -ENOSPC) { - can_remove_rx_filter(CANmodule->dev, CANmodule->rx_array[i].filter_id); - CANmodule->rx_array[i].filter_id = -ENOSPC; + const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); + + for (i = 0U; i < CANmodule->rxSize; i++) { + if (CANmodule->rxArray[i].filter_id != -ENOSPC) { + can_remove_rx_filter(dev, CANmodule->rxArray[i].filter_id); + CANmodule->rxArray[i].filter_id = -ENOSPC; } } } @@ -78,22 +77,21 @@ static void canopen_rx_callback(const struct device *dev, struct can_frame *fram CO_CANmodule_t *CANmodule = (CO_CANmodule_t *)user_data; CO_CANrxMsg_t rxMsg; CO_CANrx_t *buffer; - canopen_rxmsg_callback_t callback = rxmsg_callback; int i; ARG_UNUSED(dev); /* Loop through registered rx buffers in priority order */ - for (i = 0; i < CANmodule->rx_size; i++) { - buffer = &CANmodule->rx_array[i]; + for (i = 0; i < CANmodule->rxSize; i++) { + buffer = &CANmodule->rxArray[i]; - if (buffer->filter_id == -ENOSPC || buffer->pFunct == NULL) { + if (buffer->filter_id == -ENOSPC || buffer->CANrx_callback == NULL) { continue; } if (((frame->id ^ buffer->ident) & buffer->mask) == 0U) { #ifdef CONFIG_CAN_ACCEPT_RTR - if (buffer->rtr && ((frame->flags & CAN_FRAME_RTR) == 0U)) { + if ((buffer->ident & 0x800) && ((frame->flags & CAN_FRAME_RTR) == 0U)) { continue; } #endif /* CONFIG_CAN_ACCEPT_RTR */ @@ -120,7 +118,7 @@ static void canopen_tx_callback(const struct device *dev, int error, void *arg) } if (error == 0) { - CANmodule->first_tx_msg = false; + CANmodule->firstCANtxMessage = false; } k_work_submit_to_queue(&canopen_tx_workq, &canopen_tx_queue.work); @@ -131,25 +129,25 @@ static void canopen_tx_retry(struct k_work *item) struct canopen_tx_work_container *container = CONTAINER_OF(item, struct canopen_tx_work_container, work); CO_CANmodule_t *CANmodule = container->CANmodule; + const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); struct can_frame frame; CO_CANtx_t *buffer; int err; - uint16_t i; + uint_fast16_t i; memset(&frame, 0, sizeof(frame)); CO_LOCK_CAN_SEND(); - for (i = 0; i < CANmodule->tx_size; i++) { - buffer = &CANmodule->tx_array[i]; + for (i = 0; i < CANmodule->txSize; i++) { + buffer = &CANmodule->txArray[i]; if (buffer->bufferFull) { frame.id = buffer->ident; frame.dlc = buffer->DLC; - frame.flags |= (buffer->rtr ? CAN_FRAME_RTR : 0); + frame.flags |= ((buffer->ident & 0x800) ? CAN_FRAME_RTR : 0); memcpy(frame.data, buffer->data, buffer->DLC); - err = can_send(CANmodule->dev, &frame, K_NO_WAIT, canopen_tx_callback, - CANmodule); + err = can_send(dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); if (err == -EAGAIN) { break; } else if (err != 0) { @@ -165,10 +163,14 @@ static void canopen_tx_retry(struct k_work *item) void CO_CANsetConfigurationMode(void *CANptr) { - struct canopen_context *ctx = (struct canopen_context *)CANdriverState; + if (!CANptr) { + return; + } + + const struct device *dev = CANPTR_TO_DEV(CANptr); int err; - err = can_stop(ctx->dev); + err = can_stop(dev); if (err != 0 && err != -EALREADY) { LOG_ERR("failed to stop CAN interface (err %d)", err); } @@ -176,9 +178,14 @@ void CO_CANsetConfigurationMode(void *CANptr) void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) { + if (!CANmodule || !CANmodule->CANptr) { + return; + } + + const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); int err; - err = can_start(CANmodule->dev); + err = can_start(dev); if (err != 0 && err != -EALREADY) { LOG_ERR("failed to start CAN interface (err %d)", err); return; @@ -187,24 +194,24 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) CANmodule->CANnormal = true; } -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) +CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, void *CANptr, CO_CANrx_t rxArray[], + uint16_t rxSize, CO_CANtx_t txArray[], uint16_t txSize, + uint16_t CANbitRate) { - struct canopen_context *ctx = (struct canopen_context *)CANdriverState; - uint16_t i; + const struct device *dev = CANPTR_TO_DEV(CANptr); + uint_fast16_t i; int err; int max_filters; LOG_DBG("rxSize = %d, txSize = %d", rxSize, txSize); /* verify arguments */ - if (CANmodule == NULL || rxArray == NULL || txArray == NULL || CANdriverState == NULL) { + if (CANmodule == NULL || CANptr == NULL || rxArray == NULL || txArray == NULL) { LOG_ERR("failed to initialize CAN module"); return CO_ERROR_ILLEGAL_ARGUMENT; } - max_filters = can_get_max_filters(ctx->dev, false); + max_filters = can_get_max_filters(dev, false); if (max_filters != -ENOSYS) { if (max_filters < 0) { LOG_ERR("unable to determine number of CAN RX filters"); @@ -227,7 +234,7 @@ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, void *CANdriverSta canopen_tx_queue.CANmodule = CANmodule; /* Configure object variables */ - CANmodule->CANptr = ctx->dev; + CANmodule->CANptr = CANptr; CANmodule->rxArray = rxArray; CANmodule->rxSize = rxSize; CANmodule->txArray = txArray; @@ -244,7 +251,7 @@ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, void *CANdriverSta /* init functions. */ for (i = 0U; i < rxSize; i++) { rxArray[i].ident = 0U; - rxArray[i].pFunct = NULL; + rxArray[i].CANrx_callback = NULL; rxArray[i].filter_id = -ENOSPC; } } else { @@ -255,13 +262,13 @@ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, void *CANdriverSta txArray[i].bufferFull = false; } - err = can_set_bitrate(CANmodule->dev, KHZ(CANbitRate)); + err = can_set_bitrate(dev, KHZ(CANbitRate)); if (err) { LOG_ERR("failed to configure CAN bitrate (err %d)", err); return CO_ERROR_ILLEGAL_ARGUMENT; } - err = can_set_mode(CANmodule->dev, CAN_MODE_NORMAL); + err = can_set_mode(dev, CAN_MODE_NORMAL); if (err) { LOG_ERR("failed to configure CAN interface (err %d)", err); return CO_ERROR_ILLEGAL_ARGUMENT; @@ -274,13 +281,15 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) { int err; - if (!CANmodule || !CANmodule->dev) { + if (!CANmodule || !CANmodule->CANptr) { return; } + const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); + canopen_detach_all_rx_filters(CANmodule); - err = can_stop(CANmodule->dev); + err = can_stop(dev); if (err != 0 && err != -EALREADY) { LOG_ERR("failed to disable CAN interface (err %d)", err); } @@ -293,19 +302,19 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, u struct can_filter filter; CO_ReturnError_t ret = CO_ERROR_NO; - if ((CANmodule != NULL) && (object != NULL) && (CANrx_callback != NULL) && - (index < CANmodule->rxSize)) { + if ((CANmodule != NULL) && (CANmodule->CANptr != NULL) && (object != NULL) && + (CANrx_callback != NULL) && (index < CANmodule->rxSize)) { /* buffer, which will be configured */ CO_CANrx_t *buffer = &CANmodule->rxArray[index]; - + const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); /* Configure object variables */ buffer->object = object; buffer->CANrx_callback = CANrx_callback; /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different * microcontrollers. */ - buffer->ident = ident & 0x07FFU; - buffer->mask = (mask & 0x07FFU) | 0x0800U; + buffer->ident = ident & CAN_STD_ID_MASK; + buffer->mask = (mask & CAN_STD_ID_MASK) | 0x0800U; #ifndef CONFIG_CAN_ACCEPT_RTR if (rtr) { @@ -325,10 +334,10 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, u filter.mask = mask; if (buffer->filter_id != -ENOSPC) { - can_remove_rx_filter(CANmodule->dev, buffer->filter_id); + can_remove_rx_filter(dev, buffer->filter_id); } - buffer->filter_id = can_add_rx_filter(CANmodule->dev, canopen_rx_callback, - CANmodule, &filter); + buffer->filter_id = + can_add_rx_filter(dev, canopen_rx_callback, CANmodule, &filter); if (buffer->filter_id == -ENOSPC) { LOG_ERR("failed to add CAN rx callback, no free filter"); ret = CO_ERROR_OUT_OF_MEMORY; @@ -352,9 +361,9 @@ CO_CANtx_t *CO_CANtxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, uint16 /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer, * microcontroller specific. */ - buffer->ident = ((uint32_t)ident & 0x07FFU) | + buffer->ident = ((uint32_t)ident & CAN_STD_ID_MASK) | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) | - ((uint32_t)(rtr ? 0x8000U : 0U)); + ((uint32_t)(rtr ? 0x800U : 0U)); buffer->bufferFull = false; buffer->syncFlag = syncFlag; @@ -368,19 +377,21 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) CO_ReturnError_t err = CO_ERROR_NO; struct can_frame frame; - if (!CANmodule || !CANmodule->dev || !buffer) { + if (!CANmodule || !CANmodule->CANptr || !buffer) { return CO_ERROR_ILLEGAL_ARGUMENT; } + const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); + memset(&frame, 0, sizeof(frame)); frame.id = buffer->ident; frame.dlc = buffer->DLC; - frame.flags = (buffer->rtr ? CAN_FRAME_RTR : 0); + frame.flags = ((buffer->ident & 0x800) ? CAN_FRAME_RTR : 0); memcpy(frame.data, buffer->data, buffer->DLC); CO_LOCK_CAN_SEND(CANmodule); - err = can_send(CANmodule->dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); + err = can_send(dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); if (err == -EAGAIN) { LOG_ERR("failed to send CAN frame, tx overflow"); err = CO_ERROR_TX_OVERFLOW; @@ -399,12 +410,16 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) { bool_t tpdoDeleted = false; CO_CANtx_t *buffer; - uint16_fast_t i; + uint_fast16_t i; + + if (!CANmodule || !CANmodule->CANptr || !CANmodule->txArray) { + return; + } CO_LOCK_CAN_SEND(CANmodule); - for (i = 0; i < CANmodule->tx_size; i++) { - buffer = &CANmodule->tx_array[i]; + for (i = 0; i < CANmodule->txSize; i++) { + buffer = &CANmodule->txArray[i]; if (buffer->bufferFull && buffer->syncFlag) { buffer->bufferFull = false; tpdoDeleted = true; @@ -420,16 +435,20 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) /* Get error counters from the module. If necessary, function may use different way to determine * errors. */ -static uint16_t rxErrors = 0, txErrors = 0, overflow = 0; +static uint_fast16_t rxErrors = 0, txErrors = 0, overflow = 0; void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { uint32_t err; + if (!CANmodule || !CANmodule->CANptr) { + return; + } + err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; if (CANmodule->errOld != err) { - uint16_t status = CANmodule->CANerrorStatus; + uint_fast16_t status = CANmodule->CANerrorStatus; CANmodule->errOld = err; @@ -470,3 +489,19 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) CANmodule->CANerrorStatus = status; } } + +static int canopen_init(void) +{ + + k_work_queue_start(&canopen_tx_workq, canopen_tx_workq_stack, + K_KERNEL_STACK_SIZEOF(canopen_tx_workq_stack), + CONFIG_CANOPENNODE_TX_WORKQUEUE_PRIORITY, NULL); + + k_thread_name_set(&canopen_tx_workq.thread, "canopen_tx_workq"); + + k_work_init(&canopen_tx_queue.work, canopen_tx_retry); + + return 0; +} + +SYS_INIT(canopen_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From 8e1072a08d5b2c3c83b67fca9f129697dba0f6b9 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Thu, 7 Aug 2025 14:17:30 -0400 Subject: [PATCH 501/520] Improves PDO configuration and storage Refactors PDO configuration by correcting conditional compilation flags for dynamic PDO mapping and SYNC enabling. Adds flexible storage backend selection (Settings, RAM, None) with Kconfig options, replacing the previous boolean flag. Improves code readability and maintainability. --- 301/CO_PDO.c | 112 +++++++++++++++--------------- zephyr/CMakeLists.txt | 36 +++++++++- zephyr/CO_driver.c | 31 ++++++++- zephyr/CO_driver_target.h | 11 +++ zephyr/CO_storage_zephyr.c | 135 ++++++++++++++++++++++--------------- zephyr/CO_storage_zephyr.h | 57 ++++++++++------ zephyr/Kconfig.zephyr | 82 ++++++++++++++++------ 7 files changed, 310 insertions(+), 154 deletions(-) diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 527618b3..f264c73a 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -24,13 +24,13 @@ #if ((CO_CONFIG_PDO) & (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE)) != 0 -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) == 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 #error Dynamic PDO mapping is not possible without CO_CONFIG_PDO_OD_IO_ACCESS #endif #endif -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 /* * Custom function for write dummy OD object. Will be used only from RPDO. * @@ -207,7 +207,7 @@ PDO_initMapping(CO_PDO_common_t* PDO, OD_t* OD, OD_entry_t* OD_PDOMapPar, bool_t return CO_ERROR_NO; } -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "PDO mapping parameter" * @@ -273,7 +273,7 @@ OD_write_PDO_mapping(OD_stream_t* stream, const void* buf, OD_size_t count, OD_s #endif /* (CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC */ #endif /* (CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) == 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 static CO_ReturnError_t PDO_initMapping(CO_PDO_common_t* PDO, OD_t* OD, OD_entry_t* OD_PDOMapPar, bool_t isRPDO, uint32_t* errInfo, uint32_t* erroneousMap) { @@ -370,7 +370,7 @@ PDO_initMapping(CO_PDO_common_t* PDO, OD_t* OD, OD_entry_t* OD_PDOMapPar, bool_t #endif /* ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) == 0 */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for reading OD object "PDO communication parameter" * @@ -407,7 +407,7 @@ OD_read_PDO_commParam(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t /******************************************************************************* * R P D O ******************************************************************************/ -#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) != 0 /* * @defgroup CO_PDO_receiveErrors_t States for RPDO->receiveError indicates received RPDOs with wrong length. * @{ @@ -453,17 +453,19 @@ CO_PDO_receive(void* object, void* msg) { /* Determine, to which of the two rx buffers copy the message. */ uint8_t bufNo = 0; -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if (RPDO->synchronous && (RPDO->SYNC != NULL) && RPDO->SYNC->CANrxToggle) { bufNo = 1; } #endif /* copy data into appropriate buffer and set 'new message' flag */ - (void)memcpy(RPDO->CANrxData[bufNo], data, CO_PDO_MAX_SIZE); - CO_FLAG_SET(RPDO->CANrxNew[bufNo]); + if (data != NULL) { + (void)memcpy(RPDO->CANrxData[bufNo], data, CO_PDO_MAX_SIZE); + CO_FLAG_SET(RPDO->CANrxNew[bufNo]); + } -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 /* Optional signal to RTOS, which can resume task, which handles the RPDO. */ if (RPDO->pFunctSignalPre != NULL) { RPDO->pFunctSignalPre(RPDO->functSignalObjectPre); @@ -478,7 +480,7 @@ CO_PDO_receive(void* object, void* msg) { RPDO->receiveError = err; } -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "RPDO communication parameter" * @@ -528,7 +530,7 @@ OD_write_14xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* } else { PDO->valid = false; CO_FLAG_CLEAR(RPDO->CANrxNew[0]); -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 CO_FLAG_CLEAR(RPDO->CANrxNew[1]); #endif if (ret != CO_ERROR_NO) { @@ -540,7 +542,7 @@ OD_write_14xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* } case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)) { return ODR_INVALID_VALUE; @@ -561,7 +563,7 @@ OD_write_14xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* break; } -#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 case 5: { /* event-timer */ uint32_t eventTime = CO_getUint16(buf); RPDO->timeoutTime_us = eventTime * 1000U; @@ -581,7 +583,7 @@ OD_write_14xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* CO_ReturnError_t CO_RPDO_init(CO_RPDO_t* RPDO, OD_t* OD, CO_EM_t* em, -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 CO_SYNC_t* SYNC, #endif uint16_t preDefinedCanId, OD_entry_t* OD_14xx_RPDOCommPar, OD_entry_t* OD_16xx_RPDOMapPar, @@ -650,7 +652,7 @@ CO_RPDO_init(CO_RPDO_t* RPDO, OD_t* OD, CO_EM_t* em, PDO->valid = valid; /* Configure communication parameter - transmission type */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 uint8_t transmissionType = (uint8_t)(CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO); odRet = OD_get_u8(OD_14xx_RPDOCommPar, 2, &transmissionType, true); if (odRet != ODR_OK) { @@ -665,14 +667,14 @@ CO_RPDO_init(CO_RPDO_t* RPDO, OD_t* OD, CO_EM_t* em, #endif /* Configure communication parameter - event-timer (optional) */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 uint16_t eventTime = 0; (void)OD_get_u16(OD_14xx_RPDOCommPar, 5, &eventTime, true); RPDO->timeoutTime_us = (uint32_t)eventTime * 1000U; #endif /* Configure OD extensions */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 PDO->isRPDO = true; PDO->OD = OD; PDO->CANdevIdx = CANdevRxIdx; @@ -691,7 +693,7 @@ CO_RPDO_init(CO_RPDO_t* RPDO, OD_t* OD, CO_EM_t* em, return CO_ERROR_NO; } -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) != 0 void CO_RPDO_initCallbackPre(CO_RPDO_t* RPDO, void* object, void (*pFunctSignalPre)(void* object)) { if (RPDO != NULL) { @@ -703,19 +705,19 @@ CO_RPDO_initCallbackPre(CO_RPDO_t* RPDO, void* object, void (*pFunctSignalPre)(v void CO_RPDO_process(CO_RPDO_t* RPDO, -#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 uint32_t timeDifference_us, uint32_t* timerNext_us, #endif bool_t NMTisOperational, bool_t syncWas) { (void)syncWas; -#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 (void)timerNext_us; #endif CO_PDO_common_t* PDO = &RPDO->PDO_common; if (PDO->valid && NMTisOperational -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 && (syncWas || !RPDO->synchronous) #endif ) { @@ -729,7 +731,7 @@ CO_RPDO_process(CO_RPDO_t* RPDO, /* Determine, which of the two rx buffers contains relevant message. */ uint8_t bufNo = 0; -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if (RPDO->synchronous && (RPDO->SYNC != NULL) && !RPDO->SYNC->CANrxToggle) { bufNo = 1; } @@ -746,7 +748,7 @@ CO_RPDO_process(CO_RPDO_t* RPDO, * by receive thread, then copy the latest data again. */ CO_FLAG_CLEAR(RPDO->CANrxNew[bufNo]); -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { OD_IO_t* OD_IO = &PDO->OD_IO[i]; @@ -816,7 +818,7 @@ CO_RPDO_process(CO_RPDO_t* RPDO, /* verify RPDO timeout */ (void)rpdoReceived; -#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 if (RPDO->timeoutTime_us > 0U) { if (rpdoReceived) { if (RPDO->timeoutTimer > RPDO->timeoutTime_us) { @@ -832,7 +834,7 @@ CO_RPDO_process(CO_RPDO_t* RPDO, } } else { /* MISRA C 2004 14.10 */ } -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if ((timerNext_us != NULL) && (RPDO->timeoutTimer < RPDO->timeoutTime_us)) { uint32_t diff = RPDO->timeoutTime_us - RPDO->timeoutTimer; if (*timerNext_us > diff) { @@ -842,20 +844,20 @@ CO_RPDO_process(CO_RPDO_t* RPDO, #endif } #endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE */ - } /* if (PDO->valid && NMTisOperational) */ + } /* if (PDO->valid && NMTisOperational) */ else { /* not valid and operational, clear CAN receive flags and timeoutTimer */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if (!PDO->valid || !NMTisOperational) { CO_FLAG_CLEAR(RPDO->CANrxNew[0]); CO_FLAG_CLEAR(RPDO->CANrxNew[1]); -#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 RPDO->timeoutTimer = 0; #endif } #else CO_FLAG_CLEAR(RPDO->CANrxNew[0]); -#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 RPDO->timeoutTimer = 0; #endif #endif @@ -866,8 +868,8 @@ CO_RPDO_process(CO_RPDO_t* RPDO, /******************************************************************************* * T P D O ******************************************************************************/ -#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0 -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 /* * Custom function for writing OD object "TPDO communication parameter" * @@ -924,7 +926,7 @@ OD_write_18xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* } case 2: { /* transmission type */ uint8_t transmissionType = CO_getUint8(buf); -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 if ((transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) && (transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)) { return ODR_INVALID_VALUE; @@ -938,14 +940,14 @@ OD_write_18xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* #endif TPDO->transmissionType = transmissionType; TPDO->sendRequest = true; -#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->inhibitTimer = 0; TPDO->eventTimer = 0; #endif break; } -#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 case 3: { /* inhibit time */ if (PDO->valid) { return ODR_INVALID_VALUE; @@ -964,7 +966,7 @@ OD_write_18xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* } #endif -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 case 6: { /* SYNC start value */ uint8_t syncStartValue = CO_getUint8(buf); @@ -987,7 +989,7 @@ OD_write_18xx(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* CO_ReturnError_t CO_TPDO_init(CO_TPDO_t* TPDO, OD_t* OD, CO_EM_t* em, -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 CO_SYNC_t* SYNC, #endif uint16_t preDefinedCanId, OD_entry_t* OD_18xx_TPDOCommPar, OD_entry_t* OD_1Axx_TPDOMapPar, @@ -1025,7 +1027,7 @@ CO_TPDO_init(CO_TPDO_t* TPDO, OD_t* OD, CO_EM_t* em, return CO_ERROR_OD_PARAMETERS; } if ((transmissionType < (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 && (transmissionType > (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_240) #endif ) { @@ -1076,7 +1078,7 @@ CO_TPDO_init(CO_TPDO_t* TPDO, OD_t* OD, CO_EM_t* em, PDO->valid = valid; /* Configure communication parameter - inhibit time and event-timer (opt) */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 uint16_t inhibitTime = 0; uint16_t eventTime = 0; (void)OD_get_u16(OD_18xx_TPDOCommPar, 3, &inhibitTime, true); @@ -1086,7 +1088,7 @@ CO_TPDO_init(CO_TPDO_t* TPDO, OD_t* OD, CO_EM_t* em, #endif /* Configure communication parameter - SYNC start value (optional) */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncStartValue = 0; (void)OD_get_u8(OD_18xx_TPDOCommPar, 6, &TPDO->syncStartValue, true); TPDO->SYNC = SYNC; @@ -1094,7 +1096,7 @@ CO_TPDO_init(CO_TPDO_t* TPDO, OD_t* OD, CO_EM_t* em, #endif /* Configure OD extensions */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) != 0 PDO->isRPDO = false; PDO->OD = OD; PDO->CANdevIdx = CANdevTxIdx; @@ -1134,7 +1136,7 @@ CO_TPDOsend(CO_TPDO_t* TPDO) { || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)); #endif -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_OD_IO_ACCESS) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) != 0 for (uint8_t i = 0; i < PDO->mappedObjectsCount; i++) { OD_IO_t* OD_IO = &PDO->OD_IO[i]; OD_stream_t* stream = &OD_IO->stream; @@ -1219,7 +1221,7 @@ CO_TPDOsend(CO_TPDO_t* TPDO) { } TPDO->sendRequest = false; -#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->eventTimer = TPDO->eventTime_us; TPDO->inhibitTimer = TPDO->inhibitTime_us; #endif @@ -1228,12 +1230,12 @@ CO_TPDOsend(CO_TPDO_t* TPDO) { void CO_TPDO_process(CO_TPDO_t* TPDO, -#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN uint32_t timeDifference_us, uint32_t* timerNext_us, #endif bool_t NMTisOperational, bool_t syncWas) { CO_PDO_common_t* PDO = &TPDO->PDO_common; -#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE)) != 0 +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE)) != 0 (void)timerNext_us; #endif (void)syncWas; @@ -1241,17 +1243,17 @@ CO_TPDO_process(CO_TPDO_t* TPDO, if (PDO->valid && NMTisOperational) { /* check for event timer or application event */ -#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || (OD_FLAGS_PDO_SIZE > 0) +#if (((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0) || (OD_FLAGS_PDO_SIZE > 0) if ((TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) || (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO)) { /* event timer */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 if (TPDO->eventTime_us != 0U) { TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) ? (TPDO->eventTimer - timeDifference_us) : 0U; if (TPDO->eventTimer == 0U) { TPDO->sendRequest = true; } -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if ((timerNext_us != NULL) && (*timerNext_us > TPDO->eventTimer)) { /* Schedule for next event time */ *timerNext_us = TPDO->eventTimer; @@ -1278,7 +1280,7 @@ CO_TPDO_process(CO_TPDO_t* TPDO, /* Send PDO by application request or by Event timer */ if (TPDO->transmissionType >= (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) { -#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) : 0U; @@ -1287,7 +1289,7 @@ CO_TPDO_process(CO_TPDO_t* TPDO, (void)CO_TPDOsend(TPDO); } -#if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (TPDO->sendRequest && (timerNext_us != NULL) && (*timerNext_us > TPDO->inhibitTimer)) { /* Schedule for just beyond inhibit window */ *timerNext_us = TPDO->inhibitTimer; @@ -1301,7 +1303,7 @@ CO_TPDO_process(CO_TPDO_t* TPDO, } /* if (TPDO->transmissionType >= CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO) */ /* Synchronous PDOs */ -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 else if ((TPDO->SYNC != NULL) && syncWas) { /* send synchronous acyclic TPDO */ if (TPDO->transmissionType == (uint8_t)CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC) { @@ -1335,7 +1337,7 @@ CO_TPDO_process(CO_TPDO_t* TPDO, } else { /* MISRA C 2004 14.10 */ } } - } /* else if (TPDO->SYNC && syncWas) */ + } /* else if (TPDO->SYNC && syncWas) */ else { /* MISRA C 2004 14.10 */ } #endif @@ -1343,11 +1345,11 @@ CO_TPDO_process(CO_TPDO_t* TPDO, } else { /* Not operational or valid, reset triggers */ TPDO->sendRequest = true; -#if ((CO_CONFIG_PDO)&CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) != 0 TPDO->inhibitTimer = 0; TPDO->eventTimer = 0; #endif -#if ((CO_CONFIG_PDO)&CO_CONFIG_PDO_SYNC_ENABLE) != 0 +#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) != 0 TPDO->syncCounter = 255; #endif } diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index f5fa448c..fdccb4f4 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -76,14 +76,46 @@ if(CONFIG_CANOPENNODE) # Optional modules zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_LEDS "${CANOPENNODE_DIR}/303/CO_LEDs.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_304 "${CANOPENNODE_DIR}/304/CO_GFC.c") zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_304 "${CANOPENNODE_DIR}/304/CO_SRDO.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/305/CO_LSSmaster.c") zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/305/CO_LSSslave.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_309 "${CANOPENNODE_DIR}/309/CO_gateway_ascii.c") + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/extra/CO_trace.c") - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_STORAGE "${CANOPENNODE_DIR}/storage/CO_storage.c") - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_STORAGE "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c") + + + zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_PROGRAM_DOWNLOAD "${CANOPENNODE_DIR}/zephyr/canopen_program.c") + + + if(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) + zephyr_library_sources( + "${CANOPENNODE_DIR}/storage/CO_storage.c" + "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c" + "${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c" + ) + message(STATUS "CANopenNode: Using Zephyr Settings storage backend") + + elseif(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) + zephyr_library_sources( + "${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c" + ) + message(STATUS "CANopenNode: Using RAM-only OD storage") + + elseif(CONFIG_CANOPEN_STORAGE_BACKEND_NONE) + message(STATUS "CANopenNode: OD storage disabled (NONE)") + + else() + message(WARNING "CANopenNode: No valid OD storage backend selected — defaulting to NONE") + add_compile_definitions(CONFIG_CANOPEN_STORAGE_BACKEND_NONE=1) + message(STATUS "CANopenNode: OD storage disabled (failsafe fallback)") + endif() + + + endif() diff --git a/zephyr/CO_driver.c b/zephyr/CO_driver.c index 62c1f5e3..b69ebeb5 100644 --- a/zephyr/CO_driver.c +++ b/zephyr/CO_driver.c @@ -54,6 +54,36 @@ K_MUTEX_DEFINE(canopen_send_mutex); K_MUTEX_DEFINE(canopen_emcy_mutex); K_MUTEX_DEFINE(canopen_co_mutex); +inline void canopen_send_lock(void) +{ + k_mutex_lock(&canopen_send_mutex, K_FOREVER); +} + +inline void canopen_send_unlock(void) +{ + k_mutex_unlock(&canopen_send_mutex); +} + +inline void canopen_emcy_lock(void) +{ + k_mutex_lock(&canopen_emcy_mutex, K_FOREVER); +} + +inline void canopen_emcy_unlock(void) +{ + k_mutex_unlock(&canopen_emcy_mutex); +} + +inline void canopen_od_lock(void) +{ + k_mutex_lock(&canopen_co_mutex, K_FOREVER); +} + +inline void canopen_od_unlock(void) +{ + k_mutex_unlock(&canopen_co_mutex); +} + static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule) { uint_fast16_t i; @@ -492,7 +522,6 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) static int canopen_init(void) { - k_work_queue_start(&canopen_tx_workq, canopen_tx_workq_stack, K_KERNEL_STACK_SIZEOF(canopen_tx_workq_stack), CONFIG_CANOPENNODE_TX_WORKQUEUE_PRIORITY, NULL); diff --git a/zephyr/CO_driver_target.h b/zephyr/CO_driver_target.h index 033c5d94..15101baa 100644 --- a/zephyr/CO_driver_target.h +++ b/zephyr/CO_driver_target.h @@ -116,8 +116,19 @@ typedef struct { uint8_t attr; /* Additional variables (target specific) */ void *addrNV; + void *storageModule; + uint8_t *data; + size_t eepromAddr; + // size_t len; + + // entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); + // entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); + // entry->offset = 0; + // entry->storageModule, entry->addr, entry->eepromAddr, entry->len); } CO_storage_entry_t; +// bool_t CO_eeprom_writeBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len); + /* (un)lock critical section in CO_CANsend() */ void canopen_send_lock(void); void canopen_send_unlock(void); diff --git a/zephyr/CO_storage_zephyr.c b/zephyr/CO_storage_zephyr.c index ae70eaba..59911221 100644 --- a/zephyr/CO_storage_zephyr.c +++ b/zephyr/CO_storage_zephyr.c @@ -1,90 +1,117 @@ -/* - * CANopen Object Dictionary storage object (blank example). - * - * @file CO_storageBlank.c - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -#include "CO_storageBlank.h" +#include "CO_storage_zephyr.h" + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(canopen_storage, CONFIG_CANOPENNODE_LOG_LEVEL); #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE -/* - * Function for writing data on "Store parameters" command - OD object 1010 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t storeBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) +#ifdef CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS +#include +#endif + +/* Store OD entry (1010) */ +static ODR_t store_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { +#if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) + + char key[64]; + snprintf(key, sizeof(key), "canopen/od/%04X", entry->subIndexOD); + int err = settings_save_one(key, entry->addr, entry->len); + if (err) { + LOG_ERR("Settings save failed (%d) for key %s", err, key); + return ODR_HW; + } + +#elif defined(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) + + LOG_DBG("Skipping store (RAM-only backend)"); - /* Open a file and write data to it */ - /* file = open(entry->pathToFileOrPointerToMemory); */ - /* write(entry->addr, entry->len, file); */ +#else + + LOG_WRN("No valid storage backend selected — store operation skipped"); + +#endif return ODR_OK; } -/* - * Function for restoring data on "Restore default parameters" command - OD 1011 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t restoreBlank(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) +/* Restore OD entry (1011) */ +static ODR_t restore_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { +#if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) + + char key[64]; + snprintf(key, sizeof(key), "canopen/od/%04X", entry->subIndexOD); + int err = settings_delete(key); + if (err) { + LOG_WRN("Settings delete failed (%d) for key %s", err, key); + } + +#elif defined(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) + + LOG_DBG("Skipping restore (RAM-only backend)"); - /* disable (delete) the file, so default values will stay after startup */ +#else + + LOG_WRN("No valid storage backend selected — restore operation skipped"); + +#endif return ODR_OK; } -CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParam, - CO_storage_entry_t *entries, uint8_t entriesCount, - uint32_t *storageInitError) +/* Initialization */ +CO_ReturnError_t CO_storage_zephyr_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, uint8_t entriesCount, + uint32_t *storageInitError) { - CO_ReturnError_t ret; - - /* verify arguments */ if (storage == NULL || entries == NULL || entriesCount == 0 || storageInitError == NULL) { return CO_ERROR_ILLEGAL_ARGUMENT; } - /* initialize storage and OD extensions */ - ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, - OD_1011_RestoreDefaultParam, storeBlank, restoreBlank, entries, - entriesCount); + CO_ReturnError_t ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, + OD_1011_RestoreDefaultParam, store_zephyr, + restore_zephyr, entries, entriesCount); + if (ret != CO_ERROR_NO) { return ret; } - /* initialize entries */ *storageInitError = 0; + for (uint8_t i = 0; i < entriesCount; i++) { CO_storage_entry_t *entry = &entries[i]; - /* verify arguments */ if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { *storageInitError = i; return CO_ERROR_ILLEGAL_ARGUMENT; } - /* Open a file and read data from file to entry->addr */ - /* file = open(entry->pathToFileOrPointerToMemory); */ - /* read(entry->addr, entry->len, file); */ +#if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) + + char key[64]; + snprintf(key, sizeof(key), "canopen/od/%04X", entry->subIndexOD); + int rc = settings_load_subtree_direct(key, entry->addr, entry->len); + if (rc < 0) { + LOG_DBG("No settings found for %s", key); + } + +#elif defined(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) + + // RAM-only, already loaded from default or boot values + +#else + + LOG_WRN("No valid storage backend selected — skipping restore for 0x%02X", + entry->subIndexOD); + +#endif } return ret; diff --git a/zephyr/CO_storage_zephyr.h b/zephyr/CO_storage_zephyr.h index 9b97268d..4e7363b3 100644 --- a/zephyr/CO_storage_zephyr.h +++ b/zephyr/CO_storage_zephyr.h @@ -1,5 +1,5 @@ /* - * CANopen data storage object (blank example) + * CANopen Object Dictionary storage for Zephyr backends * * @file CO_storageBlank.h * @author Janez Paternoster @@ -12,14 +12,12 @@ * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND. */ -#ifndef CO_STORAGE_BLANK_H -#define CO_STORAGE_BLANK_H +#ifndef CO_STORAGE_ZEPHYR_H +#define CO_STORAGE_ZEPHYR_H #include "storage/CO_storage.h" @@ -29,29 +27,48 @@ extern "C" { #endif -/* - * This is very basic example of implementing (object dictionary) data storage. Data storage is - * target specific. CO_storageBlank.h and .c files only shows the basic principle, but does nothing. - * For complete example of storage see: - * - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c, - * CANopenNode/storage/CO_storageEeprom.h/.c, CANopenNode/storage/CO_eeprom.h and - * CANopenPIC/PIC32/CO_eepromPIC32.c files. - * - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and - * CANopenLinux/CO_storageLinux.h files. +/** + * @brief Initialize CANopen storage using Zephyr backends (Settings, LittleFS, or RAM). + * + * This implementation uses the selected Kconfig storage backend. + * + * @param storage Pointer to CO_storage object + * @param CANmodule CAN module used for logging and sync + * @param OD_1010_StoreParameters Object Dictionary entry for OD 1010 + * @param OD_1011_RestoreDefaultParam Object Dictionary entry for OD 1011 + * @param entries Array of storage entries + * @param entriesCount Number of entries in the array + * @param storageInitError Pointer to variable to store error index (if any) + * + * @return CO_ReturnError_t CO_ERROR_NO on success, otherwise error code */ - CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParam, CO_storage_entry_t *entries, uint8_t entriesCount, uint32_t *storageInitError); -uint32_t CO_storageBlank_auto_process(CO_storage_t *storage, bool_t closeFiles); +/** + * @brief Optional auto-save processing function (not implemented in Zephyr backend) + * + * This is a stub function that can be implemented if needed for timed or conditional saving. + * + * @param storage Pointer to CO_storage object + * @param closeFiles Flag to indicate if files should be closed after processing + * + * @return uint32_t Bitmask of flags indicating modified entries (always 0 in this backend) + */ +static inline uint32_t CO_storageBlank_auto_process(CO_storage_t *storage, bool_t closeFiles) +{ + ARG_UNUSED(storage); + ARG_UNUSED(closeFiles); + return 0; +} #ifdef __cplusplus } -#endif /* __cplusplus */ +#endif #endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ -#endif /* CO_STORAGE_BLANK_H */ +#endif /* CO_STORAGE_ZEPHYR_H */ diff --git a/zephyr/Kconfig.zephyr b/zephyr/Kconfig.zephyr index ba29156a..673726d4 100644 --- a/zephyr/Kconfig.zephyr +++ b/zephyr/Kconfig.zephyr @@ -1,28 +1,65 @@ +# Top-level module enable config ZEPHYR_CANOPENNODE_MODULE bool + prompt "Enable CANopenNode module integration with Zephyr" + default y +# Zephyr CANopenNode backend support config CANOPENNODE_TARGET_ZEPHYR - bool "Enable Zephyr CANopen backend" - depends on CANOPENNODE - default y - help - Use Zephyr RTOS-specific CANopenNode interface for CAN and storage. - This enables CO_driver_zephyr.c and CO_storage_zephyr.c. - -# Optional override for storage backend -config CANOPENNODE_ZEPHYR_STORAGE_SETTINGS - bool "Use Zephyr settings API for OD storage" - depends on CANOPENNODE_TARGET_ZEPHYR && CANOPENNODE_STORAGE - default y - help - Use Zephyr's settings subsystem to persist CANopen Object Dictionary parameters. - - -# ------------------------------------------------------------------------------ -# Logging -# ------------------------------------------------------------------------------ - -# CANOPEN_LOG_LEVEL_DBG + bool "Enable Zephyr CANopen backend" + depends on ZEPHYR_CANOPENNODE_MODULE + default y + help + Use Zephyr RTOS-specific CANopenNode interface for CAN and storage. + This enables CO_driver_zephyr.c and CO_storage_zephyr.c. + +# ------------------------------------------------------------------ +# CANopenNode OD Storage Backend +# ------------------------------------------------------------------ + +menu "CANopenNode OD Storage" + depends on CANOPENNODE_TARGET_ZEPHYR + +choice CANOPEN_STORAGE_BACKEND_CHOICE + prompt "Select CANopenNode OD storage backend" + depends on CANOPENNODE_TARGET_ZEPHYR + default CANOPEN_STORAGE_BACKEND_RAM + +config CANOPEN_STORAGE_BACKEND_SETTINGS + bool "Zephyr Settings subsystem" + select SETTINGS + help + Use Zephyr’s settings subsystem to persist Object Dictionary (OD) entries. + +config CANOPEN_STORAGE_BACKEND_RAM + bool "RAM-only (no persistence)" + help + Store Object Dictionary (OD) values in RAM only. + Values will be lost on reset or power cycle. Suitable for testing and + volatile-only applications. + +config CANOPEN_STORAGE_BACKEND_NONE + bool "None (disable OD storage)" + help + Disable Object Dictionary (OD) storage completely. + No RAM or persistent storage will be allocated or used. + +endchoice + +config CANOPEN_LITTLEFS_MOUNT_PATH + string "Mount path for LittleFS OD storage" + depends on CANOPEN_STORAGE_BACKEND_LITTLEFS + default "/lfs1" + help + Filesystem mount path under which OD entries will be stored. + Full path will be /canopen/od/. + +endmenu + +# ------------------------------------------------------------------ +# Logging Configuration +# ------------------------------------------------------------------ + config CANOPENNODE_LOG_LEVEL int "CANopenNode log level" default 0 if LOG_DEFAULT_LEVEL_OFF @@ -32,4 +69,5 @@ config CANOPENNODE_LOG_LEVEL default 4 if LOG_DEFAULT_LEVEL_DBG range 0 5 help - Set the log level for CANopenNode (overrides LOG_DEFAULT_LEVEL). + Set the log level for CANopenNode. Overrides LOG_DEFAULT_LEVEL. + Levels: 0=Off, 1=Error, 2=Warning, 3=Info, 4=Debug, 5=Verbose. From 148facc2a2599db186ac4340a5e619f76effb1cb Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Mon, 11 Aug 2025 17:41:09 -0400 Subject: [PATCH 502/520] Fix kconfigs and add correct file inclusions. --- Kconfig | 23 -- Kconfig.core | 38 -- Kconfig.optional | 55 --- Kconfig.roles | 67 --- zephyr/CMakeLists.txt | 250 ++++++----- zephyr/CO_driver.c | 2 +- zephyr/CO_storage_zephyr.c | 2 +- zephyr/Kconfig | 503 +++++++++++++++++++++++ zephyr/Kconfig.zephyr | 73 ---- zephyr/crc16-ccitt_zephyr.c | 36 ++ zephyr/include/CO_config_zephyr.h | 141 +++++++ zephyr/{ => include}/CO_driver_target.h | 0 zephyr/{ => include}/CO_storage_zephyr.h | 0 zephyr/module.yml | 2 +- 14 files changed, 833 insertions(+), 359 deletions(-) delete mode 100644 Kconfig delete mode 100644 Kconfig.core delete mode 100644 Kconfig.optional delete mode 100644 Kconfig.roles create mode 100644 zephyr/Kconfig delete mode 100644 zephyr/Kconfig.zephyr create mode 100644 zephyr/crc16-ccitt_zephyr.c create mode 100644 zephyr/include/CO_config_zephyr.h rename zephyr/{ => include}/CO_driver_target.h (100%) rename zephyr/{ => include}/CO_storage_zephyr.h (100%) diff --git a/Kconfig b/Kconfig deleted file mode 100644 index 73802401..00000000 --- a/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -# CANopenNode CANopen protocol stack configuration options -# -# Copyright (c) 2019 Vestas Wind Systems A/S -# SPDX-License-Identifier: Apache-2.0 - -config CANOPENNODE - bool "CANopenNode support" - depends on CAN - help - This option enables the CANopenNode library. - -if CANOPENNODE - -source "modules/canopennode/Kconfig.roles" -source "modules/canopennode/Kconfig.core" -source "modules/canopennode/Kconfig.optional" - -# Conditionally include Zephyr-specific config -if ZEPHYR_BASE -source "modules/canopennode/zephyr/Kconfig.zephyr" -endif - -endif # CANOPENNODE diff --git a/Kconfig.core b/Kconfig.core deleted file mode 100644 index 3b5fa9a0..00000000 --- a/Kconfig.core +++ /dev/null @@ -1,38 +0,0 @@ -config CANOPENNODE_EDS_FILE_PATH - string "EDS file used to generate Object Dictionary" - default "" - help - Path to the EDS (Electronic Data Sheet) file used to generate the - CANopenNode object dictionary files (OD.h, OD.c). - - This file is passed into the eds2c.py code generator. You may override - this to use a board-specific or application-specific EDS file. - - The path may be relative to the workspace root. - -config CANOPENNODE_SDO_BUFFER_SIZE - int "CANopen SDO buffer size" - default 32 - range 7 889 - help - Size of the internal CANopen SDO buffer in bytes. Must be large enough to hold the - largest variable in the object dictionary. - -config CANOPENNODE_TRACE_BUFFER_SIZE - int "CANopen trace buffer size" - default 100 - help - Size of the CANopen trace buffer in bytes. - -config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE - int "Stack size for the CANopen transmit workqueue" - default 512 - help - Stack size used for the internal CANopen transmit workqueue. - -config CANOPENNODE_TX_WORKQUEUE_PRIORITY - int "Priority for CANopen transmit workqueue" - default 0 if !COOP_ENABLED - default -1 - help - Priority of the CANopen transmit workqueue. diff --git a/Kconfig.optional b/Kconfig.optional deleted file mode 100644 index 94e33dc8..00000000 --- a/Kconfig.optional +++ /dev/null @@ -1,55 +0,0 @@ -config CANOPENNODE_STORAGE - bool "CANopen object dictionary storage" - depends on SETTINGS - default y - help - Enable storing the CANopen object dictionary to non-volatile storage. - -config CANOPENNODE_STORAGE_HANDLER_ERASES_EEPROM - bool "Erase CANopen object dictionary EEPROM entries in storage handler" - depends on CANOPENNODE_STORAGE - help - Erase EEPROM entries upon write to OD index 0x1011 subindex 1. - -config CANOPENNODE_LEDS - bool "CANopen LED indicators" - default y - help - Enable support for CANopen LED indicators (CiA 303-3). - -config CANOPENNODE_LEDS_BICOLOR - bool "CANopen bicolor LED indicator" - depends on CANOPENNODE_LEDS - help - Treat LEDs as one bicolor LED, favoring red per CiA 303-3. - -config CANOPENNODE_SYNC_THREAD - bool "CANopen SYNC thread" - default y - help - Use an internal thread to process SYNC RPDOs and TPDOs. - -config CANOPENNODE_SYNC_THREAD_STACK_SIZE - int "Stack size for the CANopen SYNC thread" - depends on CANOPENNODE_SYNC_THREAD - default 512 - help - Stack size for the internal SYNC processing thread. - -config CANOPENNODE_SYNC_THREAD_PRIORITY - int "Priority for CANopen SYNC thread" - depends on CANOPENNODE_SYNC_THREAD - default 0 if !COOP_ENABLED - default -5 - help - Thread priority for SYNC processing. - -config CANOPENNODE_PROGRAM_DOWNLOAD - bool "CANopen program download" - depends on BOOTLOADER_MCUBOOT - select IMG_MANAGER - default y if CANOPENNODE_ROLE_COMBINED - help - Enable CiA 302-3 based program download over CANopen. - - diff --git a/Kconfig.roles b/Kconfig.roles deleted file mode 100644 index 4f2ed88e..00000000 --- a/Kconfig.roles +++ /dev/null @@ -1,67 +0,0 @@ -comment "CANopen Communication Role Selection" - -choice CANOPENNODE_ROLE - prompt "CANopen node communication role" - default CANOPENNODE_ROLE_SERVER - -config CANOPENNODE_ROLE_CLIENT - bool "Client (initiates SDO requests)" - help - CANopen node acting as a client (e.g., NMT master, network manager, update tool). - Enables SDO client and LSS master functionality. - -config CANOPENNODE_ROLE_SERVER - bool "Server (responds to SDO requests)" - help - Typical CANopen node acting as a device/slave, responding to SDO client transfers. - -config CANOPENNODE_ROLE_COMBINED - bool "Combined (Client + Server)" - help - Gateway or dual-role device (e.g., bootloader host and target). Enables both roles. - -endchoice - -config CANOPENNODE_ROLE_CONTROLLER - bool "CANopen Controller (Client/Master)" - select CANOPENNODE_SDO_CLIENT - select CANOPENNODE_LSS_CLIENT - -config CANOPENNODE_ROLE_DEVICE - bool "CANopen Device (Server/Slave)" - select CANOPENNODE_SDO_SERVER - select CANOPENNODE_LSS_SERVER - -config CANOPENNODE_LSS - bool "Enable Layer Setting Services (LSS)" - depends on CANOPENNODE - help - Enable support for CiA 305 LSS functionality. - -config CANOPENNODE_LSS_CLIENT - bool "Enable LSS Client (master role)" - depends on CANOPENNODE_LSS - help - Enable the LSS client role. Used in tools that configure other nodes. - -config CANOPENNODE_LSS_SERVER - bool "Enable LSS Server (slave role)" - depends on CANOPENNODE_LSS - help - Enable the LSS server role. Used in nodes that are being configured. - -config CANOPENNODE_SDO_CLIENT - bool - default y if CANOPENNODE_ROLE_CLIENT || CANOPENNODE_ROLE_COMBINED - -config CANOPENNODE_SDO_SERVER - bool - default y if CANOPENNODE_ROLE_SERVER || CANOPENNODE_ROLE_COMBINED - -config CANOPENNODE_LSS_MASTER - bool - default y if CANOPENNODE_ROLE_CLIENT || CANOPENNODE_ROLE_COMBINED - -config CANOPENNODE_LSS_SLAVE - bool - default y if CANOPENNODE_ROLE_SERVER || CANOPENNODE_ROLE_COMBINED diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index fdccb4f4..9dc005de 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -1,121 +1,171 @@ +# CMakeLists.txt for building canopennode as a Zephyr project +# +# Copyright (c) 2025 BitConcepts, LLC. # SPDX-License-Identifier: Apache-2.0 -if(CONFIG_CANOPENNODE) - - set(CANOPENNODE_DIR "${ZEPHYR_CURRENT_MODULE_DIR}") - set(CANOPENNODE_BINARY_DIR "${CMAKE_BINARY_DIR}/modules/${ZEPHYR_CURRENT_MODULE_NAME}") +cmake_minimum_required(VERSION 3.20) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(canopennode) + +# ---- Paths ---- +set(CANOPENNODE_DIR "${ZEPHYR_CURRENT_MODULE_DIR}") +set(CANOPENNODE_OD_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") +set(CANOPENNODE_OD_GEN_C "${CANOPENNODE_OD_GEN_DIR}/OD.c") +set(CANOPENNODE_OD_GEN_H "${CANOPENNODE_OD_GEN_DIR}/OD.h") +set(CANOPENNODE_OD_GEN_SCRIPT "${CANOPENNODE_DIR}/tools/eds2c_wrapper.py") + +# ---- Include dirs (public to this module) ---- +zephyr_include_directories( + "${CANOPENNODE_DIR}" + "${CANOPENNODE_DIR}/zephyr/include" + "${CANOPENNODE_OD_GEN_DIR}" +) + +# ---- Always-built Zephyr port sources ---- +zephyr_library_sources( + "${CANOPENNODE_DIR}/zephyr/CO_driver.c" + "${CANOPENNODE_OD_GEN_C}" +) + +# ---- Object Dictionary generation (EDS -> OD.c/.h) ---- +find_package(Python3 REQUIRED COMPONENTS Interpreter) + +# Handle empty CONFIG_CANOPENNODE_EDS_FILE_PATH by defaulting to example EDS +if("${CONFIG_CANOPENNODE_EDS_FILE_PATH}" STREQUAL "") + set(CANOPENNODE_EDS_FILE "${CANOPENNODE_DIR}/example/DS301_profile.eds") +else() + set(CANOPENNODE_EDS_FILE_REL "${CONFIG_CANOPENNODE_EDS_FILE_PATH}") + set(CANOPENNODE_EDS_FILE "${APPLICATION_SOURCE_DIR}/${CANOPENNODE_EDS_FILE_REL}") + file(TO_CMAKE_PATH "${CANOPENNODE_EDS_FILE}" CANOPENNODE_EDS_FILE) +endif() - set(CANOPENNODE_OD_GEN_SCRIPT "${CANOPENNODE_DIR}/tools/eds2c_wrapper.py") - set(CANOPENNODE_OD_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") - set(CANOPENNODE_OD_GEN_C "${CANOPENNODE_OD_GEN_DIR}/OD.c") - set(CANOPENNODE_OD_GEN_H "${CANOPENNODE_OD_GEN_DIR}/OD.h") +file(MAKE_DIRECTORY "${CANOPENNODE_OD_GEN_DIR}") + +message(STATUS "CANopenNode: Using EDS file: ${CANOPENNODE_EDS_FILE}") +message(STATUS "CANopenNode: Will generate OD headers to: ${CANOPENNODE_OD_GEN_H}") +message(STATUS "CANopenNode: Will generate OD sources to: ${CANOPENNODE_OD_GEN_C}") + +# Generate OD files from EDS +add_custom_command( + OUTPUT "${CANOPENNODE_OD_GEN_H}" "${CANOPENNODE_OD_GEN_C}" + COMMAND ${PYTHON_EXECUTABLE} "${CANOPENNODE_OD_GEN_SCRIPT}" + "${CANOPENNODE_EDS_FILE}" + -o "${CANOPENNODE_OD_GEN_DIR}" + DEPENDS "${CANOPENNODE_OD_GEN_SCRIPT}" "${CANOPENNODE_EDS_FILE}" + COMMENT "CANopenNode: Generating Object Dictionary from ${CANOPENNODE_EDS_FILE_REL}" + VERBATIM +) + +add_custom_target(canopennode_od_gen + DEPENDS "${CANOPENNODE_OD_GEN_H}" "${CANOPENNODE_OD_GEN_C}" +) + +# ---- Core/common sources (conditionally compiled) ---- +# CANopen.c and OD interface are foundational. +zephyr_library_sources( + "${CANOPENNODE_DIR}/CANopen.c" + "${CANOPENNODE_DIR}/301/CO_ODinterface.c" +) + +# Emergency (always compiled; feature flags gate behavior) +zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_Emergency.c") + +# FIFO only if needed (explicitly enabled, SDO client, or Gateway ASCII uses it) +if(CONFIG_CANOPENNODE_FIFO_ENABLE + OR CONFIG_CANOPENNODE_SDO_CLI_ENABLE + OR CONFIG_CANOPENNODE_GTW_ASCII + OR CONFIG_CANOPENNODE_GTW_ASCII_SDO) + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_fifo.c") +endif() - # Handle empty CONFIG_CANOPENNODE_EDS_FILE_PATH by defaulting to example EDS - if("${CONFIG_CANOPENNODE_EDS_FILE_PATH}" STREQUAL "") - set(CANOPENNODE_EDS_FILE "${CANOPENNODE_DIR}/example/DS301_profile.eds") +# CRC16 helper only if requested or FIFO CRC is enabled +if(CONFIG_CANOPENNODE_CRC16_ENABLE) + if(CONFIG_CANOPENNODE_CRC16_EXTERNAL) + zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/crc16-ccitt_zephyr.c") else() - set(CANOPENNODE_EDS_FILE_REL "${CONFIG_CANOPENNODE_EDS_FILE_PATH}") - set(CANOPENNODE_EDS_FILE "${APPLICATION_SOURCE_DIR}/${CANOPENNODE_EDS_FILE_REL}") - file(TO_CMAKE_PATH "${CANOPENNODE_EDS_FILE}" CANOPENNODE_EDS_FILE) + zephyr_library_sources("${CANOPENNODE_DIR}/301/crc16-ccitt.c") endif() +endif() - file(MAKE_DIRECTORY "${CANOPENNODE_OD_GEN_DIR}") - - message(STATUS "CANopenNode: Using EDS file: ${CANOPENNODE_EDS_FILE}") - message(STATUS "CANopenNode: Will generate OD headers to: ${CANOPENNODE_OD_GEN_H}") - message(STATUS "CANopenNode: Will generate OD sources to: ${CANOPENNODE_OD_GEN_C}") - - # Generate OD files from EDS - add_custom_command( - OUTPUT "${CANOPENNODE_OD_GEN_H}" "${CANOPENNODE_OD_GEN_C}" - COMMAND ${PYTHON_EXECUTABLE} "${CANOPENNODE_OD_GEN_SCRIPT}" - "${CANOPENNODE_EDS_FILE}" - -o "${CANOPENNODE_OD_GEN_DIR}" - DEPENDS "${CANOPENNODE_OD_GEN_SCRIPT}" "${CANOPENNODE_EDS_FILE}" - COMMENT "CANopenNode: Generating Object Dictionary from ${CANOPENNODE_EDS_FILE_REL}" - VERBATIM - ) - - add_custom_target(canopennode_od_gen - DEPENDS "${CANOPENNODE_OD_GEN_H}" "${CANOPENNODE_OD_GEN_C}" - ) - - zephyr_library() - - zephyr_include_directories( - "${CANOPENNODE_DIR}" - "${CANOPENNODE_DIR}/301" - "${CANOPENNODE_DIR}/303" - "${CANOPENNODE_DIR}/304" - "${CANOPENNODE_DIR}/305" - "${CANOPENNODE_DIR}/309" - "${CANOPENNODE_DIR}/extra" - "${CANOPENNODE_DIR}/storage" - "${CANOPENNODE_DIR}/zephyr" - "${CANOPENNODE_OD_GEN_DIR}" - ) - - zephyr_library_sources( - "${CANOPENNODE_DIR}/CANopen.c" - "${CANOPENNODE_DIR}/301/CO_Emergency.c" - "${CANOPENNODE_DIR}/301/CO_fifo.c" - "${CANOPENNODE_DIR}/301/CO_HBconsumer.c" - "${CANOPENNODE_DIR}/301/CO_NMT_Heartbeat.c" - "${CANOPENNODE_DIR}/301/CO_Node_Guarding.c" - "${CANOPENNODE_DIR}/301/CO_ODinterface.c" - "${CANOPENNODE_DIR}/301/CO_PDO.c" - "${CANOPENNODE_DIR}/301/CO_SDOclient.c" - "${CANOPENNODE_DIR}/301/CO_SDOserver.c" - "${CANOPENNODE_DIR}/301/CO_SYNC.c" - "${CANOPENNODE_DIR}/301/CO_TIME.c" - "${CANOPENNODE_DIR}/301/crc16-ccitt.c" - "${CANOPENNODE_OD_GEN_C}" - ) - - zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_driver.c") - - # Optional modules - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_LEDS "${CANOPENNODE_DIR}/303/CO_LEDs.c") - - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_304 "${CANOPENNODE_DIR}/304/CO_GFC.c") - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_304 "${CANOPENNODE_DIR}/304/CO_SRDO.c") - - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/305/CO_LSSmaster.c") - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/305/CO_LSSslave.c") - - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_309 "${CANOPENNODE_DIR}/309/CO_gateway_ascii.c") +# Heartbeat consumer +if(CONFIG_CANOPENNODE_HB_CONS_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_HBconsumer.c") +endif() - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_SYNC_THREAD "${CANOPENNODE_DIR}/extra/CO_trace.c") +# NMT / Heartbeat (NMT object is generally always useful) +zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_NMT_Heartbeat.c") +# Node Guarding +if(CONFIG_CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE OR CONFIG_CANOPENNODE_NODE_GUARDING_MASTER_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_Node_Guarding.c") +endif() +# PDO (only if any PDOs enabled) +if(CONFIG_CANOPENNODE_RPDO_ENABLE OR CONFIG_CANOPENNODE_TPDO_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_PDO.c") +endif() - zephyr_library_sources_ifdef(CONFIG_CANOPENNODE_PROGRAM_DOWNLOAD "${CANOPENNODE_DIR}/zephyr/canopen_program.c") +# SDO Server (server is available if either segmented or block option is selected) +if(CONFIG_CANOPENNODE_SDO_SRV_SEGMENTED OR CONFIG_CANOPENNODE_SDO_SRV_BLOCK) + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SDOserver.c") +endif() +# SDO Client +if(CONFIG_CANOPENNODE_SDO_CLI_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SDOclient.c") +endif() +# SYNC +if(CONFIG_CANOPENNODE_SYNC_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SYNC.c") +endif() - if(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) - zephyr_library_sources( - "${CANOPENNODE_DIR}/storage/CO_storage.c" - "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c" - "${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c" - ) - message(STATUS "CANopenNode: Using Zephyr Settings storage backend") +# TIME +if(CONFIG_CANOPENNODE_TIME_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_TIME.c") +endif() - elseif(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) - zephyr_library_sources( - "${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c" - ) - message(STATUS "CANopenNode: Using RAM-only OD storage") +# LEDs (CiA 303-3) +if(CONFIG_CANOPENNODE_LEDS_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/303/CO_LEDs.c") +endif() - elseif(CONFIG_CANOPEN_STORAGE_BACKEND_NONE) - message(STATUS "CANopenNode: OD storage disabled (NONE)") +# GFC / SRDO (CiA 304) +if(CONFIG_CANOPENNODE_GFC_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/304/CO_GFC.c") +endif() +if(CONFIG_CANOPENNODE_SRDO_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/304/CO_SRDO.c") +endif() - else() - message(WARNING "CANopenNode: No valid OD storage backend selected — defaulting to NONE") - add_compile_definitions(CONFIG_CANOPEN_STORAGE_BACKEND_NONE=1) - message(STATUS "CANopenNode: OD storage disabled (failsafe fallback)") - endif() +# LSS (CiA 305) +if(CONFIG_CANOPENNODE_LSS_MASTER) + zephyr_library_sources("${CANOPENNODE_DIR}/305/CO_LSSmaster.c") +endif() +if(CONFIG_CANOPENNODE_LSS_SLAVE) + zephyr_library_sources("${CANOPENNODE_DIR}/305/CO_LSSslave.c") +endif() +# Gateway (CiA 309) +if(CONFIG_CANOPENNODE_GTW_ASCII) + zephyr_library_sources("${CANOPENNODE_DIR}/309/CO_gateway_ascii.c") +endif() +# Trace (non-standard) +if(CONFIG_CANOPENNODE_TRACE_ENABLE) + zephyr_library_sources("${CANOPENNODE_DIR}/extra/CO_trace.c") +endif() +# ---- Storage backend (Zephyr-specific choice) ---- +# If you expose a choice() in Kconfig for storage, these match its symbols. +if(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) + zephyr_library_sources( + "${CANOPENNODE_DIR}/storage/CO_storage.c" + "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c" + "${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c" + ) +elseif(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) + zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c") +elseif(CONFIG_CANOPEN_STORAGE_BACKEND_NONE) + add_compile_definitions(CONFIG_CANOPEN_STORAGE_BACKEND_NONE=1) endif() diff --git a/zephyr/CO_driver.c b/zephyr/CO_driver.c index b69ebeb5..2cd675e8 100644 --- a/zephyr/CO_driver.c +++ b/zephyr/CO_driver.c @@ -29,7 +29,7 @@ #include #include -LOG_MODULE_REGISTER(canopennode_driver, CONFIG_CANOPEN_LOG_LEVEL); +LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPENNODE_LOG_LEVEL); #define CANPTR_TO_DEV(ptr) ((const struct device *)(ptr)) diff --git a/zephyr/CO_storage_zephyr.c b/zephyr/CO_storage_zephyr.c index 59911221..7932533a 100644 --- a/zephyr/CO_storage_zephyr.c +++ b/zephyr/CO_storage_zephyr.c @@ -5,7 +5,7 @@ #include #include -LOG_MODULE_REGISTER(canopen_storage, CONFIG_CANOPENNODE_LOG_LEVEL); +LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPENNODE_LOG_LEVEL); #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE diff --git a/zephyr/Kconfig b/zephyr/Kconfig new file mode 100644 index 00000000..9f00fba7 --- /dev/null +++ b/zephyr/Kconfig @@ -0,0 +1,503 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 BitConcepts, LLC +# +# CANopenNode — Zephyr module Kconfig + +menuconfig CANOPENNODE + bool "CANopenNode protocol stack support" + depends on CAN + default y + help + Enable the CANopenNode stack integration for Zephyr. + +if CANOPENNODE + +menu "Common / Global flags" + +config CANOPENNODE_GLOBAL_FLAG_CALLBACK_PRE + bool "Global: CALLBACK_PRE (mainline)" + default y + +config CANOPENNODE_GLOBAL_RT_FLAG_CALLBACK_PRE + bool "Global: CALLBACK_PRE (real-time: SYNC/PDO/SRDO)" + default y + +config CANOPENNODE_GLOBAL_FLAG_TIMERNEXT + bool "Global: TIMERNEXT" + default y + +config CANOPENNODE_GLOBAL_FLAG_OD_DYNAMIC + bool "Global: OD_DYNAMIC" + default n +endmenu + +# Logging (template-based) +module = CANOPENNODE +module-str = CANopenNode +source "subsys/logging/Kconfig.template.log_config" + +menu "Object Dictionary (EDS)" + +config CANOPENNODE_EDS_FILE_PATH + string "EDS file (path relative to application root)" + default "" + help + Path to the EDS file used to generate OD.c/OD.h. + Leave empty to use the built-in example: + example/DS301_profile.eds + Examples: + boards/nxp/ismart_fanout/ismart_example.eds + config/my_device.eds + +endmenu + +menu "CANopenNode TX Workqueue Options" + +config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE + int "TX workqueue stack size" + default 1024 + range 256 16384 + help + Stack size (in bytes) for the CANopenNode TX workqueue thread. + +config CANOPENNODE_TX_WORKQUEUE_PRIORITY + int "TX workqueue priority" + default 0 + help + Thread priority for the CANopenNode TX workqueue. + Lower numbers mean higher priority. + +endmenu + +menu "NMT / Heartbeat" + +config CANOPENNODE_NMT_CALLBACK_CHANGE + bool "NMT: callback on state change" + default y + +config CANOPENNODE_NMT_MASTER + bool "NMT: master" + default n + +config CANOPENNODE_HB_CONS_ENABLE + bool "HB consumer" + default n + +if CANOPENNODE_HB_CONS_ENABLE + +choice CANOPENNODE_HB_CONS_CALLBACK_MODE + prompt "HB consumer: callback mode" + default CANOPENNODE_HB_CONS_CALLBACK_NONE + +config CANOPENNODE_HB_CONS_CALLBACK_NONE + bool "No callbacks" + +config CANOPENNODE_HB_CONS_CALLBACK_CHANGE + bool "Single callback" + +config CANOPENNODE_HB_CONS_CALLBACK_MULTI + bool "Per-node callbacks" + +endchoice + +config CANOPENNODE_HB_CONS_QUERY_FUNCT + bool "HB consumer: query functions" + default n + +endif # CANOPENNODE_HB_CONS_ENABLE + +endmenu + + +menu "Node Guarding" + +config CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE + bool "Node guarding: slave" + default n + +config CANOPENNODE_NODE_GUARDING_MASTER_ENABLE + bool "Node guarding: master" + default n + +config CANOPENNODE_NODE_GUARDING_MASTER_COUNT + int "Node guarding master: max monitored nodes" + range 0 127 + default 127 + depends on CANOPENNODE_NODE_GUARDING_MASTER_ENABLE +endmenu + +menu "Emergency" + +config CANOPENNODE_EM_PRODUCER + bool "Emergency: producer" + default y + +config CANOPENNODE_EM_PROD_CONFIGURABLE + bool "Emergency: configurable COB-ID (1014)" + depends on CANOPENNODE_EM_PRODUCER + default y + +config CANOPENNODE_EM_PROD_INHIBIT + bool "Emergency: inhibit time (1015)" + depends on CANOPENNODE_EM_PRODUCER + default y + +config CANOPENNODE_EM_HISTORY + bool "Emergency: error history (1003)" + default y + +config CANOPENNODE_EM_STATUS_BITS + bool "Emergency: expose status bits to OD" + default y + +config CANOPENNODE_EM_CONSUMER + bool "Emergency: consumer" + default n + +config CANOPENNODE_EM_ERR_STATUS_BITS_COUNT + int "Emergency: error status bits (multiple of 8)" + range 48 256 + default 80 + +# Optional error-register conditions (enable default expressions in mapper) +config CANOPENNODE_ERR_CONDITION_GENERIC + bool "ErrReg condition: GENERIC" + default y + +config CANOPENNODE_ERR_CONDITION_CURRENT + bool "ErrReg condition: CURRENT" + default n + +config CANOPENNODE_ERR_CONDITION_VOLTAGE + bool "ErrReg condition: VOLTAGE" + default n + +config CANOPENNODE_ERR_CONDITION_TEMPERATURE + bool "ErrReg condition: TEMPERATURE" + default n + +config CANOPENNODE_ERR_CONDITION_COMMUNICATION + bool "ErrReg condition: COMMUNICATION" + default y + +config CANOPENNODE_ERR_CONDITION_DEV_PROFILE + bool "ErrReg condition: DEVICE PROFILE" + default n + +config CANOPENNODE_ERR_CONDITION_MANUFACTURER + bool "ErrReg condition: MANUFACTURER" + default y +endmenu + +menu "SDO" + +config CANOPENNODE_SDO_SRV_SEGMENTED + bool "SDO server: segmented" + default y + +config CANOPENNODE_SDO_SRV_BLOCK + bool "SDO server: block" + depends on CANOPENNODE_SDO_SRV_SEGMENTED + default y + +config CANOPENNODE_SDO_SRV_BUFFER_SIZE + int "SDO server buffer size" + range 8 10000 + default 32 + +config CANOPENNODE_SDO_CLI_ENABLE + bool "SDO client" + default n + +config CANOPENNODE_SDO_CLI_SEGMENTED + bool "SDO client: segmented" + depends on CANOPENNODE_SDO_CLI_ENABLE + default y + +config CANOPENNODE_SDO_CLI_BLOCK + bool "SDO client: block" + depends on CANOPENNODE_SDO_CLI_ENABLE + select CANOPENNODE_FIFO_ENABLE + select CANOPENNODE_FIFO_ALT_READ + select CANOPENNODE_FIFO_CRC16_CCITT + default n + +config CANOPENNODE_SDO_CLI_LOCAL + bool "SDO client: local (client/server same node)" + depends on CANOPENNODE_SDO_CLI_ENABLE + default n + +config CANOPENNODE_SDO_CLI_BUFFER_SIZE + int "SDO client buffer size" + range 7 10000 + depends on CANOPENNODE_SDO_CLI_ENABLE + default 32 +endmenu + +menu "TIME / SYNC / PDO" + +config CANOPENNODE_TIME_ENABLE + bool "TIME: consumer" + default n + +config CANOPENNODE_TIME_PRODUCER + bool "TIME: producer" + depends on CANOPENNODE_TIME_ENABLE + default n + +config CANOPENNODE_SYNC_ENABLE + bool "SYNC: consumer" + default y + +config CANOPENNODE_SYNC_PRODUCER + bool "SYNC: producer" + depends on CANOPENNODE_SYNC_ENABLE + default n + +config CANOPENNODE_RPDO_ENABLE + bool "PDO: RPDOs" + default y + +config CANOPENNODE_TPDO_ENABLE + bool "PDO: TPDOs" + default y + +config CANOPENNODE_RPDO_TIMERS_ENABLE + bool "PDO: RPDO timers" + depends on CANOPENNODE_RPDO_ENABLE + default y + +config CANOPENNODE_TPDO_TIMERS_ENABLE + bool "PDO: TPDO timers" + depends on CANOPENNODE_TPDO_ENABLE + default y + +config CANOPENNODE_PDO_SYNC_ENABLE + bool "PDO: SYNC" + default y + +config CANOPENNODE_PDO_OD_IO_ACCESS + bool "PDO: OD IO access (OD_IO_t)" + default n +endmenu + +menu "Storage / LEDs" + +config CANOPENNODE_STORAGE_ENABLE + bool "OD storage (1010/1011)" + default n + +config CANOPENNODE_LEDS_ENABLE + bool "LEDs (CiA 303-3)" + default y +endmenu + +menu "CANopenNode OD Storage Backend" + depends on CANOPENNODE_STORAGE_ENABLE + +choice CANOPEN_STORAGE_BACKEND_CHOICE + prompt "Select CANopenNode OD storage backend" + depends on CANOPENNODE_TARGET_ZEPHYR + default CANOPEN_STORAGE_BACKEND_RAM + +config CANOPEN_STORAGE_BACKEND_SETTINGS + bool "Zephyr Settings subsystem" + select SETTINGS + help + Use Zephyr’s settings subsystem to persist Object Dictionary (OD) entries. + +config CANOPEN_STORAGE_BACKEND_RAM + bool "RAM-only (no persistence)" + help + Store Object Dictionary (OD) values in RAM only. + Values will be lost on reset or power cycle. Suitable for testing and + volatile-only applications. + +config CANOPEN_STORAGE_BACKEND_NONE + bool "None (disable OD storage)" + help + Disable Object Dictionary (OD) storage completely. + No RAM or persistent storage will be allocated or used. + +endchoice + +config CANOPEN_LITTLEFS_MOUNT_PATH + string "Mount path for LittleFS OD storage" + depends on CANOPEN_STORAGE_BACKEND_LITTLEFS + default "/lfs1" + help + Filesystem mount path under which OD entries will be stored. + Full path will be /canopen/od/. + +endmenu + +menu "SRDO / GFC (CiA 304)" + +config CANOPENNODE_GFC_ENABLE + bool "GFC" + default n + +config CANOPENNODE_GFC_CONSUMER + bool "GFC: consumer" + depends on CANOPENNODE_GFC_ENABLE + default n + +config CANOPENNODE_GFC_PRODUCER + bool "GFC: producer" + depends on CANOPENNODE_GFC_ENABLE + default n + +config CANOPENNODE_SRDO_ENABLE + bool "SRDO" + default n + +config CANOPENNODE_SRDO_CHECK_TX + bool "SRDO: check TX data" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_MINIMUM_DELAY + int "SRDO: minimum TX delay (us)" + range 0 1000000 + depends on CANOPENNODE_SRDO_ENABLE + default 0 +endmenu + +menu "LSS (CiA 305)" + +config CANOPENNODE_LSS_SLAVE + bool "LSS: slave" + default n + +config CANOPENNODE_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND + bool "LSS: slave fastscan direct respond" + depends on CANOPENNODE_LSS_SLAVE + default n + +config CANOPENNODE_LSS_MASTER + bool "LSS: master" + default n +endmenu + +menu "Gateway (CiA 309)" + +config CANOPENNODE_GTW_MULTI_NET + bool "Gateway: multi-network" + default n + +config CANOPENNODE_GTW_ASCII + bool "Gateway: ASCII" + default n + +config CANOPENNODE_GTW_ASCII_SDO + bool "Gateway: ASCII + SDO client" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_NMT + bool "Gateway: ASCII + NMT" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_LSS + bool "Gateway: ASCII + LSS" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_LOG + bool "Gateway: ASCII + log" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_ERROR_DESC + bool "Gateway: ASCII + error descriptions" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_PRINT_HELP + bool "Gateway: ASCII + 'help'" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_PRINT_LEDS + bool "Gateway: ASCII + LED state" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_BLOCK_DL_LOOP + int "Gateway: block download loop (1..127)" + range 1 127 + default 1 + +config CANOPENNODE_GTWA_COMM_BUF_SIZE + int "Gateway: command buffer size" + range 16 65535 + default 200 + +config CANOPENNODE_GTWA_LOG_BUF_SIZE + int "Gateway: log buffer size" + range 128 131072 + default 2000 +endmenu + +menu "CRC16 / FIFO / Trace / Debug" + +config CANOPENNODE_CRC16_ENABLE + bool "CRC16" + default n + +config CANOPENNODE_CRC16_EXTERNAL + bool "CRC16 external implementation" + depends on CANOPENNODE_CRC16_ENABLE + default y if CANOPENNODE_CRC16_ENABLE + select CRC + +config CANOPENNODE_FIFO_ENABLE + bool "FIFO" + default n + +config CANOPENNODE_FIFO_ALT_READ + bool "FIFO alternate read (needed by SDO client block)" + depends on CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_FIFO_CRC16_CCITT + bool "FIFO CRC16-CCITT (needed by SDO client block)" + depends on CANOPENNODE_FIFO_ENABLE + select CANOPENNODE_CRC16_ENABLE + default n + +config CANOPENNODE_FIFO_ASCII_COMMANDS + bool "FIFO ASCII command helpers" + depends on CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_FIFO_ASCII_DATATYPES + bool "FIFO ASCII datatype helpers" + depends on CANOPENNODE_FIFO_ENABLE && CANOPENNODE_FIFO_ASCII_COMMANDS + default n + +config CANOPENNODE_TRACE_ENABLE + bool "Trace recorder" + default n + +config CANOPENNODE_TRACE_OWN_INTTYPES + bool "Trace: own inttypes" + depends on CANOPENNODE_TRACE_ENABLE + default n + +config CANOPENNODE_DEBUG_COMMON + bool "Debug: COMMON" + default n + +config CANOPENNODE_DEBUG_SDO_CLIENT + bool "Debug: SDO CLIENT" + default n + +config CANOPENNODE_DEBUG_SDO_SERVER + bool "Debug: SDO SERVER" + default n + +endmenu + +endif # CANOPENNODE diff --git a/zephyr/Kconfig.zephyr b/zephyr/Kconfig.zephyr deleted file mode 100644 index 673726d4..00000000 --- a/zephyr/Kconfig.zephyr +++ /dev/null @@ -1,73 +0,0 @@ -# Top-level module enable -config ZEPHYR_CANOPENNODE_MODULE - bool - prompt "Enable CANopenNode module integration with Zephyr" - default y - -# Zephyr CANopenNode backend support -config CANOPENNODE_TARGET_ZEPHYR - bool "Enable Zephyr CANopen backend" - depends on ZEPHYR_CANOPENNODE_MODULE - default y - help - Use Zephyr RTOS-specific CANopenNode interface for CAN and storage. - This enables CO_driver_zephyr.c and CO_storage_zephyr.c. - -# ------------------------------------------------------------------ -# CANopenNode OD Storage Backend -# ------------------------------------------------------------------ - -menu "CANopenNode OD Storage" - depends on CANOPENNODE_TARGET_ZEPHYR - -choice CANOPEN_STORAGE_BACKEND_CHOICE - prompt "Select CANopenNode OD storage backend" - depends on CANOPENNODE_TARGET_ZEPHYR - default CANOPEN_STORAGE_BACKEND_RAM - -config CANOPEN_STORAGE_BACKEND_SETTINGS - bool "Zephyr Settings subsystem" - select SETTINGS - help - Use Zephyr’s settings subsystem to persist Object Dictionary (OD) entries. - -config CANOPEN_STORAGE_BACKEND_RAM - bool "RAM-only (no persistence)" - help - Store Object Dictionary (OD) values in RAM only. - Values will be lost on reset or power cycle. Suitable for testing and - volatile-only applications. - -config CANOPEN_STORAGE_BACKEND_NONE - bool "None (disable OD storage)" - help - Disable Object Dictionary (OD) storage completely. - No RAM or persistent storage will be allocated or used. - -endchoice - -config CANOPEN_LITTLEFS_MOUNT_PATH - string "Mount path for LittleFS OD storage" - depends on CANOPEN_STORAGE_BACKEND_LITTLEFS - default "/lfs1" - help - Filesystem mount path under which OD entries will be stored. - Full path will be /canopen/od/. - -endmenu - -# ------------------------------------------------------------------ -# Logging Configuration -# ------------------------------------------------------------------ - -config CANOPENNODE_LOG_LEVEL - int "CANopenNode log level" - default 0 if LOG_DEFAULT_LEVEL_OFF - default 1 if LOG_DEFAULT_LEVEL_ERR - default 2 if LOG_DEFAULT_LEVEL_WRN - default 3 if LOG_DEFAULT_LEVEL_INF - default 4 if LOG_DEFAULT_LEVEL_DBG - range 0 5 - help - Set the log level for CANopenNode. Overrides LOG_DEFAULT_LEVEL. - Levels: 0=Off, 1=Error, 2=Warning, 3=Info, 4=Debug, 5=Verbose. diff --git a/zephyr/crc16-ccitt_zephyr.c b/zephyr/crc16-ccitt_zephyr.c new file mode 100644 index 00000000..f8a57607 --- /dev/null +++ b/zephyr/crc16-ccitt_zephyr.c @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2025 BitConcepts, LLC + * + * CANopenNode CRC-16/CCITT shim to Zephyr + */ + +#include "301/crc16-ccitt.h" +#include + +/* We need to include Zephyr's crc API but avoid a symbol/type conflict: + * Zephyr declares crc16_ccitt(seed, src, len), while CANopenNode declares + * crc16_ccitt(block, len, crc). To prevent conflicting prototypes, we + * temporarily remap the Zephyr declaration to ZEPHYR_crc16_ccitt. + */ +#define crc16_ccitt ZEPHYR_crc16_ccitt +#include +#undef crc16_ccitt + +void crc16_ccitt_single(uint16_t *crc, const uint8_t chr) +{ + if (crc == NULL) { + return; + } + /* Zephyr prototype: uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len); */ + *crc = ZEPHYR_crc16_ccitt(*crc, &chr, 1U); +} + +uint16_t crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) +{ + if ((block == NULL) && (blockLength != 0U)) { + /* Defensive: if caller passed NULL with non-zero length, just return seed. */ + return crc; + } + return ZEPHYR_crc16_ccitt(crc, block, blockLength); +} diff --git a/zephyr/include/CO_config_zephyr.h b/zephyr/include/CO_config_zephyr.h new file mode 100644 index 00000000..5b77789e --- /dev/null +++ b/zephyr/include/CO_config_zephyr.h @@ -0,0 +1,141 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2025 BitConcepts, LLC + * + * CANopenNode — Zephyr configuration mapping + * This header maps Zephyr Kconfig symbols (CONFIG_CANOPENNODE_*) to + * the CO_CONFIG_* macros used by the portable CANopenNode stack. + * + * The CO_CONFIG_* macros are documented in CO_config.h of CANopenNode. + * This mapper ensures that undefined CONFIG_ symbols are treated as 0, + * so the macros are safe for use outside Zephyr. + */ + +#ifndef CO_CONFIG_ZEPHYR_H +#define CO_CONFIG_ZEPHYR_H + +/* Helper: ensure undefined CONFIG_* are treated as 0 */ +#define ZCFG(sym) (defined(CONFIG_##sym) && (CONFIG_##sym) ? 1 : 0) + +/* ---------------- Global configuration flags ---------------- */ +#define CO_CONFIG_GLOBAL(CALLBACK_PRE, CALLBACK_PRE_RTR, TIMERNEXT, OD_DYNAMIC) \ + (((CALLBACK_PRE) ? CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE : 0) | \ + ((CALLBACK_PRE_RTR) ? CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE : 0) | \ + ((TIMERNEXT) ? CO_CONFIG_GLOBAL_FLAG_TIMERNEXT : 0) | \ + ((OD_DYNAMIC) ? CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC : 0)) + +#define CO_CONFIG_GLOBAL_FLAGS \ + CO_CONFIG_GLOBAL(ZCFG(CANOPENNODE_GLOBAL_FLAG_CALLBACK_PRE), \ + ZCFG(CANOPENNODE_GLOBAL_RT_FLAG_CALLBACK_PRE), \ + ZCFG(CANOPENNODE_GLOBAL_FLAG_TIMERNEXT), \ + ZCFG(CANOPENNODE_GLOBAL_FLAG_OD_DYNAMIC)) + +/* ---------------- NMT and Heartbeat ---------------- */ +#define CO_CONFIG_NMT_FLAGS \ + ((ZCFG(CANOPENNODE_NMT_CALLBACK_CHANGE) ? CO_CONFIG_NMT_CALLBACK_CHANGE : 0) | \ + (ZCFG(CANOPENNODE_NMT_MASTER) ? CO_CONFIG_NMT_MASTER : 0)) + +#define CO_CONFIG_HB_CONS_FLAGS \ + ((ZCFG(CANOPENNODE_HB_CONS_ENABLE) ? CO_CONFIG_HB_CONS_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_HB_CONS_CALLBACK_CHANGE) ? CO_CONFIG_HB_CONS_CALLBACK_CHANGE : 0) | \ + (ZCFG(CANOPENNODE_HB_CONS_CALLBACK_MULTI) ? CO_CONFIG_HB_CONS_CALLBACK_MULTI : 0) | \ + (ZCFG(CANOPENNODE_HB_CONS_QUERY_FUNCT) ? CO_CONFIG_HB_CONS_QUERY_FUNCT : 0)) + +/* ---------------- Emergency ---------------- */ +#define CO_CONFIG_EM_FLAGS \ + ((ZCFG(CANOPENNODE_EM_PRODUCER) ? CO_CONFIG_EM_PRODUCER : 0) | \ + (ZCFG(CANOPENNODE_EM_PROD_CONFIGURABLE) ? CO_CONFIG_EM_PROD_CONFIGURABLE : 0) | \ + (ZCFG(CANOPENNODE_EM_PROD_INHIBIT) ? CO_CONFIG_EM_PROD_INHIBIT : 0) | \ + (ZCFG(CANOPENNODE_EM_HISTORY) ? CO_CONFIG_EM_HISTORY : 0) | \ + (ZCFG(CANOPENNODE_EM_STATUS_BITS) ? CO_CONFIG_EM_STATUS_BITS : 0) | \ + (ZCFG(CANOPENNODE_EM_CONSUMER) ? CO_CONFIG_EM_CONSUMER : 0)) + +#define CO_CONFIG_ERR_CONDITION_FLAGS \ + ((ZCFG(CANOPENNODE_ERR_CONDITION_GENERIC) ? CO_CONFIG_ERR_CONDITION_GENERIC : 0) | \ + (ZCFG(CANOPENNODE_ERR_CONDITION_CURRENT) ? CO_CONFIG_ERR_CONDITION_CURRENT : 0) | \ + (ZCFG(CANOPENNODE_ERR_CONDITION_VOLTAGE) ? CO_CONFIG_ERR_CONDITION_VOLTAGE : 0) | \ + (ZCFG(CANOPENNODE_ERR_CONDITION_TEMPERATURE) ? CO_CONFIG_ERR_CONDITION_TEMPERATURE : 0) | \ + (ZCFG(CANOPENNODE_ERR_CONDITION_COMMUNICATION) ? CO_CONFIG_ERR_CONDITION_COMMUNICATION \ + : 0) | \ + (ZCFG(CANOPENNODE_ERR_CONDITION_DEV_PROFILE) ? CO_CONFIG_ERR_CONDITION_DEV_PROFILE : 0) | \ + (ZCFG(CANOPENNODE_ERR_CONDITION_MANUFACTURER) ? CO_CONFIG_ERR_CONDITION_MANUFACTURER \ + : 0)) + +/* ---------------- SDO ---------------- */ +#define CO_CONFIG_SDO_SRV_FLAGS \ + ((ZCFG(CANOPENNODE_SDO_SRV_SEGMENTED) ? CO_CONFIG_SDO_SRV_SEGMENTED : 0) | \ + (ZCFG(CANOPENNODE_SDO_SRV_BLOCK) ? CO_CONFIG_SDO_SRV_BLOCK : 0)) + +#define CO_CONFIG_SDO_CLI_FLAGS \ + ((ZCFG(CANOPENNODE_SDO_CLI_ENABLE) ? CO_CONFIG_SDO_CLI_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_SDO_CLI_SEGMENTED) ? CO_CONFIG_SDO_CLI_SEGMENTED : 0) | \ + (ZCFG(CANOPENNODE_SDO_CLI_BLOCK) ? CO_CONFIG_SDO_CLI_BLOCK : 0) | \ + (ZCFG(CANOPENNODE_SDO_CLI_LOCAL) ? CO_CONFIG_SDO_CLI_LOCAL : 0)) + +/* ---------------- TIME / SYNC / PDO ---------------- */ +#define CO_CONFIG_SYNC_FLAGS \ + ((ZCFG(CANOPENNODE_SYNC_ENABLE) ? CO_CONFIG_SYNC_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_SYNC_PRODUCER) ? CO_CONFIG_SYNC_PRODUCER : 0)) + +#define CO_CONFIG_PDO_FLAGS \ + ((ZCFG(CANOPENNODE_RPDO_ENABLE) ? CO_CONFIG_RPDO_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_TPDO_ENABLE) ? CO_CONFIG_TPDO_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_RPDO_TIMERS_ENABLE) ? CO_CONFIG_RPDO_TIMERS_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_TPDO_TIMERS_ENABLE) ? CO_CONFIG_TPDO_TIMERS_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_PDO_SYNC_ENABLE) ? CO_CONFIG_PDO_SYNC_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_PDO_OD_IO_ACCESS) ? CO_CONFIG_PDO_OD_IO_ACCESS : 0)) + +/* ---------------- Storage / LEDs ---------------- */ +#define CO_CONFIG_STORAGE_FLAGS (ZCFG(CANOPENNODE_STORAGE_ENABLE) ? CO_CONFIG_STORAGE_ENABLE : 0) + +#define CO_CONFIG_LEDS_FLAGS (ZCFG(CANOPENNODE_LEDS_ENABLE) ? CO_CONFIG_LEDS_ENABLE : 0) + +/* ---------------- SRDO / GFC ---------------- */ +#define CO_CONFIG_GFC_FLAGS \ + ((ZCFG(CANOPENNODE_GFC_ENABLE) ? CO_CONFIG_GFC_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_GFC_CONSUMER) ? CO_CONFIG_GFC_CONSUMER : 0) | \ + (ZCFG(CANOPENNODE_GFC_PRODUCER) ? CO_CONFIG_GFC_PRODUCER : 0)) + +#define CO_CONFIG_SRDO_FLAGS \ + ((ZCFG(CANOPENNODE_SRDO_ENABLE) ? CO_CONFIG_SRDO_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_SRDO_CHECK_TX) ? CO_CONFIG_SRDO_CHECK_TX : 0)) + +/* ---------------- LSS ---------------- */ +#define CO_CONFIG_LSS_FLAGS \ + ((ZCFG(CANOPENNODE_LSS_SLAVE) ? CO_CONFIG_LSS_SLAVE : 0) | \ + (ZCFG(CANOPENNODE_LSS_MASTER) ? CO_CONFIG_LSS_MASTER : 0)) + +/* ---------------- Gateway ---------------- */ +#define CO_CONFIG_GTWA_FLAGS \ + ((ZCFG(CANOPENNODE_GTW_MULTI_NET) ? CO_CONFIG_GTWA_MULTI_NET : 0) | \ + (ZCFG(CANOPENNODE_GTW_ASCII) ? CO_CONFIG_GTWA_ASCII : 0) | \ + (ZCFG(CANOPENNODE_GTW_ASCII_SDO) ? CO_CONFIG_GTWA_ASCII_SDO : 0) | \ + (ZCFG(CANOPENNODE_GTW_ASCII_NMT) ? CO_CONFIG_GTWA_ASCII_NMT : 0) | \ + (ZCFG(CANOPENNODE_GTW_ASCII_LSS) ? CO_CONFIG_GTWA_ASCII_LSS : 0) | \ + (ZCFG(CANOPENNODE_GTW_ASCII_LOG) ? CO_CONFIG_GTWA_ASCII_LOG : 0) | \ + (ZCFG(CANOPENNODE_GTW_ASCII_ERROR_DESC) ? CO_CONFIG_GTWA_ASCII_ERROR_DESC : 0) | \ + (ZCFG(CANOPENNODE_GTW_ASCII_PRINT_HELP) ? CO_CONFIG_GTWA_ASCII_PRINT_HELP : 0) | \ + (ZCFG(CANOPENNODE_GTW_ASCII_PRINT_LEDS) ? CO_CONFIG_GTWA_ASCII_PRINT_LEDS : 0)) + +/* ---------------- FIFO / CRC / Trace / Debug ---------------- */ +#define CO_CONFIG_FIFO_FLAGS \ + ((ZCFG(CANOPENNODE_FIFO_ENABLE) ? CO_CONFIG_FIFO_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_FIFO_ALT_READ) ? CO_CONFIG_FIFO_ALT_READ : 0) | \ + (ZCFG(CANOPENNODE_FIFO_CRC16_CCITT) ? CO_CONFIG_FIFO_CRC16_CCITT : 0) | \ + (ZCFG(CANOPENNODE_FIFO_ASCII_COMMANDS) ? CO_CONFIG_FIFO_ASCII_COMMANDS : 0) | \ + (ZCFG(CANOPENNODE_FIFO_ASCII_DATATYPES) ? CO_CONFIG_FIFO_ASCII_DATATYPES : 0)) + +#define CO_CONFIG_CRC16_FLAGS \ + ((ZCFG(CANOPENNODE_CRC16_ENABLE) ? CO_CONFIG_CRC16_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_CRC16_EXTERNAL) ? CO_CONFIG_CRC16_EXTERNAL : 0)) + +#define CO_CONFIG_TRACE_FLAGS \ + ((ZCFG(CANOPENNODE_TRACE_ENABLE) ? CO_CONFIG_TRACE_ENABLE : 0) | \ + (ZCFG(CANOPENNODE_TRACE_OWN_INTTYPES) ? CO_CONFIG_TRACE_OWN_INTTYPES : 0)) + +#define CO_CONFIG_DEBUG_FLAGS \ + ((ZCFG(CANOPENNODE_DEBUG_COMMON) ? CO_CONFIG_DEBUG_COMMON : 0) | \ + (ZCFG(CANOPENNODE_DEBUG_SDO_CLIENT) ? CO_CONFIG_DEBUG_SDO_CLIENT : 0) | \ + (ZCFG(CANOPENNODE_DEBUG_SDO_SERVER) ? CO_CONFIG_DEBUG_SDO_SERVER : 0)) + +#endif /* CO_CONFIG_ZEPHYR_H */ diff --git a/zephyr/CO_driver_target.h b/zephyr/include/CO_driver_target.h similarity index 100% rename from zephyr/CO_driver_target.h rename to zephyr/include/CO_driver_target.h diff --git a/zephyr/CO_storage_zephyr.h b/zephyr/include/CO_storage_zephyr.h similarity index 100% rename from zephyr/CO_storage_zephyr.h rename to zephyr/include/CO_storage_zephyr.h diff --git a/zephyr/module.yml b/zephyr/module.yml index 18106843..6f8d917c 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -2,7 +2,7 @@ name: canopennode build: cmake: zephyr - kconfig: Kconfig + kconfig: zephyr/Kconfig package-managers: pip: requirement-files: From ce2400e1b1cba970b2985c8b2f05d45dd04b4247 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 13 Aug 2025 13:40:18 -0400 Subject: [PATCH 503/520] Enables LED callback for CANopenNode LEDs Adds a callback mechanism for CANopenNode LEDs, allowing applications to respond to LED state changes, for example, to mirror the states to hardware. Also fixes some Kconfig and build issues. --- 301/CO_config.h | 12 +- 303/CO_LEDs.c | 31 +- 303/CO_LEDs.h | 75 +++- zephyr/CMakeLists.txt | 101 +++-- zephyr/CO_LEDs_zephyr.c | 83 ++++ zephyr/CO_canopen_zephyr.c | 353 +++++++++++++++ zephyr/CO_driver.c | 2 +- zephyr/CO_storage_zephyr.c | 12 +- zephyr/Kconfig | 685 ++++++++++++++++++++--------- zephyr/include/CO_LEDs_zephyr.h | 40 ++ zephyr/include/CO_canopen_zephyr.h | 83 ++++ zephyr/include/CO_config_zephyr.h | 382 ++++++++++------ zephyr/include/CO_driver_target.h | 17 +- zephyr/include/CO_storage_zephyr.h | 31 +- 14 files changed, 1461 insertions(+), 446 deletions(-) create mode 100644 zephyr/CO_LEDs_zephyr.c create mode 100644 zephyr/CO_canopen_zephyr.c create mode 100644 zephyr/include/CO_LEDs_zephyr.h create mode 100644 zephyr/include/CO_canopen_zephyr.h diff --git a/301/CO_config.h b/301/CO_config.h index 5a07ae63..be2e1939 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -530,13 +530,21 @@ extern "C" { * * Possible flags, can be ORed: * - CO_CONFIG_LEDS_ENABLE - Enable calculation of the CANopen LED indicators. + * - CO_CONFIG_LEDS_CALLBACK - Enable application callback after LED state changes. + * Callback is configured by CO_LEDs_registerCallback(). It is invoked from + * CO_LEDs_process() after @ref CO_LEDs_t::LEDred and + * @ref CO_LEDs_t::LEDgreen are updated. This can be used to mirror the + * computed CANopen LED states to hardware (e.g. GPIO pins or OS-level LEDs). + * The callback receives a pointer to the @ref CO_LEDs_t object and a + * user-supplied argument. * - #CO_CONFIG_FLAG_TIMERNEXT - Enable calculation of timerNext_us variable * inside CO_NMT_process(). */ #ifdef CO_DOXYGEN -#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) +#define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | CO_CONFIG_LEDS_CALLBACK | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif -#define CO_CONFIG_LEDS_ENABLE 0x01 +#define CO_CONFIG_LEDS_ENABLE 0x01 +#define CO_CONFIG_LEDS_CALLBACK 0x02 /** @} */ /* CO_STACK_CONFIG_LEDS */ /** diff --git a/303/CO_LEDs.c b/303/CO_LEDs.c index 3562ea5b..96b2dcd4 100644 --- a/303/CO_LEDs.c +++ b/303/CO_LEDs.c @@ -20,7 +20,7 @@ #include "303/CO_LEDs.h" -#if ((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0 +#if ((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0 CO_ReturnError_t CO_LEDs_init(CO_LEDs_t* LEDs) { @@ -34,9 +34,26 @@ CO_LEDs_init(CO_LEDs_t* LEDs) { /* clear the object */ (void)memset(LEDs, 0, sizeof(CO_LEDs_t)); +#if (CO_CONFIG_LEDS_CALLBACK) != 0 + /* Explicitly ensure callback fields are cleared even if layout changes */ + LEDs->cb = NULL; + LEDs->cb_user = NULL; +#endif + return ret; } +#if (CO_CONFIG_LEDS_CALLBACK) != 0 +void +CO_LEDs_registerCallback(CO_LEDs_t* LEDs, CO_LEDs_cb_t cb, void* user_arg) { + if (LEDs == NULL) { + return; + } + LEDs->cb = cb; + LEDs->cb_user = user_arg; +} +#endif /* CO_CONFIG_LEDS_CALLBACK */ + void CO_LEDs_process(CO_LEDs_t* LEDs, uint32_t timeDifference_us, CO_NMT_internalState_t NMTstate, bool_t LSSconfig, bool_t ErrCANbusOff, bool_t ErrCANbusWarn, bool_t ErrRpdo, bool_t ErrSync, bool_t ErrHbCons, @@ -139,6 +156,13 @@ CO_LEDs_process(CO_LEDs_t* LEDs, uint32_t timeDifference_us, CO_NMT_internalStat rd_co = 0; } +#if CO_CONFIG_LEDS_CALLBACK + /* Invoke application callback after state update */ + if (LEDs->cb != NULL) { + LEDs->cb(LEDs, LEDs->cb_user); + } +#endif + /* CANopen green RUN LED */ if (LSSconfig) { gr_co = gr & CO_LED_flicker; @@ -164,14 +188,13 @@ CO_LEDs_process(CO_LEDs_t* LEDs, uint32_t timeDifference_us, CO_NMT_internalStat LEDs->LEDgreen = gr; } /* if (tick) */ -#if ((CO_CONFIG_LEDS)&CO_CONFIG_FLAG_TIMERNEXT) != 0 +#if ((CO_CONFIG_LEDS) & CO_CONFIG_FLAG_TIMERNEXT) != 0 if (timerNext_us != NULL) { uint32_t diff = 50000 - LEDs->LEDtmr50ms; if (*timerNext_us > diff) { *timerNext_us = diff; } } -#endif -} +#endif } #endif /* (CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE */ diff --git a/303/CO_LEDs.h b/303/CO_LEDs.h index 10d15ad7..a2609ce6 100644 --- a/303/CO_LEDs.h +++ b/303/CO_LEDs.h @@ -29,7 +29,7 @@ #define CO_CONFIG_LEDS (CO_CONFIG_LEDS_ENABLE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT) #endif -#if (((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_LEDS) & CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -70,13 +70,13 @@ extern "C" { * @{ * Bitmasks for the LED indicators */ -#define CO_LED_flicker 0x01U /**< LED flickering 10Hz */ -#define CO_LED_blink 0x02U /**< LED blinking 2,5Hz */ -#define CO_LED_flash_1 0x04U /**< LED single flash */ -#define CO_LED_flash_2 0x08U /**< LED double flash */ -#define CO_LED_flash_3 0x10U /**< LED triple flash */ -#define CO_LED_flash_4 0x20U /**< LED quadruple flash */ -#define CO_LED_CANopen 0x80U /**< LED CANopen according to CiA 303-3 */ +#define CO_LED_flicker 0x01U /**< LED flickering 10Hz */ +#define CO_LED_blink 0x02U /**< LED blinking 2,5Hz */ +#define CO_LED_flash_1 0x04U /**< LED single flash */ +#define CO_LED_flash_2 0x08U /**< LED double flash */ +#define CO_LED_flash_3 0x10U /**< LED triple flash */ +#define CO_LED_flash_4 0x20U /**< LED quadruple flash */ +#define CO_LED_CANopen 0x80U /**< LED CANopen according to CiA 303-3 */ /** @} */ /** Get on/off state for red led for one of the @ref CO_LED_bitmasks */ @@ -84,10 +84,29 @@ extern "C" { /** Get on/off state for green led for one of the @ref CO_LED_bitmasks */ #define CO_LED_GREEN(LEDs, BITMASK) ((((LEDs)->LEDgreen & BITMASK) != 0U) ? 1U : 0U) +/* Forward declare the tagged struct and typedef it, so we can use the name + * inside member declarations and in callback typedefs without incomplete-type warnings. + */ +typedef struct CO_LEDs_t CO_LEDs_t; + +#if (CO_CONFIG_LEDS_CALLBACK) != 0 +/** + * Callback invoked after LED state is updated. + * + * The callback is called from within CO_LEDs_process() after the LED state + * machine computes and stores new values into @ref CO_LEDs_t::LEDred and + * @ref CO_LEDs_t::LEDgreen. The callback must be lightweight and non-blocking. + * + * @param leds Pointer to the @ref CO_LEDs_t instance that triggered the callback. + * @param user_arg Opaque user pointer supplied at registration time. + */ +typedef void (*CO_LEDs_cb_t)(CO_LEDs_t* leds, void* user_arg); +#endif /* CO_CONFIG_LEDS_CALLBACK */ + /** * LEDs object, initialized by CO_LEDs_init() */ -typedef struct { +struct CO_LEDs_t { uint32_t LEDtmr50ms; /**< 50ms led timer */ uint8_t LEDtmr200ms; /**< 200ms led timer */ uint8_t LEDtmrflash_1; /**< single flash led timer */ @@ -96,7 +115,11 @@ typedef struct { uint8_t LEDtmrflash_4; /**< quadruple flash led timer */ uint8_t LEDred; /**< red led bitfield, to be combined with @ref CO_LED_bitmasks */ uint8_t LEDgreen; /**< green led bitfield, to be combined with @ref CO_LED_bitmasks */ -} CO_LEDs_t; +#if (CO_CONFIG_LEDS_CALLBACK) != 0 + CO_LEDs_cb_t cb; /**< Callback invoked after LED fields update */ + void* cb_user; /**< Opaque user pointer passed to @ref cb */ +#endif +}; /** * Initialize LEDs object. @@ -109,6 +132,38 @@ typedef struct { */ CO_ReturnError_t CO_LEDs_init(CO_LEDs_t* LEDs); +#if (CO_CONFIG_LEDS_CALLBACK) != 0 +/** + * Register (or replace) LED state callback. + * + * Registers a callback that is invoked after LED states are updated in + * CO_LEDs_process(). Function may be called any time after CO_LEDs_init(). + * Passing @p cb as NULL clears the callback (same effect as + * CO_LEDs_unregisterCallback()). + * + * Typical usage is to mirror the computed CANopen LED indication to hardware + * (e.g. GPIO pins or OS-level LED drivers). + * + * @param LEDs LEDs object to configure. + * @param cb Callback function pointer (NULL to clear). + * @param user_arg Opaque pointer passed back to @p cb on each invocation. + */ +void CO_LEDs_registerCallback(CO_LEDs_t* LEDs, CO_LEDs_cb_t cb, void* user_arg); + +/** + * Unregister LED state callback (header-only helper). + * + * @param LEDs LEDs object to modify. + */ +static inline void +CO_LEDs_unregisterCallback(CO_LEDs_t* LEDs) { + if (LEDs != NULL) { + LEDs->cb = NULL; + LEDs->cb_user = NULL; + } +} +#endif /* CO_CONFIG_LEDS_CALLBACK */ + /** * Process indicator states * diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 9dc005de..7ebab48b 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -1,8 +1,3 @@ -# CMakeLists.txt for building canopennode as a Zephyr project -# -# Copyright (c) 2025 BitConcepts, LLC. -# SPDX-License-Identifier: Apache-2.0 - cmake_minimum_required(VERSION 3.20) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(canopennode) @@ -14,7 +9,7 @@ set(CANOPENNODE_OD_GEN_C "${CANOPENNODE_OD_GEN_DIR}/OD.c") set(CANOPENNODE_OD_GEN_H "${CANOPENNODE_OD_GEN_DIR}/OD.h") set(CANOPENNODE_OD_GEN_SCRIPT "${CANOPENNODE_DIR}/tools/eds2c_wrapper.py") -# ---- Include dirs (public to this module) ---- +# ---- Include dirs ---- zephyr_include_directories( "${CANOPENNODE_DIR}" "${CANOPENNODE_DIR}/zephyr/include" @@ -24,61 +19,81 @@ zephyr_include_directories( # ---- Always-built Zephyr port sources ---- zephyr_library_sources( "${CANOPENNODE_DIR}/zephyr/CO_driver.c" - "${CANOPENNODE_OD_GEN_C}" ) # ---- Object Dictionary generation (EDS -> OD.c/.h) ---- find_package(Python3 REQUIRED COMPONENTS Interpreter) -# Handle empty CONFIG_CANOPENNODE_EDS_FILE_PATH by defaulting to example EDS if("${CONFIG_CANOPENNODE_EDS_FILE_PATH}" STREQUAL "") set(CANOPENNODE_EDS_FILE "${CANOPENNODE_DIR}/example/DS301_profile.eds") + set(CANOPENNODE_EDS_FILE_DISPLAY "${CANOPENNODE_EDS_FILE}") else() set(CANOPENNODE_EDS_FILE_REL "${CONFIG_CANOPENNODE_EDS_FILE_PATH}") set(CANOPENNODE_EDS_FILE "${APPLICATION_SOURCE_DIR}/${CANOPENNODE_EDS_FILE_REL}") file(TO_CMAKE_PATH "${CANOPENNODE_EDS_FILE}" CANOPENNODE_EDS_FILE) + set(CANOPENNODE_EDS_FILE_DISPLAY "${CANOPENNODE_EDS_FILE_REL}") endif() file(MAKE_DIRECTORY "${CANOPENNODE_OD_GEN_DIR}") +if(NOT EXISTS "${CANOPENNODE_EDS_FILE}") + message(FATAL_ERROR "CANopenNode: EDS file not found: ${CANOPENNODE_EDS_FILE}") +endif() + message(STATUS "CANopenNode: Using EDS file: ${CANOPENNODE_EDS_FILE}") message(STATUS "CANopenNode: Will generate OD headers to: ${CANOPENNODE_OD_GEN_H}") message(STATUS "CANopenNode: Will generate OD sources to: ${CANOPENNODE_OD_GEN_C}") -# Generate OD files from EDS -add_custom_command( - OUTPUT "${CANOPENNODE_OD_GEN_H}" "${CANOPENNODE_OD_GEN_C}" - COMMAND ${PYTHON_EXECUTABLE} "${CANOPENNODE_OD_GEN_SCRIPT}" - "${CANOPENNODE_EDS_FILE}" - -o "${CANOPENNODE_OD_GEN_DIR}" - DEPENDS "${CANOPENNODE_OD_GEN_SCRIPT}" "${CANOPENNODE_EDS_FILE}" - COMMENT "CANopenNode: Generating Object Dictionary from ${CANOPENNODE_EDS_FILE_REL}" +# Ensure we only ever add this rule once in the whole build +get_property(_co_od_rule_defined GLOBAL PROPERTY CANOPENNODE_OD_RULE_DEFINED SET) +if(NOT _co_od_rule_defined) + add_custom_command( + OUTPUT "${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}" + COMMAND ${Python3_EXECUTABLE} "${CANOPENNODE_OD_GEN_SCRIPT}" + "${CANOPENNODE_EDS_FILE}" + -o "${CANOPENNODE_OD_GEN_DIR}" + DEPENDS "${CANOPENNODE_OD_GEN_SCRIPT}" "${CANOPENNODE_EDS_FILE}" + COMMENT "CANopenNode: Generating Object Dictionary from ${CANOPENNODE_EDS_FILE_DISPLAY}" VERBATIM -) + ) -add_custom_target(canopennode_od_gen - DEPENDS "${CANOPENNODE_OD_GEN_H}" "${CANOPENNODE_OD_GEN_C}" -) + # Phony target that represents the OD being generated + add_custom_target(canopennode_od_gen + DEPENDS "${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}" + ) -# ---- Core/common sources (conditionally compiled) ---- -# CANopen.c and OD interface are foundational. + # Mark generated and add as sources so Ninja needs the rule + set_source_files_properties("${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}" PROPERTIES GENERATED TRUE) + zephyr_library_sources("${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}") + + # Make the module library wait for the OD generation + add_dependencies(${ZEPHYR_CURRENT_LIBRARY} canopennode_od_gen) + + # Remember we defined this rule so it won't be added twice + set_property(GLOBAL PROPERTY CANOPENNODE_OD_RULE_DEFINED TRUE) +endif() + +# Include dir so headers resolve +zephyr_include_directories("${CANOPENNODE_OD_GEN_DIR}") + +# ---- Core/common sources ---- zephyr_library_sources( "${CANOPENNODE_DIR}/CANopen.c" "${CANOPENNODE_DIR}/301/CO_ODinterface.c" ) -# Emergency (always compiled; feature flags gate behavior) +# Emergency (always build; features are runtime/compile-time gated) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_Emergency.c") -# FIFO only if needed (explicitly enabled, SDO client, or Gateway ASCII uses it) +# FIFO only if needed if(CONFIG_CANOPENNODE_FIFO_ENABLE - OR CONFIG_CANOPENNODE_SDO_CLI_ENABLE + OR CONFIG_CANOPENNODE_SDO_CLIENT_ENABLE OR CONFIG_CANOPENNODE_GTW_ASCII OR CONFIG_CANOPENNODE_GTW_ASCII_SDO) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_fifo.c") endif() -# CRC16 helper only if requested or FIFO CRC is enabled +# CRC16 helper if(CONFIG_CANOPENNODE_CRC16_ENABLE) if(CONFIG_CANOPENNODE_CRC16_EXTERNAL) zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/crc16-ccitt_zephyr.c") @@ -92,7 +107,7 @@ if(CONFIG_CANOPENNODE_HB_CONS_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_HBconsumer.c") endif() -# NMT / Heartbeat (NMT object is generally always useful) +# NMT / Heartbeat zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_NMT_Heartbeat.c") # Node Guarding @@ -100,18 +115,18 @@ if(CONFIG_CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE OR CONFIG_CANOPENNODE_NODE_GUAR zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_Node_Guarding.c") endif() -# PDO (only if any PDOs enabled) +# PDO if(CONFIG_CANOPENNODE_RPDO_ENABLE OR CONFIG_CANOPENNODE_TPDO_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_PDO.c") endif() -# SDO Server (server is available if either segmented or block option is selected) -if(CONFIG_CANOPENNODE_SDO_SRV_SEGMENTED OR CONFIG_CANOPENNODE_SDO_SRV_BLOCK) +# SDO Server +if(CONFIG_CANOPENNODE_SDO_SERVER_SEGMENTED OR CONFIG_CANOPENNODE_SDO_SERVER_BLOCK) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SDOserver.c") endif() # SDO Client -if(CONFIG_CANOPENNODE_SDO_CLI_ENABLE) +if(CONFIG_CANOPENNODE_SDO_CLIENT_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SDOclient.c") endif() @@ -128,6 +143,7 @@ endif() # LEDs (CiA 303-3) if(CONFIG_CANOPENNODE_LEDS_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/303/CO_LEDs.c") + zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_LEDs_zephyr.c") endif() # GFC / SRDO (CiA 304) @@ -157,15 +173,16 @@ if(CONFIG_CANOPENNODE_TRACE_ENABLE) endif() # ---- Storage backend (Zephyr-specific choice) ---- -# If you expose a choice() in Kconfig for storage, these match its symbols. -if(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) - zephyr_library_sources( - "${CANOPENNODE_DIR}/storage/CO_storage.c" - "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c" - "${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c" - ) -elseif(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) - zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c") -elseif(CONFIG_CANOPEN_STORAGE_BACKEND_NONE) - add_compile_definitions(CONFIG_CANOPEN_STORAGE_BACKEND_NONE=1) +if(CONFIG_CANOPENNODE_STORAGE_ENABLE) + if(CONFIG_CANOPENNODE_STORAGE_BACKEND_SETTINGS) + zephyr_library_sources( + "${CANOPENNODE_DIR}/storage/CO_storage.c" + "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c" + "${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c" + ) + elseif(CONFIG_CANOPENNODE_STORAGE_BACKEND_RAM) + zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c") + elseif(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE) + add_compile_definitions(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE=1) + endif() endif() diff --git a/zephyr/CO_LEDs_zephyr.c b/zephyr/CO_LEDs_zephyr.c new file mode 100644 index 00000000..d30c0e76 --- /dev/null +++ b/zephyr/CO_LEDs_zephyr.c @@ -0,0 +1,83 @@ +#include "co_leds_zephyr.h" + +#include +#include +#include +#include + +/* --- DT aliases (Approach #1) --- */ +#define RUN_NODE DT_ALIAS(co_led_run) +#define ERR_NODE DT_ALIAS(co_led_err) + +/* Build-time checks: make sure aliases exist and are enabled */ +BUILD_ASSERT(DT_NODE_HAS_STATUS(RUN_NODE, okay), "DT alias 'co-led-run' missing or disabled"); +BUILD_ASSERT(DT_NODE_HAS_STATUS(ERR_NODE, okay), "DT alias 'co-led-err' missing or disabled"); + +/* Resolve GPIO specs (handles ACTIVE_LOW/HIGH) */ +static const struct gpio_dt_spec LED_RUN = GPIO_DT_SPEC_GET(RUN_NODE, gpios); +static const struct gpio_dt_spec LED_ERR = GPIO_DT_SPEC_GET(ERR_NODE, gpios); + +static bool hw_ready; + +/* Mirror the synthesized CANopen RUN/ERR bits to hardware */ +static void co_leds_cb(CO_LEDs_t *leds, void *user_arg) +{ + ARG_UNUSED(user_arg); + if (!hw_ready || leds == NULL) { + return; + } + + /* Only the “computed on/off” bit (CO_LED_CANopen) matters for hardware */ + const bool run_on = (leds->LEDgreen & CO_LED_CANopen) != 0; + const bool err_on = (leds->LEDred & CO_LED_CANopen) != 0; + + /* gpio_pin_set_dt() respects ACTIVE_LOW via DT flags */ + (void)gpio_pin_set_dt(&LED_RUN, run_on); + (void)gpio_pin_set_dt(&LED_ERR, err_on); +} + +int co_leds_zephyr_init_dt_aliases(void) +{ + /* Validate ports */ + if (!device_is_ready(LED_RUN.port) || !device_is_ready(LED_ERR.port)) { + return -ENODEV; + } + + int ret = gpio_pin_configure_dt(&LED_RUN, GPIO_OUTPUT_INACTIVE); + if (ret) { + return ret; + } + + ret = gpio_pin_configure_dt(&LED_ERR, GPIO_OUTPUT_INACTIVE); + if (ret) { + return ret; + } + + hw_ready = true; + return 0; +} + +void co_leds_zephyr_connect_callback(CO_LEDs_t *leds) +{ + if (!leds) { + return; + } + /* Requires your CO_CONFIG_LEDS_CALLBACK integration */ + CO_LEDs_registerCallback(leds, co_leds_cb, NULL); + + /* Push current state to pins immediately (optional nicety) */ + co_leds_zephyr_sync_once(leds); +} + +void co_leds_zephyr_sync_once(CO_LEDs_t *leds) +{ + if (!hw_ready || !leds) { + return; + } + + const bool run_on = (leds->LEDgreen & CO_LED_CANopen) != 0; + const bool err_on = (leds->LEDred & CO_LED_CANopen) != 0; + + (void)gpio_pin_set_dt(&LED_RUN, run_on); + (void)gpio_pin_set_dt(&LED_ERR, err_on); +} diff --git a/zephyr/CO_canopen_zephyr.c b/zephyr/CO_canopen_zephyr.c new file mode 100644 index 00000000..bfeed63a --- /dev/null +++ b/zephyr/CO_canopen_zephyr.c @@ -0,0 +1,353 @@ +#include "CO_canopen_zephyr.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "OD.h" + +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) +#include "CO_storage_zephyr.h" +#endif + +LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); + +/* ---------- Kconfig-backed defaults ---------- */ +#ifndef CONFIG_COZ_PERIOD_MIN_US +#define CONFIG_COZ_PERIOD_MIN_US 500 +#endif +#ifndef CONFIG_COZ_PERIOD_MAX_US +#define CONFIG_COZ_PERIOD_MAX_US 5000 +#endif +#ifndef CONFIG_COZ_NODE_ID +#define CONFIG_COZ_NODE_ID 1 +#endif +#ifndef CONFIG_COZ_BITRATE_KBPS +#define CONFIG_COZ_BITRATE_KBPS 1000 +#endif +#ifndef CONFIG_COZ_RT_THREAD_STACK_SIZE +#define CONFIG_COZ_RT_THREAD_STACK_SIZE 1024 +#endif +#ifndef CONFIG_COZ_RT_THREAD_PRIORITY +#define CONFIG_COZ_RT_THREAD_PRIORITY 5 +#endif +#ifndef CONFIG_COZ_RT_IDLE_MS +#define CONFIG_COZ_RT_IDLE_MS 2 +#endif + +/* Prefer CANopen-specific chosen; fallback to generic if present */ +#if DT_HAS_CHOSEN(zephyr_co_can) +#define COZ_CAN_NODE DT_CHOSEN(zephyr_co_can) +#elif DT_HAS_CHOSEN(zephyr_canbus) +#define COZ_CAN_NODE DT_CHOSEN(zephyr_canbus) +#endif + +/* ---------- Module state ---------- */ + +static CO_t *CO = NULL; /* CANopen object */ +static CO_storage_t *CO_storage = NULL; /* Storage object */ + +static atomic_t g_running; + +static struct k_work_delayable g_work; + +/* RT thread wake signal (ISR-safe) */ +static K_SEM_DEFINE(rt_sem, 0, UINT_MAX); + +/* ---------- Helpers ---------- */ +static void rt_signal_cb(void *object) +{ + ARG_UNUSED(object); + + if (!atomic_get(&g_running)) { + return; + } + + /* ISR-safe in Zephyr */ + k_sem_give(&rt_sem); +} + +static void enable_pre_signals(CO_t *co, void (*pre_cb)(void *object), void *pre_arg) +{ + CO_SYNC_initCallbackPre(co->SYNC, pre_cb, pre_arg); + + for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { + CO_RPDO_initCallbackPre(co->RPDO[i], pre_cb, pre_arg); + } +} + +/* ---------- Worker: CO_process() cadence ---------- */ +static void canopen_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + if (!atomic_get(&g_running) || g_co == NULL) { + return; + } + + /* elapsed time (ms->us is fine for CO_process cadence) */ + static int64_t last_ms; + int64_t now_ms = k_uptime_get(); + uint32_t dt_us = (last_ms == 0) ? CONFIG_COZ_PERIOD_MIN_US + : (uint32_t)MAX(now_ms - last_ms, 0) * 1000U; + last_ms = now_ms; + +#if IS_ENABLED(CONFIG_CANOPENNODE_GLOBAL_FLAG_TIMERNEXT) + uint32_t next_us = UINT32_MAX; + (void)CO_process(g_co, false, dt_us, &next_us); + uint32_t delay_us = (next_us == UINT32_MAX) ? CONFIG_COZ_PERIOD_MIN_US : next_us; +#else + (void)CO_process(g_co, false, dt_us, NULL); + uint32_t delay_us = CONFIG_COZ_PERIOD_MIN_US; +#endif + + delay_us = CLAMP(delay_us, CONFIG_COZ_PERIOD_MIN_US, CONFIG_COZ_PERIOD_MAX_US); + (void)k_work_reschedule(&g_work, K_USEC(delay_us)); +} + +/* ---------- RT thread: event-driven SYNC/RPDO/TPDO ---------- */ +static void canopen_rt_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + uint32_t prev = k_cycle_get_32(); + + for (;;) { + /* Wake on PRE-callback or idle timeout to service TPDO timers */ + (void)k_sem_take(&rt_sem, K_MSEC(CONFIG_COZ_RT_IDLE_MS)); + + if (!atomic_get(&g_running) || CO == NULL) { + continue; + } + + bool_t sync = false; + uint32_t now = k_cycle_get_32(); + uint32_t delta = now - prev; /* wraps fine for uint32_t */ + prev = now; + + uint32_t dt_us = (uint32_t)(k_cyc_to_ns_floor64(delta) / 1000U); + + CO_LOCK_OD(); +#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) + sync = CO_process_SYNC(CO, dt_us); +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) + CO_process_RPDO(CO, sync); +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_TPDO_ENABLE) + CO_process_TPDO(CO, sync, dt_us); +#endif + CO_UNLOCK_OD(); + } +} + +/* Higher priority than system workqueue to minimize SYNC latency */ +K_THREAD_DEFINE(canopen_rt, CONFIG_COZ_RT_THREAD_STACK_SIZE, canopen_rt_thread, NULL, NULL, NULL, + CONFIG_COZ_RT_THREAD_PRIORITY, 0, 0); + +/* ---------- Public API ---------- */ +int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) +{ + if (atomic_get(&g_running)) { + return -EALREADY; + } + if (!can_dev || !device_is_ready(can_dev)) { + return -ENODEV; + } + if (node_id == 0 || node_id > 127) { + return -EINVAL; + } + + if (CO != NULL) { + CO_delete(CO); + CO = NULL; + } + + uint32_t heapMemoryUsed; + CO = CO_new(NULL, &heapMemoryUsed); + if (CO == NULL) { + LOG_ERR("Can't allocate memory for CANopen objects"); + return -ENOMEM; + } else { + LOG_INF("Allocated %u bytes for CANopen objects\n", heapMemoryUsed); + } + + CO_ReturnError_t err = 0; + int32_t ret = 0; + +/* Initialize storage module */ +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) + CO_storage_entry_t storageEntries[] = {{.addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), + .subIndexOD = 2, + .attr = CO_storage_cmd | CO_storage_restore, + .addrNV = NULL}}; + uint8_t storageEntriesCount = sizeof(storageEntries) / sizeof(storageEntries[0]); + uint32_t storageInitError = 0; + + err = CO_storage_zephyr_init(CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, + OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, + storageEntriesCount, &storageInitError); + if (err != CO_ERROR_NO) { + LOG_ERR("Storage module initialization failed: %d", err); + ret = -ENOMEM; + goto error; + } + if (storageInitError != 0) { + LOG_ERR("Storage module initialization error: 0x%X", storageInitError); + ret = -EIO; + goto error; + } +#endif + /* Initialzie CANopen */ + err = CO_CANinit(CO, can_dev, bitrate_kbps); + if (err != CO_ERROR_NO) { + LOG_ERR("CAN initialization failed: %d", err); + ret = -EINVAL; + goto error; + } + +/* Initialzie LSS */ +#if IS_ENABLED(CONFIG_CANOPENNODE_LSS_SLAVE) + CO_LSS_address_t lssAddress = { + .identity = {.vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, + .productCode = OD_PERSIST_COMM.x1018_identity.productCode, + .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, + .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber}}; + err = CO_LSSinit(CO, &lssAddress, &node_id, &bitrate_kbps); + if (err != CO_ERROR_NO) { + LOG_ERR("LSS slave initialization failed: %d", err); + ret = -EINVAL; + goto error; + } +#endif + uint32_t errInfo = 0; + + err = CO_CANopenInit(CO, /* CANopen object */ + NULL, /* alternate NMT */ + NULL, /* alternate em */ + OD, /* Object dictionary */ + NULL, /* Optional OD_statusBits */ + CO_CONFIG_NMT, /* CO_NMT_control_t */ + CO_NMT_FIRST_HB_TIME_MS, /* firstHBTime_ms */ + CO_CONFIG_SDO_SRV_TIMEOUT_MS, /* SDOserverTimeoutTime_ms */ + CO_CONFIG_SDO_CLI_TIMEOUT_MS, /* SDOclientTimeoutTime_ms */ + CO_CONFIG_SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ + node_id, &errInfo); + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + if (err == CO_ERROR_OD_PARAMETERS) { + LOG_ERR("Object Dictionary entry 0x%X", errInfo); + ret = -EINVAL; + } else { + LOG_ERR("CANopen initialization failed: %d", err); + ret = -EIO + } + goto error; + } + + err = CO_CANopenInitPDO(CO, CO->em, OD, node_id, &errInfo); + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + if (err == CO_ERROR_OD_PARAMETERS) { + LOG_ERR("Object Dictionary entry 0x%X", errInfo); + ret = -EINVAL; + } else { + LOG_ERR("PDO initialization failed: %d", err); + ret = -EIO; + } + goto error; + } + + if (!CO->nodeIdUnconfigured) { +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) + if (storageInitError != 0) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, + storageInitError); + } +#endif + } else { + LOG_INF("CANopenNode - Node-id not initialized"); + } + + /* Enable PRE-callbacks so RT thread wakes on SYNC/RPDO */ + enable_pre_signals(CO, rt_signal_cb, NULL); + + k_work_init_delayable(&g_work, canopen_work_handler); + atomic_set(&g_running, 1); + (void)k_work_schedule(&g_work, K_NO_WAIT); + + CO_CANsetNormalMode(CO->CANmodule); + LOG_INF("CANopenNode - Running..."); + + return 0; + +error: + if (CO != NULL) { + CO_delete(CO); + CO = NULL; + } + return ret; +} + +void co_canopen_stop(void) +{ + if (!atomic_get(&g_running)) { + return; + } + atomic_set(&g_running, 0); + + (void)k_work_cancel_delayable(&g_work); + + CO_CANmodule_disable(CO->CANmodule); + CO_delete(CO); + CO = NULL; + + LOG_ING("CANopenNode - Stopped"); +} + +bool co_canopen_is_running(void) +{ + return atomic_get(&g_running); +} +/* Resolve CAN device (DT chosen or Kconfig fallback) and start */ +int co_canopen_start_auto(void) +{ + const struct device *can_dev = NULL; + +#ifdef COZ_CAN_NODE + can_dev = DEVICE_DT_GET(COZ_CAN_NODE); + if (!device_is_ready(can_dev)) { + return -ENODEV; + } +#elif defined(CONFIG_COZ_CAN_DEV_NAME) + if (CONFIG_COZ_CAN_DEV_NAME[0] != '\0') { + can_dev = device_get_binding(CONFIG_COZ_CAN_DEV_NAME); + if (!can_dev || !device_is_ready(can_dev)) { + return -ENODEV; + } + } else { + return -ENODEV; + } +#else + return -ENODEV; +#endif + + return co_canopen_start(can_dev, CONFIG_COZ_NODE_ID, CONFIG_COZ_BITRATE_KBPS); +} + +/* Auto-start at POST_KERNEL if enabled */ +static int co_canopen_init_sys(const struct device *unused) +{ + ARG_UNUSED(unused); + +#if IS_ENABLED(CONFIG_COZ_AUTO_START) + (void)co_canopen_start_auto(); +#endif + return 0; +} +SYS_INIT(co_canopen_init_sys, POST_KERNEL, CONFIG_COZ_SYSINIT_PRIO); diff --git a/zephyr/CO_driver.c b/zephyr/CO_driver.c index 2cd675e8..22e71a8c 100644 --- a/zephyr/CO_driver.c +++ b/zephyr/CO_driver.c @@ -29,7 +29,7 @@ #include #include -LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPENNODE_LOG_LEVEL); +LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); #define CANPTR_TO_DEV(ptr) ((const struct device *)(ptr)) diff --git a/zephyr/CO_storage_zephyr.c b/zephyr/CO_storage_zephyr.c index 7932533a..28e8f21a 100644 --- a/zephyr/CO_storage_zephyr.c +++ b/zephyr/CO_storage_zephyr.c @@ -5,9 +5,7 @@ #include #include -LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPENNODE_LOG_LEVEL); - -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE +LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); #ifdef CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS #include @@ -94,27 +92,19 @@ CO_ReturnError_t CO_storage_zephyr_init(CO_storage_t *storage, CO_CANmodule_t *C } #if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) - char key[64]; snprintf(key, sizeof(key), "canopen/od/%04X", entry->subIndexOD); int rc = settings_load_subtree_direct(key, entry->addr, entry->len); if (rc < 0) { LOG_DBG("No settings found for %s", key); } - #elif defined(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) - // RAM-only, already loaded from default or boot values - #else - LOG_WRN("No valid storage backend selected — skipping restore for 0x%02X", entry->subIndexOD); - #endif } return ret; } - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 9f00fba7..6611c427 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -12,448 +12,687 @@ menuconfig CANOPENNODE if CANOPENNODE -menu "Common / Global flags" +menu "NMT / Heartbeat producer - Specified in standard CiA 301" -config CANOPENNODE_GLOBAL_FLAG_CALLBACK_PRE - bool "Global: CALLBACK_PRE (mainline)" - default y +config CANOPENNODE_NMT_CALLBACK_CHANGE + bool "Enable custom callback after NMT state changes" + default n + help + Enable a custom callback invoked after the NMT state changes. + Configure via CO_NMT_initCallbackChanged(). -config CANOPENNODE_GLOBAL_RT_FLAG_CALLBACK_PRE - bool "Global: CALLBACK_PRE (real-time: SYNC/PDO/SRDO)" - default y +config CANOPENNODE_NMT_MASTER + bool "Enable simple NMT master" + default n + help + Enable a simple NMT master object to control other nodes' + NMT states (start/stop/reset). -config CANOPENNODE_GLOBAL_FLAG_TIMERNEXT - bool "Global: TIMERNEXT" - default y +config CANOPENNODE_NMT_CALLBACK + bool "Enable custom callback after preprocessing received NMT message" + default n + help + Enable a custom callback invoked after a received NMT message + is preprocessed. Configure via CO_NMT_initCallbackPre(). -config CANOPENNODE_GLOBAL_FLAG_OD_DYNAMIC - bool "Global: OD_DYNAMIC" +config CANOPENNODE_NMT_TIMERNEXT + bool "Enable NMT timerNext_us calculation" default n + help + Enable calculation of timerNext_us for NMT to schedule next processing. + +config CANOPENNODE_NMT_FIRST_HB_TIME_MS + int "First heartbeat delay (ms)" + range 0 65535 + default 0 + help + Delay before the first Heartbeat after boot/reset. + 0 = no extra delay (start HB with the normal 0x1017 period). + Typical values: 200–1000 ms to let peers install filters and avoid + false HB-consumer timeouts during bus bring-up. + endmenu -# Logging (template-based) -module = CANOPENNODE -module-str = CANopenNode -source "subsys/logging/Kconfig.template.log_config" +menu "NMT startup/control" -menu "Object Dictionary (EDS)" +config CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL + bool "Start in Operational after init (CO_NMT_STARTUP_TO_OPERATIONAL)" + default y -config CANOPENNODE_EDS_FILE_PATH - string "EDS file (path relative to application root)" - default "" - help - Path to the EDS file used to generate OD.c/OD.h. - Leave empty to use the built-in example: - example/DS301_profile.eds - Examples: - boards/nxp/ismart_fanout/ismart_example.eds - config/my_device.eds +config CANOPENNODE_NMT_ERR_ON_BUSOFF_HB + bool "Error on bus-off / HB timeout (CO_NMT_ERR_ON_BUSOFF_HB)" + default y -endmenu +config CANOPENNODE_NMT_ERR_ON_ERR_REG + bool "Error on nonzero masked error register (CO_NMT_ERR_ON_ERR_REG)" + default y -menu "CANopenNode TX Workqueue Options" +config CANOPENNODE_NMT_ERR_TO_STOPPED + bool "On error -> go to Stopped (else Pre-op) (CO_NMT_ERR_TO_STOPPED)" + default n -config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE - int "TX workqueue stack size" - default 1024 - range 256 16384 - help - Stack size (in bytes) for the CANopenNode TX workqueue thread. +config CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL + bool "Auto-return to Operational when errors clear (CO_NMT_ERR_FREE_TO_OPERATIONAL)" + default y -config CANOPENNODE_TX_WORKQUEUE_PRIORITY - int "TX workqueue priority" - default 0 +comment "Error register mask (low 8 bits of NMT control)" + +config CANOPENNODE_NMT_ERR_REG_MASK + hex "Base error-register mask (hex, 0x00-0xFF)" + range 0x00 0xFF + default 0x00 help - Thread priority for the CANopenNode TX workqueue. - Lower numbers mean higher priority. + Low 8 bits of the NMT control are the error register mask. + Set bits here directly (hex), or enable the convenience flags below. -endmenu +config CANOPENNODE_NMT_ERR_MASK_GENERIC + bool "Include GENERIC error bit" + default y -menu "NMT / Heartbeat" +config CANOPENNODE_NMT_ERR_MASK_CURRENT + bool "Include CURRENT error bit" + default n -config CANOPENNODE_NMT_CALLBACK_CHANGE - bool "NMT: callback on state change" +config CANOPENNODE_NMT_ERR_MASK_VOLTAGE + bool "Include VOLTAGE error bit" + default n + +config CANOPENNODE_NMT_ERR_MASK_TEMPERATURE + bool "Include TEMPERATURE error bit" + default n + +config CANOPENNODE_NMT_ERR_MASK_COMM + bool "Include COMMUNICATION error bit" default y -config CANOPENNODE_NMT_MASTER - bool "NMT: master" +config CANOPENNODE_NMT_ERR_MASK_DEV_PROFILE + bool "Include DEVICE PROFILE error bit" default n -config CANOPENNODE_HB_CONS_ENABLE - bool "HB consumer" +config CANOPENNODE_NMT_ERR_MASK_MANUFACTURER + bool "Include MANUFACTURER error bit" default n -if CANOPENNODE_HB_CONS_ENABLE +endmenu -choice CANOPENNODE_HB_CONS_CALLBACK_MODE - prompt "HB consumer: callback mode" - default CANOPENNODE_HB_CONS_CALLBACK_NONE +menu "Heartbeat consumer - Specified in standard CiA 301" -config CANOPENNODE_HB_CONS_CALLBACK_NONE - bool "No callbacks" +config CANOPENNODE_HB_CONS_ENABLE + bool "Enable heartbeat consumer" + default n + help + Monitor heartbeat messages from other nodes and trigger actions + based on their status. + +choice CANOPENNODE_HB_CONS_CALLBACK_MODE + prompt "Heartbeat consumer callback mode" + depends on CANOPENNODE_HB_CONS_ENABLE + optional + help + Select how heartbeat/NMT-change callbacks are handled. + Leave unset for no callbacks (default). Only one option can be active. config CANOPENNODE_HB_CONS_CALLBACK_CHANGE - bool "Single callback" + bool "Single common callback after NMT state change" + help + Enable a single common callback invoked on NMT state changes. + Configure via CO_HBconsumer_initCallbackNmtChanged(). config CANOPENNODE_HB_CONS_CALLBACK_MULTI bool "Per-node callbacks" + help + Enable per-node callbacks for NMT change, heartbeat started, + timeout, and remote reset. Configure via: + CO_HBconsumer_initCallbackNmtChanged(), + CO_HBconsumer_initCallbackHeartbeatStarted(), + CO_HBconsumer_initCallbackTimeout(), + CO_HBconsumer_initCallbackRemoteReset(). endchoice config CANOPENNODE_HB_CONS_QUERY_FUNCT - bool "HB consumer: query functions" + bool "Enable heartbeat and NMT query functions" + depends on CANOPENNODE_HB_CONS_ENABLE default n -endif # CANOPENNODE_HB_CONS_ENABLE +config CANOPENNODE_HB_CONS_CALLBACK + bool "Enable custom callback after heartbeat message received" + depends on CANOPENNODE_HB_CONS_ENABLE + default n + help + Enable a callback invoked after a heartbeat message is preprocessed. + Configure via CO_HBconsumer_initCallbackPre(). -endmenu +config CANOPENNODE_HB_CONS_TIMERNEXT + bool "Enable heartbeat consumer timerNext_us calculation" + depends on CANOPENNODE_HB_CONS_ENABLE + default n + +config CANOPENNODE_HB_CONS_OD_DYNAMIC + bool "Enable dynamic behaviour of heartbeat consumer OD variables" + depends on CANOPENNODE_HB_CONS_ENABLE + default n +endmenu -menu "Node Guarding" +menu "CANopen Node Guarding slave and master objects - Specified in standard CiA 301" config CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE - bool "Node guarding: slave" + bool "Enable Node guarding slave" default n config CANOPENNODE_NODE_GUARDING_MASTER_ENABLE - bool "Node guarding: master" + bool "Enable Node guarding master" default n config CANOPENNODE_NODE_GUARDING_MASTER_COUNT - int "Node guarding master: max monitored nodes" - range 0 127 - default 127 + int "Max nodes monitored by guarding master" depends on CANOPENNODE_NODE_GUARDING_MASTER_ENABLE + range 1 127 + default 1 + +config CANOPENNODE_NODE_GUARDING_TIMERNEXT + bool "Enable Node guarding timerNext_us calculation" + depends on CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE || CANOPENNODE_NODE_GUARDING_MASTER_ENABLE + default n + endmenu -menu "Emergency" +menu "Emergency producer/consumer - Specified in standard CiA 301" config CANOPENNODE_EM_PRODUCER - bool "Emergency: producer" - default y + bool "Enable emergency producer" + default n config CANOPENNODE_EM_PROD_CONFIGURABLE - bool "Emergency: configurable COB-ID (1014)" - depends on CANOPENNODE_EM_PRODUCER - default y + bool "Enable configurable COB-ID for emergency producer" + default n config CANOPENNODE_EM_PROD_INHIBIT - bool "Emergency: inhibit time (1015)" - depends on CANOPENNODE_EM_PRODUCER - default y + bool "Enable inhibit time for emergency producer" + default n config CANOPENNODE_EM_HISTORY - bool "Emergency: error history (1003)" - default y + bool "Enable emergency error history" + default n + +config CANOPENNODE_EM_CONSUMER + bool "Enable emergency consumer" + default n config CANOPENNODE_EM_STATUS_BITS - bool "Emergency: expose status bits to OD" - default y + bool "Enable emergency status bits in Object Dictionary" + default n -config CANOPENNODE_EM_CONSUMER - bool "Emergency: consumer" +config CANOPENNODE_EM_CALLBACK + bool "Enable custom callback after emergency message received" + default n + +config CANOPENNODE_EM_TIMERNEXT + bool "Enable emergency timerNext_us calculation" default n config CANOPENNODE_EM_ERR_STATUS_BITS_COUNT - int "Emergency: error status bits (multiple of 8)" + int "Emergency error status bits (multiple of 8)" range 48 256 default 80 # Optional error-register conditions (enable default expressions in mapper) config CANOPENNODE_ERR_CONDITION_GENERIC - bool "ErrReg condition: GENERIC" + bool "Condition for calculating Error register: GENERIC" default y config CANOPENNODE_ERR_CONDITION_CURRENT - bool "ErrReg condition: CURRENT" + bool "Condition for calculating Error register: CURRENT" default n config CANOPENNODE_ERR_CONDITION_VOLTAGE - bool "ErrReg condition: VOLTAGE" + bool "Condition for calculating Error register: VOLTAGE" default n config CANOPENNODE_ERR_CONDITION_TEMPERATURE - bool "ErrReg condition: TEMPERATURE" + bool "Condition for calculating Error register: TEMPERATURE" default n config CANOPENNODE_ERR_CONDITION_COMMUNICATION - bool "ErrReg condition: COMMUNICATION" + bool "Condition for calculating Error register: COMMUNICATION" default y config CANOPENNODE_ERR_CONDITION_DEV_PROFILE - bool "ErrReg condition: DEVICE PROFILE" + bool "Condition for calculating Error register: DEVICE PROFILE" default n config CANOPENNODE_ERR_CONDITION_MANUFACTURER - bool "ErrReg condition: MANUFACTURER" + bool "Condition for calculating Error register: MANUFACTURER" default y + endmenu -menu "SDO" +menu "SDO server - Specified in standard CiA 301" -config CANOPENNODE_SDO_SRV_SEGMENTED - bool "SDO server: segmented" - default y +config CANOPENNODE_SDO_SERVER_SEGMENTED + bool "Enable segmented SDO server" + default n -config CANOPENNODE_SDO_SRV_BLOCK - bool "SDO server: block" - depends on CANOPENNODE_SDO_SRV_SEGMENTED - default y +config CANOPENNODE_SDO_SERVER_BLOCK + bool "Enable block SDO server" + select CANOPENNODE_SDO_SERVER_SEGMENTED + select CANOPENNODE_CRC16_ENABLE + default n + help + Use 127-segment block transfers with optional CRC for large, efficient transfers. -config CANOPENNODE_SDO_SRV_BUFFER_SIZE +config CANOPENNODE_SDO_SERVER_CALLBACK + bool "Enable SDO server callback" + depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK + default n + +config CANOPENNODE_SDO_SERVER_TIMERNEXT + bool "Enable SDO server timerNext_us calculation" + depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK + default n + +config CANOPENNODE_SDO_SERVER_OD_DYNAMIC + bool "Enable dynamic behaviour of SDO server OD variables" + depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK + default n + +config CANOPENNODE_SDO_SERVER_BUFFER_SIZE int "SDO server buffer size" - range 8 10000 + depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK + range 900 4096 if CANOPENNODE_SDO_SERVER_BLOCK + range 20 4096 if !CANOPENNODE_SDO_SERVER_BLOCK + default 900 if CANOPENNODE_SDO_SERVER_BLOCK default 32 + help + Internal buffer for SDO server. + - >=20 for segmented + - >=900 recommended for block (127 x 7 bytes) -config CANOPENNODE_SDO_CLI_ENABLE - bool "SDO client" - default n +config CANOPENNODE_SDO_SERVER_TIMEOUT_MS + int "SDO server timeout (ms)" + depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK + range 50 60000 + default 1000 -config CANOPENNODE_SDO_CLI_SEGMENTED - bool "SDO client: segmented" - depends on CANOPENNODE_SDO_CLI_ENABLE - default y +endmenu -config CANOPENNODE_SDO_CLI_BLOCK - bool "SDO client: block" - depends on CANOPENNODE_SDO_CLI_ENABLE +menu "SDO client - Specified in standard CiA 301" + +config CANOPENNODE_SDO_CLIENT_ENABLE + bool "Enable SDO client" select CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_SEGMENTED + bool "Enable SDO client segmented transfer" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_BLOCK + bool "Enable SDO client block transfer" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + select CANOPENNODE_SDO_CLIENT_SEGMENTED select CANOPENNODE_FIFO_ALT_READ select CANOPENNODE_FIFO_CRC16_CCITT default n -config CANOPENNODE_SDO_CLI_LOCAL - bool "SDO client: local (client/server same node)" - depends on CANOPENNODE_SDO_CLI_ENABLE +config CANOPENNODE_SDO_CLIENT_LOCAL + bool "Enable local transfer (client/server same node)" + depends on CANOPENNODE_SDO_CLIENT_ENABLE default n -config CANOPENNODE_SDO_CLI_BUFFER_SIZE +config CANOPENNODE_SDO_CLIENT_CALLBACK + bool "Enable SDO client callback" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_TIMERNEXT + bool "Enable SDO client timerNext_us calculation" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_OD_DYNAMIC + bool "Enable dynamic behaviour of SDO client OD variables" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_BUFFER_SIZE int "SDO client buffer size" - range 7 10000 - depends on CANOPENNODE_SDO_CLI_ENABLE - default 32 + depends on CANOPENNODE_SDO_CLIENT_ENABLE + range 1000 4096 if CANOPENNODE_SDO_CLIENT_BLOCK + range 7 4096 if CANOPENNODE_SDO_CLIENT_SEGMENTED && !CANOPENNODE_SDO_CLIENT_BLOCK + default 1000 if CANOPENNODE_SDO_CLIENT_BLOCK + default 32 if !CANOPENNODE_SDO_CLIENT_BLOCK + help + Circular buffer used by SDO client. Can be <= object size since it is + processed over multiple calls. >=7 for segmented; >=1000 recommended for block. + +config CANOPENNODE_SDO_CLIENT_TIMEOUT_MS + int "SDO client timeout (ms)" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + range 50 60000 + default 1000 + endmenu -menu "TIME / SYNC / PDO" +menu "Time producer/consumer - Specified in standard CiA 301" config CANOPENNODE_TIME_ENABLE - bool "TIME: consumer" + bool "Enable TIME object and TIME consumer" default n config CANOPENNODE_TIME_PRODUCER - bool "TIME: producer" + bool "Enable TIME producer" + depends on CANOPENNODE_TIME_ENABLE + default n + +config CANOPENNODE_TIME_CALLBACK + bool "Enable TIME callback" depends on CANOPENNODE_TIME_ENABLE default n +config CANOPENNODE_TIME_OD_DYNAMIC + bool "Enable dynamic behaviour of TIME OD variables" + depends on CANOPENNODE_TIME_ENABLE + default n + +endmenu + +menu "SYNC and PDO producer/consumer - Specified in standard CiA 301" + config CANOPENNODE_SYNC_ENABLE - bool "SYNC: consumer" - default y + bool "Enable SYNC object and SYNC consumer" + default n config CANOPENNODE_SYNC_PRODUCER - bool "SYNC: producer" + bool "Enable SYNC producer" + depends on CANOPENNODE_SYNC_ENABLE + default n + +config CANOPENNODE_SYNC_CALLBACK + bool "Enable SYNC callback" + depends on CANOPENNODE_SYNC_ENABLE + default n + +config CANOPENNODE_SYNC_TIMERNEXT + bool "Enable SYNC timerNext_us calculation" + depends on CANOPENNODE_SYNC_ENABLE + default n + +config CANOPENNODE_SYNC_OD_DYNAMIC + bool "Enable dynamic behaviour of SYNC OD variables" depends on CANOPENNODE_SYNC_ENABLE default n config CANOPENNODE_RPDO_ENABLE - bool "PDO: RPDOs" - default y + bool "Enable receive PDO objects (RPDOs)" + default n config CANOPENNODE_TPDO_ENABLE - bool "PDO: TPDOs" - default y + bool "Enable transmit PDO objects (TPDOs)" + default n config CANOPENNODE_RPDO_TIMERS_ENABLE - bool "PDO: RPDO timers" + bool "Enable RPDO timers" depends on CANOPENNODE_RPDO_ENABLE - default y + default n config CANOPENNODE_TPDO_TIMERS_ENABLE - bool "PDO: TPDO timers" + bool "Enable TPDO timers" depends on CANOPENNODE_TPDO_ENABLE - default y + default n config CANOPENNODE_PDO_SYNC_ENABLE - bool "PDO: SYNC" - default y + bool "Enable PDO SYNC" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + select CANOPENNODE_SYNC_ENABLE + default n + help + Synchronize PDO processing with network SYNC messages. config CANOPENNODE_PDO_OD_IO_ACCESS - bool "PDO: OD IO access (OD_IO_t)" + bool "Enable PDO OD IO access" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + select CANOPENNODE_PDO_OD_DYNAMIC default n + help + Use OD IO accessors (OD_IO_t) for mapped PDO variables. + +config CANOPENNODE_PDO_CALLBACK + bool "Enable PDO callback" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default n + +config CANOPENNODE_PDO_TIMERNEXT + bool "Enable PDO timerNext_us calculation" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default n + +config CANOPENNODE_PDO_OD_DYNAMIC + bool "Enable dynamic behaviour of PDO OD variables" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default n + endmenu -menu "Storage / LEDs" +menu "Data storage - Data storage with CANopen OD objects 1010 and 1011, CiA 301" config CANOPENNODE_STORAGE_ENABLE - bool "OD storage (1010/1011)" + bool "Enable data storage" default n + help + Persist OD entries via 0x1010/0x1011. -config CANOPENNODE_LEDS_ENABLE - bool "LEDs (CiA 303-3)" - default y endmenu -menu "CANopenNode OD Storage Backend" +menu "Storage Backend" depends on CANOPENNODE_STORAGE_ENABLE -choice CANOPEN_STORAGE_BACKEND_CHOICE - prompt "Select CANopenNode OD storage backend" - depends on CANOPENNODE_TARGET_ZEPHYR - default CANOPEN_STORAGE_BACKEND_RAM - -config CANOPEN_STORAGE_BACKEND_SETTINGS - bool "Zephyr Settings subsystem" - select SETTINGS - help - Use Zephyr’s settings subsystem to persist Object Dictionary (OD) entries. - -config CANOPEN_STORAGE_BACKEND_RAM - bool "RAM-only (no persistence)" - help - Store Object Dictionary (OD) values in RAM only. - Values will be lost on reset or power cycle. Suitable for testing and - volatile-only applications. - -config CANOPEN_STORAGE_BACKEND_NONE - bool "None (disable OD storage)" - help - Disable Object Dictionary (OD) storage completely. - No RAM or persistent storage will be allocated or used. +choice CANOPENNODE_STORAGE_BACKEND_CHOICE + prompt "Select CANopenNode OD storage backend" + default CANOPENNODE_STORAGE_BACKEND_RAM -endchoice +config CANOPENNODE_STORAGE_BACKEND_SETTINGS + bool "Zephyr Settings subsystem" + select SETTINGS + help + Use Zephyr’s settings subsystem to persist OD entries. + +config CANOPENNODE_STORAGE_BACKEND_RAM + bool "RAM-only (no persistence)" + help + Store OD values in RAM only. Lost on reset. -config CANOPEN_LITTLEFS_MOUNT_PATH - string "Mount path for LittleFS OD storage" - depends on CANOPEN_STORAGE_BACKEND_LITTLEFS - default "/lfs1" +config CANOPENNODE_STORAGE_BACKEND_NONE + bool "None (disable OD storage)" help - Filesystem mount path under which OD entries will be stored. - Full path will be /canopen/od/. + Disable OD storage completely. + +endchoice endmenu -menu "SRDO / GFC (CiA 304)" +menu "CANopen LED Indicators - Specified in standard CiA 303-3" + +config CANOPENNODE_LEDS_ENABLE + bool "Enable calculation of the CANopen LED indicators" + default n + +config CANOPENNODE_LEDS_CALLBACK + bool "Enable custom callback after LED state changes" + depends on CANOPENNODE_LEDS_ENABLE + default n + +config CANOPENNODE_LEDS_TIMERNEXT + bool "Enable calculation of timerNext_us for LED indicators" + depends on CANOPENNODE_LEDS_ENABLE + default n + +endmenu + +menu "Safety Related Data Objects (SRDO) - Specified in standard EN 50325-5 (CiA 304)" config CANOPENNODE_GFC_ENABLE - bool "GFC" + bool "Enable GFC (Guarding Function Control)" default n config CANOPENNODE_GFC_CONSUMER - bool "GFC: consumer" + bool "Enable GFC consumer" depends on CANOPENNODE_GFC_ENABLE default n config CANOPENNODE_GFC_PRODUCER - bool "GFC: producer" + bool "Enable GFC producer" depends on CANOPENNODE_GFC_ENABLE default n config CANOPENNODE_SRDO_ENABLE - bool "SRDO" + bool "Enable SRDO (Safety Related Data Objects)" default n config CANOPENNODE_SRDO_CHECK_TX - bool "SRDO: check TX data" + bool "Enable SRDO TX data check" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_CALLBACK + bool "Enable SRDO callback" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_TIMERNEXT + bool "Enable SRDO timerNext_us calculation" depends on CANOPENNODE_SRDO_ENABLE default n config CANOPENNODE_SRDO_MINIMUM_DELAY - int "SRDO: minimum TX delay (us)" - range 0 1000000 + int "Minimum time between the first and second SRDO (Tx) message (us)" depends on CANOPENNODE_SRDO_ENABLE + range 0 1000000 default 0 + endmenu -menu "LSS (CiA 305)" +menu "LSS master/slave - Specified in standard CiA 305" config CANOPENNODE_LSS_SLAVE - bool "LSS: slave" + bool "Enable LSS slave" default n config CANOPENNODE_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND - bool "LSS: slave fastscan direct respond" + bool "Enable fast-scan direct response" depends on CANOPENNODE_LSS_SLAVE default n config CANOPENNODE_LSS_MASTER - bool "LSS: master" + bool "Enable LSS master" default n + +config CANOPENNODE_LSS_CALLBACK + bool "Enable LSS callback" + default n + endmenu -menu "Gateway (CiA 309)" +menu "Gateways - Specified in standard CiA 309" config CANOPENNODE_GTW_MULTI_NET - bool "Gateway: multi-network" + bool "Enable multiple network interfaces in gateway device" + depends on 0 default n config CANOPENNODE_GTW_ASCII - bool "Gateway: ASCII" + bool "Enable gateway device with ASCII mapping" + select CANOPENNODE_FIFO_ENABLE + select CANOPENNODE_FIFO_ASCII_COMMANDS default n config CANOPENNODE_GTW_ASCII_SDO - bool "Gateway: ASCII + SDO client" + bool "Enable SDO client in gateway-ascii" depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_SDO_CLIENT_ENABLE + select CANOPENNODE_FIFO_ASCII_DATATYPES default n config CANOPENNODE_GTW_ASCII_NMT - bool "Gateway: ASCII + NMT" + bool "Enable NMT master in gateway-ascii" depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_NMT_MASTER default n config CANOPENNODE_GTW_ASCII_LSS - bool "Gateway: ASCII + LSS" + bool "Enable LSS master in gateway-ascii" depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_LSS_MASTER default n config CANOPENNODE_GTW_ASCII_LOG - bool "Gateway: ASCII + log" + bool "Enable non-standard message log read" depends on CANOPENNODE_GTW_ASCII default n config CANOPENNODE_GTW_ASCII_ERROR_DESC - bool "Gateway: ASCII + error descriptions" + bool "Print error descriptions as comments in gateway-ascii" depends on CANOPENNODE_GTW_ASCII default n config CANOPENNODE_GTW_ASCII_PRINT_HELP - bool "Gateway: ASCII + 'help'" + bool "Enable non-standard \"help\" command" depends on CANOPENNODE_GTW_ASCII default n config CANOPENNODE_GTW_ASCII_PRINT_LEDS - bool "Gateway: ASCII + LED state" + bool "Display CANopen status LEDs on terminal" depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_LEDS_ENABLE default n config CANOPENNODE_GTW_BLOCK_DL_LOOP - int "Gateway: block download loop (1..127)" + int "Number of process loops in case of block download" range 1 127 default 1 + help + Additional local loop iterations while a block download is in progress + to speed up transfer (up to 127). config CANOPENNODE_GTWA_COMM_BUF_SIZE - int "Gateway: command buffer size" - range 16 65535 + int "Size of command buffer in ASCII gateway object" + range 16 4096 default 200 + help + Increase to >=1000 when doing large block transfers. config CANOPENNODE_GTWA_LOG_BUF_SIZE int "Gateway: log buffer size" - range 128 131072 + range 128 4096 default 2000 + endmenu -menu "CRC16 / FIFO / Trace / Debug" +menu "CRC 16 calculation" config CANOPENNODE_CRC16_ENABLE - bool "CRC16" + bool "Enable CRC16 calculation" default n config CANOPENNODE_CRC16_EXTERNAL - bool "CRC16 external implementation" + bool "CRC functions are defined externally" depends on CANOPENNODE_CRC16_ENABLE - default y if CANOPENNODE_CRC16_ENABLE select CRC + default y if CANOPENNODE_CRC16_ENABLE + help + If enabled, the application must provide: + void crc16_ccitt_single(uint16_t *crc, uint8_t chr); + uint16_t crc16_ccitt(const uint8_t block[], size_t len, uint16_t crc); + If disabled, the internal CRC16 functions will be used. + +endmenu + +menu "FIFO buffer" config CANOPENNODE_FIFO_ENABLE - bool "FIFO" + bool "Enable FIFO buffer" default n config CANOPENNODE_FIFO_ALT_READ @@ -476,28 +715,68 @@ config CANOPENNODE_FIFO_ASCII_DATATYPES bool "FIFO ASCII datatype helpers" depends on CANOPENNODE_FIFO_ENABLE && CANOPENNODE_FIFO_ASCII_COMMANDS default n + help + Helpers to read/write integers/floats/strings in ASCII. + +endmenu + +menu "Trace recorder" config CANOPENNODE_TRACE_ENABLE - bool "Trace recorder" + bool "Enable Trace recorder" default n config CANOPENNODE_TRACE_OWN_INTTYPES - bool "Trace: own inttypes" + bool "Provide custom PRIu32/PRId32 macros (no )" depends on CANOPENNODE_TRACE_ENABLE default n +endmenu + +menu "Debug messages" + config CANOPENNODE_DEBUG_COMMON - bool "Debug: COMMON" + bool "Define default CO_DEBUG_COMMON(msg) macro" default n config CANOPENNODE_DEBUG_SDO_CLIENT - bool "Debug: SDO CLIENT" + bool "Define default CO_DEBUG_SDO_CLIENT(msg) macro" default n config CANOPENNODE_DEBUG_SDO_SERVER - bool "Debug: SDO SERVER" + bool "Define default CO_DEBUG_SDO_SERVER(msg) macro" default n endmenu +menu "Object Dictionary (EDS)" + +config CANOPENNODE_EDS_FILE_PATH + string "EDS file (path relative to application root)" + default "" + help + Path to the EDS used to generate OD.c/OD.h. + Leave empty to use: + example/DS301_profile.eds + +endmenu + +menu "CANopenNode TX Workqueue Options" + +config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE + int "TX workqueue stack size" + range 256 16384 + default 1024 + help + Stack size (bytes) for the CANopenNode TX workqueue thread. + +config CANOPENNODE_TX_WORKQUEUE_PRIORITY + int "TX workqueue priority" + default 0 + help + Thread priority for the CANopenNode TX workqueue. + Lower numbers mean higher priority. + +endmenu + endif # CANOPENNODE diff --git a/zephyr/include/CO_LEDs_zephyr.h b/zephyr/include/CO_LEDs_zephyr.h new file mode 100644 index 00000000..ebc4603f --- /dev/null +++ b/zephyr/include/CO_LEDs_zephyr.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include +#include "303/CO_LEDs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialize GPIOs for CANopen LEDs using DT aliases: + * - alias: co_led_run -> RUN/green LED + * - alias: co_led_err -> ERR/red LED + * + * Pins are configured OUTPUT_INACTIVE. Active level/inversion + * is taken from devicetree flags (GPIO_ACTIVE_LOW/HIGH). + * + * @return 0 on success, -ENODEV if aliases missing or devices not ready, + * or a negative errno from gpio_pin_configure_dt(). + */ +int co_leds_zephyr_init_dt_aliases(void); + +/** + * Register the CANopen LED callback so LED states are mirrored to hardware + * after each CO_LEDs_process() update. Call once after CO_LEDs_init(). + */ +void co_leds_zephyr_connect_callback(CO_LEDs_t *leds); + +/** + * Optional: immediately mirror the current CO LEDs once (e.g., right after init). + * Safe to call anytime. + */ +void co_leds_zephyr_sync_once(CO_LEDs_t *leds); + +#ifdef __cplusplus +} +#endif diff --git a/zephyr/include/CO_canopen_zephyr.h b/zephyr/include/CO_canopen_zephyr.h new file mode 100644 index 00000000..30039c58 --- /dev/null +++ b/zephyr/include/CO_canopen_zephyr.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include + +#include "CANopen.h" + +/** + * @file co_canopen_zephyr.h + * @brief Zephyr-owned CANopen scheduler: + * - Worker: runs CO_process() and reschedules (timerNext_us optional) + * - RT thread: event-driven SYNC/RPDO/TPDO via PRE-callbacks (Option B) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------- Core scheduler API ---------- */ + +/** Resolve CAN device (DT chosen or Kconfig) and start the worker. */ +int co_canopen_start_auto(void); + +/** Start with explicit CAN device and Node-ID. */ +int co_canopen_start(const struct device *can_dev, uint8_t node_id); + +/** Stop worker and tear down stack. */ +void co_canopen_stop(void); + +/** Get active CO_t pointer (or NULL). */ +CO_t *co_canopen_get(void); + +/** Is worker running? */ +bool co_canopen_is_running(void); + +/** Rebuild RX filters from the port-provided table (safe when running). */ +int co_canopen_refresh_filters(void); + +/* ---------- Port hooks (weak) you implement in your CANopenNode port ---------- */ +/** + * Allocate/init CANopenNode (CO), bind to @p can_dev, configure OD/COB-IDs, etc. + * Must set *out_co on success. + */ +int __weak coz_port_create(const struct device *can_dev, uint8_t node_id, CO_t **out_co); + +/** Teardown/free CANopenNode created by coz_port_create(). */ +void __weak coz_port_destroy(CO_t *co); + +/** + * Provide RX filter table for all COB-IDs the stack should receive. + * Return count (<= max_filters). Fill @p out (id/mask/flags). + */ +size_t __weak coz_port_get_filter_table(const CO_t *co, struct can_filter *out, size_t max_filters); + +/** + * Dispatch one received CAN frame into CANopenNode (ISR context). + * Keep this short & non-blocking; do heavy work in CO_process(). + */ +void __weak coz_port_rx_dispatch_isr(CO_t *co, const struct can_frame *frame); + +/** + * Enable PRE-callbacks for SYNC and RPDO so the RT thread wakes immediately. + * Typical implementation: + * CO_SYNC_initCallbackPre(CO->SYNC, pre_cb, pre_arg); + * for each RPDO: CO_RPDO_initCallbackPre(rpdo, pre_cb, pre_arg); + * + * Pass @p pre_cb = coz_rt_signal_cb and @p pre_arg = NULL (or anything). + */ +void __weak coz_port_enable_pre_signals(CO_t *co, void (*pre_cb)(void *object), void *pre_arg); + +/* ---------- Provided PRE-callback for ports to use ---------- */ +/** + * PRE-callback you can register in your port to wake the RT thread. + * Signature matches CANopenNode's *_initCallbackPre() expectations. + * Safe to call from ISR or thread context. + */ +void coz_rt_signal_cb(void *object); + +#ifdef __cplusplus +} +#endif diff --git a/zephyr/include/CO_config_zephyr.h b/zephyr/include/CO_config_zephyr.h index 5b77789e..a39836d2 100644 --- a/zephyr/include/CO_config_zephyr.h +++ b/zephyr/include/CO_config_zephyr.h @@ -1,141 +1,243 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright (c) 2025 BitConcepts, LLC - * - * CANopenNode — Zephyr configuration mapping - * This header maps Zephyr Kconfig symbols (CONFIG_CANOPENNODE_*) to - * the CO_CONFIG_* macros used by the portable CANopenNode stack. - * - * The CO_CONFIG_* macros are documented in CO_config.h of CANopenNode. - * This mapper ensures that undefined CONFIG_ symbols are treated as 0, - * so the macros are safe for use outside Zephyr. +/* co_config_zephyr.h + * Map Zephyr Kconfig (CONFIG_CANOPENNODE_*) to CANopenNode CO_CONFIG_* macros. */ - -#ifndef CO_CONFIG_ZEPHYR_H -#define CO_CONFIG_ZEPHYR_H - -/* Helper: ensure undefined CONFIG_* are treated as 0 */ -#define ZCFG(sym) (defined(CONFIG_##sym) && (CONFIG_##sym) ? 1 : 0) - -/* ---------------- Global configuration flags ---------------- */ -#define CO_CONFIG_GLOBAL(CALLBACK_PRE, CALLBACK_PRE_RTR, TIMERNEXT, OD_DYNAMIC) \ - (((CALLBACK_PRE) ? CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE : 0) | \ - ((CALLBACK_PRE_RTR) ? CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE : 0) | \ - ((TIMERNEXT) ? CO_CONFIG_GLOBAL_FLAG_TIMERNEXT : 0) | \ - ((OD_DYNAMIC) ? CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC : 0)) - -#define CO_CONFIG_GLOBAL_FLAGS \ - CO_CONFIG_GLOBAL(ZCFG(CANOPENNODE_GLOBAL_FLAG_CALLBACK_PRE), \ - ZCFG(CANOPENNODE_GLOBAL_RT_FLAG_CALLBACK_PRE), \ - ZCFG(CANOPENNODE_GLOBAL_FLAG_TIMERNEXT), \ - ZCFG(CANOPENNODE_GLOBAL_FLAG_OD_DYNAMIC)) - -/* ---------------- NMT and Heartbeat ---------------- */ -#define CO_CONFIG_NMT_FLAGS \ - ((ZCFG(CANOPENNODE_NMT_CALLBACK_CHANGE) ? CO_CONFIG_NMT_CALLBACK_CHANGE : 0) | \ - (ZCFG(CANOPENNODE_NMT_MASTER) ? CO_CONFIG_NMT_MASTER : 0)) - -#define CO_CONFIG_HB_CONS_FLAGS \ - ((ZCFG(CANOPENNODE_HB_CONS_ENABLE) ? CO_CONFIG_HB_CONS_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_HB_CONS_CALLBACK_CHANGE) ? CO_CONFIG_HB_CONS_CALLBACK_CHANGE : 0) | \ - (ZCFG(CANOPENNODE_HB_CONS_CALLBACK_MULTI) ? CO_CONFIG_HB_CONS_CALLBACK_MULTI : 0) | \ - (ZCFG(CANOPENNODE_HB_CONS_QUERY_FUNCT) ? CO_CONFIG_HB_CONS_QUERY_FUNCT : 0)) - -/* ---------------- Emergency ---------------- */ -#define CO_CONFIG_EM_FLAGS \ - ((ZCFG(CANOPENNODE_EM_PRODUCER) ? CO_CONFIG_EM_PRODUCER : 0) | \ - (ZCFG(CANOPENNODE_EM_PROD_CONFIGURABLE) ? CO_CONFIG_EM_PROD_CONFIGURABLE : 0) | \ - (ZCFG(CANOPENNODE_EM_PROD_INHIBIT) ? CO_CONFIG_EM_PROD_INHIBIT : 0) | \ - (ZCFG(CANOPENNODE_EM_HISTORY) ? CO_CONFIG_EM_HISTORY : 0) | \ - (ZCFG(CANOPENNODE_EM_STATUS_BITS) ? CO_CONFIG_EM_STATUS_BITS : 0) | \ - (ZCFG(CANOPENNODE_EM_CONSUMER) ? CO_CONFIG_EM_CONSUMER : 0)) - -#define CO_CONFIG_ERR_CONDITION_FLAGS \ - ((ZCFG(CANOPENNODE_ERR_CONDITION_GENERIC) ? CO_CONFIG_ERR_CONDITION_GENERIC : 0) | \ - (ZCFG(CANOPENNODE_ERR_CONDITION_CURRENT) ? CO_CONFIG_ERR_CONDITION_CURRENT : 0) | \ - (ZCFG(CANOPENNODE_ERR_CONDITION_VOLTAGE) ? CO_CONFIG_ERR_CONDITION_VOLTAGE : 0) | \ - (ZCFG(CANOPENNODE_ERR_CONDITION_TEMPERATURE) ? CO_CONFIG_ERR_CONDITION_TEMPERATURE : 0) | \ - (ZCFG(CANOPENNODE_ERR_CONDITION_COMMUNICATION) ? CO_CONFIG_ERR_CONDITION_COMMUNICATION \ - : 0) | \ - (ZCFG(CANOPENNODE_ERR_CONDITION_DEV_PROFILE) ? CO_CONFIG_ERR_CONDITION_DEV_PROFILE : 0) | \ - (ZCFG(CANOPENNODE_ERR_CONDITION_MANUFACTURER) ? CO_CONFIG_ERR_CONDITION_MANUFACTURER \ - : 0)) - -/* ---------------- SDO ---------------- */ -#define CO_CONFIG_SDO_SRV_FLAGS \ - ((ZCFG(CANOPENNODE_SDO_SRV_SEGMENTED) ? CO_CONFIG_SDO_SRV_SEGMENTED : 0) | \ - (ZCFG(CANOPENNODE_SDO_SRV_BLOCK) ? CO_CONFIG_SDO_SRV_BLOCK : 0)) - -#define CO_CONFIG_SDO_CLI_FLAGS \ - ((ZCFG(CANOPENNODE_SDO_CLI_ENABLE) ? CO_CONFIG_SDO_CLI_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_SDO_CLI_SEGMENTED) ? CO_CONFIG_SDO_CLI_SEGMENTED : 0) | \ - (ZCFG(CANOPENNODE_SDO_CLI_BLOCK) ? CO_CONFIG_SDO_CLI_BLOCK : 0) | \ - (ZCFG(CANOPENNODE_SDO_CLI_LOCAL) ? CO_CONFIG_SDO_CLI_LOCAL : 0)) - -/* ---------------- TIME / SYNC / PDO ---------------- */ -#define CO_CONFIG_SYNC_FLAGS \ - ((ZCFG(CANOPENNODE_SYNC_ENABLE) ? CO_CONFIG_SYNC_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_SYNC_PRODUCER) ? CO_CONFIG_SYNC_PRODUCER : 0)) - -#define CO_CONFIG_PDO_FLAGS \ - ((ZCFG(CANOPENNODE_RPDO_ENABLE) ? CO_CONFIG_RPDO_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_TPDO_ENABLE) ? CO_CONFIG_TPDO_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_RPDO_TIMERS_ENABLE) ? CO_CONFIG_RPDO_TIMERS_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_TPDO_TIMERS_ENABLE) ? CO_CONFIG_TPDO_TIMERS_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_PDO_SYNC_ENABLE) ? CO_CONFIG_PDO_SYNC_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_PDO_OD_IO_ACCESS) ? CO_CONFIG_PDO_OD_IO_ACCESS : 0)) - -/* ---------------- Storage / LEDs ---------------- */ -#define CO_CONFIG_STORAGE_FLAGS (ZCFG(CANOPENNODE_STORAGE_ENABLE) ? CO_CONFIG_STORAGE_ENABLE : 0) - -#define CO_CONFIG_LEDS_FLAGS (ZCFG(CANOPENNODE_LEDS_ENABLE) ? CO_CONFIG_LEDS_ENABLE : 0) - -/* ---------------- SRDO / GFC ---------------- */ -#define CO_CONFIG_GFC_FLAGS \ - ((ZCFG(CANOPENNODE_GFC_ENABLE) ? CO_CONFIG_GFC_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_GFC_CONSUMER) ? CO_CONFIG_GFC_CONSUMER : 0) | \ - (ZCFG(CANOPENNODE_GFC_PRODUCER) ? CO_CONFIG_GFC_PRODUCER : 0)) - -#define CO_CONFIG_SRDO_FLAGS \ - ((ZCFG(CANOPENNODE_SRDO_ENABLE) ? CO_CONFIG_SRDO_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_SRDO_CHECK_TX) ? CO_CONFIG_SRDO_CHECK_TX : 0)) - -/* ---------------- LSS ---------------- */ -#define CO_CONFIG_LSS_FLAGS \ - ((ZCFG(CANOPENNODE_LSS_SLAVE) ? CO_CONFIG_LSS_SLAVE : 0) | \ - (ZCFG(CANOPENNODE_LSS_MASTER) ? CO_CONFIG_LSS_MASTER : 0)) - -/* ---------------- Gateway ---------------- */ -#define CO_CONFIG_GTWA_FLAGS \ - ((ZCFG(CANOPENNODE_GTW_MULTI_NET) ? CO_CONFIG_GTWA_MULTI_NET : 0) | \ - (ZCFG(CANOPENNODE_GTW_ASCII) ? CO_CONFIG_GTWA_ASCII : 0) | \ - (ZCFG(CANOPENNODE_GTW_ASCII_SDO) ? CO_CONFIG_GTWA_ASCII_SDO : 0) | \ - (ZCFG(CANOPENNODE_GTW_ASCII_NMT) ? CO_CONFIG_GTWA_ASCII_NMT : 0) | \ - (ZCFG(CANOPENNODE_GTW_ASCII_LSS) ? CO_CONFIG_GTWA_ASCII_LSS : 0) | \ - (ZCFG(CANOPENNODE_GTW_ASCII_LOG) ? CO_CONFIG_GTWA_ASCII_LOG : 0) | \ - (ZCFG(CANOPENNODE_GTW_ASCII_ERROR_DESC) ? CO_CONFIG_GTWA_ASCII_ERROR_DESC : 0) | \ - (ZCFG(CANOPENNODE_GTW_ASCII_PRINT_HELP) ? CO_CONFIG_GTWA_ASCII_PRINT_HELP : 0) | \ - (ZCFG(CANOPENNODE_GTW_ASCII_PRINT_LEDS) ? CO_CONFIG_GTWA_ASCII_PRINT_LEDS : 0)) - -/* ---------------- FIFO / CRC / Trace / Debug ---------------- */ -#define CO_CONFIG_FIFO_FLAGS \ - ((ZCFG(CANOPENNODE_FIFO_ENABLE) ? CO_CONFIG_FIFO_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_FIFO_ALT_READ) ? CO_CONFIG_FIFO_ALT_READ : 0) | \ - (ZCFG(CANOPENNODE_FIFO_CRC16_CCITT) ? CO_CONFIG_FIFO_CRC16_CCITT : 0) | \ - (ZCFG(CANOPENNODE_FIFO_ASCII_COMMANDS) ? CO_CONFIG_FIFO_ASCII_COMMANDS : 0) | \ - (ZCFG(CANOPENNODE_FIFO_ASCII_DATATYPES) ? CO_CONFIG_FIFO_ASCII_DATATYPES : 0)) - -#define CO_CONFIG_CRC16_FLAGS \ - ((ZCFG(CANOPENNODE_CRC16_ENABLE) ? CO_CONFIG_CRC16_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_CRC16_EXTERNAL) ? CO_CONFIG_CRC16_EXTERNAL : 0)) - -#define CO_CONFIG_TRACE_FLAGS \ - ((ZCFG(CANOPENNODE_TRACE_ENABLE) ? CO_CONFIG_TRACE_ENABLE : 0) | \ - (ZCFG(CANOPENNODE_TRACE_OWN_INTTYPES) ? CO_CONFIG_TRACE_OWN_INTTYPES : 0)) - -#define CO_CONFIG_DEBUG_FLAGS \ - ((ZCFG(CANOPENNODE_DEBUG_COMMON) ? CO_CONFIG_DEBUG_COMMON : 0) | \ - (ZCFG(CANOPENNODE_DEBUG_SDO_CLIENT) ? CO_CONFIG_DEBUG_SDO_CLIENT : 0) | \ - (ZCFG(CANOPENNODE_DEBUG_SDO_SERVER) ? CO_CONFIG_DEBUG_SDO_SERVER : 0)) - -#endif /* CO_CONFIG_ZEPHYR_H */ +#pragma once + +#include /* CONFIG_* */ +#include /* IS_ENABLED, BIT */ + +/* Small helpers to OR flags conditionally */ +#define ZBIT(flag, cfgsym) (IS_ENABLED(cfgsym) ? (flag) : 0) +#define ZVAL(cfgsym) (cfgsym) + +/* ---------- NMT / Heartbeat producer ---------- */ +#define CO_CONFIG_NMT \ + (ZBIT(CO_CONFIG_NMT_CALLBACK_CHANGE, CONFIG_CANOPENNODE_NMT_CALLBACK_CHANGE) | \ + ZBIT(CO_CONFIG_NMT_MASTER, CONFIG_CANOPENNODE_NMT_MASTER) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_NMT_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_NMT_TIMERNEXT)) + +/* Optional: first heartbeat delay (ms) if you wire it in app code */ +#define CO_NMT_FIRST_HB_TIME_MS CONFIG_CANOPENNODE_NMT_FIRST_HB_TIME_MS + +/* NMT startup/control bits as plain defines you use in app/init glue */ +#define CO_NMT_STARTUP_TO_OPERATIONAL IS_ENABLED(CONFIG_CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL) +#define CO_NMT_ERR_ON_BUSOFF_HB IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_ON_BUSOFF_HB) +#define CO_NMT_ERR_ON_ERR_REG IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_ON_ERR_REG) +#define CO_NMT_ERR_TO_STOPPED IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_TO_STOPPED) +#define CO_NMT_ERR_FREE_TO_OPERATIONAL IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL) + +/* NMT error-register mask composition */ +#define CO_NMT_ERR_MASK_BASE CONFIG_CANOPENNODE_NMT_ERR_REG_MASK +#define CO_NMT_ERR_MASK_GENERIC (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_GENERIC) ? BIT(0) : 0) +#define CO_NMT_ERR_MASK_CURRENT (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_CURRENT) ? BIT(1) : 0) +#define CO_NMT_ERR_MASK_VOLTAGE (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_VOLTAGE) ? BIT(2) : 0) +#define CO_NMT_ERR_MASK_TEMP (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_TEMPERATURE) ? BIT(3) : 0) +#define CO_NMT_ERR_MASK_COMM (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_COMM) ? BIT(4) : 0) +#define CO_NMT_ERR_MASK_DEVPROF \ + (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_DEV_PROFILE) ? BIT(5) : 0) +#define CO_NMT_ERR_MASK_MFG (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_MANUFACTURER) ? BIT(7) : 0) +/* Effective mask you can pass into your init */ +#define CO_NMT_ERR_MASK \ + (CO_NMT_ERR_MASK_BASE | CO_NMT_ERR_MASK_GENERIC | CO_NMT_ERR_MASK_CURRENT | \ + CO_NMT_ERR_MASK_VOLTAGE | CO_NMT_ERR_MASK_TEMP | CO_NMT_ERR_MASK_COMM | \ + CO_NMT_ERR_MASK_DEVPROF | CO_NMT_ERR_MASK_MFG) + +/* ---------- Heartbeat consumer ---------- */ +#define CO_CONFIG_HB_CONS \ + (ZBIT(CO_CONFIG_HB_CONS_ENABLE, CONFIG_CANOPENNODE_HB_CONS_ENABLE) | \ + ZBIT(CO_CONFIG_HB_CONS_CALLBACK_CHANGE, CONFIG_CANOPENNODE_HB_CONS_CALLBACK_CHANGE) | \ + ZBIT(CO_CONFIG_HB_CONS_CALLBACK_MULTI, CONFIG_CANOPENNODE_HB_CONS_CALLBACK_MULTI) | \ + ZBIT(CO_CONFIG_HB_CONS_QUERY_FUNCT, CONFIG_CANOPENNODE_HB_CONS_QUERY_FUNCT) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_HB_CONS_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_HB_CONS_TIMERNEXT) | \ + ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_HB_CONS_OD_DYNAMIC)) + +/* ---------- Node Guarding ---------- */ +#define CO_CONFIG_NODE_GUARDING \ + (ZBIT(CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE, \ + CONFIG_CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE) | \ + ZBIT(CO_CONFIG_NODE_GUARDING_MASTER_ENABLE, \ + CONFIG_CANOPENNODE_NODE_GUARDING_MASTER_ENABLE) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_NODE_GUARDING_TIMERNEXT)) + +/* Count */ +#ifdef CONFIG_CANOPENNODE_NODE_GUARDING_MASTER_COUNT +#define CO_CONFIG_NODE_GUARDING_MASTER_COUNT CONFIG_CANOPENNODE_NODE_GUARDING_MASTER_COUNT +#endif + +/* ---------- Emergency ---------- */ +#define CO_CONFIG_EM \ + (ZBIT(CO_CONFIG_EM_PRODUCER, CONFIG_CANOPENNODE_EM_PRODUCER) | \ + ZBIT(CO_CONFIG_EM_PROD_CONFIGURABLE, CONFIG_CANOPENNODE_EM_PROD_CONFIGURABLE) | \ + ZBIT(CO_CONFIG_EM_PROD_INHIBIT, CONFIG_CANOPENNODE_EM_PROD_INHIBIT) | \ + ZBIT(CO_CONFIG_EM_HISTORY, CONFIG_CANOPENNODE_EM_HISTORY) | \ + ZBIT(CO_CONFIG_EM_CONSUMER, CONFIG_CANOPENNODE_EM_CONSUMER) | \ + ZBIT(CO_CONFIG_EM_STATUS_BITS, CONFIG_CANOPENNODE_EM_STATUS_BITS) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_EM_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_EM_TIMERNEXT)) + +#define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT CONFIG_CANOPENNODE_EM_ERR_STATUS_BITS_COUNT + +/* Optional default conditions (you’ll map these to your CO_CONFIG_ERR_CONDITION_* usage) */ +#define CO_HAVE_ERR_COND_GENERIC IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_GENERIC) +#define CO_HAVE_ERR_COND_CURRENT IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_CURRENT) +#define CO_HAVE_ERR_COND_VOLTAGE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_VOLTAGE) +#define CO_HAVE_ERR_COND_TEMPERATURE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_TEMPERATURE) +#define CO_HAVE_ERR_COND_COMMUNICATION IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_COMMUNICATION) +#define CO_HAVE_ERR_COND_DEV_PROFILE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_DEV_PROFILE) +#define CO_HAVE_ERR_COND_MANUFACTURER IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_MANUFACTURER) + +/* ---------- SDO server ---------- */ +#define CO_CONFIG_SDO_SRV \ + (ZBIT(CO_CONFIG_SDO_SRV_SEGMENTED, CONFIG_CANOPENNODE_SDO_SERVER_SEGMENTED) | \ + ZBIT(CO_CONFIG_SDO_SRV_BLOCK, CONFIG_CANOPENNODE_SDO_SERVER_BLOCK) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_SDO_SERVER_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_SDO_SERVER_TIMERNEXT) | \ + ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_SDO_SERVER_OD_DYNAMIC)) + +#define CO_CONFIG_SDO_SRV_BUFFER_SIZE CONFIG_CANOPENNODE_SDO_SERVER_BUFFER_SIZE +#define CO_CONFIG_SDO_SRV_TIMEOUT_MS CONFIG_CANOPENNODE_SDO_SERVER_TIMEOUT_MS + +/* ---------- SDO client ---------- */ +#define CO_CONFIG_SDO_CLI \ + (ZBIT(CO_CONFIG_SDO_CLI_ENABLE, CONFIG_CANOPENNODE_SDO_CLIENT_ENABLE) | \ + ZBIT(CO_CONFIG_SDO_CLI_SEGMENTED, CONFIG_CANOPENNODE_SDO_CLIENT_SEGMENTED) | \ + ZBIT(CO_CONFIG_SDO_CLI_BLOCK, CONFIG_CANOPENNODE_SDO_CLIENT_BLOCK) | \ + ZBIT(CO_CONFIG_SDO_CLI_LOCAL, CONFIG_CANOPENNODE_SDO_CLIENT_LOCAL) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_SDO_CLIENT_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_SDO_CLIENT_TIMERNEXT) | \ + ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_SDO_CLIENT_OD_DYNAMIC)) + +#define CO_CONFIG_SDO_CLI_BUFFER_SIZE CONFIG_CANOPENNODE_SDO_CLIENT_BUFFER_SIZE +#define CO_CONFIG_SDO_CLI_TIMEOUT_MS CONFIG_CANOPENNODE_SDO_CLIENT_TIMEOUT_MS + +/* Sanity for block client deps (belt & suspenders) */ +#if IS_ENABLED(CONFIG_CANOPENNODE_SDO_CLIENT_BLOCK) +#if !IS_ENABLED(CONFIG_CANOPENNODE_FIFO_ALT_READ) || \ + !IS_ENABLED(CONFIG_CANOPENNODE_FIFO_CRC16_CCITT) +#error "SDO client block requires FIFO_ALT_READ and FIFO_CRC16_CCITT" +#endif +#endif + +/* ---------- TIME ---------- */ +#define CO_CONFIG_TIME \ + (ZBIT(CO_CONFIG_TIME_ENABLE, CONFIG_CANOPENNODE_TIME_ENABLE) | \ + ZBIT(CO_CONFIG_TIME_PRODUCER, CONFIG_CANOPENNODE_TIME_PRODUCER) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_TIME_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_TIME_OD_DYNAMIC)) + +/* ---------- SYNC / PDO ---------- */ +#define CO_CONFIG_SYNC \ + (ZBIT(CO_CONFIG_SYNC_ENABLE, CONFIG_CANOPENNODE_SYNC_ENABLE) | \ + ZBIT(CO_CONFIG_SYNC_PRODUCER, CONFIG_CANOPENNODE_SYNC_PRODUCER) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_SYNC_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_SYNC_TIMERNEXT) | \ + ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_SYNC_OD_DYNAMIC)) + +#define CO_CONFIG_PDO \ + (ZBIT(CO_CONFIG_RPDO_ENABLE, CONFIG_CANOPENNODE_RPDO_ENABLE) | \ + ZBIT(CO_CONFIG_TPDO_ENABLE, CONFIG_CANOPENNODE_TPDO_ENABLE) | \ + ZBIT(CO_CONFIG_RPDO_TIMERS_ENABLE, CONFIG_CANOPENNODE_RPDO_TIMERS_ENABLE) | \ + ZBIT(CO_CONFIG_TPDO_TIMERS_ENABLE, CONFIG_CANOPENNODE_TPDO_TIMERS_ENABLE) | \ + ZBIT(CO_CONFIG_PDO_SYNC_ENABLE, CONFIG_CANOPENNODE_PDO_SYNC_ENABLE) | \ + ZBIT(CO_CONFIG_PDO_OD_IO_ACCESS, CONFIG_CANOPENNODE_PDO_OD_IO_ACCESS) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_PDO_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_PDO_TIMERNEXT) | \ + ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_PDO_OD_DYNAMIC)) + +/* ---------- Storage ---------- */ +#define CO_CONFIG_STORAGE (ZBIT(CO_CONFIG_STORAGE_ENABLE, CONFIG_CANOPENNODE_STORAGE_ENABLE)) + +/* Backend selection for your storage glue */ +#define CO_STORAGE_BACKEND_SETTINGS IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_BACKEND_SETTINGS) +#define CO_STORAGE_BACKEND_RAM IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_BACKEND_RAM) +#define CO_STORAGE_BACKEND_NONE IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE) + +/* ---------- LEDs ---------- */ +#define CO_CONFIG_LEDs \ + (ZBIT(CO_CONFIG_LEDS_ENABLE, CONFIG_CANOPENNODE_LEDS_ENABLE) | \ + ZBIT(CO_CONFIG_LEDS_CALLBACK, CONFIG_CANOPENNODE_LEDS_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_LEDS_TIMERNEXT)) + +/* ---------- SRDO / GFC ---------- */ +#define CO_CONFIG_GFC \ + (ZBIT(CO_CONFIG_GFC_ENABLE, CONFIG_CANOPENNODE_GFC_ENABLE) | \ + ZBIT(CO_CONFIG_GFC_CONSUMER, CONFIG_CANOPENNODE_GFC_CONSUMER) | \ + ZBIT(CO_CONFIG_GFC_PRODUCER, CONFIG_CANOPENNODE_GFC_PRODUCER)) + +#define CO_CONFIG_SRDO \ + (ZBIT(CO_CONFIG_SRDO_ENABLE, CONFIG_CANOPENNODE_SRDO_ENABLE) | \ + ZBIT(CO_CONFIG_SRDO_CHECK_TX, CONFIG_CANOPENNODE_SRDO_CHECK_TX) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_SRDO_CALLBACK) | \ + ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_SRDO_TIMERNEXT)) + +#define CO_CONFIG_SRDO_MINIMUM_DELAY CONFIG_CANOPENNODE_SRDO_MINIMUM_DELAY + +/* ---------- LSS ---------- */ +#define CO_CONFIG_LSS \ + (ZBIT(CO_CONFIG_LSS_SLAVE, CONFIG_CANOPENNODE_LSS_SLAVE) | \ + ZBIT(CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND, \ + CONFIG_CANOPENNODE_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND) | \ + ZBIT(CO_CONFIG_LSS_MASTER, CONFIG_CANOPENNODE_LSS_MASTER) | \ + ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_LSS_CALLBACK)) + +/* ---------- Gateway (CiA 309) ---------- */ +#define CO_CONFIG_GTW \ + (ZBIT(CO_CONFIG_GTW_MULTI_NET, CONFIG_CANOPENNODE_GTW_MULTI_NET) | \ + ZBIT(CO_CONFIG_GTW_ASCII, CONFIG_CANOPENNODE_GTW_ASCII) | \ + ZBIT(CO_CONFIG_GTW_ASCII_SDO, CONFIG_CANOPENNODE_GTW_ASCII_SDO) | \ + ZBIT(CO_CONFIG_GTW_ASCII_NMT, CONFIG_CANOPENNODE_GTW_ASCII_NMT) | \ + ZBIT(CO_CONFIG_GTW_ASCII_LSS, CONFIG_CANOPENNODE_GTW_ASCII_LSS) | \ + ZBIT(CO_CONFIG_GTW_ASCII_LOG, CONFIG_CANOPENNODE_GTW_ASCII_LOG) | \ + ZBIT(CO_CONFIG_GTW_ASCII_ERROR_DESC, CONFIG_CANOPENNODE_GTW_ASCII_ERROR_DESC) | \ + ZBIT(CO_CONFIG_GTW_ASCII_PRINT_HELP, CONFIG_CANOPENNODE_GTW_ASCII_PRINT_HELP) | \ + ZBIT(CO_CONFIG_GTW_ASCII_PRINT_LEDS, CONFIG_CANOPENNODE_GTW_ASCII_PRINT_LEDS)) + +#define CO_CONFIG_GTW_BLOCK_DL_LOOP CONFIG_CANOPENNODE_GTW_BLOCK_DL_LOOP +#define CO_CONFIG_GTWA_COMM_BUF_SIZE CONFIG_CANOPENNODE_GTWA_COMM_BUF_SIZE +#define CO_CONFIG_GTWA_LOG_BUF_SIZE CONFIG_CANOPENNODE_GTWA_LOG_BUF_SIZE + +/* ---------- CRC16 ---------- */ +#define CO_CONFIG_CRC16 \ + (ZBIT(CO_CONFIG_CRC16_ENABLE, CONFIG_CANOPENNODE_CRC16_ENABLE) | \ + ZBIT(CO_CONFIG_CRC16_EXTERNAL, CONFIG_CANOPENNODE_CRC16_EXTERNAL)) + +/* ---------- FIFO ---------- */ +#define CO_CONFIG_FIFO \ + (ZBIT(CO_CONFIG_FIFO_ENABLE, CONFIG_CANOPENNODE_FIFO_ENABLE) | \ + ZBIT(CO_CONFIG_FIFO_ALT_READ, CONFIG_CANOPENNODE_FIFO_ALT_READ) | \ + ZBIT(CO_CONFIG_FIFO_CRC16_CCITT, CONFIG_CANOPENNODE_FIFO_CRC16_CCITT) | \ + ZBIT(CO_CONFIG_FIFO_ASCII_COMMANDS, CONFIG_CANOPENNODE_FIFO_ASCII_COMMANDS) | \ + ZBIT(CO_CONFIG_FIFO_ASCII_DATATYPES, CONFIG_CANOPENNODE_FIFO_ASCII_DATATYPES)) + +/* ---------- Trace ---------- */ +#define CO_CONFIG_TRACE \ + (ZBIT(CO_CONFIG_TRACE_ENABLE, CONFIG_CANOPENNODE_TRACE_ENABLE) | \ + ZBIT(CO_CONFIG_TRACE_OWN_INTTYPES, CONFIG_CANOPENNODE_TRACE_OWN_INTTYPES)) + +/* ---------- Debug ---------- */ +#define CO_CONFIG_DEBUG \ + (ZBIT(CO_CONFIG_DEBUG_COMMON, CONFIG_CANOPENNODE_DEBUG_COMMON) | \ + ZBIT(CO_CONFIG_DEBUG_SDO_CLIENT, CONFIG_CANOPENNODE_DEBUG_SDO_CLIENT) | \ + ZBIT(CO_CONFIG_DEBUG_SDO_SERVER, CONFIG_CANOPENNODE_DEBUG_SDO_SERVER)) + +/* ---------- TX workqueue (Zephyr integration) ---------- */ +#define CO_TX_WQ_STACK_SIZE CONFIG_CANOPENNODE_TX_WORKQUEUE_STACK_SIZE +#define CO_TX_WQ_PRIORITY CONFIG_CANOPENNODE_TX_WORKQUEUE_PRIORITY + +/* ---------- EDS path ---------- */ +#define CO_EDS_FILE_PATH CONFIG_CANOPENNODE_EDS_FILE_PATH + +/* --------- Optional compile-time sanity checks --------- */ +#if IS_ENABLED(CONFIG_CANOPENNODE_SDO_SERVER_BLOCK) +#if (CONFIG_CANOPENNODE_SDO_SERVER_BUFFER_SIZE < 900) +#error "SDO server block requires buffer >= 900 bytes" +#endif +#endif + +#if IS_ENABLED(CONFIG_CANOPENNODE_SDO_CLIENT_BLOCK) +#if (CONFIG_CANOPENNODE_SDO_CLIENT_BUFFER_SIZE < 1000) +#error "SDO client block recommends buffer >= 1000 bytes" +#endif +#endif diff --git a/zephyr/include/CO_driver_target.h b/zephyr/include/CO_driver_target.h index 15101baa..0ba6ffc1 100644 --- a/zephyr/include/CO_driver_target.h +++ b/zephyr/include/CO_driver_target.h @@ -38,12 +38,12 @@ extern "C" { #endif -#include -#include -#include #include -#include #include /* float32_t, float64_t */ +#include +#include +#include +#include /* Stack configuration override default values. For more information see file CO_config.h. */ @@ -60,6 +60,9 @@ extern "C" { #define CO_SWAP_64(x) sys_cpu_to_be64(x) #endif +#define CO_alloc(num, size) k_calloc((num), (size)) +#define CO_free(ptr) k_free((ptr)) + /* NULL is defined in stddef.h */ /* true and false are defined in stdbool.h */ /* int8_t to uint64_t are defined in stdint.h */ @@ -121,9 +124,9 @@ typedef struct { size_t eepromAddr; // size_t len; - // entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); - // entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); - // entry->offset = 0; + // entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); + // entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); + // entry->offset = 0; // entry->storageModule, entry->addr, entry->eepromAddr, entry->len); } CO_storage_entry_t; diff --git a/zephyr/include/CO_storage_zephyr.h b/zephyr/include/CO_storage_zephyr.h index 4e7363b3..f5bec5cf 100644 --- a/zephyr/include/CO_storage_zephyr.h +++ b/zephyr/include/CO_storage_zephyr.h @@ -21,8 +21,6 @@ #include "storage/CO_storage.h" -#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN - #ifdef __cplusplus extern "C" { #endif @@ -42,33 +40,14 @@ extern "C" { * * @return CO_ReturnError_t CO_ERROR_NO on success, otherwise error code */ -CO_ReturnError_t CO_storageBlank_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, - OD_entry_t *OD_1010_StoreParameters, - OD_entry_t *OD_1011_RestoreDefaultParam, - CO_storage_entry_t *entries, uint8_t entriesCount, - uint32_t *storageInitError); - -/** - * @brief Optional auto-save processing function (not implemented in Zephyr backend) - * - * This is a stub function that can be implemented if needed for timed or conditional saving. - * - * @param storage Pointer to CO_storage object - * @param closeFiles Flag to indicate if files should be closed after processing - * - * @return uint32_t Bitmask of flags indicating modified entries (always 0 in this backend) - */ -static inline uint32_t CO_storageBlank_auto_process(CO_storage_t *storage, bool_t closeFiles) -{ - ARG_UNUSED(storage); - ARG_UNUSED(closeFiles); - return 0; -} +CO_ReturnError_t CO_storage_zephyr_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, + OD_entry_t *OD_1010_StoreParameters, + OD_entry_t *OD_1011_RestoreDefaultParam, + CO_storage_entry_t *entries, uint8_t entriesCount, + uint32_t *storageInitError); #ifdef __cplusplus } #endif -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ - #endif /* CO_STORAGE_ZEPHYR_H */ From 7c1646f28d53e670c7fb7a67dc8b65002927a844 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 13 Aug 2025 16:40:52 -0400 Subject: [PATCH 504/520] Refactors CANopenNode Zephyr integration Modernizes the CANopenNode Zephyr integration, replacing the worker-based scheduler with a dedicated real-time thread for SYNC/RPDO/TPDO processing. Consolidates configuration via Kconfig and devicetree, simplifying setup. Provides optional non-volatile storage (CiA 302-6) and integrates with Zephyr. Renames source files for clarity. --- zephyr/CMakeLists.txt | 9 +- zephyr/CO_canopen_zephyr.c | 353 ------------------ zephyr/{CO_driver.c => CO_zephyr_driver.c} | 98 ++--- zephyr/CO_zephyr_integration.c | 287 ++++++++++++++ zephyr/{CO_LEDs_zephyr.c => CO_zephyr_leds.c} | 14 +- ...O_storage_zephyr.c => CO_zephyr_storage.c} | 32 +- zephyr/Kconfig | 193 +++++----- zephyr/include/CO_canopen_zephyr.h | 83 ---- zephyr/include/CO_driver_target.h | 31 +- ...{CO_config_zephyr.h => CO_zephyr_config.h} | 72 ++-- zephyr/include/CO_zephyr_integration.h | 67 ++++ .../{CO_LEDs_zephyr.h => CO_zephyr_leds.h} | 11 +- ...O_storage_zephyr.h => CO_zephyr_storage.h} | 24 +- 13 files changed, 609 insertions(+), 665 deletions(-) delete mode 100644 zephyr/CO_canopen_zephyr.c rename zephyr/{CO_driver.c => CO_zephyr_driver.c} (84%) create mode 100644 zephyr/CO_zephyr_integration.c rename zephyr/{CO_LEDs_zephyr.c => CO_zephyr_leds.c} (85%) rename zephyr/{CO_storage_zephyr.c => CO_zephyr_storage.c} (67%) delete mode 100644 zephyr/include/CO_canopen_zephyr.h rename zephyr/include/{CO_config_zephyr.h => CO_zephyr_config.h} (82%) create mode 100644 zephyr/include/CO_zephyr_integration.h rename zephyr/include/{CO_LEDs_zephyr.h => CO_zephyr_leds.h} (74%) rename zephyr/include/{CO_storage_zephyr.h => CO_zephyr_storage.h} (65%) diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 7ebab48b..bc243311 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -18,7 +18,8 @@ zephyr_include_directories( # ---- Always-built Zephyr port sources ---- zephyr_library_sources( - "${CANOPENNODE_DIR}/zephyr/CO_driver.c" + "${CANOPENNODE_DIR}/zephyr/CO_zephyr_integration.c" + "${CANOPENNODE_DIR}/zephyr/CO_zephyr_driver.c" ) # ---- Object Dictionary generation (EDS -> OD.c/.h) ---- @@ -143,7 +144,7 @@ endif() # LEDs (CiA 303-3) if(CONFIG_CANOPENNODE_LEDS_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/303/CO_LEDs.c") - zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_LEDs_zephyr.c") + zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_zephyr_leds.c") endif() # GFC / SRDO (CiA 304) @@ -178,10 +179,10 @@ if(CONFIG_CANOPENNODE_STORAGE_ENABLE) zephyr_library_sources( "${CANOPENNODE_DIR}/storage/CO_storage.c" "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c" - "${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c" + "${CANOPENNODE_DIR}/zephyr/CO_zephyr_storage.c" ) elseif(CONFIG_CANOPENNODE_STORAGE_BACKEND_RAM) - zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_storage_zephyr.c") + zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_zephyr_storage.c") elseif(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE) add_compile_definitions(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE=1) endif() diff --git a/zephyr/CO_canopen_zephyr.c b/zephyr/CO_canopen_zephyr.c deleted file mode 100644 index bfeed63a..00000000 --- a/zephyr/CO_canopen_zephyr.c +++ /dev/null @@ -1,353 +0,0 @@ -#include "CO_canopen_zephyr.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "OD.h" - -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) -#include "CO_storage_zephyr.h" -#endif - -LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); - -/* ---------- Kconfig-backed defaults ---------- */ -#ifndef CONFIG_COZ_PERIOD_MIN_US -#define CONFIG_COZ_PERIOD_MIN_US 500 -#endif -#ifndef CONFIG_COZ_PERIOD_MAX_US -#define CONFIG_COZ_PERIOD_MAX_US 5000 -#endif -#ifndef CONFIG_COZ_NODE_ID -#define CONFIG_COZ_NODE_ID 1 -#endif -#ifndef CONFIG_COZ_BITRATE_KBPS -#define CONFIG_COZ_BITRATE_KBPS 1000 -#endif -#ifndef CONFIG_COZ_RT_THREAD_STACK_SIZE -#define CONFIG_COZ_RT_THREAD_STACK_SIZE 1024 -#endif -#ifndef CONFIG_COZ_RT_THREAD_PRIORITY -#define CONFIG_COZ_RT_THREAD_PRIORITY 5 -#endif -#ifndef CONFIG_COZ_RT_IDLE_MS -#define CONFIG_COZ_RT_IDLE_MS 2 -#endif - -/* Prefer CANopen-specific chosen; fallback to generic if present */ -#if DT_HAS_CHOSEN(zephyr_co_can) -#define COZ_CAN_NODE DT_CHOSEN(zephyr_co_can) -#elif DT_HAS_CHOSEN(zephyr_canbus) -#define COZ_CAN_NODE DT_CHOSEN(zephyr_canbus) -#endif - -/* ---------- Module state ---------- */ - -static CO_t *CO = NULL; /* CANopen object */ -static CO_storage_t *CO_storage = NULL; /* Storage object */ - -static atomic_t g_running; - -static struct k_work_delayable g_work; - -/* RT thread wake signal (ISR-safe) */ -static K_SEM_DEFINE(rt_sem, 0, UINT_MAX); - -/* ---------- Helpers ---------- */ -static void rt_signal_cb(void *object) -{ - ARG_UNUSED(object); - - if (!atomic_get(&g_running)) { - return; - } - - /* ISR-safe in Zephyr */ - k_sem_give(&rt_sem); -} - -static void enable_pre_signals(CO_t *co, void (*pre_cb)(void *object), void *pre_arg) -{ - CO_SYNC_initCallbackPre(co->SYNC, pre_cb, pre_arg); - - for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { - CO_RPDO_initCallbackPre(co->RPDO[i], pre_cb, pre_arg); - } -} - -/* ---------- Worker: CO_process() cadence ---------- */ -static void canopen_work_handler(struct k_work *work) -{ - ARG_UNUSED(work); - if (!atomic_get(&g_running) || g_co == NULL) { - return; - } - - /* elapsed time (ms->us is fine for CO_process cadence) */ - static int64_t last_ms; - int64_t now_ms = k_uptime_get(); - uint32_t dt_us = (last_ms == 0) ? CONFIG_COZ_PERIOD_MIN_US - : (uint32_t)MAX(now_ms - last_ms, 0) * 1000U; - last_ms = now_ms; - -#if IS_ENABLED(CONFIG_CANOPENNODE_GLOBAL_FLAG_TIMERNEXT) - uint32_t next_us = UINT32_MAX; - (void)CO_process(g_co, false, dt_us, &next_us); - uint32_t delay_us = (next_us == UINT32_MAX) ? CONFIG_COZ_PERIOD_MIN_US : next_us; -#else - (void)CO_process(g_co, false, dt_us, NULL); - uint32_t delay_us = CONFIG_COZ_PERIOD_MIN_US; -#endif - - delay_us = CLAMP(delay_us, CONFIG_COZ_PERIOD_MIN_US, CONFIG_COZ_PERIOD_MAX_US); - (void)k_work_reschedule(&g_work, K_USEC(delay_us)); -} - -/* ---------- RT thread: event-driven SYNC/RPDO/TPDO ---------- */ -static void canopen_rt_thread(void *p1, void *p2, void *p3) -{ - ARG_UNUSED(p1); - ARG_UNUSED(p2); - ARG_UNUSED(p3); - - uint32_t prev = k_cycle_get_32(); - - for (;;) { - /* Wake on PRE-callback or idle timeout to service TPDO timers */ - (void)k_sem_take(&rt_sem, K_MSEC(CONFIG_COZ_RT_IDLE_MS)); - - if (!atomic_get(&g_running) || CO == NULL) { - continue; - } - - bool_t sync = false; - uint32_t now = k_cycle_get_32(); - uint32_t delta = now - prev; /* wraps fine for uint32_t */ - prev = now; - - uint32_t dt_us = (uint32_t)(k_cyc_to_ns_floor64(delta) / 1000U); - - CO_LOCK_OD(); -#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) - sync = CO_process_SYNC(CO, dt_us); -#endif -#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) - CO_process_RPDO(CO, sync); -#endif -#if IS_ENABLED(CONFIG_CANOPENNODE_TPDO_ENABLE) - CO_process_TPDO(CO, sync, dt_us); -#endif - CO_UNLOCK_OD(); - } -} - -/* Higher priority than system workqueue to minimize SYNC latency */ -K_THREAD_DEFINE(canopen_rt, CONFIG_COZ_RT_THREAD_STACK_SIZE, canopen_rt_thread, NULL, NULL, NULL, - CONFIG_COZ_RT_THREAD_PRIORITY, 0, 0); - -/* ---------- Public API ---------- */ -int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) -{ - if (atomic_get(&g_running)) { - return -EALREADY; - } - if (!can_dev || !device_is_ready(can_dev)) { - return -ENODEV; - } - if (node_id == 0 || node_id > 127) { - return -EINVAL; - } - - if (CO != NULL) { - CO_delete(CO); - CO = NULL; - } - - uint32_t heapMemoryUsed; - CO = CO_new(NULL, &heapMemoryUsed); - if (CO == NULL) { - LOG_ERR("Can't allocate memory for CANopen objects"); - return -ENOMEM; - } else { - LOG_INF("Allocated %u bytes for CANopen objects\n", heapMemoryUsed); - } - - CO_ReturnError_t err = 0; - int32_t ret = 0; - -/* Initialize storage module */ -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) - CO_storage_entry_t storageEntries[] = {{.addr = &OD_PERSIST_COMM, - .len = sizeof(OD_PERSIST_COMM), - .subIndexOD = 2, - .attr = CO_storage_cmd | CO_storage_restore, - .addrNV = NULL}}; - uint8_t storageEntriesCount = sizeof(storageEntries) / sizeof(storageEntries[0]); - uint32_t storageInitError = 0; - - err = CO_storage_zephyr_init(CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, - OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, - storageEntriesCount, &storageInitError); - if (err != CO_ERROR_NO) { - LOG_ERR("Storage module initialization failed: %d", err); - ret = -ENOMEM; - goto error; - } - if (storageInitError != 0) { - LOG_ERR("Storage module initialization error: 0x%X", storageInitError); - ret = -EIO; - goto error; - } -#endif - /* Initialzie CANopen */ - err = CO_CANinit(CO, can_dev, bitrate_kbps); - if (err != CO_ERROR_NO) { - LOG_ERR("CAN initialization failed: %d", err); - ret = -EINVAL; - goto error; - } - -/* Initialzie LSS */ -#if IS_ENABLED(CONFIG_CANOPENNODE_LSS_SLAVE) - CO_LSS_address_t lssAddress = { - .identity = {.vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, - .productCode = OD_PERSIST_COMM.x1018_identity.productCode, - .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, - .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber}}; - err = CO_LSSinit(CO, &lssAddress, &node_id, &bitrate_kbps); - if (err != CO_ERROR_NO) { - LOG_ERR("LSS slave initialization failed: %d", err); - ret = -EINVAL; - goto error; - } -#endif - uint32_t errInfo = 0; - - err = CO_CANopenInit(CO, /* CANopen object */ - NULL, /* alternate NMT */ - NULL, /* alternate em */ - OD, /* Object dictionary */ - NULL, /* Optional OD_statusBits */ - CO_CONFIG_NMT, /* CO_NMT_control_t */ - CO_NMT_FIRST_HB_TIME_MS, /* firstHBTime_ms */ - CO_CONFIG_SDO_SRV_TIMEOUT_MS, /* SDOserverTimeoutTime_ms */ - CO_CONFIG_SDO_CLI_TIMEOUT_MS, /* SDOclientTimeoutTime_ms */ - CO_CONFIG_SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ - node_id, &errInfo); - if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - if (err == CO_ERROR_OD_PARAMETERS) { - LOG_ERR("Object Dictionary entry 0x%X", errInfo); - ret = -EINVAL; - } else { - LOG_ERR("CANopen initialization failed: %d", err); - ret = -EIO - } - goto error; - } - - err = CO_CANopenInitPDO(CO, CO->em, OD, node_id, &errInfo); - if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - if (err == CO_ERROR_OD_PARAMETERS) { - LOG_ERR("Object Dictionary entry 0x%X", errInfo); - ret = -EINVAL; - } else { - LOG_ERR("PDO initialization failed: %d", err); - ret = -EIO; - } - goto error; - } - - if (!CO->nodeIdUnconfigured) { -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) - if (storageInitError != 0) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, - storageInitError); - } -#endif - } else { - LOG_INF("CANopenNode - Node-id not initialized"); - } - - /* Enable PRE-callbacks so RT thread wakes on SYNC/RPDO */ - enable_pre_signals(CO, rt_signal_cb, NULL); - - k_work_init_delayable(&g_work, canopen_work_handler); - atomic_set(&g_running, 1); - (void)k_work_schedule(&g_work, K_NO_WAIT); - - CO_CANsetNormalMode(CO->CANmodule); - LOG_INF("CANopenNode - Running..."); - - return 0; - -error: - if (CO != NULL) { - CO_delete(CO); - CO = NULL; - } - return ret; -} - -void co_canopen_stop(void) -{ - if (!atomic_get(&g_running)) { - return; - } - atomic_set(&g_running, 0); - - (void)k_work_cancel_delayable(&g_work); - - CO_CANmodule_disable(CO->CANmodule); - CO_delete(CO); - CO = NULL; - - LOG_ING("CANopenNode - Stopped"); -} - -bool co_canopen_is_running(void) -{ - return atomic_get(&g_running); -} -/* Resolve CAN device (DT chosen or Kconfig fallback) and start */ -int co_canopen_start_auto(void) -{ - const struct device *can_dev = NULL; - -#ifdef COZ_CAN_NODE - can_dev = DEVICE_DT_GET(COZ_CAN_NODE); - if (!device_is_ready(can_dev)) { - return -ENODEV; - } -#elif defined(CONFIG_COZ_CAN_DEV_NAME) - if (CONFIG_COZ_CAN_DEV_NAME[0] != '\0') { - can_dev = device_get_binding(CONFIG_COZ_CAN_DEV_NAME); - if (!can_dev || !device_is_ready(can_dev)) { - return -ENODEV; - } - } else { - return -ENODEV; - } -#else - return -ENODEV; -#endif - - return co_canopen_start(can_dev, CONFIG_COZ_NODE_ID, CONFIG_COZ_BITRATE_KBPS); -} - -/* Auto-start at POST_KERNEL if enabled */ -static int co_canopen_init_sys(const struct device *unused) -{ - ARG_UNUSED(unused); - -#if IS_ENABLED(CONFIG_COZ_AUTO_START) - (void)co_canopen_start_auto(); -#endif - return 0; -} -SYS_INIT(co_canopen_init_sys, POST_KERNEL, CONFIG_COZ_SYSINIT_PRIO); diff --git a/zephyr/CO_driver.c b/zephyr/CO_zephyr_driver.c similarity index 84% rename from zephyr/CO_driver.c rename to zephyr/CO_zephyr_driver.c index 22e71a8c..aaf69422 100644 --- a/zephyr/CO_driver.c +++ b/zephyr/CO_zephyr_driver.c @@ -1,12 +1,17 @@ +/* SPDX-License-Identifier: Apache-2.0 */ /* - * CAN module object for generic microcontroller. + * Zephyr CAN backend for CANopenNode driver (CO_driver). * - * This file is a template for other microcontrollers. + * Zephyr-specific implementation that adapts CANopenNode’s generic CAN + * driver to the Zephyr CAN API. It configures bitrate/mode, installs RX + * filters, handles TX queueing and completion callbacks, and propagates + * bus/error status into CO_CANmodule for the CANopen stack. * - * @file CO_driver.c - * @ingroup CO_driver - * @author Janez Paternoster + * @file CO_zephyr_driver.c + * @author Janez Paternoster (original template) + * @author BitConcepts, LLC * @copyright 2004 - 2020 Janez Paternoster + * @copyright 2025 BitConcepts, LLC * * This file is part of , a CANopen Stack. * @@ -23,6 +28,7 @@ #include "301/CO_driver.h" +#include #include #include #include @@ -143,11 +149,13 @@ static void canopen_tx_callback(const struct device *dev, int error, void *arg) ARG_UNUSED(dev); if (!CANmodule) { - LOG_ERR("failed to process CAN tx callback"); + LOG_ERR("tx callback arg invalid"); return; } - if (error == 0) { + if (error != 0) { + LOG_WRN("tx callback error (err %d)", error); + } else { CANmodule->firstCANtxMessage = false; } @@ -179,9 +187,10 @@ static void canopen_tx_retry(struct k_work *item) err = can_send(dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); if (err == -EAGAIN) { + LOG_DBG("tx busy, will retry"); break; } else if (err != 0) { - LOG_ERR("failed to send CAN frame (err %d)", err); + LOG_ERR("tx send failed (err %d)", err); } buffer->bufferFull = false; @@ -198,11 +207,9 @@ void CO_CANsetConfigurationMode(void *CANptr) } const struct device *dev = CANPTR_TO_DEV(CANptr); - int err; - - err = can_stop(dev); + int err = can_stop(dev); if (err != 0 && err != -EALREADY) { - LOG_ERR("failed to stop CAN interface (err %d)", err); + LOG_ERR("can stop failed (err %d)", err); } } @@ -213,11 +220,9 @@ void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule) } const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); - int err; - - err = can_start(dev); + int err = can_start(dev); if (err != 0 && err != -EALREADY) { - LOG_ERR("failed to start CAN interface (err %d)", err); + LOG_ERR("can start failed (err %d)", err); return; } @@ -233,30 +238,26 @@ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, void *CANptr, CO_C int err; int max_filters; - LOG_DBG("rxSize = %d, txSize = %d", rxSize, txSize); + LOG_DBG("init: rx_size=%u tx_size=%u", rxSize, txSize); /* verify arguments */ if (CANmodule == NULL || CANptr == NULL || rxArray == NULL || txArray == NULL) { - LOG_ERR("failed to initialize CAN module"); + LOG_ERR("init failed: invalid args"); return CO_ERROR_ILLEGAL_ARGUMENT; } max_filters = can_get_max_filters(dev, false); if (max_filters != -ENOSYS) { if (max_filters < 0) { - LOG_ERR("unable to determine number of CAN RX filters"); + LOG_ERR("rx filter count query failed (err %d)", max_filters); return CO_ERROR_SYSCALL; } if (rxSize > max_filters) { - LOG_ERR("insufficient number of concurrent CAN RX filters" - " (needs %d, %d available)", - rxSize, max_filters); + LOG_ERR("rx filters insufficient: need=%u avail=%d", rxSize, max_filters); return CO_ERROR_OUT_OF_MEMORY; } else if (rxSize < max_filters) { - LOG_DBG("excessive number of concurrent CAN RX filters enabled" - " (needs %d, %d available)", - rxSize, max_filters); + LOG_DBG("rx filters: need=%u avail=%d", rxSize, max_filters); } } @@ -276,31 +277,29 @@ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, void *CANptr, CO_C CANmodule->errOld = 0U; if (CANmodule->useCANrxFilters) { - /* CAN module filters are used, they will be configured with */ - /* CO_CANrxBufferInit() functions, called by separate CANopen */ - /* init functions. */ + /* Filters will be configured by CO_CANrxBufferInit() */ for (i = 0U; i < rxSize; i++) { rxArray[i].ident = 0U; rxArray[i].CANrx_callback = NULL; rxArray[i].filter_id = -ENOSPC; } } else { - /* CAN module filters are not used, all messages with standard 11-bit */ - /* identifier will be received */ + /* If filters aren't used, all 11-bit IDs will be received */ } + for (i = 0U; i < txSize; i++) { txArray[i].bufferFull = false; } err = can_set_bitrate(dev, KHZ(CANbitRate)); if (err) { - LOG_ERR("failed to configure CAN bitrate (err %d)", err); + LOG_ERR("bitrate set failed (err %d)", err); return CO_ERROR_ILLEGAL_ARGUMENT; } err = can_set_mode(dev, CAN_MODE_NORMAL); if (err) { - LOG_ERR("failed to configure CAN interface (err %d)", err); + LOG_ERR("mode set failed (err %d)", err); return CO_ERROR_ILLEGAL_ARGUMENT; } @@ -309,8 +308,6 @@ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, void *CANptr, CO_C void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) { - int err; - if (!CANmodule || !CANmodule->CANptr) { return; } @@ -319,9 +316,9 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) canopen_detach_all_rx_filters(CANmodule); - err = can_stop(dev); + int err = can_stop(dev); if (err != 0 && err != -EALREADY) { - LOG_ERR("failed to disable CAN interface (err %d)", err); + LOG_ERR("can stop failed (err %d)", err); } } @@ -334,30 +331,31 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, u if ((CANmodule != NULL) && (CANmodule->CANptr != NULL) && (object != NULL) && (CANrx_callback != NULL) && (index < CANmodule->rxSize)) { - /* buffer, which will be configured */ + + /* Buffer to configure */ CO_CANrx_t *buffer = &CANmodule->rxArray[index]; const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); + /* Configure object variables */ buffer->object = object; buffer->CANrx_callback = CANrx_callback; - /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different - * microcontrollers. */ + /* CAN identifier and mask, bit-aligned with CAN module */ buffer->ident = ident & CAN_STD_ID_MASK; buffer->mask = (mask & CAN_STD_ID_MASK) | 0x0800U; #ifndef CONFIG_CAN_ACCEPT_RTR if (rtr) { - LOG_ERR("request for RTR frames, but RTR frames are rejected"); + LOG_WRN("rtr requested but disabled"); return CO_ERROR_ILLEGAL_ARGUMENT; } -#else /* !CONFIG_CAN_ACCEPT_RTR */ +#else /* CONFIG_CAN_ACCEPT_RTR */ if (rtr) { buffer->ident |= 0x0800U; } #endif /* CONFIG_CAN_ACCEPT_RTR */ - /* Set CAN hardware module filter and mask. */ + /* Set CAN hardware module filter and mask */ if (CANmodule->useCANrxFilters) { filter.flags = 0U; filter.id = ident; @@ -369,11 +367,12 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, u buffer->filter_id = can_add_rx_filter(dev, canopen_rx_callback, CANmodule, &filter); if (buffer->filter_id == -ENOSPC) { - LOG_ERR("failed to add CAN rx callback, no free filter"); + LOG_ERR("rx filter add failed: no slots"); ret = CO_ERROR_OUT_OF_MEMORY; } } } else { + LOG_ERR("rx buffer init failed: invalid args"); ret = CO_ERROR_ILLEGAL_ARGUMENT; } @@ -386,11 +385,10 @@ CO_CANtx_t *CO_CANtxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, uint16 CO_CANtx_t *buffer = NULL; if ((CANmodule != NULL) && (index < CANmodule->txSize)) { - /* get specific buffer */ + /* specific buffer */ buffer = &CANmodule->txArray[index]; - /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer, - * microcontroller specific. */ + /* CAN identifier, DLC, and RTR packed per CANopenNode template */ buffer->ident = ((uint32_t)ident & CAN_STD_ID_MASK) | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) | ((uint32_t)(rtr ? 0x800U : 0U)); @@ -408,13 +406,15 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) struct can_frame frame; if (!CANmodule || !CANmodule->CANptr || !buffer) { + LOG_ERR("tx send failed: invalid args"); return CO_ERROR_ILLEGAL_ARGUMENT; } const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); memset(&frame, 0, sizeof(frame)); - frame.id = buffer->ident; + frame.id = buffer->ident; /* note: template packs DLC/RTR into ident; driver extracts flags + below */ frame.dlc = buffer->DLC; frame.flags = ((buffer->ident & 0x800) ? CAN_FRAME_RTR : 0); memcpy(frame.data, buffer->data, buffer->DLC); @@ -423,11 +423,11 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) err = can_send(dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); if (err == -EAGAIN) { - LOG_ERR("failed to send CAN frame, tx overflow"); + LOG_ERR("tx overflow"); err = CO_ERROR_TX_OVERFLOW; buffer->bufferFull = true; } else if (err != 0) { - LOG_ERR("failed to send CAN frame (err %d)", err); + LOG_ERR("tx send failed (err %d)", err); err = CO_ERROR_TX_UNCONFIGURED; } diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c new file mode 100644 index 00000000..5d048507 --- /dev/null +++ b/zephyr/CO_zephyr_integration.c @@ -0,0 +1,287 @@ +/** + * @file CO_canopen_zephyr.c + * @brief Zephyr integration layer for CANopenNode + * + * This file integrates CANopenNode with the Zephyr RTOS. It provides: + * - RT thread for SYNC/RPDO/TPDO via PRE-callbacks + * - Worker-based scheduling for CO_process() + * - Support for devicetree and Kconfig-based configuration + * - Optional non-volatile parameter storage (CiA 302-6) + * + * @authors + * Janez Paternoster + * BitConcepts + * + * @copyright + * CANopenNode is licensed under the Apache License, Version 2.0. + * Modifications Copyright (c) 2025 BitConcepts, LLC. + */ + +#include "CO_zephyr_integration.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "OD.h" + +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) +#include "CO_storage_zephyr.h" +#endif + +LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); + +#define CAN_NODE DT_CHOSEN(zephyr_canbus) +#define CAN_BITRATE_KBPS (DT_PROP(CAN_NODE, bitrate) / 1000U) + +/* ---------- Module state ---------- */ + +static CO_t *CO = NULL; +static CO_storage_t *CO_storage = NULL; +static atomic_t g_running; + +K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ + +/* ---------- Helpers ---------- */ + +static void rt_signal_cb(void *object) +{ + ARG_UNUSED(object); + if (atomic_get(&g_running)) { + k_sem_give(&rt_sem); + } +} + +static void enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) +{ + CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); + for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { + CO_RPDO_initCallbackPre(co->RPDO[i], pre_cb, arg); + } +} + +/* ---------- RT Thread: SYNC/RPDO/TPDO ---------- */ +#if IS_ENABLED(CANOPENNODE_RT_THREAD) +static void canopen_rt_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + int64_t last_ms = 0; + uint32_t prev_cyc = k_cycle_get_32(); + const uint32_t fallback_us = 1000U; + uint32_t timeout_us = fallback_us; + + while (true) { + k_sem_take(&rt_sem, K_USEC(timeout_us)); + + if (!atomic_get(&g_running) || CO == NULL) { + continue; + } + + /* Mainline: CO_process() */ + int64_t now_ms = k_uptime_get(); + uint32_t dt_us = + (last_ms == 0) ? fallback_us : (uint32_t)MAX(now_ms - last_ms, 0) * 1000U; + last_ms = now_ms; + +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) + uint32_t next_us = UINT32_MAX; + (void)CO_process(CO, false, dt_us, &next_us); + timeout_us = (next_us == 0U || next_us == UINT32_MAX) ? fallback_us : next_us; +#else + (void)CO_process(CO, false, dt_us, NULL); + timeout_us = fallback_us; +#endif + + /* RT part: SYNC, RPDO, TPDO */ + uint32_t now_cyc = k_cycle_get_32(); + uint32_t delta_cyc = now_cyc - prev_cyc; + prev_cyc = now_cyc; + + uint32_t dt_rt_us = (uint32_t)(k_cyc_to_ns_floor64(delta_cyc) / 1000U); + + CO_LOCK_OD(); +#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) + bool_t sync = CO_process_SYNC(CO, dt_rt_us); +#else + bool_t sync = false; +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) + CO_process_RPDO(CO, sync); +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_TPDO_ENABLE) + CO_process_TPDO(CO, sync, dt_rt_us); +#endif + CO_UNLOCK_OD(); + } +} + +K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, canopen_rt_thread, NULL, NULL, + NULL, CONFIG_CANOPENNODE_RT_THREAD_PRIORITY, 0, 0); + +#endif /* IS_ENABLED(CANOPENNODE_RT_THREAD) */ + +/* ---------- Public API ---------- */ + +int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) +{ + if (atomic_get(&g_running)) { + return -EALREADY; + } + if (!can_dev) { + can_dev = DEVICE_DT_GET(CAN_NODE); + } + if (!can_dev || !device_is_ready(can_dev)) { + return -ENODEV; + } + if (node_id == 0 || node_id > 127) { + return -EINVAL; + } + if (bitrate_kbps == 0) { + bitrate_kbps = CONFIG_CANOPENNODE_BITRATE_KBPS; + } + + if (CO != NULL) { + CO_delete(CO); + CO = NULL; + } + + uint32_t heap_used = 0; + CO = CO_new(NULL, &heap_used); + if (CO == NULL) { + LOG_ERR("[%s] Memory allocation failed", __func__); + return -ENOMEM; + } + LOG_INF("[%s] Allocated %u bytes for CANopen", __func__, heap_used); + + int ret = 0; + CO_ReturnError_t err; + uint32_t errInfo = 0; + +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) + CO_storage_entry_t storageEntries[] = {{.addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), + .subIndexOD = 2, + .attr = CO_storage_cmd | CO_storage_restore, + .addrNV = NULL}}; + uint8_t entryCount = ARRAY_SIZE(storageEntries); + uint32_t storageErr = 0; + + err = CO_zephyr_storage_init(CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, + OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, + entryCount, &storageErr); + + if (err != CO_ERROR_NO) { + LOG_ERR("[%s] Storage init failed: %d", __func__, err); + ret = -ENOMEM; + goto error; + } + if (storageErr != 0) { + LOG_ERR("[%s] Storage error: 0x%X", __func__, storageErr); + ret = -EIO; + goto error; + } +#endif + + err = CO_CANinit(CO, can_dev, bitrate_kbps); + if (err != CO_ERROR_NO) { + LOG_ERR("[%s] CAN init failed: %d", __func__, err); + ret = -EINVAL; + goto error; + } + +#if IS_ENABLED(CONFIG_CANOPENNODE_LSS_SLAVE) + CO_LSS_address_t lssAddr = { + .identity = {.vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, + .productCode = OD_PERSIST_COMM.x1018_identity.productCode, + .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, + .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber}}; + err = CO_LSSinit(CO, &lssAddr, &node_id, &bitrate_kbps); + if (err != CO_ERROR_NO) { + LOG_ERR("[%s] LSS init failed: %d", __func__, err); + ret = -EINVAL; + goto error; + } +#endif + + err = CO_CANopenInit(CO, NULL, NULL, OD, NULL, CO_CONFIG_NMT_CONTROL, + CO_NMT_FIRST_HB_TIME_MS, CO_CONFIG_SDO_SRV_TIMEOUT_MS, + CO_CONFIG_SDO_CLI_TIMEOUT_MS, CO_CONFIG_SDO_CLI_BLOCK, node_id, + &errInfo); + + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + LOG_ERR("[%s] CANopen init failed: %d (OD entry 0x%X)", __func__, err, errInfo); + ret = -EIO; + goto error; + } + + err = CO_CANopenInitPDO(CO, CO->em, OD, node_id, &errInfo); + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + LOG_ERR("[%s] PDO init failed: %d (OD entry 0x%X)", __func__, err, errInfo); + ret = -EIO; + goto error; + } + + if (!CO->nodeIdUnconfigured) { +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) + if (storageErr != 0) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, + storageErr); + } +#endif + } else { + LOG_INF("[%s] Node-ID not configured (LSS active)", __func__); + } + + enable_pre_signals(CO, rt_signal_cb, NULL); + atomic_set(&g_running, 1); + CO_CANsetNormalMode(CO->CANmodule); + + LOG_INF("[%s] CANopenNode running", __func__); + return 0; + +error: + if (CO) { + CO_delete(CO); + CO = NULL; + } + return ret; +} + +void co_canopen_stop(void) +{ + if (!atomic_get(&g_running)) { + return; + } + + atomic_clear(&g_running); + + if (CO != NULL) { + CO_CANmodule_disable(CO->CANmodule); + CO_delete(CO); + CO = NULL; + LOG_INF("[%s] CANopenNode stopped", __func__); + } +} + +bool co_canopen_is_running(void) +{ + return atomic_get(&g_running); +} + +static int co_canopen_init_sys(const struct device *unused) +{ + ARG_UNUSED(unused); +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) + (void)co_canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, CAN_BITRATE_KBPS); +#endif + return 0; +} +SYS_INIT(co_canopen_init_sys, POST_KERNEL, CONFIG_CANOPENNODE_INIT_PRIORITY); diff --git a/zephyr/CO_LEDs_zephyr.c b/zephyr/CO_zephyr_leds.c similarity index 85% rename from zephyr/CO_LEDs_zephyr.c rename to zephyr/CO_zephyr_leds.c index d30c0e76..a32e6a8d 100644 --- a/zephyr/CO_LEDs_zephyr.c +++ b/zephyr/CO_zephyr_leds.c @@ -1,4 +1,4 @@ -#include "co_leds_zephyr.h" +#include "CO_zephyr_leds.h" #include #include @@ -20,7 +20,7 @@ static const struct gpio_dt_spec LED_ERR = GPIO_DT_SPEC_GET(ERR_NODE, gpios); static bool hw_ready; /* Mirror the synthesized CANopen RUN/ERR bits to hardware */ -static void co_leds_cb(CO_LEDs_t *leds, void *user_arg) +static void co_zephyr_leds_cb(CO_LEDs_t *leds, void *user_arg) { ARG_UNUSED(user_arg); if (!hw_ready || leds == NULL) { @@ -36,7 +36,7 @@ static void co_leds_cb(CO_LEDs_t *leds, void *user_arg) (void)gpio_pin_set_dt(&LED_ERR, err_on); } -int co_leds_zephyr_init_dt_aliases(void) +int co_zephyr_leds_init_dt_aliases(void) { /* Validate ports */ if (!device_is_ready(LED_RUN.port) || !device_is_ready(LED_ERR.port)) { @@ -57,19 +57,19 @@ int co_leds_zephyr_init_dt_aliases(void) return 0; } -void co_leds_zephyr_connect_callback(CO_LEDs_t *leds) +void co_zephyr_leds_connect_callback(CO_LEDs_t *leds) { if (!leds) { return; } /* Requires your CO_CONFIG_LEDS_CALLBACK integration */ - CO_LEDs_registerCallback(leds, co_leds_cb, NULL); + CO_LEDs_registerCallback(leds, co_zephyr_leds_cb, NULL); /* Push current state to pins immediately (optional nicety) */ - co_leds_zephyr_sync_once(leds); + co_zephyr_leds_sync_once(leds); } -void co_leds_zephyr_sync_once(CO_LEDs_t *leds) +void co_zephyr_leds_sync_once(CO_LEDs_t *leds) { if (!hw_ready || !leds) { return; diff --git a/zephyr/CO_storage_zephyr.c b/zephyr/CO_zephyr_storage.c similarity index 67% rename from zephyr/CO_storage_zephyr.c rename to zephyr/CO_zephyr_storage.c index 28e8f21a..9b9a381e 100644 --- a/zephyr/CO_storage_zephyr.c +++ b/zephyr/CO_zephyr_storage.c @@ -1,4 +1,32 @@ -#include "CO_storage_zephyr.h" +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * CANopen Object Dictionary storage for Zephyr backends. + * + * Zephyr-backed implementation of the CANopenNode storage object that + * provides persistent parameter handling (load / store / restore) suitable + * for production systems. Integrates with Zephyr subsystems (e.g. Settings + * or NVS/flash), as selected by the application. + * + * @file CO_zephyr_storage.c + * @author Janez Paternoster (original template) + * @author BitConcepts, LLC + * @copyright 2021 Janez Paternoster + * @copyright 2025 BitConcepts, LLC + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "CO_zephyr_storage.h" #include #include @@ -63,7 +91,7 @@ static ODR_t restore_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule } /* Initialization */ -CO_ReturnError_t CO_storage_zephyr_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, +CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParam, CO_storage_entry_t *entries, uint8_t entriesCount, diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 6611c427..5b4a043b 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -16,7 +16,7 @@ menu "NMT / Heartbeat producer - Specified in standard CiA 301" config CANOPENNODE_NMT_CALLBACK_CHANGE bool "Enable custom callback after NMT state changes" - default n + default y help Enable a custom callback invoked after the NMT state changes. Configure via CO_NMT_initCallbackChanged(). @@ -37,7 +37,7 @@ config CANOPENNODE_NMT_CALLBACK config CANOPENNODE_NMT_TIMERNEXT bool "Enable NMT timerNext_us calculation" - default n + default y help Enable calculation of timerNext_us for NMT to schedule next processing. @@ -48,7 +48,7 @@ config CANOPENNODE_NMT_FIRST_HB_TIME_MS help Delay before the first Heartbeat after boot/reset. 0 = no extra delay (start HB with the normal 0x1017 period). - Typical values: 200–1000 ms to let peers install filters and avoid + Typical values: 200-1000 ms to let peers install filters and avoid false HB-consumer timeouts during bus bring-up. endmenu @@ -77,41 +77,7 @@ config CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL comment "Error register mask (low 8 bits of NMT control)" -config CANOPENNODE_NMT_ERR_REG_MASK - hex "Base error-register mask (hex, 0x00-0xFF)" - range 0x00 0xFF - default 0x00 - help - Low 8 bits of the NMT control are the error register mask. - Set bits here directly (hex), or enable the convenience flags below. - -config CANOPENNODE_NMT_ERR_MASK_GENERIC - bool "Include GENERIC error bit" - default y - -config CANOPENNODE_NMT_ERR_MASK_CURRENT - bool "Include CURRENT error bit" - default n - -config CANOPENNODE_NMT_ERR_MASK_VOLTAGE - bool "Include VOLTAGE error bit" - default n - -config CANOPENNODE_NMT_ERR_MASK_TEMPERATURE - bool "Include TEMPERATURE error bit" - default n - -config CANOPENNODE_NMT_ERR_MASK_COMM - bool "Include COMMUNICATION error bit" - default y -config CANOPENNODE_NMT_ERR_MASK_DEV_PROFILE - bool "Include DEVICE PROFILE error bit" - default n - -config CANOPENNODE_NMT_ERR_MASK_MANUFACTURER - bool "Include MANUFACTURER error bit" - default n endmenu @@ -119,7 +85,7 @@ menu "Heartbeat consumer - Specified in standard CiA 301" config CANOPENNODE_HB_CONS_ENABLE bool "Enable heartbeat consumer" - default n + default y help Monitor heartbeat messages from other nodes and trigger actions based on their status. @@ -128,9 +94,10 @@ choice CANOPENNODE_HB_CONS_CALLBACK_MODE prompt "Heartbeat consumer callback mode" depends on CANOPENNODE_HB_CONS_ENABLE optional + default CANOPENNODE_HB_CONS_CALLBACK_CHANGE help Select how heartbeat/NMT-change callbacks are handled. - Leave unset for no callbacks (default). Only one option can be active. + Leave unset for no callbacks. Only one option can be active. config CANOPENNODE_HB_CONS_CALLBACK_CHANGE bool "Single common callback after NMT state change" @@ -166,12 +133,12 @@ config CANOPENNODE_HB_CONS_CALLBACK config CANOPENNODE_HB_CONS_TIMERNEXT bool "Enable heartbeat consumer timerNext_us calculation" depends on CANOPENNODE_HB_CONS_ENABLE - default n + default y config CANOPENNODE_HB_CONS_OD_DYNAMIC bool "Enable dynamic behaviour of heartbeat consumer OD variables" depends on CANOPENNODE_HB_CONS_ENABLE - default n + default y endmenu @@ -189,7 +156,7 @@ config CANOPENNODE_NODE_GUARDING_MASTER_COUNT int "Max nodes monitored by guarding master" depends on CANOPENNODE_NODE_GUARDING_MASTER_ENABLE range 1 127 - default 1 + default 127 config CANOPENNODE_NODE_GUARDING_TIMERNEXT bool "Enable Node guarding timerNext_us calculation" @@ -202,7 +169,7 @@ menu "Emergency producer/consumer - Specified in standard CiA 301" config CANOPENNODE_EM_PRODUCER bool "Enable emergency producer" - default n + default y config CANOPENNODE_EM_PROD_CONFIGURABLE bool "Enable configurable COB-ID for emergency producer" @@ -214,7 +181,7 @@ config CANOPENNODE_EM_PROD_INHIBIT config CANOPENNODE_EM_HISTORY bool "Enable emergency error history" - default n + default y config CANOPENNODE_EM_CONSUMER bool "Enable emergency consumer" @@ -226,11 +193,11 @@ config CANOPENNODE_EM_STATUS_BITS config CANOPENNODE_EM_CALLBACK bool "Enable custom callback after emergency message received" - default n + default y config CANOPENNODE_EM_TIMERNEXT bool "Enable emergency timerNext_us calculation" - default n + default y config CANOPENNODE_EM_ERR_STATUS_BITS_COUNT int "Emergency error status bits (multiple of 8)" @@ -238,10 +205,6 @@ config CANOPENNODE_EM_ERR_STATUS_BITS_COUNT default 80 # Optional error-register conditions (enable default expressions in mapper) -config CANOPENNODE_ERR_CONDITION_GENERIC - bool "Condition for calculating Error register: GENERIC" - default y - config CANOPENNODE_ERR_CONDITION_CURRENT bool "Condition for calculating Error register: CURRENT" default n @@ -254,25 +217,17 @@ config CANOPENNODE_ERR_CONDITION_TEMPERATURE bool "Condition for calculating Error register: TEMPERATURE" default n -config CANOPENNODE_ERR_CONDITION_COMMUNICATION - bool "Condition for calculating Error register: COMMUNICATION" - default y - config CANOPENNODE_ERR_CONDITION_DEV_PROFILE bool "Condition for calculating Error register: DEVICE PROFILE" default n -config CANOPENNODE_ERR_CONDITION_MANUFACTURER - bool "Condition for calculating Error register: MANUFACTURER" - default y - endmenu menu "SDO server - Specified in standard CiA 301" config CANOPENNODE_SDO_SERVER_SEGMENTED bool "Enable segmented SDO server" - default n + default y config CANOPENNODE_SDO_SERVER_BLOCK bool "Enable block SDO server" @@ -285,17 +240,17 @@ config CANOPENNODE_SDO_SERVER_BLOCK config CANOPENNODE_SDO_SERVER_CALLBACK bool "Enable SDO server callback" depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK - default n + default y config CANOPENNODE_SDO_SERVER_TIMERNEXT bool "Enable SDO server timerNext_us calculation" depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK - default n + default y config CANOPENNODE_SDO_SERVER_OD_DYNAMIC bool "Enable dynamic behaviour of SDO server OD variables" depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK - default n + default y config CANOPENNODE_SDO_SERVER_BUFFER_SIZE int "SDO server buffer size" @@ -380,7 +335,7 @@ menu "Time producer/consumer - Specified in standard CiA 301" config CANOPENNODE_TIME_ENABLE bool "Enable TIME object and TIME consumer" - default n + default y config CANOPENNODE_TIME_PRODUCER bool "Enable TIME producer" @@ -390,12 +345,12 @@ config CANOPENNODE_TIME_PRODUCER config CANOPENNODE_TIME_CALLBACK bool "Enable TIME callback" depends on CANOPENNODE_TIME_ENABLE - default n + default y config CANOPENNODE_TIME_OD_DYNAMIC bool "Enable dynamic behaviour of TIME OD variables" depends on CANOPENNODE_TIME_ENABLE - default n + default y endmenu @@ -403,51 +358,51 @@ menu "SYNC and PDO producer/consumer - Specified in standard CiA 301" config CANOPENNODE_SYNC_ENABLE bool "Enable SYNC object and SYNC consumer" - default n + default y config CANOPENNODE_SYNC_PRODUCER bool "Enable SYNC producer" depends on CANOPENNODE_SYNC_ENABLE - default n + default y config CANOPENNODE_SYNC_CALLBACK bool "Enable SYNC callback" depends on CANOPENNODE_SYNC_ENABLE - default n + default y config CANOPENNODE_SYNC_TIMERNEXT bool "Enable SYNC timerNext_us calculation" depends on CANOPENNODE_SYNC_ENABLE - default n + default y config CANOPENNODE_SYNC_OD_DYNAMIC bool "Enable dynamic behaviour of SYNC OD variables" depends on CANOPENNODE_SYNC_ENABLE - default n + default y config CANOPENNODE_RPDO_ENABLE bool "Enable receive PDO objects (RPDOs)" - default n + default y config CANOPENNODE_TPDO_ENABLE bool "Enable transmit PDO objects (TPDOs)" - default n + default y config CANOPENNODE_RPDO_TIMERS_ENABLE bool "Enable RPDO timers" depends on CANOPENNODE_RPDO_ENABLE - default n + default y config CANOPENNODE_TPDO_TIMERS_ENABLE bool "Enable TPDO timers" depends on CANOPENNODE_TPDO_ENABLE - default n + default y config CANOPENNODE_PDO_SYNC_ENABLE bool "Enable PDO SYNC" depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE select CANOPENNODE_SYNC_ENABLE - default n + default y help Synchronize PDO processing with network SYNC messages. @@ -455,24 +410,24 @@ config CANOPENNODE_PDO_OD_IO_ACCESS bool "Enable PDO OD IO access" depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE select CANOPENNODE_PDO_OD_DYNAMIC - default n + default y help Use OD IO accessors (OD_IO_t) for mapped PDO variables. config CANOPENNODE_PDO_CALLBACK bool "Enable PDO callback" depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default n + default y config CANOPENNODE_PDO_TIMERNEXT bool "Enable PDO timerNext_us calculation" depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default n + default y config CANOPENNODE_PDO_OD_DYNAMIC bool "Enable dynamic behaviour of PDO OD variables" depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default n + default y endmenu @@ -480,7 +435,7 @@ menu "Data storage - Data storage with CANopen OD objects 1010 and 1011, CiA 301 config CANOPENNODE_STORAGE_ENABLE bool "Enable data storage" - default n + default y help Persist OD entries via 0x1010/0x1011. @@ -497,7 +452,7 @@ config CANOPENNODE_STORAGE_BACKEND_SETTINGS bool "Zephyr Settings subsystem" select SETTINGS help - Use Zephyr’s settings subsystem to persist OD entries. + Use Zephy's settings subsystem to persist OD entries. config CANOPENNODE_STORAGE_BACKEND_RAM bool "RAM-only (no persistence)" @@ -761,22 +716,78 @@ config CANOPENNODE_EDS_FILE_PATH endmenu -menu "CANopenNode TX Workqueue Options" +menu "CANopenNode Thread Options" -config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE - int "TX workqueue stack size" - range 256 16384 - default 1024 +config CANOPENNODE_RT_THREAD + bool "Use real-time thread for CANopen processing" + default y help - Stack size (bytes) for the CANopenNode TX workqueue thread. + If enabled, a dedicated real-time thread will be created for CANopen + processing. Otherwise, the application must call CO_process() periodically. -config CANOPENNODE_TX_WORKQUEUE_PRIORITY - int "TX workqueue priority" - default 0 +config CANOPENNODE_RT_THREAD_STACK_SIZE + int "Real-time thread stack size" + default 1024 help - Thread priority for the CANopenNode TX workqueue. + Stack size (bytes) for the CANopenNode real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. + Increase if you use many PDOs, SDOs, or large OD entries. + Decrease if you have memory constraints and use few CANopen features. + Typical values: 1024-4096 bytes. + Measure actual stack usage to optimize. + +config CANOPENNODE_RT_THREAD_PRIORITY + int "Real-time thread priority" + default -1 + help + Thread priority for the CANopenNode real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. Lower numbers mean higher priority. + Typical values: -1 to -3 for real-time processing. + +config CANOPENNODE_RT_THREAD_IDLE_MS + int "Real-time thread idle time (ms)" + default 10 + help + Time (ms) the CANopenNode real-time thread sleeps when idle. + Only used if CANOPENNODE_RT_THREAD is enabled. + Lower values mean more CPU usage but lower latency. + Typical values: 1-100 ms. +config CANOPENNODE_RT_THREAD_TIMERNEXT + bool "Enable timerNext_us calculation in real-time thread" + default y + help + If enabled, timerNext_us will be calculated in the real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. + Disable to save CPU if you don't use features that need timerNext_us. + +config CANOPENNODE_RT_THREAD_AUTO_START + bool "Auto-start CANopenNode real-time thread" + default y + help + If enabled, the CANopenNode real-time thread will be started automatically + at POST_KERNEL. Otherwise, you must call CO_RT_threadStart() manually. +endmenu + +menu "CANopenNode Initialization" + +config CANOPENNODE_INIT_PRIORITY + int "CANopenNode initialization priority" + default 90 + help + Priority for CANopenNode initialization. + Lower numbers mean earlier initialization. + Typical values: 80-100. + Must be lower than the application's main thread priority. + +config CANOPENNODE_INIT_NODE_ID + int "CANopenNode node ID" + default 1 + range 0 127 + help + Node ID for the CANopenNode instance. + Must be unique on the CAN bus. endmenu endif # CANOPENNODE diff --git a/zephyr/include/CO_canopen_zephyr.h b/zephyr/include/CO_canopen_zephyr.h deleted file mode 100644 index 30039c58..00000000 --- a/zephyr/include/CO_canopen_zephyr.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "CANopen.h" - -/** - * @file co_canopen_zephyr.h - * @brief Zephyr-owned CANopen scheduler: - * - Worker: runs CO_process() and reschedules (timerNext_us optional) - * - RT thread: event-driven SYNC/RPDO/TPDO via PRE-callbacks (Option B) - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* ---------- Core scheduler API ---------- */ - -/** Resolve CAN device (DT chosen or Kconfig) and start the worker. */ -int co_canopen_start_auto(void); - -/** Start with explicit CAN device and Node-ID. */ -int co_canopen_start(const struct device *can_dev, uint8_t node_id); - -/** Stop worker and tear down stack. */ -void co_canopen_stop(void); - -/** Get active CO_t pointer (or NULL). */ -CO_t *co_canopen_get(void); - -/** Is worker running? */ -bool co_canopen_is_running(void); - -/** Rebuild RX filters from the port-provided table (safe when running). */ -int co_canopen_refresh_filters(void); - -/* ---------- Port hooks (weak) you implement in your CANopenNode port ---------- */ -/** - * Allocate/init CANopenNode (CO), bind to @p can_dev, configure OD/COB-IDs, etc. - * Must set *out_co on success. - */ -int __weak coz_port_create(const struct device *can_dev, uint8_t node_id, CO_t **out_co); - -/** Teardown/free CANopenNode created by coz_port_create(). */ -void __weak coz_port_destroy(CO_t *co); - -/** - * Provide RX filter table for all COB-IDs the stack should receive. - * Return count (<= max_filters). Fill @p out (id/mask/flags). - */ -size_t __weak coz_port_get_filter_table(const CO_t *co, struct can_filter *out, size_t max_filters); - -/** - * Dispatch one received CAN frame into CANopenNode (ISR context). - * Keep this short & non-blocking; do heavy work in CO_process(). - */ -void __weak coz_port_rx_dispatch_isr(CO_t *co, const struct can_frame *frame); - -/** - * Enable PRE-callbacks for SYNC and RPDO so the RT thread wakes immediately. - * Typical implementation: - * CO_SYNC_initCallbackPre(CO->SYNC, pre_cb, pre_arg); - * for each RPDO: CO_RPDO_initCallbackPre(rpdo, pre_cb, pre_arg); - * - * Pass @p pre_cb = coz_rt_signal_cb and @p pre_arg = NULL (or anything). - */ -void __weak coz_port_enable_pre_signals(CO_t *co, void (*pre_cb)(void *object), void *pre_arg); - -/* ---------- Provided PRE-callback for ports to use ---------- */ -/** - * PRE-callback you can register in your port to wake the RT thread. - * Signature matches CANopenNode's *_initCallbackPre() expectations. - * Safe to call from ISR or thread context. - */ -void coz_rt_signal_cb(void *object); - -#ifdef __cplusplus -} -#endif diff --git a/zephyr/include/CO_driver_target.h b/zephyr/include/CO_driver_target.h index 0ba6ffc1..d57a7977 100644 --- a/zephyr/include/CO_driver_target.h +++ b/zephyr/include/CO_driver_target.h @@ -1,9 +1,17 @@ +/* SPDX-License-Identifier: Apache-2.0 */ /* - * Device and application specific definitions for CANopenNode. + * Zephyr target configuration for CANopenNode driver. + * + * Device- and application-specific definitions used by CANopenNode’s + * driver/porting layer on Zephyr. Provides target constants and macros + * (locking, timing, endian helpers, limits, etc.) tailored to the SoC/board + * and build configuration. * * @file CO_driver_target.h - * @author Janez Paternoster + * @author Janez Paternoster (original template) + * @author BitConcepts, LLC * @copyright 2021 Janez Paternoster + * @copyright 2025 BitConcepts, LLC * * This file is part of , a CANopen Stack. * @@ -18,21 +26,8 @@ * the License. */ -/* - * Copyright (c) 2019 Vestas Wind Systems A/S - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_H -#define ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_H - -/* - * Zephyr RTOS CAN driver interface and configuration for CANopenNode - * CANopen protocol stack. - * - * See CANopenNode/example/CO_driver_blank.h for API description. - */ +#ifndef ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_TARGET_H +#define ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_TARGET_H #ifdef __cplusplus extern "C" { @@ -168,4 +163,4 @@ void canopen_od_unlock(void); } #endif /* __cplusplus */ -#endif /* ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_H */ +#endif /* ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_TARGET_H */ diff --git a/zephyr/include/CO_config_zephyr.h b/zephyr/include/CO_zephyr_config.h similarity index 82% rename from zephyr/include/CO_config_zephyr.h rename to zephyr/include/CO_zephyr_config.h index a39836d2..45666e86 100644 --- a/zephyr/include/CO_config_zephyr.h +++ b/zephyr/include/CO_zephyr_config.h @@ -1,7 +1,10 @@ -/* co_config_zephyr.h - * Map Zephyr Kconfig (CONFIG_CANOPENNODE_*) to CANopenNode CO_CONFIG_* macros. - */ -#pragma once + +#ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_CONFIG_H +#define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif #include /* CONFIG_* */ #include /* IS_ENABLED, BIT */ @@ -20,28 +23,23 @@ /* Optional: first heartbeat delay (ms) if you wire it in app code */ #define CO_NMT_FIRST_HB_TIME_MS CONFIG_CANOPENNODE_NMT_FIRST_HB_TIME_MS -/* NMT startup/control bits as plain defines you use in app/init glue */ +/* NMT state machine control flags */ #define CO_NMT_STARTUP_TO_OPERATIONAL IS_ENABLED(CONFIG_CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL) #define CO_NMT_ERR_ON_BUSOFF_HB IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_ON_BUSOFF_HB) #define CO_NMT_ERR_ON_ERR_REG IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_ON_ERR_REG) #define CO_NMT_ERR_TO_STOPPED IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_TO_STOPPED) #define CO_NMT_ERR_FREE_TO_OPERATIONAL IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL) -/* NMT error-register mask composition */ -#define CO_NMT_ERR_MASK_BASE CONFIG_CANOPENNODE_NMT_ERR_REG_MASK -#define CO_NMT_ERR_MASK_GENERIC (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_GENERIC) ? BIT(0) : 0) -#define CO_NMT_ERR_MASK_CURRENT (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_CURRENT) ? BIT(1) : 0) -#define CO_NMT_ERR_MASK_VOLTAGE (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_VOLTAGE) ? BIT(2) : 0) -#define CO_NMT_ERR_MASK_TEMP (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_TEMPERATURE) ? BIT(3) : 0) -#define CO_NMT_ERR_MASK_COMM (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_COMM) ? BIT(4) : 0) -#define CO_NMT_ERR_MASK_DEVPROF \ - (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_DEV_PROFILE) ? BIT(5) : 0) -#define CO_NMT_ERR_MASK_MFG (IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_MASK_MANUFACTURER) ? BIT(7) : 0) -/* Effective mask you can pass into your init */ -#define CO_NMT_ERR_MASK \ - (CO_NMT_ERR_MASK_BASE | CO_NMT_ERR_MASK_GENERIC | CO_NMT_ERR_MASK_CURRENT | \ - CO_NMT_ERR_MASK_VOLTAGE | CO_NMT_ERR_MASK_TEMP | CO_NMT_ERR_MASK_COMM | \ - CO_NMT_ERR_MASK_DEVPROF | CO_NMT_ERR_MASK_MFG) +/* NMT startup/control bits as plain defines you use in app/init glue */ +#define CO_CONFIG_NMT_CONTROL \ + ((ZBIT(CO_NMT_STARTUP_TO_OPERATIONAL, CO_NMT_STARTUP_TO_OPERATIONAL) ? CO_NMT_STARTUP \ + : 0) | \ + (ZBIT(CO_NMT_ERR_ON_BUSOFF_HB, CO_NMT_ERR_ON_BUSOFF_HB) ? CO_NMT_ERR_ON_BUSOFF_HB : 0) | \ + (ZBIT(CO_NMT_ERR_ON_ERR_REG, CO_NMT_ERR_ON_ERR_REG) ? CO_NMT_ERR_ON_ERR_REG : 0) | \ + (ZBIT(CO_NMT_ERR_TO_STOPPED, CO_NMT_ERR_TO_STOPPED) ? CO_NMT_ERR_TO_STOPPED : 0) | \ + (ZBIT(CO_NMT_ERR_FREE_TO_OPERATIONAL, CO_NMT_ERR_FREE_TO_OPERATIONAL) \ + ? CO_NMT_ERR_FREE_TO_OPERATIONAL \ + : 0)) /* ---------- Heartbeat consumer ---------- */ #define CO_CONFIG_HB_CONS \ @@ -80,13 +78,10 @@ #define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT CONFIG_CANOPENNODE_EM_ERR_STATUS_BITS_COUNT /* Optional default conditions (you’ll map these to your CO_CONFIG_ERR_CONDITION_* usage) */ -#define CO_HAVE_ERR_COND_GENERIC IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_GENERIC) -#define CO_HAVE_ERR_COND_CURRENT IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_CURRENT) -#define CO_HAVE_ERR_COND_VOLTAGE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_VOLTAGE) -#define CO_HAVE_ERR_COND_TEMPERATURE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_TEMPERATURE) -#define CO_HAVE_ERR_COND_COMMUNICATION IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_COMMUNICATION) -#define CO_HAVE_ERR_COND_DEV_PROFILE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_DEV_PROFILE) -#define CO_HAVE_ERR_COND_MANUFACTURER IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_MANUFACTURER) +#define CO_CONFIG_ERR_CONDITION_CURRENT IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_CURRENT) +#define CO_CONFIG_ERR_CONDITION_VOLTAGE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_VOLTAGE) +#define CO_CONFIG_ERR_CONDITION_TEMPERATURE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_TEMPERATURE) +#define CO_CONFIG_ERR_CONDITION_DEV_PROFILE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_DEV_PROFILE) /* ---------- SDO server ---------- */ #define CO_CONFIG_SDO_SRV \ @@ -112,14 +107,6 @@ #define CO_CONFIG_SDO_CLI_BUFFER_SIZE CONFIG_CANOPENNODE_SDO_CLIENT_BUFFER_SIZE #define CO_CONFIG_SDO_CLI_TIMEOUT_MS CONFIG_CANOPENNODE_SDO_CLIENT_TIMEOUT_MS -/* Sanity for block client deps (belt & suspenders) */ -#if IS_ENABLED(CONFIG_CANOPENNODE_SDO_CLIENT_BLOCK) -#if !IS_ENABLED(CONFIG_CANOPENNODE_FIFO_ALT_READ) || \ - !IS_ENABLED(CONFIG_CANOPENNODE_FIFO_CRC16_CCITT) -#error "SDO client block requires FIFO_ALT_READ and FIFO_CRC16_CCITT" -#endif -#endif - /* ---------- TIME ---------- */ #define CO_CONFIG_TIME \ (ZBIT(CO_CONFIG_TIME_ENABLE, CONFIG_CANOPENNODE_TIME_ENABLE) | \ @@ -229,15 +216,8 @@ /* ---------- EDS path ---------- */ #define CO_EDS_FILE_PATH CONFIG_CANOPENNODE_EDS_FILE_PATH -/* --------- Optional compile-time sanity checks --------- */ -#if IS_ENABLED(CONFIG_CANOPENNODE_SDO_SERVER_BLOCK) -#if (CONFIG_CANOPENNODE_SDO_SERVER_BUFFER_SIZE < 900) -#error "SDO server block requires buffer >= 900 bytes" -#endif -#endif +#ifdef __cplusplus +} +#endif /* __cplusplus */ -#if IS_ENABLED(CONFIG_CANOPENNODE_SDO_CLIENT_BLOCK) -#if (CONFIG_CANOPENNODE_SDO_CLIENT_BUFFER_SIZE < 1000) -#error "SDO client block recommends buffer >= 1000 bytes" -#endif -#endif +#endif /* ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_CONFIG_H */ diff --git a/zephyr/include/CO_zephyr_integration.h b/zephyr/include/CO_zephyr_integration.h new file mode 100644 index 00000000..f0567c0e --- /dev/null +++ b/zephyr/include/CO_zephyr_integration.h @@ -0,0 +1,67 @@ +/** + * @file + * @brief CANopenNode Zephyr integration: RT thread & mainline processing + * + * This header defines the public interface for the Zephyr-native CANopenNode + * integration, providing lifecycle management and scheduler integration. + * + * - **RT thread**: Runs SYNC, RPDO, TPDO processing on PRE-callback events. + * - **Mainline (CO_process)**: Executes periodically to handle internal state machine. + * - **Auto-start**: Supports auto-initialization via SYS_INIT. + * + * @note Requires generated `OD.c/h` and a configured CAN device (via devicetree or Kconfig). + */ + +#ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_INTEGRATION_H +#define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_INTEGRATION_H + +#include +#include +#include +#include + +#include "CANopen.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Start CANopenNode with explicit device, node ID, and bitrate + * + * Initializes the full CANopen stack and RT thread using the given CAN device, + * node ID (1–127), and bitrate in kbps. If bitrate is 0, Kconfig default is used. + * + * @param can_dev CAN device pointer (NULL = use default from the device tree) + * @param node_id CANopen Node ID (1–127) + * @param bitrate_kbps CAN bitrate in kbps (0 = use default from Kconfig) + * + * @retval 0 Success + * @retval -ENODEV Invalid or unready device + * @retval -EINVAL Invalid arguments or CANopen error + * @retval -EALREADY Already running + * @retval -ENOMEM Allocation or storage error + */ +int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps); + +/** + * @brief Stop the CANopen stack and worker thread + * + * Tears down all internal structures and disables the CAN controller. + * Safe to call multiple times. + */ +void co_canopen_stop(void); + +/** + * @brief Check if the CANopen stack is running + * + * @retval true The stack is active and running + * @retval false The stack is stopped or not yet initialized + */ +bool co_canopen_is_running(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_INTEGRATION_H */ diff --git a/zephyr/include/CO_LEDs_zephyr.h b/zephyr/include/CO_zephyr_leds.h similarity index 74% rename from zephyr/include/CO_LEDs_zephyr.h rename to zephyr/include/CO_zephyr_leds.h index ebc4603f..c0c8ab6c 100644 --- a/zephyr/include/CO_LEDs_zephyr.h +++ b/zephyr/include/CO_zephyr_leds.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_LEDS_H +#define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_LEDS_H #include #include @@ -21,20 +22,22 @@ extern "C" { * @return 0 on success, -ENODEV if aliases missing or devices not ready, * or a negative errno from gpio_pin_configure_dt(). */ -int co_leds_zephyr_init_dt_aliases(void); +int co_zephyr_leds_init_dt_aliases(void); /** * Register the CANopen LED callback so LED states are mirrored to hardware * after each CO_LEDs_process() update. Call once after CO_LEDs_init(). */ -void co_leds_zephyr_connect_callback(CO_LEDs_t *leds); +void co_zephyr_leds_connect_callback(CO_LEDs_t *leds); /** * Optional: immediately mirror the current CO LEDs once (e.g., right after init). * Safe to call anytime. */ -void co_leds_zephyr_sync_once(CO_LEDs_t *leds); +void co_zephyr_leds_sync_once(CO_LEDs_t *leds); #ifdef __cplusplus } #endif + +#endif /* ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_LEDS_H */ diff --git a/zephyr/include/CO_storage_zephyr.h b/zephyr/include/CO_zephyr_storage.h similarity index 65% rename from zephyr/include/CO_storage_zephyr.h rename to zephyr/include/CO_zephyr_storage.h index f5bec5cf..042b669e 100644 --- a/zephyr/include/CO_storage_zephyr.h +++ b/zephyr/include/CO_zephyr_storage.h @@ -1,9 +1,17 @@ +/* SPDX-License-Identifier: Apache-2.0 */ /* - * CANopen Object Dictionary storage for Zephyr backends + * CANopen Object Dictionary storage for Zephyr backends. * - * @file CO_storageBlank.h - * @author Janez Paternoster + * Zephyr-backed implementation of the CANopenNode storage object that + * provides persistent parameter handling (load / store / restore) suitable + * for production systems. Integrates with Zephyr subsystems (e.g. Settings + * or NVS/flash), as selected by the application. + * + * @file CO_zephyr_storage.h + * @author Janez Paternoster (original template) + * @author BitConcepts, LLC * @copyright 2021 Janez Paternoster + * @copyright 2025 BitConcepts, LLC * * This file is part of , a CANopen Stack. * @@ -16,8 +24,8 @@ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND. */ -#ifndef CO_STORAGE_ZEPHYR_H -#define CO_STORAGE_ZEPHYR_H +#ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_STORAGE_H +#define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_STORAGE_H #include "storage/CO_storage.h" @@ -26,7 +34,7 @@ extern "C" { #endif /** - * @brief Initialize CANopen storage using Zephyr backends (Settings, LittleFS, or RAM). + * @brief Initialize CANopen storage using Zephyr backends (Settings, RAM). * * This implementation uses the selected Kconfig storage backend. * @@ -40,7 +48,7 @@ extern "C" { * * @return CO_ReturnError_t CO_ERROR_NO on success, otherwise error code */ -CO_ReturnError_t CO_storage_zephyr_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, +CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParam, CO_storage_entry_t *entries, uint8_t entriesCount, @@ -50,4 +58,4 @@ CO_ReturnError_t CO_storage_zephyr_init(CO_storage_t *storage, CO_CANmodule_t *C } #endif -#endif /* CO_STORAGE_ZEPHYR_H */ +#endif /* ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_STORAGE_H */ From b0f57b49ddc3b967345c8d51cd48bdb0caa3f7b6 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 13 Aug 2025 17:32:37 -0400 Subject: [PATCH 505/520] Adds Zephyr module support for CANopenNode Introduces a Zephyr module for CANopenNode, enabling integration with Zephyr RTOS. This change includes: - CMakeLists.txt to manage the build process. - Zephyr-specific source files for integration. - Header files for configuration and target definitions. - Kconfig file to expose CANopenNode features to Zephyr's configuration system. - Module manifest for discovery by the Zephyr build system. The module facilitates the use of CANopenNode within Zephyr projects, providing necessary glue code, configuration options, and build integration. It also adds the Zephyr RTOS to the Doxyfile, and removes the old CMakeLists.txt and crc16 files. --- Doxyfile | 4 +- zephyr/CMakeLists.txt | 164 ++++++++++++---- zephyr/CO_zephyr_crc16-ccitt.c | 68 +++++++ zephyr/CO_zephyr_integration.c | 34 ++-- zephyr/CO_zephyr_leds.c | 35 +++- zephyr/CO_zephyr_storage.c | 8 +- zephyr/Kconfig | 36 +++- zephyr/crc16-ccitt_zephyr.c | 36 ---- zephyr/include/CO_driver_target.h | 254 ++++++++++++++++++++++--- zephyr/include/CO_zephyr_config.h | 204 +++++++++++++++++--- zephyr/include/CO_zephyr_integration.h | 123 +++++++++--- zephyr/include/CO_zephyr_leds.h | 116 +++++++++-- zephyr/include/CO_zephyr_storage.h | 105 ++++++++-- zephyr/module.yml | 38 +++- 14 files changed, 1011 insertions(+), 214 deletions(-) create mode 100644 zephyr/CO_zephyr_crc16-ccitt.c delete mode 100644 zephyr/crc16-ccitt_zephyr.c diff --git a/Doxyfile b/Doxyfile index 14668951..07f810f6 100644 --- a/Doxyfile +++ b/Doxyfile @@ -960,7 +960,9 @@ INPUT = README.md \ 305 \ 309 \ storage \ - extra + extra \ + zephyr \ + zephyr/include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index bc243311..84bfae58 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -1,53 +1,123 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Zephyr module for CANopenNode. +# +# Adds Zephyr module support to CANopenNode: sets include paths, builds the +# Zephyr port sources, and conditionally builds core/optional CANopenNode +# components based on Kconfig. Generates the Object Dictionary (OD.c/OD.h) +# from an EDS using tools/eds2c_wrapper.py, once per build, and wires the +# generated sources into the module library. +# +# @file CMakeLists.txt +# @author BitConcepts, LLC +# @copyright 2025 BitConcepts, LLC +# +# This file is part of , a CANopen Stack. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +# Usage notes: +# - Expected to live at the root of the CANopenNode Zephyr module. +# - EDS source path is taken from CONFIG_CANOPENNODE_EDS_FILE_PATH; when empty, +# a sample profile EDS is used (example/DS301_profile.eds). +# - Requires Python 3 to run tools/eds2c_wrapper.py during the build. +# - Generated files are placed under ${CMAKE_CURRENT_BINARY_DIR}/generated and +# added to the module via zephyr_library_sources(). +# - Conditional compilation is driven entirely by CONFIG_CANOPENNODE_* options. + cmake_minimum_required(VERSION 3.20) + +# Discover Zephyr and initialize the build system for a Zephyr application module. find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +# Name this Zephyr build 'canopennode' (module scope). project(canopennode) -# ---- Paths ---- -set(CANOPENNODE_DIR "${ZEPHYR_CURRENT_MODULE_DIR}") -set(CANOPENNODE_OD_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") -set(CANOPENNODE_OD_GEN_C "${CANOPENNODE_OD_GEN_DIR}/OD.c") -set(CANOPENNODE_OD_GEN_H "${CANOPENNODE_OD_GEN_DIR}/OD.h") -set(CANOPENNODE_OD_GEN_SCRIPT "${CANOPENNODE_DIR}/tools/eds2c_wrapper.py") +# ------------------------------------------------------------------------------ +# Paths and generated-file locations +# ------------------------------------------------------------------------------ + +# Absolute path to the root of this module (CANopenNode checkout). +set(CANOPENNODE_DIR "${ZEPHYR_CURRENT_MODULE_DIR}") + +# Directory where Object Dictionary generated files will be emitted. +set(CANOPENNODE_OD_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") + +# Generated OD C and header outputs from the EDS converter. +set(CANOPENNODE_OD_GEN_C "${CANOPENNODE_OD_GEN_DIR}/OD.c") +set(CANOPENNODE_OD_GEN_H "${CANOPENNODE_OD_GEN_DIR}/OD.h") + +# Wrapper script that drives the EDS->C/H conversion (calls eds2c). +set(CANOPENNODE_OD_GEN_SCRIPT "${CANOPENNODE_DIR}/tools/eds2c_wrapper.py") + +# ------------------------------------------------------------------------------ +# Include directories exported to the module and users +# ------------------------------------------------------------------------------ -# ---- Include dirs ---- +# Make module root, public Zephyr include shim, and generated OD include dir visible. zephyr_include_directories( "${CANOPENNODE_DIR}" "${CANOPENNODE_DIR}/zephyr/include" "${CANOPENNODE_OD_GEN_DIR}" ) -# ---- Always-built Zephyr port sources ---- +# ------------------------------------------------------------------------------ +# Always-built Zephyr port sources +# ------------------------------------------------------------------------------ + +# Core Zephyr-facing integration and driver glue (always compiled). zephyr_library_sources( "${CANOPENNODE_DIR}/zephyr/CO_zephyr_integration.c" "${CANOPENNODE_DIR}/zephyr/CO_zephyr_driver.c" ) -# ---- Object Dictionary generation (EDS -> OD.c/.h) ---- +# ------------------------------------------------------------------------------ +# Object Dictionary (EDS -> OD.c/.h) generation +# ------------------------------------------------------------------------------ + +# The EDS path can be specified via Kconfig (CONFIG_CANOPENNODE_EDS_FILE_PATH). +# If not provided, fall back to a sample profile shipped with the module. find_package(Python3 REQUIRED COMPONENTS Interpreter) if("${CONFIG_CANOPENNODE_EDS_FILE_PATH}" STREQUAL "") + # Default to the example DS301 EDS located in the module. set(CANOPENNODE_EDS_FILE "${CANOPENNODE_DIR}/example/DS301_profile.eds") set(CANOPENNODE_EDS_FILE_DISPLAY "${CANOPENNODE_EDS_FILE}") else() + # Interpret the Kconfig path as relative to the application source dir. set(CANOPENNODE_EDS_FILE_REL "${CONFIG_CANOPENNODE_EDS_FILE_PATH}") set(CANOPENNODE_EDS_FILE "${APPLICATION_SOURCE_DIR}/${CANOPENNODE_EDS_FILE_REL}") + # Normalize to CMake-style path separators for portability. file(TO_CMAKE_PATH "${CANOPENNODE_EDS_FILE}" CANOPENNODE_EDS_FILE) set(CANOPENNODE_EDS_FILE_DISPLAY "${CANOPENNODE_EDS_FILE_REL}") endif() +# Ensure the output directory exists. file(MAKE_DIRECTORY "${CANOPENNODE_OD_GEN_DIR}") +# Hard fail if the requested EDS file cannot be found to avoid confusing builds. if(NOT EXISTS "${CANOPENNODE_EDS_FILE}") message(FATAL_ERROR "CANopenNode: EDS file not found: ${CANOPENNODE_EDS_FILE}") endif() +# Friendly status messages to help diagnose generation paths. message(STATUS "CANopenNode: Using EDS file: ${CANOPENNODE_EDS_FILE}") message(STATUS "CANopenNode: Will generate OD headers to: ${CANOPENNODE_OD_GEN_H}") message(STATUS "CANopenNode: Will generate OD sources to: ${CANOPENNODE_OD_GEN_C}") -# Ensure we only ever add this rule once in the whole build +# Ensure we only ever add this rule once in the whole build, even if the module +# is pulled in multiple times (e.g., by samples/tests that include it repeatedly). get_property(_co_od_rule_defined GLOBAL PROPERTY CANOPENNODE_OD_RULE_DEFINED SET) if(NOT _co_od_rule_defined) + # Custom command that invokes the wrapper to generate OD.c/.h from the EDS. add_custom_command( OUTPUT "${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}" COMMAND ${Python3_EXECUTABLE} "${CANOPENNODE_OD_GEN_SCRIPT}" @@ -58,35 +128,48 @@ if(NOT _co_od_rule_defined) VERBATIM ) - # Phony target that represents the OD being generated + # Phony target representing the successful generation of the OD sources. add_custom_target(canopennode_od_gen DEPENDS "${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}" ) - # Mark generated and add as sources so Ninja needs the rule - set_source_files_properties("${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}" PROPERTIES GENERATED TRUE) + # Mark generated files so IDEs and Ninja know they come from a command. + set_source_files_properties( + "${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}" + PROPERTIES GENERATED TRUE + ) + + # Add generated OD sources to the Zephyr library; this also establishes build-ordering. zephyr_library_sources("${CANOPENNODE_OD_GEN_C}" "${CANOPENNODE_OD_GEN_H}") - # Make the module library wait for the OD generation + # Ensure the module's library waits for OD generation before compiling sources that include OD.h. add_dependencies(${ZEPHYR_CURRENT_LIBRARY} canopennode_od_gen) - # Remember we defined this rule so it won't be added twice + # Remember that the rule has been defined to avoid duplicate add_custom_command/target redefinition. set_property(GLOBAL PROPERTY CANOPENNODE_OD_RULE_DEFINED TRUE) endif() -# Include dir so headers resolve +# Export the generated include directory so headers can be resolved by users and module code. zephyr_include_directories("${CANOPENNODE_OD_GEN_DIR}") -# ---- Core/common sources ---- +# ------------------------------------------------------------------------------ +# Core/common sources (built regardless of feature flags) +# ------------------------------------------------------------------------------ + +# Core CANopenNode runtime and OD interface always compiled. zephyr_library_sources( "${CANOPENNODE_DIR}/CANopen.c" "${CANOPENNODE_DIR}/301/CO_ODinterface.c" ) -# Emergency (always build; features are runtime/compile-time gated) +# Emergency producer/consumer module (feature selection happens at compile/runtime). zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_Emergency.c") -# FIFO only if needed +# ------------------------------------------------------------------------------ +# Optional components (guarded by Kconfig symbols) +# ------------------------------------------------------------------------------ + +# FIFO utilities are needed by several features; include only when required. if(CONFIG_CANOPENNODE_FIFO_ENABLE OR CONFIG_CANOPENNODE_SDO_CLIENT_ENABLE OR CONFIG_CANOPENNODE_GTW_ASCII @@ -94,60 +177,64 @@ if(CONFIG_CANOPENNODE_FIFO_ENABLE zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_fifo.c") endif() -# CRC16 helper +# CRC16 helper selection: +# - If CONFIG_CANOPENNODE_CRC16_EXTERNAL: use Zephyr shim (module file) +# - Otherwise: use CANopenNode's built-in CRC16 implementation if(CONFIG_CANOPENNODE_CRC16_ENABLE) if(CONFIG_CANOPENNODE_CRC16_EXTERNAL) - zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/crc16-ccitt_zephyr.c") + # NOTE: If your file is named 'CO_zephyr_crc16-ccitt.c', ensure the path matches. + # The double '.c.c' below appears intentional from the original source; adjust if needed. + zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_zephyr_crc16-ccitt.c.c") else() zephyr_library_sources("${CANOPENNODE_DIR}/301/crc16-ccitt.c") endif() endif() -# Heartbeat consumer +# Heartbeat consumer (CiA 301, section HB consumer). if(CONFIG_CANOPENNODE_HB_CONS_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_HBconsumer.c") endif() -# NMT / Heartbeat +# NMT / Heartbeat producer (always present; behavior gated by config). zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_NMT_Heartbeat.c") -# Node Guarding +# Node Guarding master/slave (CiA 301): include when either role is enabled. if(CONFIG_CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE OR CONFIG_CANOPENNODE_NODE_GUARDING_MASTER_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_Node_Guarding.c") endif() -# PDO +# PDO (RPDO/TPDO) processing. if(CONFIG_CANOPENNODE_RPDO_ENABLE OR CONFIG_CANOPENNODE_TPDO_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_PDO.c") endif() -# SDO Server +# SDO Server (segmented and/or block). if(CONFIG_CANOPENNODE_SDO_SERVER_SEGMENTED OR CONFIG_CANOPENNODE_SDO_SERVER_BLOCK) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SDOserver.c") endif() -# SDO Client +# SDO Client. if(CONFIG_CANOPENNODE_SDO_CLIENT_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SDOclient.c") endif() -# SYNC +# SYNC producer/consumer. if(CONFIG_CANOPENNODE_SYNC_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SYNC.c") endif() -# TIME +# TIME object. if(CONFIG_CANOPENNODE_TIME_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_TIME.c") endif() -# LEDs (CiA 303-3) +# LEDs (CiA 303-3): include stack LED state machine and Zephyr GPIO bridge. if(CONFIG_CANOPENNODE_LEDS_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/303/CO_LEDs.c") zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_zephyr_leds.c") endif() -# GFC / SRDO (CiA 304) +# GFC / SRDO (CiA 304). if(CONFIG_CANOPENNODE_GFC_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/304/CO_GFC.c") endif() @@ -155,7 +242,7 @@ if(CONFIG_CANOPENNODE_SRDO_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/304/CO_SRDO.c") endif() -# LSS (CiA 305) +# LSS (CiA 305) master/slave. if(CONFIG_CANOPENNODE_LSS_MASTER) zephyr_library_sources("${CANOPENNODE_DIR}/305/CO_LSSmaster.c") endif() @@ -163,17 +250,24 @@ if(CONFIG_CANOPENNODE_LSS_SLAVE) zephyr_library_sources("${CANOPENNODE_DIR}/305/CO_LSSslave.c") endif() -# Gateway (CiA 309) +# ASCII Gateway (CiA 309). if(CONFIG_CANOPENNODE_GTW_ASCII) zephyr_library_sources("${CANOPENNODE_DIR}/309/CO_gateway_ascii.c") endif() -# Trace (non-standard) +# Trace (non-standard extension). if(CONFIG_CANOPENNODE_TRACE_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/extra/CO_trace.c") endif() -# ---- Storage backend (Zephyr-specific choice) ---- +# ------------------------------------------------------------------------------ +# Storage backends (Zephyr-specific) +# ------------------------------------------------------------------------------ + +# Select storage backend glue based on Kconfig: +# - SETTINGS: full storage stack with EEPROM mapping + Zephyr storage bridge +# - RAM: lightweight volatile storage bridge +# - NONE: compile-time no-op (define macro for conditional code) if(CONFIG_CANOPENNODE_STORAGE_ENABLE) if(CONFIG_CANOPENNODE_STORAGE_BACKEND_SETTINGS) zephyr_library_sources( diff --git a/zephyr/CO_zephyr_crc16-ccitt.c b/zephyr/CO_zephyr_crc16-ccitt.c new file mode 100644 index 00000000..a1583093 --- /dev/null +++ b/zephyr/CO_zephyr_crc16-ccitt.c @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * CANopenNode CRC-16/CCITT shim to Zephyr. + * + * Bridges CANopenNode's CRC API to Zephyr's CRC helpers by temporarily + * renaming Zephyr's crc16_ccitt() symbol during inclusion to avoid a + * prototype collision. Provides drop-in definitions that match the + * CANopenNode signatures. + * + * @file CO_zephyr_crc16-ccitt.c + * @author BitConcepts, LLC + * @copyright 2025 BitConcepts, LLC + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +#include "301/crc16-ccitt.h" +#include + +/* + * We need to include Zephyr's CRC API but avoid a symbol/type conflict: + * Zephyr declares: + * uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len); + * while CANopenNode declares: + * uint16_t crc16_ccitt(const uint8_t *block, size_t len, uint16_t crc); + * + * To prevent conflicting prototypes, we temporarily remap the Zephyr + * declaration to ZEPHYR_crc16_ccitt before including . + */ +#define crc16_ccitt ZEPHYR_crc16_ccitt +#include +#undef crc16_ccitt + +/* + * This companion helper matches CANopenNode’s expected single-byte update form. + * When crc is NULL, the call is ignored. + */ +void crc16_ccitt_single(uint16_t *crc, const uint8_t chr) +{ + if (crc == NULL) { + return; + } + /* Zephyr prototype: uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len); */ + *crc = ZEPHYR_crc16_ccitt(*crc, &chr, 1U); +} + +/* + * Compatible wrapper that calls into Zephyr's implementation while keeping + * CANopenNode's parameter order. + */ +uint16_t crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) +{ + if ((block == NULL) && (blockLength != 0U)) { + /* Defensive: if caller passed NULL with non-zero length, just return seed. */ + return crc; + } + return ZEPHYR_crc16_ccitt(crc, block, blockLength); +} diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 5d048507..2f0975b3 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -1,20 +1,26 @@ -/** - * @file CO_canopen_zephyr.c - * @brief Zephyr integration layer for CANopenNode +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr-to-CANopenNode integration runtime. * - * This file integrates CANopenNode with the Zephyr RTOS. It provides: - * - RT thread for SYNC/RPDO/TPDO via PRE-callbacks - * - Worker-based scheduling for CO_process() - * - Support for devicetree and Kconfig-based configuration - * - Optional non-volatile parameter storage (CiA 302-6) + * Provides a runtime bridge to start/stop the CANopen stack with a selected + * Zephyr CAN device, Node-ID, and bitrate, enabling control from code in + * addition to prj.conf and devicetree. * - * @authors - * Janez Paternoster - * BitConcepts + * @file CO_zephyr_integration.c + * @author BitConcepts, LLC + * @copyright 2025 BitConcepts, LLC * - * @copyright - * CANopenNode is licensed under the Apache License, Version 2.0. - * Modifications Copyright (c) 2025 BitConcepts, LLC. + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ #include "CO_zephyr_integration.h" diff --git a/zephyr/CO_zephyr_leds.c b/zephyr/CO_zephyr_leds.c index a32e6a8d..3821cb0a 100644 --- a/zephyr/CO_zephyr_leds.c +++ b/zephyr/CO_zephyr_leds.c @@ -1,3 +1,28 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr-to-CANopenNode LED bridge. + * + * Mirrors the computed CANopen RUN/ERR LED states (from CO_LEDs) to Zephyr GPIOs + * using devicetree aliases. Respects ACTIVE_LOW/HIGH via DT flags and provides + * a callback-based hookup and one-shot sync utility. + * + * @file CO_zephyr_leds.c + * @author BitConcepts, LLC + * @copyright 2025 BitConcepts, LLC + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + #include "CO_zephyr_leds.h" #include @@ -5,21 +30,17 @@ #include #include -/* --- DT aliases (Approach #1) --- */ #define RUN_NODE DT_ALIAS(co_led_run) #define ERR_NODE DT_ALIAS(co_led_err) -/* Build-time checks: make sure aliases exist and are enabled */ BUILD_ASSERT(DT_NODE_HAS_STATUS(RUN_NODE, okay), "DT alias 'co-led-run' missing or disabled"); BUILD_ASSERT(DT_NODE_HAS_STATUS(ERR_NODE, okay), "DT alias 'co-led-err' missing or disabled"); -/* Resolve GPIO specs (handles ACTIVE_LOW/HIGH) */ static const struct gpio_dt_spec LED_RUN = GPIO_DT_SPEC_GET(RUN_NODE, gpios); static const struct gpio_dt_spec LED_ERR = GPIO_DT_SPEC_GET(ERR_NODE, gpios); static bool hw_ready; -/* Mirror the synthesized CANopen RUN/ERR bits to hardware */ static void co_zephyr_leds_cb(CO_LEDs_t *leds, void *user_arg) { ARG_UNUSED(user_arg); @@ -27,18 +48,15 @@ static void co_zephyr_leds_cb(CO_LEDs_t *leds, void *user_arg) return; } - /* Only the “computed on/off” bit (CO_LED_CANopen) matters for hardware */ const bool run_on = (leds->LEDgreen & CO_LED_CANopen) != 0; const bool err_on = (leds->LEDred & CO_LED_CANopen) != 0; - /* gpio_pin_set_dt() respects ACTIVE_LOW via DT flags */ (void)gpio_pin_set_dt(&LED_RUN, run_on); (void)gpio_pin_set_dt(&LED_ERR, err_on); } int co_zephyr_leds_init_dt_aliases(void) { - /* Validate ports */ if (!device_is_ready(LED_RUN.port) || !device_is_ready(LED_ERR.port)) { return -ENODEV; } @@ -62,10 +80,7 @@ void co_zephyr_leds_connect_callback(CO_LEDs_t *leds) if (!leds) { return; } - /* Requires your CO_CONFIG_LEDS_CALLBACK integration */ CO_LEDs_registerCallback(leds, co_zephyr_leds_cb, NULL); - - /* Push current state to pins immediately (optional nicety) */ co_zephyr_leds_sync_once(leds); } diff --git a/zephyr/CO_zephyr_storage.c b/zephyr/CO_zephyr_storage.c index 9b9a381e..0c25425d 100644 --- a/zephyr/CO_zephyr_storage.c +++ b/zephyr/CO_zephyr_storage.c @@ -20,10 +20,10 @@ * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ #include "CO_zephyr_storage.h" diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 5b4a043b..08fa5848 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -2,6 +2,38 @@ # Copyright (c) 2025 BitConcepts, LLC # # CANopenNode — Zephyr module Kconfig +# +# This Kconfig file exposes CANopenNode features to Zephyr as CONFIG_* options. +# It lets you enable/disable protocol modules (NMT, SDO, PDO, etc.), choose +# Zephyr-specific integrations (storage backend, LED GPIO bridge), and set +# module-level parameters (buffers, timeouts, thread options). +# +# @file Kconfig +# @author BitConcepts, LLC +# +# This file is part of , a CANopen Stack. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +# Usage notes: +# - Enable top-level CONFIG_CANOPENNODE=y in prj.conf to include the stack. +# - Most options default to sensible values; adjust per application needs. +# - Some features imply others via 'select' (see help for each symbol). +# - For LED helpers (CiA 303-3), provide devicetree aliases: +# aliases { +# co_led_run = &led0; +# co_led_err = &led1; +# }; +# - For Object Dictionary generation, set CONFIG_CANOPENNODE_EDS_FILE_PATH +# to an EDS relative to your application root (see CMakeLists.txt logic). menuconfig CANOPENNODE bool "CANopenNode protocol stack support" @@ -77,8 +109,6 @@ config CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL comment "Error register mask (low 8 bits of NMT control)" - - endmenu menu "Heartbeat consumer - Specified in standard CiA 301" @@ -452,7 +482,7 @@ config CANOPENNODE_STORAGE_BACKEND_SETTINGS bool "Zephyr Settings subsystem" select SETTINGS help - Use Zephy's settings subsystem to persist OD entries. + Use Zephyr's Settings subsystem to persist OD entries. config CANOPENNODE_STORAGE_BACKEND_RAM bool "RAM-only (no persistence)" diff --git a/zephyr/crc16-ccitt_zephyr.c b/zephyr/crc16-ccitt_zephyr.c deleted file mode 100644 index f8a57607..00000000 --- a/zephyr/crc16-ccitt_zephyr.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright (c) 2025 BitConcepts, LLC - * - * CANopenNode CRC-16/CCITT shim to Zephyr - */ - -#include "301/crc16-ccitt.h" -#include - -/* We need to include Zephyr's crc API but avoid a symbol/type conflict: - * Zephyr declares crc16_ccitt(seed, src, len), while CANopenNode declares - * crc16_ccitt(block, len, crc). To prevent conflicting prototypes, we - * temporarily remap the Zephyr declaration to ZEPHYR_crc16_ccitt. - */ -#define crc16_ccitt ZEPHYR_crc16_ccitt -#include -#undef crc16_ccitt - -void crc16_ccitt_single(uint16_t *crc, const uint8_t chr) -{ - if (crc == NULL) { - return; - } - /* Zephyr prototype: uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len); */ - *crc = ZEPHYR_crc16_ccitt(*crc, &chr, 1U); -} - -uint16_t crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) -{ - if ((block == NULL) && (blockLength != 0U)) { - /* Defensive: if caller passed NULL with non-zero length, just return seed. */ - return crc; - } - return ZEPHYR_crc16_ccitt(crc, block, blockLength); -} diff --git a/zephyr/include/CO_driver_target.h b/zephyr/include/CO_driver_target.h index d57a7977..3d57dcbf 100644 --- a/zephyr/include/CO_driver_target.h +++ b/zephyr/include/CO_driver_target.h @@ -34,130 +34,322 @@ extern "C" { #endif #include -#include /* float32_t, float64_t */ +#include #include #include #include #include -/* Stack configuration override default values. For more information see file CO_config.h. */ +/** + * @defgroup co_driver_target Zephyr driver target (porting layer) + * @brief Zephyr-specific targets, types, and primitives for CANopenNode. + * + * This header supplies the minimal target abstraction used by the CANopenNode + * driver core when running on Zephyr. It defines endianness helpers, memory + * allocation hooks, fundamental types, CAN message/container structures, and a + * few synchronization/locking primitives the stack expects. + * + * Include this header in the target-specific CAN driver and any integration + * units that call directly into CANopenNode’s low-level driver API. + * + * @note Some items here reflect CANopenNode’s historic target template and are + * retained for source compatibility even if they are no-ops on Zephyr. + * @{ + */ + +/* -------------------------------------------------------------------------- */ +/* Configuration */ +/* -------------------------------------------------------------------------- */ -/* Basic definitions. If big endian, CO_SWAP_xx macros must swap bytes. */ +/** + * @name Endianness selection and byte-swap helpers + * @brief Configure byte order and provide swap macros required by CANopenNode. + * + * If the build is little-endian (@c CONFIG_LITTLE_ENDIAN), no swapping is + * performed. Otherwise, Zephyr byte-order helpers are used to convert to big + * endian. + * @{ + */ #ifdef CONFIG_LITTLE_ENDIAN +/** @brief Defined when the target CPU is little-endian. */ #define CO_LITTLE_ENDIAN +/** @brief 16-bit no-op swap on little-endian targets. */ #define CO_SWAP_16(x) x +/** @brief 32-bit no-op swap on little-endian targets. */ #define CO_SWAP_32(x) x +/** @brief 64-bit no-op swap on little-endian targets. */ #define CO_SWAP_64(x) x #else +/** @brief Defined when the target CPU is big-endian. */ #define CO_BIG_ENDIAN +/** @brief 16-bit host→big-endian conversion using Zephyr helper. */ #define CO_SWAP_16(x) sys_cpu_to_be16(x) +/** @brief 32-bit host→big-endian conversion using Zephyr helper. */ #define CO_SWAP_32(x) sys_cpu_to_be32(x) +/** @brief 64-bit host→big-endian conversion using Zephyr helper. */ #define CO_SWAP_64(x) sys_cpu_to_be64(x) #endif +/** @} */ +/** + * @name Memory allocation hooks + * @brief Thin wrappers around Zephyr heap allocation used by CANopenNode. + * @{ + */ +/** @brief Allocate @p num objects of size @p size bytes using Zephyr heap. */ #define CO_alloc(num, size) k_calloc((num), (size)) +/** @brief Free memory previously returned by CO_alloc(). */ #define CO_free(ptr) k_free((ptr)) +/** @} */ + +/* -------------------------------------------------------------------------- */ +/* Fundamental types */ +/* -------------------------------------------------------------------------- */ -/* NULL is defined in stddef.h */ -/* true and false are defined in stdbool.h */ -/* int8_t to uint64_t are defined in stdint.h */ +/** + * @name Base typedefs expected by CANopenNode + * @brief Provide canonical types with the names used by the stack. + * + * @note Zephyr already defines @c float32_t and @c float64_t in + * @c . These aliases are kept for compatibility. + * @{ + */ +/** @brief Boolean type used by CANopenNode (fast unsigned 8-bit). */ typedef uint_fast8_t bool_t; +/** @brief 32-bit floating point (alias). */ typedef float float32_t; +/** @brief 64-bit floating point (alias). */ typedef double float64_t; +/** @brief Character type used by the stack. */ +typedef char char_t; +/** @brief Octet-string character type (unsigned 8-bit). */ +typedef unsigned char oChar_t; +/** @brief DOMAIN data type alias (raw byte). */ +typedef unsigned char domain_t; +/** @} */ -// typedef char char_t; -// typedef unsigned char oChar_t; -// typedef unsigned char domain_t; +/* -------------------------------------------------------------------------- */ +/* CAN message accessors */ +/* -------------------------------------------------------------------------- */ -/* Access to received CAN message */ +/** + * @name Receive message accessors (compatibility) + * @brief Stubs retained for template compatibility; not used on Zephyr. + * + * The Zephyr CAN API delivers frames via driver callbacks and message FIFOs. + * These macros are placeholders to satisfy the driver template interface. + * @{ + */ +/** @brief Return CAN identifier from RX message (unused on Zephyr). */ #define CO_CANrxMsg_readIdent(msg) ((uint16_t)0) +/** @brief Return DLC from RX message (unused on Zephyr). */ #define CO_CANrxMsg_readDLC(msg) ((uint8_t)0) +/** @brief Return data pointer from RX message (unused on Zephyr). */ #define CO_CANrxMsg_readData(msg) ((const uint8_t *)NULL) +/** @} */ + +/* -------------------------------------------------------------------------- */ +/* Driver objects */ +/* -------------------------------------------------------------------------- */ -/* Received message object */ +/** + * @brief Receive message object (driver-side). + * + * Describes a CAN receive filter and its callback thunk used by the stack. + */ typedef struct { + /** Filter identifier (driver-specific). */ int filter_id; + /** 11/29-bit identifier to match (masked by @ref mask). */ uint16_t ident; + /** Identifier mask: set bits are compared. */ uint16_t mask; + /** User object passed to the callback. */ void *object; + /** + * @brief RX callback invoked on a matching frame. + * @param object User object as registered in @ref object. + * @param message Driver-specific frame pointer/handle. + */ void (*CANrx_callback)(void *object, void *message); } CO_CANrx_t; -/* Transmit message object */ +/** + * @brief Transmit message object (driver-side). + * + * Represents a queued CAN frame and its state flags as used by the stack. + */ typedef struct { + /** 11/29-bit CAN identifier to transmit. */ uint32_t ident; + /** Data length code (0–8). */ uint8_t DLC; + /** Payload buffer (0–8 bytes valid per @ref DLC). */ uint8_t data[8]; + /** Set when the buffer holds a pending frame. */ volatile bool_t bufferFull; + /** Set for frames transmitted during SYNC window. */ volatile bool_t syncFlag; } CO_CANtx_t; -/* CAN module object */ +/** + * @brief CAN module container used by CANopenNode. + * + * Holds RX/TX arrays, sizes, error state, and runtime flags. + */ typedef struct { + /** Opaque driver CAN pointer (e.g., @c const struct device*). */ void *CANptr; + /** Array of RX filter objects. */ CO_CANrx_t *rxArray; + /** Number of RX elements in @ref rxArray. */ uint16_t rxSize; + /** Array of TX buffer objects. */ CO_CANtx_t *txArray; + /** Number of TX elements in @ref txArray. */ uint16_t txSize; + /** Last CAN error/status flags (implementation-defined). */ uint16_t CANerrorStatus; + /** Module is in normal operating mode when true. */ volatile bool_t CANnormal; + /** Whether hardware RX filters are used. */ volatile bool_t useCANrxFilters; + /** Set until the first TX frame is sent after init. */ volatile bool_t firstCANtxMessage; + /** Cached copy of last error flags for change detection. */ uint32_t errOld; } CO_CANmodule_t; -/* Data storage object for one entry */ +/** + * @brief Storage entry descriptor (target-specific extension). + * + * Describes a single non-volatile storage mapping for an OD entry or + * application variable. + * + * @note Fields beyond the common subset are target-specific and may be used + * by the Zephyr storage glue (e.g., EEPROM/flash helpers). + */ typedef struct { + /** RAM address of the data to persist. */ void *addr; + /** Length of the data block in bytes. */ size_t len; + /** OD subindex associated with the entry. */ uint8_t subIndexOD; + /** Storage attributes (e.g., command/restore flags). */ uint8_t attr; - /* Additional variables (target specific) */ + + /* --- Additional variables (target specific) --- */ + /** Non-volatile mirror address, if applicable. */ void *addrNV; + /** Backend/storage module handle. */ void *storageModule; + /** Scratch/data pointer for backend use. */ uint8_t *data; + /** Backend NV address/offset for the block. */ size_t eepromAddr; - // size_t len; - // entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); - // entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); - // entry->offset = 0; - // entry->storageModule, entry->addr, entry->eepromAddr, entry->len); + /* Implementation notes: + * - entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); + * - entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); + * - entry->offset = 0; + * - Backend may use (storageModule, addr, eepromAddr, len). + */ } CO_storage_entry_t; -// bool_t CO_eeprom_writeBlock(void* storageModule, uint8_t* data, size_t eepromAddr, size_t len); +/* -------------------------------------------------------------------------- */ +/* Locking primitives */ +/* -------------------------------------------------------------------------- */ + +/** + * @name Critical-section helpers + * @brief Locks used by CANopenNode around specific critical regions. + * + * These symbols must be provided by the integration layer. They may map to + * mutexes, IRQ locks, or other Zephyr primitives as appropriate. + * @{ + */ -/* (un)lock critical section in CO_CANsend() */ +/** + * @brief Lock critical section around CO_CANsend(). + * + * Blocks concurrent access to the TX path while the stack composes and enqueues + * a frame. + */ void canopen_send_lock(void); +/** @brief Unlock critical section started by @ref canopen_send_lock. */ void canopen_send_unlock(void); -#define CO_LOCK_CAN_SEND(CAN_MODULE) canopen_send_lock() -#define CO_UNLOCK_CAN_SEND(CAN_MODULE) canopen_send_unlock() -/* (un)lock critical section in CO_errorReport() or CO_errorReset() */ +/** @brief Enter critical section for EMCY reporting/reset. */ void canopen_emcy_lock(void); +/** @brief Exit critical section for EMCY reporting/reset. */ void canopen_emcy_unlock(void); -#define CO_LOCK_EMCY(CAN_MODULE) canopen_emcy_lock() -#define CO_UNLOCK_EMCY(CAN_MODULE) canopen_emcy_unlock() -/* (un)lock critical section when accessing Object Dictionary */ +/** @brief Enter critical section for Object Dictionary access. */ void canopen_od_lock(void); +/** @brief Exit critical section for Object Dictionary access. */ void canopen_od_unlock(void); -#define CO_LOCK_OD(CAN_MODULE) canopen_od_lock() -#define CO_UNLOCK_OD(CAN_MODULE) canopen_od_unlock() -/* Synchronization between CAN receive and message processing threads. */ +/** @brief Macro used by CANopenNode to guard TX critical section. */ +#define CO_LOCK_CAN_SEND(CAN_MODULE) canopen_send_lock() +/** @brief Macro used by CANopenNode to release TX critical section. */ +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) canopen_send_unlock() +/** @brief Macro used by CANopenNode to guard EMCY critical section. */ +#define CO_LOCK_EMCY(CAN_MODULE) canopen_emcy_lock() +/** @brief Macro used by CANopenNode to release EMCY critical section. */ +#define CO_UNLOCK_EMCY(CAN_MODULE) canopen_emcy_unlock() +/** @brief Macro used by CANopenNode to guard OD critical section. */ +#define CO_LOCK_OD(CAN_MODULE) canopen_od_lock() +/** @brief Macro used by CANopenNode to release OD critical section. */ +#define CO_UNLOCK_OD(CAN_MODULE) canopen_od_unlock() +/** @} */ + +/* -------------------------------------------------------------------------- */ +/* Inter-thread synchronization */ +/* -------------------------------------------------------------------------- */ + +/** + * @name RX/TX synchronization flags + * @brief Simple flag protocol between ISR/worker contexts. + * + * These macros implement a trivial "new data" flag with a memory barrier + * placeholder. On Zephyr, @ref CO_MemoryBarrier resolves to an empty macro by + * default; define it to an architecture-appropriate barrier if needed. + * @{ + */ +/** @brief Memory barrier used by flag setters/getters (no-op by default). */ #define CO_MemoryBarrier() + +/** + * @brief Test the "new data" flag. + * @param rxNew An lvalue flag variable (pointer-sized). + * @retval true New data is available. + * @retval false No new data. + */ #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) + +/** + * @brief Set the "new data" flag (with barrier). + * @param rxNew An lvalue flag variable (pointer-sized). + */ #define CO_FLAG_SET(rxNew) \ { \ CO_MemoryBarrier(); \ rxNew = (void *)1L; \ } + +/** + * @brief Clear the "new data" flag (with barrier). + * @param rxNew An lvalue flag variable (pointer-sized). + */ #define CO_FLAG_CLEAR(rxNew) \ { \ CO_MemoryBarrier(); \ rxNew = NULL; \ } +/** @} */ + +/** @} */ /* end of co_driver_target */ #ifdef __cplusplus } diff --git a/zephyr/include/CO_zephyr_config.h b/zephyr/include/CO_zephyr_config.h index 45666e86..b2db2a45 100644 --- a/zephyr/include/CO_zephyr_config.h +++ b/zephyr/include/CO_zephyr_config.h @@ -1,3 +1,27 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr-to-CANopenNode configuration bridge. + * + * Aggregates Zephyr Kconfig (CONFIG_*) options into CANopenNode's + * CO_CONFIG_* compile-time flags and related values, so the stack can + * be configured from prj.conf and devicetree. + * + * @file CO_zephyr_config.h + * @author BitConcepts, LLC + * @copyright 2025 BitConcepts, LLC + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ #ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_CONFIG_H #define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_CONFIG_H @@ -6,31 +30,65 @@ extern "C" { #endif -#include /* CONFIG_* */ -#include /* IS_ENABLED, BIT */ - -/* Small helpers to OR flags conditionally */ +#include +#include + +/** + * @defgroup co_zephyr_config Zephyr ↔ CANopenNode configuration bridge + * @brief Map Zephyr Kconfig to CANopenNode @c CO_CONFIG_* flags and constants. + * + * This header is a thin preprocessor bridge. It reads Zephyr @c CONFIG_* symbols + * and produces the @c CO_CONFIG_* bitmasks and values that CANopenNode expects at + * compile time. Include this header before including CANopenNode modules (or in a + * central integration translation unit) so that the configuration takes effect. + * + * ### Helpers + * - ::ZBIT(flag, cfgsym) — Expands to @p flag when @p cfgsym is enabled, otherwise 0. + * - ::ZVAL(cfgsym) — Expands to the value of @p cfgsym (numeric or 0 if unset). + * + * ### Notes + * - Requires Zephyr’s @c . + * - All @c CONFIG_CANOPENNODE_* options come from your project’s @c prj.conf/Kconfig. + * + * @{ + */ + +/** @name Helper macros + * @brief Small utilities for conditional bit composition. + * @{ + */ +/** @brief Conditionally OR a flag when a Kconfig symbol is enabled. */ #define ZBIT(flag, cfgsym) (IS_ENABLED(cfgsym) ? (flag) : 0) +/** @brief Yield the value of a Kconfig symbol (or 0 if not defined). */ #define ZVAL(cfgsym) (cfgsym) +/** @} */ -/* ---------- NMT / Heartbeat producer ---------- */ +/** @name NMT / Heartbeat Producer + * @brief Configure CANopen NMT producer behavior and control bits. + * @{ + */ +/** @brief Bitmask for CANopenNode NMT configuration derived from Kconfig. */ #define CO_CONFIG_NMT \ (ZBIT(CO_CONFIG_NMT_CALLBACK_CHANGE, CONFIG_CANOPENNODE_NMT_CALLBACK_CHANGE) | \ ZBIT(CO_CONFIG_NMT_MASTER, CONFIG_CANOPENNODE_NMT_MASTER) | \ ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_NMT_CALLBACK) | \ ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_NMT_TIMERNEXT)) -/* Optional: first heartbeat delay (ms) if you wire it in app code */ +/** @brief Optional initial heartbeat delay in milliseconds. */ #define CO_NMT_FIRST_HB_TIME_MS CONFIG_CANOPENNODE_NMT_FIRST_HB_TIME_MS -/* NMT state machine control flags */ +/** @brief Convenience booleans for NMT control policy (source: Kconfig). */ #define CO_NMT_STARTUP_TO_OPERATIONAL IS_ENABLED(CONFIG_CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL) #define CO_NMT_ERR_ON_BUSOFF_HB IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_ON_BUSOFF_HB) #define CO_NMT_ERR_ON_ERR_REG IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_ON_ERR_REG) #define CO_NMT_ERR_TO_STOPPED IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_TO_STOPPED) #define CO_NMT_ERR_FREE_TO_OPERATIONAL IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL) -/* NMT startup/control bits as plain defines you use in app/init glue */ +/** + * @brief Composite NMT startup/control mask you can pass to CANopenNode init. + * + * Combines the policy booleans above into the bitmask expected by CANopenNode. + */ #define CO_CONFIG_NMT_CONTROL \ ((ZBIT(CO_NMT_STARTUP_TO_OPERATIONAL, CO_NMT_STARTUP_TO_OPERATIONAL) ? CO_NMT_STARTUP \ : 0) | \ @@ -40,8 +98,12 @@ extern "C" { (ZBIT(CO_NMT_ERR_FREE_TO_OPERATIONAL, CO_NMT_ERR_FREE_TO_OPERATIONAL) \ ? CO_NMT_ERR_FREE_TO_OPERATIONAL \ : 0)) +/** @} */ -/* ---------- Heartbeat consumer ---------- */ +/** @name Heartbeat Consumer + * @brief Configure HB consumer behavior, callbacks, and OD options. + * @{ + */ #define CO_CONFIG_HB_CONS \ (ZBIT(CO_CONFIG_HB_CONS_ENABLE, CONFIG_CANOPENNODE_HB_CONS_ENABLE) | \ ZBIT(CO_CONFIG_HB_CONS_CALLBACK_CHANGE, CONFIG_CANOPENNODE_HB_CONS_CALLBACK_CHANGE) | \ @@ -50,8 +112,12 @@ extern "C" { ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_HB_CONS_CALLBACK) | \ ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_HB_CONS_TIMERNEXT) | \ ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_HB_CONS_OD_DYNAMIC)) +/** @} */ -/* ---------- Node Guarding ---------- */ +/** @name Node Guarding + * @brief Enable/Configure node guarding master/slave roles and timing. + * @{ + */ #define CO_CONFIG_NODE_GUARDING \ (ZBIT(CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE, \ CONFIG_CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE) | \ @@ -59,12 +125,16 @@ extern "C" { CONFIG_CANOPENNODE_NODE_GUARDING_MASTER_ENABLE) | \ ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_NODE_GUARDING_TIMERNEXT)) -/* Count */ +/** @brief Number of guarded nodes when acting as a master (if provided). */ #ifdef CONFIG_CANOPENNODE_NODE_GUARDING_MASTER_COUNT #define CO_CONFIG_NODE_GUARDING_MASTER_COUNT CONFIG_CANOPENNODE_NODE_GUARDING_MASTER_COUNT #endif +/** @} */ -/* ---------- Emergency ---------- */ +/** @name Emergency (EM) + * @brief Configure emergency producer/consumer and status bits. + * @{ + */ #define CO_CONFIG_EM \ (ZBIT(CO_CONFIG_EM_PRODUCER, CONFIG_CANOPENNODE_EM_PRODUCER) | \ ZBIT(CO_CONFIG_EM_PROD_CONFIGURABLE, CONFIG_CANOPENNODE_EM_PROD_CONFIGURABLE) | \ @@ -75,15 +145,20 @@ extern "C" { ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_EM_CALLBACK) | \ ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_EM_TIMERNEXT)) +/** @brief Size of error status bits array. */ #define CO_CONFIG_EM_ERR_STATUS_BITS_COUNT CONFIG_CANOPENNODE_EM_ERR_STATUS_BITS_COUNT -/* Optional default conditions (you’ll map these to your CO_CONFIG_ERR_CONDITION_* usage) */ +/** @brief Optional default error-condition enables (application maps them as needed). */ #define CO_CONFIG_ERR_CONDITION_CURRENT IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_CURRENT) #define CO_CONFIG_ERR_CONDITION_VOLTAGE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_VOLTAGE) #define CO_CONFIG_ERR_CONDITION_TEMPERATURE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_TEMPERATURE) #define CO_CONFIG_ERR_CONDITION_DEV_PROFILE IS_ENABLED(CONFIG_CANOPENNODE_ERR_CONDITION_DEV_PROFILE) +/** @} */ -/* ---------- SDO server ---------- */ +/** @name SDO Server + * @brief Configure SDO server features, callbacks, and timeouts. + * @{ + */ #define CO_CONFIG_SDO_SRV \ (ZBIT(CO_CONFIG_SDO_SRV_SEGMENTED, CONFIG_CANOPENNODE_SDO_SERVER_SEGMENTED) | \ ZBIT(CO_CONFIG_SDO_SRV_BLOCK, CONFIG_CANOPENNODE_SDO_SERVER_BLOCK) | \ @@ -91,10 +166,16 @@ extern "C" { ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_SDO_SERVER_TIMERNEXT) | \ ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_SDO_SERVER_OD_DYNAMIC)) +/** @brief Server buffer size in bytes. */ #define CO_CONFIG_SDO_SRV_BUFFER_SIZE CONFIG_CANOPENNODE_SDO_SERVER_BUFFER_SIZE +/** @brief SDO server timeout in ms. */ #define CO_CONFIG_SDO_SRV_TIMEOUT_MS CONFIG_CANOPENNODE_SDO_SERVER_TIMEOUT_MS +/** @} */ -/* ---------- SDO client ---------- */ +/** @name SDO Client + * @brief Configure SDO client features, callbacks, and timeouts. + * @{ + */ #define CO_CONFIG_SDO_CLI \ (ZBIT(CO_CONFIG_SDO_CLI_ENABLE, CONFIG_CANOPENNODE_SDO_CLIENT_ENABLE) | \ ZBIT(CO_CONFIG_SDO_CLI_SEGMENTED, CONFIG_CANOPENNODE_SDO_CLIENT_SEGMENTED) | \ @@ -104,17 +185,27 @@ extern "C" { ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_SDO_CLIENT_TIMERNEXT) | \ ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_SDO_CLIENT_OD_DYNAMIC)) +/** @brief Client buffer size in bytes. */ #define CO_CONFIG_SDO_CLI_BUFFER_SIZE CONFIG_CANOPENNODE_SDO_CLIENT_BUFFER_SIZE +/** @brief SDO client timeout in ms. */ #define CO_CONFIG_SDO_CLI_TIMEOUT_MS CONFIG_CANOPENNODE_SDO_CLIENT_TIMEOUT_MS +/** @} */ -/* ---------- TIME ---------- */ +/** @name TIME object + * @brief Configure TIME producer/consumer and callbacks. + * @{ + */ #define CO_CONFIG_TIME \ (ZBIT(CO_CONFIG_TIME_ENABLE, CONFIG_CANOPENNODE_TIME_ENABLE) | \ ZBIT(CO_CONFIG_TIME_PRODUCER, CONFIG_CANOPENNODE_TIME_PRODUCER) | \ ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_TIME_CALLBACK) | \ ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_TIME_OD_DYNAMIC)) +/** @} */ -/* ---------- SYNC / PDO ---------- */ +/** @name SYNC / PDO + * @brief Configure SYNC and PDO features, timers, and callbacks. + * @{ + */ #define CO_CONFIG_SYNC \ (ZBIT(CO_CONFIG_SYNC_ENABLE, CONFIG_CANOPENNODE_SYNC_ENABLE) | \ ZBIT(CO_CONFIG_SYNC_PRODUCER, CONFIG_CANOPENNODE_SYNC_PRODUCER) | \ @@ -132,22 +223,35 @@ extern "C" { ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_PDO_CALLBACK) | \ ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_PDO_TIMERNEXT) | \ ZBIT(CO_CONFIG_FLAG_OD_DYNAMIC, CONFIG_CANOPENNODE_PDO_OD_DYNAMIC)) +/** @} */ -/* ---------- Storage ---------- */ +/** @name Storage + * @brief Enable storage glue and select backends. + * @{ + */ +/** @brief Master switch for CANopenNode storage module. */ #define CO_CONFIG_STORAGE (ZBIT(CO_CONFIG_STORAGE_ENABLE, CONFIG_CANOPENNODE_STORAGE_ENABLE)) -/* Backend selection for your storage glue */ +/** @brief Backend selections for the integration layer. */ #define CO_STORAGE_BACKEND_SETTINGS IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_BACKEND_SETTINGS) #define CO_STORAGE_BACKEND_RAM IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_BACKEND_RAM) #define CO_STORAGE_BACKEND_NONE IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE) +/** @} */ -/* ---------- LEDs ---------- */ +/** @name LEDs (CiA 303-3) + * @brief Enable LED state machine and optional callback. + * @{ + */ #define CO_CONFIG_LEDs \ (ZBIT(CO_CONFIG_LEDS_ENABLE, CONFIG_CANOPENNODE_LEDS_ENABLE) | \ ZBIT(CO_CONFIG_LEDS_CALLBACK, CONFIG_CANOPENNODE_LEDS_CALLBACK) | \ ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_LEDS_TIMERNEXT)) +/** @} */ -/* ---------- SRDO / GFC ---------- */ +/** @name SRDO / GFC + * @brief Safety-related data objects and global fail-safe command. + * @{ + */ #define CO_CONFIG_GFC \ (ZBIT(CO_CONFIG_GFC_ENABLE, CONFIG_CANOPENNODE_GFC_ENABLE) | \ ZBIT(CO_CONFIG_GFC_CONSUMER, CONFIG_CANOPENNODE_GFC_CONSUMER) | \ @@ -159,17 +263,26 @@ extern "C" { ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_SRDO_CALLBACK) | \ ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_SRDO_TIMERNEXT)) +/** @brief Minimum SRDO Tx delay in microseconds. */ #define CO_CONFIG_SRDO_MINIMUM_DELAY CONFIG_CANOPENNODE_SRDO_MINIMUM_DELAY +/** @} */ -/* ---------- LSS ---------- */ +/** @name LSS (Layer Setting Services) + * @brief Configure LSS master/slave and callbacks. + * @{ + */ #define CO_CONFIG_LSS \ (ZBIT(CO_CONFIG_LSS_SLAVE, CONFIG_CANOPENNODE_LSS_SLAVE) | \ ZBIT(CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND, \ CONFIG_CANOPENNODE_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND) | \ ZBIT(CO_CONFIG_LSS_MASTER, CONFIG_CANOPENNODE_LSS_MASTER) | \ ZBIT(CO_CONFIG_FLAG_CALLBACK_PRE, CONFIG_CANOPENNODE_LSS_CALLBACK)) +/** @} */ -/* ---------- Gateway (CiA 309) ---------- */ +/** @name ASCII Gateway (CiA 309) + * @brief Configure ASCII gateway features and buffer sizes. + * @{ + */ #define CO_CONFIG_GTW \ (ZBIT(CO_CONFIG_GTW_MULTI_NET, CONFIG_CANOPENNODE_GTW_MULTI_NET) | \ ZBIT(CO_CONFIG_GTW_ASCII, CONFIG_CANOPENNODE_GTW_ASCII) | \ @@ -181,40 +294,73 @@ extern "C" { ZBIT(CO_CONFIG_GTW_ASCII_PRINT_HELP, CONFIG_CANOPENNODE_GTW_ASCII_PRINT_HELP) | \ ZBIT(CO_CONFIG_GTW_ASCII_PRINT_LEDS, CONFIG_CANOPENNODE_GTW_ASCII_PRINT_LEDS)) +/** @brief Block download loop count for the gateway. */ #define CO_CONFIG_GTW_BLOCK_DL_LOOP CONFIG_CANOPENNODE_GTW_BLOCK_DL_LOOP +/** @brief ASCII gateway communication buffer size in bytes. */ #define CO_CONFIG_GTWA_COMM_BUF_SIZE CONFIG_CANOPENNODE_GTWA_COMM_BUF_SIZE +/** @brief ASCII gateway log buffer size in bytes. */ #define CO_CONFIG_GTWA_LOG_BUF_SIZE CONFIG_CANOPENNODE_GTWA_LOG_BUF_SIZE +/** @} */ -/* ---------- CRC16 ---------- */ +/** @name CRC16 + * @brief Enable/route CRC16 implementation used by various modules. + * @{ + */ #define CO_CONFIG_CRC16 \ (ZBIT(CO_CONFIG_CRC16_ENABLE, CONFIG_CANOPENNODE_CRC16_ENABLE) | \ ZBIT(CO_CONFIG_CRC16_EXTERNAL, CONFIG_CANOPENNODE_CRC16_EXTERNAL)) +/** @} */ -/* ---------- FIFO ---------- */ +/** @name FIFO + * @brief Configure FIFO utilities and optional ASCII helpers. + * @{ + */ #define CO_CONFIG_FIFO \ (ZBIT(CO_CONFIG_FIFO_ENABLE, CONFIG_CANOPENNODE_FIFO_ENABLE) | \ ZBIT(CO_CONFIG_FIFO_ALT_READ, CONFIG_CANOPENNODE_FIFO_ALT_READ) | \ ZBIT(CO_CONFIG_FIFO_CRC16_CCITT, CONFIG_CANOPENNODE_FIFO_CRC16_CCITT) | \ ZBIT(CO_CONFIG_FIFO_ASCII_COMMANDS, CONFIG_CANOPENNODE_FIFO_ASCII_COMMANDS) | \ ZBIT(CO_CONFIG_FIFO_ASCII_DATATYPES, CONFIG_CANOPENNODE_FIFO_ASCII_DATATYPES)) +/** @} */ -/* ---------- Trace ---------- */ +/** @name Trace + * @brief Configure trace recorder and integer type selection. + * @{ + */ #define CO_CONFIG_TRACE \ (ZBIT(CO_CONFIG_TRACE_ENABLE, CONFIG_CANOPENNODE_TRACE_ENABLE) | \ ZBIT(CO_CONFIG_TRACE_OWN_INTTYPES, CONFIG_CANOPENNODE_TRACE_OWN_INTTYPES)) +/** @} */ -/* ---------- Debug ---------- */ +/** @name Debug + * @brief Enable debug features at module granularity. + * @{ + */ #define CO_CONFIG_DEBUG \ (ZBIT(CO_CONFIG_DEBUG_COMMON, CONFIG_CANOPENNODE_DEBUG_COMMON) | \ ZBIT(CO_CONFIG_DEBUG_SDO_CLIENT, CONFIG_CANOPENNODE_DEBUG_SDO_CLIENT) | \ ZBIT(CO_CONFIG_DEBUG_SDO_SERVER, CONFIG_CANOPENNODE_DEBUG_SDO_SERVER)) +/** @} */ -/* ---------- TX workqueue (Zephyr integration) ---------- */ +/** @name Zephyr integration (TX workqueue) + * @brief Configure TX worker thread resources used by the integration. + * @{ + */ +/** @brief Stack size for the CAN TX workqueue thread. */ #define CO_TX_WQ_STACK_SIZE CONFIG_CANOPENNODE_TX_WORKQUEUE_STACK_SIZE +/** @brief Priority for the CAN TX workqueue thread. */ #define CO_TX_WQ_PRIORITY CONFIG_CANOPENNODE_TX_WORKQUEUE_PRIORITY +/** @} */ -/* ---------- EDS path ---------- */ +/** @name EDS/DCF + * @brief Path to the EDS/DCF file used by the application (if any). + * @{ + */ +/** @brief File system path to the node’s EDS file. */ #define CO_EDS_FILE_PATH CONFIG_CANOPENNODE_EDS_FILE_PATH +/** @} */ + +/** @} */ /* end of co_zephyr_config */ #ifdef __cplusplus } diff --git a/zephyr/include/CO_zephyr_integration.h b/zephyr/include/CO_zephyr_integration.h index f0567c0e..55527cc0 100644 --- a/zephyr/include/CO_zephyr_integration.h +++ b/zephyr/include/CO_zephyr_integration.h @@ -1,15 +1,26 @@ -/** - * @file - * @brief CANopenNode Zephyr integration: RT thread & mainline processing +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr-to-CANopenNode integration API. + * + * Provides a runtime bridge to start/stop the CANopen stack with a selected + * Zephyr CAN device, Node-ID, and bitrate, enabling control from code in + * addition to prj.conf and devicetree. + * + * @file CO_zephyr_integration.h + * @author BitConcepts, LLC + * @copyright 2025 BitConcepts, LLC * - * This header defines the public interface for the Zephyr-native CANopenNode - * integration, providing lifecycle management and scheduler integration. + * This file is part of , a CANopen Stack. * - * - **RT thread**: Runs SYNC, RPDO, TPDO processing on PRE-callback events. - * - **Mainline (CO_process)**: Executes periodically to handle internal state machine. - * - **Auto-start**: Supports auto-initialization via SYS_INIT. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at * - * @note Requires generated `OD.c/h` and a configured CAN device (via devicetree or Kconfig). + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ #ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_INTEGRATION_H @@ -27,39 +38,99 @@ extern "C" { #endif /** - * @brief Start CANopenNode with explicit device, node ID, and bitrate + * @defgroup co_zephyr_integration CANopenNode ↔ Zephyr runtime integration + * @brief Start/stop helpers that wire CANopenNode to a Zephyr CAN device. + * + * This API brings up the full CANopenNode stack on Zephyr with an explicitly + * chosen CAN device, Node-ID, and bitrate. It complements Kconfig/devicetree + * configuration by allowing programmatic control at runtime. + * + * ### Behavior + * - Initializes CANopenNode (CAN, NMT, SDO, PDO, etc.) and enters normal mode. + * - Optionally creates/uses an RT processing thread (SYNC/RPDO/TPDO) if enabled + * by Kconfig in the integration module. + * - Supports optional persistent parameter storage when configured. + * + * ### Devicetree / Kconfig + * - If @p can_dev is `NULL`, the default CAN device is resolved from + * `DT_CHOSEN(zephyr_canbus)`. + * - When @p bitrate_kbps is 0, the bitrate falls back to the Kconfig default + * (e.g., `CONFIG_CANOPENNODE_BITRATE_KBPS`). + * + * ### Typical usage + * @code{.c} + * #include "CO_zephyr_integration.h" + * + * void app_start_canopen(void) + * { + * // Use default CAN dev from DT, Node-ID from Kconfig, default bitrate + * int rc = co_canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, 0); + * if (rc != 0) { + * printk("CANopen start failed: %d\n", rc); + * return; + * } * - * Initializes the full CANopen stack and RT thread using the given CAN device, - * node ID (1–127), and bitrate in kbps. If bitrate is 0, Kconfig default is used. + * if (co_canopen_is_running()) { + * printk("CANopen is up\n"); + * } + * } * - * @param can_dev CAN device pointer (NULL = use default from the device tree) - * @param node_id CANopen Node ID (1–127) - * @param bitrate_kbps CAN bitrate in kbps (0 = use default from Kconfig) + * void app_stop_canopen(void) + * { + * co_canopen_stop(); + * } + * @endcode * - * @retval 0 Success - * @retval -ENODEV Invalid or unready device - * @retval -EINVAL Invalid arguments or CANopen error - * @retval -EALREADY Already running - * @retval -ENOMEM Allocation or storage error + * @{ + */ + +/** + * @brief Start CANopenNode with explicit device, node ID, and bitrate. + * + * Initializes the full CANopen stack and (optionally) the real-time processing + * thread using the given CAN device, CANopen Node-ID (1–127), and bitrate in + * kbps. When @p can_dev is `NULL`, the CAN device is taken from devicetree + * (the `zephyr,canbus` chosen node). When @p bitrate_kbps is 0, the Kconfig + * default is used. + * + * @param[in] can_dev Zephyr CAN device pointer + * (`NULL` = use DT chosen `zephyr,canbus`). + * @param[in] node_id CANopen Node-ID in the range 1–127. + * @param[in] bitrate_kbps CAN bitrate in kbps + * (0 = use Kconfig default, e.g., `CONFIG_CANOPENNODE_BITRATE_KBPS`). + * + * @retval 0 Success. + * @retval -ENODEV Invalid, missing, or not-ready CAN device. + * @retval -EINVAL Invalid arguments (e.g., Node-ID out of range) or CANopen init error. + * @retval -EALREADY Integration is already running. + * @retval -ENOMEM Allocation or storage initialization error. + * + * @note If persistent storage is enabled via Kconfig, initialization may + * perform a one-time load and can surface backend errors via logs. + * @pre Zephyr kernel is initialized; @p can_dev (if non-NULL) is ready. + * @warning Do not call from ISR context. */ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps); /** - * @brief Stop the CANopen stack and worker thread + * @brief Stop the CANopen stack and worker thread. * - * Tears down all internal structures and disables the CAN controller. - * Safe to call multiple times. + * Tears down all internal structures, disables the CAN controller, and + * stops the integration’s RT processing thread if present. Safe to call + * multiple times; subsequent calls become no-ops. */ void co_canopen_stop(void); /** - * @brief Check if the CANopen stack is running + * @brief Query whether the CANopen stack is running. * - * @retval true The stack is active and running - * @retval false The stack is stopped or not yet initialized + * @retval true The stack is active and running. + * @retval false The stack is stopped or not yet initialized. */ bool co_canopen_is_running(void); +/** @} */ /* end of co_zephyr_integration */ + #ifdef __cplusplus } #endif diff --git a/zephyr/include/CO_zephyr_leds.h b/zephyr/include/CO_zephyr_leds.h index c0c8ab6c..a33216ac 100644 --- a/zephyr/include/CO_zephyr_leds.h +++ b/zephyr/include/CO_zephyr_leds.h @@ -1,3 +1,28 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr-to-CANopenNode LED bridge. + * + * Mirrors the computed CANopen RUN/ERR LED states (from CO_LEDs) to Zephyr GPIOs + * using devicetree aliases. Respects ACTIVE_LOW/HIGH via DT flags and provides + * a callback-based hookup and one-shot sync utility. + * + * @file CO_zephyr_leds.h + * @author BitConcepts, LLC + * @copyright 2025 BitConcepts, LLC + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + #ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_LEDS_H #define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_LEDS_H @@ -12,30 +37,99 @@ extern "C" { #endif /** - * Initialize GPIOs for CANopen LEDs using DT aliases: - * - alias: co_led_run -> RUN/green LED - * - alias: co_led_err -> ERR/red LED + * @defgroup co_zephyr_leds CANopenNode ↔ Zephyr LED helpers + * @brief Mirror CANopen RUN/ERR LED states to Zephyr GPIOs. + * + * This helper binds the CANopen LED state machine from @ref CO_LEDs_t (CiA 303-3) + * to two Zephyr-controlled GPIOs selected via **devicetree aliases**: + * + * - `co_led_run` → RUN (green) LED + * - `co_led_err` → ERR (red) LED + * + * The active level and inversion are taken from the GPIO flags on the aliased + * pins (e.g., `GPIO_ACTIVE_LOW`). Pins are configured as `GPIO_OUTPUT_INACTIVE` + * during initialization. After you connect the callback, each call to + * `CO_LEDs_process()` updates the physical pins to match the synthesized + * CANopen RUN/ERR indicators (bit @ref CO_LED_CANopen in `LEDgreen`/`LEDred`). + * + * ### Devicetree requirements + * Provide two DT aliases that point to GPIOs, for example: + * @code{.dts} + * / { + * aliases { + * co_led_run = &led0; + * co_led_err = &led1; + * }; + * }; + * + * &led0 { gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; status = "okay"; }; + * &led1 { gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; status = "okay"; }; + * @endcode + * + * ### Typical usage + * @code{.c} + * // After CO_LEDs_init(&leds, ...): + * int rc = co_zephyr_leds_init_dt_aliases(); + * if (rc == 0) { + * co_zephyr_leds_connect_callback(&leds); + * // Optionally mirror immediately: + * co_zephyr_leds_sync_once(&leds); + * } + * @endcode + * + * @{ + */ + +/** + * @brief Initialize GPIOs for CANopen LEDs using devicetree aliases. + * + * Resolves the `co_led_run` and `co_led_err` DT aliases to GPIO pins, + * validates their controller readiness, and configures both pins as + * `GPIO_OUTPUT_INACTIVE`. Active level and inversion are honored from + * each pin's devicetree flags (e.g., `GPIO_ACTIVE_LOW`). * - * Pins are configured OUTPUT_INACTIVE. Active level/inversion - * is taken from devicetree flags (GPIO_ACTIVE_LOW/HIGH). + * @note This function does **not** register any callbacks; call + * co_zephyr_leds_connect_callback() after @ref CO_LEDs_init(). * - * @return 0 on success, -ENODEV if aliases missing or devices not ready, - * or a negative errno from gpio_pin_configure_dt(). + * @retval 0 Success. + * @retval -ENODEV A referenced GPIO controller is not ready, or required DT + * aliases are missing/disabled. + * @retval <0 A negative errno returned by @ref gpio_pin_configure_dt. */ int co_zephyr_leds_init_dt_aliases(void); /** - * Register the CANopen LED callback so LED states are mirrored to hardware - * after each CO_LEDs_process() update. Call once after CO_LEDs_init(). + * @brief Connect the CANopen LED callback to mirror states to hardware. + * + * Registers an internal callback via @ref CO_LEDs_registerCallback so that + * every @ref CO_LEDs_process update pushes the synthesized RUN/ERR states + * to the configured GPIOs. Safe to call once after @ref CO_LEDs_init. + * + * @param[in] leds Pointer to a valid @ref CO_LEDs_t instance. + * + * @note This function does not reconfigure GPIOs; call + * co_zephyr_leds_init_dt_aliases() first. + * @note If @p leds is `NULL`, the function returns immediately. */ void co_zephyr_leds_connect_callback(CO_LEDs_t *leds); /** - * Optional: immediately mirror the current CO LEDs once (e.g., right after init). - * Safe to call anytime. + * @brief One-shot mirror of the current CANopen LED state to GPIOs. + * + * Evaluates the current `LEDgreen`/`LEDred` fields and writes the corresponding + * RUN/ERR outputs once. Useful immediately after initialization to ensure the + * physical LEDs reflect the current state without waiting for the next + * @ref CO_LEDs_process call. + * + * @param[in] leds Pointer to a valid @ref CO_LEDs_t instance. + * + * @note If the GPIOs were not initialized (hardware not ready) or @p leds is + * `NULL`, the call is ignored. */ void co_zephyr_leds_sync_once(CO_LEDs_t *leds); +/** @} */ /* end of co_zephyr_leds */ + #ifdef __cplusplus } #endif diff --git a/zephyr/include/CO_zephyr_storage.h b/zephyr/include/CO_zephyr_storage.h index 042b669e..5e6bbd15 100644 --- a/zephyr/include/CO_zephyr_storage.h +++ b/zephyr/include/CO_zephyr_storage.h @@ -20,8 +20,10 @@ * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND. + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ #ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_STORAGE_H @@ -34,19 +36,96 @@ extern "C" { #endif /** - * @brief Initialize CANopen storage using Zephyr backends (Settings, RAM). + * @defgroup co_zephyr_storage CANopenNode ↔ Zephyr storage bridge + * @brief Persistence glue for OD parameters using Zephyr backends. * - * This implementation uses the selected Kconfig storage backend. + * This interface wires CANopenNode's storage object (@ref CO_storage_t) to a Zephyr + * persistence backend chosen via Kconfig (e.g., Settings, RAM). It enables: * - * @param storage Pointer to CO_storage object - * @param CANmodule CAN module used for logging and sync - * @param OD_1010_StoreParameters Object Dictionary entry for OD 1010 - * @param OD_1011_RestoreDefaultParam Object Dictionary entry for OD 1011 - * @param entries Array of storage entries - * @param entriesCount Number of entries in the array - * @param storageInitError Pointer to variable to store error index (if any) + * - Loading parameters at boot/reset (OD 0x1011 semantics). + * - Storing parameters on request (OD 0x1010 semantics). + * - Optional restore-to-default handling. * - * @return CO_ReturnError_t CO_ERROR_NO on success, otherwise error code + * ### Kconfig overview + * Select one of the integration backends at build time (symbol names may vary + * per project): + * - `CONFIG_CANOPENNODE_STORAGE_BACKEND_SETTINGS` — Zephyr Settings API + * - `CONFIG_CANOPENNODE_STORAGE_BACKEND_RAM` — RAM-backed mock (volatile) + * - `CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE` — disabled/no-op + * + * Also enable the storage module: + * - `CONFIG_CANOPENNODE_STORAGE_ENABLE` + * + * ### Typical usage + * @code{.c} + * #include "CO_zephyr_storage.h" + * // ... + * CO_storage_t storage; + * uint32_t storage_err = 0; + * + * CO_ReturnError_t ret = co_zephyr_storage_init( + * &storage, + * CO->CANmodule, + * OD_ENTRY_H1010_storeParameters, + * OD_ENTRY_H1011_restoreDefaultParameters, + * storageEntries, entryCount, + * &storage_err + * ); + * + * if (ret != CO_ERROR_NO) { + * // handle init error + * } + * if (storage_err != 0) { + * // optional: report backend-specific error code + * } + * @endcode + * + * @note This header only declares the initialization function. Subsequent + * load/store operations are driven by the stack via OD 0x1010/0x1011 + * access (e.g., from SDO writes, gateway commands, or application code). + * + * @{ + */ + +/** + * @brief Initialize CANopen storage using a Zephyr-selected backend. + * + * Binds a @ref CO_storage_t instance to the configured Zephyr persistence + * provider and connects it to the Object Dictionary entries for: + * - OD 0x1010: Store Parameters + * - OD 0x1011: Restore Default Parameters + * + * Depending on the selected backend, this may create or open storage areas, + * validate metadata, and perform a one-time load of persisted values into RAM. + * + * @param[out] storage Pointer to a @ref CO_storage_t object to + * initialize. + * @param[in] CANmodule Active @ref CO_CANmodule_t used for + * timing/logging. + * @param[in] OD_1010_StoreParameters OD entry pointer for 0x1010 (Store). + * @param[in] OD_1011_RestoreDefaultParam OD entry pointer for 0x1011 (Restore Defaults). + * @param[in] entries Array of @ref CO_storage_entry_t mappings to + * persist. + * @param[in] entriesCount Number of elements in @p entries. + * @param[out] storageInitError Optional backend-specific error code (0 on + * success). + * + * @retval CO_ERROR_NO Success. + * @retval CO_ERROR_ILLEGAL_ARGUMENT + * Any required pointer is NULL or arguments are inconsistent. + * @retval CO_ERROR_OUT_OF_MEMORY + * Allocation failed in the selected backend. + * @retval CO_ERROR_DATA_CORRUPT + * Stored data failed integrity/format checks + * (backend-specific). + * @retval CO_ERROR_INVALID_STATE + * Backend not available or not initialized correctly. + * + * @note When `storageInitError` is non-NULL, it will contain an implementation- + * specific error value that can be logged or surfaced via EMCY/status bits. + * A value of 0 indicates no backend error. + * @note This function does not take ownership of @p entries; they must remain + * valid for the lifetime of @p storage. */ CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, @@ -54,6 +133,8 @@ CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *C CO_storage_entry_t *entries, uint8_t entriesCount, uint32_t *storageInitError); +/** @} */ /* end of co_zephyr_storage */ + #ifdef __cplusplus } #endif diff --git a/zephyr/module.yml b/zephyr/module.yml index 6f8d917c..8a0e620d 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -1,8 +1,42 @@ -# modules/canopennode/zephyr/module.yml +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 BitConcepts, LLC +# +# Zephyr module manifest for CANopenNode. +# +# Declares this repository as a Zephyr module so the build system can: +# - discover the module during west/cmake processing, +# - add the module's CMake/Kconfig entry points, +# - install Python requirements needed by the module tooling. +# +# @file modules/canopennode/zephyr/module.yml +# @author BitConcepts, LLC +# +# This file is part of , a CANopen Stack. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +# Usage notes: +# - Place this file at: modules/canopennode/zephyr/module.yml (or equivalent module path). +# - 'build.cmake: zephyr' tells Zephyr to use the module's CMake entry point located at +# ${ZEPHYR_CURRENT_MODULE_DIR}/CMakeLists.txt. +# - 'build.kconfig' points to the module’s top-level Kconfig (relative to the module root). +# - 'package-managers.pip.requirement-files' lists pip requirement files (relative paths from +# the module root) that Zephyr tooling may install to support code generation or other tasks. + name: canopennode + build: - cmake: zephyr + cmake: zephyr/CMakeLists.txt kconfig: zephyr/Kconfig + package-managers: pip: requirement-files: From 3bfd83247c28d809afa6a94114f76b9c63ac953b Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 13 Aug 2025 17:39:00 -0400 Subject: [PATCH 506/520] Improves Zephyr driver and integration layers Refactors the Zephyr CANopen driver for robustness and clarity. Adds comprehensive documentation to key functions, enhancing maintainability and understanding. Improves TX handling with a dedicated work queue for retries and fixes a bug where bufferFull was not cleared on tx success. Enhances RT thread signaling and adds pre-callback mechanism for faster SYNC/RPDO processing. Adds devicetree assertions for LEDs and improves storage backend with value preloading and validation. --- zephyr/CO_zephyr_driver.c | 53 ++++++++++++++++++++++++++++++++-- zephyr/CO_zephyr_integration.c | 36 +++++++++++++++++++++-- zephyr/CO_zephyr_leds.c | 7 +++++ zephyr/CO_zephyr_storage.c | 20 +++++++++---- 4 files changed, 106 insertions(+), 10 deletions(-) diff --git a/zephyr/CO_zephyr_driver.c b/zephyr/CO_zephyr_driver.c index aaf69422..c920dad2 100644 --- a/zephyr/CO_zephyr_driver.c +++ b/zephyr/CO_zephyr_driver.c @@ -90,6 +90,13 @@ inline void canopen_od_unlock(void) k_mutex_unlock(&canopen_co_mutex); } +/* + * Detach all installed RX filters from the Zephyr CAN device for this module. + * + * Notes: + * - Uses filter_id == -ENOSPC as a sentinel for "no filter installed". + * - Safe to call multiple times; non-installed entries are skipped. + */ static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule) { uint_fast16_t i; @@ -108,6 +115,17 @@ static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule) } } +/* + * RX callback bound to hardware filters. + * + * Matches incoming frames against the software buffer table (priority order), + * performs optional RTR handling, repacks data into CO_CANrxMsg_t, and invokes + * the registered CANopen rx callback for the first matching buffer. + * + * Context: + * - Called from Zephyr CAN driver context (may be IRQ or thread depending on driver). + * - Keep it short; heavy work is done later by the stack. + */ static void canopen_rx_callback(const struct device *dev, struct can_frame *frame, void *user_data) { CO_CANmodule_t *CANmodule = (CO_CANmodule_t *)user_data; @@ -125,8 +143,10 @@ static void canopen_rx_callback(const struct device *dev, struct can_frame *fram continue; } + /* Masked identifier match */ if (((frame->id ^ buffer->ident) & buffer->mask) == 0U) { #ifdef CONFIG_CAN_ACCEPT_RTR + /* If buffer expects RTR, ignore non-RTR frames. */ if ((buffer->ident & 0x800) && ((frame->flags & CAN_FRAME_RTR) == 0U)) { continue; } @@ -137,11 +157,18 @@ static void canopen_rx_callback(const struct device *dev, struct can_frame *fram if (buffer->CANrx_callback != NULL) { buffer->CANrx_callback(buffer->object, &rxMsg); } - break; + break; /* first match wins */ } } } +/* + * TX completion callback from the Zephyr CAN driver. + * + * On success: marks that the first TX was sent and schedules a work item to + * retry any queued frames. On error: logs a warning and still schedules retry + * so buffered frames get another chance. + */ static void canopen_tx_callback(const struct device *dev, int error, void *arg) { CO_CANmodule_t *CANmodule = arg; @@ -159,9 +186,20 @@ static void canopen_tx_callback(const struct device *dev, int error, void *arg) CANmodule->firstCANtxMessage = false; } + /* Defer follow-up sends to a work queue to avoid busy loops here. */ k_work_submit_to_queue(&canopen_tx_workq, &canopen_tx_queue.work); } +/* + * Work-queue handler that retries sending buffered CAN frames. + * + * Attempts to flush the software TX ring into the controller. If the driver + * reports -EAGAIN (mailbox busy), we stop and the next completion will resubmit + * this work again. + * + * Concurrency: + * - Protected by CO_LOCK_CAN_SEND() to synchronize with CO_CANsend(). + */ static void canopen_tx_retry(struct k_work *item) { struct canopen_tx_work_container *container = @@ -187,12 +225,14 @@ static void canopen_tx_retry(struct k_work *item) err = can_send(dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); if (err == -EAGAIN) { + /* Controller is busy; stop here and try again later. */ LOG_DBG("tx busy, will retry"); break; } else if (err != 0) { LOG_ERR("tx send failed (err %d)", err); } + /* Clear the bufferFull flag on success or non-retryable error. */ buffer->bufferFull = false; } } @@ -463,8 +503,8 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) } } -/* Get error counters from the module. If necessary, function may use different way to determine - * errors. */ +/* File-local error counters (placeholder). If your CAN driver exposes real + * error counters, wire them here and into CO_CANmodule_process(). */ static uint_fast16_t rxErrors = 0, txErrors = 0, overflow = 0; void CO_CANmodule_process(CO_CANmodule_t *CANmodule) @@ -520,6 +560,13 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) } } +/* + * Module initialization hook. + * + * Creates and starts the dedicated work queue used for deferred TX retries, + * names its thread (handy for debugging), and initializes the work item. + * Runs at SYS_INIT(APPLICATION) stage. + */ static int canopen_init(void) { k_work_queue_start(&canopen_tx_workq, canopen_tx_workq_stack, diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 2f0975b3..34c3d9c1 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -45,8 +45,11 @@ LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); #define CAN_NODE DT_CHOSEN(zephyr_canbus) #define CAN_BITRATE_KBPS (DT_PROP(CAN_NODE, bitrate) / 1000U) -/* ---------- Module state ---------- */ - +/* ---------- Module state ---------- + * CO / CO_storage are the runtime stack handles. + * g_running is an atomic "stack is active" flag used by the RT thread and signalers. + * rt_sem wakes the RT thread from pre-callbacks and periodic processing. + */ static CO_t *CO = NULL; static CO_storage_t *CO_storage = NULL; static atomic_t g_running; @@ -55,6 +58,10 @@ K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ /* ---------- Helpers ---------- */ +/* + * Pre-callback used by SYNC/RPDO to poke the RT thread. + * Gives the semaphore only when the stack is marked running. + */ static void rt_signal_cb(void *object) { ARG_UNUSED(object); @@ -63,6 +70,10 @@ static void rt_signal_cb(void *object) } } +/* + * Register a common pre-callback for SYNC and all RPDOs. + * This lets incoming traffic promptly wake the RT thread. + */ static void enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) { CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); @@ -73,6 +84,22 @@ static void enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) /* ---------- RT Thread: SYNC/RPDO/TPDO ---------- */ #if IS_ENABLED(CANOPENNODE_RT_THREAD) +/* + * Real-time CANopen processing thread. + * + * Responsibilities: + * - Waits on a semaphore or timeout. + * - Calls CO_process() (mainline timing and housekeeping). + * - Runs SYNC/RPDO/TPDO processing in a tight, low-latency section. + * + * Timing: + * - Uses uptime (ms) for CO_process() dt. + * - Uses CPU cycle delta for RT section dt to improve precision. + * + * Concurrency: + * - OD access is protected with CO_LOCK_OD()/CO_UNLOCK_OD(). + * - Thread runs continuously but only acts when the stack is running. + */ static void canopen_rt_thread(void *p1, void *p2, void *p3) { ARG_UNUSED(p1); @@ -129,6 +156,7 @@ static void canopen_rt_thread(void *p1, void *p2, void *p3) } } +/* Spawn the real-time processing thread at boot; priority/stack are Kconfig-driven. */ K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, canopen_rt_thread, NULL, NULL, NULL, CONFIG_CANOPENNODE_RT_THREAD_PRIORITY, 0, 0); @@ -282,6 +310,10 @@ bool co_canopen_is_running(void) return atomic_get(&g_running); } +/* + * System init hook. + * Optionally auto-starts CANopen at POST_KERNEL if configured via Kconfig. + */ static int co_canopen_init_sys(const struct device *unused) { ARG_UNUSED(unused); diff --git a/zephyr/CO_zephyr_leds.c b/zephyr/CO_zephyr_leds.c index 3821cb0a..1f883a8b 100644 --- a/zephyr/CO_zephyr_leds.c +++ b/zephyr/CO_zephyr_leds.c @@ -33,14 +33,21 @@ #define RUN_NODE DT_ALIAS(co_led_run) #define ERR_NODE DT_ALIAS(co_led_err) +/* Ensure the expected DT aliases exist and are enabled. */ BUILD_ASSERT(DT_NODE_HAS_STATUS(RUN_NODE, okay), "DT alias 'co-led-run' missing or disabled"); BUILD_ASSERT(DT_NODE_HAS_STATUS(ERR_NODE, okay), "DT alias 'co-led-err' missing or disabled"); +/* File-local GPIO descriptors resolved from devicetree. */ static const struct gpio_dt_spec LED_RUN = GPIO_DT_SPEC_GET(RUN_NODE, gpios); static const struct gpio_dt_spec LED_ERR = GPIO_DT_SPEC_GET(ERR_NODE, gpios); +/* Set true after successful pin configuration; guards callbacks before init. */ static bool hw_ready; +/* + * CANopen LED callback. + * Maps CO_LEDs_t state bits to the two GPIOs. Safe to call anytime after init. + */ static void co_zephyr_leds_cb(CO_LEDs_t *leds, void *user_arg) { ARG_UNUSED(user_arg); diff --git a/zephyr/CO_zephyr_storage.c b/zephyr/CO_zephyr_storage.c index 0c25425d..ec6e2d77 100644 --- a/zephyr/CO_zephyr_storage.c +++ b/zephyr/CO_zephyr_storage.c @@ -39,7 +39,10 @@ LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); #include #endif -/* Store OD entry (1010) */ +/* Store callback for OD 0x1010 "Store Parameters". + * Persists one configured storage entry using the selected backend. + * Returns ODR_OK on success, ODR_HW on backend failure. + */ static ODR_t store_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { #if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) @@ -65,7 +68,10 @@ static ODR_t store_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) return ODR_OK; } -/* Restore OD entry (1011) */ +/* Restore callback for OD 0x1011 "Restore Default Parameters". + * Clears any persisted value for the entry (or no-ops for RAM), + * so defaults take effect after the next load. + */ static ODR_t restore_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { #if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) @@ -90,7 +96,9 @@ static ODR_t restore_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule return ODR_OK; } -/* Initialization */ +/* Initialize CO_storage with Zephyr-backed store/restore hooks and + * optionally load initial values from the selected backend. + */ CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *CANmodule, OD_entry_t *OD_1010_StoreParameters, OD_entry_t *OD_1011_RestoreDefaultParam, @@ -104,16 +112,18 @@ CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *C CO_ReturnError_t ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, store_zephyr, restore_zephyr, entries, entriesCount); - if (ret != CO_ERROR_NO) { return ret; } + /* Mark "no index error" unless we detect a bad entry below. */ *storageInitError = 0; + /* Optionally preload values from the backend into RAM. */ for (uint8_t i = 0; i < entriesCount; i++) { CO_storage_entry_t *entry = &entries[i]; + /* Basic entry validation: require addr/len and subindex >= 2. */ if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { *storageInitError = i; return CO_ERROR_ILLEGAL_ARGUMENT; @@ -127,7 +137,7 @@ CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *C LOG_DBG("No settings found for %s", key); } #elif defined(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) - // RAM-only, already loaded from default or boot values + /* RAM-only backend: nothing to load; defaults already in place. */ #else LOG_WRN("No valid storage backend selected — skipping restore for 0x%02X", entry->subIndexOD); From f880c9facafeae692865564809367be40ec2151f Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 13 Aug 2025 19:44:47 -0400 Subject: [PATCH 507/520] Adds initial CANopenNode documentation This commit introduces the initial documentation for CANopenNode, providing a comprehensive overview of the project. It details: - CANopen protocol stack characteristics - Zephyr RTOS integration - Related projects - Documentation and contribution guidelines - File structure - Object dictionary editor - Device support information --- README.md | 378 ++++++--- tools/CMakeLists.txt | 59 -- tools/example.eds | 1806 ------------------------------------------ zephyr/Kconfig | 4 +- 4 files changed, 261 insertions(+), 1986 deletions(-) delete mode 100644 tools/CMakeLists.txt delete mode 100644 tools/example.eds diff --git a/README.md b/README.md index 34b18dd4..a41dfe21 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,181 @@ -CANopenNode -=========== +# CANopenNode CANopenNode is free and open source CANopen protocol stack. -CANopen is the internationally standardized (EN 50325-4) ([CiA301](https://www.can-cia.org/cia-groups/technical-documents)) higher-layer protocol for embedded control system built on top of CAN. For more information on CANopen see http://www.can-cia.org/ +CANopen is the internationally standardized (EN 50325-4) ([CiA301](https://www.can-cia.org/cia-groups/technical-documents)) higher-layer protocol for embedded control system built on top of CAN. For more information on CANopen see [http://www.can-cia.org/](http://www.can-cia.org/) CANopenNode is written in ANSI C in object-oriented way. It runs on different microcontrollers, as standalone application or with RTOS. Variables (communication, device, custom) are collected in CANopen Object Dictionary and are accessible from both: C code and from CANopen network. -CANopenNode homepage is https://github.com/CANopenNode/CANopenNode +CANopenNode homepage is [https://github.com/CANopenNode/CANopenNode](https://github.com/CANopenNode/CANopenNode) This is version 4 of CANopenNode with new Object Dictionary implementation. For older versions `git checkout` branches `v1.3-master` or `v2.0-master`. +## Characteristics -Characteristics ---------------- ### CANopen - - [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen-internal-device-architecture/) offers clear and flexible organisation of any variables. Variables can be accessed directly or via read/write functions. - - [NMT](https://www.can-cia.org/can-knowledge/network-management/) slave to start, stop, reset device. Simple NMT master. - - [Heartbeat](https://www.can-cia.org/can-knowledge/error-control-protocols) producer/consumer error control for monitoring of CANopen devices. An older alternative, 'node guarding', is also available. - - [PDO](https://www.can-cia.org/can-knowledge/pdo-protocol/) for broadcasting process data with high priority and no protocol overhead. Variables from Object Dictionary can be dynamically mapped to the TPDO, which is then transmitted according to communication rules and received as RPDO by another device. - - [SDO](https://www.can-cia.org/can-knowledge/sdo-protocol/) server enables expedited, segmented and block transfer access to all Object Dictionary variables inside CANopen device. - - [SDO](https://www.can-cia.org/can-knowledge/sdo-protocol/) client can access any Object Dictionary variable on any CANopen device inside the network. - - [Emergency](https://www.can-cia.org/can-knowledge/special-function-protocols/) message producer/consumer. - - [Sync](https://www.can-cia.org/can-knowledge/special-function-protocols/) producer/consumer enables network synchronized transmission of the PDO objects, etc. - - [Time-stamp](https://www.can-cia.org/can-knowledge/special-function-protocols/) producer/consumer enables date and time synchronization in millisecond resolution. - - [LSS](https://www.can-cia.org/can-knowledge/cia-305-layer-setting-services-lss/) CANopen node-id and bitrate setup, master and slave, LSS fastscan. - - [CANopen gateway](https://www.can-cia.org/can-knowledge/cia-309-series-accessing-canopen-via-tcp/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. - - [CANopen Safety](https://standards.globalspec.com/std/1284438/en-50325-5), EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks - - [CANopen Conformance Test Tool](https://www.can-cia.org/services/canopen-conformance-test-tool/) passed. + +* [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen-internal-device-architecture/) offers clear and flexible organisation of any variables. Variables can be accessed directly or via read/write functions. +* [NMT](https://www.can-cia.org/can-knowledge/network-management/) slave to start, stop, reset device. Simple NMT master. +* [Heartbeat](https://www.can-cia.org/can-knowledge/error-control-protocols) producer/consumer error control for monitoring of CANopen devices. An older alternative, 'node guarding', is also available. +* [PDO](https://www.can-cia.org/can-knowledge/pdo-protocol/) for broadcasting process data with high priority and no protocol overhead. Variables from Object Dictionary can be dynamically mapped to the TPDO, which is then transmitted according to communication rules and received as RPDO by another device. +* [SDO](https://www.can-cia.org/can-knowledge/sdo-protocol/) server enables expedited, segmented and block transfer access to all Object Dictionary variables inside CANopen device. +* [SDO](https://www.can-cia.org/can-knowledge/sdo-protocol/) client can access any Object Dictionary variable on any CANopen device inside the network. +* [Emergency](https://www.can-cia.org/can-knowledge/special-function-protocols/) message producer/consumer. +* [Sync](https://www.can-cia.org/can-knowledge/special-function-protocols/) producer/consumer enables network synchronized transmission of the PDO objects, etc. +* [Time-stamp](https://www.can-cia.org/can-knowledge/special-function-protocols/) producer/consumer enables date and time synchronization in millisecond resolution. +* [LSS](https://www.can-cia.org/can-knowledge/cia-305-layer-setting-services-lss/) CANopen node-id and bitrate setup, master and slave, LSS fastscan. +* [CANopen gateway](https://www.can-cia.org/can-knowledge/cia-309-series-accessing-canopen-via-tcp/), CiA309-3 Ascii command interface for NMT master, LSS master and SDO client. +* [CANopen Safety](https://standards.globalspec.com/std/1284438/en-50325-5), EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks +* [CANopen Conformance Test Tool](https://www.can-cia.org/services/canopen-conformance-test-tool/) passed. ### Other - - [Suitable for 16-bit microcontrollers and above](#device-support) - - [Multithreaded, real-time](#canopenNode-flowchart) - - [Object Dictionary editor](#object-dictionary-editor) - - Non-volatile storage for Object Dictionary or other variables. Automatic or controlled by standard CANopen commands, configurable. - - [Power saving possible](#power-saving) - - [Bootloader possible](https://github.com/CANopenNode/CANopenNode/issues/111) (for firmware update) - - -Related projects ----------------- - - [CANopenNode](https://github.com/CANopenNode/CANopenNode) (this project): CANopen protocol stack, base for CANopen device. It contains no device specific code (drivers), which must be added separately for each target system. An example shows the basic principles, compiles on any system, but does not connect to any CAN hardware. - - [CANopenDemo](https://github.com/CANopenNode/CANopenDemo): Demo device with CANopenNode and different target systems, tutorial and testing tools. - - [CANopenNode.github.io](https://github.com/CANopenNode/CANopenNode.github.io): Html documentation, compiled by doxygen, for CANopenDemo, CANopenNode and other devices, available also online: https://canopennode.github.io - - [CANopenEditor](https://github.com/CANopenNode/CANopenEditor): Object Dictionary editor, external GUI tool for editing CANopen Object Dictionary for custom device. It generates C source code, electronic data sheet and documentation for the device. It is a fork from [libedssharp](https://github.com/robincornelius/libedssharp). - - [CANopenLinux](https://github.com/CANopenNode/CANopenLinux): CANopenNode on Linux devices. It can be a basic CANopen device or more advanced with commander functionalities. - - [CANopenSTM32](https://github.com/CANopenNode/CanOpenSTM32): CANopenNode on STM32 microcontrollers. - - [Analog Devices Inc.](https://github.com/Analog-Devices-MSDK/CANopenADI): CANopenNode on Analog Devices Inc. MAX32xx microcontrollers. - - [CANopenPIC](https://github.com/CANopenNode/CANopenPIC): CANopenNode on PIC microcontrollers from Microchip. Works with 16-bit and 32 bit devices. Includes example for Arduino style [Max32](https://reference.digilentinc.com/reference/microprocessor/max32/start) board. - - [doc/deviceSupport.md](doc/deviceSupport.md): List of other implementations of CANopenNode on different devices. - - -Documentation, support and contributions ----------------------------------------- + +* [Suitable for 16-bit microcontrollers and above](#device-support) +* [Multithreaded, real-time](#canopennode-flowchart) +* [Object Dictionary editor](#object-dictionary-editor) +* Non-volatile storage for Object Dictionary or other variables. Automatic or controlled by standard CANopen commands, configurable. +* [Power saving possible](#power-saving) +* [Bootloader possible](https://github.com/CANopenNode/CANopenNode/issues/111) (for firmware update) + +## Zephyr RTOS integration (module) + +CANopenNode ships an in-tree Zephyr module for first-class Zephyr support. + +**Location:** `modules/canopennode/zephyr/` +**What you get:** + +* **Native CAN driver backend** (`CO_zephyr_driver.c`) that adapts CANopenNode to Zephyr’s `drivers/can` API (bitrate/mode, filters, TX callbacks, error status). +* **Runtime control API** (`CO_zephyr_integration.c/.h`): start/stop the stack from your app (`co_canopen_start()/co_canopen_stop()`), pick CAN device, Node-ID, and bitrate at runtime. +* **Optional RT thread** to run SYNC/RPDO/TPDO with low jitter (configurable with Kconfig). +* **LED bridge** (`CO_zephyr_leds.c/.h`) that mirrors CANopen RUN/ERR LEDs to GPIOs via DT aliases `co-led-run` and `co-led-err`. +* **Storage** (`CO_zephyr_storage.c/.h`) that plugs CANopenNode’s storage object into Zephyr subsystems (e.g., `settings`) or a RAM-only mode. + +### Quick start (West-based app) + +1. **Add the module to your west manifest:** + + ```yaml + manifest: + projects: + - name: CANopenNode + url: https://github.com/CANopenNode/CANopenNode.git + path: modules/canopennode + revision: + ``` + +2. **Enable features in `prj.conf`:** + + ```ini + # Core + CONFIG_CAN=y + + # CANopenNode (Zephyr module) + CONFIG_CANOPENNODE=y + CONFIG_CANOPENNODE_INIT_NODE_ID=1 # default if not passed at runtime + + # Optional LED bridge + CONFIG_GPIO=y + CONFIG_CANOPENNODE_LEDS_ENABLE=y + + # Optional storage via Zephyr settings + CONFIG_SETTINGS=y + CONFIG_SETTINGS_RUNTIME=y + CONFIG_CANOPENNODE_STORAGE_ENABLE=y + CONFIG_CANOPENNODE_STORAGE_BACKEND_SETTINGS=y + ``` + +3. **Devicetree setup (CAN + LED aliases):** + + ```dts + / { + aliases { + zephyr,canbus = &can0; /* or set in your board .dts */ + co-led-run = &led0; + co-led-err = &led1; + }; + }; + /* Ensure &can0 has bitrate etc. or rely on runtime start() parameters */ + ``` + +4. **Start from your application (optional, if not auto-starting):** + + ```c + #include + #include "CO_zephyr_integration.h" + + void main(void) + { + /* Use chosen CAN (zephyr,canbus), Node-ID 1, 500 kbit/s. + * Pass NULL to use DT_CHOSEN(zephyr_canbus). + */ + (void)co_canopen_start(NULL, 1, 500); + /* ... your app ... */ + } + ``` + + If `CONFIG_CANOPENNODE_RT_THREAD_AUTO_START=y` is enabled (default), the stack can also auto-start after kernel init using defaults from Kconfig/DT. + +5. **LEDs** + + * Provide `co-led-run` and `co-led-err` DT aliases as shown above. + * If you integrate CANopen directly (without the runtime auto-wiring), call: + + ```c + co_zephyr_leds_init_dt_aliases(); + co_zephyr_leds_connect_callback(CO->LEDs); + ``` + + (Requires access to your `CO_t` instance.) + +6. **Storage** + + * With `CONFIG_CANOPENNODE_STORAGE_ENABLE=y` and `CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS=y`, + standard store/restore commands (OD 0x1010/0x1011) persist parameters via Zephyr `settings`. + +> Tip: You can also pass an explicit `const struct device *can_dev` to `co_canopen_start()` if you don’t want to rely on `zephyr,canbus`. + +## Related projects + +* [CANopenNode](https://github.com/CANopenNode/CANopenNode) (this project): CANopen protocol stack, base for CANopen device. It contains no device specific code (drivers), which must be added separately for each target system. An example shows the basic principles, compiles on any system, but does not connect to any CAN hardware. +* [CANopenDemo](https://github.com/CANopenNode/CANopenDemo): Demo device with CANopenNode and different target systems, tutorial and testing tools. +* [CANopenNode.github.io](https://github.com/CANopenNode/CANopenNode.github.io): Html documentation, compiled by doxygen, for CANopenDemo, CANopenNode and other devices, available also online: [https://canopennode.github.io](https://canopennode.github.io) +* [CANopenEditor](https://github.com/CANopenNode/CANopenEditor): Object Dictionary editor, external GUI tool for editing CANopen Object Dictionary for custom device. It generates C source code, electronic data sheet and documentation for the device. It is a fork from [libedssharp](https://github.com/robincornelius/libedssharp). +* [CANopenLinux](https://github.com/CANopenNode/CANopenLinux): CANopenNode on Linux devices. It can be a basic CANopen device or more advanced with commander functionalities. +* [CANopenSTM32](https://github.com/CANopenNode/CanOpenSTM32): CANopenNode on STM32 microcontrollers. +* [Analog Devices Inc.](https://github.com/Analog-Devices-MSDK/CANopenADI): CANopenNode on Analog Devices Inc. MAX32xx microcontrollers. +* [CANopenPIC](https://github.com/CANopenNode/CANopenPIC): CANopenNode on PIC microcontrollers from Microchip. Works with 16-bit and 32 bit devices. Includes example for Arduino style [Max32](https://reference.digilentinc.com/reference/microprocessor/max32/start) board. +* [doc/deviceSupport.md](doc/deviceSupport.md): List of other implementations of CANopenNode on different devices. + +## Documentation, support and contributions + All code is documented in the source header files. Some additional documents are in `doc` directory. -To generate complete html documentation, run [doxygen](https://www.doxygen.nl/index.html) in the project base directory: `sudo apt install doxygen graphviz pdf2svg; doxygen > /dev/null` +To generate complete html documentation, run [doxygen](https://www.doxygen.nl/index.html) in the project base directory: + +```bash +sudo apt install doxygen graphviz pdf2svg +doxygen > /dev/null +``` -Complete generated documentation is also available online: https://canopennode.github.io +Complete generated documentation is also available online: [https://canopennode.github.io](https://canopennode.github.io) + +> **Note:** If you want Zephyr-port APIs (driver/integration/LEDs/storage) included in Doxygen, ensure the `zephyr/` directory is listed in `Doxyfile` `INPUT` (or keep the provided defaults if already present). Tutorial, demo device and tests are available in [CANopenDemo](https://github.com/CANopenNode/CANopenDemo) repository. -Report issues on https://github.com/CANopenNode/CANopenNode/issues +Report issues on [https://github.com/CANopenNode/CANopenNode/issues](https://github.com/CANopenNode/CANopenNode/issues) Contributions are welcome. Best way to contribute your code is to fork a project, modify it and then send a pull request. Please follow the [Recommended C style and coding rules](https://github.com/MaJerle/c-code-style), use .clang-format file for automatic code formatting. The CANopenNode files conform to the [MISRA C:2012](https://www.misra.org.uk) guidelines, with some noted exceptions, as indicated in [MISRA.md](MISRA.md). -CANopenNode flowchart ---------------------- +## CANopenNode flowchart + Flowchart of a typical CANopenNode implementation: -~~~ + +``` ----------------------- | Program start | ----------------------- @@ -105,83 +208,27 @@ Flowchart of a typical CANopenNode implementation: | | | | | - May cyclically call | | | | | | application code. | ---------------------- ------------------------ ----------------------- -~~~ +``` -All code of the CANopenNode is non-blocking. Code in source files is collected into objects. Parts of the code can be enabled/disabled, so only files and parts of code can be used, which are required for the project. See stack configuration in 301/CO_config.h file. +All code of the CANopenNode is non-blocking. Code in source files is collected into objects. Parts of the code can be enabled/disabled, so only files and parts of code can be used, which are required for the project. See stack configuration in 301/CO\_config.h file. For most efficiency code can run in different thread as seen in above flowchart. This is suitable for microcontrollers. It is also possible to run everything from single thread, as available on Linux devices. Code includes mechanisms, which triggers processing of OD objects when necessary. In CANopen initialization section all CANopen objects are initialized. In run time CANopen objects are processed cyclically. -Files CANopen.h and CANopen.c is a joint of all CANopen objects. It may seems complex, but offers some flexibility and is suitable for most common configurations of the CANopen objects. CANopen objects can be defined in global space or can be dynamically allocated. Object dictionary can be used default (OD.h/.c files), but configuration with multiple object dictionaries is also possible by using the #CO_config_t structure. CANopen.h and CANopen.c files can also be only a reference for more customized implementation of CANopenNode based device. +Files CANopen.h and CANopen.c is a joint of all CANopen objects. It may seems complex, but offers some flexibility and is suitable for most common configurations of the CANopen objects. CANopen objects can be defined in global space or can be dynamically allocated. Object dictionary can be used default (OD.h/.c files), but configuration with multiple object dictionaries is also possible by using the #CO\_config\_t structure. CANopen.h and CANopen.c files can also be only a reference for more customized implementation of CANopenNode based device. Object Dictionary is a collection of all network accessible variables and offers most flexible usage. OD variables can be initialized by object dictionary or application can specify own read/write access functions for specific OD variables. Groups of OD variables are also able to be stored to non-volatile memory, either on command or automatically. +## Object dictionary editor -File structure --------------- - - **301/** - CANopen application layer and communication profile. - - **CO_config.h** - Configuration macros for CANopenNode. - - **CO_driver.h** - Interface between CAN hardware and CANopenNode. - - **CO_ODinterface.h/.c** - CANopen Object Dictionary interface. - - **CO_Emergency.h/.c** - CANopen Emergency protocol. - - **CO_HBconsumer.h/.c** - CANopen Heartbeat consumer protocol. - - **CO_NMT_Heartbeat.h/.c** - CANopen Network management and Heartbeat producer protocol. - - **CO_PDO.h/.c** - CANopen Process Data Object protocol. - - **CO_SDOclient.h/.c** - CANopen Service Data Object - client protocol (master functionality). - - **CO_SDOserver.h/.c** - CANopen Service Data Object - server protocol. - - **CO_SYNC.h/.c** - CANopen Synchronisation protocol (producer and consumer). - - **CO_TIME.h/.c** - CANopen Time-stamp protocol. - - **CO_fifo.h/.c** - Fifo buffer for SDO and gateway data transfer. - - **crc16-ccitt.h/.c** - Calculation of CRC 16 CCITT polynomial. - - **303/** - CANopen Recommendation - - **CO_LEDs.h/.c** - CANopen LED Indicators - - **304/** - CANopen Safety Related Data Object, as specified by EN 50325-5:2010 - - **CO_SRDO.h/.c** - CANopen Safety-relevant Data Object protocol. - - **CO_GFC.h/.c** - CANopen Global Failsafe Command (producer and consumer). - - **305/** - CANopen layer setting services (LSS) and protocols. - - **CO_LSS.h** - CANopen Layer Setting Services protocol (common). - - **CO_LSSmaster.h/.c** - CANopen Layer Setting Service - master protocol. - - **CO_LSSslave.h/.c** - CANopen Layer Setting Service - slave protocol. - - **309/** - CANopen access from other networks. - - **CO_gateway_ascii.h/.c** - Ascii mapping: NMT master, LSS master, SDO client. - - **storage/** - - **CO_storage.h/.c** - CANopen data storage base object. - - **CO_storageEeprom.h/.c** - CANopen data storage object for storing data into block device (eeprom). - - **CO_eeprom.h** - Eeprom interface for use with CO_storageEeprom, functions are target system specific. - - **extra/** - - **CO_trace.h/.c** - CANopen trace object for recording variables over time. - - **example/** - Directory with basic example, should compile on any system. - - **CO_driver_target.h** - Example hardware definitions for CANopenNode. - - **CO_driver_blank.c** - Example blank interface for CANopenNode. - - **main_blank.c** - Mainline and other threads - example template. - - **CO_storageBlank.h/.c** - Example blank demonstration for data storage to non-volatile memory. - - **Makefile** - Makefile for example. - - **DS301_profile.xpd** - CANopen device description file for DS301. It includes also CANopenNode specific properties. This file is also available in Profiles in Object dictionary editor. - - **DS301_profile.eds**, **DS301_profile.md** - Standard CANopen EDS file and markdown documentation file, automatically generated from DS301_profile.xpd. - - **OD.h/.c** - CANopen Object dictionary source files, automatically generated from DS301_profile.xpd. - - **doc/** - Directory with documentation - - **CHANGELOG.md** - Change Log file. - - **deviceSupport.md** - Information about supported devices. - - **objectDictionary.md** - Description of CANopen object dictionary interface. - - **CANopenNode.png** - Little icon. - - **html** - Directory with documentation - must be generated by Doxygen. - - **CANopen.h/.c** - Initialization and processing of CANopen objects, suitable for common configurations. - - **Doxyfile** - Configuration file for the documentation generator *doxygen*. - - **LICENSE** - License. - - **MISRA.md** - MISRA C:2012 conformance information. - - **README.md** - This file. - - -Object dictionary editor ------------------------- Object Dictionary is one of the most essential parts of CANopen. To customize the Object Dictionary it is necessary to use external application: [CANopenEditor](https://github.com/CANopenNode/CANopenEditor). Binaries are also available there. In Linux it runs with mono, which is available by default on Ubuntu. -In program, in preferences, set exporter to "CANopenNode_V4". Then start new project or open the existing project file. +In program, in preferences, set exporter to "CANopenNode\_V4". Then start new project or open the existing project file. -Many project file types are supported, EDS, XDD v1.0, XDD v1.1, old custom XML format. Generated project file can then be saved in XDD v1.1 file format (xmlns="http://www.canopen.org/xml/1.1"). Project file can also be exported to other formats, it can be used to generate documentation and CANopenNode source files for Object Dictionary. +Many project file types are supported, EDS, XDD v1.0, XDD v1.1, old custom XML format. Generated project file can then be saved in XDD v1.1 file format (xmlns="[http://www.canopen.org/xml/1.1](http://www.canopen.org/xml/1.1)"). Project file can also be exported to other formats, it can be used to generate documentation and CANopenNode source files for Object Dictionary. If new project was started, then `DS301_profile.xpd` may be inserted. If existing (old) project is edited, then existing `Communication Specific Parameters` may be deleted and then new `DS301_profile.xpd` may be inserted. Alternative is editing existing communication parameters with observation to Object Dictionary Requirements By CANopenNode in [objectDictionary.md](doc/objectDictionary.md). @@ -189,38 +236,131 @@ To clone, add or delete, select object(s) and use right click. Some knowledge of CANopenNode includes some custom properties inside standard project file. See [objectDictionary.md](doc/objectDictionary.md) for more information. +### EDS → C generator (eds-utils) + +For teams that keep the Object Dictionary as an **EDS** file, this repo includes a small **CLI wrapper** around the Python package **`eds-utils`** so you can generate `OD.h`/`OD.c` without any GUI dependencies (handy on Windows). Usage example: + +```bash +python eds2c_wrapper.py generate path/to/device.eds -o build/od +``` + +The wrapper simply forwards all arguments to `eds_utils.eds2c`’s CLI entry point and avoids GTK/GUI modules. + +#### Build integration (CMake) + +A helper `CMakeLists.txt` is provided that will: + +* Ensure `eds-utils` is available (auto-installs it with `pip` if missing), +* Run `eds2c_wrapper.py` to generate `OD.h` and `OD.c` from your EDS, +* Place outputs in the build directory and export `CO_OD_H`, `CO_OD_C`, and `CO_OD_DIR` cache variables you can add to your build, +* Expose a `generate_od` target that depends on the generated files. + +This lets you regenerate the Object Dictionary whenever the EDS changes, fully integrated into your normal build. + +> Tip: If you prefer to drive generation manually, you can call `eds2c_wrapper.py` directly as shown above; it accepts the same arguments as the upstream `eds2c` tool. + +## File structure + +* **301/** – CANopen application layer and communication profile. + + * **CO\_config.h** – Configuration macros for CANopenNode. + * **CO\_driver.h** – Interface between CAN hardware and CANopenNode. + * **CO\_ODinterface.h/.c** – CANopen Object Dictionary interface. + * **CO\_Emergency.h/.c** – CANopen Emergency protocol. + * **CO\_HBconsumer.h/.c** – CANopen Heartbeat consumer protocol. + * **CO\_NMT\_Heartbeat.h/.c** – CANopen Network management and Heartbeat producer protocol. + * **CO\_PDO.h/.c** – CANopen Process Data Object protocol. + * **CO\_SDOclient.h/.c** – CANopen Service Data Object – client protocol (master functionality). + * **CO\_SDOserver.h/.c** – CANopen Service Data Object – server protocol. + * **CO\_SYNC.h/.c** – CANopen Synchronisation protocol (producer and consumer). + * **CO\_TIME.h/.c** – CANopen Time-stamp protocol. + * **CO\_fifo.h/.c** – Fifo buffer for SDO and gateway data transfer. + * **crc16-ccitt.h/.c** – Calculation of CRC 16 CCITT polynomial. +* **303/** – CANopen Recommendation + + * **CO\_LEDs.h/.c** – CANopen LED Indicators +* **304/** – CANopen Safety Related Data Object, as specified by EN 50325-5:2010 + + * **CO\_SRDO.h/.c** – CANopen Safety-relevant Data Object protocol. + * **CO\_GFC.h/.c** – CANopen Global Failsafe Command (producer and consumer). +* **305/** – CANopen layer setting services (LSS) and protocols. + + * **CO\_LSS.h** – CANopen Layer Setting Services protocol (common). + * **CO\_LSSmaster.h/.c** – CANopen Layer Setting Service – master protocol. + * **CO\_LSSslave.h/.c** – CANopen Layer Setting Service – slave protocol. +* **309/** – CANopen access from other networks. + + * **CO\_gateway\_ascii.h/.c** – Ascii mapping: NMT master, LSS master, SDO client. +* **storage/** + + * **CO\_storage.h/.c** – CANopen data storage base object. + * **CO\_storageEeprom.h/.c** – CANopen data storage object for storing data into block device (eeprom). + * **CO\_eeprom.h** – Eeprom interface for use with CO\_storageEeprom, functions are target system specific. +* **extra/** + + * **CO\_trace.h/.c** – CANopen trace object for recording variables over time. +* **example/** – Directory with basic example, should compile on any system. + + * **CO\_driver\_target.h** – Example hardware definitions for CANopenNode. + * **CO\_driver\_blank.c** – Example blank interface for CANopenNode. + * **main\_blank.c** – Mainline and other threads – example template. + * **CO\_storageBlank.h/.c** – Example blank demonstration for data storage to non-volatile memory. + * **Makefile** – Makefile for example. + * **DS301\_profile.xpd** – CANopen device description file for DS301. It includes also CANopenNode specific properties. This file is also available in Profiles in Object dictionary editor. + * **DS301\_profile.eds**, **DS301\_profile.md** – Standard CANopen EDS file and markdown documentation file, automatically generated from DS301\_profile.xpd. + * **OD.h/.c** – CANopen Object dictionary source files, automatically generated from DS301\_profile.xpd. +* **doc/** – Directory with documentation + + * **CHANGELOG.md** – Change Log file. + * **deviceSupport.md** – Information about supported devices. + * **objectDictionary.md** – Description of CANopen object dictionary interface. + * **CANopenNode.png** – Little icon. + * **html** – Directory with documentation – must be generated by Doxygen. +* **modules/canopennode/zephyr/** – Zephyr module integration + + * **module.yml** – Zephyr module metadata. + * **Kconfig** – Kconfig options for the Zephyr port. + * **src/** – Zephyr backend sources: `CO_zephyr_driver.c`, `CO_zephyr_integration.c`, `CO_zephyr_leds.c`, `CO_zephyr_storage.c`, etc. + * **include/** – Public headers for the Zephyr integration (e.g. `CO_zephyr_integration.h`). +* **eds2c\_wrapper.py** – CLI wrapper that calls `eds_utils.eds2c` to convert an EDS into `OD.h/OD.c` (Windows-friendly, no GUI deps). +* **CMakeLists.txt** – Helper target `generate_od` that installs `eds-utils` if needed and generates `OD.h/OD.c` from your EDS; exports `CO_OD_H/CO_OD_C/CO_OD_DIR`. +* **CANopen.h/.c** – Initialization and processing of CANopen objects, suitable for common configurations. +* **Doxyfile** – Configuration file for the documentation generator *doxygen*. +* **LICENSE** – License. +* **MISRA.md** – MISRA C:2012 conformance information. +* **README.md** – This file. + +## Device support -Device support --------------- CANopenNode can run on many different devices. Each device (or microcontroller) must have own interface to CANopenNode. CANopenNode can run with or without operating system. It is not practical to have all device interfaces in a single project. Interfaces to other microcontrollers are in separate projects. See [deviceSupport.md](doc/deviceSupport.md) for list of known device interfaces. +## Some details -Some details ------------- ### RTR + RTR (remote transmission request) is a feature of CAN bus. Usage of RTR is not recommended for CANopen. RTR PDO is not implemented in CANopenNode. ### Error control + When node is started (in NMT operational state), it is allowed to send or receive Process Data Objects (PDO). If Error Register (object 0x1001) is set, then NMT operational state may not be allowed. ### Power saving + All CANopen objects calculates next timer info for OS. Calculation is based on various timers which expire in known time. Can be used to put microcontroller into sleep and wake at the calculated time. +## Change Log -Change Log ----------- See [CHANGELOG.md](doc/CHANGELOG.md) +## License -License -------- Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 +[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt deleted file mode 100644 index ea0aceae..00000000 --- a/tools/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -# COPYRIGHT (C) 2025 INDUCTOHEAT, INC. ALL RIGHTS RESERVED. -# -# THIS SOURCE CODE DISTRIBUTION IS THE SOLE PROPERTY OF INDUCTOHEAT, INC. ANY -# REPRODUCTION IN PART OR AS A WHOLE IS STRICTLY PROHIBITED WITHOUT THE WRITTEN -# PERMISSION OF INDUCTOHEAT, INC. - -cmake_minimum_required(VERSION 3.20.0) - -find_package(Python3 REQUIRED COMPONENTS Interpreter) - -# Set default value for CANOPEN_DIR if it wasn't set externally -if(NOT DEFINED CANOPEN_DIR) - set(CANOPEN_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -endif() - -set(EDS2C_SCRIPT "${CANOPEN_DIR}/eds2c_wrapper.py") -set(EDS_UTILS_PY "eds-utils==0.3.1") -set(EDS_FILE "${CANOPEN_DIR}/ismart-fanout-board.eds") -set(GENERATED_HEADER "${CMAKE_CURRENT_BINARY_DIR}/OD.h") -set(GENERATED_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/OD.c") - -file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - -# Check if eds-utils is installed -execute_process( - COMMAND pip show eds-utils - RESULT_VARIABLE EDS_UTILS_FOUND - OUTPUT_QUIET - ERROR_QUIET -) - -if(NOT EDS_UTILS_FOUND EQUAL 0) - message(STATUS "eds-utils not found. Installing with pip...") - execute_process( - COMMAND pip install ${EDS_UTILS_PY} - RESULT_VARIABLE PIP_INSTALL_RESULT - ) - if(NOT PIP_INSTALL_RESULT EQUAL 0) - message(FATAL_ERROR "Failed to install eds-utils via pip") - endif() -endif() - -# Generate if EDS file changed or outputs missing -add_custom_command( - OUTPUT ${GENERATED_HEADER} ${GENERATED_SOURCE} - COMMAND ${Python3_EXECUTABLE} ${EDS2C_SCRIPT} ${EDS_FILE} -o ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${EDS_FILE} - COMMENT "Generating CANopenNode object dictionary from ${EDS_FILE} using eds-utils" - VERBATIM -) - -add_custom_target(generate_od - DEPENDS ${GENERATED_HEADER} ${GENERATED_SOURCE} -) - -# Export variables so parent scope can use -set(CO_OD_H ${GENERATED_HEADER} PARENT_SCOPE) -set(CO_OD_C ${GENERATED_SOURCE} PARENT_SCOPE) -set(CO_OD_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) diff --git a/tools/example.eds b/tools/example.eds deleted file mode 100644 index 7476becb..00000000 --- a/tools/example.eds +++ /dev/null @@ -1,1806 +0,0 @@ -[FileInfo] -FileName=objdict.eds -FileVersion=1 -FileRevision=1 -LastEDS= -EDSVersion=4.0 -Description= -CreationTime=2:52PM -CreationDate=09-18-2019 -CreatedBy= -ModificationTime=12:28PM -ModificationDate=02-20-2020 -ModifiedBy= - -[DeviceInfo] -VendorName= -VendorNumber=0 -ProductName=Zephyr RTOS CANopen sample -ProductNumber=0 -RevisionNumber=0 -BaudRate_10=1 -BaudRate_20=1 -BaudRate_50=1 -BaudRate_125=1 -BaudRate_250=1 -BaudRate_500=1 -BaudRate_800=1 -BaudRate_1000=1 -SimpleBootUpMaster=0 -SimpleBootUpSlave=0 -Granularity=0 -DynamicChannelsSupported=0 -CompactPDO=0 -GroupMessaging=0 -NrOfRXPDO=4 -NrOfTXPDO=4 -LSS_Supported=0 -;LSS_Type=Server - -[DummyUsage] -Dummy0001=0 -Dummy0002=0 -Dummy0003=0 -Dummy0004=0 -Dummy0005=0 -Dummy0006=0 -Dummy0007=0 - -[Comments] -Lines=0 - -[MandatoryObjects] -SupportedObjects=3 -1=0x1000 -2=0x1001 -3=0x1018 - -[1000] -ParameterName=Device type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue=0x00000000 -PDOMapping=0 - -[1001] -ParameterName=Error register -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=ro -DefaultValue=0 -PDOMapping=1 - -[1018] -ParameterName=Identity -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x5 - -[1018sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=4 -PDOMapping=0 - -[1018sub1] -ParameterName=Vendor-ID -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue=0x00000000 -PDOMapping=0 - -[1018sub2] -ParameterName=Product code -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue=0x00000000 -PDOMapping=0 - -[1018sub3] -ParameterName=Revision number -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue=0x00000000 -PDOMapping=0 - -[1018sub4] -ParameterName=Serial number -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue=0x00000000 -PDOMapping=0 - -[OptionalObjects] -SupportedObjects=39 -1=0x1002 -2=0x1003 -3=0x1005 -4=0x1006 -5=0x1007 -6=0x1008 -7=0x1009 -8=0x100A -9=0x1010 -10=0x1011 -11=0x1012 -12=0x1014 -13=0x1015 -14=0x1016 -15=0x1017 -16=0x1019 -17=0x1029 -18=0x1200 -19=0x1400 -20=0x1401 -21=0x1402 -22=0x1403 -23=0x1600 -24=0x1601 -25=0x1602 -26=0x1603 -27=0x1800 -28=0x1801 -29=0x1802 -30=0x1803 -31=0x1A00 -32=0x1A01 -33=0x1A02 -34=0x1A03 -35=0x1F50 -36=0x1F51 -37=0x1F56 -38=0x1F57 -39=0x1F80 - -[1002] -ParameterName=Manufacturer status register -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=1 - -[1003] -ParameterName=Pre-defined error field -ObjectType=0x8 -;StorageLocation=RAM -SubNumber=0x9 - -[1003sub0] -ParameterName=Number of errors -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=rw -DefaultValue=0x00 -PDOMapping=0 - -[1003sub1] -ParameterName=Standard error field -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1003sub2] -ParameterName=Standard error field -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1003sub3] -ParameterName=Standard error field -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1003sub4] -ParameterName=Standard error field -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1003sub5] -ParameterName=Standard error field -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1003sub6] -ParameterName=Standard error field -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1003sub7] -ParameterName=Standard error field -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1003sub8] -ParameterName=Standard error field -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1005] -ParameterName=COB-ID SYNC message -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000080 -PDOMapping=0 - -[1006] -ParameterName=Communication cycle period -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1007] -ParameterName=Synchronous window length -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1008] -ParameterName=Manufacturer device name -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0009 -AccessType=const -DefaultValue=Zephyr RTOS/CANopenNode -PDOMapping=0 - -[1009] -ParameterName=Manufacturer hardware version -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0009 -AccessType=const -DefaultValue=3.00 -PDOMapping=0 - -[100A] -ParameterName=Manufacturer software version -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0009 -AccessType=const -DefaultValue=3.00 -PDOMapping=0 - -[1010] -ParameterName=Store parameters -ObjectType=0x8 -;StorageLocation=RAM -SubNumber=0x2 - -[1010sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[1010sub1] -ParameterName=save all parameters -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000003 -PDOMapping=0 - -[1011] -ParameterName=Restore default parameters -ObjectType=0x8 -;StorageLocation=RAM -SubNumber=0x2 - -[1011sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[1011sub1] -ParameterName=restore all default parameters -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000001 -PDOMapping=0 - -[1012] -ParameterName=COB-ID TIME -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue= -PDOMapping=0 - -[1014] -ParameterName=COB-ID EMCY -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue=$NODEID+0x80 -PDOMapping=0 - -[1015] -ParameterName=inhibit time EMCY -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=100 -PDOMapping=0 - -[1016] -ParameterName=Consumer heartbeat time -ObjectType=0x8 -;StorageLocation=ROM -SubNumber=0x5 - -[1016sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=4 -PDOMapping=0 - -[1016sub1] -ParameterName=Consumer heartbeat time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1016sub2] -ParameterName=Consumer heartbeat time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1016sub3] -ParameterName=Consumer heartbeat time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1016sub4] -ParameterName=Consumer heartbeat time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1017] -ParameterName=Producer heartbeat time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=1000 -PDOMapping=0 - -[1019] -ParameterName=Synchronous counter overflow value -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1029] -ParameterName=Error behavior -ObjectType=0x8 -;StorageLocation=ROM -SubNumber=0x7 - -[1029sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=6 -PDOMapping=0 - -[1029sub1] -ParameterName=Communication -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0x00 -PDOMapping=0 - -[1029sub2] -ParameterName=Communication other -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0x00 -PDOMapping=0 - -[1029sub3] -ParameterName=Communication passive -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0x01 -PDOMapping=0 - -[1029sub4] -ParameterName=Generic -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0x00 -PDOMapping=0 - -[1029sub5] -ParameterName=Device profile -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0x00 -PDOMapping=0 - -[1029sub6] -ParameterName=Manufacturer specific -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0x00 -PDOMapping=0 - -[1200] -ParameterName=SDO server parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x3 - -[1200sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 - -[1200sub1] -ParameterName=COB-ID client to server -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue=$NODEID+0x600 -PDOMapping=0 - -[1200sub2] -ParameterName=COB-ID server to client -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=ro -DefaultValue=$NODEID+0x580 -PDOMapping=0 - -[1400] -ParameterName=RPDO communication parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x3 - -[1400sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 - -[1400sub1] -ParameterName=COB-ID used by RPDO -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x200 -PDOMapping=0 - -[1400sub2] -ParameterName=transmission type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=254 -PDOMapping=0 - -[1401] -ParameterName=RPDO communication parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x3 - -[1401sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 - -[1401sub1] -ParameterName=COB-ID used by RPDO -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x300 -PDOMapping=0 - -[1401sub2] -ParameterName=transmission type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=254 -PDOMapping=0 - -[1402] -ParameterName=RPDO communication parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x3 - -[1402sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 - -[1402sub1] -ParameterName=COB-ID used by RPDO -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x400 -PDOMapping=0 - -[1402sub2] -ParameterName=transmission type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=254 -PDOMapping=0 - -[1403] -ParameterName=RPDO communication parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x3 - -[1403sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 - -[1403sub1] -ParameterName=COB-ID used by RPDO -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x500 -PDOMapping=0 - -[1403sub2] -ParameterName=transmission type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=254 -PDOMapping=0 - -[1600] -ParameterName=RPDO mapping parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x9 - -[1600sub0] -ParameterName=Number of mapped objects -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1600sub1] -ParameterName=mapped object 1 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1600sub2] -ParameterName=mapped object 2 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1600sub3] -ParameterName=mapped object 3 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1600sub4] -ParameterName=mapped object 4 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1600sub5] -ParameterName=mapped object 5 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1600sub6] -ParameterName=mapped object 6 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1600sub7] -ParameterName=mapped object 7 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1600sub8] -ParameterName=mapped object 8 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1601] -ParameterName=RPDO mapping parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x9 - -[1601sub0] -ParameterName=Number of mapped objects -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1601sub1] -ParameterName=mapped object 1 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1601sub2] -ParameterName=mapped object 2 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1601sub3] -ParameterName=mapped object 3 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1601sub4] -ParameterName=mapped object 4 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1601sub5] -ParameterName=mapped object 5 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1601sub6] -ParameterName=mapped object 6 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1601sub7] -ParameterName=mapped object 7 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1601sub8] -ParameterName=mapped object 8 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1602] -ParameterName=RPDO mapping parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x9 - -[1602sub0] -ParameterName=Number of mapped objects -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1602sub1] -ParameterName=mapped object 1 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1602sub2] -ParameterName=mapped object 2 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1602sub3] -ParameterName=mapped object 3 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1602sub4] -ParameterName=mapped object 4 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1602sub5] -ParameterName=mapped object 5 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1602sub6] -ParameterName=mapped object 6 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1602sub7] -ParameterName=mapped object 7 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1602sub8] -ParameterName=mapped object 8 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1603] -ParameterName=RPDO mapping parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x9 - -[1603sub0] -ParameterName=Number of mapped objects -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1603sub1] -ParameterName=mapped object 1 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1603sub2] -ParameterName=mapped object 2 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1603sub3] -ParameterName=mapped object 3 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1603sub4] -ParameterName=mapped object 4 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1603sub5] -ParameterName=mapped object 5 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1603sub6] -ParameterName=mapped object 6 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1603sub7] -ParameterName=mapped object 7 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1603sub8] -ParameterName=mapped object 8 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1800] -ParameterName=TPDO communication parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x7 - -[1800sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=6 -PDOMapping=0 - -[1800sub1] -ParameterName=COB-ID used by TPDO -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x180 -PDOMapping=0 - -[1800sub2] -ParameterName=transmission type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=254 -PDOMapping=0 - -[1800sub3] -ParameterName=inhibit time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1800sub4] -ParameterName=compatibility entry -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1800sub5] -ParameterName=event timer -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1800sub6] -ParameterName=SYNC start value -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1801] -ParameterName=TPDO communication parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x7 - -[1801sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=6 -PDOMapping=0 - -[1801sub1] -ParameterName=COB-ID used by TPDO -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x280 -PDOMapping=0 - -[1801sub2] -ParameterName=transmission type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=254 -PDOMapping=0 - -[1801sub3] -ParameterName=inhibit time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1801sub4] -ParameterName=compatibility entry -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1801sub5] -ParameterName=event timer -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1801sub6] -ParameterName=SYNC start value -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1802] -ParameterName=TPDO communication parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x7 - -[1802sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=6 -PDOMapping=0 - -[1802sub1] -ParameterName=COB-ID used by TPDO -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x380 -PDOMapping=0 - -[1802sub2] -ParameterName=transmission type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=254 -PDOMapping=0 - -[1802sub3] -ParameterName=inhibit time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1802sub4] -ParameterName=compatibility entry -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1802sub5] -ParameterName=event timer -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1802sub6] -ParameterName=SYNC start value -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1803] -ParameterName=TPDO communication parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x7 - -[1803sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=6 -PDOMapping=0 - -[1803sub1] -ParameterName=COB-ID used by TPDO -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x480 -PDOMapping=0 - -[1803sub2] -ParameterName=transmission type -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=254 -PDOMapping=0 - -[1803sub3] -ParameterName=inhibit time -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1803sub4] -ParameterName=compatibility entry -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1803sub5] -ParameterName=event timer -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1803sub6] -ParameterName=SYNC start value -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1A00] -ParameterName=TPDO mapping parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x9 - -[1A00sub0] -ParameterName=Number of mapped objects -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1A00sub1] -ParameterName=mapped object 1 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A00sub2] -ParameterName=mapped object 2 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A00sub3] -ParameterName=mapped object 3 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A00sub4] -ParameterName=mapped object 4 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A00sub5] -ParameterName=mapped object 5 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A00sub6] -ParameterName=mapped object 6 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A00sub7] -ParameterName=mapped object 7 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A00sub8] -ParameterName=mapped object 8 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A01] -ParameterName=TPDO mapping parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x9 - -[1A01sub0] -ParameterName=Number of mapped objects -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1A01sub1] -ParameterName=mapped object 1 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A01sub2] -ParameterName=mapped object 2 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A01sub3] -ParameterName=mapped object 3 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A01sub4] -ParameterName=mapped object 4 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A01sub5] -ParameterName=mapped object 5 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A01sub6] -ParameterName=mapped object 6 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A01sub7] -ParameterName=mapped object 7 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A01sub8] -ParameterName=mapped object 8 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A02] -ParameterName=TPDO mapping parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x9 - -[1A02sub0] -ParameterName=Number of mapped objects -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1A02sub1] -ParameterName=mapped object 1 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A02sub2] -ParameterName=mapped object 2 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A02sub3] -ParameterName=mapped object 3 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A02sub4] -ParameterName=mapped object 4 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A02sub5] -ParameterName=mapped object 5 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A02sub6] -ParameterName=mapped object 6 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A02sub7] -ParameterName=mapped object 7 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A02sub8] -ParameterName=mapped object 8 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A03] -ParameterName=TPDO mapping parameter -ObjectType=0x9 -;StorageLocation=ROM -SubNumber=0x9 - -[1A03sub0] -ParameterName=Number of mapped objects -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1A03sub1] -ParameterName=mapped object 1 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A03sub2] -ParameterName=mapped object 2 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A03sub3] -ParameterName=mapped object 3 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A03sub4] -ParameterName=mapped object 4 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A03sub5] -ParameterName=mapped object 5 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A03sub6] -ParameterName=mapped object 6 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A03sub7] -ParameterName=mapped object 7 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1A03sub8] -ParameterName=mapped object 8 -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[1F50] -ParameterName=Program data -ObjectType=0x8 -;StorageLocation=RAM -SubNumber=0x2 - -[1F50sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[1F50sub1] -ParameterName= -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x000F -AccessType=wo -DefaultValue= -PDOMapping=0 - -[1F51] -ParameterName=Program control -ObjectType=0x8 -;StorageLocation=RAM -SubNumber=0x2 - -[1F51sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[1F51sub1] -ParameterName= -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=rw -DefaultValue= -PDOMapping=0 - -[1F56] -ParameterName=Program software identification -ObjectType=0x8 -;StorageLocation=RAM -SubNumber=0x2 - -[1F56sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[1F56sub1] -ParameterName= -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue= -PDOMapping=0 - -[1F57] -ParameterName=Flash status identification -ObjectType=0x8 -;StorageLocation=RAM -SubNumber=0x2 - -[1F57sub0] -ParameterName=max sub-index -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[1F57sub1] -ParameterName= -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=ro -DefaultValue= -PDOMapping=0 - -[1F80] -ParameterName=NMT startup -ObjectType=0x7 -;StorageLocation=ROM -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000000 -PDOMapping=0 - -[ManufacturerObjects] -SupportedObjects=3 -1=0x2100 -2=0x2101 -3=0x2102 - -[2100] -ParameterName=Error status bits -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x000A -AccessType=ro -DefaultValue=00000000000000000000 -PDOMapping=1 - -[2101] -ParameterName=Power-on counter -ObjectType=0x7 -;StorageLocation=EEPROM -DataType=0x0007 -AccessType=ro -DefaultValue=0 -PDOMapping=1 - -[2102] -ParameterName=Button press counter -ObjectType=0x7 -;StorageLocation=RAM -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=1 - diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 08fa5848..68282194 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -507,12 +507,12 @@ config CANOPENNODE_LEDS_ENABLE config CANOPENNODE_LEDS_CALLBACK bool "Enable custom callback after LED state changes" depends on CANOPENNODE_LEDS_ENABLE - default n + default y config CANOPENNODE_LEDS_TIMERNEXT bool "Enable calculation of timerNext_us for LED indicators" depends on CANOPENNODE_LEDS_ENABLE - default n + default y endmenu From f4a352b7a835f371c082e9db487fc1a37eb5a69a Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 13 Aug 2025 21:38:57 -0400 Subject: [PATCH 508/520] Refactors CANopenNode storage and initialization Simplifies storage backend selection by removing conditional source inclusion. This change consolidates storage source files and uses Kconfig options for backend configuration. It also corrects the CANopen initialization sequence and addresses potential errors during startup. Additionally, it improves the real-time thread timing mechanisms. --- zephyr/CMakeLists.txt | 15 ++--- zephyr/CO_zephyr_driver.c | 2 +- zephyr/CO_zephyr_integration.c | 91 ++++++++++++++++++------------- zephyr/CO_zephyr_storage.c | 17 +----- zephyr/Kconfig | 33 +++++++---- zephyr/include/CO_driver_target.h | 45 +++++++-------- zephyr/include/CO_zephyr_config.h | 53 +++++++++++++----- zephyr/module.yml | 2 +- 8 files changed, 143 insertions(+), 115 deletions(-) diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 84bfae58..894c0882 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -267,17 +267,12 @@ endif() # Select storage backend glue based on Kconfig: # - SETTINGS: full storage stack with EEPROM mapping + Zephyr storage bridge # - RAM: lightweight volatile storage bridge -# - NONE: compile-time no-op (define macro for conditional code) if(CONFIG_CANOPENNODE_STORAGE_ENABLE) + zephyr_library_sources( + "${CANOPENNODE_DIR}/storage/CO_storage.c" + "${CANOPENNODE_DIR}/zephyr/CO_zephyr_storage.c" + ) if(CONFIG_CANOPENNODE_STORAGE_BACKEND_SETTINGS) - zephyr_library_sources( - "${CANOPENNODE_DIR}/storage/CO_storage.c" - "${CANOPENNODE_DIR}/storage/CO_storageEeprom.c" - "${CANOPENNODE_DIR}/zephyr/CO_zephyr_storage.c" - ) - elseif(CONFIG_CANOPENNODE_STORAGE_BACKEND_RAM) - zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_zephyr_storage.c") - elseif(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE) - add_compile_definitions(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE=1) + zephyr_library_sources("${CANOPENNODE_DIR}/storage/CO_storageEeprom.c") endif() endif() diff --git a/zephyr/CO_zephyr_driver.c b/zephyr/CO_zephyr_driver.c index c920dad2..a57d0872 100644 --- a/zephyr/CO_zephyr_driver.c +++ b/zephyr/CO_zephyr_driver.c @@ -35,7 +35,7 @@ #include #include -LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); +LOG_MODULE_REGISTER(canopennode_driver, CONFIG_CANOPEN_LOG_LEVEL); #define CANPTR_TO_DEV(ptr) ((const struct device *)(ptr)) diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 34c3d9c1..8b265a4c 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -37,14 +37,17 @@ #include "OD.h" #if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) -#include "CO_storage_zephyr.h" +#include "CO_zephyr_storage.h" #endif -LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); +LOG_MODULE_REGISTER(canopennode_zephyr, CONFIG_CANOPEN_LOG_LEVEL); #define CAN_NODE DT_CHOSEN(zephyr_canbus) #define CAN_BITRATE_KBPS (DT_PROP(CAN_NODE, bitrate) / 1000U) +#define DEV_TO_CANPTR(d) ((void *)(uintptr_t)(d)) +#define CANPTR_TO_DEV(p) ((const struct device *)(p)) + /* ---------- Module state ---------- * CO / CO_storage are the runtime stack handles. * g_running is an atomic "stack is active" flag used by the RT thread and signalers. @@ -77,13 +80,13 @@ static void rt_signal_cb(void *object) static void enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) { CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); - for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { - CO_RPDO_initCallbackPre(co->RPDO[i], pre_cb, arg); + for (uint16_t i = 0; i < OD_CNT_RPDO; i++) { + CO_RPDO_initCallbackPre(&co->RPDO[i], pre_cb, arg); } } /* ---------- RT Thread: SYNC/RPDO/TPDO ---------- */ -#if IS_ENABLED(CANOPENNODE_RT_THREAD) +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD) /* * Real-time CANopen processing thread. * @@ -125,12 +128,10 @@ static void canopen_rt_thread(void *p1, void *p2, void *p3) last_ms = now_ms; #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) - uint32_t next_us = UINT32_MAX; - (void)CO_process(CO, false, dt_us, &next_us); - timeout_us = (next_us == 0U || next_us == UINT32_MAX) ? fallback_us : next_us; + uint32_t next_main_us = UINT32_MAX; + (void)CO_process(CO, false, dt_us, &next_main_us); #else (void)CO_process(CO, false, dt_us, NULL); - timeout_us = fallback_us; #endif /* RT part: SYNC, RPDO, TPDO */ @@ -141,18 +142,34 @@ static void canopen_rt_thread(void *p1, void *p2, void *p3) uint32_t dt_rt_us = (uint32_t)(k_cyc_to_ns_floor64(delta_cyc) / 1000U); CO_LOCK_OD(); + + uint32_t next_sync_us = UINT32_MAX; + uint32_t next_rpdo_us = UINT32_MAX; + uint32_t next_tpdo_us = UINT32_MAX; + #if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) - bool_t sync = CO_process_SYNC(CO, dt_rt_us); + bool_t sync = CO_process_SYNC(CO, dt_rt_us, &next_sync_us); #else bool_t sync = false; #endif #if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) - CO_process_RPDO(CO, sync); + CO_process_RPDO(CO, sync, dt_rt_us, &next_rpdo_us); #endif #if IS_ENABLED(CONFIG_CANOPENNODE_TPDO_ENABLE) - CO_process_TPDO(CO, sync, dt_rt_us); + CO_process_TPDO(CO, sync, dt_rt_us, &next_tpdo_us); #endif + CO_UNLOCK_OD(); + + /* Compute next wakeup based on returned timers */ + uint32_t next_rt_us = MIN(next_sync_us, MIN(next_rpdo_us, next_tpdo_us)); + +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) + uint32_t next_all = MIN(next_rt_us, next_main_us); + timeout_us = (next_all == 0U || next_all == UINT32_MAX) ? fallback_us : next_all; +#else + timeout_us = fallback_us; +#endif } } @@ -179,7 +196,7 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit return -EINVAL; } if (bitrate_kbps == 0) { - bitrate_kbps = CONFIG_CANOPENNODE_BITRATE_KBPS; + bitrate_kbps = CAN_BITRATE_KBPS; } if (CO != NULL) { @@ -190,56 +207,57 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit uint32_t heap_used = 0; CO = CO_new(NULL, &heap_used); if (CO == NULL) { - LOG_ERR("[%s] Memory allocation failed", __func__); + LOG_ERR("Memory allocation failed"); return -ENOMEM; } - LOG_INF("[%s] Allocated %u bytes for CANopen", __func__, heap_used); + LOG_INF("Allocated %u bytes for CANopen", heap_used); int ret = 0; CO_ReturnError_t err; uint32_t errInfo = 0; #if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) - CO_storage_entry_t storageEntries[] = {{.addr = &OD_PERSIST_COMM, - .len = sizeof(OD_PERSIST_COMM), - .subIndexOD = 2, - .attr = CO_storage_cmd | CO_storage_restore, - .addrNV = NULL}}; + CO_storage_entry_t storageEntries[] = {{ + .addr = &OD_ROM, + .len = sizeof(OD_ROM), + .subIndexOD = 2, + .attr = CO_storage_cmd | CO_storage_restore, + }}; uint8_t entryCount = ARRAY_SIZE(storageEntries); uint32_t storageErr = 0; - err = CO_zephyr_storage_init(CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, + err = co_zephyr_storage_init(CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, entryCount, &storageErr); if (err != CO_ERROR_NO) { - LOG_ERR("[%s] Storage init failed: %d", __func__, err); + LOG_ERR("Storage init failed: %d", err); ret = -ENOMEM; goto error; } if (storageErr != 0) { - LOG_ERR("[%s] Storage error: 0x%X", __func__, storageErr); + LOG_ERR("Storage error: 0x%X", storageErr); ret = -EIO; goto error; } #endif - err = CO_CANinit(CO, can_dev, bitrate_kbps); + err = CO_CANinit(CO, DEV_TO_CANPTR(can_dev), bitrate_kbps); if (err != CO_ERROR_NO) { - LOG_ERR("[%s] CAN init failed: %d", __func__, err); + LOG_ERR("CAN init failed: %d", err); ret = -EINVAL; goto error; } #if IS_ENABLED(CONFIG_CANOPENNODE_LSS_SLAVE) CO_LSS_address_t lssAddr = { - .identity = {.vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, - .productCode = OD_PERSIST_COMM.x1018_identity.productCode, - .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, - .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber}}; + .identity = {.vendorID = OD_ROM.x1018_identity.vendor_ID, + .productCode = OD_ROM.x1018_identity.productCode, + .revisionNumber = OD_ROM.x1018_identity.revisionNumber, + .serialNumber = OD_ROM.x1018_identity.serialNumber}}; err = CO_LSSinit(CO, &lssAddr, &node_id, &bitrate_kbps); if (err != CO_ERROR_NO) { - LOG_ERR("[%s] LSS init failed: %d", __func__, err); + LOG_ERR("LSS init failed: %d", err); ret = -EINVAL; goto error; } @@ -251,14 +269,14 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit &errInfo); if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - LOG_ERR("[%s] CANopen init failed: %d (OD entry 0x%X)", __func__, err, errInfo); + LOG_ERR("CANopen init failed: %d (OD entry 0x%X)", err, errInfo); ret = -EIO; goto error; } err = CO_CANopenInitPDO(CO, CO->em, OD, node_id, &errInfo); if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - LOG_ERR("[%s] PDO init failed: %d (OD entry 0x%X)", __func__, err, errInfo); + LOG_ERR("PDO init failed: %d (OD entry 0x%X)", err, errInfo); ret = -EIO; goto error; } @@ -271,14 +289,14 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit } #endif } else { - LOG_INF("[%s] Node-ID not configured (LSS active)", __func__); + LOG_INF("Node-ID not configured (LSS active)"); } enable_pre_signals(CO, rt_signal_cb, NULL); atomic_set(&g_running, 1); CO_CANsetNormalMode(CO->CANmodule); - LOG_INF("[%s] CANopenNode running", __func__); + LOG_INF("CANopenNode running"); return 0; error: @@ -301,7 +319,7 @@ void co_canopen_stop(void) CO_CANmodule_disable(CO->CANmodule); CO_delete(CO); CO = NULL; - LOG_INF("[%s] CANopenNode stopped", __func__); + LOG_INF("CANopenNode stopped"); } } @@ -314,9 +332,8 @@ bool co_canopen_is_running(void) * System init hook. * Optionally auto-starts CANopen at POST_KERNEL if configured via Kconfig. */ -static int co_canopen_init_sys(const struct device *unused) +static int co_canopen_init_sys(void) { - ARG_UNUSED(unused); #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) (void)co_canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, CAN_BITRATE_KBPS); #endif diff --git a/zephyr/CO_zephyr_storage.c b/zephyr/CO_zephyr_storage.c index ec6e2d77..ca40d3b4 100644 --- a/zephyr/CO_zephyr_storage.c +++ b/zephyr/CO_zephyr_storage.c @@ -33,7 +33,7 @@ #include #include -LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); +LOG_MODULE_REGISTER(canopennode_storage, CONFIG_CANOPEN_LOG_LEVEL); #ifdef CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS #include @@ -46,7 +46,6 @@ LOG_MODULE_REGISTER(canopennode, CONFIG_CANOPEN_LOG_LEVEL); static ODR_t store_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { #if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) - char key[64]; snprintf(key, sizeof(key), "canopen/od/%04X", entry->subIndexOD); int err = settings_save_one(key, entry->addr, entry->len); @@ -54,17 +53,11 @@ static ODR_t store_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) LOG_ERR("Settings save failed (%d) for key %s", err, key); return ODR_HW; } - #elif defined(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) - LOG_DBG("Skipping store (RAM-only backend)"); - #else - LOG_WRN("No valid storage backend selected — store operation skipped"); - #endif - return ODR_OK; } @@ -75,24 +68,17 @@ static ODR_t store_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) static ODR_t restore_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { #if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) - char key[64]; snprintf(key, sizeof(key), "canopen/od/%04X", entry->subIndexOD); int err = settings_delete(key); if (err) { LOG_WRN("Settings delete failed (%d) for key %s", err, key); } - #elif defined(CONFIG_CANOPEN_STORAGE_BACKEND_RAM) - LOG_DBG("Skipping restore (RAM-only backend)"); - #else - LOG_WRN("No valid storage backend selected — restore operation skipped"); - #endif - return ODR_OK; } @@ -143,6 +129,5 @@ CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *C entry->subIndexOD); #endif } - return ret; } diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 68282194..17887fc3 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -184,7 +184,6 @@ config CANOPENNODE_NODE_GUARDING_MASTER_ENABLE config CANOPENNODE_NODE_GUARDING_MASTER_COUNT int "Max nodes monitored by guarding master" - depends on CANOPENNODE_NODE_GUARDING_MASTER_ENABLE range 1 127 default 127 @@ -284,7 +283,6 @@ config CANOPENNODE_SDO_SERVER_OD_DYNAMIC config CANOPENNODE_SDO_SERVER_BUFFER_SIZE int "SDO server buffer size" - depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK range 900 4096 if CANOPENNODE_SDO_SERVER_BLOCK range 20 4096 if !CANOPENNODE_SDO_SERVER_BLOCK default 900 if CANOPENNODE_SDO_SERVER_BLOCK @@ -296,7 +294,6 @@ config CANOPENNODE_SDO_SERVER_BUFFER_SIZE config CANOPENNODE_SDO_SERVER_TIMEOUT_MS int "SDO server timeout (ms)" - depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK range 50 60000 default 1000 @@ -344,7 +341,6 @@ config CANOPENNODE_SDO_CLIENT_OD_DYNAMIC config CANOPENNODE_SDO_CLIENT_BUFFER_SIZE int "SDO client buffer size" - depends on CANOPENNODE_SDO_CLIENT_ENABLE range 1000 4096 if CANOPENNODE_SDO_CLIENT_BLOCK range 7 4096 if CANOPENNODE_SDO_CLIENT_SEGMENTED && !CANOPENNODE_SDO_CLIENT_BLOCK default 1000 if CANOPENNODE_SDO_CLIENT_BLOCK @@ -355,7 +351,6 @@ config CANOPENNODE_SDO_CLIENT_BUFFER_SIZE config CANOPENNODE_SDO_CLIENT_TIMEOUT_MS int "SDO client timeout (ms)" - depends on CANOPENNODE_SDO_CLIENT_ENABLE range 50 60000 default 1000 @@ -481,6 +476,7 @@ choice CANOPENNODE_STORAGE_BACKEND_CHOICE config CANOPENNODE_STORAGE_BACKEND_SETTINGS bool "Zephyr Settings subsystem" select SETTINGS + select CANOPENNODE_CRC16_EXTERNAL help Use Zephyr's Settings subsystem to persist OD entries. @@ -506,13 +502,13 @@ config CANOPENNODE_LEDS_ENABLE config CANOPENNODE_LEDS_CALLBACK bool "Enable custom callback after LED state changes" - depends on CANOPENNODE_LEDS_ENABLE - default y + default y if CANOPENNODE_LEDS_ENABLE + default n if !CANOPENNODE_LEDS_ENABLE config CANOPENNODE_LEDS_TIMERNEXT bool "Enable calculation of timerNext_us for LED indicators" - depends on CANOPENNODE_LEDS_ENABLE - default y + default y if CANOPENNODE_LEDS_ENABLE + default n if !CANOPENNODE_LEDS_ENABLE endmenu @@ -553,7 +549,6 @@ config CANOPENNODE_SRDO_TIMERNEXT config CANOPENNODE_SRDO_MINIMUM_DELAY int "Minimum time between the first and second SRDO (Tx) message (us)" - depends on CANOPENNODE_SRDO_ENABLE range 0 1000000 default 0 @@ -746,6 +741,24 @@ config CANOPENNODE_EDS_FILE_PATH endmenu +menu "CANopenNode TX Workqueue Options" + +config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE + int "TX workqueue stack size" + default 1024 + range 256 16384 + help + Stack size (in bytes) for the CANopenNode TX workqueue thread. + +config CANOPENNODE_TX_WORKQUEUE_PRIORITY + int "TX workqueue priority" + default 0 + help + Thread priority for the CANopenNode TX workqueue. + Lower numbers mean higher priority. + +endmenu + menu "CANopenNode Thread Options" config CANOPENNODE_RT_THREAD diff --git a/zephyr/include/CO_driver_target.h b/zephyr/include/CO_driver_target.h index 3d57dcbf..4f67dcdf 100644 --- a/zephyr/include/CO_driver_target.h +++ b/zephyr/include/CO_driver_target.h @@ -40,6 +40,8 @@ extern "C" { #include #include +#include "CO_zephyr_config.h" + /** * @defgroup co_driver_target Zephyr driver target (porting layer) * @brief Zephyr-specific targets, types, and primitives for CANopenNode. @@ -230,31 +232,24 @@ typedef struct { * by the Zephyr storage glue (e.g., EEPROM/flash helpers). */ typedef struct { - /** RAM address of the data to persist. */ - void *addr; - /** Length of the data block in bytes. */ - size_t len; - /** OD subindex associated with the entry. */ - uint8_t subIndexOD; - /** Storage attributes (e.g., command/restore flags). */ - uint8_t attr; - - /* --- Additional variables (target specific) --- */ - /** Non-volatile mirror address, if applicable. */ - void *addrNV; - /** Backend/storage module handle. */ - void *storageModule; - /** Scratch/data pointer for backend use. */ - uint8_t *data; - /** Backend NV address/offset for the block. */ - size_t eepromAddr; - - /* Implementation notes: - * - entry->eepromAddrSignature = signaturesAddress + (sizeof(uint32_t) * i); - * - entry->eepromAddr = CO_eeprom_getAddr(storageModule, isAuto, entry->len, &eepromOvf); - * - entry->offset = 0; - * - Backend may use (storageModule, addr, eepromAddr, len). - */ + void *addr; /**< Address of data to store, always required. */ + size_t len; /**< Length of data to store, always required. */ + uint8_t subIndexOD; /**< Sub index in OD objects 1010 and 1011, from 2 to 127. Writing + 0x65766173 to 1010,subIndexOD will store data to non-volatile memory + Writing 0x64616F6C to 1011,subIndexOD will restore default data, + always required. */ + uint8_t attr; /**< Attribute from @ref CO_storage_attributes_t, always required. */ + void *storageModule; /**< Pointer to storage module, target system specific usage, required + with @ref CO_storage_eeprom. */ + uint16_t crc; /**< CRC checksum of the data stored in eeprom, set on store, required with + @ref CO_storage_eeprom. */ + size_t eepromAddrSignature; /**< Address of entry signature inside eeprom, set by init, + required with @ref CO_storage_eeprom. */ + size_t eepromAddr; /**< Address of data inside eeprom, set by init, required with @ref + CO_storage_eeprom. */ + size_t offset; /**< Offset of next byte being updated by automatic storage, required with + @ref CO_storage_eeprom. */ + void *additionalParameters; /**< Additional target specific parameters, optional. */ } CO_storage_entry_t; /* -------------------------------------------------------------------------- */ diff --git a/zephyr/include/CO_zephyr_config.h b/zephyr/include/CO_zephyr_config.h index b2db2a45..f33eb0e3 100644 --- a/zephyr/include/CO_zephyr_config.h +++ b/zephyr/include/CO_zephyr_config.h @@ -63,6 +63,39 @@ extern "C" { #define ZVAL(cfgsym) (cfgsym) /** @} */ +/** @def CO_USE_GLOBALS + * @brief Selects storage model for CANopenNode objects. + * + * If not provided by the build, this header auto-derives the value from + * Zephyr’s heap setting: + * - `1` — Use global/static objects; no dynamic allocation. + * - `0` — Use dynamic allocation; requires a non-zero + * `CONFIG_HEAP_MEM_POOL_SIZE`. + * + * You may override by defining `CO_USE_GLOBALS` before including this header + * or via the build system (e.g., `-DCO_USE_GLOBALS=0`). + * + * @see CONFIG_HEAP_MEM_POOL_SIZE + */ +#ifndef CO_USE_GLOBALS +/* Treat “heap present” (non-zero) as “use dynamic allocation”. */ +#if defined(CONFIG_HEAP_MEM_POOL_SIZE) && (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#define CO_USE_GLOBALS 0 +#else +#define CO_USE_GLOBALS 1 +#endif +#endif + +/** @brief Build-time sanity check for dynamic mode. + * + * Triggers a compile-time error if `CO_USE_GLOBALS==0` (dynamic allocation) + * but Zephyr’s heap is not enabled or has size 0. + */ +#if (CO_USE_GLOBALS == 0) && \ + !(defined(CONFIG_HEAP_MEM_POOL_SIZE) && (CONFIG_HEAP_MEM_POOL_SIZE > 0)) +#error "CO_USE_GLOBALS=0 requires a nonzero CONFIG_HEAP_MEM_POOL_SIZE" +#endif + /** @name NMT / Heartbeat Producer * @brief Configure CANopen NMT producer behavior and control bits. * @{ @@ -77,27 +110,17 @@ extern "C" { /** @brief Optional initial heartbeat delay in milliseconds. */ #define CO_NMT_FIRST_HB_TIME_MS CONFIG_CANOPENNODE_NMT_FIRST_HB_TIME_MS -/** @brief Convenience booleans for NMT control policy (source: Kconfig). */ -#define CO_NMT_STARTUP_TO_OPERATIONAL IS_ENABLED(CONFIG_CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL) -#define CO_NMT_ERR_ON_BUSOFF_HB IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_ON_BUSOFF_HB) -#define CO_NMT_ERR_ON_ERR_REG IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_ON_ERR_REG) -#define CO_NMT_ERR_TO_STOPPED IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_TO_STOPPED) -#define CO_NMT_ERR_FREE_TO_OPERATIONAL IS_ENABLED(CONFIG_CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL) - /** * @brief Composite NMT startup/control mask you can pass to CANopenNode init. * * Combines the policy booleans above into the bitmask expected by CANopenNode. */ #define CO_CONFIG_NMT_CONTROL \ - ((ZBIT(CO_NMT_STARTUP_TO_OPERATIONAL, CO_NMT_STARTUP_TO_OPERATIONAL) ? CO_NMT_STARTUP \ - : 0) | \ - (ZBIT(CO_NMT_ERR_ON_BUSOFF_HB, CO_NMT_ERR_ON_BUSOFF_HB) ? CO_NMT_ERR_ON_BUSOFF_HB : 0) | \ - (ZBIT(CO_NMT_ERR_ON_ERR_REG, CO_NMT_ERR_ON_ERR_REG) ? CO_NMT_ERR_ON_ERR_REG : 0) | \ - (ZBIT(CO_NMT_ERR_TO_STOPPED, CO_NMT_ERR_TO_STOPPED) ? CO_NMT_ERR_TO_STOPPED : 0) | \ - (ZBIT(CO_NMT_ERR_FREE_TO_OPERATIONAL, CO_NMT_ERR_FREE_TO_OPERATIONAL) \ - ? CO_NMT_ERR_FREE_TO_OPERATIONAL \ - : 0)) + (ZBIT(CO_NMT_STARTUP_TO_OPERATIONAL, CONFIG_CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL) | \ + ZBIT(CO_NMT_ERR_ON_BUSOFF_HB, CONFIG_CANOPENNODE_NMT_ERR_ON_BUSOFF_HB) | \ + ZBIT(CO_NMT_ERR_ON_ERR_REG, CONFIG_CANOPENNODE_NMT_ERR_ON_ERR_REG) | \ + ZBIT(CO_NMT_ERR_TO_STOPPED, CONFIG_CANOPENNODE_NMT_ERR_TO_STOPPED) | \ + ZBIT(CO_NMT_ERR_FREE_TO_OPERATIONAL, CONFIG_CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL)) /** @} */ /** @name Heartbeat Consumer diff --git a/zephyr/module.yml b/zephyr/module.yml index 8a0e620d..c5431465 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -34,7 +34,7 @@ name: canopennode build: - cmake: zephyr/CMakeLists.txt + cmake: zephyr kconfig: zephyr/Kconfig package-managers: From d12997f06cc162ffd301cc5276a2ad4a19323d8a Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Thu, 14 Aug 2025 08:24:06 -0400 Subject: [PATCH 509/520] Fixes include order and macro definition Corrects include order in `CO_zephyr_config.h` to ensure proper dependency resolution. Relocates the `extern "C"` block in `CO_driver_target.h` to encapsulate the header contents. Fixes typo in `CO_CONFIG_LEDS` macro name. --- zephyr/include/CO_driver_target.h | 8 ++++---- zephyr/include/CO_zephyr_config.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/zephyr/include/CO_driver_target.h b/zephyr/include/CO_driver_target.h index 4f67dcdf..7b5ebb4f 100644 --- a/zephyr/include/CO_driver_target.h +++ b/zephyr/include/CO_driver_target.h @@ -29,10 +29,6 @@ #ifndef ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_TARGET_H #define ZEPHYR_MODULES_CANOPENNODE_CO_DRIVER_TARGET_H -#ifdef __cplusplus -extern "C" { -#endif - #include #include #include @@ -42,6 +38,10 @@ extern "C" { #include "CO_zephyr_config.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * @defgroup co_driver_target Zephyr driver target (porting layer) * @brief Zephyr-specific targets, types, and primitives for CANopenNode. diff --git a/zephyr/include/CO_zephyr_config.h b/zephyr/include/CO_zephyr_config.h index f33eb0e3..13f3c114 100644 --- a/zephyr/include/CO_zephyr_config.h +++ b/zephyr/include/CO_zephyr_config.h @@ -26,13 +26,13 @@ #ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_CONFIG_H #define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_CONFIG_H +#include +#include + #ifdef __cplusplus extern "C" { #endif -#include -#include - /** * @defgroup co_zephyr_config Zephyr ↔ CANopenNode configuration bridge * @brief Map Zephyr Kconfig to CANopenNode @c CO_CONFIG_* flags and constants. @@ -265,7 +265,7 @@ extern "C" { * @brief Enable LED state machine and optional callback. * @{ */ -#define CO_CONFIG_LEDs \ +#define CO_CONFIG_LEDS \ (ZBIT(CO_CONFIG_LEDS_ENABLE, CONFIG_CANOPENNODE_LEDS_ENABLE) | \ ZBIT(CO_CONFIG_LEDS_CALLBACK, CONFIG_CANOPENNODE_LEDS_CALLBACK) | \ ZBIT(CO_CONFIG_FLAG_TIMERNEXT, CONFIG_CANOPENNODE_LEDS_TIMERNEXT)) From 54bb113446f9c809c03622fa3d73e5c7c1619ee2 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Thu, 14 Aug 2025 14:32:35 -0400 Subject: [PATCH 510/520] Enables application-defined CANopen Node-ID Allows the application to provide a callback function for determining the CANopen Node-ID dynamically. This enables scenarios where the Node-ID is derived from external sources, such as DIP switches or configuration files, instead of being hardcoded or defined by Kconfig. Adds Kconfig option to enable/disable the callback feature. --- zephyr/CO_zephyr_integration.c | 73 +++++++++++++++++++++++++- zephyr/Kconfig | 15 ++++++ zephyr/include/CO_zephyr_integration.h | 71 +++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 1 deletion(-) diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 8b265a4c..2df011dd 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -57,10 +57,47 @@ static CO_t *CO = NULL; static CO_storage_t *CO_storage = NULL; static atomic_t g_running; +#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) +static co_node_id_cb_t g_node_id_cb; +static void *g_node_id_cb_ud; +static const struct device *g_last_can_dev; +static uint8_t g_node_id_current; +static uint16_t g_last_bitrate_kbps; +#endif + K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ /* ---------- Helpers ---------- */ +/* Resolve a usable CANopen Node-ID. + * + * Priority: + * 1) If 'requested' is in [1..127], use it as-is. + * 2) If enabled and registered, ask the application callback + * (CONFIG_CANOPENNODE_NODE_ID_CALLBACK). Ignore out-of-range results. + * 3) Fall back to CONFIG_CANOPENNODE_INIT_NODE_ID. + * + * Notes: + * - Pass 0 for 'requested' to defer to the callback or the Kconfig default. + * - The returned value is intended to be in [1..127]; ensure your Kconfig + * default is valid for your system. + */ +static uint8_t resolve_node_id(uint8_t requested) +{ + if (requested >= 1 && requested <= 127) { + return requested; + } +#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) + if (g_node_id_cb) { + uint8_t id = g_node_id_cb(g_node_id_cb_ud); + if (id >= 1 && id <= 127) { + return id; + } + } +#endif + return CONFIG_CANOPENNODE_INIT_NODE_ID; +} + /* * Pre-callback used by SYNC/RPDO to poke the RT thread. * Gives the semaphore only when the stack is marked running. @@ -181,6 +218,33 @@ K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, canopen_rt_ /* ---------- Public API ---------- */ +#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) +void co_canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data) +{ + g_node_id_cb = cb; + g_node_id_cb_ud = user_data; + + /* If not running or no callback registered, nothing more to do. */ + if (!atomic_get(&g_running) || g_node_id_cb == NULL) { + return; + } + + /* Ask the app for the desired Node-ID. */ + uint8_t new_id = g_node_id_cb(g_node_id_cb_ud); + if (new_id < 1 || new_id > 127 || new_id == g_node_id_current) { + return; /* invalid or no change */ + } + + /* Use last known device/bitrate; fall back to DT/Kconfig if missing. */ + const struct device *dev = g_last_can_dev ? g_last_can_dev : DEVICE_DT_GET(CAN_NODE); + uint16_t bitrate = g_last_bitrate_kbps ? g_last_bitrate_kbps : CAN_BITRATE_KBPS; + + /* Restart with new Node-ID. This will briefly interrupt communications. */ + co_canopen_stop(); + (void)co_canopen_start(dev, new_id, bitrate); +} +#endif + int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) { if (atomic_get(&g_running)) { @@ -192,9 +256,12 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit if (!can_dev || !device_is_ready(can_dev)) { return -ENODEV; } - if (node_id == 0 || node_id > 127) { + + node_id = resolve_node_id(node_id); + if (node_id < 1 || node_id > 127) { return -EINVAL; } + if (bitrate_kbps == 0) { bitrate_kbps = CAN_BITRATE_KBPS; } @@ -335,7 +402,11 @@ bool co_canopen_is_running(void) static int co_canopen_init_sys(void) { #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) +#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) + (void)co_canopen_start(NULL, 0, CAN_BITRATE_KBPS); +#else (void)co_canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, CAN_BITRATE_KBPS); +#endif #endif return 0; } diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 17887fc3..f1c9a850 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -831,6 +831,21 @@ config CANOPENNODE_INIT_NODE_ID help Node ID for the CANopenNode instance. Must be unique on the CAN bus. + +config CANOPENNODE_NODE_ID_CALLBACK + bool "Allow application-supplied Node-ID callback" + default n + help + Enable an application callback for dynamic Node-ID selection. + + Register your callback BEFORE calling co_canopen_start(): + co_canopen_register_node_id_cb(my_node_id_cb, my_ctx); + + The callback must return a Node-ID in the range 1..127. + Return 0 to indicate "unspecified". If the callback is not + registered or returns 0/out-of-range, the value from + CONFIG_CANOPENNODE_INIT_NODE_ID is used as the fallback. + endmenu endif # CANOPENNODE diff --git a/zephyr/include/CO_zephyr_integration.h b/zephyr/include/CO_zephyr_integration.h index 55527cc0..664bc496 100644 --- a/zephyr/include/CO_zephyr_integration.h +++ b/zephyr/include/CO_zephyr_integration.h @@ -129,6 +129,77 @@ void co_canopen_stop(void); */ bool co_canopen_is_running(void); +#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) + +/** + * @brief Application-supplied provider for the CANopen Node-ID. + * + * This callback is queried by the Zephyr integration when the application + * passes `node_id == 0` to @ref co_canopen_start(), indicating that the + * Node-ID should be sourced dynamically. The callback must return a valid + * CANopen Node-ID in the range 1..127. Returning 0 indicates "unspecified" or + * "invalid", in which case the integration will fall back to + * @c CONFIG_CANOPENNODE_INIT_NODE_ID. + * + * The callback is invoked in the context of @ref co_canopen_start() before the + * stack is started (i.e., not from an ISR). Keep the implementation fast and + * non-blocking. It is safe to read from non-volatile storage or board straps + * if this does not block excessively. + * + * @param[in] user_data + * Opaque pointer supplied when registering the callback via + * @ref co_canopen_register_node_id_cb(). May be @c NULL. + * + * @retval 1..127 Valid Node-ID to use. + * @retval 0 Unspecified/invalid; use fallback. + * + * @see co_canopen_register_node_id_cb() + * @see co_canopen_start() + */ +typedef uint8_t (*co_node_id_cb_t)(void *user_data); + +/** + * @brief Register or clear the application Node-ID callback. + * + * When enabled by Kconfig (@c CONFIG_CANOPENNODE_NODE_ID_CALLBACK), the + * application may provide a function that returns the desired CANopen Node-ID + * at runtime. If @p cb is @c NULL, any previously registered callback is + * cleared and the integration will use the Node-ID explicitly passed to + * @ref co_canopen_start(), or fall back to + * @c CONFIG_CANOPENNODE_INIT_NODE_ID if that value is 0. + * + * @note Call this function **before** @ref co_canopen_start(). Registration is + * not thread-safe with a concurrently starting/stopping stack. + * + * @param[in] cb + * Callback function pointer, or @c NULL to clear the current callback. + * @param[in] user_data + * Opaque pointer forwarded to @p cb on each invocation. Ignored if + * @p cb is @c NULL. May be @c NULL. + * + * @return void + * + * @code{.c} + * // Example: provide Node-ID from DIP switches or settings + * static uint8_t my_node_id_cb(void *ud) + * { + * ARG_UNUSED(ud); + * // return 1..127 if known; return 0 to fall back + * return 7; + * } + * + * void main(void) + * { + * co_canopen_register_node_id_cb(my_node_id_cb, NULL); + * // Pass node_id = 0 to request dynamic Node-ID via the callback + * (void)co_canopen_start(NULL, 0, 500); + * } + * @endcode + */ +void co_canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data); + +#endif /* IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) */ + /** @} */ /* end of co_zephyr_integration */ #ifdef __cplusplus From ebe169a86eb487f0acb404b9a4a9af27e18a886a Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Thu, 14 Aug 2025 18:25:07 -0400 Subject: [PATCH 511/520] Allows node ID 0 and callback-requested ID 255 Updates the node ID resolution logic to allow a node ID of 0, and introduces a special node ID value (255) to explicitly request a node ID from the application callback. This enables scenarios where a node ID of 0 is valid, and provides a clear mechanism to request a dynamic node ID assignment. --- zephyr/CO_zephyr_integration.c | 14 ++++++------- zephyr/include/CO_zephyr_integration.h | 27 +++++++++++++++++++++----- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 2df011dd..da2a415d 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -72,25 +72,25 @@ K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ /* Resolve a usable CANopen Node-ID. * * Priority: - * 1) If 'requested' is in [1..127], use it as-is. + * 1) If 'requested' is in [0..127], use it as-is. * 2) If enabled and registered, ask the application callback * (CONFIG_CANOPENNODE_NODE_ID_CALLBACK). Ignore out-of-range results. * 3) Fall back to CONFIG_CANOPENNODE_INIT_NODE_ID. * * Notes: - * - Pass 0 for 'requested' to defer to the callback or the Kconfig default. - * - The returned value is intended to be in [1..127]; ensure your Kconfig + * - Pass > 127 for 'requested' to defer to the callback or the Kconfig default. + * - The returned value is intended to be in [0..127]; ensure your Kconfig * default is valid for your system. */ static uint8_t resolve_node_id(uint8_t requested) { - if (requested >= 1 && requested <= 127) { + if (requested <= 127) { return requested; } #if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) if (g_node_id_cb) { uint8_t id = g_node_id_cb(g_node_id_cb_ud); - if (id >= 1 && id <= 127) { + if (id <= 127) { return id; } } @@ -258,7 +258,7 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit } node_id = resolve_node_id(node_id); - if (node_id < 1 || node_id > 127) { + if (node_id > 127) { return -EINVAL; } @@ -403,7 +403,7 @@ static int co_canopen_init_sys(void) { #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) #if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) - (void)co_canopen_start(NULL, 0, CAN_BITRATE_KBPS); + (void)co_canopen_start(NULL, CANOPENNODE_NODE_ID_CALLBACK_REQUEST, CAN_BITRATE_KBPS); #else (void)co_canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, CAN_BITRATE_KBPS); #endif diff --git a/zephyr/include/CO_zephyr_integration.h b/zephyr/include/CO_zephyr_integration.h index 664bc496..098a9d77 100644 --- a/zephyr/include/CO_zephyr_integration.h +++ b/zephyr/include/CO_zephyr_integration.h @@ -84,11 +84,28 @@ extern "C" { * @{ */ +/** + * @brief Special CANopen node ID value that requests a new ID via the application callback. + * + * When this value (255) is set as the node ID, it signals that the CANopen device + * should obtain its actual node ID from the application layer by invoking the + * configured callback function. + * + * This mechanism is useful for scenarios where the node ID is not fixed at compile-time + * and must be assigned dynamically during startup or reconfiguration. + * + * @note Per the CANopen standard, 255 (0xFF) is reserved for special purposes and + * must not be used as a normal operational node ID. + * + * @see for the callback responsible for providing the node ID. + */ +#define CANOPENNODE_NODE_ID_CALLBACK_REQUEST 255 + /** * @brief Start CANopenNode with explicit device, node ID, and bitrate. * * Initializes the full CANopen stack and (optionally) the real-time processing - * thread using the given CAN device, CANopen Node-ID (1–127), and bitrate in + * thread using the given CAN device, CANopen Node-ID (0–127), and bitrate in * kbps. When @p can_dev is `NULL`, the CAN device is taken from devicetree * (the `zephyr,canbus` chosen node). When @p bitrate_kbps is 0, the Kconfig * default is used. @@ -137,7 +154,7 @@ bool co_canopen_is_running(void); * This callback is queried by the Zephyr integration when the application * passes `node_id == 0` to @ref co_canopen_start(), indicating that the * Node-ID should be sourced dynamically. The callback must return a valid - * CANopen Node-ID in the range 1..127. Returning 0 indicates "unspecified" or + * CANopen Node-ID in the range 0..127. Returning 0 indicates "unspecified" or * "invalid", in which case the integration will fall back to * @c CONFIG_CANOPENNODE_INIT_NODE_ID. * @@ -150,8 +167,8 @@ bool co_canopen_is_running(void); * Opaque pointer supplied when registering the callback via * @ref co_canopen_register_node_id_cb(). May be @c NULL. * - * @retval 1..127 Valid Node-ID to use. - * @retval 0 Unspecified/invalid; use fallback. + * @retval 0..127 Valid Node-ID to use. + * @retval >127 Unspecified/invalid; use fallback. * * @see co_canopen_register_node_id_cb() * @see co_canopen_start() @@ -184,7 +201,7 @@ typedef uint8_t (*co_node_id_cb_t)(void *user_data); * static uint8_t my_node_id_cb(void *ud) * { * ARG_UNUSED(ud); - * // return 1..127 if known; return 0 to fall back + * // return 0..127 if known; return 0 to fall back * return 7; * } * From d7d62f65880ec86da2b8fe86ce034c710069a160 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Fri, 15 Aug 2025 18:21:48 -0400 Subject: [PATCH 512/520] Implements CiA 302-3 Program Download Adds support for program download functionality as specified in CiA 302-3, including OD entries and streaming operations. Renames crc16-ccitt files to CO_crc16-ccitt for consistency and to avoid naming conflicts in certain build environments. Zephyr CRC16 implementation is used via a shim. --- 301/CO_SDOserver.c | 8 +- 301/CO_config.h | 29 ++ 301/{crc16-ccitt.c => CO_crc16-ccitt.c} | 12 +- 301/{crc16-ccitt.h => CO_crc16-ccitt.h} | 6 +- 301/CO_fifo.c | 6 +- 302/CO_Prog_Download.c | 368 +++++++++++++++++++++ 302/CO_Prog_Download.h | 212 ++++++++++++ 304/CO_SRDO.c | 18 +- storage/CO_storageEeprom.c | 6 +- zephyr/CMakeLists.txt | 16 +- zephyr/CO_zephyr_crc16-ccitt.c | 32 +- zephyr/CO_zephyr_program.c | 423 ++++++++++++++++++++++++ zephyr/Kconfig | 26 +- zephyr/include/CO_zephyr_config.h | 12 + zephyr/include/CO_zephyr_program.h | 0 15 files changed, 1117 insertions(+), 57 deletions(-) rename 301/{crc16-ccitt.c => CO_crc16-ccitt.c} (92%) rename 301/{crc16-ccitt.h => CO_crc16-ccitt.h} (90%) create mode 100644 302/CO_Prog_Download.c create mode 100644 302/CO_Prog_Download.h create mode 100644 zephyr/CO_zephyr_program.c create mode 100644 zephyr/include/CO_zephyr_program.h diff --git a/301/CO_SDOserver.c b/301/CO_SDOserver.c index 728ea3fd..570bdb2f 100644 --- a/301/CO_SDOserver.c +++ b/301/CO_SDOserver.c @@ -21,7 +21,7 @@ #include #include "301/CO_SDOserver.h" -#include "301/crc16-ccitt.h" +#include "301/CO_crc16-ccitt.h" /* verify configuration */ #if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_SEGMENTED) != 0 @@ -454,7 +454,7 @@ validateAndWriteToOD(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, uint8_t #if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 /* calculate crc on current data */ if (SDO->block_crcEnabled && crcOperation > 0) { - SDO->block_crc = crc16_ccitt(SDO->buf, bufOffsetWrOrig, SDO->block_crc); + SDO->block_crc = CO_crc16_ccitt(SDO->buf, bufOffsetWrOrig, SDO->block_crc); if (crcOperation == 2 && crcClient != SDO->block_crc) { *abortCode = CO_SDO_AB_CRC; SDO->state = CO_SDO_ST_ABORT; @@ -582,7 +582,7 @@ readFromOd(CO_SDOserver_t* SDO, CO_SDO_abortCode_t* abortCode, OD_size_t countMi #if ((CO_CONFIG_SDO_SRV)&CO_CONFIG_SDO_SRV_BLOCK) != 0 /* update the crc */ if (calculateCrc && SDO->block_crcEnabled) { - SDO->block_crc = crc16_ccitt(&SDO->buf[countRemain], countRd, SDO->block_crc); + SDO->block_crc = CO_crc16_ccitt(&SDO->buf[countRemain], countRd, SDO->block_crc); } #endif } @@ -944,7 +944,7 @@ CO_SDOserver_process(CO_SDOserver_t* SDO, bool_t NMTisPreOrOperational, uint32_t /* data were already loaded from OD variable, verify crc */ if ((SDO->CANrxData[0] & 0x04) != 0) { SDO->block_crcEnabled = true; - SDO->block_crc = crc16_ccitt(SDO->buf, SDO->bufOffsetWr, 0); + SDO->block_crc = CO_crc16_ccitt(SDO->buf, SDO->bufOffsetWr, 0); } else { SDO->block_crcEnabled = false; } diff --git a/301/CO_config.h b/301/CO_config.h index be2e1939..5e0400f4 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -520,6 +520,35 @@ extern "C" { #define CO_CONFIG_STORAGE_ENABLE 0x01 /** @} */ /* CO_STACK_CONFIG_STORAGE */ +/** + * @defgroup CO_STACK_CONFIG_PROG_DOWNLOAD Program download (CiA 302-3) + * Specified in CiA 302-3: Configuration and Program download + * @{ + */ +/** + * Configuration of @ref CO_Prog_Download + * + * Possible flags, can be ORed: + * - CO_CONFIG_PROG_DOWNLOAD_ENABLE - Enable Program Download object (0x1F50, 0x1F51, 0x1F56, 0x1F57) + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_PROG_DOWNLOAD (CO_CONFIG_PROG_DOWNLOAD_ENABLE) +#endif +#define CO_CONFIG_PROG_DOWNLOAD_ENABLE 0x01 + +/** + * Maximum EDS file size in bytes. + * + * Used by CO_Prog_Download for OD entry 0x1F23 ("Store EDS NMT slave"). + * If the EDS data exceeds this limit, the download will be aborted + * with ODR_OUT_OF_MEM. + */ +#ifdef CO_DOXYGEN +#define CO_CONFIG_PROG_DOWNLOAD_EDS_MAX_SIZE 2048 +#endif + +/** @} */ /* CO_STACK_CONFIG_PROG_DOWNLOAD */ + /** * @defgroup CO_STACK_CONFIG_LEDS CANopen LED diodes * Specified in standard CiA 303-3 diff --git a/301/crc16-ccitt.c b/301/CO_crc16-ccitt.c similarity index 92% rename from 301/crc16-ccitt.c rename to 301/CO_crc16-ccitt.c index 5f1c2f34..2520479b 100644 --- a/301/crc16-ccitt.c +++ b/301/CO_crc16-ccitt.c @@ -18,15 +18,15 @@ * See the License for the specific language governing permissions and limitations under the License. */ -#include "301/crc16-ccitt.h" +#include "301/CO_crc16-ccitt.h" -#if ((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_ENABLE) != 0 -#if ((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_EXTERNAL) == 0 +#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) != 0 +#if ((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_EXTERNAL) == 0 /* * CRC table calculated by the following algorithm: * - * void crc16_ccitt_table_init(void){ + * void CO_crc16_ccitt_table_init(void){ * uint16_t i, j; * for(i=0; i<256; i++){ * uint16_t crc = 0; @@ -63,13 +63,13 @@ static const uint16_t crc16_ccitt_table[256] = { 0x9FF8U, 0x6E17U, 0x7E36U, 0x4E55U, 0x5E74U, 0x2E93U, 0x3EB2U, 0x0ED1U, 0x1EF0U}; void -crc16_ccitt_single(uint16_t* crc, const uint8_t chr) { +CO_crc16_ccitt_single(uint16_t* crc, const uint8_t chr) { uint8_t tmp = (uint8_t)(*crc >> 8U) ^ chr; *crc = (uint16_t)((*crc << 8U) ^ crc16_ccitt_table[tmp]); } uint16_t -crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) { +CO_crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) { size_t i; for (i = 0U; i < blockLength; i++) { diff --git a/301/crc16-ccitt.h b/301/CO_crc16-ccitt.h similarity index 90% rename from 301/crc16-ccitt.h rename to 301/CO_crc16-ccitt.h index 5712ad5b..12f1c6af 100644 --- a/301/crc16-ccitt.h +++ b/301/CO_crc16-ccitt.h @@ -29,7 +29,7 @@ #define CO_CONFIG_CRC16 (0) #endif -#if (((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_ENABLE) != 0) || defined CO_DOXYGEN +#if (((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { @@ -55,7 +55,7 @@ extern "C" { * be initialized (zero for xmodem). * @param chr One byte of data */ -void crc16_ccitt_single(uint16_t* crc, const uint8_t chr); +void CO_crc16_ccitt_single(uint16_t* crc, const uint8_t chr); /** * Calculate CRC sum on block of data. @@ -67,7 +67,7 @@ void crc16_ccitt_single(uint16_t* crc, const uint8_t chr); * * @return Calculated CRC. */ -uint16_t crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc); +uint16_t CO_crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc); /** @} */ /* CO_crc16_ccitt */ diff --git a/301/CO_fifo.c b/301/CO_fifo.c index cadb7446..69e032b9 100644 --- a/301/CO_fifo.c +++ b/301/CO_fifo.c @@ -26,7 +26,7 @@ #include #include -#include "crc16-ccitt.h" +#include "CO_crc16-ccitt.h" #if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_ASCII_COMMANDS) != 0 #include @@ -97,7 +97,7 @@ CO_fifo_write(CO_fifo_t* fifo, const uint8_t* buf, size_t count, uint16_t* crc) #if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_CRC16_CCITT) != 0 if (crc != NULL) { - crc16_ccitt_single(crc, *buf); + CO_crc16_ccitt_single(crc, *buf); } #endif @@ -199,7 +199,7 @@ CO_fifo_altFinish(CO_fifo_t* fifo, uint16_t* crc) { const uint8_t* bufSrc = &fifo->buf[fifo->readPtr]; while (fifo->readPtr != fifo->altReadPtr) { #if ((CO_CONFIG_FIFO)&CO_CONFIG_FIFO_CRC16_CCITT) != 0 - crc16_ccitt_single(crc, *bufSrc); + CO_crc16_ccitt_single(crc, *bufSrc); #endif /* increment variable */ if (++fifo->readPtr == fifo->bufSize) { diff --git a/302/CO_Prog_Download.c b/302/CO_Prog_Download.c new file mode 100644 index 00000000..053388a6 --- /dev/null +++ b/302/CO_Prog_Download.c @@ -0,0 +1,368 @@ +/* + * CANopen Program Download (CiA 302-3 oriented, streaming + storage-friendly) + * + * @file CO_Prog_Download.c + * @ingroup CO_Prog_Download + * @author BitConcepts + * @copyright 2025 BitConcepts + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#include "CO_Prog_Download.h" + +#if ((CO_CONFIG_PROG_DOWNLOAD) & CO_CONFIG_PROG_DOWNLOAD_ENABLE) != 0 + +#ifndef CO_PROGDL_EDS_MAX +#ifdef CO_CONFIG_PROG_DOWNLOAD_EDS_MAX_SIZE +#define CO_PROGDL_EDS_MAX ((uint32_t)CO_CONFIG_PROG_DOWNLOAD_EDS_MAX_SIZE) +#else +#define CO_PROGDL_EDS_MAX (2048) +#endif +#endif + +#include +#include "301/CO_crc16-ccitt.h" + +/* If globals are requested, provide a static buffer for EDS data. */ +#ifdef CO_USE_GLOBALS +static uint8_t CO_ProgDL_EDS_StaticBuf[CO_PROGDL_EDS_MAX]; +#endif + +/* ---------- Internal helpers ---------- */ + +static inline void +pdl_setStatus(CO_ProgDL_t* pdl, uint32_t set, uint32_t clr) { + pdl->status &= ~clr; + pdl->status |= set; +} + +/* Optionally persist EDS via CO_storage after a completed transfer. */ +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 +static ODR_t +pdl_persistEDS(CO_ProgDL_t* pdl) { + if ((pdl != NULL) && pdl->storage && pdl->edsEntry && pdl->storage->store) { + return pdl->storage->store(pdl->edsEntry, pdl->storage->CANmodule); + } + return ODR_OK; +} +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +/* ---------- OD extension read/write hooks ---------- */ + +/* 0x1F21 Store format (RO) */ +static ODR_t +OD_read_1F21(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + (void)buf; + (void)count; + + if ((buf == NULL) || (stream == NULL) || (countRead == NULL)) { + return ODR_DEV_INCOMPAT; + } + + uint32_t fmt = CO_PROGDL_STORE_FMT_PROG; + return OD_readOriginal(stream, &fmt, sizeof(fmt), countRead); +} + +/* 0x1F24 Store format EDS NMT slave (RO) */ +static ODR_t +OD_read_1F24(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + (void)buf; + (void)count; + + if ((buf == NULL) || (stream == NULL) || (countRead == NULL)) { + return ODR_DEV_INCOMPAT; + } + + uint32_t fmt = CO_PROGDL_STORE_FMT_EDS; + return OD_readOriginal(stream, &fmt, sizeof(fmt), countRead); +} + +/* 0x1F56 Program software identification (RW VISIBLE_STRING) */ +static ODR_t +OD_read_1F56(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + if ((buf == NULL) || (stream == NULL) || (countRead == NULL)) { + return ODR_DEV_INCOMPAT; + } + + CO_ProgDL_t* pdl = (CO_ProgDL_t*)stream->object; + size_t len = strnlen(pdl->swId, sizeof(pdl->swId)); + return OD_readOriginal(stream, pdl->swId, (OD_size_t)len, countRead); +} + +static ODR_t +OD_write_1F56(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { + return ODR_DEV_INCOMPAT; + } + + CO_ProgDL_t* pdl = (CO_ProgDL_t*)stream->object; + size_t n = (size_t)((count < sizeof(pdl->swId) - 1) ? count : (sizeof(pdl->swId) - 1)); + (void)memset(pdl->swId, 0, sizeof(pdl->swId)); + (void)memcpy(pdl->swId, buf, n); + if (countWritten) { + *countWritten = (OD_size_t)n; + } + return ODR_OK; +} + +/* 0x1F57 Flash status identification (RO U32) */ +static ODR_t +OD_read_1F57(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead) { + if ((buf == NULL) || (stream == NULL) || (countRead == NULL)) { + return ODR_DEV_INCOMPAT; + } + + CO_ProgDL_t* pdl = (CO_ProgDL_t*)stream->object; + return OD_readOriginal(stream, &pdl->status, sizeof(pdl->status), countRead); +} + +/* 0x1F50 Program data – forward chunks to streaming backend and update CRC16-CCITT */ +static ODR_t +OD_write_1F50(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { + return ODR_DEV_INCOMPAT; + } + + CO_ProgDL_t* pdl = (CO_ProgDL_t*)stream->object; + if (!pdl->sessionOpen) { + return ODR_NO_RESOURCE; /* require BEGIN */ + } + if (!pdl->ops.write) { + return ODR_GENERAL; + } + + if (!pdl->ops.write((const uint8_t*)buf, (uint32_t)count)) { + pdl_setStatus(pdl, CO_PROGDL_STATUS_ERROR, 0); + return ODR_HW; + } + + pdl->bytesReceived += (uint32_t)count; + pdl->runningCRC16 = CO_crc16_ccitt((const uint8_t*)buf, (size_t)count, pdl->runningCRC16); + pdl_setStatus(pdl, CO_PROGDL_STATUS_RECEIVING | CO_PROGDL_STATUS_WRITING, 0); + + if (countWritten) { + *countWritten = count; + } + return ODR_OK; +} + +/* 0x1F51 Program control (U32) */ +static ODR_t +OD_write_1F51(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + (void)count; + + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { + return ODR_DEV_INCOMPAT; + } + + CO_ProgDL_t* pdl = (CO_ProgDL_t*)stream->object; + uint32_t cmd = 0; + (void)memcpy(&cmd, buf, sizeof(uint32_t)); + + switch (cmd) { + case CO_PROGDL_CTRL_ABORT: + if (pdl->ops.abort) { + pdl->ops.abort(); + } + pdl->sessionOpen = false; + pdl->bytesReceived = 0; + pdl->runningCRC16 = 0; + pdl->imageSizeHint = 0; + pdl_setStatus(pdl, 0, + CO_PROGDL_STATUS_RECEIVING | CO_PROGDL_STATUS_WRITING | CO_PROGDL_STATUS_ERASING + | CO_PROGDL_STATUS_VERIFYING | CO_PROGDL_STATUS_DONE_OK | CO_PROGDL_STATUS_ERROR); + break; + + case CO_PROGDL_CTRL_BEGIN: + if (!pdl->ops.begin) { + return ODR_GENERAL; + } + pdl_setStatus(pdl, CO_PROGDL_STATUS_ERASING, CO_PROGDL_STATUS_DONE_OK | CO_PROGDL_STATUS_ERROR); + if (!pdl->ops.begin(pdl->imageSizeHint)) { + pdl_setStatus(pdl, CO_PROGDL_STATUS_ERROR, CO_PROGDL_STATUS_ERASING); + return ODR_HW; + } + pdl->sessionOpen = true; + pdl->bytesReceived = 0; + pdl->runningCRC16 = 0; + pdl_setStatus(pdl, CO_PROGDL_STATUS_RECEIVING, CO_PROGDL_STATUS_ERASING); + break; + + case CO_PROGDL_CTRL_COMMIT: + if (!pdl->sessionOpen) { + return ODR_INVALID_VALUE; + } + if (!pdl->ops.commit) { + return ODR_GENERAL; + } + pdl_setStatus(pdl, CO_PROGDL_STATUS_VERIFYING, CO_PROGDL_STATUS_RECEIVING | CO_PROGDL_STATUS_WRITING); + if (!pdl->ops.commit()) { + pdl_setStatus(pdl, CO_PROGDL_STATUS_ERROR, CO_PROGDL_STATUS_VERIFYING); + return ODR_HW; + } + /* Optionally persist via CO_storage (e.g. mark/program metadata) */ +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 + if (pdl->storage && pdl->fwEntry && pdl->storage->store) { + ODR_t r = pdl->storage->store(pdl->fwEntry, pdl->storage->CANmodule); + if (r != ODR_OK) { + pdl_setStatus(pdl, CO_PROGDL_STATUS_ERROR, CO_PROGDL_STATUS_DONE_OK); + return ODR_HW; + } + } +#endif + pdl->sessionOpen = false; + pdl_setStatus(pdl, CO_PROGDL_STATUS_DONE_OK, CO_PROGDL_STATUS_VERIFYING); + break; + + case CO_PROGDL_CTRL_JUMP_BOOT: + if (pdl->ops.jumpToBootloader) { + pdl->ops.jumpToBootloader(); + } + return ODR_GENERAL; /* Should not return if jump was successful */ + + default: return ODR_INVALID_VALUE; + } + + if (countWritten) { + *countWritten = sizeof(uint32_t); + } + return ODR_OK; +} + +/* 0x1F23 Store EDS NMT slave – buffered here; app can persist via CO_storage */ +static ODR_t +OD_write_1F23(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten) { + if ((stream == NULL) || (buf == NULL) || (countWritten == NULL)) { + return ODR_DEV_INCOMPAT; + } + + CO_ProgDL_t* pdl = (CO_ProgDL_t*)stream->object; + +#ifdef CO_USE_GLOBALS + /* Use statically defined buffer; initialize it lazily if needed */ + if (pdl->edsBuf == NULL) { + pdl->edsBuf = CO_ProgDL_EDS_StaticBuf; + pdl->edsLen = 0; + } +#else + /* Allocate from heap on first use */ + if (pdl->edsBuf == NULL) { + pdl->edsBuf = (uint8_t*)CO_alloc((size_t)CO_PROGDL_EDS_MAX); + if (pdl->edsBuf == NULL) { + return ODR_OUT_OF_MEM; + } + pdl->edsLen = 0; + } +#endif + + if (pdl->edsLen + count > CO_PROGDL_EDS_MAX) { + return ODR_DATA_LONG; + } + (void)memcpy(&pdl->edsBuf[pdl->edsLen], buf, count); + pdl->edsLen += (uint32_t)count; + if (countWritten) { + *countWritten = count; + } + return ODR_OK; +} + +/* ---------- Initialization / API ---------- */ + +static void +attach_ext(CO_ProgDL_t* pdl, OD_extension_t* ext, uint16_t idx, void* rd, void* wr) { + OD_entry_t* entry = OD_find(pdl->co->SDOserver->OD, idx); + if (entry) { + ext->read = rd; + ext->write = wr; + (void)OD_extension_init(entry, ext); + } +} + +CO_ReturnError_t +CO_Prog_Download_init(CO_ProgDL_t* pdl, CO_t* co) { + if ((pdl == NULL) || (co == NULL)) { + return CO_ERROR_ILLEGAL_ARGUMENT; + } + + (void)memset(pdl, 0, sizeof(*pdl)); + pdl->co = co; + pdl->status = CO_PROGDL_STATUS_IDLE; + +#ifdef CO_USE_GLOBALS + /* Pre-bind the static buffer for EDS. */ + pdl->edsBuf = CO_ProgDL_EDS_StaticBuf; + pdl->edsLen = 0; +#endif + + attach_ext(pdl, &pdl->ext_1F21, 0x1F21, OD_read_1F21, NULL); + attach_ext(pdl, &pdl->ext_1F24, 0x1F24, OD_read_1F24, NULL); + attach_ext(pdl, &pdl->ext_1F56, 0x1F56, OD_read_1F56, OD_write_1F56); + attach_ext(pdl, &pdl->ext_1F57, 0x1F57, OD_read_1F57, NULL); + attach_ext(pdl, &pdl->ext_1F50, 0x1F50, NULL, OD_write_1F50); + attach_ext(pdl, &pdl->ext_1F51, 0x1F51, NULL, OD_write_1F51); + attach_ext(pdl, &pdl->ext_1F23, 0x1F23, NULL, OD_write_1F23); + + return CO_ERROR_NO; +} + +void +CO_Prog_Download_deinit(CO_ProgDL_t* pdl) { + if (pdl == NULL) { + return; + } +#ifndef CO_USE_GLOBALS + if (pdl->edsBuf) { + CO_free(pdl->edsBuf); + pdl->edsBuf = NULL; + } +#else + /* Using static storage: nothing to free, just clear length. */ + pdl->edsLen = 0; +#endif +} + +int +CO_Prog_Download_registerStreamOps(CO_ProgDL_t* pdl, const CO_ProgDL_StreamOps_t* ops) { + if ((pdl == NULL) || (ops == NULL)) { + return -1; + } + pdl->ops = *ops; + return 0; +} + +void +CO_Prog_Download_setImageSizeHint(CO_ProgDL_t* pdl, uint32_t size_hint) { + if (pdl == NULL) { + return; + } + pdl->imageSizeHint = size_hint; +} + +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 +void +CO_Prog_Download_bindStorage(CO_ProgDL_t* pdl, CO_storage_t* storage, CO_storage_entry_t* fwEntry, + CO_storage_entry_t* edsEntry) { + if (pdl == NULL) { + return; + } + pdl->storage = storage; + pdl->fwEntry = fwEntry; + pdl->edsEntry = edsEntry; +} + +ODR_t +CO_Prog_Download_persistEDS(CO_ProgDL_t* pdl) { + return pdl_persistEDS(pdl); +} +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ +#endif /* (CO_CONFIG_PROG_DOWNLOAD) & CO_CONFIG_PROG_DOWNLOAD_ENABLE */ diff --git a/302/CO_Prog_Download.h b/302/CO_Prog_Download.h new file mode 100644 index 00000000..dfa4d4ae --- /dev/null +++ b/302/CO_Prog_Download.h @@ -0,0 +1,212 @@ +/** + * CANopen Program Download (CiA 302-3 oriented, streaming + storage-friendly) + * + * @file CO_Prog_Download.h + * @ingroup CO_Prog_Download + * @author BitConcepts + * @copyright 2025 BitConcepts + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +#ifndef CO_PROG_DOWNLOAD_H +#define CO_PROG_DOWNLOAD_H + +#include "CANopen.h" +#include "301/CO_driver.h" +#include "301/CO_ODinterface.h" + +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 +#include "storage/CO_storage.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* default configuration, see CO_config.h */ +#ifndef CO_CONFIG_PROG_DOWNLOAD +#define CO_CONFIG_PROG_DOWNLOAD (0) +#endif + +#if (((CO_CONFIG_PROG_DOWNLOAD) & CO_CONFIG_PROG_DOWNLOAD_ENABLE) != 0) || defined CO_DOXYGEN + +/** + * @defgroup CO_Prog_Download Program Download + * Program Download support per CiA 302-3 using CANopen SDO (DOMAIN) transfer. + * + * @ingroup CO_CANopen_302 + * @{ + * + * Bytes arrive over SDO into 0x1F50 and are forwarded to a streaming backend + * (e.g., flash writer, bootloader) via `begin`/`write`/`commit`. This module is + * storage-agnostic and *optionally* binds to CO_storage to persist metadata/EDS. + * + * ### OD entries used by this module + * - 0x1F21: Store format (U32, RO) + * - 0x1F23: Store EDS NMT slave (DOMAIN) + * - 0x1F24: Store format EDS NMT slave (U32, RO) + * - 0x1F50: Program data (DOMAIN) + * - 0x1F51: Program control (U32) + * - 0x1F56: Program software identification (VISIBLE_STRING) + * - 0x1F57: Flash status identification (U32, RO) + * + * ### Control values for 0x1F51 + * - 0x00000000: ABORT + * - 0x00000001: BEGIN + * - 0x00000002: COMMIT + * - 0x0000B007: JUMP (optional jump to bootloader) + */ + +/** Streaming backend operations supplied by the application/port. */ +typedef struct { + /** Called on BEGIN. May prepare erase or open a stream. */ + bool_t (*begin)(uint32_t image_size_hint); + /** Called for each chunk written to 0x1F50. Must be safe for repeated calls. */ + bool_t (*write)(const uint8_t* data, uint32_t len); + /** Called on COMMIT to finalize/verify and make image ready. */ + bool_t (*commit)(void); + /** Called on ABORT to cleanup (optional). */ + void (*abort)(void); + /** Optional: jump to bootloader after successful programming. */ + void (*jumpToBootloader)(void); +} CO_ProgDL_StreamOps_t; + +/** Status bits for 0x1F57. */ +typedef enum { + CO_PROGDL_STATUS_IDLE = 0u, + CO_PROGDL_STATUS_RECEIVING = 1u << 0, + CO_PROGDL_STATUS_ERASING = 1u << 1, + CO_PROGDL_STATUS_WRITING = 1u << 2, + CO_PROGDL_STATUS_VERIFYING = 1u << 3, + CO_PROGDL_STATUS_DONE_OK = 1u << 4, + CO_PROGDL_STATUS_ERROR = 1u << 5 +} CO_ProgDL_StatusBit_t; + +/** Control values for 0x1F51. */ +typedef enum { + CO_PROGDL_CTRL_ABORT = 0x00000000u, + CO_PROGDL_CTRL_BEGIN = 0x00000001u, + CO_PROGDL_CTRL_COMMIT = 0x00000002u, + CO_PROGDL_CTRL_JUMP_BOOT = 0x0000B007u +} CO_ProgDL_Control_t; + +/** Informational store format constants returned in 0x1F21/0x1F24. */ +typedef enum { CO_PROGDL_STORE_FMT_PROG = 0x00000001u, CO_PROGDL_STORE_FMT_EDS = 0x00000001u } CO_ProgDL_StoreFmt_t; + +/** Program Download object */ +typedef struct { + /* Core */ + CO_t* co; /**< From CO_Prog_Download_init() */ + +/* Optional: CANopenNode Storage binding (0x1010/0x1011) */ +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 + CO_storage_t* storage; /**< From CO_Prog_Download_bindStorage(), optional */ + CO_storage_entry_t* fwEntry; /**< Storage entry for firmware image metadata, optional */ + CO_storage_entry_t* edsEntry; /**< Storage entry for EDS, optional */ +#endif + + /* Streaming backend (port-supplied) */ + CO_ProgDL_StreamOps_t ops; + + /* State */ + uint32_t status; /**< Status bitfield for 0x1F57 */ + bool_t sessionOpen; /**< True after BEGIN until COMMIT/ABORT */ + uint32_t bytesReceived; /**< Bytes written to 0x1F50 in current session */ + uint32_t imageSizeHint; /**< Optional size hint (0 if unknown) */ + uint16_t runningCRC16; /**< Running CRC16 (CRC16-CCITT) */ + + /* 0x1F56: software identification */ + char swId[64]; + + /* EDS buffering (0x1F23); can be replaced by app-specific persistence */ + uint8_t* edsBuf; + uint32_t edsLen; + + /* OD extensions */ + OD_extension_t ext_1F21, ext_1F23, ext_1F24, ext_1F50, ext_1F51, ext_1F56, ext_1F57; +} CO_ProgDL_t; + +/** + * Initialize Program Download object. + * + * Function must be called in the communication reset section, after SDO/OD are ready. + * + * @param pdl This object will be initialized. + * @param co CANopen root object. + * + * @return #CO_ReturnError_t CO_ERROR_NO on success. + */ +CO_ReturnError_t CO_Prog_Download_init(CO_ProgDL_t* pdl, CO_t* co); + +/** + * Deinitialize Program Download object. + * + * @param pdl This object. + */ +void CO_Prog_Download_deinit(CO_ProgDL_t* pdl); + +/** + * Register streaming backend operations (required). + * + * @param pdl Program Download object. + * @param ops Streaming operations; copied by value. + * + * @return 0 on success, -1 on invalid args. + */ +int CO_Prog_Download_registerStreamOps(CO_ProgDL_t* pdl, const CO_ProgDL_StreamOps_t* ops); + +/** + * Optionally set an image size hint (forwarded to ops.begin()). + * + * @param pdl Program Download object. + * @param size_hint Expected total image size in bytes (0 if unknown). + */ +void CO_Prog_Download_setImageSizeHint(CO_ProgDL_t* pdl, uint32_t size_hint); + +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 +/** + * Optionally bind to CANopenNode Storage API. + * + * If bound, this module will call `storage->store(fwEntry, ...)` after a successful + * COMMIT. Application may also persist EDS after transfer using + * CO_Prog_Download_persistEDS(). + * + * @param pdl Program Download object. + * @param storage CO_storage instance. + * @param fwEntry Storage entry describing the firmware image metadata region. + * @param edsEntry Storage entry describing EDS region. + */ +#if ((CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE) != 0 +void CO_Prog_Download_bindStorage(CO_ProgDL_t* pdl, CO_storage_t* storage, CO_storage_entry_t* fwEntry, + CO_storage_entry_t* edsEntry); +#endif +/** + * Persist EDS (0x1F23) via CO_storage after transfer completes. + * + * This is optional and only effective if CO_storage is bound and `edsEntry` provided. + * + * @param pdl Program Download object. + * @return ODR_OK on success or an appropriate ODR_* error. + */ +ODR_t CO_Prog_Download_persistEDS(CO_ProgDL_t* pdl); +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ + +/** @} */ /* CO_Prog_Download */ + +#endif /* (CO_CONFIG_PROG_DOWNLOAD) & CO_CONFIG_PROG_DOWNLOAD_ENABLE */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CO_PROG_DOWNLOAD_H */ diff --git a/304/CO_SRDO.c b/304/CO_SRDO.c index d3d36730..d1cd0fa6 100644 --- a/304/CO_SRDO.c +++ b/304/CO_SRDO.c @@ -24,7 +24,7 @@ #if ((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0 -#include "301/crc16-ccitt.h" +#include "301/CO_crc16-ccitt.h" /* verify configuration */ #if ((CO_CONFIG_CRC16)&CO_CONFIG_CRC16_ENABLE) == 0 @@ -512,20 +512,20 @@ CO_SRDO_config(CO_SRDO_t* SRDO, uint8_t SRDO_Index, CO_SRDOGuard_t* SRDOGuard, u uint16_t tmp_u16; uint32_t tmp_u32; - crcResult = crc16_ccitt(&informationDirection, 1, crcResult); + crcResult = CO_crc16_ccitt(&informationDirection, 1, crcResult); tmp_u16 = CO_SWAP_16(safetyCycleTime); - crcResult = crc16_ccitt((uint8_t*)&tmp_u16, 2, crcResult); - crcResult = crc16_ccitt(&safetyRelatedValidationTime, 1, crcResult); + crcResult = CO_crc16_ccitt((uint8_t*)&tmp_u16, 2, crcResult); + crcResult = CO_crc16_ccitt(&safetyRelatedValidationTime, 1, crcResult); tmp_u32 = CO_SWAP_32(COB_ID1_normal); - crcResult = crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); + crcResult = CO_crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); tmp_u32 = CO_SWAP_32(COB_ID2_inverted); - crcResult = crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); - crcResult = crc16_ccitt(&mappedObjectsCount, 1, crcResult); + crcResult = CO_crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); + crcResult = CO_crc16_ccitt(&mappedObjectsCount, 1, crcResult); for (uint8_t i = 0; i < mappedObjectsCount; i++) { uint8_t crcsubindex = i + 1U; - crcResult = crc16_ccitt(&crcsubindex, 1, crcResult); + crcResult = CO_crc16_ccitt(&crcsubindex, 1, crcResult); tmp_u32 = CO_SWAP_32(mapping[i]); - crcResult = crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); + crcResult = CO_crc16_ccitt((uint8_t*)&tmp_u32, 4, crcResult); } if (crcResult != crcSignatureFromOD) { diff --git a/storage/CO_storageEeprom.c b/storage/CO_storageEeprom.c index 045d6281..d2720dd4 100644 --- a/storage/CO_storageEeprom.c +++ b/storage/CO_storageEeprom.c @@ -19,7 +19,7 @@ #include "storage/CO_storageEeprom.h" #include "storage/CO_eeprom.h" -#include "301/crc16-ccitt.h" +#include "301/CO_crc16-ccitt.h" #if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0 @@ -35,7 +35,7 @@ storeEeprom(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { /* save data to the eeprom */ writeOk = CO_eeprom_writeBlock(entry->storageModule, entry->addr, entry->eepromAddr, entry->len); - entry->crc = crc16_ccitt(entry->addr, entry->len, 0); + entry->crc = CO_crc16_ccitt(entry->addr, entry->len, 0); /* Verify, if data in eeprom are equal */ uint16_t crc_read = CO_eeprom_getCrcBlock(entry->storageModule, entry->eepromAddr, entry->len); @@ -160,7 +160,7 @@ CO_storageEeprom_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, void* st /* Verify CRC, except for auto storage variables */ if (!isAuto) { - uint16_t crc = crc16_ccitt(entry->addr, entry->len, 0); + uint16_t crc = CO_crc16_ccitt(entry->addr, entry->len, 0); if (crc != entry->crc) { dataCorrupt = true; } diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 894c0882..fffbac3a 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -182,11 +182,11 @@ endif() # - Otherwise: use CANopenNode's built-in CRC16 implementation if(CONFIG_CANOPENNODE_CRC16_ENABLE) if(CONFIG_CANOPENNODE_CRC16_EXTERNAL) - # NOTE: If your file is named 'CO_zephyr_crc16-ccitt.c', ensure the path matches. - # The double '.c.c' below appears intentional from the original source; adjust if needed. - zephyr_library_sources("${CANOPENNODE_DIR}/zephyr/CO_zephyr_crc16-ccitt.c.c") + zephyr_library_sources( + "${CANOPENNODE_DIR}/zephyr/CO_zephyr_crc16-ccitt.c" + ) else() - zephyr_library_sources("${CANOPENNODE_DIR}/301/crc16-ccitt.c") + zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_crc16-ccitt.c") endif() endif() @@ -228,6 +228,14 @@ if(CONFIG_CANOPENNODE_TIME_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_TIME.c") endif() +# Program Download (CiA 302-3) +if(CONFIG_CANOPENNODE_PROG_DOWNLOAD) + zephyr_library_sources( + "${CANOPENNODE_DIR}/302/CO_Prog_Download.c" + + ) +endif() + # LEDs (CiA 303-3): include stack LED state machine and Zephyr GPIO bridge. if(CONFIG_CANOPENNODE_LEDS_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/303/CO_LEDs.c") diff --git a/zephyr/CO_zephyr_crc16-ccitt.c b/zephyr/CO_zephyr_crc16-ccitt.c index a1583093..ad435265 100644 --- a/zephyr/CO_zephyr_crc16-ccitt.c +++ b/zephyr/CO_zephyr_crc16-ccitt.c @@ -2,10 +2,7 @@ /* * CANopenNode CRC-16/CCITT shim to Zephyr. * - * Bridges CANopenNode's CRC API to Zephyr's CRC helpers by temporarily - * renaming Zephyr's crc16_ccitt() symbol during inclusion to avoid a - * prototype collision. Provides drop-in definitions that match the - * CANopenNode signatures. + * Bridges CANopenNode's CRC API to Zephyr's CRC. * * @file CO_zephyr_crc16-ccitt.c * @author BitConcepts, LLC @@ -24,45 +21,32 @@ * the License. */ -#include "301/crc16-ccitt.h" -#include - -/* - * We need to include Zephyr's CRC API but avoid a symbol/type conflict: - * Zephyr declares: - * uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len); - * while CANopenNode declares: - * uint16_t crc16_ccitt(const uint8_t *block, size_t len, uint16_t crc); - * - * To prevent conflicting prototypes, we temporarily remap the Zephyr - * declaration to ZEPHYR_crc16_ccitt before including . - */ -#define crc16_ccitt ZEPHYR_crc16_ccitt +#include "301/CO_crc16-ccitt.h" #include -#undef crc16_ccitt +#include +#include /* * This companion helper matches CANopenNode’s expected single-byte update form. * When crc is NULL, the call is ignored. */ -void crc16_ccitt_single(uint16_t *crc, const uint8_t chr) +void CO_crc16_ccitt_single(uint16_t *crc, const uint8_t chr) { if (crc == NULL) { return; } - /* Zephyr prototype: uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len); */ - *crc = ZEPHYR_crc16_ccitt(*crc, &chr, 1U); + *crc = crc16_ccitt(*crc, &chr, 1U); } /* * Compatible wrapper that calls into Zephyr's implementation while keeping * CANopenNode's parameter order. */ -uint16_t crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) +uint16_t CO_crc16_ccitt(const uint8_t block[], size_t blockLength, uint16_t crc) { if ((block == NULL) && (blockLength != 0U)) { /* Defensive: if caller passed NULL with non-zero length, just return seed. */ return crc; } - return ZEPHYR_crc16_ccitt(crc, block, blockLength); + return crc16_ccitt(crc, block, blockLength); } diff --git a/zephyr/CO_zephyr_program.c b/zephyr/CO_zephyr_program.c new file mode 100644 index 00000000..80b34224 --- /dev/null +++ b/zephyr/CO_zephyr_program.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2020 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_CANOPEN_LOG_LEVEL +#include +LOG_MODULE_REGISTER(canopen_program); + +/* Object dictionary indexes */ +#define OD_H1F50_PROGRAM_DATA 0x1F50 +#define OD_H1F51_PROGRAM_CTRL 0x1F51 +#define OD_H1F56_PROGRAM_SWID 0x1F56 +#define OD_H1F57_FLASH_STATUS 0x1F57 + +/* Common program control commands and status */ +#define PROGRAM_CTRL_STOP 0x00 +#define PROGRAM_CTRL_START 0x01 +#define PROGRAM_CTRL_RESET 0x02 +#define PROGRAM_CTRL_CLEAR 0x03 +/* Zephyr specific program control and status */ +#define PROGRAM_CTRL_ZEPHYR_CONFIRM 0x80 + +/* Flash status bits */ +#define FLASH_STATUS_IN_PROGRESS BIT(0) +/* Flash common error bits values */ +#define FLASH_STATUS_NO_ERROR (0U << 1U) +#define FLASH_STATUS_NO_VALID_PROGRAM (1U << 1U) +#define FLASH_STATUS_DATA_FORMAT_UNKNOWN (2U << 1U) +#define FLASH_STATUS_DATA_FORMAT_ERROR (3U << 1U) +#define FLASH_STATUS_FLASH_NOT_CLEARED (4U << 1U) +#define FLASH_STATUS_FLASH_WRITE_ERROR (5U << 1U) +#define FLASH_STATUS_GENERAL_ADDR_ERROR (6U << 1U) +#define FLASH_STATUS_FLASH_SECURED (7U << 1U) +#define FLASH_STATUS_UNSPECIFIED_ERROR (63U << 1) + +struct canopen_program_context { + uint32_t flash_status; + size_t total; + CO_NMT_t *nmt; + CO_EM_t *em; + struct flash_img_context flash_img_ctx; + uint8_t program_status; + bool flash_written; +}; + +static struct canopen_program_context ctx; + +static void canopen_program_set_status(uint32_t status) +{ + ctx.program_status = status; +} + +static uint32_t canopen_program_get_status(void) +{ + /* + * Non-confirmed boot image takes precedence over other + * status. This must be checked on every invocation since the + * app may be using other means of confirming the image. + */ + if (!boot_is_img_confirmed()) { + return PROGRAM_CTRL_ZEPHYR_CONFIRM; + } + + return ctx.program_status; +} + +static CO_SDO_abortCode_t canopen_odf_1f50(CO_ODF_arg_t *odf_arg) +{ + int err; + + if (odf_arg->subIndex != 1U) { + return CO_SDO_AB_NONE; + } + + if (odf_arg->reading) { + return CO_SDO_AB_WRITEONLY; + } + + if (canopen_program_get_status() != PROGRAM_CTRL_CLEAR) { + ctx.flash_status = FLASH_STATUS_FLASH_NOT_CLEARED; + return CO_SDO_AB_DATA_DEV_STATE; + } + + if (odf_arg->firstSegment) { + err = flash_img_init(&ctx.flash_img_ctx); + if (err) { + LOG_ERR("failed to initialize flash img (err %d)", err); + CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); + ctx.flash_status = FLASH_STATUS_FLASH_WRITE_ERROR; + return CO_SDO_AB_HW; + } + ctx.flash_status = FLASH_STATUS_IN_PROGRESS; + if (IS_ENABLED(CONFIG_CANOPENNODE_LEDS)) { + canopen_leds_program_download(true); + } + ctx.total = odf_arg->dataLengthTotal; + LOG_DBG("total = %d", ctx.total); + } + + err = flash_img_buffered_write(&ctx.flash_img_ctx, odf_arg->data, odf_arg->dataLength, + odf_arg->lastSegment); + if (err) { + CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); + ctx.flash_status = FLASH_STATUS_FLASH_WRITE_ERROR; + canopen_leds_program_download(false); + return CO_SDO_AB_HW; + } + + if (odf_arg->lastSegment) { + /* ctx.total is zero if not provided by download process */ + if (ctx.total != 0 && ctx.total != flash_img_bytes_written(&ctx.flash_img_ctx)) { + LOG_WRN("premature end of program download"); + ctx.flash_status = FLASH_STATUS_DATA_FORMAT_ERROR; + } else { + LOG_DBG("program downloaded"); + ctx.flash_written = true; + ctx.flash_status = FLASH_STATUS_NO_ERROR; + } + + canopen_program_set_status(PROGRAM_CTRL_STOP); + canopen_leds_program_download(false); + } + + return CO_SDO_AB_NONE; +} + +static inline CO_SDO_abortCode_t canopen_program_cmd_stop(void) +{ + if (canopen_program_get_status() == PROGRAM_CTRL_ZEPHYR_CONFIRM) { + return CO_SDO_AB_DATA_DEV_STATE; + } + + LOG_DBG("program stopped"); + canopen_program_set_status(PROGRAM_CTRL_STOP); + + return CO_SDO_AB_NONE; +} + +static inline CO_SDO_abortCode_t canopen_program_cmd_start(void) +{ + int err; + + if (canopen_program_get_status() == PROGRAM_CTRL_ZEPHYR_CONFIRM) { + return CO_SDO_AB_DATA_DEV_STATE; + } + + if (ctx.flash_written) { + LOG_DBG("requesting upgrade and reset"); + + err = boot_request_upgrade(BOOT_UPGRADE_TEST); + if (err) { + LOG_ERR("failed to request upgrade (err %d)", err); + CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); + return CO_SDO_AB_HW; + } + + ctx.nmt->resetCommand = CO_RESET_APP; + } else { + LOG_DBG("program started"); + canopen_program_set_status(PROGRAM_CTRL_START); + } + + return CO_SDO_AB_NONE; +} + +static inline CO_SDO_abortCode_t canopen_program_cmd_clear(void) +{ + int err; + + if (canopen_program_get_status() != PROGRAM_CTRL_STOP) { + return CO_SDO_AB_DATA_DEV_STATE; + } + + if (!IS_ENABLED(CONFIG_IMG_ERASE_PROGRESSIVELY)) { + LOG_DBG("erasing flash area"); + + err = boot_erase_img_bank(FIXED_PARTITION_ID(slot1_partition)); + if (err) { + LOG_ERR("failed to erase image bank (err %d)", err); + CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); + return CO_SDO_AB_HW; + } + } + + LOG_DBG("program cleared"); + canopen_program_set_status(PROGRAM_CTRL_CLEAR); + ctx.flash_status = FLASH_STATUS_NO_ERROR; + ctx.flash_written = false; + + return CO_SDO_AB_NONE; +} + +static inline CO_SDO_abortCode_t canopen_program_cmd_confirm(void) +{ + int err; + + if (canopen_program_get_status() == PROGRAM_CTRL_ZEPHYR_CONFIRM) { + err = boot_write_img_confirmed(); + if (err) { + LOG_ERR("failed to confirm image (err %d)", err); + CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); + return CO_SDO_AB_HW; + } + + LOG_DBG("program confirmed"); + canopen_program_set_status(PROGRAM_CTRL_START); + } + + return CO_SDO_AB_NONE; +} + +static CO_SDO_abortCode_t canopen_odf_1f51(CO_ODF_arg_t *odf_arg) +{ + CO_SDO_abortCode_t ab; + uint8_t cmd; + + if (odf_arg->subIndex != 1U) { + return CO_SDO_AB_NONE; + } + + if (odf_arg->reading) { + odf_arg->data[0] = canopen_program_get_status(); + return CO_SDO_AB_NONE; + } + + if (CO_NMT_getInternalState(ctx.nmt) != CO_NMT_PRE_OPERATIONAL) { + LOG_DBG("not in pre-operational state"); + return CO_SDO_AB_DATA_DEV_STATE; + } + + /* Preserve old value */ + cmd = odf_arg->data[0]; + memcpy(odf_arg->data, odf_arg->ODdataStorage, sizeof(uint8_t)); + + LOG_DBG("program status = %d, cmd = %d", canopen_program_get_status(), cmd); + + switch (cmd) { + case PROGRAM_CTRL_STOP: + ab = canopen_program_cmd_stop(); + break; + case PROGRAM_CTRL_START: + ab = canopen_program_cmd_start(); + break; + case PROGRAM_CTRL_CLEAR: + ab = canopen_program_cmd_clear(); + break; + case PROGRAM_CTRL_ZEPHYR_CONFIRM: + ab = canopen_program_cmd_confirm(); + break; + case PROGRAM_CTRL_RESET: + __fallthrough; + default: + LOG_DBG("unsupported command '%d'", cmd); + ab = CO_SDO_AB_INVALID_VALUE; + } + + return ab; +} + +#ifdef CONFIG_BOOTLOADER_MCUBOOT +/** @brief Calculate crc for region in flash + * + * @param flash_area Flash area to read from, must be open + * @offset Offset to read from + * @size Number of bytes to include in calculation + * @pcrc Pointer to uint32_t where crc will be written if return value is 0 + * + * @return 0 if successful, negative errno on failure + */ +static int flash_crc(const struct flash_area *flash_area, off_t offset, size_t size, uint32_t *pcrc) +{ + uint32_t crc = 0; + uint8_t buffer[32]; + + while (size > 0) { + size_t len = MIN(size, sizeof(buffer)); + + int err = flash_area_read(flash_area, offset, buffer, len); + + if (err) { + return err; + } + + crc = crc32_ieee_update(crc, buffer, len); + + offset += len; + size -= len; + } + + *pcrc = crc; + + return 0; +} + +static CO_SDO_abortCode_t canopen_odf_1f56(CO_ODF_arg_t *odf_arg) +{ + const struct flash_area *flash_area; + struct mcuboot_img_header header; + off_t offset = 0; + uint32_t crc = 0; + uint8_t fa_id; + uint32_t len; + int err; + + if (odf_arg->subIndex != 1U) { + return CO_SDO_AB_NONE; + } + + if (!odf_arg->reading) { + /* Preserve old value */ + memcpy(odf_arg->data, odf_arg->ODdataStorage, sizeof(uint32_t)); + return CO_SDO_AB_READONLY; + } + + /* Reading from flash and calculating crc can take 100ms or more, and + * this function is called with the can od lock taken. + * + * Release the lock before performing time consuming work, and reacquire + * before return. + */ + CO_UNLOCK_OD(); + + /* + * Calculate the CRC32 of the image that is running or will be + * started upon receiveing the next 'start' command. + */ + if (ctx.flash_written) { + fa_id = FIXED_PARTITION_ID(slot1_partition); + } else { + fa_id = FIXED_PARTITION_ID(slot0_partition); + } + + err = boot_read_bank_header(fa_id, &header, sizeof(header)); + if (err) { + LOG_WRN("failed to read bank header (err %d)", err); + CO_setUint32(odf_arg->data, 0U); + + CO_LOCK_OD(); + return CO_SDO_AB_NONE; + } + + if (header.mcuboot_version != 1) { + LOG_WRN("unsupported mcuboot header version %d", header.mcuboot_version); + CO_setUint32(odf_arg->data, 0U); + + CO_LOCK_OD(); + return CO_SDO_AB_NONE; + } + len = header.h.v1.image_size; + + err = flash_area_open(fa_id, &flash_area); + if (err) { + LOG_ERR("failed to open flash area (err %d)", err); + CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); + + CO_LOCK_OD(); + return CO_SDO_AB_HW; + } + + err = flash_crc(flash_area, offset, len, &crc); + + flash_area_close(flash_area); + + if (err) { + LOG_ERR("failed to read flash (err %d)", err); + CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); + + CO_LOCK_OD(); + return CO_SDO_AB_HW; + } + + CO_setUint32(odf_arg->data, crc); + + CO_LOCK_OD(); + return CO_SDO_AB_NONE; +} +#endif /* CONFIG_BOOTLOADER_MCUBOOT */ + +static CO_SDO_abortCode_t canopen_odf_1f57(CO_ODF_arg_t *odf_arg) +{ + if (odf_arg->subIndex != 1U) { + return CO_SDO_AB_NONE; + } + + if (!odf_arg->reading) { + /* Preserve old value */ + memcpy(odf_arg->data, odf_arg->ODdataStorage, sizeof(uint32_t)); + return CO_SDO_AB_READONLY; + } + + CO_setUint32(odf_arg->data, ctx.flash_status); + + return CO_SDO_AB_NONE; +} + +void canopen_program_download_attach(CO_NMT_t *nmt, CO_SDO_t *sdo, CO_EM_t *em) +{ + canopen_program_set_status(PROGRAM_CTRL_START); + ctx.flash_status = FLASH_STATUS_NO_ERROR; + ctx.flash_written = false; + ctx.nmt = nmt; + ctx.em = em; + + CO_OD_configure(sdo, OD_H1F50_PROGRAM_DATA, canopen_odf_1f50, NULL, 0U, 0U); + + CO_OD_configure(sdo, OD_H1F51_PROGRAM_CTRL, canopen_odf_1f51, NULL, 0U, 0U); + + if (IS_ENABLED(CONFIG_BOOTLOADER_MCUBOOT)) { + CO_OD_configure(sdo, OD_H1F56_PROGRAM_SWID, canopen_odf_1f56, NULL, 0U, 0U); + } + + CO_OD_configure(sdo, OD_H1F57_FLASH_STATUS, canopen_odf_1f57, NULL, 0U, 0U); +} diff --git a/zephyr/Kconfig b/zephyr/Kconfig index f1c9a850..16abb1a5 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -476,7 +476,7 @@ choice CANOPENNODE_STORAGE_BACKEND_CHOICE config CANOPENNODE_STORAGE_BACKEND_SETTINGS bool "Zephyr Settings subsystem" select SETTINGS - select CANOPENNODE_CRC16_EXTERNAL + select CANOPENNODE_CRC16_ENABLE help Use Zephyr's Settings subsystem to persist OD entries. @@ -494,6 +494,30 @@ endchoice endmenu +menu "Program Download - Specified in standard CiA 302-3" + +config CANOPENNODE_PROG_DOWNLOAD + bool "Enable Program Download object (CiA 302-3)" + select CANOPENNODE_CRC16_ENABLE + default n + help + Enables CO_Prog_Download: OD entries 0x1F21, 0x1F23, 0x1F24, 0x1F50, + 0x1F51, 0x1F56, 0x1F57. Streams data via registered backend and can + optionally bind to CO_storage for persistence. + +config CANOPENNODE_PROG_DOWNLOAD_EDS_MAX_SIZE + int "Maximum EDS file size (bytes)" + depends on CANOPENNODE_PROG_DOWNLOAD + default 2048 + range 256 1048576 + help + Upper limit for OD 0x1F23 (“Store EDS NMT slave”) data length. + If the received EDS exceeds this size, the transfer should be + rejected/aborted. Keep this reasonably small to avoid large + RAM allocations during transfer on constrained targets. + +endmenu + menu "CANopen LED Indicators - Specified in standard CiA 303-3" config CANOPENNODE_LEDS_ENABLE diff --git a/zephyr/include/CO_zephyr_config.h b/zephyr/include/CO_zephyr_config.h index 13f3c114..21331933 100644 --- a/zephyr/include/CO_zephyr_config.h +++ b/zephyr/include/CO_zephyr_config.h @@ -261,6 +261,18 @@ extern "C" { #define CO_STORAGE_BACKEND_NONE IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_BACKEND_NONE) /** @} */ +/** @name Program Download (CiA 302-3) + * @brief Enable LED state machine and optional callback. + * @{ + */ +#define CO_CONFIG_PROG_DOWNLOAD \ + (ZBIT(CO_CONFIG_PROG_DOWNLOAD_ENABLE, CONFIG_CANOPENNODE_PROG_DOWNLOAD)) + +/** @brief Maximum EDS file size in bytes. */ +#define CO_CONFIG_PROG_DOWNLOAD_EDS_MAX_SIZE CONFIG_CANOPENNODE_PROG_DOWNLOAD_EDS_MAX_SIZE + +/** @} */ + /** @name LEDs (CiA 303-3) * @brief Enable LED state machine and optional callback. * @{ diff --git a/zephyr/include/CO_zephyr_program.h b/zephyr/include/CO_zephyr_program.h new file mode 100644 index 00000000..e69de29b From 1d113cb34cd4bf6888f022c1f9a6725e7ef71071 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Fri, 15 Aug 2025 18:28:51 -0400 Subject: [PATCH 513/520] Delete unneeded files --- zephyr/CO_zephyr_program.c | 423 ----------------------------- zephyr/include/CO_zephyr_program.h | 0 2 files changed, 423 deletions(-) delete mode 100644 zephyr/CO_zephyr_program.c delete mode 100644 zephyr/include/CO_zephyr_program.h diff --git a/zephyr/CO_zephyr_program.c b/zephyr/CO_zephyr_program.c deleted file mode 100644 index 80b34224..00000000 --- a/zephyr/CO_zephyr_program.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2020 Vestas Wind Systems A/S - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include -#include -#include -#include - -#define LOG_LEVEL CONFIG_CANOPEN_LOG_LEVEL -#include -LOG_MODULE_REGISTER(canopen_program); - -/* Object dictionary indexes */ -#define OD_H1F50_PROGRAM_DATA 0x1F50 -#define OD_H1F51_PROGRAM_CTRL 0x1F51 -#define OD_H1F56_PROGRAM_SWID 0x1F56 -#define OD_H1F57_FLASH_STATUS 0x1F57 - -/* Common program control commands and status */ -#define PROGRAM_CTRL_STOP 0x00 -#define PROGRAM_CTRL_START 0x01 -#define PROGRAM_CTRL_RESET 0x02 -#define PROGRAM_CTRL_CLEAR 0x03 -/* Zephyr specific program control and status */ -#define PROGRAM_CTRL_ZEPHYR_CONFIRM 0x80 - -/* Flash status bits */ -#define FLASH_STATUS_IN_PROGRESS BIT(0) -/* Flash common error bits values */ -#define FLASH_STATUS_NO_ERROR (0U << 1U) -#define FLASH_STATUS_NO_VALID_PROGRAM (1U << 1U) -#define FLASH_STATUS_DATA_FORMAT_UNKNOWN (2U << 1U) -#define FLASH_STATUS_DATA_FORMAT_ERROR (3U << 1U) -#define FLASH_STATUS_FLASH_NOT_CLEARED (4U << 1U) -#define FLASH_STATUS_FLASH_WRITE_ERROR (5U << 1U) -#define FLASH_STATUS_GENERAL_ADDR_ERROR (6U << 1U) -#define FLASH_STATUS_FLASH_SECURED (7U << 1U) -#define FLASH_STATUS_UNSPECIFIED_ERROR (63U << 1) - -struct canopen_program_context { - uint32_t flash_status; - size_t total; - CO_NMT_t *nmt; - CO_EM_t *em; - struct flash_img_context flash_img_ctx; - uint8_t program_status; - bool flash_written; -}; - -static struct canopen_program_context ctx; - -static void canopen_program_set_status(uint32_t status) -{ - ctx.program_status = status; -} - -static uint32_t canopen_program_get_status(void) -{ - /* - * Non-confirmed boot image takes precedence over other - * status. This must be checked on every invocation since the - * app may be using other means of confirming the image. - */ - if (!boot_is_img_confirmed()) { - return PROGRAM_CTRL_ZEPHYR_CONFIRM; - } - - return ctx.program_status; -} - -static CO_SDO_abortCode_t canopen_odf_1f50(CO_ODF_arg_t *odf_arg) -{ - int err; - - if (odf_arg->subIndex != 1U) { - return CO_SDO_AB_NONE; - } - - if (odf_arg->reading) { - return CO_SDO_AB_WRITEONLY; - } - - if (canopen_program_get_status() != PROGRAM_CTRL_CLEAR) { - ctx.flash_status = FLASH_STATUS_FLASH_NOT_CLEARED; - return CO_SDO_AB_DATA_DEV_STATE; - } - - if (odf_arg->firstSegment) { - err = flash_img_init(&ctx.flash_img_ctx); - if (err) { - LOG_ERR("failed to initialize flash img (err %d)", err); - CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); - ctx.flash_status = FLASH_STATUS_FLASH_WRITE_ERROR; - return CO_SDO_AB_HW; - } - ctx.flash_status = FLASH_STATUS_IN_PROGRESS; - if (IS_ENABLED(CONFIG_CANOPENNODE_LEDS)) { - canopen_leds_program_download(true); - } - ctx.total = odf_arg->dataLengthTotal; - LOG_DBG("total = %d", ctx.total); - } - - err = flash_img_buffered_write(&ctx.flash_img_ctx, odf_arg->data, odf_arg->dataLength, - odf_arg->lastSegment); - if (err) { - CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); - ctx.flash_status = FLASH_STATUS_FLASH_WRITE_ERROR; - canopen_leds_program_download(false); - return CO_SDO_AB_HW; - } - - if (odf_arg->lastSegment) { - /* ctx.total is zero if not provided by download process */ - if (ctx.total != 0 && ctx.total != flash_img_bytes_written(&ctx.flash_img_ctx)) { - LOG_WRN("premature end of program download"); - ctx.flash_status = FLASH_STATUS_DATA_FORMAT_ERROR; - } else { - LOG_DBG("program downloaded"); - ctx.flash_written = true; - ctx.flash_status = FLASH_STATUS_NO_ERROR; - } - - canopen_program_set_status(PROGRAM_CTRL_STOP); - canopen_leds_program_download(false); - } - - return CO_SDO_AB_NONE; -} - -static inline CO_SDO_abortCode_t canopen_program_cmd_stop(void) -{ - if (canopen_program_get_status() == PROGRAM_CTRL_ZEPHYR_CONFIRM) { - return CO_SDO_AB_DATA_DEV_STATE; - } - - LOG_DBG("program stopped"); - canopen_program_set_status(PROGRAM_CTRL_STOP); - - return CO_SDO_AB_NONE; -} - -static inline CO_SDO_abortCode_t canopen_program_cmd_start(void) -{ - int err; - - if (canopen_program_get_status() == PROGRAM_CTRL_ZEPHYR_CONFIRM) { - return CO_SDO_AB_DATA_DEV_STATE; - } - - if (ctx.flash_written) { - LOG_DBG("requesting upgrade and reset"); - - err = boot_request_upgrade(BOOT_UPGRADE_TEST); - if (err) { - LOG_ERR("failed to request upgrade (err %d)", err); - CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); - return CO_SDO_AB_HW; - } - - ctx.nmt->resetCommand = CO_RESET_APP; - } else { - LOG_DBG("program started"); - canopen_program_set_status(PROGRAM_CTRL_START); - } - - return CO_SDO_AB_NONE; -} - -static inline CO_SDO_abortCode_t canopen_program_cmd_clear(void) -{ - int err; - - if (canopen_program_get_status() != PROGRAM_CTRL_STOP) { - return CO_SDO_AB_DATA_DEV_STATE; - } - - if (!IS_ENABLED(CONFIG_IMG_ERASE_PROGRESSIVELY)) { - LOG_DBG("erasing flash area"); - - err = boot_erase_img_bank(FIXED_PARTITION_ID(slot1_partition)); - if (err) { - LOG_ERR("failed to erase image bank (err %d)", err); - CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); - return CO_SDO_AB_HW; - } - } - - LOG_DBG("program cleared"); - canopen_program_set_status(PROGRAM_CTRL_CLEAR); - ctx.flash_status = FLASH_STATUS_NO_ERROR; - ctx.flash_written = false; - - return CO_SDO_AB_NONE; -} - -static inline CO_SDO_abortCode_t canopen_program_cmd_confirm(void) -{ - int err; - - if (canopen_program_get_status() == PROGRAM_CTRL_ZEPHYR_CONFIRM) { - err = boot_write_img_confirmed(); - if (err) { - LOG_ERR("failed to confirm image (err %d)", err); - CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); - return CO_SDO_AB_HW; - } - - LOG_DBG("program confirmed"); - canopen_program_set_status(PROGRAM_CTRL_START); - } - - return CO_SDO_AB_NONE; -} - -static CO_SDO_abortCode_t canopen_odf_1f51(CO_ODF_arg_t *odf_arg) -{ - CO_SDO_abortCode_t ab; - uint8_t cmd; - - if (odf_arg->subIndex != 1U) { - return CO_SDO_AB_NONE; - } - - if (odf_arg->reading) { - odf_arg->data[0] = canopen_program_get_status(); - return CO_SDO_AB_NONE; - } - - if (CO_NMT_getInternalState(ctx.nmt) != CO_NMT_PRE_OPERATIONAL) { - LOG_DBG("not in pre-operational state"); - return CO_SDO_AB_DATA_DEV_STATE; - } - - /* Preserve old value */ - cmd = odf_arg->data[0]; - memcpy(odf_arg->data, odf_arg->ODdataStorage, sizeof(uint8_t)); - - LOG_DBG("program status = %d, cmd = %d", canopen_program_get_status(), cmd); - - switch (cmd) { - case PROGRAM_CTRL_STOP: - ab = canopen_program_cmd_stop(); - break; - case PROGRAM_CTRL_START: - ab = canopen_program_cmd_start(); - break; - case PROGRAM_CTRL_CLEAR: - ab = canopen_program_cmd_clear(); - break; - case PROGRAM_CTRL_ZEPHYR_CONFIRM: - ab = canopen_program_cmd_confirm(); - break; - case PROGRAM_CTRL_RESET: - __fallthrough; - default: - LOG_DBG("unsupported command '%d'", cmd); - ab = CO_SDO_AB_INVALID_VALUE; - } - - return ab; -} - -#ifdef CONFIG_BOOTLOADER_MCUBOOT -/** @brief Calculate crc for region in flash - * - * @param flash_area Flash area to read from, must be open - * @offset Offset to read from - * @size Number of bytes to include in calculation - * @pcrc Pointer to uint32_t where crc will be written if return value is 0 - * - * @return 0 if successful, negative errno on failure - */ -static int flash_crc(const struct flash_area *flash_area, off_t offset, size_t size, uint32_t *pcrc) -{ - uint32_t crc = 0; - uint8_t buffer[32]; - - while (size > 0) { - size_t len = MIN(size, sizeof(buffer)); - - int err = flash_area_read(flash_area, offset, buffer, len); - - if (err) { - return err; - } - - crc = crc32_ieee_update(crc, buffer, len); - - offset += len; - size -= len; - } - - *pcrc = crc; - - return 0; -} - -static CO_SDO_abortCode_t canopen_odf_1f56(CO_ODF_arg_t *odf_arg) -{ - const struct flash_area *flash_area; - struct mcuboot_img_header header; - off_t offset = 0; - uint32_t crc = 0; - uint8_t fa_id; - uint32_t len; - int err; - - if (odf_arg->subIndex != 1U) { - return CO_SDO_AB_NONE; - } - - if (!odf_arg->reading) { - /* Preserve old value */ - memcpy(odf_arg->data, odf_arg->ODdataStorage, sizeof(uint32_t)); - return CO_SDO_AB_READONLY; - } - - /* Reading from flash and calculating crc can take 100ms or more, and - * this function is called with the can od lock taken. - * - * Release the lock before performing time consuming work, and reacquire - * before return. - */ - CO_UNLOCK_OD(); - - /* - * Calculate the CRC32 of the image that is running or will be - * started upon receiveing the next 'start' command. - */ - if (ctx.flash_written) { - fa_id = FIXED_PARTITION_ID(slot1_partition); - } else { - fa_id = FIXED_PARTITION_ID(slot0_partition); - } - - err = boot_read_bank_header(fa_id, &header, sizeof(header)); - if (err) { - LOG_WRN("failed to read bank header (err %d)", err); - CO_setUint32(odf_arg->data, 0U); - - CO_LOCK_OD(); - return CO_SDO_AB_NONE; - } - - if (header.mcuboot_version != 1) { - LOG_WRN("unsupported mcuboot header version %d", header.mcuboot_version); - CO_setUint32(odf_arg->data, 0U); - - CO_LOCK_OD(); - return CO_SDO_AB_NONE; - } - len = header.h.v1.image_size; - - err = flash_area_open(fa_id, &flash_area); - if (err) { - LOG_ERR("failed to open flash area (err %d)", err); - CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); - - CO_LOCK_OD(); - return CO_SDO_AB_HW; - } - - err = flash_crc(flash_area, offset, len, &crc); - - flash_area_close(flash_area); - - if (err) { - LOG_ERR("failed to read flash (err %d)", err); - CO_errorReport(ctx.em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, err); - - CO_LOCK_OD(); - return CO_SDO_AB_HW; - } - - CO_setUint32(odf_arg->data, crc); - - CO_LOCK_OD(); - return CO_SDO_AB_NONE; -} -#endif /* CONFIG_BOOTLOADER_MCUBOOT */ - -static CO_SDO_abortCode_t canopen_odf_1f57(CO_ODF_arg_t *odf_arg) -{ - if (odf_arg->subIndex != 1U) { - return CO_SDO_AB_NONE; - } - - if (!odf_arg->reading) { - /* Preserve old value */ - memcpy(odf_arg->data, odf_arg->ODdataStorage, sizeof(uint32_t)); - return CO_SDO_AB_READONLY; - } - - CO_setUint32(odf_arg->data, ctx.flash_status); - - return CO_SDO_AB_NONE; -} - -void canopen_program_download_attach(CO_NMT_t *nmt, CO_SDO_t *sdo, CO_EM_t *em) -{ - canopen_program_set_status(PROGRAM_CTRL_START); - ctx.flash_status = FLASH_STATUS_NO_ERROR; - ctx.flash_written = false; - ctx.nmt = nmt; - ctx.em = em; - - CO_OD_configure(sdo, OD_H1F50_PROGRAM_DATA, canopen_odf_1f50, NULL, 0U, 0U); - - CO_OD_configure(sdo, OD_H1F51_PROGRAM_CTRL, canopen_odf_1f51, NULL, 0U, 0U); - - if (IS_ENABLED(CONFIG_BOOTLOADER_MCUBOOT)) { - CO_OD_configure(sdo, OD_H1F56_PROGRAM_SWID, canopen_odf_1f56, NULL, 0U, 0U); - } - - CO_OD_configure(sdo, OD_H1F57_FLASH_STATUS, canopen_odf_1f57, NULL, 0U, 0U); -} diff --git a/zephyr/include/CO_zephyr_program.h b/zephyr/include/CO_zephyr_program.h deleted file mode 100644 index e69de29b..00000000 From fefe10e0a448533e426bb2d1ac795fca1fa4b591 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Mon, 18 Aug 2025 09:10:10 -0400 Subject: [PATCH 514/520] Enables program download feature for Zephyr Adds support for program download functionality in the Zephyr RTOS environment. This includes: - Enabling the program download object with permanent upgrade configuration. - Adding a Zephyr-specific driver for program download, managing flash memory operations. - Providing a stream ops implementation for program download using Zephyr flash areas and MCUBoot upgrade APIs. - Integrating Program Download functionality to CO_zephyr_integration.c --- 301/CO_config.h | 6 +- 302/CO_Prog_Download.c | 5 +- 302/CO_Prog_Download.h | 5 +- zephyr/CMakeLists.txt | 2 +- zephyr/CO_zephyr_driver.c | 36 ++-- zephyr/CO_zephyr_integration.c | 58 ++++-- zephyr/CO_zephyr_leds.c | 4 +- zephyr/CO_zephyr_prog_download.c | 243 +++++++++++++++++++++++ zephyr/CO_zephyr_storage.c | 8 +- zephyr/Kconfig | 11 + zephyr/include/CO_driver_target.h | 26 +-- zephyr/include/CO_zephyr_config.h | 6 +- zephyr/include/CO_zephyr_integration.h | 32 +-- zephyr/include/CO_zephyr_prog_download.h | 127 ++++++++++++ 14 files changed, 487 insertions(+), 82 deletions(-) create mode 100644 zephyr/CO_zephyr_prog_download.c create mode 100644 zephyr/include/CO_zephyr_prog_download.h diff --git a/301/CO_config.h b/301/CO_config.h index 5e0400f4..ef8c21b3 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -530,11 +530,13 @@ extern "C" { * * Possible flags, can be ORed: * - CO_CONFIG_PROG_DOWNLOAD_ENABLE - Enable Program Download object (0x1F50, 0x1F51, 0x1F56, 0x1F57) + * - CO_CONFIG_PROG_DOWNLOAD_PERMANENT - Determines if program commit is permanent upgrade */ #ifdef CO_DOXYGEN -#define CO_CONFIG_PROG_DOWNLOAD (CO_CONFIG_PROG_DOWNLOAD_ENABLE) +#define CO_CONFIG_PROG_DOWNLOAD (CO_CONFIG_PROG_DOWNLOAD_ENABLE | CO_CONFIG_PROG_DOWNLOAD_PERMANENT) #endif -#define CO_CONFIG_PROG_DOWNLOAD_ENABLE 0x01 +#define CO_CONFIG_PROG_DOWNLOAD_ENABLE 0x01 +#define CO_CONFIG_PROG_DOWNLOAD_PERMANENT 0x02 /** * Maximum EDS file size in bytes. diff --git a/302/CO_Prog_Download.c b/302/CO_Prog_Download.c index 053388a6..1bb04ba4 100644 --- a/302/CO_Prog_Download.c +++ b/302/CO_Prog_Download.c @@ -18,7 +18,7 @@ * See the License for the specific language governing permissions and limitations under the License. */ -#include "CO_Prog_Download.h" +#include "302/CO_Prog_Download.h" #if ((CO_CONFIG_PROG_DOWNLOAD) & CO_CONFIG_PROG_DOWNLOAD_ENABLE) != 0 @@ -30,9 +30,6 @@ #endif #endif -#include -#include "301/CO_crc16-ccitt.h" - /* If globals are requested, provide a static buffer for EDS data. */ #ifdef CO_USE_GLOBALS static uint8_t CO_ProgDL_EDS_StaticBuf[CO_PROGDL_EDS_MAX]; diff --git a/302/CO_Prog_Download.h b/302/CO_Prog_Download.h index dfa4d4ae..4fe663b1 100644 --- a/302/CO_Prog_Download.h +++ b/302/CO_Prog_Download.h @@ -22,6 +22,7 @@ #define CO_PROG_DOWNLOAD_H #include "CANopen.h" +#include "301/CO_crc16-ccitt.h" #include "301/CO_driver.h" #include "301/CO_ODinterface.h" @@ -29,13 +30,15 @@ #include "storage/CO_storage.h" #endif +#include + #ifdef __cplusplus extern "C" { #endif /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_PROG_DOWNLOAD -#define CO_CONFIG_PROG_DOWNLOAD (0) +#define CO_CONFIG_PROG_DOWNLOAD (CO_CONFIG_PROG_DOWNLOAD_ENABLE | CO_CONFIG_PROG_DOWNLOAD_PERMANENT) #endif #if (((CO_CONFIG_PROG_DOWNLOAD) & CO_CONFIG_PROG_DOWNLOAD_ENABLE) != 0) || defined CO_DOXYGEN diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index fffbac3a..a5c63a07 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -232,7 +232,7 @@ endif() if(CONFIG_CANOPENNODE_PROG_DOWNLOAD) zephyr_library_sources( "${CANOPENNODE_DIR}/302/CO_Prog_Download.c" - + "${CANOPENNODE_DIR}/zephyr/CO_zephyr_prog_download.c" ) endif() diff --git a/zephyr/CO_zephyr_driver.c b/zephyr/CO_zephyr_driver.c index a57d0872..be5f8b02 100644 --- a/zephyr/CO_zephyr_driver.c +++ b/zephyr/CO_zephyr_driver.c @@ -60,32 +60,32 @@ K_MUTEX_DEFINE(canopen_send_mutex); K_MUTEX_DEFINE(canopen_emcy_mutex); K_MUTEX_DEFINE(canopen_co_mutex); -inline void canopen_send_lock(void) +inline void z_co_send_lock(void) { k_mutex_lock(&canopen_send_mutex, K_FOREVER); } -inline void canopen_send_unlock(void) +inline void z_co_send_unlock(void) { k_mutex_unlock(&canopen_send_mutex); } -inline void canopen_emcy_lock(void) +inline void z_co_emcy_lock(void) { k_mutex_lock(&canopen_emcy_mutex, K_FOREVER); } -inline void canopen_emcy_unlock(void) +inline void z_co_emcy_unlock(void) { k_mutex_unlock(&canopen_emcy_mutex); } -inline void canopen_od_lock(void) +inline void z_co_od_lock(void) { k_mutex_lock(&canopen_co_mutex, K_FOREVER); } -inline void canopen_od_unlock(void) +inline void z_co_od_unlock(void) { k_mutex_unlock(&canopen_co_mutex); } @@ -97,7 +97,7 @@ inline void canopen_od_unlock(void) * - Uses filter_id == -ENOSPC as a sentinel for "no filter installed". * - Safe to call multiple times; non-installed entries are skipped. */ -static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule) +static void z_co_detach_all_rx_filters(CO_CANmodule_t *CANmodule) { uint_fast16_t i; @@ -126,7 +126,7 @@ static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule) * - Called from Zephyr CAN driver context (may be IRQ or thread depending on driver). * - Keep it short; heavy work is done later by the stack. */ -static void canopen_rx_callback(const struct device *dev, struct can_frame *frame, void *user_data) +static void z_co_rx_callback(const struct device *dev, struct can_frame *frame, void *user_data) { CO_CANmodule_t *CANmodule = (CO_CANmodule_t *)user_data; CO_CANrxMsg_t rxMsg; @@ -169,7 +169,7 @@ static void canopen_rx_callback(const struct device *dev, struct can_frame *fram * retry any queued frames. On error: logs a warning and still schedules retry * so buffered frames get another chance. */ -static void canopen_tx_callback(const struct device *dev, int error, void *arg) +static void z_co_tx_callback(const struct device *dev, int error, void *arg) { CO_CANmodule_t *CANmodule = arg; @@ -200,7 +200,7 @@ static void canopen_tx_callback(const struct device *dev, int error, void *arg) * Concurrency: * - Protected by CO_LOCK_CAN_SEND() to synchronize with CO_CANsend(). */ -static void canopen_tx_retry(struct k_work *item) +static void z_co_tx_retry(struct k_work *item) { struct canopen_tx_work_container *container = CONTAINER_OF(item, struct canopen_tx_work_container, work); @@ -223,7 +223,7 @@ static void canopen_tx_retry(struct k_work *item) frame.flags |= ((buffer->ident & 0x800) ? CAN_FRAME_RTR : 0); memcpy(frame.data, buffer->data, buffer->DLC); - err = can_send(dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); + err = can_send(dev, &frame, K_NO_WAIT, z_co_tx_callback, CANmodule); if (err == -EAGAIN) { /* Controller is busy; stop here and try again later. */ LOG_DBG("tx busy, will retry"); @@ -301,7 +301,7 @@ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, void *CANptr, CO_C } } - canopen_detach_all_rx_filters(CANmodule); + z_co_detach_all_rx_filters(CANmodule); canopen_tx_queue.CANmodule = CANmodule; /* Configure object variables */ @@ -354,7 +354,7 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); - canopen_detach_all_rx_filters(CANmodule); + z_co_detach_all_rx_filters(CANmodule); int err = can_stop(dev); if (err != 0 && err != -EALREADY) { @@ -405,7 +405,7 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, u can_remove_rx_filter(dev, buffer->filter_id); } buffer->filter_id = - can_add_rx_filter(dev, canopen_rx_callback, CANmodule, &filter); + can_add_rx_filter(dev, z_co_rx_callback, CANmodule, &filter); if (buffer->filter_id == -ENOSPC) { LOG_ERR("rx filter add failed: no slots"); ret = CO_ERROR_OUT_OF_MEMORY; @@ -461,7 +461,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) CO_LOCK_CAN_SEND(CANmodule); - err = can_send(dev, &frame, K_NO_WAIT, canopen_tx_callback, CANmodule); + err = can_send(dev, &frame, K_NO_WAIT, z_co_tx_callback, CANmodule); if (err == -EAGAIN) { LOG_ERR("tx overflow"); err = CO_ERROR_TX_OVERFLOW; @@ -567,7 +567,7 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) * names its thread (handy for debugging), and initializes the work item. * Runs at SYS_INIT(APPLICATION) stage. */ -static int canopen_init(void) +static int z_co_init(void) { k_work_queue_start(&canopen_tx_workq, canopen_tx_workq_stack, K_KERNEL_STACK_SIZEOF(canopen_tx_workq_stack), @@ -575,9 +575,9 @@ static int canopen_init(void) k_thread_name_set(&canopen_tx_workq.thread, "canopen_tx_workq"); - k_work_init(&canopen_tx_queue.work, canopen_tx_retry); + k_work_init(&canopen_tx_queue.work, z_co_tx_retry); return 0; } -SYS_INIT(canopen_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(z_co_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index da2a415d..70ce3d0f 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -40,6 +40,10 @@ #include "CO_zephyr_storage.h" #endif +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) +#include "CO_zephyr_prog_download.h" +#endif + LOG_MODULE_REGISTER(canopennode_zephyr, CONFIG_CANOPEN_LOG_LEVEL); #define CAN_NODE DT_CHOSEN(zephyr_canbus) @@ -57,6 +61,11 @@ static CO_t *CO = NULL; static CO_storage_t *CO_storage = NULL; static atomic_t g_running; +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) +static CO_ProgDL_t pdl; +static CO_ProgDL_Zephyr_t zb_ctx; +#endif + #if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) static co_node_id_cb_t g_node_id_cb; static void *g_node_id_cb_ud; @@ -82,7 +91,7 @@ K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ * - The returned value is intended to be in [0..127]; ensure your Kconfig * default is valid for your system. */ -static uint8_t resolve_node_id(uint8_t requested) +static uint8_t z_resolve_node_id(uint8_t requested) { if (requested <= 127) { return requested; @@ -102,7 +111,7 @@ static uint8_t resolve_node_id(uint8_t requested) * Pre-callback used by SYNC/RPDO to poke the RT thread. * Gives the semaphore only when the stack is marked running. */ -static void rt_signal_cb(void *object) +static void z_rt_signal_cb(void *object) { ARG_UNUSED(object); if (atomic_get(&g_running)) { @@ -114,7 +123,7 @@ static void rt_signal_cb(void *object) * Register a common pre-callback for SYNC and all RPDOs. * This lets incoming traffic promptly wake the RT thread. */ -static void enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) +static void z_enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) { CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); for (uint16_t i = 0; i < OD_CNT_RPDO; i++) { @@ -140,7 +149,7 @@ static void enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) * - OD access is protected with CO_LOCK_OD()/CO_UNLOCK_OD(). * - Thread runs continuously but only acts when the stack is running. */ -static void canopen_rt_thread(void *p1, void *p2, void *p3) +static void z_canopen_rt_thread(void *p1, void *p2, void *p3) { ARG_UNUSED(p1); ARG_UNUSED(p2); @@ -211,15 +220,15 @@ static void canopen_rt_thread(void *p1, void *p2, void *p3) } /* Spawn the real-time processing thread at boot; priority/stack are Kconfig-driven. */ -K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, canopen_rt_thread, NULL, NULL, - NULL, CONFIG_CANOPENNODE_RT_THREAD_PRIORITY, 0, 0); +K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, z_canopen_rt_thread, NULL, + NULL, NULL, CONFIG_CANOPENNODE_RT_THREAD_PRIORITY, 0, 0); #endif /* IS_ENABLED(CANOPENNODE_RT_THREAD) */ /* ---------- Public API ---------- */ #if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) -void co_canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data) +void canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data) { g_node_id_cb = cb; g_node_id_cb_ud = user_data; @@ -240,12 +249,12 @@ void co_canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data) uint16_t bitrate = g_last_bitrate_kbps ? g_last_bitrate_kbps : CAN_BITRATE_KBPS; /* Restart with new Node-ID. This will briefly interrupt communications. */ - co_canopen_stop(); - (void)co_canopen_start(dev, new_id, bitrate); + canopen_stop(); + (void)canopen_start(dev, new_id, bitrate); } #endif -int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) +int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) { if (atomic_get(&g_running)) { return -EALREADY; @@ -257,7 +266,7 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit return -ENODEV; } - node_id = resolve_node_id(node_id); + node_id = z_resolve_node_id(node_id); if (node_id > 127) { return -EINVAL; } @@ -348,6 +357,18 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit goto error; } +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) + { + /* If your binder takes a partition ID and optional CO_storage handle: */ + err = CO_Prog_Download_zephyr_bind_default(&pdl, &zb_ctx); + if (ret != CO_ERROR_NO) { + LOG_ERR("Program Download bind failed: %d", ret); + ret = -EINVAL; + goto error; + } + } +#endif + if (!CO->nodeIdUnconfigured) { #if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) if (storageErr != 0) { @@ -359,7 +380,7 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit LOG_INF("Node-ID not configured (LSS active)"); } - enable_pre_signals(CO, rt_signal_cb, NULL); + z_enable_pre_signals(CO, z_rt_signal_cb, NULL); atomic_set(&g_running, 1); CO_CANsetNormalMode(CO->CANmodule); @@ -374,7 +395,7 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit return ret; } -void co_canopen_stop(void) +void canopen_stop(void) { if (!atomic_get(&g_running)) { return; @@ -390,7 +411,7 @@ void co_canopen_stop(void) } } -bool co_canopen_is_running(void) +bool canopen_is_running(void) { return atomic_get(&g_running); } @@ -399,15 +420,16 @@ bool co_canopen_is_running(void) * System init hook. * Optionally auto-starts CANopen at POST_KERNEL if configured via Kconfig. */ -static int co_canopen_init_sys(void) +static int z_co_init_sys(void) { #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) #if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) - (void)co_canopen_start(NULL, CANOPENNODE_NODE_ID_CALLBACK_REQUEST, CAN_BITRATE_KBPS); + (void)canopen_start(NULL, CANOPENNODE_NODE_ID_CALLBACK_REQUEST, CAN_BITRATE_KBPS); #else - (void)co_canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, CAN_BITRATE_KBPS); + (void)canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, CAN_BITRATE_KBPS); #endif #endif + return 0; } -SYS_INIT(co_canopen_init_sys, POST_KERNEL, CONFIG_CANOPENNODE_INIT_PRIORITY); +SYS_INIT(z_co_init_sys, POST_KERNEL, CONFIG_CANOPENNODE_INIT_PRIORITY); diff --git a/zephyr/CO_zephyr_leds.c b/zephyr/CO_zephyr_leds.c index 1f883a8b..b538c0b8 100644 --- a/zephyr/CO_zephyr_leds.c +++ b/zephyr/CO_zephyr_leds.c @@ -48,7 +48,7 @@ static bool hw_ready; * CANopen LED callback. * Maps CO_LEDs_t state bits to the two GPIOs. Safe to call anytime after init. */ -static void co_zephyr_leds_cb(CO_LEDs_t *leds, void *user_arg) +static void z_leds_cb(CO_LEDs_t *leds, void *user_arg) { ARG_UNUSED(user_arg); if (!hw_ready || leds == NULL) { @@ -87,7 +87,7 @@ void co_zephyr_leds_connect_callback(CO_LEDs_t *leds) if (!leds) { return; } - CO_LEDs_registerCallback(leds, co_zephyr_leds_cb, NULL); + CO_LEDs_registerCallback(leds, z_leds_cb, NULL); co_zephyr_leds_sync_once(leds); } diff --git a/zephyr/CO_zephyr_prog_download.c b/zephyr/CO_zephyr_prog_download.c new file mode 100644 index 00000000..a49b9570 --- /dev/null +++ b/zephyr/CO_zephyr_prog_download.c @@ -0,0 +1,243 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr backend (ops) for CANopen Program Download (CiA 302-3 oriented). + * + * See header for details. This file implements CO_ProgDL_StreamOps_t using + * Zephyr flash areas and MCUBoot upgrade APIs. + */ + +#include "CO_zephyr_prog_download.h" +#include + +LOG_MODULE_REGISTER(canopennode_prog_download, CONFIG_CANOPEN_LOG_LEVEL); + +/* -------- Internal helpers -------- */ + +static bool_t z_pdl_begin(uint32_t size_hint); +static bool_t z_pdl_write(const uint8_t *data, uint32_t len); +static bool_t z_pdl_commit(void); +static void z_pdl_abort(void); +static void z_pdl_jump_to_boot(void); + +/* We record a back-pointer from ops to our context. */ +typedef struct { + CO_ProgDL_Zephyr_t *zb; +} z_ctx_holder_t; + +static z_ctx_holder_t g_ctx = {0}; /* One instance per app; adjust if you need multiple. */ + +static inline CO_ProgDL_Zephyr_t *ctx(void) +{ + return g_ctx.zb; +} + +/* -------- Ops implementation -------- */ + +static bool_t z_open_and_erase(CO_ProgDL_Zephyr_t *zb, uint32_t size_hint) +{ + int rc; + + /* Open the flash area for the secondary slot. */ + rc = flash_area_open(zb->area_id, &zb->fa); + if (rc != 0 || zb->fa == NULL) { + LOG_ERR("flash_area_open(%u) failed: %d", zb->area_id, rc); + zb->fa = NULL; + return false; + } + + /* Bounds check: ensure image fits in area. */ + if (size_hint != 0U && size_hint > zb->fa->fa_size) { + LOG_ERR("size_hint (%u) exceeds area size (%u)", size_hint, zb->fa->fa_size); + flash_area_close(zb->fa); + zb->fa = NULL; + return false; + } + + /* Full erase of the target area. */ + rc = flash_area_erase(zb->fa, 0, zb->fa->fa_size); + if (rc != 0) { + LOG_ERR("flash_area_erase failed: %d", rc); + flash_area_close(zb->fa); + zb->fa = NULL; + return false; + } + + zb->off = 0U; + zb->expected_size = size_hint; + return true; +} + +static bool_t z_pdl_begin(uint32_t size_hint) +{ + CO_ProgDL_Zephyr_t *zb = ctx(); + if (zb == NULL) { + return false; + } + + k_mutex_lock(&zb->lock, K_FOREVER); + + if (zb->active) { + /* If a previous session is active, abort/close it. */ + if (zb->fa) { + flash_area_close(zb->fa); + zb->fa = NULL; + } + zb->active = false; + zb->off = 0; + } + + bool ok = z_open_and_erase(zb, size_hint); + if (ok) { + zb->active = true; + LOG_INF("BEGIN OK: area=%u size_hint=%u", zb->area_id, size_hint); + } + + k_mutex_unlock(&zb->lock); + return ok; +} + +static bool_t z_pdl_write(const uint8_t *data, uint32_t len) +{ + CO_ProgDL_Zephyr_t *zb = ctx(); + if (zb == NULL || !zb->active || zb->fa == NULL || data == NULL || len == 0U) { + return false; + } + + k_mutex_lock(&zb->lock, K_FOREVER); + + /* Honor device alignment if needed. */ + uint32_t align = flash_area_align(zb->fa); + if (align > 1U) { + /* We accept any length; Zephyr will handle internal alignment as long as + * controller supports it. If your SoC requires aligned writes, you can + * add a small staging buffer here. For most MCUBoot targets, unaligned + * chunks are OK. + */ + (void)align; + } + + /* Check bounds if expected_size is known. */ + if (zb->expected_size && (zb->off + len > zb->expected_size)) { + LOG_ERR("Write would exceed expected_size: off=%u len=%u exp=%u", zb->off, len, + zb->expected_size); + k_mutex_unlock(&zb->lock); + return false; + } + + int rc = flash_area_write(zb->fa, zb->off, data, len); + if (rc != 0) { + LOG_ERR("flash_area_write off=%u len=%u failed: %d", zb->off, len, rc); + k_mutex_unlock(&zb->lock); + return false; + } + + zb->off += len; + + k_mutex_unlock(&zb->lock); + return true; +} + +static bool_t z_pdl_commit(void) +{ + CO_ProgDL_Zephyr_t *zb = ctx(); + if (zb == NULL || !zb->active) { + return false; + } + + k_mutex_lock(&zb->lock, K_FOREVER); + + /* Optional: sanity check if expected_size was given. */ + if (zb->expected_size && zb->off != zb->expected_size) { + LOG_WRN("COMMIT with size mismatch: written=%u expected=%u", zb->off, + zb->expected_size); + /* Not fatal — MCUBoot will validate the image anyway. */ + } + + /* Close area before requesting upgrade. */ + if (zb->fa) { + flash_area_close(zb->fa); + zb->fa = NULL; + } + + /* Ask MCUBoot to upgrade on next boot. */ + int rc = boot_request_upgrade(zb->permanent_upgrade); + if (rc != 0) { + LOG_ERR("boot_request_upgrade(permanent=%d) failed: %d", + zb->permanent_upgrade ? 1 : 0, rc); + zb->active = false; + k_mutex_unlock(&zb->lock); + return false; + } + + /* Mark session closed. */ + zb->active = false; + LOG_INF("COMMIT OK: bytes=%u, upgrade=%s", zb->off, + zb->permanent_upgrade ? "permanent" : "test"); + + k_mutex_unlock(&zb->lock); + return true; +} + +static void z_pdl_abort(void) +{ + CO_ProgDL_Zephyr_t *zb = ctx(); + if (zb == NULL) { + return; + } + + k_mutex_lock(&zb->lock, K_FOREVER); + + if (zb->fa) { + /* Just close; we keep the area contents (already erased) as-is. */ + flash_area_close(zb->fa); + zb->fa = NULL; + } + + zb->active = false; + zb->off = 0; + zb->expected_size = 0; + + LOG_INF("ABORT done"); + + k_mutex_unlock(&zb->lock); +} + +static void z_pdl_jump_to_boot(void) +{ + sys_reboot(SYS_REBOOT_WARM); +} + +/* -------- Public binding -------- */ + +int CO_zephyr_prog_download_bind(CO_ProgDL_t *pdl, CO_ProgDL_Zephyr_t *zb, uint8_t area_id, + bool permanent_upgrade) +{ + if (pdl == NULL || zb == NULL) { + return -EINVAL; + } + + (void)memset(zb, 0, sizeof(*zb)); + zb->area_id = area_id; + zb->permanent_upgrade = permanent_upgrade; + k_mutex_init(&zb->lock); + + /* Publish ops into PDL. */ + CO_ProgDL_StreamOps_t ops = { + .begin = z_pdl_begin, + .write = z_pdl_write, + .commit = z_pdl_commit, + .abort = z_pdl_abort, + .jumpToBootloader = z_pdl_jump_to_boot, + }; + + g_ctx.zb = zb; + + if (CO_Prog_Download_registerStreamOps(pdl, &ops) != 0) { + g_ctx.zb = NULL; + return -EIO; + } + + LOG_INF("CO_Prog_Download Zephyr backend bound: area=%u, %s", zb->area_id, + zb->permanent_upgrade ? "permanent" : "test"); + return 0; +} diff --git a/zephyr/CO_zephyr_storage.c b/zephyr/CO_zephyr_storage.c index ca40d3b4..28f17b0b 100644 --- a/zephyr/CO_zephyr_storage.c +++ b/zephyr/CO_zephyr_storage.c @@ -43,7 +43,7 @@ LOG_MODULE_REGISTER(canopennode_storage, CONFIG_CANOPEN_LOG_LEVEL); * Persists one configured storage entry using the selected backend. * Returns ODR_OK on success, ODR_HW on backend failure. */ -static ODR_t store_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) +static ODR_t z_store(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { #if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) char key[64]; @@ -65,7 +65,7 @@ static ODR_t store_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) * Clears any persisted value for the entry (or no-ops for RAM), * so defaults take effect after the next load. */ -static ODR_t restore_zephyr(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) +static ODR_t z_restore(CO_storage_entry_t *entry, CO_CANmodule_t *CANmodule) { #if defined(CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS) char key[64]; @@ -96,8 +96,8 @@ CO_ReturnError_t co_zephyr_storage_init(CO_storage_t *storage, CO_CANmodule_t *C } CO_ReturnError_t ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, - OD_1011_RestoreDefaultParam, store_zephyr, - restore_zephyr, entries, entriesCount); + OD_1011_RestoreDefaultParam, z_store, z_restore, + entries, entriesCount); if (ret != CO_ERROR_NO) { return ret; } diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 16abb1a5..605210bd 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -499,6 +499,8 @@ menu "Program Download - Specified in standard CiA 302-3" config CANOPENNODE_PROG_DOWNLOAD bool "Enable Program Download object (CiA 302-3)" select CANOPENNODE_CRC16_ENABLE + select FLASH_MAP + depends on FLASH default n help Enables CO_Prog_Download: OD entries 0x1F21, 0x1F23, 0x1F24, 0x1F50, @@ -516,6 +518,15 @@ config CANOPENNODE_PROG_DOWNLOAD_EDS_MAX_SIZE rejected/aborted. Keep this reasonably small to avoid large RAM allocations during transfer on constrained targets. +config CANOPENNODE_PROG_DOWNLOAD_PERMANENT + bool "Program commit is permanent upgrade" + default y + help + If enabled, COMMIT (0x1F51 command) will request a permanent + upgrade of the programmed image. + If disabled, COMMIT will request a test upgrade instead, + requiring a later confirmation to keep the image. + endmenu menu "CANopen LED Indicators - Specified in standard CiA 303-3" diff --git a/zephyr/include/CO_driver_target.h b/zephyr/include/CO_driver_target.h index 7b5ebb4f..5df40b0c 100644 --- a/zephyr/include/CO_driver_target.h +++ b/zephyr/include/CO_driver_target.h @@ -271,32 +271,32 @@ typedef struct { * Blocks concurrent access to the TX path while the stack composes and enqueues * a frame. */ -void canopen_send_lock(void); -/** @brief Unlock critical section started by @ref canopen_send_lock. */ -void canopen_send_unlock(void); +void z_co_send_lock(void); +/** @brief Unlock critical section started by @ref z_co_send_lock. */ +void z_co_send_unlock(void); /** @brief Enter critical section for EMCY reporting/reset. */ -void canopen_emcy_lock(void); +void z_co_emcy_lock(void); /** @brief Exit critical section for EMCY reporting/reset. */ -void canopen_emcy_unlock(void); +void z_co_emcy_unlock(void); /** @brief Enter critical section for Object Dictionary access. */ -void canopen_od_lock(void); +void z_co_od_lock(void); /** @brief Exit critical section for Object Dictionary access. */ -void canopen_od_unlock(void); +void z_co_od_unlock(void); /** @brief Macro used by CANopenNode to guard TX critical section. */ -#define CO_LOCK_CAN_SEND(CAN_MODULE) canopen_send_lock() +#define CO_LOCK_CAN_SEND(CAN_MODULE) z_co_send_lock() /** @brief Macro used by CANopenNode to release TX critical section. */ -#define CO_UNLOCK_CAN_SEND(CAN_MODULE) canopen_send_unlock() +#define CO_UNLOCK_CAN_SEND(CAN_MODULE) z_co_send_unlock() /** @brief Macro used by CANopenNode to guard EMCY critical section. */ -#define CO_LOCK_EMCY(CAN_MODULE) canopen_emcy_lock() +#define CO_LOCK_EMCY(CAN_MODULE) z_co_emcy_lock() /** @brief Macro used by CANopenNode to release EMCY critical section. */ -#define CO_UNLOCK_EMCY(CAN_MODULE) canopen_emcy_unlock() +#define CO_UNLOCK_EMCY(CAN_MODULE) z_co_emcy_unlock() /** @brief Macro used by CANopenNode to guard OD critical section. */ -#define CO_LOCK_OD(CAN_MODULE) canopen_od_lock() +#define CO_LOCK_OD(CAN_MODULE) z_co_od_lock() /** @brief Macro used by CANopenNode to release OD critical section. */ -#define CO_UNLOCK_OD(CAN_MODULE) canopen_od_unlock() +#define CO_UNLOCK_OD(CAN_MODULE) z_co_od_unlock() /** @} */ /* -------------------------------------------------------------------------- */ diff --git a/zephyr/include/CO_zephyr_config.h b/zephyr/include/CO_zephyr_config.h index 21331933..a912a51b 100644 --- a/zephyr/include/CO_zephyr_config.h +++ b/zephyr/include/CO_zephyr_config.h @@ -262,15 +262,15 @@ extern "C" { /** @} */ /** @name Program Download (CiA 302-3) - * @brief Enable LED state machine and optional callback. + * @brief Configuration and Program download. * @{ */ #define CO_CONFIG_PROG_DOWNLOAD \ - (ZBIT(CO_CONFIG_PROG_DOWNLOAD_ENABLE, CONFIG_CANOPENNODE_PROG_DOWNLOAD)) + (ZBIT(CO_CONFIG_PROG_DOWNLOAD_ENABLE, CONFIG_CANOPENNODE_PROG_DOWNLOAD) | \ + ZBIT(CO_CONFIG_PROG_DOWNLOAD_PERMANENT, CONFIG_CANOPENNODE_PROG_DOWNLOAD_PERMANENT)) /** @brief Maximum EDS file size in bytes. */ #define CO_CONFIG_PROG_DOWNLOAD_EDS_MAX_SIZE CONFIG_CANOPENNODE_PROG_DOWNLOAD_EDS_MAX_SIZE - /** @} */ /** @name LEDs (CiA 303-3) diff --git a/zephyr/include/CO_zephyr_integration.h b/zephyr/include/CO_zephyr_integration.h index 098a9d77..69731090 100644 --- a/zephyr/include/CO_zephyr_integration.h +++ b/zephyr/include/CO_zephyr_integration.h @@ -64,20 +64,20 @@ extern "C" { * void app_start_canopen(void) * { * // Use default CAN dev from DT, Node-ID from Kconfig, default bitrate - * int rc = co_canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, 0); + * int rc = canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, 0); * if (rc != 0) { * printk("CANopen start failed: %d\n", rc); * return; * } * - * if (co_canopen_is_running()) { + * if (canopen_is_running()) { * printk("CANopen is up\n"); * } * } * * void app_stop_canopen(void) * { - * co_canopen_stop(); + * canopen_stop(); * } * @endcode * @@ -127,7 +127,7 @@ extern "C" { * @pre Zephyr kernel is initialized; @p can_dev (if non-NULL) is ready. * @warning Do not call from ISR context. */ -int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps); +int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps); /** * @brief Stop the CANopen stack and worker thread. @@ -136,7 +136,7 @@ int co_canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bit * stops the integration’s RT processing thread if present. Safe to call * multiple times; subsequent calls become no-ops. */ -void co_canopen_stop(void); +void canopen_stop(void); /** * @brief Query whether the CANopen stack is running. @@ -144,7 +144,7 @@ void co_canopen_stop(void); * @retval true The stack is active and running. * @retval false The stack is stopped or not yet initialized. */ -bool co_canopen_is_running(void); +bool canopen_is_running(void); #if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) @@ -152,26 +152,26 @@ bool co_canopen_is_running(void); * @brief Application-supplied provider for the CANopen Node-ID. * * This callback is queried by the Zephyr integration when the application - * passes `node_id == 0` to @ref co_canopen_start(), indicating that the + * passes `node_id == 0` to @ref canopen_start(), indicating that the * Node-ID should be sourced dynamically. The callback must return a valid * CANopen Node-ID in the range 0..127. Returning 0 indicates "unspecified" or * "invalid", in which case the integration will fall back to * @c CONFIG_CANOPENNODE_INIT_NODE_ID. * - * The callback is invoked in the context of @ref co_canopen_start() before the + * The callback is invoked in the context of @ref canopen_start() before the * stack is started (i.e., not from an ISR). Keep the implementation fast and * non-blocking. It is safe to read from non-volatile storage or board straps * if this does not block excessively. * * @param[in] user_data * Opaque pointer supplied when registering the callback via - * @ref co_canopen_register_node_id_cb(). May be @c NULL. + * @ref canopen_register_node_id_cb(). May be @c NULL. * * @retval 0..127 Valid Node-ID to use. * @retval >127 Unspecified/invalid; use fallback. * - * @see co_canopen_register_node_id_cb() - * @see co_canopen_start() + * @see canopen_register_node_id_cb() + * @see canopen_start() */ typedef uint8_t (*co_node_id_cb_t)(void *user_data); @@ -182,10 +182,10 @@ typedef uint8_t (*co_node_id_cb_t)(void *user_data); * application may provide a function that returns the desired CANopen Node-ID * at runtime. If @p cb is @c NULL, any previously registered callback is * cleared and the integration will use the Node-ID explicitly passed to - * @ref co_canopen_start(), or fall back to + * @ref canopen_start(), or fall back to * @c CONFIG_CANOPENNODE_INIT_NODE_ID if that value is 0. * - * @note Call this function **before** @ref co_canopen_start(). Registration is + * @note Call this function **before** @ref canopen_start(). Registration is * not thread-safe with a concurrently starting/stopping stack. * * @param[in] cb @@ -207,13 +207,13 @@ typedef uint8_t (*co_node_id_cb_t)(void *user_data); * * void main(void) * { - * co_canopen_register_node_id_cb(my_node_id_cb, NULL); + * canopen_register_node_id_cb(my_node_id_cb, NULL); * // Pass node_id = 0 to request dynamic Node-ID via the callback - * (void)co_canopen_start(NULL, 0, 500); + * (void)canopen_start(NULL, 0, 500); * } * @endcode */ -void co_canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data); +void canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data); #endif /* IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) */ diff --git a/zephyr/include/CO_zephyr_prog_download.h b/zephyr/include/CO_zephyr_prog_download.h new file mode 100644 index 00000000..424f19bb --- /dev/null +++ b/zephyr/include/CO_zephyr_prog_download.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr backend (ops) for CANopen Program Download (CiA 302-3 oriented). + * + * Streams incoming program bytes to the MCUBoot secondary slot via Zephyr's + * flash area API, then marks the image for upgrade on COMMIT. + * + * Requirements: + * - CONFIG_BOOTLOADER_MCUBOOT=y + * - CONFIG_FLASH=y + * - CONFIG_FLASH_MAP=y + * - CONFIG_IMG_MANAGER=y (recommended) + * + * Optional: + * - CONFIG_CO_PROGDL_ZEPHYR_PERMANENT=y to make upgrade permanent immediately + * (otherwise marks image as "test" and lets app confirm after self-test). + */ + +/** + * @section CO_ProgDL_ZephyrPartition Zephyr partition selection via Devicetree alias + * + * To select which flash partition CO_Prog_Download programs, define a Devicetree + * **alias** and reference it from code. This avoids fragile Kconfig strings and allows + * board- or app-specific DTS overlays to choose the target cleanly. + * + * ### Devicetree (board or application overlay) + * @code{.dts} + * / { + * aliases { + * // Point Program Download at the partition to be programmed + * can-progdl-partition = &image_1; // or &image_0, &slot1, etc. + * }; + * }; + * @endcode + * + * ### C usage + * In your Zephyr integration (e.g. the port glue that implements begin/write/commit), + * use the alias to resolve the partition node: + * @code{.c} + * #include + * + * #if DT_NODE_HAS_STATUS(DT_ALIAS(can_progdl_partition), okay) + * #define CO_PROGDL_PART_NODE DT_ALIAS(can_progdl_partition) + * #else + * #error "DT alias 'can-progdl-partition' is not defined or not okay" + * #endif + * + * // Example: get partition ID for flash_area_open() or FIXED_PARTITION_ID() + * #define CO_PROGDL_PARTITION_ID FIXED_PARTITION_ID(CO_PROGDL_PART_NODE) + * @endcode + * + * With this approach, changing the programmed area is a one - line change in DTS. + * No Kconfig strings are required, and the C preprocessor receives a proper + * Devicetree **token** (not a string), which is compatible with DT macros. + */ + +#ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_PROG_DOWNLOAD_H +#define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_PROG_DOWNLOAD_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "302/CO_Prog_Download.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONFIG_CO_PROGDL_ZEPHYR_FLASH_AREA_ID +#define CONFIG_CO_PROGDL_ZEPHYR_FLASH_AREA_ID FLASH_AREA_IMAGE_SECONDARY +#endif + +/* Backend context; one instance per PDL. */ +typedef struct { + /* Target flash area for the new image (normally image_1 / secondary). */ + uint8_t area_id; + + /* Flash area handle (opened on BEGIN, closed on ABORT/COMMIT). */ + const struct flash_area *fa; + + /* Running byte offset within the area. */ + uint32_t off; + + /* Expected total image size (hint from PDL). */ + uint32_t expected_size; + + /* True if BEGIN has successfully opened/erased. */ + bool active; + + /* If true, use boot_request_upgrade(permanent=1); else test upgrade. */ + bool permanent_upgrade; + + /* Optional: guard concurrent access if your SDO path is multithreaded. */ + struct k_mutex lock; +} CO_ProgDL_Zephyr_t; + +/** + * Initialize a Zephyr backend and register the stream ops into CO_ProgDL. + * + * @param pdl The CO_ProgDL instance (already initialized). + * @param zb Backend storage (caller supplies memory). + * @param area_id Flash area id (e.g., FLASH_AREA_ID(image_1)). + * @param permanent_upgrade If true, request a permanent upgrade at COMMIT. + * @return 0 on success, negative on error. + */ +int CO_zephyr_prog_download_bind(CO_ProgDL_t *pdl, CO_ProgDL_Zephyr_t *zb, uint8_t area_id, + bool permanent_upgrade); + +/* Convenience: bind with defaults from Kconfig. */ +static inline int CO_Prog_Download_zephyr_bind_default(CO_ProgDL_t *pdl, CO_ProgDL_Zephyr_t *zb) +{ + return CO_zephyr_prog_download_bind(pdl, zb, CONFIG_CO_PROGDL_ZEPHYR_FLASH_AREA_ID, + CONFIG_CANOPENNODE_PROG_DOWNLOAD_PERMANENT ? true + : false); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_PROG_DOWNLOAD_H */ From a80f1a105d3fbb5fea33e6ab600431b013821c89 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Tue, 19 Aug 2025 06:47:40 -0400 Subject: [PATCH 515/520] Refactors node ID handling and logging Simplifies the node ID assignment process by removing the callback mechanism and introducing a weak hook. This change centralizes node ID configuration, improving code maintainability and reducing complexity. It also corrects the logging module names across several files. --- zephyr/CO_zephyr_driver.c | 2 +- zephyr/CO_zephyr_integration.c | 81 +++----------------- zephyr/CO_zephyr_prog_download.c | 2 +- zephyr/CO_zephyr_storage.c | 2 +- zephyr/Kconfig | 14 ---- zephyr/include/CO_zephyr_integration.h | 100 ++++++------------------- 6 files changed, 33 insertions(+), 168 deletions(-) diff --git a/zephyr/CO_zephyr_driver.c b/zephyr/CO_zephyr_driver.c index be5f8b02..b7b66c06 100644 --- a/zephyr/CO_zephyr_driver.c +++ b/zephyr/CO_zephyr_driver.c @@ -35,7 +35,7 @@ #include #include -LOG_MODULE_REGISTER(canopennode_driver, CONFIG_CANOPEN_LOG_LEVEL); +LOG_MODULE_REGISTER(canopen_driver, CONFIG_CANOPEN_LOG_LEVEL); #define CANPTR_TO_DEV(ptr) ((const struct device *)(ptr)) diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 70ce3d0f..9c944689 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -44,7 +44,7 @@ #include "CO_zephyr_prog_download.h" #endif -LOG_MODULE_REGISTER(canopennode_zephyr, CONFIG_CANOPEN_LOG_LEVEL); +LOG_MODULE_REGISTER(canopen_zephyr, CONFIG_CANOPEN_LOG_LEVEL); #define CAN_NODE DT_CHOSEN(zephyr_canbus) #define CAN_BITRATE_KBPS (DT_PROP(CAN_NODE, bitrate) / 1000U) @@ -66,47 +66,10 @@ static CO_ProgDL_t pdl; static CO_ProgDL_Zephyr_t zb_ctx; #endif -#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) -static co_node_id_cb_t g_node_id_cb; -static void *g_node_id_cb_ud; -static const struct device *g_last_can_dev; -static uint8_t g_node_id_current; -static uint16_t g_last_bitrate_kbps; -#endif - K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ /* ---------- Helpers ---------- */ -/* Resolve a usable CANopen Node-ID. - * - * Priority: - * 1) If 'requested' is in [0..127], use it as-is. - * 2) If enabled and registered, ask the application callback - * (CONFIG_CANOPENNODE_NODE_ID_CALLBACK). Ignore out-of-range results. - * 3) Fall back to CONFIG_CANOPENNODE_INIT_NODE_ID. - * - * Notes: - * - Pass > 127 for 'requested' to defer to the callback or the Kconfig default. - * - The returned value is intended to be in [0..127]; ensure your Kconfig - * default is valid for your system. - */ -static uint8_t z_resolve_node_id(uint8_t requested) -{ - if (requested <= 127) { - return requested; - } -#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) - if (g_node_id_cb) { - uint8_t id = g_node_id_cb(g_node_id_cb_ud); - if (id <= 127) { - return id; - } - } -#endif - return CONFIG_CANOPENNODE_INIT_NODE_ID; -} - /* * Pre-callback used by SYNC/RPDO to poke the RT thread. * Gives the semaphore only when the stack is marked running. @@ -227,33 +190,6 @@ K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, z_canopen_r /* ---------- Public API ---------- */ -#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) -void canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data) -{ - g_node_id_cb = cb; - g_node_id_cb_ud = user_data; - - /* If not running or no callback registered, nothing more to do. */ - if (!atomic_get(&g_running) || g_node_id_cb == NULL) { - return; - } - - /* Ask the app for the desired Node-ID. */ - uint8_t new_id = g_node_id_cb(g_node_id_cb_ud); - if (new_id < 1 || new_id > 127 || new_id == g_node_id_current) { - return; /* invalid or no change */ - } - - /* Use last known device/bitrate; fall back to DT/Kconfig if missing. */ - const struct device *dev = g_last_can_dev ? g_last_can_dev : DEVICE_DT_GET(CAN_NODE); - uint16_t bitrate = g_last_bitrate_kbps ? g_last_bitrate_kbps : CAN_BITRATE_KBPS; - - /* Restart with new Node-ID. This will briefly interrupt communications. */ - canopen_stop(); - (void)canopen_start(dev, new_id, bitrate); -} -#endif - int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) { if (atomic_get(&g_running)) { @@ -266,8 +202,7 @@ int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrat return -ENODEV; } - node_id = z_resolve_node_id(node_id); - if (node_id > 127) { + if (node_id == 0 || node_id > 127) { return -EINVAL; } @@ -416,6 +351,12 @@ bool canopen_is_running(void) return atomic_get(&g_running); } +__weak uint8_t canopen_get_node_id(void *ud) +{ + ARG_UNUSED(ud); + return CONFIG_CANOPENNODE_INIT_NODE_ID; +} + /* * System init hook. * Optionally auto-starts CANopen at POST_KERNEL if configured via Kconfig. @@ -423,11 +364,7 @@ bool canopen_is_running(void) static int z_co_init_sys(void) { #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) -#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) - (void)canopen_start(NULL, CANOPENNODE_NODE_ID_CALLBACK_REQUEST, CAN_BITRATE_KBPS); -#else - (void)canopen_start(NULL, CONFIG_CANOPENNODE_INIT_NODE_ID, CAN_BITRATE_KBPS); -#endif + (void)canopen_start(NULL, canopen_get_node_id(NULL), CAN_BITRATE_KBPS); #endif return 0; diff --git a/zephyr/CO_zephyr_prog_download.c b/zephyr/CO_zephyr_prog_download.c index a49b9570..158984c7 100644 --- a/zephyr/CO_zephyr_prog_download.c +++ b/zephyr/CO_zephyr_prog_download.c @@ -9,7 +9,7 @@ #include "CO_zephyr_prog_download.h" #include -LOG_MODULE_REGISTER(canopennode_prog_download, CONFIG_CANOPEN_LOG_LEVEL); +LOG_MODULE_REGISTER(canopen_prog_download, CONFIG_CANOPEN_LOG_LEVEL); /* -------- Internal helpers -------- */ diff --git a/zephyr/CO_zephyr_storage.c b/zephyr/CO_zephyr_storage.c index 28f17b0b..31f627fb 100644 --- a/zephyr/CO_zephyr_storage.c +++ b/zephyr/CO_zephyr_storage.c @@ -33,7 +33,7 @@ #include #include -LOG_MODULE_REGISTER(canopennode_storage, CONFIG_CANOPEN_LOG_LEVEL); +LOG_MODULE_REGISTER(canopen_storage, CONFIG_CANOPEN_LOG_LEVEL); #ifdef CONFIG_CANOPEN_STORAGE_BACKEND_SETTINGS #include diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 605210bd..8cbd6492 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -867,20 +867,6 @@ config CANOPENNODE_INIT_NODE_ID Node ID for the CANopenNode instance. Must be unique on the CAN bus. -config CANOPENNODE_NODE_ID_CALLBACK - bool "Allow application-supplied Node-ID callback" - default n - help - Enable an application callback for dynamic Node-ID selection. - - Register your callback BEFORE calling co_canopen_start(): - co_canopen_register_node_id_cb(my_node_id_cb, my_ctx); - - The callback must return a Node-ID in the range 1..127. - Return 0 to indicate "unspecified". If the callback is not - registered or returns 0/out-of-range, the value from - CONFIG_CANOPENNODE_INIT_NODE_ID is used as the fallback. - endmenu endif # CANOPENNODE diff --git a/zephyr/include/CO_zephyr_integration.h b/zephyr/include/CO_zephyr_integration.h index 69731090..59fe0cfb 100644 --- a/zephyr/include/CO_zephyr_integration.h +++ b/zephyr/include/CO_zephyr_integration.h @@ -84,23 +84,6 @@ extern "C" { * @{ */ -/** - * @brief Special CANopen node ID value that requests a new ID via the application callback. - * - * When this value (255) is set as the node ID, it signals that the CANopen device - * should obtain its actual node ID from the application layer by invoking the - * configured callback function. - * - * This mechanism is useful for scenarios where the node ID is not fixed at compile-time - * and must be assigned dynamically during startup or reconfiguration. - * - * @note Per the CANopen standard, 255 (0xFF) is reserved for special purposes and - * must not be used as a normal operational node ID. - * - * @see for the callback responsible for providing the node ID. - */ -#define CANOPENNODE_NODE_ID_CALLBACK_REQUEST 255 - /** * @brief Start CANopenNode with explicit device, node ID, and bitrate. * @@ -146,76 +129,35 @@ void canopen_stop(void); */ bool canopen_is_running(void); -#if IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) - /** - * @brief Application-supplied provider for the CANopen Node-ID. - * - * This callback is queried by the Zephyr integration when the application - * passes `node_id == 0` to @ref canopen_start(), indicating that the - * Node-ID should be sourced dynamically. The callback must return a valid - * CANopen Node-ID in the range 0..127. Returning 0 indicates "unspecified" or - * "invalid", in which case the integration will fall back to - * @c CONFIG_CANOPENNODE_INIT_NODE_ID. + * @brief Weak hook for providing the CANopen Node-ID. * - * The callback is invoked in the context of @ref canopen_start() before the - * stack is started (i.e., not from an ISR). Keep the implementation fast and - * non-blocking. It is safe to read from non-volatile storage or board straps - * if this does not block excessively. + * This function is provided as a weak symbol and may be overridden by the + * application to supply a board- or system-specific Node-ID. If not + * overridden, the default implementation uses a fixed Node-ID from + * @c CONFIG_CANOPENNODE_INIT_NODE_ID or other built-in mechanism. * - * @param[in] user_data - * Opaque pointer supplied when registering the callback via - * @ref canopen_register_node_id_cb(). May be @c NULL. + * The Zephyr integration calls this hook when @ref canopen_start() is invoked + * with @p node_id > 127 (meaning "use default resolution"). The hook must + * return a valid CANopen Node-ID in the range 1..127. Returning 0 or a value + * greater than 127 is treated as "unspecified" or "invalid", and the + * integration will fall back to @c CONFIG_CANOPENNODE_INIT_NODE_ID. * - * @retval 0..127 Valid Node-ID to use. - * @retval >127 Unspecified/invalid; use fallback. + * The function is invoked in the context of @ref canopen_start() before the + * stack is started (i.e., not from an ISR). Implementations should keep the + * logic fast and non-blocking. It is safe to read from non-volatile storage + * or board configuration straps provided this does not block excessively. * - * @see canopen_register_node_id_cb() - * @see canopen_start() - */ -typedef uint8_t (*co_node_id_cb_t)(void *user_data); - -/** - * @brief Register or clear the application Node-ID callback. + * @param[in] ud + * Optional user data passed through from the integration. May be @c NULL. * - * When enabled by Kconfig (@c CONFIG_CANOPENNODE_NODE_ID_CALLBACK), the - * application may provide a function that returns the desired CANopen Node-ID - * at runtime. If @p cb is @c NULL, any previously registered callback is - * cleared and the integration will use the Node-ID explicitly passed to - * @ref canopen_start(), or fall back to - * @c CONFIG_CANOPENNODE_INIT_NODE_ID if that value is 0. + * @retval 1..127 Valid Node-ID to use. + * @retval 0 Invalid/unspecified, fall back to @c CONFIG_CANOPENNODE_INIT_NODE_ID. + * @retval >127 Invalid/unspecified, fall back to @c CONFIG_CANOPENNODE_INIT_NODE_ID. * - * @note Call this function **before** @ref canopen_start(). Registration is - * not thread-safe with a concurrently starting/stopping stack. - * - * @param[in] cb - * Callback function pointer, or @c NULL to clear the current callback. - * @param[in] user_data - * Opaque pointer forwarded to @p cb on each invocation. Ignored if - * @p cb is @c NULL. May be @c NULL. - * - * @return void - * - * @code{.c} - * // Example: provide Node-ID from DIP switches or settings - * static uint8_t my_node_id_cb(void *ud) - * { - * ARG_UNUSED(ud); - * // return 0..127 if known; return 0 to fall back - * return 7; - * } - * - * void main(void) - * { - * canopen_register_node_id_cb(my_node_id_cb, NULL); - * // Pass node_id = 0 to request dynamic Node-ID via the callback - * (void)canopen_start(NULL, 0, 500); - * } - * @endcode + * @see canopen_start() */ -void canopen_register_node_id_cb(co_node_id_cb_t cb, void *user_data); - -#endif /* IS_ENABLED(CONFIG_CANOPENNODE_NODE_ID_CALLBACK) */ +__weak uint8_t canopen_get_node_id_hook(void *ud); /** @} */ /* end of co_zephyr_integration */ From 68a8e43abc4ab5e4464c015c0a9f4864ee82cff2 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Thu, 21 Aug 2025 15:16:42 -0400 Subject: [PATCH 516/520] Improves CAN bus error handling and ID masking Updates CAN module processing to retrieve and utilize error counters from the Zephyr CAN driver, providing more accurate CAN bus error status. This change also corrects the CAN ID masking to properly extract the ID, ensuring correct functionality. The storage init function now correctly passes the storage struct, resolving a potential initialization issue. --- zephyr/CO_zephyr_driver.c | 54 ++++++++++++++++++++++++---------- zephyr/CO_zephyr_integration.c | 4 +-- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/zephyr/CO_zephyr_driver.c b/zephyr/CO_zephyr_driver.c index b7b66c06..3b7701cd 100644 --- a/zephyr/CO_zephyr_driver.c +++ b/zephyr/CO_zephyr_driver.c @@ -453,8 +453,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); memset(&frame, 0, sizeof(frame)); - frame.id = buffer->ident; /* note: template packs DLC/RTR into ident; driver extracts flags - below */ + frame.id = buffer->ident & 0x7FF; frame.dlc = buffer->DLC; frame.flags = ((buffer->ident & 0x800) ? CAN_FRAME_RTR : 0); memcpy(frame.data, buffer->data, buffer->DLC); @@ -503,10 +502,6 @@ void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule) } } -/* File-local error counters (placeholder). If your CAN driver exposes real - * error counters, wire them here and into CO_CANmodule_process(). */ -static uint_fast16_t rxErrors = 0, txErrors = 0, overflow = 0; - void CO_CANmodule_process(CO_CANmodule_t *CANmodule) { uint32_t err; @@ -515,6 +510,28 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) return; } + const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); + + /* Read controller state and error counters. + * If your can_get_state() takes values (not pointers), drop the '&'. + */ + enum can_state state; + struct can_bus_err_cnt err_cnt; + if (can_get_state(dev, &state, &err_cnt) != 0) { + /* Keep previous status if state can't be read this cycle. */ + return; + } + + /* Map driver counters/state into CANopenNode error inputs. */ + uint16_t txErrors = err_cnt.tx_err_cnt; /* 0..255 from controller */ + uint16_t rxErrors = err_cnt.rx_err_cnt; /* 0..255 from controller */ + uint8_t overflow = overflow = (can_stats_get_rx_overruns(dev) > 0); + + /* Ensure BUS-OFF handling even if counters aren't >= 256 yet. */ + if (state == CAN_STATE_BUS_OFF) { + txErrors = 256U; + } + err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow; if (CANmodule->errOld != err) { @@ -527,31 +544,31 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) status |= CO_CAN_ERRTX_BUS_OFF; } else { /* recalculate CANerrorStatus, first clear some flags */ - status &= 0xFFFF ^ (CO_CAN_ERRTX_BUS_OFF | CO_CAN_ERRRX_WARNING | - CO_CAN_ERRRX_PASSIVE | CO_CAN_ERRTX_WARNING | - CO_CAN_ERRTX_PASSIVE); + status &= 0xFFFFU ^ (CO_CAN_ERRTX_BUS_OFF | CO_CAN_ERRRX_WARNING | + CO_CAN_ERRRX_PASSIVE | CO_CAN_ERRTX_WARNING | + CO_CAN_ERRTX_PASSIVE); /* rx bus warning or passive */ - if (rxErrors >= 128) { + if (rxErrors >= 128U) { status |= CO_CAN_ERRRX_WARNING | CO_CAN_ERRRX_PASSIVE; - } else if (rxErrors >= 96) { + } else if (rxErrors >= 96U) { status |= CO_CAN_ERRRX_WARNING; } /* tx bus warning or passive */ - if (txErrors >= 128) { + if (txErrors >= 128U) { status |= CO_CAN_ERRTX_WARNING | CO_CAN_ERRTX_PASSIVE; - } else if (txErrors >= 96) { + } else if (txErrors >= 96U) { status |= CO_CAN_ERRTX_WARNING; } /* if not tx passive clear also overflow */ - if ((status & CO_CAN_ERRTX_PASSIVE) == 0) { - status &= 0xFFFF ^ CO_CAN_ERRTX_OVERFLOW; + if ((status & CO_CAN_ERRTX_PASSIVE) == 0U) { + status &= 0xFFFFU ^ CO_CAN_ERRTX_OVERFLOW; } } - if (overflow != 0) { + if (overflow != 0U) { /* CAN RX bus overflow */ status |= CO_CAN_ERRRX_OVERFLOW; } @@ -560,6 +577,11 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) } } +// void CO_CANmodule_process(CO_CANmodule_t *CANmodule) +// { + +// } + /* * Module initialization hook. * diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 9c944689..1c742c17 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -58,7 +58,7 @@ LOG_MODULE_REGISTER(canopen_zephyr, CONFIG_CANOPEN_LOG_LEVEL); * rt_sem wakes the RT thread from pre-callbacks and periodic processing. */ static CO_t *CO = NULL; -static CO_storage_t *CO_storage = NULL; +static CO_storage_t CO_storage; static atomic_t g_running; #if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) @@ -237,7 +237,7 @@ int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrat uint8_t entryCount = ARRAY_SIZE(storageEntries); uint32_t storageErr = 0; - err = co_zephyr_storage_init(CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, + err = co_zephyr_storage_init(&CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, entryCount, &storageErr); From 2c4c0a4a2c05d56f439dc8ec44cb902965884975 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Tue, 9 Sep 2025 20:30:31 -0400 Subject: [PATCH 517/520] Improves CANopenNode Zephyr integration Refactors and enhances the CANopenNode Zephyr integration for robustness and flexibility. Reorders flag definitions in `CO_config.h` for clarity. Introduces `eds2c_wrapper.py` for generating C source files from EDS, improving Windows compatibility by avoiding GTK dependencies. Adds SDO server compilation by default to simplify configuration. Enhances CAN driver error handling and retry mechanism, adding backoff strategy for managing TX failures due to bus congestion or errors. Adds NMT state change callback. Improves storage by adding persistent communication parameters Adds stack restart capability. These changes improve the reliability and ease of use of the CANopenNode stack within a Zephyr RTOS environment. --- 301/CO_config.h | 2 +- tools/eds2c_wrapper.py | 33 ++++- zephyr/CMakeLists.txt | 12 +- zephyr/CO_zephyr_driver.c | 202 +++++++++++++++++++++++------- zephyr/CO_zephyr_integration.c | 106 ++++++++++++++-- zephyr/Kconfig | 41 +++--- zephyr/include/CO_driver_target.h | 47 +++++-- zephyr/include/CO_zephyr_config.h | 1 + 8 files changed, 342 insertions(+), 102 deletions(-) diff --git a/301/CO_config.h b/301/CO_config.h index ef8c21b3..0d22406c 100644 --- a/301/CO_config.h +++ b/301/CO_config.h @@ -496,8 +496,8 @@ extern "C" { | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #define CO_CONFIG_RPDO_ENABLE 0x01 -#define CO_CONFIG_TPDO_ENABLE 0x02 #define CO_CONFIG_RPDO_TIMERS_ENABLE 0x04 +#define CO_CONFIG_TPDO_ENABLE 0x02 #define CO_CONFIG_TPDO_TIMERS_ENABLE 0x08 #define CO_CONFIG_PDO_SYNC_ENABLE 0x10 #define CO_CONFIG_PDO_OD_IO_ACCESS 0x20 diff --git a/tools/eds2c_wrapper.py b/tools/eds2c_wrapper.py index e0757413..6242f3d5 100644 --- a/tools/eds2c_wrapper.py +++ b/tools/eds2c_wrapper.py @@ -1,10 +1,30 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2025 BitConcepts, LLC +# Author: BitConcepts, LLC +# +# This file is part of , a CANopen stack. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + """ EDS to C Conversion Script (CLI Wrapper) -This script provides a minimal command-line interface (CLI) for invoking the -`eds2c` module from the `eds-utils` Python package. It allows Windows users -to generate C source files from an EDS (Electronic Data Sheet) file without -requiring GTK or other GUI dependencies, which are typically only supported +This script provides a minimal command-line interface (CLI) for invoking the +`eds2c` module from the `eds-utils` Python package. It allows Windows users +to generate C source files from an EDS (Electronic Data Sheet) file without +requiring GTK or other GUI dependencies, which are typically only supported on Linux or macOS. Usage: @@ -13,12 +33,13 @@ Arguments are passed directly to the `eds2c` entry point. For example: python eds2c_wrapper.py generate path/to/file.eds -o output/dir -Note: -- This bypasses GUI-related modules like `gi` and `eds_editor.main`, which +Notes: +- This bypasses GUI-related modules like `gi` and `eds_editor.main`, which often cause issues in Windows environments lacking GTK. - Make sure `eds-utils` is installed in your Python environment. """ + import sys from eds_utils import eds2c diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index a5c63a07..797497f7 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -33,7 +33,7 @@ # added to the module via zephyr_library_sources(). # - Conditional compilation is driven entirely by CONFIG_CANOPENNODE_* options. -cmake_minimum_required(VERSION 3.20) +if(CONFIG_CANOPENNODE) # Discover Zephyr and initialize the build system for a Zephyr application module. find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) @@ -156,10 +156,11 @@ zephyr_include_directories("${CANOPENNODE_OD_GEN_DIR}") # Core/common sources (built regardless of feature flags) # ------------------------------------------------------------------------------ -# Core CANopenNode runtime and OD interface always compiled. +# Core CANopenNode runtime, OD interface, and SDO server always compiled. zephyr_library_sources( "${CANOPENNODE_DIR}/CANopen.c" "${CANOPENNODE_DIR}/301/CO_ODinterface.c" + "${CANOPENNODE_DIR}/301/CO_SDOserver.c" ) # Emergency producer/consumer module (feature selection happens at compile/runtime). @@ -208,11 +209,6 @@ if(CONFIG_CANOPENNODE_RPDO_ENABLE OR CONFIG_CANOPENNODE_TPDO_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_PDO.c") endif() -# SDO Server (segmented and/or block). -if(CONFIG_CANOPENNODE_SDO_SERVER_SEGMENTED OR CONFIG_CANOPENNODE_SDO_SERVER_BLOCK) - zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SDOserver.c") -endif() - # SDO Client. if(CONFIG_CANOPENNODE_SDO_CLIENT_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/301/CO_SDOclient.c") @@ -284,3 +280,5 @@ if(CONFIG_CANOPENNODE_STORAGE_ENABLE) zephyr_library_sources("${CANOPENNODE_DIR}/storage/CO_storageEeprom.c") endif() endif() + +endif() # CONFIG_CANOPENNODE diff --git a/zephyr/CO_zephyr_driver.c b/zephyr/CO_zephyr_driver.c index 3b7701cd..794219ee 100644 --- a/zephyr/CO_zephyr_driver.c +++ b/zephyr/CO_zephyr_driver.c @@ -29,29 +29,32 @@ #include "301/CO_driver.h" #include -#include #include #include -#include +#include #include +#include LOG_MODULE_REGISTER(canopen_driver, CONFIG_CANOPEN_LOG_LEVEL); #define CANPTR_TO_DEV(ptr) ((const struct device *)(ptr)) -typedef struct { - uint32_t ident; - uint8_t DLC; - uint8_t data[8]; -} CO_CANrxMsg_t; - K_KERNEL_STACK_DEFINE(canopen_tx_workq_stack, CONFIG_CANOPENNODE_TX_WORKQUEUE_STACK_SIZE); +/* Retry backoff tunables (very small; CAN is fast and we only need to yield briefly) */ +#ifndef CONFIG_CANOPENNODE_TX_RETRY_INITIAL_MS +#define CONFIG_CANOPENNODE_TX_RETRY_INITIAL_MS 1 +#endif +#ifndef CONFIG_CANOPENNODE_TX_RETRY_MAX_MS +#define CONFIG_CANOPENNODE_TX_RETRY_MAX_MS 64 +#endif + struct k_work_q canopen_tx_workq; struct canopen_tx_work_container { - struct k_work work; + struct k_work_delayable dwork; CO_CANmodule_t *CANmodule; + uint32_t backoff_ms; /* current backoff (0 means “unset”) */ }; struct canopen_tx_work_container canopen_tx_queue; @@ -162,6 +165,37 @@ static void z_co_rx_callback(const struct device *dev, struct can_frame *frame, } } +static inline uint32_t z_co_next_backoff_ms(struct canopen_tx_work_container *c) +{ + if (c->backoff_ms == 0) { + c->backoff_ms = CONFIG_CANOPENNODE_TX_RETRY_INITIAL_MS; + } else if (c->backoff_ms < CONFIG_CANOPENNODE_TX_RETRY_MAX_MS) { + uint32_t next = c->backoff_ms << 1; + c->backoff_ms = (next > CONFIG_CANOPENNODE_TX_RETRY_MAX_MS) + ? CONFIG_CANOPENNODE_TX_RETRY_MAX_MS + : next; + } + return c->backoff_ms; +} + +static inline void z_co_retry_schedule(uint32_t delay_ms) +{ + k_work_schedule_for_queue(&canopen_tx_workq, &canopen_tx_queue.dwork, K_MSEC(delay_ms)); +} + +static inline void z_co_retry_schedule_backoff(void) +{ + if (canopen_tx_queue.backoff_ms < CONFIG_CANOPENNODE_TX_RETRY_MAX_MS) { + z_co_retry_schedule(z_co_next_backoff_ms(&canopen_tx_queue)); + } +} + +static inline void z_co_retry_schedule_now(void) +{ + canopen_tx_queue.backoff_ms = 0; /* reset on success/explicit wake */ + z_co_retry_schedule(0); +} + /* * TX completion callback from the Zephyr CAN driver. * @@ -186,8 +220,8 @@ static void z_co_tx_callback(const struct device *dev, int error, void *arg) CANmodule->firstCANtxMessage = false; } - /* Defer follow-up sends to a work queue to avoid busy loops here. */ - k_work_submit_to_queue(&canopen_tx_workq, &canopen_tx_queue.work); + /* A slot just freed up—reset backoff and drain now */ + z_co_retry_schedule_now(); } /* @@ -203,7 +237,7 @@ static void z_co_tx_callback(const struct device *dev, int error, void *arg) static void z_co_tx_retry(struct k_work *item) { struct canopen_tx_work_container *container = - CONTAINER_OF(item, struct canopen_tx_work_container, work); + CONTAINER_OF(item, struct canopen_tx_work_container, dwork.work); CO_CANmodule_t *CANmodule = container->CANmodule; const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); struct can_frame frame; @@ -220,20 +254,52 @@ static void z_co_tx_retry(struct k_work *item) if (buffer->bufferFull) { frame.id = buffer->ident; frame.dlc = buffer->DLC; - frame.flags |= ((buffer->ident & 0x800) ? CAN_FRAME_RTR : 0); + frame.flags = buffer->flags; memcpy(frame.data, buffer->data, buffer->DLC); - err = can_send(dev, &frame, K_NO_WAIT, z_co_tx_callback, CANmodule); - if (err == -EAGAIN) { - /* Controller is busy; stop here and try again later. */ - LOG_DBG("tx busy, will retry"); - break; - } else if (err != 0) { - LOG_ERR("tx send failed (err %d)", err); + if (err == 0) { + /* accepted; reset backoff and clear buffered copy */ + canopen_tx_queue.backoff_ms = 0; + buffer->bufferFull = false; + continue; } - /* Clear the bufferFull flag on success or non-retryable error. */ - buffer->bufferFull = false; + switch (err) { + case -EAGAIN: + /* busy / no slot right now */ + __fallthrough; + case -ENETDOWN: + /* stopped */ + __fallthrough; + case -ENETUNREACH: + /* bus-off */ + __fallthrough; + case -EBUSY: + /* arbitration lost (no auto-retry) */ + __fallthrough; + case -EIO: + /* Keep buffered; back off and try again */ + z_co_retry_schedule_backoff(); + /* Stop early so we don’t spin while saturated */ + CO_UNLOCK_CAN_SEND(); + return; + case -EINVAL: + __fallthrough; + case -ENOTSUP: + /* Unrecoverable param/config: drop */ + LOG_ERR("retry send invalid/unsupported (rc %d); dropping frame", + err); + buffer->bufferFull = false; + /* Continue to try other slots */ + break; + default: + LOG_WRN("retry send unexpected rc=%d; backoff", err); + z_co_retry_schedule_backoff(); + CO_UNLOCK_CAN_SEND(); + return; + } + /* Exit the for-loop on first backpressure to yield CPU and avoid thrash */ + break; } } @@ -354,8 +420,19 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); + /* Clear TX queue */ + if (k_work_cancel_delayable(&canopen_tx_queue.dwork) != 0) { + while (k_work_delayable_busy_get(&canopen_tx_queue.dwork) != 0) { + k_yield(); + } + } + + canopen_tx_queue.backoff_ms = 0; + + /* Remove all RX filters */ z_co_detach_all_rx_filters(CANmodule); + /* Stop the CAN bus */ int err = can_stop(dev); if (err != 0 && err != -EALREADY) { LOG_ERR("can stop failed (err %d)", err); @@ -427,12 +504,9 @@ CO_CANtx_t *CO_CANtxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, uint16 if ((CANmodule != NULL) && (index < CANmodule->txSize)) { /* specific buffer */ buffer = &CANmodule->txArray[index]; - - /* CAN identifier, DLC, and RTR packed per CANopenNode template */ - buffer->ident = ((uint32_t)ident & CAN_STD_ID_MASK) | - ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 11U)) | - ((uint32_t)(rtr ? 0x800U : 0U)); - + buffer->ident = ident & CAN_STD_ID_MASK; + buffer->DLC = noOfBytes; + buffer->flags = rtr ? CAN_FRAME_RTR : 0U; buffer->bufferFull = false; buffer->syncFlag = syncFlag; } @@ -444,6 +518,7 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) { CO_ReturnError_t err = CO_ERROR_NO; struct can_frame frame; + bool wasFullBefore = false; if (!CANmodule || !CANmodule->CANptr || !buffer) { LOG_ERR("tx send failed: invalid args"); @@ -453,21 +528,57 @@ CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); memset(&frame, 0, sizeof(frame)); - frame.id = buffer->ident & 0x7FF; + frame.id = buffer->ident; frame.dlc = buffer->DLC; - frame.flags = ((buffer->ident & 0x800) ? CAN_FRAME_RTR : 0); + frame.flags = buffer->flags; memcpy(frame.data, buffer->data, buffer->DLC); CO_LOCK_CAN_SEND(CANmodule); + wasFullBefore = buffer->bufferFull; - err = can_send(dev, &frame, K_NO_WAIT, z_co_tx_callback, CANmodule); - if (err == -EAGAIN) { - LOG_ERR("tx overflow"); - err = CO_ERROR_TX_OVERFLOW; - buffer->bufferFull = true; - } else if (err != 0) { - LOG_ERR("tx send failed (err %d)", err); - err = CO_ERROR_TX_UNCONFIGURED; + int rc = can_send(dev, &frame, K_NO_WAIT, z_co_tx_callback, CANmodule); + if (rc == 0) { + /* sent or accepted by driver; callback will fire later */ + canopen_tx_queue.backoff_ms = 0; + err = CO_ERROR_NO; + } else { + switch (rc) { + case -EAGAIN: + /* timeout (mailboxes busy / no immediate slot) */ + __fallthrough; + case -ENETDOWN: + /* controller stopped */ + __fallthrough; + case -ENETUNREACH: + /* bus-off */ + __fallthrough; + case -EBUSY: + /* arbitration lost (auto-retry off) */ + __fallthrough; + case -EIO: + /* general TX error (e.g., missing ACK w/ no auto-retry) */ + /* Buffer and ensure retry work runs */ + buffer->bufferFull = true; + z_co_retry_schedule_backoff(); + /* Only report overflow if we had no software room BEFORE this call */ + err = wasFullBefore ? CO_ERROR_TX_OVERFLOW : CO_ERROR_NO; + break; + case -EINVAL: + __fallthrough; + case -ENOTSUP: + /* Programming/config issue: retrying won’t help. Drop and surface. */ + LOG_ERR("can_send invalid/unsupported params (rc %d); dropping frame", rc); + buffer->bufferFull = false; + err = CO_ERROR_TX_UNCONFIGURED; + break; + default: + /* Unknown negative errno: keep it and retry */ + LOG_WRN("can_send unexpected err %d; will retry", rc); + buffer->bufferFull = true; + z_co_retry_schedule_backoff(); + err = wasFullBefore ? CO_ERROR_TX_OVERFLOW : CO_ERROR_NO; + break; + } } CO_UNLOCK_CAN_SEND(CANmodule); @@ -525,8 +636,11 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) /* Map driver counters/state into CANopenNode error inputs. */ uint16_t txErrors = err_cnt.tx_err_cnt; /* 0..255 from controller */ uint16_t rxErrors = err_cnt.rx_err_cnt; /* 0..255 from controller */ - uint8_t overflow = overflow = (can_stats_get_rx_overruns(dev) > 0); - +#if CONFIG_CAN_STATS + uint8_t overflow = (can_stats_get_rx_overruns(dev) > 0); +#else + uint8_t overflow = 0U; +#endif /* Ensure BUS-OFF handling even if counters aren't >= 256 yet. */ if (state == CAN_STATE_BUS_OFF) { txErrors = 256U; @@ -577,11 +691,6 @@ void CO_CANmodule_process(CO_CANmodule_t *CANmodule) } } -// void CO_CANmodule_process(CO_CANmodule_t *CANmodule) -// { - -// } - /* * Module initialization hook. * @@ -597,7 +706,8 @@ static int z_co_init(void) k_thread_name_set(&canopen_tx_workq.thread, "canopen_tx_workq"); - k_work_init(&canopen_tx_queue.work, z_co_tx_retry); + k_work_init_delayable(&canopen_tx_queue.dwork, z_co_tx_retry); + canopen_tx_queue.backoff_ms = 0; return 0; } diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 1c742c17..dc724c76 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -58,8 +59,13 @@ LOG_MODULE_REGISTER(canopen_zephyr, CONFIG_CANOPEN_LOG_LEVEL); * rt_sem wakes the RT thread from pre-callbacks and periodic processing. */ static CO_t *CO = NULL; +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) static CO_storage_t CO_storage; +#endif static atomic_t g_running; +static const struct device *g_last_can_dev = NULL; +static uint8_t g_last_node_id = 0; +static uint16_t g_last_bitrate_kbps = 0; #if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) static CO_ProgDL_t pdl; @@ -70,6 +76,35 @@ K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ /* ---------- Helpers ---------- */ +#ifdef CO_DEBUG_COMMON +void z_canopen_log(const char *msg) +{ + LOG_DBG("%s", msg); +} +#endif + +static void z_canopen_nmt_state_cb(CO_NMT_internalState_t state) +{ + const char *state_str = "UNKNOWN"; + switch (state) { + case CO_NMT_INITIALIZING: + state_str = "INITIALIZING"; + break; + case CO_NMT_PRE_OPERATIONAL: + state_str = "PRE-OPERATIONAL"; + break; + case CO_NMT_OPERATIONAL: + state_str = "OPERATIONAL"; + break; + case CO_NMT_STOPPED: + state_str = "STOPPED"; + break; + default: + break; + } + LOG_INF("NMT state changed to %s", state_str); +} + /* * Pre-callback used by SYNC/RPDO to poke the RT thread. * Gives the semaphore only when the stack is marked running. @@ -88,14 +123,38 @@ static void z_rt_signal_cb(void *object) */ static void z_enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) { +#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_SYNC_CALLBACK) CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_RPDO_CALLBACK) for (uint16_t i = 0; i < OD_CNT_RPDO; i++) { CO_RPDO_initCallbackPre(&co->RPDO[i], pre_cb, arg); } +#endif } /* ---------- RT Thread: SYNC/RPDO/TPDO ---------- */ #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD) + +__weak uint8_t canopen_get_node_id(); + +/* + * Function used to restart CANopen stack with last known parameters. + */ +static int z_canopen_restart(void) +{ + const struct device *can_dev = g_last_can_dev ? g_last_can_dev : DEVICE_DT_GET(CAN_NODE); + uint8_t node_id = g_last_node_id ? g_last_node_id : (uint8_t)canopen_get_node_id(); + uint16_t bitrate = g_last_bitrate_kbps ? g_last_bitrate_kbps : CAN_BITRATE_KBPS; + + if (atomic_get(&g_running)) { + canopen_stop(); + /* small settle time for CAN driver/filters */ + k_sleep(K_MSEC(10)); + } + return canopen_start(can_dev, node_id, bitrate); +} + /* * Real-time CANopen processing thread. * @@ -131,6 +190,7 @@ static void z_canopen_rt_thread(void *p1, void *p2, void *p3) } /* Mainline: CO_process() */ + CO_NMT_reset_cmd_t reset = CO_RESET_NOT; int64_t now_ms = k_uptime_get(); uint32_t dt_us = (last_ms == 0) ? fallback_us : (uint32_t)MAX(now_ms - last_ms, 0) * 1000U; @@ -138,11 +198,10 @@ static void z_canopen_rt_thread(void *p1, void *p2, void *p3) #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) uint32_t next_main_us = UINT32_MAX; - (void)CO_process(CO, false, dt_us, &next_main_us); + reset = CO_process(CO, false, dt_us, &next_main_us); #else - (void)CO_process(CO, false, dt_us, NULL); + reset = CO_process(CO, false, dt_us, NULL); #endif - /* RT part: SYNC, RPDO, TPDO */ uint32_t now_cyc = k_cycle_get_32(); uint32_t delta_cyc = now_cyc - prev_cyc; @@ -179,6 +238,27 @@ static void z_canopen_rt_thread(void *p1, void *p2, void *p3) #else timeout_us = fallback_us; #endif + if (reset == CO_RESET_NOT) { + /* No action */ + continue; + } else if (reset == CO_RESET_COMM) { + /* Reset CANopen stack */ + LOG_INF("Restarting CANopen stack"); + z_canopen_restart(); + } else if (reset == CO_RESET_APP) { + /* Stop CANopen stack and reboot device */ + LOG_INF("Rebooting device"); + canopen_stop(); + k_sleep(K_MSEC(100)); + sys_reboot(SYS_REBOOT_COLD); + } else if (reset == CO_RESET_QUIT) { + /* Stop CANopen stack and exit thread */ + LOG_INF("Stopping CANopen stack"); + canopen_stop(); + break; + } else { + LOG_WRN("Unexpected reset code: %d", reset); + } } } @@ -229,15 +309,15 @@ int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrat #if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) CO_storage_entry_t storageEntries[] = {{ - .addr = &OD_ROM, - .len = sizeof(OD_ROM), + .addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), .subIndexOD = 2, .attr = CO_storage_cmd | CO_storage_restore, }}; uint8_t entryCount = ARRAY_SIZE(storageEntries); uint32_t storageErr = 0; - err = co_zephyr_storage_init(&CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, + err = co_zephyr_storage_init(&CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameterField, OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, entryCount, &storageErr); @@ -315,10 +395,19 @@ int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrat LOG_INF("Node-ID not configured (LSS active)"); } +#if IS_ENABLED(CONFIG_CANOPENNODE_NMT_CALLBACK) + CO_NMT_initCallbackChanged(CO->NMT, z_canopen_nmt_state_cb); +#endif + z_enable_pre_signals(CO, z_rt_signal_cb, NULL); atomic_set(&g_running, 1); CO_CANsetNormalMode(CO->CANmodule); + /* Save previous values */ + g_last_can_dev = can_dev; + g_last_node_id = node_id; + g_last_bitrate_kbps = bitrate_kbps; + LOG_INF("CANopenNode running"); return 0; @@ -351,9 +440,8 @@ bool canopen_is_running(void) return atomic_get(&g_running); } -__weak uint8_t canopen_get_node_id(void *ud) +__weak uint8_t canopen_get_node_id() { - ARG_UNUSED(ud); return CONFIG_CANOPENNODE_INIT_NODE_ID; } @@ -364,7 +452,7 @@ __weak uint8_t canopen_get_node_id(void *ud) static int z_co_init_sys(void) { #if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) - (void)canopen_start(NULL, canopen_get_node_id(NULL), CAN_BITRATE_KBPS); + (void)canopen_start(NULL, canopen_get_node_id(), CAN_BITRATE_KBPS); #endif return 0; diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 8cbd6492..9e98fcf3 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -38,7 +38,7 @@ menuconfig CANOPENNODE bool "CANopenNode protocol stack support" depends on CAN - default y + default n help Enable the CANopenNode stack integration for Zephyr. @@ -62,7 +62,7 @@ config CANOPENNODE_NMT_MASTER config CANOPENNODE_NMT_CALLBACK bool "Enable custom callback after preprocessing received NMT message" - default n + default y help Enable a custom callback invoked after a received NMT message is preprocessed. Configure via CO_NMT_initCallbackPre(). @@ -105,7 +105,7 @@ config CANOPENNODE_NMT_ERR_TO_STOPPED config CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL bool "Auto-return to Operational when errors clear (CO_NMT_ERR_FREE_TO_OPERATIONAL)" - default y + default n comment "Error register mask (low 8 bits of NMT control)" @@ -115,7 +115,7 @@ menu "Heartbeat consumer - Specified in standard CiA 301" config CANOPENNODE_HB_CONS_ENABLE bool "Enable heartbeat consumer" - default y + default n help Monitor heartbeat messages from other nodes and trigger actions based on their status. @@ -198,7 +198,7 @@ menu "Emergency producer/consumer - Specified in standard CiA 301" config CANOPENNODE_EM_PRODUCER bool "Enable emergency producer" - default y + default n config CANOPENNODE_EM_PROD_CONFIGURABLE bool "Enable configurable COB-ID for emergency producer" @@ -256,7 +256,7 @@ menu "SDO server - Specified in standard CiA 301" config CANOPENNODE_SDO_SERVER_SEGMENTED bool "Enable segmented SDO server" - default y + default n config CANOPENNODE_SDO_SERVER_BLOCK bool "Enable block SDO server" @@ -268,17 +268,14 @@ config CANOPENNODE_SDO_SERVER_BLOCK config CANOPENNODE_SDO_SERVER_CALLBACK bool "Enable SDO server callback" - depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK default y config CANOPENNODE_SDO_SERVER_TIMERNEXT bool "Enable SDO server timerNext_us calculation" - depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK default y config CANOPENNODE_SDO_SERVER_OD_DYNAMIC bool "Enable dynamic behaviour of SDO server OD variables" - depends on CANOPENNODE_SDO_SERVER_SEGMENTED || CANOPENNODE_SDO_SERVER_BLOCK default y config CANOPENNODE_SDO_SERVER_BUFFER_SIZE @@ -327,17 +324,17 @@ config CANOPENNODE_SDO_CLIENT_LOCAL config CANOPENNODE_SDO_CLIENT_CALLBACK bool "Enable SDO client callback" depends on CANOPENNODE_SDO_CLIENT_ENABLE - default n + default y config CANOPENNODE_SDO_CLIENT_TIMERNEXT bool "Enable SDO client timerNext_us calculation" depends on CANOPENNODE_SDO_CLIENT_ENABLE - default n + default y config CANOPENNODE_SDO_CLIENT_OD_DYNAMIC bool "Enable dynamic behaviour of SDO client OD variables" depends on CANOPENNODE_SDO_CLIENT_ENABLE - default n + default y config CANOPENNODE_SDO_CLIENT_BUFFER_SIZE int "SDO client buffer size" @@ -360,7 +357,7 @@ menu "Time producer/consumer - Specified in standard CiA 301" config CANOPENNODE_TIME_ENABLE bool "Enable TIME object and TIME consumer" - default y + default n config CANOPENNODE_TIME_PRODUCER bool "Enable TIME producer" @@ -383,12 +380,12 @@ menu "SYNC and PDO producer/consumer - Specified in standard CiA 301" config CANOPENNODE_SYNC_ENABLE bool "Enable SYNC object and SYNC consumer" - default y + default n config CANOPENNODE_SYNC_PRODUCER bool "Enable SYNC producer" depends on CANOPENNODE_SYNC_ENABLE - default y + default n config CANOPENNODE_SYNC_CALLBACK bool "Enable SYNC callback" @@ -407,21 +404,23 @@ config CANOPENNODE_SYNC_OD_DYNAMIC config CANOPENNODE_RPDO_ENABLE bool "Enable receive PDO objects (RPDOs)" - default y + default n config CANOPENNODE_TPDO_ENABLE bool "Enable transmit PDO objects (TPDOs)" - default y + default n config CANOPENNODE_RPDO_TIMERS_ENABLE bool "Enable RPDO timers" depends on CANOPENNODE_RPDO_ENABLE - default y + default y if CANOPENNODE_RPDO_ENABLE + default n config CANOPENNODE_TPDO_TIMERS_ENABLE bool "Enable TPDO timers" depends on CANOPENNODE_TPDO_ENABLE - default y + default y if CANOPENNODE_TPDO_ENABLE + default n config CANOPENNODE_PDO_SYNC_ENABLE bool "Enable PDO SYNC" @@ -460,7 +459,7 @@ menu "Data storage - Data storage with CANopen OD objects 1010 and 1011, CiA 301 config CANOPENNODE_STORAGE_ENABLE bool "Enable data storage" - default y + default n help Persist OD entries via 0x1010/0x1011. @@ -756,10 +755,12 @@ config CANOPENNODE_DEBUG_COMMON config CANOPENNODE_DEBUG_SDO_CLIENT bool "Define default CO_DEBUG_SDO_CLIENT(msg) macro" + select CANOPENNODE_DEBUG_COMMON default n config CANOPENNODE_DEBUG_SDO_SERVER bool "Define default CO_DEBUG_SDO_SERVER(msg) macro" + select CANOPENNODE_DEBUG_COMMON default n endmenu diff --git a/zephyr/include/CO_driver_target.h b/zephyr/include/CO_driver_target.h index 5df40b0c..bc2d50cb 100644 --- a/zephyr/include/CO_driver_target.h +++ b/zephyr/include/CO_driver_target.h @@ -104,6 +104,17 @@ extern "C" { #define CO_free(ptr) k_free((ptr)) /** @} */ +/** + * @name Debug log hook + * @brief Thin wrapper around Zephyr debug logging used by CANopenNode. + * @{ + */ +#ifdef CO_CONFIG_DEBUG +extern void z_canopen_log(const char *msg); +#define CO_DEBUG_COMMON(msg) canopen_log(msg) +#endif +/** @} */ + /* -------------------------------------------------------------------------- */ /* Fundamental types */ /* -------------------------------------------------------------------------- */ @@ -135,25 +146,33 @@ typedef unsigned char domain_t; /* -------------------------------------------------------------------------- */ /** - * @name Receive message accessors (compatibility) - * @brief Stubs retained for template compatibility; not used on Zephyr. - * - * The Zephyr CAN API delivers frames via driver callbacks and message FIFOs. - * These macros are placeholders to satisfy the driver template interface. - * @{ + * @name Receive message accessors */ -/** @brief Return CAN identifier from RX message (unused on Zephyr). */ -#define CO_CANrxMsg_readIdent(msg) ((uint16_t)0) -/** @brief Return DLC from RX message (unused on Zephyr). */ -#define CO_CANrxMsg_readDLC(msg) ((uint8_t)0) -/** @brief Return data pointer from RX message (unused on Zephyr). */ -#define CO_CANrxMsg_readData(msg) ((const uint8_t *)NULL) +/** @brief Return CAN identifier from RX message. */ +#define CO_CANrxMsg_readIdent(msg) (((CO_CANrxMsg_t *)msg)->ident) +/** @brief Return ID from packed RX message CAN identifier. */ +#define CO_CANrxMsg_readID(msg) (CO_CANrxMsg_readIdent(msg) & CAN_STD_ID_MASK) +/** @brief Return DLC from packed RX message CAN identifier. */ +#define CO_CANrxMsg_readDLC(msg) (((CO_CANrxMsg_t *)msg)->DLC) +/** @brief Return data pointer from RX message. */ +#define CO_CANrxMsg_readData(msg) (((CO_CANrxMsg_t *)msg)->data) /** @} */ /* -------------------------------------------------------------------------- */ /* Driver objects */ /* -------------------------------------------------------------------------- */ +/** + * @brief Receive message object (driver-side). + * + * Describes a CAN receive object thunk used by the stack. + */ +typedef struct { + uint32_t ident; + uint8_t DLC; + uint8_t data[8]; +} CO_CANrxMsg_t; + /** * @brief Receive message object (driver-side). * @@ -182,12 +201,14 @@ typedef struct { * Represents a queued CAN frame and its state flags as used by the stack. */ typedef struct { - /** 11/29-bit CAN identifier to transmit. */ + /** Standard (11-bit) or extended (29-bit) CAN identifier. */ uint32_t ident; /** Data length code (0–8). */ uint8_t DLC; /** Payload buffer (0–8 bytes valid per @ref DLC). */ uint8_t data[8]; + /** Flags. @see @ref CAN_FRAME_FLAGS. */ + uint8_t flags; /** Set when the buffer holds a pending frame. */ volatile bool_t bufferFull; /** Set for frames transmitted during SYNC window. */ diff --git a/zephyr/include/CO_zephyr_config.h b/zephyr/include/CO_zephyr_config.h index a912a51b..5219da89 100644 --- a/zephyr/include/CO_zephyr_config.h +++ b/zephyr/include/CO_zephyr_config.h @@ -375,6 +375,7 @@ extern "C" { (ZBIT(CO_CONFIG_DEBUG_COMMON, CONFIG_CANOPENNODE_DEBUG_COMMON) | \ ZBIT(CO_CONFIG_DEBUG_SDO_CLIENT, CONFIG_CANOPENNODE_DEBUG_SDO_CLIENT) | \ ZBIT(CO_CONFIG_DEBUG_SDO_SERVER, CONFIG_CANOPENNODE_DEBUG_SDO_SERVER)) + /** @} */ /** @name Zephyr integration (TX workqueue) From 5214b84fde9abc8aeb764c49d474e0c53c059d97 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Wed, 10 Sep 2025 22:51:12 -0400 Subject: [PATCH 518/520] Improves CANopenNode shutdown and error handling Adds a controlled shutdown mechanism for the CANopenNode stack to prevent TX retries after disabling. Introduces error reporting and reset functions to allow the application to interact with the stack's error management. --- zephyr/CO_zephyr_driver.c | 39 ++++++++++--- zephyr/CO_zephyr_integration.c | 17 ++++-- zephyr/include/CO_zephyr_integration.h | 79 +++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 13 deletions(-) diff --git a/zephyr/CO_zephyr_driver.c b/zephyr/CO_zephyr_driver.c index 794219ee..a9bd6b26 100644 --- a/zephyr/CO_zephyr_driver.c +++ b/zephyr/CO_zephyr_driver.c @@ -33,6 +33,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(canopen_driver, CONFIG_CANOPEN_LOG_LEVEL); @@ -57,6 +58,8 @@ struct canopen_tx_work_container { uint32_t backoff_ms; /* current backoff (0 means “unset”) */ }; +atomic_t canopen_tx_shutdown = ATOMIC_INIT(0); + struct canopen_tx_work_container canopen_tx_queue; K_MUTEX_DEFINE(canopen_send_mutex); @@ -180,11 +183,17 @@ static inline uint32_t z_co_next_backoff_ms(struct canopen_tx_work_container *c) static inline void z_co_retry_schedule(uint32_t delay_ms) { + if (atomic_get(&canopen_tx_shutdown)) { + return; + } k_work_schedule_for_queue(&canopen_tx_workq, &canopen_tx_queue.dwork, K_MSEC(delay_ms)); } static inline void z_co_retry_schedule_backoff(void) { + if (atomic_get(&canopen_tx_shutdown)) { + return; + } if (canopen_tx_queue.backoff_ms < CONFIG_CANOPENNODE_TX_RETRY_MAX_MS) { z_co_retry_schedule(z_co_next_backoff_ms(&canopen_tx_queue)); } @@ -192,10 +201,22 @@ static inline void z_co_retry_schedule_backoff(void) static inline void z_co_retry_schedule_now(void) { + if (atomic_get(&canopen_tx_shutdown)) { + return; + } canopen_tx_queue.backoff_ms = 0; /* reset on success/explicit wake */ z_co_retry_schedule(0); } +static void z_flush_tx_work(void) +{ + struct k_work_sync sync = {0}; + + (void)k_work_cancel_delayable(&canopen_tx_queue.dwork); + (void)k_work_flush_delayable(&canopen_tx_queue.dwork, &sync); + canopen_tx_queue.backoff_ms = 0; +} + /* * TX completion callback from the Zephyr CAN driver. * @@ -220,6 +241,10 @@ static void z_co_tx_callback(const struct device *dev, int error, void *arg) CANmodule->firstCANtxMessage = false; } + if (atomic_get(&canopen_tx_shutdown)) { + return; + } + /* A slot just freed up—reset backoff and drain now */ z_co_retry_schedule_now(); } @@ -420,14 +445,9 @@ void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) const struct device *dev = CANPTR_TO_DEV(CANmodule->CANptr); - /* Clear TX queue */ - if (k_work_cancel_delayable(&canopen_tx_queue.dwork) != 0) { - while (k_work_delayable_busy_get(&canopen_tx_queue.dwork) != 0) { - k_yield(); - } - } - - canopen_tx_queue.backoff_ms = 0; + /* Flush TX queue */ + atomic_set(&canopen_tx_shutdown, 1); + z_flush_tx_work(); /* Remove all RX filters */ z_co_detach_all_rx_filters(CANmodule); @@ -707,8 +727,11 @@ static int z_co_init(void) k_thread_name_set(&canopen_tx_workq.thread, "canopen_tx_workq"); k_work_init_delayable(&canopen_tx_queue.dwork, z_co_tx_retry); + canopen_tx_queue.backoff_ms = 0; + atomic_clear(&canopen_tx_shutdown); + return 0; } diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index dc724c76..846fdaae 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -58,11 +58,11 @@ LOG_MODULE_REGISTER(canopen_zephyr, CONFIG_CANOPEN_LOG_LEVEL); * g_running is an atomic "stack is active" flag used by the RT thread and signalers. * rt_sem wakes the RT thread from pre-callbacks and periodic processing. */ -static CO_t *CO = NULL; +CO_t *CO = NULL; #if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) static CO_storage_t CO_storage; #endif -static atomic_t g_running; +atomic_t g_running; static const struct device *g_last_can_dev = NULL; static uint8_t g_last_node_id = 0; static uint16_t g_last_bitrate_kbps = 0; @@ -435,9 +435,18 @@ void canopen_stop(void) } } -bool canopen_is_running(void) +void canopen_error_report(uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) { - return atomic_get(&g_running); + if (CO && CO->em) { + CO_errorReport(CO->em, errorBit, errorCode, infoCode); + } +} + +void canopen_error_reset(uint8_t errorBit, uint32_t infoCode) +{ + if (CO && CO->em) { + CO_errorReset(CO->em, errorBit, infoCode); + } } __weak uint8_t canopen_get_node_id() diff --git a/zephyr/include/CO_zephyr_integration.h b/zephyr/include/CO_zephyr_integration.h index 59fe0cfb..1cdb0dc0 100644 --- a/zephyr/include/CO_zephyr_integration.h +++ b/zephyr/include/CO_zephyr_integration.h @@ -26,7 +26,9 @@ #ifndef ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_INTEGRATION_H #define ZEPHYR_MODULES_CANOPENNODE_CO_ZEPHYR_INTEGRATION_H +#include #include +#include #include #include #include @@ -84,6 +86,9 @@ extern "C" { * @{ */ +extern atomic_t g_running; +extern CO_t *CO; + /** * @brief Start CANopenNode with explicit device, node ID, and bitrate. * @@ -127,7 +132,79 @@ void canopen_stop(void); * @retval true The stack is active and running. * @retval false The stack is stopped or not yet initialized. */ -bool canopen_is_running(void); +static inline bool canopen_is_running(void) +{ + return (bool)atomic_get(&g_running); +} + +/** + * @brief Check whether a specific application error is currently active. + * + * Thin wrapper around CO_isError(). This tests an error/status bit managed by + * the CANopenNode Emergency/Error Manager. + * + * @param errorBit Error/status selector (one of the CO_EM_* values such as + * CO_EM_GENERIC_ERROR). Note: kept as @c uint8_t to match + * the current signature; consider using @c CO_EM_t for clarity. + * + * @retval true The selected error is active. + * @retval false The selected error is not active, or the stack is not initialized. + */ +static inline bool canopen_is_error(uint8_t errorBit) +{ + return (CO && CO->em) ? CO_isError(CO->em, errorBit) : false; +} + +/** + * @brief Read the CiA 301 Error Register (object 0x1001). + * + * Returns the current 8-bit Error Register maintained by the stack (per CiA 301), + * or 0 if the stack has not been initialized yet. + * + * @return Current value of object 0x1001 (Error Register), or 0 on uninitialized stack. + */ +static inline uint8_t canopen_get_error_register(void) +{ + return (CO && CO->em && CO->em->errorRegister) ? *(CO->em->errorRegister) : (uint8_t)0; +} + +/** + * @brief Report a generic application error via the Emergency (EMCY) object. + * + * Sets the CO_EM_GENERIC_ERROR condition and requests the stack to emit an EMCY + * with the given 16-bit EMCY error code (CiA 301) and a manufacturer-specific + * 32-bit info field. + * + * Typical usage: call when detecting an application fault (e.g., invalid config, + * overtemperature) to make the error visible to the network and to log it in + * 0x1003 (Pre-defined Error Field) according to the stack’s configuration. + * + * @param errorBit Error/status selector (one of the CO_EM_* values such as + * CO_EM_GENERIC_ERROR). Note: kept as @c uint8_t to match the + * current signature; consider using @c CO_EM_t for clarity. + * @param errorCode 16-bit EMCY error code (CiA 301 compliant). + * @param infoCode 32-bit manufacturer-specific info (placed in EMCY data as + * defined by the stack). + * + * @note No-op if the stack (CO/CO->em) is not initialized. + */ +void canopen_error_report(uint8_t errorBit, uint16_t errorCode, uint32_t infoCode); + +/** + * @brief Clear the previously reported generic application error. + * + * Clears the CO_EM_GENERIC_ERROR condition using CO_errorReset(). Depending on + * stack configuration, this may also cause an “error reset/cleared” EMCY + * indication to be sent to the network. + * + * @param errorBit Error/status selector (one of the CO_EM_* values such as + * CO_EM_GENERIC_ERROR). Note: kept as @c uint8_t to match the + * current signature; consider using @c CO_EM_t for clarity. + * @param infoCode 32-bit manufacturer-specific info (placed in EMCY data as + * defined by the stack). + * @note No-op if the stack (CO/CO->em) is not initialized. + */ +void canopen_error_reset(uint8_t errorBit, uint32_t infoCode); /** * @brief Weak hook for providing the CANopen Node-ID. From 3d270976bc01212da9800591b03da603ebc4a127 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Fri, 3 Apr 2026 11:27:09 -0400 Subject: [PATCH 519/520] Fix program download error check and add logging Kconfig - CO_zephyr_integration.c: Fix err vs ret variable in program download bind error check (was always false, silently ignoring failures) - Kconfig: Add Zephyr logging template for CONFIG_CANOPEN_LOG_LEVEL (referenced by CO_zephyr_driver.c and CO_zephyr_integration.c but was never defined, falling back to default log level) Co-Authored-By: Oz --- zephyr/CO_zephyr_integration.c | 938 ++++++++--------- zephyr/Kconfig | 1750 ++++++++++++++++---------------- 2 files changed, 1346 insertions(+), 1342 deletions(-) diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 846fdaae..0f313881 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -1,469 +1,469 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * Zephyr-to-CANopenNode integration runtime. - * - * Provides a runtime bridge to start/stop the CANopen stack with a selected - * Zephyr CAN device, Node-ID, and bitrate, enabling control from code in - * addition to prj.conf and devicetree. - * - * @file CO_zephyr_integration.c - * @author BitConcepts, LLC - * @copyright 2025 BitConcepts, LLC - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -#include "CO_zephyr_integration.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "OD.h" - -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) -#include "CO_zephyr_storage.h" -#endif - -#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) -#include "CO_zephyr_prog_download.h" -#endif - -LOG_MODULE_REGISTER(canopen_zephyr, CONFIG_CANOPEN_LOG_LEVEL); - -#define CAN_NODE DT_CHOSEN(zephyr_canbus) -#define CAN_BITRATE_KBPS (DT_PROP(CAN_NODE, bitrate) / 1000U) - -#define DEV_TO_CANPTR(d) ((void *)(uintptr_t)(d)) -#define CANPTR_TO_DEV(p) ((const struct device *)(p)) - -/* ---------- Module state ---------- - * CO / CO_storage are the runtime stack handles. - * g_running is an atomic "stack is active" flag used by the RT thread and signalers. - * rt_sem wakes the RT thread from pre-callbacks and periodic processing. - */ -CO_t *CO = NULL; -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) -static CO_storage_t CO_storage; -#endif -atomic_t g_running; -static const struct device *g_last_can_dev = NULL; -static uint8_t g_last_node_id = 0; -static uint16_t g_last_bitrate_kbps = 0; - -#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) -static CO_ProgDL_t pdl; -static CO_ProgDL_Zephyr_t zb_ctx; -#endif - -K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ - -/* ---------- Helpers ---------- */ - -#ifdef CO_DEBUG_COMMON -void z_canopen_log(const char *msg) -{ - LOG_DBG("%s", msg); -} -#endif - -static void z_canopen_nmt_state_cb(CO_NMT_internalState_t state) -{ - const char *state_str = "UNKNOWN"; - switch (state) { - case CO_NMT_INITIALIZING: - state_str = "INITIALIZING"; - break; - case CO_NMT_PRE_OPERATIONAL: - state_str = "PRE-OPERATIONAL"; - break; - case CO_NMT_OPERATIONAL: - state_str = "OPERATIONAL"; - break; - case CO_NMT_STOPPED: - state_str = "STOPPED"; - break; - default: - break; - } - LOG_INF("NMT state changed to %s", state_str); -} - -/* - * Pre-callback used by SYNC/RPDO to poke the RT thread. - * Gives the semaphore only when the stack is marked running. - */ -static void z_rt_signal_cb(void *object) -{ - ARG_UNUSED(object); - if (atomic_get(&g_running)) { - k_sem_give(&rt_sem); - } -} - -/* - * Register a common pre-callback for SYNC and all RPDOs. - * This lets incoming traffic promptly wake the RT thread. - */ -static void z_enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) -{ -#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_SYNC_CALLBACK) - CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); -#endif -#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_RPDO_CALLBACK) - for (uint16_t i = 0; i < OD_CNT_RPDO; i++) { - CO_RPDO_initCallbackPre(&co->RPDO[i], pre_cb, arg); - } -#endif -} - -/* ---------- RT Thread: SYNC/RPDO/TPDO ---------- */ -#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD) - -__weak uint8_t canopen_get_node_id(); - -/* - * Function used to restart CANopen stack with last known parameters. - */ -static int z_canopen_restart(void) -{ - const struct device *can_dev = g_last_can_dev ? g_last_can_dev : DEVICE_DT_GET(CAN_NODE); - uint8_t node_id = g_last_node_id ? g_last_node_id : (uint8_t)canopen_get_node_id(); - uint16_t bitrate = g_last_bitrate_kbps ? g_last_bitrate_kbps : CAN_BITRATE_KBPS; - - if (atomic_get(&g_running)) { - canopen_stop(); - /* small settle time for CAN driver/filters */ - k_sleep(K_MSEC(10)); - } - return canopen_start(can_dev, node_id, bitrate); -} - -/* - * Real-time CANopen processing thread. - * - * Responsibilities: - * - Waits on a semaphore or timeout. - * - Calls CO_process() (mainline timing and housekeeping). - * - Runs SYNC/RPDO/TPDO processing in a tight, low-latency section. - * - * Timing: - * - Uses uptime (ms) for CO_process() dt. - * - Uses CPU cycle delta for RT section dt to improve precision. - * - * Concurrency: - * - OD access is protected with CO_LOCK_OD()/CO_UNLOCK_OD(). - * - Thread runs continuously but only acts when the stack is running. - */ -static void z_canopen_rt_thread(void *p1, void *p2, void *p3) -{ - ARG_UNUSED(p1); - ARG_UNUSED(p2); - ARG_UNUSED(p3); - - int64_t last_ms = 0; - uint32_t prev_cyc = k_cycle_get_32(); - const uint32_t fallback_us = 1000U; - uint32_t timeout_us = fallback_us; - - while (true) { - k_sem_take(&rt_sem, K_USEC(timeout_us)); - - if (!atomic_get(&g_running) || CO == NULL) { - continue; - } - - /* Mainline: CO_process() */ - CO_NMT_reset_cmd_t reset = CO_RESET_NOT; - int64_t now_ms = k_uptime_get(); - uint32_t dt_us = - (last_ms == 0) ? fallback_us : (uint32_t)MAX(now_ms - last_ms, 0) * 1000U; - last_ms = now_ms; - -#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) - uint32_t next_main_us = UINT32_MAX; - reset = CO_process(CO, false, dt_us, &next_main_us); -#else - reset = CO_process(CO, false, dt_us, NULL); -#endif - /* RT part: SYNC, RPDO, TPDO */ - uint32_t now_cyc = k_cycle_get_32(); - uint32_t delta_cyc = now_cyc - prev_cyc; - prev_cyc = now_cyc; - - uint32_t dt_rt_us = (uint32_t)(k_cyc_to_ns_floor64(delta_cyc) / 1000U); - - CO_LOCK_OD(); - - uint32_t next_sync_us = UINT32_MAX; - uint32_t next_rpdo_us = UINT32_MAX; - uint32_t next_tpdo_us = UINT32_MAX; - -#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) - bool_t sync = CO_process_SYNC(CO, dt_rt_us, &next_sync_us); -#else - bool_t sync = false; -#endif -#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) - CO_process_RPDO(CO, sync, dt_rt_us, &next_rpdo_us); -#endif -#if IS_ENABLED(CONFIG_CANOPENNODE_TPDO_ENABLE) - CO_process_TPDO(CO, sync, dt_rt_us, &next_tpdo_us); -#endif - - CO_UNLOCK_OD(); - - /* Compute next wakeup based on returned timers */ - uint32_t next_rt_us = MIN(next_sync_us, MIN(next_rpdo_us, next_tpdo_us)); - -#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) - uint32_t next_all = MIN(next_rt_us, next_main_us); - timeout_us = (next_all == 0U || next_all == UINT32_MAX) ? fallback_us : next_all; -#else - timeout_us = fallback_us; -#endif - if (reset == CO_RESET_NOT) { - /* No action */ - continue; - } else if (reset == CO_RESET_COMM) { - /* Reset CANopen stack */ - LOG_INF("Restarting CANopen stack"); - z_canopen_restart(); - } else if (reset == CO_RESET_APP) { - /* Stop CANopen stack and reboot device */ - LOG_INF("Rebooting device"); - canopen_stop(); - k_sleep(K_MSEC(100)); - sys_reboot(SYS_REBOOT_COLD); - } else if (reset == CO_RESET_QUIT) { - /* Stop CANopen stack and exit thread */ - LOG_INF("Stopping CANopen stack"); - canopen_stop(); - break; - } else { - LOG_WRN("Unexpected reset code: %d", reset); - } - } -} - -/* Spawn the real-time processing thread at boot; priority/stack are Kconfig-driven. */ -K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, z_canopen_rt_thread, NULL, - NULL, NULL, CONFIG_CANOPENNODE_RT_THREAD_PRIORITY, 0, 0); - -#endif /* IS_ENABLED(CANOPENNODE_RT_THREAD) */ - -/* ---------- Public API ---------- */ - -int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) -{ - if (atomic_get(&g_running)) { - return -EALREADY; - } - if (!can_dev) { - can_dev = DEVICE_DT_GET(CAN_NODE); - } - if (!can_dev || !device_is_ready(can_dev)) { - return -ENODEV; - } - - if (node_id == 0 || node_id > 127) { - return -EINVAL; - } - - if (bitrate_kbps == 0) { - bitrate_kbps = CAN_BITRATE_KBPS; - } - - if (CO != NULL) { - CO_delete(CO); - CO = NULL; - } - - uint32_t heap_used = 0; - CO = CO_new(NULL, &heap_used); - if (CO == NULL) { - LOG_ERR("Memory allocation failed"); - return -ENOMEM; - } - LOG_INF("Allocated %u bytes for CANopen", heap_used); - - int ret = 0; - CO_ReturnError_t err; - uint32_t errInfo = 0; - -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) - CO_storage_entry_t storageEntries[] = {{ - .addr = &OD_PERSIST_COMM, - .len = sizeof(OD_PERSIST_COMM), - .subIndexOD = 2, - .attr = CO_storage_cmd | CO_storage_restore, - }}; - uint8_t entryCount = ARRAY_SIZE(storageEntries); - uint32_t storageErr = 0; - - err = co_zephyr_storage_init(&CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameterField, - OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, - entryCount, &storageErr); - - if (err != CO_ERROR_NO) { - LOG_ERR("Storage init failed: %d", err); - ret = -ENOMEM; - goto error; - } - if (storageErr != 0) { - LOG_ERR("Storage error: 0x%X", storageErr); - ret = -EIO; - goto error; - } -#endif - - err = CO_CANinit(CO, DEV_TO_CANPTR(can_dev), bitrate_kbps); - if (err != CO_ERROR_NO) { - LOG_ERR("CAN init failed: %d", err); - ret = -EINVAL; - goto error; - } - -#if IS_ENABLED(CONFIG_CANOPENNODE_LSS_SLAVE) - CO_LSS_address_t lssAddr = { - .identity = {.vendorID = OD_ROM.x1018_identity.vendor_ID, - .productCode = OD_ROM.x1018_identity.productCode, - .revisionNumber = OD_ROM.x1018_identity.revisionNumber, - .serialNumber = OD_ROM.x1018_identity.serialNumber}}; - err = CO_LSSinit(CO, &lssAddr, &node_id, &bitrate_kbps); - if (err != CO_ERROR_NO) { - LOG_ERR("LSS init failed: %d", err); - ret = -EINVAL; - goto error; - } -#endif - - err = CO_CANopenInit(CO, NULL, NULL, OD, NULL, CO_CONFIG_NMT_CONTROL, - CO_NMT_FIRST_HB_TIME_MS, CO_CONFIG_SDO_SRV_TIMEOUT_MS, - CO_CONFIG_SDO_CLI_TIMEOUT_MS, CO_CONFIG_SDO_CLI_BLOCK, node_id, - &errInfo); - - if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - LOG_ERR("CANopen init failed: %d (OD entry 0x%X)", err, errInfo); - ret = -EIO; - goto error; - } - - err = CO_CANopenInitPDO(CO, CO->em, OD, node_id, &errInfo); - if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - LOG_ERR("PDO init failed: %d (OD entry 0x%X)", err, errInfo); - ret = -EIO; - goto error; - } - -#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) - { - /* If your binder takes a partition ID and optional CO_storage handle: */ - err = CO_Prog_Download_zephyr_bind_default(&pdl, &zb_ctx); - if (ret != CO_ERROR_NO) { - LOG_ERR("Program Download bind failed: %d", ret); - ret = -EINVAL; - goto error; - } - } -#endif - - if (!CO->nodeIdUnconfigured) { -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) - if (storageErr != 0) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, - storageErr); - } -#endif - } else { - LOG_INF("Node-ID not configured (LSS active)"); - } - -#if IS_ENABLED(CONFIG_CANOPENNODE_NMT_CALLBACK) - CO_NMT_initCallbackChanged(CO->NMT, z_canopen_nmt_state_cb); -#endif - - z_enable_pre_signals(CO, z_rt_signal_cb, NULL); - atomic_set(&g_running, 1); - CO_CANsetNormalMode(CO->CANmodule); - - /* Save previous values */ - g_last_can_dev = can_dev; - g_last_node_id = node_id; - g_last_bitrate_kbps = bitrate_kbps; - - LOG_INF("CANopenNode running"); - return 0; - -error: - if (CO) { - CO_delete(CO); - CO = NULL; - } - return ret; -} - -void canopen_stop(void) -{ - if (!atomic_get(&g_running)) { - return; - } - - atomic_clear(&g_running); - - if (CO != NULL) { - CO_CANmodule_disable(CO->CANmodule); - CO_delete(CO); - CO = NULL; - LOG_INF("CANopenNode stopped"); - } -} - -void canopen_error_report(uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) -{ - if (CO && CO->em) { - CO_errorReport(CO->em, errorBit, errorCode, infoCode); - } -} - -void canopen_error_reset(uint8_t errorBit, uint32_t infoCode) -{ - if (CO && CO->em) { - CO_errorReset(CO->em, errorBit, infoCode); - } -} - -__weak uint8_t canopen_get_node_id() -{ - return CONFIG_CANOPENNODE_INIT_NODE_ID; -} - -/* - * System init hook. - * Optionally auto-starts CANopen at POST_KERNEL if configured via Kconfig. - */ -static int z_co_init_sys(void) -{ -#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) - (void)canopen_start(NULL, canopen_get_node_id(), CAN_BITRATE_KBPS); -#endif - - return 0; -} -SYS_INIT(z_co_init_sys, POST_KERNEL, CONFIG_CANOPENNODE_INIT_PRIORITY); +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr-to-CANopenNode integration runtime. + * + * Provides a runtime bridge to start/stop the CANopen stack with a selected + * Zephyr CAN device, Node-ID, and bitrate, enabling control from code in + * addition to prj.conf and devicetree. + * + * @file CO_zephyr_integration.c + * @author BitConcepts, LLC + * @copyright 2025 BitConcepts, LLC + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +#include "CO_zephyr_integration.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "OD.h" + +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) +#include "CO_zephyr_storage.h" +#endif + +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) +#include "CO_zephyr_prog_download.h" +#endif + +LOG_MODULE_REGISTER(canopen_zephyr, CONFIG_CANOPEN_LOG_LEVEL); + +#define CAN_NODE DT_CHOSEN(zephyr_canbus) +#define CAN_BITRATE_KBPS (DT_PROP(CAN_NODE, bitrate) / 1000U) + +#define DEV_TO_CANPTR(d) ((void *)(uintptr_t)(d)) +#define CANPTR_TO_DEV(p) ((const struct device *)(p)) + +/* ---------- Module state ---------- + * CO / CO_storage are the runtime stack handles. + * g_running is an atomic "stack is active" flag used by the RT thread and signalers. + * rt_sem wakes the RT thread from pre-callbacks and periodic processing. + */ +CO_t *CO = NULL; +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) +static CO_storage_t CO_storage; +#endif +atomic_t g_running; +static const struct device *g_last_can_dev = NULL; +static uint8_t g_last_node_id = 0; +static uint16_t g_last_bitrate_kbps = 0; + +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) +static CO_ProgDL_t pdl; +static CO_ProgDL_Zephyr_t zb_ctx; +#endif + +K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ + +/* ---------- Helpers ---------- */ + +#ifdef CO_DEBUG_COMMON +void z_canopen_log(const char *msg) +{ + LOG_DBG("%s", msg); +} +#endif + +static void z_canopen_nmt_state_cb(CO_NMT_internalState_t state) +{ + const char *state_str = "UNKNOWN"; + switch (state) { + case CO_NMT_INITIALIZING: + state_str = "INITIALIZING"; + break; + case CO_NMT_PRE_OPERATIONAL: + state_str = "PRE-OPERATIONAL"; + break; + case CO_NMT_OPERATIONAL: + state_str = "OPERATIONAL"; + break; + case CO_NMT_STOPPED: + state_str = "STOPPED"; + break; + default: + break; + } + LOG_INF("NMT state changed to %s", state_str); +} + +/* + * Pre-callback used by SYNC/RPDO to poke the RT thread. + * Gives the semaphore only when the stack is marked running. + */ +static void z_rt_signal_cb(void *object) +{ + ARG_UNUSED(object); + if (atomic_get(&g_running)) { + k_sem_give(&rt_sem); + } +} + +/* + * Register a common pre-callback for SYNC and all RPDOs. + * This lets incoming traffic promptly wake the RT thread. + */ +static void z_enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) +{ +#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_SYNC_CALLBACK) + CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_RPDO_CALLBACK) + for (uint16_t i = 0; i < OD_CNT_RPDO; i++) { + CO_RPDO_initCallbackPre(&co->RPDO[i], pre_cb, arg); + } +#endif +} + +/* ---------- RT Thread: SYNC/RPDO/TPDO ---------- */ +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD) + +__weak uint8_t canopen_get_node_id(); + +/* + * Function used to restart CANopen stack with last known parameters. + */ +static int z_canopen_restart(void) +{ + const struct device *can_dev = g_last_can_dev ? g_last_can_dev : DEVICE_DT_GET(CAN_NODE); + uint8_t node_id = g_last_node_id ? g_last_node_id : (uint8_t)canopen_get_node_id(); + uint16_t bitrate = g_last_bitrate_kbps ? g_last_bitrate_kbps : CAN_BITRATE_KBPS; + + if (atomic_get(&g_running)) { + canopen_stop(); + /* small settle time for CAN driver/filters */ + k_sleep(K_MSEC(10)); + } + return canopen_start(can_dev, node_id, bitrate); +} + +/* + * Real-time CANopen processing thread. + * + * Responsibilities: + * - Waits on a semaphore or timeout. + * - Calls CO_process() (mainline timing and housekeeping). + * - Runs SYNC/RPDO/TPDO processing in a tight, low-latency section. + * + * Timing: + * - Uses uptime (ms) for CO_process() dt. + * - Uses CPU cycle delta for RT section dt to improve precision. + * + * Concurrency: + * - OD access is protected with CO_LOCK_OD()/CO_UNLOCK_OD(). + * - Thread runs continuously but only acts when the stack is running. + */ +static void z_canopen_rt_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + int64_t last_ms = 0; + uint32_t prev_cyc = k_cycle_get_32(); + const uint32_t fallback_us = 1000U; + uint32_t timeout_us = fallback_us; + + while (true) { + k_sem_take(&rt_sem, K_USEC(timeout_us)); + + if (!atomic_get(&g_running) || CO == NULL) { + continue; + } + + /* Mainline: CO_process() */ + CO_NMT_reset_cmd_t reset = CO_RESET_NOT; + int64_t now_ms = k_uptime_get(); + uint32_t dt_us = + (last_ms == 0) ? fallback_us : (uint32_t)MAX(now_ms - last_ms, 0) * 1000U; + last_ms = now_ms; + +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) + uint32_t next_main_us = UINT32_MAX; + reset = CO_process(CO, false, dt_us, &next_main_us); +#else + reset = CO_process(CO, false, dt_us, NULL); +#endif + /* RT part: SYNC, RPDO, TPDO */ + uint32_t now_cyc = k_cycle_get_32(); + uint32_t delta_cyc = now_cyc - prev_cyc; + prev_cyc = now_cyc; + + uint32_t dt_rt_us = (uint32_t)(k_cyc_to_ns_floor64(delta_cyc) / 1000U); + + CO_LOCK_OD(); + + uint32_t next_sync_us = UINT32_MAX; + uint32_t next_rpdo_us = UINT32_MAX; + uint32_t next_tpdo_us = UINT32_MAX; + +#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) + bool_t sync = CO_process_SYNC(CO, dt_rt_us, &next_sync_us); +#else + bool_t sync = false; +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) + CO_process_RPDO(CO, sync, dt_rt_us, &next_rpdo_us); +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_TPDO_ENABLE) + CO_process_TPDO(CO, sync, dt_rt_us, &next_tpdo_us); +#endif + + CO_UNLOCK_OD(); + + /* Compute next wakeup based on returned timers */ + uint32_t next_rt_us = MIN(next_sync_us, MIN(next_rpdo_us, next_tpdo_us)); + +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) + uint32_t next_all = MIN(next_rt_us, next_main_us); + timeout_us = (next_all == 0U || next_all == UINT32_MAX) ? fallback_us : next_all; +#else + timeout_us = fallback_us; +#endif + if (reset == CO_RESET_NOT) { + /* No action */ + continue; + } else if (reset == CO_RESET_COMM) { + /* Reset CANopen stack */ + LOG_INF("Restarting CANopen stack"); + z_canopen_restart(); + } else if (reset == CO_RESET_APP) { + /* Stop CANopen stack and reboot device */ + LOG_INF("Rebooting device"); + canopen_stop(); + k_sleep(K_MSEC(100)); + sys_reboot(SYS_REBOOT_COLD); + } else if (reset == CO_RESET_QUIT) { + /* Stop CANopen stack and exit thread */ + LOG_INF("Stopping CANopen stack"); + canopen_stop(); + break; + } else { + LOG_WRN("Unexpected reset code: %d", reset); + } + } +} + +/* Spawn the real-time processing thread at boot; priority/stack are Kconfig-driven. */ +K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, z_canopen_rt_thread, NULL, + NULL, NULL, CONFIG_CANOPENNODE_RT_THREAD_PRIORITY, 0, 0); + +#endif /* IS_ENABLED(CANOPENNODE_RT_THREAD) */ + +/* ---------- Public API ---------- */ + +int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) +{ + if (atomic_get(&g_running)) { + return -EALREADY; + } + if (!can_dev) { + can_dev = DEVICE_DT_GET(CAN_NODE); + } + if (!can_dev || !device_is_ready(can_dev)) { + return -ENODEV; + } + + if (node_id == 0 || node_id > 127) { + return -EINVAL; + } + + if (bitrate_kbps == 0) { + bitrate_kbps = CAN_BITRATE_KBPS; + } + + if (CO != NULL) { + CO_delete(CO); + CO = NULL; + } + + uint32_t heap_used = 0; + CO = CO_new(NULL, &heap_used); + if (CO == NULL) { + LOG_ERR("Memory allocation failed"); + return -ENOMEM; + } + LOG_INF("Allocated %u bytes for CANopen", heap_used); + + int ret = 0; + CO_ReturnError_t err; + uint32_t errInfo = 0; + +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) + CO_storage_entry_t storageEntries[] = {{ + .addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), + .subIndexOD = 2, + .attr = CO_storage_cmd | CO_storage_restore, + }}; + uint8_t entryCount = ARRAY_SIZE(storageEntries); + uint32_t storageErr = 0; + + err = co_zephyr_storage_init(&CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameterField, + OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, + entryCount, &storageErr); + + if (err != CO_ERROR_NO) { + LOG_ERR("Storage init failed: %d", err); + ret = -ENOMEM; + goto error; + } + if (storageErr != 0) { + LOG_ERR("Storage error: 0x%X", storageErr); + ret = -EIO; + goto error; + } +#endif + + err = CO_CANinit(CO, DEV_TO_CANPTR(can_dev), bitrate_kbps); + if (err != CO_ERROR_NO) { + LOG_ERR("CAN init failed: %d", err); + ret = -EINVAL; + goto error; + } + +#if IS_ENABLED(CONFIG_CANOPENNODE_LSS_SLAVE) + CO_LSS_address_t lssAddr = { + .identity = {.vendorID = OD_ROM.x1018_identity.vendor_ID, + .productCode = OD_ROM.x1018_identity.productCode, + .revisionNumber = OD_ROM.x1018_identity.revisionNumber, + .serialNumber = OD_ROM.x1018_identity.serialNumber}}; + err = CO_LSSinit(CO, &lssAddr, &node_id, &bitrate_kbps); + if (err != CO_ERROR_NO) { + LOG_ERR("LSS init failed: %d", err); + ret = -EINVAL; + goto error; + } +#endif + + err = CO_CANopenInit(CO, NULL, NULL, OD, NULL, CO_CONFIG_NMT_CONTROL, + CO_NMT_FIRST_HB_TIME_MS, CO_CONFIG_SDO_SRV_TIMEOUT_MS, + CO_CONFIG_SDO_CLI_TIMEOUT_MS, CO_CONFIG_SDO_CLI_BLOCK, node_id, + &errInfo); + + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + LOG_ERR("CANopen init failed: %d (OD entry 0x%X)", err, errInfo); + ret = -EIO; + goto error; + } + + err = CO_CANopenInitPDO(CO, CO->em, OD, node_id, &errInfo); + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + LOG_ERR("PDO init failed: %d (OD entry 0x%X)", err, errInfo); + ret = -EIO; + goto error; + } + +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) + { + /* If your binder takes a partition ID and optional CO_storage handle: */ + err = CO_Prog_Download_zephyr_bind_default(&pdl, &zb_ctx); + if (err != CO_ERROR_NO) { + LOG_ERR("Program Download bind failed: %d", err); + ret = -EINVAL; + goto error; + } + } +#endif + + if (!CO->nodeIdUnconfigured) { +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) + if (storageErr != 0) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, + storageErr); + } +#endif + } else { + LOG_INF("Node-ID not configured (LSS active)"); + } + +#if IS_ENABLED(CONFIG_CANOPENNODE_NMT_CALLBACK) + CO_NMT_initCallbackChanged(CO->NMT, z_canopen_nmt_state_cb); +#endif + + z_enable_pre_signals(CO, z_rt_signal_cb, NULL); + atomic_set(&g_running, 1); + CO_CANsetNormalMode(CO->CANmodule); + + /* Save previous values */ + g_last_can_dev = can_dev; + g_last_node_id = node_id; + g_last_bitrate_kbps = bitrate_kbps; + + LOG_INF("CANopenNode running"); + return 0; + +error: + if (CO) { + CO_delete(CO); + CO = NULL; + } + return ret; +} + +void canopen_stop(void) +{ + if (!atomic_get(&g_running)) { + return; + } + + atomic_clear(&g_running); + + if (CO != NULL) { + CO_CANmodule_disable(CO->CANmodule); + CO_delete(CO); + CO = NULL; + LOG_INF("CANopenNode stopped"); + } +} + +void canopen_error_report(uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) +{ + if (CO && CO->em) { + CO_errorReport(CO->em, errorBit, errorCode, infoCode); + } +} + +void canopen_error_reset(uint8_t errorBit, uint32_t infoCode) +{ + if (CO && CO->em) { + CO_errorReset(CO->em, errorBit, infoCode); + } +} + +__weak uint8_t canopen_get_node_id() +{ + return CONFIG_CANOPENNODE_INIT_NODE_ID; +} + +/* + * System init hook. + * Optionally auto-starts CANopen at POST_KERNEL if configured via Kconfig. + */ +static int z_co_init_sys(void) +{ +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) + (void)canopen_start(NULL, canopen_get_node_id(), CAN_BITRATE_KBPS); +#endif + + return 0; +} +SYS_INIT(z_co_init_sys, POST_KERNEL, CONFIG_CANOPENNODE_INIT_PRIORITY); diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 9e98fcf3..cb87faa7 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -1,873 +1,877 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2025 BitConcepts, LLC -# -# CANopenNode — Zephyr module Kconfig -# -# This Kconfig file exposes CANopenNode features to Zephyr as CONFIG_* options. -# It lets you enable/disable protocol modules (NMT, SDO, PDO, etc.), choose -# Zephyr-specific integrations (storage backend, LED GPIO bridge), and set -# module-level parameters (buffers, timeouts, thread options). -# -# @file Kconfig -# @author BitConcepts, LLC -# -# This file is part of , a CANopen Stack. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this -# file except in compliance with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed under the License -# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions and limitations under -# the License. -# -# Usage notes: -# - Enable top-level CONFIG_CANOPENNODE=y in prj.conf to include the stack. -# - Most options default to sensible values; adjust per application needs. -# - Some features imply others via 'select' (see help for each symbol). -# - For LED helpers (CiA 303-3), provide devicetree aliases: -# aliases { -# co_led_run = &led0; -# co_led_err = &led1; -# }; -# - For Object Dictionary generation, set CONFIG_CANOPENNODE_EDS_FILE_PATH -# to an EDS relative to your application root (see CMakeLists.txt logic). - -menuconfig CANOPENNODE - bool "CANopenNode protocol stack support" - depends on CAN - default n - help - Enable the CANopenNode stack integration for Zephyr. - -if CANOPENNODE - -menu "NMT / Heartbeat producer - Specified in standard CiA 301" - -config CANOPENNODE_NMT_CALLBACK_CHANGE - bool "Enable custom callback after NMT state changes" - default y - help - Enable a custom callback invoked after the NMT state changes. - Configure via CO_NMT_initCallbackChanged(). - -config CANOPENNODE_NMT_MASTER - bool "Enable simple NMT master" - default n - help - Enable a simple NMT master object to control other nodes' - NMT states (start/stop/reset). - -config CANOPENNODE_NMT_CALLBACK - bool "Enable custom callback after preprocessing received NMT message" - default y - help - Enable a custom callback invoked after a received NMT message - is preprocessed. Configure via CO_NMT_initCallbackPre(). - -config CANOPENNODE_NMT_TIMERNEXT - bool "Enable NMT timerNext_us calculation" - default y - help - Enable calculation of timerNext_us for NMT to schedule next processing. - -config CANOPENNODE_NMT_FIRST_HB_TIME_MS - int "First heartbeat delay (ms)" - range 0 65535 - default 0 - help - Delay before the first Heartbeat after boot/reset. - 0 = no extra delay (start HB with the normal 0x1017 period). - Typical values: 200-1000 ms to let peers install filters and avoid - false HB-consumer timeouts during bus bring-up. - -endmenu - -menu "NMT startup/control" - -config CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL - bool "Start in Operational after init (CO_NMT_STARTUP_TO_OPERATIONAL)" - default y - -config CANOPENNODE_NMT_ERR_ON_BUSOFF_HB - bool "Error on bus-off / HB timeout (CO_NMT_ERR_ON_BUSOFF_HB)" - default y - -config CANOPENNODE_NMT_ERR_ON_ERR_REG - bool "Error on nonzero masked error register (CO_NMT_ERR_ON_ERR_REG)" - default y - -config CANOPENNODE_NMT_ERR_TO_STOPPED - bool "On error -> go to Stopped (else Pre-op) (CO_NMT_ERR_TO_STOPPED)" - default n - -config CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL - bool "Auto-return to Operational when errors clear (CO_NMT_ERR_FREE_TO_OPERATIONAL)" - default n - -comment "Error register mask (low 8 bits of NMT control)" - -endmenu - -menu "Heartbeat consumer - Specified in standard CiA 301" - -config CANOPENNODE_HB_CONS_ENABLE - bool "Enable heartbeat consumer" - default n - help - Monitor heartbeat messages from other nodes and trigger actions - based on their status. - -choice CANOPENNODE_HB_CONS_CALLBACK_MODE - prompt "Heartbeat consumer callback mode" - depends on CANOPENNODE_HB_CONS_ENABLE - optional - default CANOPENNODE_HB_CONS_CALLBACK_CHANGE - help - Select how heartbeat/NMT-change callbacks are handled. - Leave unset for no callbacks. Only one option can be active. - -config CANOPENNODE_HB_CONS_CALLBACK_CHANGE - bool "Single common callback after NMT state change" - help - Enable a single common callback invoked on NMT state changes. - Configure via CO_HBconsumer_initCallbackNmtChanged(). - -config CANOPENNODE_HB_CONS_CALLBACK_MULTI - bool "Per-node callbacks" - help - Enable per-node callbacks for NMT change, heartbeat started, - timeout, and remote reset. Configure via: - CO_HBconsumer_initCallbackNmtChanged(), - CO_HBconsumer_initCallbackHeartbeatStarted(), - CO_HBconsumer_initCallbackTimeout(), - CO_HBconsumer_initCallbackRemoteReset(). - -endchoice - -config CANOPENNODE_HB_CONS_QUERY_FUNCT - bool "Enable heartbeat and NMT query functions" - depends on CANOPENNODE_HB_CONS_ENABLE - default n - -config CANOPENNODE_HB_CONS_CALLBACK - bool "Enable custom callback after heartbeat message received" - depends on CANOPENNODE_HB_CONS_ENABLE - default n - help - Enable a callback invoked after a heartbeat message is preprocessed. - Configure via CO_HBconsumer_initCallbackPre(). - -config CANOPENNODE_HB_CONS_TIMERNEXT - bool "Enable heartbeat consumer timerNext_us calculation" - depends on CANOPENNODE_HB_CONS_ENABLE - default y - -config CANOPENNODE_HB_CONS_OD_DYNAMIC - bool "Enable dynamic behaviour of heartbeat consumer OD variables" - depends on CANOPENNODE_HB_CONS_ENABLE - default y - -endmenu - -menu "CANopen Node Guarding slave and master objects - Specified in standard CiA 301" - -config CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE - bool "Enable Node guarding slave" - default n - -config CANOPENNODE_NODE_GUARDING_MASTER_ENABLE - bool "Enable Node guarding master" - default n - -config CANOPENNODE_NODE_GUARDING_MASTER_COUNT - int "Max nodes monitored by guarding master" - range 1 127 - default 127 - -config CANOPENNODE_NODE_GUARDING_TIMERNEXT - bool "Enable Node guarding timerNext_us calculation" - depends on CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE || CANOPENNODE_NODE_GUARDING_MASTER_ENABLE - default n - -endmenu - -menu "Emergency producer/consumer - Specified in standard CiA 301" - -config CANOPENNODE_EM_PRODUCER - bool "Enable emergency producer" - default n - -config CANOPENNODE_EM_PROD_CONFIGURABLE - bool "Enable configurable COB-ID for emergency producer" - default n - -config CANOPENNODE_EM_PROD_INHIBIT - bool "Enable inhibit time for emergency producer" - default n - -config CANOPENNODE_EM_HISTORY - bool "Enable emergency error history" - default y - -config CANOPENNODE_EM_CONSUMER - bool "Enable emergency consumer" - default n - -config CANOPENNODE_EM_STATUS_BITS - bool "Enable emergency status bits in Object Dictionary" - default n - -config CANOPENNODE_EM_CALLBACK - bool "Enable custom callback after emergency message received" - default y - -config CANOPENNODE_EM_TIMERNEXT - bool "Enable emergency timerNext_us calculation" - default y - -config CANOPENNODE_EM_ERR_STATUS_BITS_COUNT - int "Emergency error status bits (multiple of 8)" - range 48 256 - default 80 - -# Optional error-register conditions (enable default expressions in mapper) -config CANOPENNODE_ERR_CONDITION_CURRENT - bool "Condition for calculating Error register: CURRENT" - default n - -config CANOPENNODE_ERR_CONDITION_VOLTAGE - bool "Condition for calculating Error register: VOLTAGE" - default n - -config CANOPENNODE_ERR_CONDITION_TEMPERATURE - bool "Condition for calculating Error register: TEMPERATURE" - default n - -config CANOPENNODE_ERR_CONDITION_DEV_PROFILE - bool "Condition for calculating Error register: DEVICE PROFILE" - default n - -endmenu - -menu "SDO server - Specified in standard CiA 301" - -config CANOPENNODE_SDO_SERVER_SEGMENTED - bool "Enable segmented SDO server" - default n - -config CANOPENNODE_SDO_SERVER_BLOCK - bool "Enable block SDO server" - select CANOPENNODE_SDO_SERVER_SEGMENTED - select CANOPENNODE_CRC16_ENABLE - default n - help - Use 127-segment block transfers with optional CRC for large, efficient transfers. - -config CANOPENNODE_SDO_SERVER_CALLBACK - bool "Enable SDO server callback" - default y - -config CANOPENNODE_SDO_SERVER_TIMERNEXT - bool "Enable SDO server timerNext_us calculation" - default y - -config CANOPENNODE_SDO_SERVER_OD_DYNAMIC - bool "Enable dynamic behaviour of SDO server OD variables" - default y - -config CANOPENNODE_SDO_SERVER_BUFFER_SIZE - int "SDO server buffer size" - range 900 4096 if CANOPENNODE_SDO_SERVER_BLOCK - range 20 4096 if !CANOPENNODE_SDO_SERVER_BLOCK - default 900 if CANOPENNODE_SDO_SERVER_BLOCK - default 32 - help - Internal buffer for SDO server. - - >=20 for segmented - - >=900 recommended for block (127 x 7 bytes) - -config CANOPENNODE_SDO_SERVER_TIMEOUT_MS - int "SDO server timeout (ms)" - range 50 60000 - default 1000 - -endmenu - -menu "SDO client - Specified in standard CiA 301" - -config CANOPENNODE_SDO_CLIENT_ENABLE - bool "Enable SDO client" - select CANOPENNODE_FIFO_ENABLE - default n - -config CANOPENNODE_SDO_CLIENT_SEGMENTED - bool "Enable SDO client segmented transfer" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default n - -config CANOPENNODE_SDO_CLIENT_BLOCK - bool "Enable SDO client block transfer" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - select CANOPENNODE_SDO_CLIENT_SEGMENTED - select CANOPENNODE_FIFO_ALT_READ - select CANOPENNODE_FIFO_CRC16_CCITT - default n - -config CANOPENNODE_SDO_CLIENT_LOCAL - bool "Enable local transfer (client/server same node)" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default n - -config CANOPENNODE_SDO_CLIENT_CALLBACK - bool "Enable SDO client callback" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default y - -config CANOPENNODE_SDO_CLIENT_TIMERNEXT - bool "Enable SDO client timerNext_us calculation" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default y - -config CANOPENNODE_SDO_CLIENT_OD_DYNAMIC - bool "Enable dynamic behaviour of SDO client OD variables" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default y - -config CANOPENNODE_SDO_CLIENT_BUFFER_SIZE - int "SDO client buffer size" - range 1000 4096 if CANOPENNODE_SDO_CLIENT_BLOCK - range 7 4096 if CANOPENNODE_SDO_CLIENT_SEGMENTED && !CANOPENNODE_SDO_CLIENT_BLOCK - default 1000 if CANOPENNODE_SDO_CLIENT_BLOCK - default 32 if !CANOPENNODE_SDO_CLIENT_BLOCK - help - Circular buffer used by SDO client. Can be <= object size since it is - processed over multiple calls. >=7 for segmented; >=1000 recommended for block. - -config CANOPENNODE_SDO_CLIENT_TIMEOUT_MS - int "SDO client timeout (ms)" - range 50 60000 - default 1000 - -endmenu - -menu "Time producer/consumer - Specified in standard CiA 301" - -config CANOPENNODE_TIME_ENABLE - bool "Enable TIME object and TIME consumer" - default n - -config CANOPENNODE_TIME_PRODUCER - bool "Enable TIME producer" - depends on CANOPENNODE_TIME_ENABLE - default n - -config CANOPENNODE_TIME_CALLBACK - bool "Enable TIME callback" - depends on CANOPENNODE_TIME_ENABLE - default y - -config CANOPENNODE_TIME_OD_DYNAMIC - bool "Enable dynamic behaviour of TIME OD variables" - depends on CANOPENNODE_TIME_ENABLE - default y - -endmenu - -menu "SYNC and PDO producer/consumer - Specified in standard CiA 301" - -config CANOPENNODE_SYNC_ENABLE - bool "Enable SYNC object and SYNC consumer" - default n - -config CANOPENNODE_SYNC_PRODUCER - bool "Enable SYNC producer" - depends on CANOPENNODE_SYNC_ENABLE - default n - -config CANOPENNODE_SYNC_CALLBACK - bool "Enable SYNC callback" - depends on CANOPENNODE_SYNC_ENABLE - default y - -config CANOPENNODE_SYNC_TIMERNEXT - bool "Enable SYNC timerNext_us calculation" - depends on CANOPENNODE_SYNC_ENABLE - default y - -config CANOPENNODE_SYNC_OD_DYNAMIC - bool "Enable dynamic behaviour of SYNC OD variables" - depends on CANOPENNODE_SYNC_ENABLE - default y - -config CANOPENNODE_RPDO_ENABLE - bool "Enable receive PDO objects (RPDOs)" - default n - -config CANOPENNODE_TPDO_ENABLE - bool "Enable transmit PDO objects (TPDOs)" - default n - -config CANOPENNODE_RPDO_TIMERS_ENABLE - bool "Enable RPDO timers" - depends on CANOPENNODE_RPDO_ENABLE - default y if CANOPENNODE_RPDO_ENABLE - default n - -config CANOPENNODE_TPDO_TIMERS_ENABLE - bool "Enable TPDO timers" - depends on CANOPENNODE_TPDO_ENABLE - default y if CANOPENNODE_TPDO_ENABLE - default n - -config CANOPENNODE_PDO_SYNC_ENABLE - bool "Enable PDO SYNC" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - select CANOPENNODE_SYNC_ENABLE - default y - help - Synchronize PDO processing with network SYNC messages. - -config CANOPENNODE_PDO_OD_IO_ACCESS - bool "Enable PDO OD IO access" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - select CANOPENNODE_PDO_OD_DYNAMIC - default y - help - Use OD IO accessors (OD_IO_t) for mapped PDO variables. - -config CANOPENNODE_PDO_CALLBACK - bool "Enable PDO callback" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default y - -config CANOPENNODE_PDO_TIMERNEXT - bool "Enable PDO timerNext_us calculation" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default y - -config CANOPENNODE_PDO_OD_DYNAMIC - bool "Enable dynamic behaviour of PDO OD variables" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default y - -endmenu - -menu "Data storage - Data storage with CANopen OD objects 1010 and 1011, CiA 301" - -config CANOPENNODE_STORAGE_ENABLE - bool "Enable data storage" - default n - help - Persist OD entries via 0x1010/0x1011. - -endmenu - -menu "Storage Backend" - depends on CANOPENNODE_STORAGE_ENABLE - -choice CANOPENNODE_STORAGE_BACKEND_CHOICE - prompt "Select CANopenNode OD storage backend" - default CANOPENNODE_STORAGE_BACKEND_RAM - -config CANOPENNODE_STORAGE_BACKEND_SETTINGS - bool "Zephyr Settings subsystem" - select SETTINGS - select CANOPENNODE_CRC16_ENABLE - help - Use Zephyr's Settings subsystem to persist OD entries. - -config CANOPENNODE_STORAGE_BACKEND_RAM - bool "RAM-only (no persistence)" - help - Store OD values in RAM only. Lost on reset. - -config CANOPENNODE_STORAGE_BACKEND_NONE - bool "None (disable OD storage)" - help - Disable OD storage completely. - -endchoice - -endmenu - -menu "Program Download - Specified in standard CiA 302-3" - -config CANOPENNODE_PROG_DOWNLOAD - bool "Enable Program Download object (CiA 302-3)" - select CANOPENNODE_CRC16_ENABLE - select FLASH_MAP - depends on FLASH - default n - help - Enables CO_Prog_Download: OD entries 0x1F21, 0x1F23, 0x1F24, 0x1F50, - 0x1F51, 0x1F56, 0x1F57. Streams data via registered backend and can - optionally bind to CO_storage for persistence. - -config CANOPENNODE_PROG_DOWNLOAD_EDS_MAX_SIZE - int "Maximum EDS file size (bytes)" - depends on CANOPENNODE_PROG_DOWNLOAD - default 2048 - range 256 1048576 - help - Upper limit for OD 0x1F23 (“Store EDS NMT slave”) data length. - If the received EDS exceeds this size, the transfer should be - rejected/aborted. Keep this reasonably small to avoid large - RAM allocations during transfer on constrained targets. - -config CANOPENNODE_PROG_DOWNLOAD_PERMANENT - bool "Program commit is permanent upgrade" - default y - help - If enabled, COMMIT (0x1F51 command) will request a permanent - upgrade of the programmed image. - If disabled, COMMIT will request a test upgrade instead, - requiring a later confirmation to keep the image. - -endmenu - -menu "CANopen LED Indicators - Specified in standard CiA 303-3" - -config CANOPENNODE_LEDS_ENABLE - bool "Enable calculation of the CANopen LED indicators" - default n - -config CANOPENNODE_LEDS_CALLBACK - bool "Enable custom callback after LED state changes" - default y if CANOPENNODE_LEDS_ENABLE - default n if !CANOPENNODE_LEDS_ENABLE - -config CANOPENNODE_LEDS_TIMERNEXT - bool "Enable calculation of timerNext_us for LED indicators" - default y if CANOPENNODE_LEDS_ENABLE - default n if !CANOPENNODE_LEDS_ENABLE - -endmenu - -menu "Safety Related Data Objects (SRDO) - Specified in standard EN 50325-5 (CiA 304)" - -config CANOPENNODE_GFC_ENABLE - bool "Enable GFC (Guarding Function Control)" - default n - -config CANOPENNODE_GFC_CONSUMER - bool "Enable GFC consumer" - depends on CANOPENNODE_GFC_ENABLE - default n - -config CANOPENNODE_GFC_PRODUCER - bool "Enable GFC producer" - depends on CANOPENNODE_GFC_ENABLE - default n - -config CANOPENNODE_SRDO_ENABLE - bool "Enable SRDO (Safety Related Data Objects)" - default n - -config CANOPENNODE_SRDO_CHECK_TX - bool "Enable SRDO TX data check" - depends on CANOPENNODE_SRDO_ENABLE - default n - -config CANOPENNODE_SRDO_CALLBACK - bool "Enable SRDO callback" - depends on CANOPENNODE_SRDO_ENABLE - default n - -config CANOPENNODE_SRDO_TIMERNEXT - bool "Enable SRDO timerNext_us calculation" - depends on CANOPENNODE_SRDO_ENABLE - default n - -config CANOPENNODE_SRDO_MINIMUM_DELAY - int "Minimum time between the first and second SRDO (Tx) message (us)" - range 0 1000000 - default 0 - -endmenu - -menu "LSS master/slave - Specified in standard CiA 305" - -config CANOPENNODE_LSS_SLAVE - bool "Enable LSS slave" - default n - -config CANOPENNODE_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND - bool "Enable fast-scan direct response" - depends on CANOPENNODE_LSS_SLAVE - default n - -config CANOPENNODE_LSS_MASTER - bool "Enable LSS master" - default n - -config CANOPENNODE_LSS_CALLBACK - bool "Enable LSS callback" - default n - -endmenu - -menu "Gateways - Specified in standard CiA 309" - -config CANOPENNODE_GTW_MULTI_NET - bool "Enable multiple network interfaces in gateway device" - depends on 0 - default n - -config CANOPENNODE_GTW_ASCII - bool "Enable gateway device with ASCII mapping" - select CANOPENNODE_FIFO_ENABLE - select CANOPENNODE_FIFO_ASCII_COMMANDS - default n - -config CANOPENNODE_GTW_ASCII_SDO - bool "Enable SDO client in gateway-ascii" - depends on CANOPENNODE_GTW_ASCII - select CANOPENNODE_SDO_CLIENT_ENABLE - select CANOPENNODE_FIFO_ASCII_DATATYPES - default n - -config CANOPENNODE_GTW_ASCII_NMT - bool "Enable NMT master in gateway-ascii" - depends on CANOPENNODE_GTW_ASCII - select CANOPENNODE_NMT_MASTER - default n - -config CANOPENNODE_GTW_ASCII_LSS - bool "Enable LSS master in gateway-ascii" - depends on CANOPENNODE_GTW_ASCII - select CANOPENNODE_LSS_MASTER - default n - -config CANOPENNODE_GTW_ASCII_LOG - bool "Enable non-standard message log read" - depends on CANOPENNODE_GTW_ASCII - default n - -config CANOPENNODE_GTW_ASCII_ERROR_DESC - bool "Print error descriptions as comments in gateway-ascii" - depends on CANOPENNODE_GTW_ASCII - default n - -config CANOPENNODE_GTW_ASCII_PRINT_HELP - bool "Enable non-standard \"help\" command" - depends on CANOPENNODE_GTW_ASCII - default n - -config CANOPENNODE_GTW_ASCII_PRINT_LEDS - bool "Display CANopen status LEDs on terminal" - depends on CANOPENNODE_GTW_ASCII - select CANOPENNODE_LEDS_ENABLE - default n - -config CANOPENNODE_GTW_BLOCK_DL_LOOP - int "Number of process loops in case of block download" - range 1 127 - default 1 - help - Additional local loop iterations while a block download is in progress - to speed up transfer (up to 127). - -config CANOPENNODE_GTWA_COMM_BUF_SIZE - int "Size of command buffer in ASCII gateway object" - range 16 4096 - default 200 - help - Increase to >=1000 when doing large block transfers. - -config CANOPENNODE_GTWA_LOG_BUF_SIZE - int "Gateway: log buffer size" - range 128 4096 - default 2000 - -endmenu - -menu "CRC 16 calculation" - -config CANOPENNODE_CRC16_ENABLE - bool "Enable CRC16 calculation" - default n - -config CANOPENNODE_CRC16_EXTERNAL - bool "CRC functions are defined externally" - depends on CANOPENNODE_CRC16_ENABLE - select CRC - default y if CANOPENNODE_CRC16_ENABLE - help - If enabled, the application must provide: - void crc16_ccitt_single(uint16_t *crc, uint8_t chr); - uint16_t crc16_ccitt(const uint8_t block[], size_t len, uint16_t crc); - If disabled, the internal CRC16 functions will be used. - -endmenu - -menu "FIFO buffer" - -config CANOPENNODE_FIFO_ENABLE - bool "Enable FIFO buffer" - default n - -config CANOPENNODE_FIFO_ALT_READ - bool "FIFO alternate read (needed by SDO client block)" - depends on CANOPENNODE_FIFO_ENABLE - default n - -config CANOPENNODE_FIFO_CRC16_CCITT - bool "FIFO CRC16-CCITT (needed by SDO client block)" - depends on CANOPENNODE_FIFO_ENABLE - select CANOPENNODE_CRC16_ENABLE - default n - -config CANOPENNODE_FIFO_ASCII_COMMANDS - bool "FIFO ASCII command helpers" - depends on CANOPENNODE_FIFO_ENABLE - default n - -config CANOPENNODE_FIFO_ASCII_DATATYPES - bool "FIFO ASCII datatype helpers" - depends on CANOPENNODE_FIFO_ENABLE && CANOPENNODE_FIFO_ASCII_COMMANDS - default n - help - Helpers to read/write integers/floats/strings in ASCII. - -endmenu - -menu "Trace recorder" - -config CANOPENNODE_TRACE_ENABLE - bool "Enable Trace recorder" - default n - -config CANOPENNODE_TRACE_OWN_INTTYPES - bool "Provide custom PRIu32/PRId32 macros (no )" - depends on CANOPENNODE_TRACE_ENABLE - default n - -endmenu - -menu "Debug messages" - -config CANOPENNODE_DEBUG_COMMON - bool "Define default CO_DEBUG_COMMON(msg) macro" - default n - -config CANOPENNODE_DEBUG_SDO_CLIENT - bool "Define default CO_DEBUG_SDO_CLIENT(msg) macro" - select CANOPENNODE_DEBUG_COMMON - default n - -config CANOPENNODE_DEBUG_SDO_SERVER - bool "Define default CO_DEBUG_SDO_SERVER(msg) macro" - select CANOPENNODE_DEBUG_COMMON - default n - -endmenu - -menu "Object Dictionary (EDS)" - -config CANOPENNODE_EDS_FILE_PATH - string "EDS file (path relative to application root)" - default "" - help - Path to the EDS used to generate OD.c/OD.h. - Leave empty to use: - example/DS301_profile.eds - -endmenu - -menu "CANopenNode TX Workqueue Options" - -config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE - int "TX workqueue stack size" - default 1024 - range 256 16384 - help - Stack size (in bytes) for the CANopenNode TX workqueue thread. - -config CANOPENNODE_TX_WORKQUEUE_PRIORITY - int "TX workqueue priority" - default 0 - help - Thread priority for the CANopenNode TX workqueue. - Lower numbers mean higher priority. - -endmenu - -menu "CANopenNode Thread Options" - -config CANOPENNODE_RT_THREAD - bool "Use real-time thread for CANopen processing" - default y - help - If enabled, a dedicated real-time thread will be created for CANopen - processing. Otherwise, the application must call CO_process() periodically. - -config CANOPENNODE_RT_THREAD_STACK_SIZE - int "Real-time thread stack size" - default 1024 - help - Stack size (bytes) for the CANopenNode real-time thread. - Only used if CANOPENNODE_RT_THREAD is enabled. - Increase if you use many PDOs, SDOs, or large OD entries. - Decrease if you have memory constraints and use few CANopen features. - Typical values: 1024-4096 bytes. - Measure actual stack usage to optimize. - -config CANOPENNODE_RT_THREAD_PRIORITY - int "Real-time thread priority" - default -1 - help - Thread priority for the CANopenNode real-time thread. - Only used if CANOPENNODE_RT_THREAD is enabled. - Lower numbers mean higher priority. - Typical values: -1 to -3 for real-time processing. - -config CANOPENNODE_RT_THREAD_IDLE_MS - int "Real-time thread idle time (ms)" - default 10 - help - Time (ms) the CANopenNode real-time thread sleeps when idle. - Only used if CANOPENNODE_RT_THREAD is enabled. - Lower values mean more CPU usage but lower latency. - Typical values: 1-100 ms. - -config CANOPENNODE_RT_THREAD_TIMERNEXT - bool "Enable timerNext_us calculation in real-time thread" - default y - help - If enabled, timerNext_us will be calculated in the real-time thread. - Only used if CANOPENNODE_RT_THREAD is enabled. - Disable to save CPU if you don't use features that need timerNext_us. - -config CANOPENNODE_RT_THREAD_AUTO_START - bool "Auto-start CANopenNode real-time thread" - default y - help - If enabled, the CANopenNode real-time thread will be started automatically - at POST_KERNEL. Otherwise, you must call CO_RT_threadStart() manually. -endmenu - -menu "CANopenNode Initialization" - -config CANOPENNODE_INIT_PRIORITY - int "CANopenNode initialization priority" - default 90 - help - Priority for CANopenNode initialization. - Lower numbers mean earlier initialization. - Typical values: 80-100. - Must be lower than the application's main thread priority. - -config CANOPENNODE_INIT_NODE_ID - int "CANopenNode node ID" - default 1 - range 0 127 - help - Node ID for the CANopenNode instance. - Must be unique on the CAN bus. - -endmenu - -endif # CANOPENNODE +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 BitConcepts, LLC +# +# CANopenNode — Zephyr module Kconfig +# +# This Kconfig file exposes CANopenNode features to Zephyr as CONFIG_* options. +# It lets you enable/disable protocol modules (NMT, SDO, PDO, etc.), choose +# Zephyr-specific integrations (storage backend, LED GPIO bridge), and set +# module-level parameters (buffers, timeouts, thread options). +# +# @file Kconfig +# @author BitConcepts, LLC +# +# This file is part of , a CANopen Stack. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +# Usage notes: +# - Enable top-level CONFIG_CANOPENNODE=y in prj.conf to include the stack. +# - Most options default to sensible values; adjust per application needs. +# - Some features imply others via 'select' (see help for each symbol). +# - For LED helpers (CiA 303-3), provide devicetree aliases: +# aliases { +# co_led_run = &led0; +# co_led_err = &led1; +# }; +# - For Object Dictionary generation, set CONFIG_CANOPENNODE_EDS_FILE_PATH +# to an EDS relative to your application root (see CMakeLists.txt logic). + +menuconfig CANOPENNODE + bool "CANopenNode protocol stack support" + depends on CAN + default n + help + Enable the CANopenNode stack integration for Zephyr. + +if CANOPENNODE + +menu "NMT / Heartbeat producer - Specified in standard CiA 301" + +config CANOPENNODE_NMT_CALLBACK_CHANGE + bool "Enable custom callback after NMT state changes" + default y + help + Enable a custom callback invoked after the NMT state changes. + Configure via CO_NMT_initCallbackChanged(). + +config CANOPENNODE_NMT_MASTER + bool "Enable simple NMT master" + default n + help + Enable a simple NMT master object to control other nodes' + NMT states (start/stop/reset). + +config CANOPENNODE_NMT_CALLBACK + bool "Enable custom callback after preprocessing received NMT message" + default y + help + Enable a custom callback invoked after a received NMT message + is preprocessed. Configure via CO_NMT_initCallbackPre(). + +config CANOPENNODE_NMT_TIMERNEXT + bool "Enable NMT timerNext_us calculation" + default y + help + Enable calculation of timerNext_us for NMT to schedule next processing. + +config CANOPENNODE_NMT_FIRST_HB_TIME_MS + int "First heartbeat delay (ms)" + range 0 65535 + default 0 + help + Delay before the first Heartbeat after boot/reset. + 0 = no extra delay (start HB with the normal 0x1017 period). + Typical values: 200-1000 ms to let peers install filters and avoid + false HB-consumer timeouts during bus bring-up. + +endmenu + +menu "NMT startup/control" + +config CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL + bool "Start in Operational after init (CO_NMT_STARTUP_TO_OPERATIONAL)" + default y + +config CANOPENNODE_NMT_ERR_ON_BUSOFF_HB + bool "Error on bus-off / HB timeout (CO_NMT_ERR_ON_BUSOFF_HB)" + default y + +config CANOPENNODE_NMT_ERR_ON_ERR_REG + bool "Error on nonzero masked error register (CO_NMT_ERR_ON_ERR_REG)" + default y + +config CANOPENNODE_NMT_ERR_TO_STOPPED + bool "On error -> go to Stopped (else Pre-op) (CO_NMT_ERR_TO_STOPPED)" + default n + +config CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL + bool "Auto-return to Operational when errors clear (CO_NMT_ERR_FREE_TO_OPERATIONAL)" + default n + +comment "Error register mask (low 8 bits of NMT control)" + +endmenu + +menu "Heartbeat consumer - Specified in standard CiA 301" + +config CANOPENNODE_HB_CONS_ENABLE + bool "Enable heartbeat consumer" + default n + help + Monitor heartbeat messages from other nodes and trigger actions + based on their status. + +choice CANOPENNODE_HB_CONS_CALLBACK_MODE + prompt "Heartbeat consumer callback mode" + depends on CANOPENNODE_HB_CONS_ENABLE + optional + default CANOPENNODE_HB_CONS_CALLBACK_CHANGE + help + Select how heartbeat/NMT-change callbacks are handled. + Leave unset for no callbacks. Only one option can be active. + +config CANOPENNODE_HB_CONS_CALLBACK_CHANGE + bool "Single common callback after NMT state change" + help + Enable a single common callback invoked on NMT state changes. + Configure via CO_HBconsumer_initCallbackNmtChanged(). + +config CANOPENNODE_HB_CONS_CALLBACK_MULTI + bool "Per-node callbacks" + help + Enable per-node callbacks for NMT change, heartbeat started, + timeout, and remote reset. Configure via: + CO_HBconsumer_initCallbackNmtChanged(), + CO_HBconsumer_initCallbackHeartbeatStarted(), + CO_HBconsumer_initCallbackTimeout(), + CO_HBconsumer_initCallbackRemoteReset(). + +endchoice + +config CANOPENNODE_HB_CONS_QUERY_FUNCT + bool "Enable heartbeat and NMT query functions" + depends on CANOPENNODE_HB_CONS_ENABLE + default n + +config CANOPENNODE_HB_CONS_CALLBACK + bool "Enable custom callback after heartbeat message received" + depends on CANOPENNODE_HB_CONS_ENABLE + default n + help + Enable a callback invoked after a heartbeat message is preprocessed. + Configure via CO_HBconsumer_initCallbackPre(). + +config CANOPENNODE_HB_CONS_TIMERNEXT + bool "Enable heartbeat consumer timerNext_us calculation" + depends on CANOPENNODE_HB_CONS_ENABLE + default y + +config CANOPENNODE_HB_CONS_OD_DYNAMIC + bool "Enable dynamic behaviour of heartbeat consumer OD variables" + depends on CANOPENNODE_HB_CONS_ENABLE + default y + +endmenu + +menu "CANopen Node Guarding slave and master objects - Specified in standard CiA 301" + +config CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE + bool "Enable Node guarding slave" + default n + +config CANOPENNODE_NODE_GUARDING_MASTER_ENABLE + bool "Enable Node guarding master" + default n + +config CANOPENNODE_NODE_GUARDING_MASTER_COUNT + int "Max nodes monitored by guarding master" + range 1 127 + default 127 + +config CANOPENNODE_NODE_GUARDING_TIMERNEXT + bool "Enable Node guarding timerNext_us calculation" + depends on CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE || CANOPENNODE_NODE_GUARDING_MASTER_ENABLE + default n + +endmenu + +menu "Emergency producer/consumer - Specified in standard CiA 301" + +config CANOPENNODE_EM_PRODUCER + bool "Enable emergency producer" + default n + +config CANOPENNODE_EM_PROD_CONFIGURABLE + bool "Enable configurable COB-ID for emergency producer" + default n + +config CANOPENNODE_EM_PROD_INHIBIT + bool "Enable inhibit time for emergency producer" + default n + +config CANOPENNODE_EM_HISTORY + bool "Enable emergency error history" + default y + +config CANOPENNODE_EM_CONSUMER + bool "Enable emergency consumer" + default n + +config CANOPENNODE_EM_STATUS_BITS + bool "Enable emergency status bits in Object Dictionary" + default n + +config CANOPENNODE_EM_CALLBACK + bool "Enable custom callback after emergency message received" + default y + +config CANOPENNODE_EM_TIMERNEXT + bool "Enable emergency timerNext_us calculation" + default y + +config CANOPENNODE_EM_ERR_STATUS_BITS_COUNT + int "Emergency error status bits (multiple of 8)" + range 48 256 + default 80 + +# Optional error-register conditions (enable default expressions in mapper) +config CANOPENNODE_ERR_CONDITION_CURRENT + bool "Condition for calculating Error register: CURRENT" + default n + +config CANOPENNODE_ERR_CONDITION_VOLTAGE + bool "Condition for calculating Error register: VOLTAGE" + default n + +config CANOPENNODE_ERR_CONDITION_TEMPERATURE + bool "Condition for calculating Error register: TEMPERATURE" + default n + +config CANOPENNODE_ERR_CONDITION_DEV_PROFILE + bool "Condition for calculating Error register: DEVICE PROFILE" + default n + +endmenu + +menu "SDO server - Specified in standard CiA 301" + +config CANOPENNODE_SDO_SERVER_SEGMENTED + bool "Enable segmented SDO server" + default n + +config CANOPENNODE_SDO_SERVER_BLOCK + bool "Enable block SDO server" + select CANOPENNODE_SDO_SERVER_SEGMENTED + select CANOPENNODE_CRC16_ENABLE + default n + help + Use 127-segment block transfers with optional CRC for large, efficient transfers. + +config CANOPENNODE_SDO_SERVER_CALLBACK + bool "Enable SDO server callback" + default y + +config CANOPENNODE_SDO_SERVER_TIMERNEXT + bool "Enable SDO server timerNext_us calculation" + default y + +config CANOPENNODE_SDO_SERVER_OD_DYNAMIC + bool "Enable dynamic behaviour of SDO server OD variables" + default y + +config CANOPENNODE_SDO_SERVER_BUFFER_SIZE + int "SDO server buffer size" + range 900 4096 if CANOPENNODE_SDO_SERVER_BLOCK + range 20 4096 if !CANOPENNODE_SDO_SERVER_BLOCK + default 900 if CANOPENNODE_SDO_SERVER_BLOCK + default 32 + help + Internal buffer for SDO server. + - >=20 for segmented + - >=900 recommended for block (127 x 7 bytes) + +config CANOPENNODE_SDO_SERVER_TIMEOUT_MS + int "SDO server timeout (ms)" + range 50 60000 + default 1000 + +endmenu + +menu "SDO client - Specified in standard CiA 301" + +config CANOPENNODE_SDO_CLIENT_ENABLE + bool "Enable SDO client" + select CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_SEGMENTED + bool "Enable SDO client segmented transfer" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_BLOCK + bool "Enable SDO client block transfer" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + select CANOPENNODE_SDO_CLIENT_SEGMENTED + select CANOPENNODE_FIFO_ALT_READ + select CANOPENNODE_FIFO_CRC16_CCITT + default n + +config CANOPENNODE_SDO_CLIENT_LOCAL + bool "Enable local transfer (client/server same node)" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_CALLBACK + bool "Enable SDO client callback" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default y + +config CANOPENNODE_SDO_CLIENT_TIMERNEXT + bool "Enable SDO client timerNext_us calculation" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default y + +config CANOPENNODE_SDO_CLIENT_OD_DYNAMIC + bool "Enable dynamic behaviour of SDO client OD variables" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default y + +config CANOPENNODE_SDO_CLIENT_BUFFER_SIZE + int "SDO client buffer size" + range 1000 4096 if CANOPENNODE_SDO_CLIENT_BLOCK + range 7 4096 if CANOPENNODE_SDO_CLIENT_SEGMENTED && !CANOPENNODE_SDO_CLIENT_BLOCK + default 1000 if CANOPENNODE_SDO_CLIENT_BLOCK + default 32 if !CANOPENNODE_SDO_CLIENT_BLOCK + help + Circular buffer used by SDO client. Can be <= object size since it is + processed over multiple calls. >=7 for segmented; >=1000 recommended for block. + +config CANOPENNODE_SDO_CLIENT_TIMEOUT_MS + int "SDO client timeout (ms)" + range 50 60000 + default 1000 + +endmenu + +menu "Time producer/consumer - Specified in standard CiA 301" + +config CANOPENNODE_TIME_ENABLE + bool "Enable TIME object and TIME consumer" + default n + +config CANOPENNODE_TIME_PRODUCER + bool "Enable TIME producer" + depends on CANOPENNODE_TIME_ENABLE + default n + +config CANOPENNODE_TIME_CALLBACK + bool "Enable TIME callback" + depends on CANOPENNODE_TIME_ENABLE + default y + +config CANOPENNODE_TIME_OD_DYNAMIC + bool "Enable dynamic behaviour of TIME OD variables" + depends on CANOPENNODE_TIME_ENABLE + default y + +endmenu + +menu "SYNC and PDO producer/consumer - Specified in standard CiA 301" + +config CANOPENNODE_SYNC_ENABLE + bool "Enable SYNC object and SYNC consumer" + default n + +config CANOPENNODE_SYNC_PRODUCER + bool "Enable SYNC producer" + depends on CANOPENNODE_SYNC_ENABLE + default n + +config CANOPENNODE_SYNC_CALLBACK + bool "Enable SYNC callback" + depends on CANOPENNODE_SYNC_ENABLE + default y + +config CANOPENNODE_SYNC_TIMERNEXT + bool "Enable SYNC timerNext_us calculation" + depends on CANOPENNODE_SYNC_ENABLE + default y + +config CANOPENNODE_SYNC_OD_DYNAMIC + bool "Enable dynamic behaviour of SYNC OD variables" + depends on CANOPENNODE_SYNC_ENABLE + default y + +config CANOPENNODE_RPDO_ENABLE + bool "Enable receive PDO objects (RPDOs)" + default n + +config CANOPENNODE_TPDO_ENABLE + bool "Enable transmit PDO objects (TPDOs)" + default n + +config CANOPENNODE_RPDO_TIMERS_ENABLE + bool "Enable RPDO timers" + depends on CANOPENNODE_RPDO_ENABLE + default y if CANOPENNODE_RPDO_ENABLE + default n + +config CANOPENNODE_TPDO_TIMERS_ENABLE + bool "Enable TPDO timers" + depends on CANOPENNODE_TPDO_ENABLE + default y if CANOPENNODE_TPDO_ENABLE + default n + +config CANOPENNODE_PDO_SYNC_ENABLE + bool "Enable PDO SYNC" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + select CANOPENNODE_SYNC_ENABLE + default y + help + Synchronize PDO processing with network SYNC messages. + +config CANOPENNODE_PDO_OD_IO_ACCESS + bool "Enable PDO OD IO access" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + select CANOPENNODE_PDO_OD_DYNAMIC + default y + help + Use OD IO accessors (OD_IO_t) for mapped PDO variables. + +config CANOPENNODE_PDO_CALLBACK + bool "Enable PDO callback" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default y + +config CANOPENNODE_PDO_TIMERNEXT + bool "Enable PDO timerNext_us calculation" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default y + +config CANOPENNODE_PDO_OD_DYNAMIC + bool "Enable dynamic behaviour of PDO OD variables" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default y + +endmenu + +menu "Data storage - Data storage with CANopen OD objects 1010 and 1011, CiA 301" + +config CANOPENNODE_STORAGE_ENABLE + bool "Enable data storage" + default n + help + Persist OD entries via 0x1010/0x1011. + +endmenu + +menu "Storage Backend" + depends on CANOPENNODE_STORAGE_ENABLE + +choice CANOPENNODE_STORAGE_BACKEND_CHOICE + prompt "Select CANopenNode OD storage backend" + default CANOPENNODE_STORAGE_BACKEND_RAM + +config CANOPENNODE_STORAGE_BACKEND_SETTINGS + bool "Zephyr Settings subsystem" + select SETTINGS + select CANOPENNODE_CRC16_ENABLE + help + Use Zephyr's Settings subsystem to persist OD entries. + +config CANOPENNODE_STORAGE_BACKEND_RAM + bool "RAM-only (no persistence)" + help + Store OD values in RAM only. Lost on reset. + +config CANOPENNODE_STORAGE_BACKEND_NONE + bool "None (disable OD storage)" + help + Disable OD storage completely. + +endchoice + +endmenu + +menu "Program Download - Specified in standard CiA 302-3" + +config CANOPENNODE_PROG_DOWNLOAD + bool "Enable Program Download object (CiA 302-3)" + select CANOPENNODE_CRC16_ENABLE + select FLASH_MAP + depends on FLASH + default n + help + Enables CO_Prog_Download: OD entries 0x1F21, 0x1F23, 0x1F24, 0x1F50, + 0x1F51, 0x1F56, 0x1F57. Streams data via registered backend and can + optionally bind to CO_storage for persistence. + +config CANOPENNODE_PROG_DOWNLOAD_EDS_MAX_SIZE + int "Maximum EDS file size (bytes)" + depends on CANOPENNODE_PROG_DOWNLOAD + default 2048 + range 256 1048576 + help + Upper limit for OD 0x1F23 (“Store EDS NMT slave”) data length. + If the received EDS exceeds this size, the transfer should be + rejected/aborted. Keep this reasonably small to avoid large + RAM allocations during transfer on constrained targets. + +config CANOPENNODE_PROG_DOWNLOAD_PERMANENT + bool "Program commit is permanent upgrade" + default y + help + If enabled, COMMIT (0x1F51 command) will request a permanent + upgrade of the programmed image. + If disabled, COMMIT will request a test upgrade instead, + requiring a later confirmation to keep the image. + +endmenu + +menu "CANopen LED Indicators - Specified in standard CiA 303-3" + +config CANOPENNODE_LEDS_ENABLE + bool "Enable calculation of the CANopen LED indicators" + default n + +config CANOPENNODE_LEDS_CALLBACK + bool "Enable custom callback after LED state changes" + default y if CANOPENNODE_LEDS_ENABLE + default n if !CANOPENNODE_LEDS_ENABLE + +config CANOPENNODE_LEDS_TIMERNEXT + bool "Enable calculation of timerNext_us for LED indicators" + default y if CANOPENNODE_LEDS_ENABLE + default n if !CANOPENNODE_LEDS_ENABLE + +endmenu + +menu "Safety Related Data Objects (SRDO) - Specified in standard EN 50325-5 (CiA 304)" + +config CANOPENNODE_GFC_ENABLE + bool "Enable GFC (Guarding Function Control)" + default n + +config CANOPENNODE_GFC_CONSUMER + bool "Enable GFC consumer" + depends on CANOPENNODE_GFC_ENABLE + default n + +config CANOPENNODE_GFC_PRODUCER + bool "Enable GFC producer" + depends on CANOPENNODE_GFC_ENABLE + default n + +config CANOPENNODE_SRDO_ENABLE + bool "Enable SRDO (Safety Related Data Objects)" + default n + +config CANOPENNODE_SRDO_CHECK_TX + bool "Enable SRDO TX data check" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_CALLBACK + bool "Enable SRDO callback" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_TIMERNEXT + bool "Enable SRDO timerNext_us calculation" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_MINIMUM_DELAY + int "Minimum time between the first and second SRDO (Tx) message (us)" + range 0 1000000 + default 0 + +endmenu + +menu "LSS master/slave - Specified in standard CiA 305" + +config CANOPENNODE_LSS_SLAVE + bool "Enable LSS slave" + default n + +config CANOPENNODE_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND + bool "Enable fast-scan direct response" + depends on CANOPENNODE_LSS_SLAVE + default n + +config CANOPENNODE_LSS_MASTER + bool "Enable LSS master" + default n + +config CANOPENNODE_LSS_CALLBACK + bool "Enable LSS callback" + default n + +endmenu + +menu "Gateways - Specified in standard CiA 309" + +config CANOPENNODE_GTW_MULTI_NET + bool "Enable multiple network interfaces in gateway device" + depends on 0 + default n + +config CANOPENNODE_GTW_ASCII + bool "Enable gateway device with ASCII mapping" + select CANOPENNODE_FIFO_ENABLE + select CANOPENNODE_FIFO_ASCII_COMMANDS + default n + +config CANOPENNODE_GTW_ASCII_SDO + bool "Enable SDO client in gateway-ascii" + depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_SDO_CLIENT_ENABLE + select CANOPENNODE_FIFO_ASCII_DATATYPES + default n + +config CANOPENNODE_GTW_ASCII_NMT + bool "Enable NMT master in gateway-ascii" + depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_NMT_MASTER + default n + +config CANOPENNODE_GTW_ASCII_LSS + bool "Enable LSS master in gateway-ascii" + depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_LSS_MASTER + default n + +config CANOPENNODE_GTW_ASCII_LOG + bool "Enable non-standard message log read" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_ERROR_DESC + bool "Print error descriptions as comments in gateway-ascii" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_PRINT_HELP + bool "Enable non-standard \"help\" command" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_PRINT_LEDS + bool "Display CANopen status LEDs on terminal" + depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_LEDS_ENABLE + default n + +config CANOPENNODE_GTW_BLOCK_DL_LOOP + int "Number of process loops in case of block download" + range 1 127 + default 1 + help + Additional local loop iterations while a block download is in progress + to speed up transfer (up to 127). + +config CANOPENNODE_GTWA_COMM_BUF_SIZE + int "Size of command buffer in ASCII gateway object" + range 16 4096 + default 200 + help + Increase to >=1000 when doing large block transfers. + +config CANOPENNODE_GTWA_LOG_BUF_SIZE + int "Gateway: log buffer size" + range 128 4096 + default 2000 + +endmenu + +menu "CRC 16 calculation" + +config CANOPENNODE_CRC16_ENABLE + bool "Enable CRC16 calculation" + default n + +config CANOPENNODE_CRC16_EXTERNAL + bool "CRC functions are defined externally" + depends on CANOPENNODE_CRC16_ENABLE + select CRC + default y if CANOPENNODE_CRC16_ENABLE + help + If enabled, the application must provide: + void crc16_ccitt_single(uint16_t *crc, uint8_t chr); + uint16_t crc16_ccitt(const uint8_t block[], size_t len, uint16_t crc); + If disabled, the internal CRC16 functions will be used. + +endmenu + +menu "FIFO buffer" + +config CANOPENNODE_FIFO_ENABLE + bool "Enable FIFO buffer" + default n + +config CANOPENNODE_FIFO_ALT_READ + bool "FIFO alternate read (needed by SDO client block)" + depends on CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_FIFO_CRC16_CCITT + bool "FIFO CRC16-CCITT (needed by SDO client block)" + depends on CANOPENNODE_FIFO_ENABLE + select CANOPENNODE_CRC16_ENABLE + default n + +config CANOPENNODE_FIFO_ASCII_COMMANDS + bool "FIFO ASCII command helpers" + depends on CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_FIFO_ASCII_DATATYPES + bool "FIFO ASCII datatype helpers" + depends on CANOPENNODE_FIFO_ENABLE && CANOPENNODE_FIFO_ASCII_COMMANDS + default n + help + Helpers to read/write integers/floats/strings in ASCII. + +endmenu + +menu "Trace recorder" + +config CANOPENNODE_TRACE_ENABLE + bool "Enable Trace recorder" + default n + +config CANOPENNODE_TRACE_OWN_INTTYPES + bool "Provide custom PRIu32/PRId32 macros (no )" + depends on CANOPENNODE_TRACE_ENABLE + default n + +endmenu + +menu "Debug messages" + +config CANOPENNODE_DEBUG_COMMON + bool "Define default CO_DEBUG_COMMON(msg) macro" + default n + +config CANOPENNODE_DEBUG_SDO_CLIENT + bool "Define default CO_DEBUG_SDO_CLIENT(msg) macro" + select CANOPENNODE_DEBUG_COMMON + default n + +config CANOPENNODE_DEBUG_SDO_SERVER + bool "Define default CO_DEBUG_SDO_SERVER(msg) macro" + select CANOPENNODE_DEBUG_COMMON + default n + +endmenu + +menu "Object Dictionary (EDS)" + +config CANOPENNODE_EDS_FILE_PATH + string "EDS file (path relative to application root)" + default "" + help + Path to the EDS used to generate OD.c/OD.h. + Leave empty to use: + example/DS301_profile.eds + +endmenu + +menu "CANopenNode TX Workqueue Options" + +config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE + int "TX workqueue stack size" + default 1024 + range 256 16384 + help + Stack size (in bytes) for the CANopenNode TX workqueue thread. + +config CANOPENNODE_TX_WORKQUEUE_PRIORITY + int "TX workqueue priority" + default 0 + help + Thread priority for the CANopenNode TX workqueue. + Lower numbers mean higher priority. + +endmenu + +menu "CANopenNode Thread Options" + +config CANOPENNODE_RT_THREAD + bool "Use real-time thread for CANopen processing" + default y + help + If enabled, a dedicated real-time thread will be created for CANopen + processing. Otherwise, the application must call CO_process() periodically. + +config CANOPENNODE_RT_THREAD_STACK_SIZE + int "Real-time thread stack size" + default 1024 + help + Stack size (bytes) for the CANopenNode real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. + Increase if you use many PDOs, SDOs, or large OD entries. + Decrease if you have memory constraints and use few CANopen features. + Typical values: 1024-4096 bytes. + Measure actual stack usage to optimize. + +config CANOPENNODE_RT_THREAD_PRIORITY + int "Real-time thread priority" + default -1 + help + Thread priority for the CANopenNode real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. + Lower numbers mean higher priority. + Typical values: -1 to -3 for real-time processing. + +config CANOPENNODE_RT_THREAD_IDLE_MS + int "Real-time thread idle time (ms)" + default 10 + help + Time (ms) the CANopenNode real-time thread sleeps when idle. + Only used if CANOPENNODE_RT_THREAD is enabled. + Lower values mean more CPU usage but lower latency. + Typical values: 1-100 ms. + +config CANOPENNODE_RT_THREAD_TIMERNEXT + bool "Enable timerNext_us calculation in real-time thread" + default y + help + If enabled, timerNext_us will be calculated in the real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. + Disable to save CPU if you don't use features that need timerNext_us. + +config CANOPENNODE_RT_THREAD_AUTO_START + bool "Auto-start CANopenNode real-time thread" + default y + help + If enabled, the CANopenNode real-time thread will be started automatically + at POST_KERNEL. Otherwise, you must call CO_RT_threadStart() manually. +endmenu + +menu "CANopenNode Initialization" + +config CANOPENNODE_INIT_PRIORITY + int "CANopenNode initialization priority" + default 90 + help + Priority for CANopenNode initialization. + Lower numbers mean earlier initialization. + Typical values: 80-100. + Must be lower than the application's main thread priority. + +config CANOPENNODE_INIT_NODE_ID + int "CANopenNode node ID" + default 1 + range 0 127 + help + Node ID for the CANopenNode instance. + Must be unique on the CAN bus. + +endmenu + +module = CANOPEN +module-str = canopen +source "subsys/logging/Kconfig.template.log_config" + +endif # CANOPENNODE From b2b20e12e7f3444100ef9c7cf6f405e4262986c8 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Fri, 3 Apr 2026 11:33:12 -0400 Subject: [PATCH 520/520] Normalize line endings to LF for all Zephyr files Co-Authored-By: Oz --- zephyr/CO_zephyr_integration.c | 938 ++++++++--------- zephyr/Kconfig | 1754 ++++++++++++++++---------------- 2 files changed, 1346 insertions(+), 1346 deletions(-) diff --git a/zephyr/CO_zephyr_integration.c b/zephyr/CO_zephyr_integration.c index 0f313881..601ca0f1 100644 --- a/zephyr/CO_zephyr_integration.c +++ b/zephyr/CO_zephyr_integration.c @@ -1,469 +1,469 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * Zephyr-to-CANopenNode integration runtime. - * - * Provides a runtime bridge to start/stop the CANopen stack with a selected - * Zephyr CAN device, Node-ID, and bitrate, enabling control from code in - * addition to prj.conf and devicetree. - * - * @file CO_zephyr_integration.c - * @author BitConcepts, LLC - * @copyright 2025 BitConcepts, LLC - * - * This file is part of , a CANopen Stack. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -#include "CO_zephyr_integration.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "OD.h" - -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) -#include "CO_zephyr_storage.h" -#endif - -#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) -#include "CO_zephyr_prog_download.h" -#endif - -LOG_MODULE_REGISTER(canopen_zephyr, CONFIG_CANOPEN_LOG_LEVEL); - -#define CAN_NODE DT_CHOSEN(zephyr_canbus) -#define CAN_BITRATE_KBPS (DT_PROP(CAN_NODE, bitrate) / 1000U) - -#define DEV_TO_CANPTR(d) ((void *)(uintptr_t)(d)) -#define CANPTR_TO_DEV(p) ((const struct device *)(p)) - -/* ---------- Module state ---------- - * CO / CO_storage are the runtime stack handles. - * g_running is an atomic "stack is active" flag used by the RT thread and signalers. - * rt_sem wakes the RT thread from pre-callbacks and periodic processing. - */ -CO_t *CO = NULL; -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) -static CO_storage_t CO_storage; -#endif -atomic_t g_running; -static const struct device *g_last_can_dev = NULL; -static uint8_t g_last_node_id = 0; -static uint16_t g_last_bitrate_kbps = 0; - -#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) -static CO_ProgDL_t pdl; -static CO_ProgDL_Zephyr_t zb_ctx; -#endif - -K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ - -/* ---------- Helpers ---------- */ - -#ifdef CO_DEBUG_COMMON -void z_canopen_log(const char *msg) -{ - LOG_DBG("%s", msg); -} -#endif - -static void z_canopen_nmt_state_cb(CO_NMT_internalState_t state) -{ - const char *state_str = "UNKNOWN"; - switch (state) { - case CO_NMT_INITIALIZING: - state_str = "INITIALIZING"; - break; - case CO_NMT_PRE_OPERATIONAL: - state_str = "PRE-OPERATIONAL"; - break; - case CO_NMT_OPERATIONAL: - state_str = "OPERATIONAL"; - break; - case CO_NMT_STOPPED: - state_str = "STOPPED"; - break; - default: - break; - } - LOG_INF("NMT state changed to %s", state_str); -} - -/* - * Pre-callback used by SYNC/RPDO to poke the RT thread. - * Gives the semaphore only when the stack is marked running. - */ -static void z_rt_signal_cb(void *object) -{ - ARG_UNUSED(object); - if (atomic_get(&g_running)) { - k_sem_give(&rt_sem); - } -} - -/* - * Register a common pre-callback for SYNC and all RPDOs. - * This lets incoming traffic promptly wake the RT thread. - */ -static void z_enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) -{ -#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_SYNC_CALLBACK) - CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); -#endif -#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_RPDO_CALLBACK) - for (uint16_t i = 0; i < OD_CNT_RPDO; i++) { - CO_RPDO_initCallbackPre(&co->RPDO[i], pre_cb, arg); - } -#endif -} - -/* ---------- RT Thread: SYNC/RPDO/TPDO ---------- */ -#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD) - -__weak uint8_t canopen_get_node_id(); - -/* - * Function used to restart CANopen stack with last known parameters. - */ -static int z_canopen_restart(void) -{ - const struct device *can_dev = g_last_can_dev ? g_last_can_dev : DEVICE_DT_GET(CAN_NODE); - uint8_t node_id = g_last_node_id ? g_last_node_id : (uint8_t)canopen_get_node_id(); - uint16_t bitrate = g_last_bitrate_kbps ? g_last_bitrate_kbps : CAN_BITRATE_KBPS; - - if (atomic_get(&g_running)) { - canopen_stop(); - /* small settle time for CAN driver/filters */ - k_sleep(K_MSEC(10)); - } - return canopen_start(can_dev, node_id, bitrate); -} - -/* - * Real-time CANopen processing thread. - * - * Responsibilities: - * - Waits on a semaphore or timeout. - * - Calls CO_process() (mainline timing and housekeeping). - * - Runs SYNC/RPDO/TPDO processing in a tight, low-latency section. - * - * Timing: - * - Uses uptime (ms) for CO_process() dt. - * - Uses CPU cycle delta for RT section dt to improve precision. - * - * Concurrency: - * - OD access is protected with CO_LOCK_OD()/CO_UNLOCK_OD(). - * - Thread runs continuously but only acts when the stack is running. - */ -static void z_canopen_rt_thread(void *p1, void *p2, void *p3) -{ - ARG_UNUSED(p1); - ARG_UNUSED(p2); - ARG_UNUSED(p3); - - int64_t last_ms = 0; - uint32_t prev_cyc = k_cycle_get_32(); - const uint32_t fallback_us = 1000U; - uint32_t timeout_us = fallback_us; - - while (true) { - k_sem_take(&rt_sem, K_USEC(timeout_us)); - - if (!atomic_get(&g_running) || CO == NULL) { - continue; - } - - /* Mainline: CO_process() */ - CO_NMT_reset_cmd_t reset = CO_RESET_NOT; - int64_t now_ms = k_uptime_get(); - uint32_t dt_us = - (last_ms == 0) ? fallback_us : (uint32_t)MAX(now_ms - last_ms, 0) * 1000U; - last_ms = now_ms; - -#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) - uint32_t next_main_us = UINT32_MAX; - reset = CO_process(CO, false, dt_us, &next_main_us); -#else - reset = CO_process(CO, false, dt_us, NULL); -#endif - /* RT part: SYNC, RPDO, TPDO */ - uint32_t now_cyc = k_cycle_get_32(); - uint32_t delta_cyc = now_cyc - prev_cyc; - prev_cyc = now_cyc; - - uint32_t dt_rt_us = (uint32_t)(k_cyc_to_ns_floor64(delta_cyc) / 1000U); - - CO_LOCK_OD(); - - uint32_t next_sync_us = UINT32_MAX; - uint32_t next_rpdo_us = UINT32_MAX; - uint32_t next_tpdo_us = UINT32_MAX; - -#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) - bool_t sync = CO_process_SYNC(CO, dt_rt_us, &next_sync_us); -#else - bool_t sync = false; -#endif -#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) - CO_process_RPDO(CO, sync, dt_rt_us, &next_rpdo_us); -#endif -#if IS_ENABLED(CONFIG_CANOPENNODE_TPDO_ENABLE) - CO_process_TPDO(CO, sync, dt_rt_us, &next_tpdo_us); -#endif - - CO_UNLOCK_OD(); - - /* Compute next wakeup based on returned timers */ - uint32_t next_rt_us = MIN(next_sync_us, MIN(next_rpdo_us, next_tpdo_us)); - -#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) - uint32_t next_all = MIN(next_rt_us, next_main_us); - timeout_us = (next_all == 0U || next_all == UINT32_MAX) ? fallback_us : next_all; -#else - timeout_us = fallback_us; -#endif - if (reset == CO_RESET_NOT) { - /* No action */ - continue; - } else if (reset == CO_RESET_COMM) { - /* Reset CANopen stack */ - LOG_INF("Restarting CANopen stack"); - z_canopen_restart(); - } else if (reset == CO_RESET_APP) { - /* Stop CANopen stack and reboot device */ - LOG_INF("Rebooting device"); - canopen_stop(); - k_sleep(K_MSEC(100)); - sys_reboot(SYS_REBOOT_COLD); - } else if (reset == CO_RESET_QUIT) { - /* Stop CANopen stack and exit thread */ - LOG_INF("Stopping CANopen stack"); - canopen_stop(); - break; - } else { - LOG_WRN("Unexpected reset code: %d", reset); - } - } -} - -/* Spawn the real-time processing thread at boot; priority/stack are Kconfig-driven. */ -K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, z_canopen_rt_thread, NULL, - NULL, NULL, CONFIG_CANOPENNODE_RT_THREAD_PRIORITY, 0, 0); - -#endif /* IS_ENABLED(CANOPENNODE_RT_THREAD) */ - -/* ---------- Public API ---------- */ - -int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) -{ - if (atomic_get(&g_running)) { - return -EALREADY; - } - if (!can_dev) { - can_dev = DEVICE_DT_GET(CAN_NODE); - } - if (!can_dev || !device_is_ready(can_dev)) { - return -ENODEV; - } - - if (node_id == 0 || node_id > 127) { - return -EINVAL; - } - - if (bitrate_kbps == 0) { - bitrate_kbps = CAN_BITRATE_KBPS; - } - - if (CO != NULL) { - CO_delete(CO); - CO = NULL; - } - - uint32_t heap_used = 0; - CO = CO_new(NULL, &heap_used); - if (CO == NULL) { - LOG_ERR("Memory allocation failed"); - return -ENOMEM; - } - LOG_INF("Allocated %u bytes for CANopen", heap_used); - - int ret = 0; - CO_ReturnError_t err; - uint32_t errInfo = 0; - -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) - CO_storage_entry_t storageEntries[] = {{ - .addr = &OD_PERSIST_COMM, - .len = sizeof(OD_PERSIST_COMM), - .subIndexOD = 2, - .attr = CO_storage_cmd | CO_storage_restore, - }}; - uint8_t entryCount = ARRAY_SIZE(storageEntries); - uint32_t storageErr = 0; - - err = co_zephyr_storage_init(&CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameterField, - OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, - entryCount, &storageErr); - - if (err != CO_ERROR_NO) { - LOG_ERR("Storage init failed: %d", err); - ret = -ENOMEM; - goto error; - } - if (storageErr != 0) { - LOG_ERR("Storage error: 0x%X", storageErr); - ret = -EIO; - goto error; - } -#endif - - err = CO_CANinit(CO, DEV_TO_CANPTR(can_dev), bitrate_kbps); - if (err != CO_ERROR_NO) { - LOG_ERR("CAN init failed: %d", err); - ret = -EINVAL; - goto error; - } - -#if IS_ENABLED(CONFIG_CANOPENNODE_LSS_SLAVE) - CO_LSS_address_t lssAddr = { - .identity = {.vendorID = OD_ROM.x1018_identity.vendor_ID, - .productCode = OD_ROM.x1018_identity.productCode, - .revisionNumber = OD_ROM.x1018_identity.revisionNumber, - .serialNumber = OD_ROM.x1018_identity.serialNumber}}; - err = CO_LSSinit(CO, &lssAddr, &node_id, &bitrate_kbps); - if (err != CO_ERROR_NO) { - LOG_ERR("LSS init failed: %d", err); - ret = -EINVAL; - goto error; - } -#endif - - err = CO_CANopenInit(CO, NULL, NULL, OD, NULL, CO_CONFIG_NMT_CONTROL, - CO_NMT_FIRST_HB_TIME_MS, CO_CONFIG_SDO_SRV_TIMEOUT_MS, - CO_CONFIG_SDO_CLI_TIMEOUT_MS, CO_CONFIG_SDO_CLI_BLOCK, node_id, - &errInfo); - - if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - LOG_ERR("CANopen init failed: %d (OD entry 0x%X)", err, errInfo); - ret = -EIO; - goto error; - } - - err = CO_CANopenInitPDO(CO, CO->em, OD, node_id, &errInfo); - if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { - LOG_ERR("PDO init failed: %d (OD entry 0x%X)", err, errInfo); - ret = -EIO; - goto error; - } - -#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) - { - /* If your binder takes a partition ID and optional CO_storage handle: */ - err = CO_Prog_Download_zephyr_bind_default(&pdl, &zb_ctx); - if (err != CO_ERROR_NO) { - LOG_ERR("Program Download bind failed: %d", err); - ret = -EINVAL; - goto error; - } - } -#endif - - if (!CO->nodeIdUnconfigured) { -#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) - if (storageErr != 0) { - CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, - storageErr); - } -#endif - } else { - LOG_INF("Node-ID not configured (LSS active)"); - } - -#if IS_ENABLED(CONFIG_CANOPENNODE_NMT_CALLBACK) - CO_NMT_initCallbackChanged(CO->NMT, z_canopen_nmt_state_cb); -#endif - - z_enable_pre_signals(CO, z_rt_signal_cb, NULL); - atomic_set(&g_running, 1); - CO_CANsetNormalMode(CO->CANmodule); - - /* Save previous values */ - g_last_can_dev = can_dev; - g_last_node_id = node_id; - g_last_bitrate_kbps = bitrate_kbps; - - LOG_INF("CANopenNode running"); - return 0; - -error: - if (CO) { - CO_delete(CO); - CO = NULL; - } - return ret; -} - -void canopen_stop(void) -{ - if (!atomic_get(&g_running)) { - return; - } - - atomic_clear(&g_running); - - if (CO != NULL) { - CO_CANmodule_disable(CO->CANmodule); - CO_delete(CO); - CO = NULL; - LOG_INF("CANopenNode stopped"); - } -} - -void canopen_error_report(uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) -{ - if (CO && CO->em) { - CO_errorReport(CO->em, errorBit, errorCode, infoCode); - } -} - -void canopen_error_reset(uint8_t errorBit, uint32_t infoCode) -{ - if (CO && CO->em) { - CO_errorReset(CO->em, errorBit, infoCode); - } -} - -__weak uint8_t canopen_get_node_id() -{ - return CONFIG_CANOPENNODE_INIT_NODE_ID; -} - -/* - * System init hook. - * Optionally auto-starts CANopen at POST_KERNEL if configured via Kconfig. - */ -static int z_co_init_sys(void) -{ -#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) - (void)canopen_start(NULL, canopen_get_node_id(), CAN_BITRATE_KBPS); -#endif - - return 0; -} -SYS_INIT(z_co_init_sys, POST_KERNEL, CONFIG_CANOPENNODE_INIT_PRIORITY); +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Zephyr-to-CANopenNode integration runtime. + * + * Provides a runtime bridge to start/stop the CANopen stack with a selected + * Zephyr CAN device, Node-ID, and bitrate, enabling control from code in + * addition to prj.conf and devicetree. + * + * @file CO_zephyr_integration.c + * @author BitConcepts, LLC + * @copyright 2025 BitConcepts, LLC + * + * This file is part of , a CANopen Stack. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +#include "CO_zephyr_integration.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "OD.h" + +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) +#include "CO_zephyr_storage.h" +#endif + +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) +#include "CO_zephyr_prog_download.h" +#endif + +LOG_MODULE_REGISTER(canopen_zephyr, CONFIG_CANOPEN_LOG_LEVEL); + +#define CAN_NODE DT_CHOSEN(zephyr_canbus) +#define CAN_BITRATE_KBPS (DT_PROP(CAN_NODE, bitrate) / 1000U) + +#define DEV_TO_CANPTR(d) ((void *)(uintptr_t)(d)) +#define CANPTR_TO_DEV(p) ((const struct device *)(p)) + +/* ---------- Module state ---------- + * CO / CO_storage are the runtime stack handles. + * g_running is an atomic "stack is active" flag used by the RT thread and signalers. + * rt_sem wakes the RT thread from pre-callbacks and periodic processing. + */ +CO_t *CO = NULL; +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) +static CO_storage_t CO_storage; +#endif +atomic_t g_running; +static const struct device *g_last_can_dev = NULL; +static uint8_t g_last_node_id = 0; +static uint16_t g_last_bitrate_kbps = 0; + +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) +static CO_ProgDL_t pdl; +static CO_ProgDL_Zephyr_t zb_ctx; +#endif + +K_SEM_DEFINE(rt_sem, 0, UINT_MAX); /* RT thread wake signal */ + +/* ---------- Helpers ---------- */ + +#ifdef CO_DEBUG_COMMON +void z_canopen_log(const char *msg) +{ + LOG_DBG("%s", msg); +} +#endif + +static void z_canopen_nmt_state_cb(CO_NMT_internalState_t state) +{ + const char *state_str = "UNKNOWN"; + switch (state) { + case CO_NMT_INITIALIZING: + state_str = "INITIALIZING"; + break; + case CO_NMT_PRE_OPERATIONAL: + state_str = "PRE-OPERATIONAL"; + break; + case CO_NMT_OPERATIONAL: + state_str = "OPERATIONAL"; + break; + case CO_NMT_STOPPED: + state_str = "STOPPED"; + break; + default: + break; + } + LOG_INF("NMT state changed to %s", state_str); +} + +/* + * Pre-callback used by SYNC/RPDO to poke the RT thread. + * Gives the semaphore only when the stack is marked running. + */ +static void z_rt_signal_cb(void *object) +{ + ARG_UNUSED(object); + if (atomic_get(&g_running)) { + k_sem_give(&rt_sem); + } +} + +/* + * Register a common pre-callback for SYNC and all RPDOs. + * This lets incoming traffic promptly wake the RT thread. + */ +static void z_enable_pre_signals(CO_t *co, void (*pre_cb)(void *), void *arg) +{ +#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_SYNC_CALLBACK) + CO_SYNC_initCallbackPre(co->SYNC, pre_cb, arg); +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) && IS_ENABLED(CONFIG_CANOPENNODE_RPDO_CALLBACK) + for (uint16_t i = 0; i < OD_CNT_RPDO; i++) { + CO_RPDO_initCallbackPre(&co->RPDO[i], pre_cb, arg); + } +#endif +} + +/* ---------- RT Thread: SYNC/RPDO/TPDO ---------- */ +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD) + +__weak uint8_t canopen_get_node_id(); + +/* + * Function used to restart CANopen stack with last known parameters. + */ +static int z_canopen_restart(void) +{ + const struct device *can_dev = g_last_can_dev ? g_last_can_dev : DEVICE_DT_GET(CAN_NODE); + uint8_t node_id = g_last_node_id ? g_last_node_id : (uint8_t)canopen_get_node_id(); + uint16_t bitrate = g_last_bitrate_kbps ? g_last_bitrate_kbps : CAN_BITRATE_KBPS; + + if (atomic_get(&g_running)) { + canopen_stop(); + /* small settle time for CAN driver/filters */ + k_sleep(K_MSEC(10)); + } + return canopen_start(can_dev, node_id, bitrate); +} + +/* + * Real-time CANopen processing thread. + * + * Responsibilities: + * - Waits on a semaphore or timeout. + * - Calls CO_process() (mainline timing and housekeeping). + * - Runs SYNC/RPDO/TPDO processing in a tight, low-latency section. + * + * Timing: + * - Uses uptime (ms) for CO_process() dt. + * - Uses CPU cycle delta for RT section dt to improve precision. + * + * Concurrency: + * - OD access is protected with CO_LOCK_OD()/CO_UNLOCK_OD(). + * - Thread runs continuously but only acts when the stack is running. + */ +static void z_canopen_rt_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + int64_t last_ms = 0; + uint32_t prev_cyc = k_cycle_get_32(); + const uint32_t fallback_us = 1000U; + uint32_t timeout_us = fallback_us; + + while (true) { + k_sem_take(&rt_sem, K_USEC(timeout_us)); + + if (!atomic_get(&g_running) || CO == NULL) { + continue; + } + + /* Mainline: CO_process() */ + CO_NMT_reset_cmd_t reset = CO_RESET_NOT; + int64_t now_ms = k_uptime_get(); + uint32_t dt_us = + (last_ms == 0) ? fallback_us : (uint32_t)MAX(now_ms - last_ms, 0) * 1000U; + last_ms = now_ms; + +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) + uint32_t next_main_us = UINT32_MAX; + reset = CO_process(CO, false, dt_us, &next_main_us); +#else + reset = CO_process(CO, false, dt_us, NULL); +#endif + /* RT part: SYNC, RPDO, TPDO */ + uint32_t now_cyc = k_cycle_get_32(); + uint32_t delta_cyc = now_cyc - prev_cyc; + prev_cyc = now_cyc; + + uint32_t dt_rt_us = (uint32_t)(k_cyc_to_ns_floor64(delta_cyc) / 1000U); + + CO_LOCK_OD(); + + uint32_t next_sync_us = UINT32_MAX; + uint32_t next_rpdo_us = UINT32_MAX; + uint32_t next_tpdo_us = UINT32_MAX; + +#if IS_ENABLED(CONFIG_CANOPENNODE_SYNC_ENABLE) + bool_t sync = CO_process_SYNC(CO, dt_rt_us, &next_sync_us); +#else + bool_t sync = false; +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_RPDO_ENABLE) + CO_process_RPDO(CO, sync, dt_rt_us, &next_rpdo_us); +#endif +#if IS_ENABLED(CONFIG_CANOPENNODE_TPDO_ENABLE) + CO_process_TPDO(CO, sync, dt_rt_us, &next_tpdo_us); +#endif + + CO_UNLOCK_OD(); + + /* Compute next wakeup based on returned timers */ + uint32_t next_rt_us = MIN(next_sync_us, MIN(next_rpdo_us, next_tpdo_us)); + +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_TIMERNEXT) + uint32_t next_all = MIN(next_rt_us, next_main_us); + timeout_us = (next_all == 0U || next_all == UINT32_MAX) ? fallback_us : next_all; +#else + timeout_us = fallback_us; +#endif + if (reset == CO_RESET_NOT) { + /* No action */ + continue; + } else if (reset == CO_RESET_COMM) { + /* Reset CANopen stack */ + LOG_INF("Restarting CANopen stack"); + z_canopen_restart(); + } else if (reset == CO_RESET_APP) { + /* Stop CANopen stack and reboot device */ + LOG_INF("Rebooting device"); + canopen_stop(); + k_sleep(K_MSEC(100)); + sys_reboot(SYS_REBOOT_COLD); + } else if (reset == CO_RESET_QUIT) { + /* Stop CANopen stack and exit thread */ + LOG_INF("Stopping CANopen stack"); + canopen_stop(); + break; + } else { + LOG_WRN("Unexpected reset code: %d", reset); + } + } +} + +/* Spawn the real-time processing thread at boot; priority/stack are Kconfig-driven. */ +K_THREAD_DEFINE(canopen_rt, CONFIG_CANOPENNODE_RT_THREAD_STACK_SIZE, z_canopen_rt_thread, NULL, + NULL, NULL, CONFIG_CANOPENNODE_RT_THREAD_PRIORITY, 0, 0); + +#endif /* IS_ENABLED(CANOPENNODE_RT_THREAD) */ + +/* ---------- Public API ---------- */ + +int canopen_start(const struct device *can_dev, uint8_t node_id, uint16_t bitrate_kbps) +{ + if (atomic_get(&g_running)) { + return -EALREADY; + } + if (!can_dev) { + can_dev = DEVICE_DT_GET(CAN_NODE); + } + if (!can_dev || !device_is_ready(can_dev)) { + return -ENODEV; + } + + if (node_id == 0 || node_id > 127) { + return -EINVAL; + } + + if (bitrate_kbps == 0) { + bitrate_kbps = CAN_BITRATE_KBPS; + } + + if (CO != NULL) { + CO_delete(CO); + CO = NULL; + } + + uint32_t heap_used = 0; + CO = CO_new(NULL, &heap_used); + if (CO == NULL) { + LOG_ERR("Memory allocation failed"); + return -ENOMEM; + } + LOG_INF("Allocated %u bytes for CANopen", heap_used); + + int ret = 0; + CO_ReturnError_t err; + uint32_t errInfo = 0; + +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) + CO_storage_entry_t storageEntries[] = {{ + .addr = &OD_PERSIST_COMM, + .len = sizeof(OD_PERSIST_COMM), + .subIndexOD = 2, + .attr = CO_storage_cmd | CO_storage_restore, + }}; + uint8_t entryCount = ARRAY_SIZE(storageEntries); + uint32_t storageErr = 0; + + err = co_zephyr_storage_init(&CO_storage, CO->CANmodule, OD_ENTRY_H1010_storeParameterField, + OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, + entryCount, &storageErr); + + if (err != CO_ERROR_NO) { + LOG_ERR("Storage init failed: %d", err); + ret = -ENOMEM; + goto error; + } + if (storageErr != 0) { + LOG_ERR("Storage error: 0x%X", storageErr); + ret = -EIO; + goto error; + } +#endif + + err = CO_CANinit(CO, DEV_TO_CANPTR(can_dev), bitrate_kbps); + if (err != CO_ERROR_NO) { + LOG_ERR("CAN init failed: %d", err); + ret = -EINVAL; + goto error; + } + +#if IS_ENABLED(CONFIG_CANOPENNODE_LSS_SLAVE) + CO_LSS_address_t lssAddr = { + .identity = {.vendorID = OD_ROM.x1018_identity.vendor_ID, + .productCode = OD_ROM.x1018_identity.productCode, + .revisionNumber = OD_ROM.x1018_identity.revisionNumber, + .serialNumber = OD_ROM.x1018_identity.serialNumber}}; + err = CO_LSSinit(CO, &lssAddr, &node_id, &bitrate_kbps); + if (err != CO_ERROR_NO) { + LOG_ERR("LSS init failed: %d", err); + ret = -EINVAL; + goto error; + } +#endif + + err = CO_CANopenInit(CO, NULL, NULL, OD, NULL, CO_CONFIG_NMT_CONTROL, + CO_NMT_FIRST_HB_TIME_MS, CO_CONFIG_SDO_SRV_TIMEOUT_MS, + CO_CONFIG_SDO_CLI_TIMEOUT_MS, CO_CONFIG_SDO_CLI_BLOCK, node_id, + &errInfo); + + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + LOG_ERR("CANopen init failed: %d (OD entry 0x%X)", err, errInfo); + ret = -EIO; + goto error; + } + + err = CO_CANopenInitPDO(CO, CO->em, OD, node_id, &errInfo); + if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { + LOG_ERR("PDO init failed: %d (OD entry 0x%X)", err, errInfo); + ret = -EIO; + goto error; + } + +#if IS_ENABLED(CONFIG_CANOPENNODE_PROG_DOWNLOAD) + { + /* If your binder takes a partition ID and optional CO_storage handle: */ + err = CO_Prog_Download_zephyr_bind_default(&pdl, &zb_ctx); + if (err != CO_ERROR_NO) { + LOG_ERR("Program Download bind failed: %d", err); + ret = -EINVAL; + goto error; + } + } +#endif + + if (!CO->nodeIdUnconfigured) { +#if IS_ENABLED(CONFIG_CANOPENNODE_STORAGE_ENABLE) + if (storageErr != 0) { + CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, + storageErr); + } +#endif + } else { + LOG_INF("Node-ID not configured (LSS active)"); + } + +#if IS_ENABLED(CONFIG_CANOPENNODE_NMT_CALLBACK) + CO_NMT_initCallbackChanged(CO->NMT, z_canopen_nmt_state_cb); +#endif + + z_enable_pre_signals(CO, z_rt_signal_cb, NULL); + atomic_set(&g_running, 1); + CO_CANsetNormalMode(CO->CANmodule); + + /* Save previous values */ + g_last_can_dev = can_dev; + g_last_node_id = node_id; + g_last_bitrate_kbps = bitrate_kbps; + + LOG_INF("CANopenNode running"); + return 0; + +error: + if (CO) { + CO_delete(CO); + CO = NULL; + } + return ret; +} + +void canopen_stop(void) +{ + if (!atomic_get(&g_running)) { + return; + } + + atomic_clear(&g_running); + + if (CO != NULL) { + CO_CANmodule_disable(CO->CANmodule); + CO_delete(CO); + CO = NULL; + LOG_INF("CANopenNode stopped"); + } +} + +void canopen_error_report(uint8_t errorBit, uint16_t errorCode, uint32_t infoCode) +{ + if (CO && CO->em) { + CO_errorReport(CO->em, errorBit, errorCode, infoCode); + } +} + +void canopen_error_reset(uint8_t errorBit, uint32_t infoCode) +{ + if (CO && CO->em) { + CO_errorReset(CO->em, errorBit, infoCode); + } +} + +__weak uint8_t canopen_get_node_id() +{ + return CONFIG_CANOPENNODE_INIT_NODE_ID; +} + +/* + * System init hook. + * Optionally auto-starts CANopen at POST_KERNEL if configured via Kconfig. + */ +static int z_co_init_sys(void) +{ +#if IS_ENABLED(CONFIG_CANOPENNODE_RT_THREAD_AUTO_START) + (void)canopen_start(NULL, canopen_get_node_id(), CAN_BITRATE_KBPS); +#endif + + return 0; +} +SYS_INIT(z_co_init_sys, POST_KERNEL, CONFIG_CANOPENNODE_INIT_PRIORITY); diff --git a/zephyr/Kconfig b/zephyr/Kconfig index cb87faa7..ffae1f3d 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -1,877 +1,877 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2025 BitConcepts, LLC -# -# CANopenNode — Zephyr module Kconfig -# -# This Kconfig file exposes CANopenNode features to Zephyr as CONFIG_* options. -# It lets you enable/disable protocol modules (NMT, SDO, PDO, etc.), choose -# Zephyr-specific integrations (storage backend, LED GPIO bridge), and set -# module-level parameters (buffers, timeouts, thread options). -# -# @file Kconfig -# @author BitConcepts, LLC -# -# This file is part of , a CANopen Stack. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this -# file except in compliance with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed under the License -# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions and limitations under -# the License. -# -# Usage notes: -# - Enable top-level CONFIG_CANOPENNODE=y in prj.conf to include the stack. -# - Most options default to sensible values; adjust per application needs. -# - Some features imply others via 'select' (see help for each symbol). -# - For LED helpers (CiA 303-3), provide devicetree aliases: -# aliases { -# co_led_run = &led0; -# co_led_err = &led1; -# }; -# - For Object Dictionary generation, set CONFIG_CANOPENNODE_EDS_FILE_PATH -# to an EDS relative to your application root (see CMakeLists.txt logic). - -menuconfig CANOPENNODE - bool "CANopenNode protocol stack support" - depends on CAN - default n - help - Enable the CANopenNode stack integration for Zephyr. - -if CANOPENNODE - -menu "NMT / Heartbeat producer - Specified in standard CiA 301" - -config CANOPENNODE_NMT_CALLBACK_CHANGE - bool "Enable custom callback after NMT state changes" - default y - help - Enable a custom callback invoked after the NMT state changes. - Configure via CO_NMT_initCallbackChanged(). - -config CANOPENNODE_NMT_MASTER - bool "Enable simple NMT master" - default n - help - Enable a simple NMT master object to control other nodes' - NMT states (start/stop/reset). - -config CANOPENNODE_NMT_CALLBACK - bool "Enable custom callback after preprocessing received NMT message" - default y - help - Enable a custom callback invoked after a received NMT message - is preprocessed. Configure via CO_NMT_initCallbackPre(). - -config CANOPENNODE_NMT_TIMERNEXT - bool "Enable NMT timerNext_us calculation" - default y - help - Enable calculation of timerNext_us for NMT to schedule next processing. - -config CANOPENNODE_NMT_FIRST_HB_TIME_MS - int "First heartbeat delay (ms)" - range 0 65535 - default 0 - help - Delay before the first Heartbeat after boot/reset. - 0 = no extra delay (start HB with the normal 0x1017 period). - Typical values: 200-1000 ms to let peers install filters and avoid - false HB-consumer timeouts during bus bring-up. - -endmenu - -menu "NMT startup/control" - -config CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL - bool "Start in Operational after init (CO_NMT_STARTUP_TO_OPERATIONAL)" - default y - -config CANOPENNODE_NMT_ERR_ON_BUSOFF_HB - bool "Error on bus-off / HB timeout (CO_NMT_ERR_ON_BUSOFF_HB)" - default y - -config CANOPENNODE_NMT_ERR_ON_ERR_REG - bool "Error on nonzero masked error register (CO_NMT_ERR_ON_ERR_REG)" - default y - -config CANOPENNODE_NMT_ERR_TO_STOPPED - bool "On error -> go to Stopped (else Pre-op) (CO_NMT_ERR_TO_STOPPED)" - default n - -config CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL - bool "Auto-return to Operational when errors clear (CO_NMT_ERR_FREE_TO_OPERATIONAL)" - default n - -comment "Error register mask (low 8 bits of NMT control)" - -endmenu - -menu "Heartbeat consumer - Specified in standard CiA 301" - -config CANOPENNODE_HB_CONS_ENABLE - bool "Enable heartbeat consumer" - default n - help - Monitor heartbeat messages from other nodes and trigger actions - based on their status. - -choice CANOPENNODE_HB_CONS_CALLBACK_MODE - prompt "Heartbeat consumer callback mode" - depends on CANOPENNODE_HB_CONS_ENABLE - optional - default CANOPENNODE_HB_CONS_CALLBACK_CHANGE - help - Select how heartbeat/NMT-change callbacks are handled. - Leave unset for no callbacks. Only one option can be active. - -config CANOPENNODE_HB_CONS_CALLBACK_CHANGE - bool "Single common callback after NMT state change" - help - Enable a single common callback invoked on NMT state changes. - Configure via CO_HBconsumer_initCallbackNmtChanged(). - -config CANOPENNODE_HB_CONS_CALLBACK_MULTI - bool "Per-node callbacks" - help - Enable per-node callbacks for NMT change, heartbeat started, - timeout, and remote reset. Configure via: - CO_HBconsumer_initCallbackNmtChanged(), - CO_HBconsumer_initCallbackHeartbeatStarted(), - CO_HBconsumer_initCallbackTimeout(), - CO_HBconsumer_initCallbackRemoteReset(). - -endchoice - -config CANOPENNODE_HB_CONS_QUERY_FUNCT - bool "Enable heartbeat and NMT query functions" - depends on CANOPENNODE_HB_CONS_ENABLE - default n - -config CANOPENNODE_HB_CONS_CALLBACK - bool "Enable custom callback after heartbeat message received" - depends on CANOPENNODE_HB_CONS_ENABLE - default n - help - Enable a callback invoked after a heartbeat message is preprocessed. - Configure via CO_HBconsumer_initCallbackPre(). - -config CANOPENNODE_HB_CONS_TIMERNEXT - bool "Enable heartbeat consumer timerNext_us calculation" - depends on CANOPENNODE_HB_CONS_ENABLE - default y - -config CANOPENNODE_HB_CONS_OD_DYNAMIC - bool "Enable dynamic behaviour of heartbeat consumer OD variables" - depends on CANOPENNODE_HB_CONS_ENABLE - default y - -endmenu - -menu "CANopen Node Guarding slave and master objects - Specified in standard CiA 301" - -config CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE - bool "Enable Node guarding slave" - default n - -config CANOPENNODE_NODE_GUARDING_MASTER_ENABLE - bool "Enable Node guarding master" - default n - -config CANOPENNODE_NODE_GUARDING_MASTER_COUNT - int "Max nodes monitored by guarding master" - range 1 127 - default 127 - -config CANOPENNODE_NODE_GUARDING_TIMERNEXT - bool "Enable Node guarding timerNext_us calculation" - depends on CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE || CANOPENNODE_NODE_GUARDING_MASTER_ENABLE - default n - -endmenu - -menu "Emergency producer/consumer - Specified in standard CiA 301" - -config CANOPENNODE_EM_PRODUCER - bool "Enable emergency producer" - default n - -config CANOPENNODE_EM_PROD_CONFIGURABLE - bool "Enable configurable COB-ID for emergency producer" - default n - -config CANOPENNODE_EM_PROD_INHIBIT - bool "Enable inhibit time for emergency producer" - default n - -config CANOPENNODE_EM_HISTORY - bool "Enable emergency error history" - default y - -config CANOPENNODE_EM_CONSUMER - bool "Enable emergency consumer" - default n - -config CANOPENNODE_EM_STATUS_BITS - bool "Enable emergency status bits in Object Dictionary" - default n - -config CANOPENNODE_EM_CALLBACK - bool "Enable custom callback after emergency message received" - default y - -config CANOPENNODE_EM_TIMERNEXT - bool "Enable emergency timerNext_us calculation" - default y - -config CANOPENNODE_EM_ERR_STATUS_BITS_COUNT - int "Emergency error status bits (multiple of 8)" - range 48 256 - default 80 - -# Optional error-register conditions (enable default expressions in mapper) -config CANOPENNODE_ERR_CONDITION_CURRENT - bool "Condition for calculating Error register: CURRENT" - default n - -config CANOPENNODE_ERR_CONDITION_VOLTAGE - bool "Condition for calculating Error register: VOLTAGE" - default n - -config CANOPENNODE_ERR_CONDITION_TEMPERATURE - bool "Condition for calculating Error register: TEMPERATURE" - default n - -config CANOPENNODE_ERR_CONDITION_DEV_PROFILE - bool "Condition for calculating Error register: DEVICE PROFILE" - default n - -endmenu - -menu "SDO server - Specified in standard CiA 301" - -config CANOPENNODE_SDO_SERVER_SEGMENTED - bool "Enable segmented SDO server" - default n - -config CANOPENNODE_SDO_SERVER_BLOCK - bool "Enable block SDO server" - select CANOPENNODE_SDO_SERVER_SEGMENTED - select CANOPENNODE_CRC16_ENABLE - default n - help - Use 127-segment block transfers with optional CRC for large, efficient transfers. - -config CANOPENNODE_SDO_SERVER_CALLBACK - bool "Enable SDO server callback" - default y - -config CANOPENNODE_SDO_SERVER_TIMERNEXT - bool "Enable SDO server timerNext_us calculation" - default y - -config CANOPENNODE_SDO_SERVER_OD_DYNAMIC - bool "Enable dynamic behaviour of SDO server OD variables" - default y - -config CANOPENNODE_SDO_SERVER_BUFFER_SIZE - int "SDO server buffer size" - range 900 4096 if CANOPENNODE_SDO_SERVER_BLOCK - range 20 4096 if !CANOPENNODE_SDO_SERVER_BLOCK - default 900 if CANOPENNODE_SDO_SERVER_BLOCK - default 32 - help - Internal buffer for SDO server. - - >=20 for segmented - - >=900 recommended for block (127 x 7 bytes) - -config CANOPENNODE_SDO_SERVER_TIMEOUT_MS - int "SDO server timeout (ms)" - range 50 60000 - default 1000 - -endmenu - -menu "SDO client - Specified in standard CiA 301" - -config CANOPENNODE_SDO_CLIENT_ENABLE - bool "Enable SDO client" - select CANOPENNODE_FIFO_ENABLE - default n - -config CANOPENNODE_SDO_CLIENT_SEGMENTED - bool "Enable SDO client segmented transfer" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default n - -config CANOPENNODE_SDO_CLIENT_BLOCK - bool "Enable SDO client block transfer" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - select CANOPENNODE_SDO_CLIENT_SEGMENTED - select CANOPENNODE_FIFO_ALT_READ - select CANOPENNODE_FIFO_CRC16_CCITT - default n - -config CANOPENNODE_SDO_CLIENT_LOCAL - bool "Enable local transfer (client/server same node)" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default n - -config CANOPENNODE_SDO_CLIENT_CALLBACK - bool "Enable SDO client callback" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default y - -config CANOPENNODE_SDO_CLIENT_TIMERNEXT - bool "Enable SDO client timerNext_us calculation" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default y - -config CANOPENNODE_SDO_CLIENT_OD_DYNAMIC - bool "Enable dynamic behaviour of SDO client OD variables" - depends on CANOPENNODE_SDO_CLIENT_ENABLE - default y - -config CANOPENNODE_SDO_CLIENT_BUFFER_SIZE - int "SDO client buffer size" - range 1000 4096 if CANOPENNODE_SDO_CLIENT_BLOCK - range 7 4096 if CANOPENNODE_SDO_CLIENT_SEGMENTED && !CANOPENNODE_SDO_CLIENT_BLOCK - default 1000 if CANOPENNODE_SDO_CLIENT_BLOCK - default 32 if !CANOPENNODE_SDO_CLIENT_BLOCK - help - Circular buffer used by SDO client. Can be <= object size since it is - processed over multiple calls. >=7 for segmented; >=1000 recommended for block. - -config CANOPENNODE_SDO_CLIENT_TIMEOUT_MS - int "SDO client timeout (ms)" - range 50 60000 - default 1000 - -endmenu - -menu "Time producer/consumer - Specified in standard CiA 301" - -config CANOPENNODE_TIME_ENABLE - bool "Enable TIME object and TIME consumer" - default n - -config CANOPENNODE_TIME_PRODUCER - bool "Enable TIME producer" - depends on CANOPENNODE_TIME_ENABLE - default n - -config CANOPENNODE_TIME_CALLBACK - bool "Enable TIME callback" - depends on CANOPENNODE_TIME_ENABLE - default y - -config CANOPENNODE_TIME_OD_DYNAMIC - bool "Enable dynamic behaviour of TIME OD variables" - depends on CANOPENNODE_TIME_ENABLE - default y - -endmenu - -menu "SYNC and PDO producer/consumer - Specified in standard CiA 301" - -config CANOPENNODE_SYNC_ENABLE - bool "Enable SYNC object and SYNC consumer" - default n - -config CANOPENNODE_SYNC_PRODUCER - bool "Enable SYNC producer" - depends on CANOPENNODE_SYNC_ENABLE - default n - -config CANOPENNODE_SYNC_CALLBACK - bool "Enable SYNC callback" - depends on CANOPENNODE_SYNC_ENABLE - default y - -config CANOPENNODE_SYNC_TIMERNEXT - bool "Enable SYNC timerNext_us calculation" - depends on CANOPENNODE_SYNC_ENABLE - default y - -config CANOPENNODE_SYNC_OD_DYNAMIC - bool "Enable dynamic behaviour of SYNC OD variables" - depends on CANOPENNODE_SYNC_ENABLE - default y - -config CANOPENNODE_RPDO_ENABLE - bool "Enable receive PDO objects (RPDOs)" - default n - -config CANOPENNODE_TPDO_ENABLE - bool "Enable transmit PDO objects (TPDOs)" - default n - -config CANOPENNODE_RPDO_TIMERS_ENABLE - bool "Enable RPDO timers" - depends on CANOPENNODE_RPDO_ENABLE - default y if CANOPENNODE_RPDO_ENABLE - default n - -config CANOPENNODE_TPDO_TIMERS_ENABLE - bool "Enable TPDO timers" - depends on CANOPENNODE_TPDO_ENABLE - default y if CANOPENNODE_TPDO_ENABLE - default n - -config CANOPENNODE_PDO_SYNC_ENABLE - bool "Enable PDO SYNC" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - select CANOPENNODE_SYNC_ENABLE - default y - help - Synchronize PDO processing with network SYNC messages. - -config CANOPENNODE_PDO_OD_IO_ACCESS - bool "Enable PDO OD IO access" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - select CANOPENNODE_PDO_OD_DYNAMIC - default y - help - Use OD IO accessors (OD_IO_t) for mapped PDO variables. - -config CANOPENNODE_PDO_CALLBACK - bool "Enable PDO callback" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default y - -config CANOPENNODE_PDO_TIMERNEXT - bool "Enable PDO timerNext_us calculation" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default y - -config CANOPENNODE_PDO_OD_DYNAMIC - bool "Enable dynamic behaviour of PDO OD variables" - depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE - default y - -endmenu - -menu "Data storage - Data storage with CANopen OD objects 1010 and 1011, CiA 301" - -config CANOPENNODE_STORAGE_ENABLE - bool "Enable data storage" - default n - help - Persist OD entries via 0x1010/0x1011. - -endmenu - -menu "Storage Backend" - depends on CANOPENNODE_STORAGE_ENABLE - -choice CANOPENNODE_STORAGE_BACKEND_CHOICE - prompt "Select CANopenNode OD storage backend" - default CANOPENNODE_STORAGE_BACKEND_RAM - -config CANOPENNODE_STORAGE_BACKEND_SETTINGS - bool "Zephyr Settings subsystem" - select SETTINGS - select CANOPENNODE_CRC16_ENABLE - help - Use Zephyr's Settings subsystem to persist OD entries. - -config CANOPENNODE_STORAGE_BACKEND_RAM - bool "RAM-only (no persistence)" - help - Store OD values in RAM only. Lost on reset. - -config CANOPENNODE_STORAGE_BACKEND_NONE - bool "None (disable OD storage)" - help - Disable OD storage completely. - -endchoice - -endmenu - -menu "Program Download - Specified in standard CiA 302-3" - -config CANOPENNODE_PROG_DOWNLOAD - bool "Enable Program Download object (CiA 302-3)" - select CANOPENNODE_CRC16_ENABLE - select FLASH_MAP - depends on FLASH - default n - help - Enables CO_Prog_Download: OD entries 0x1F21, 0x1F23, 0x1F24, 0x1F50, - 0x1F51, 0x1F56, 0x1F57. Streams data via registered backend and can - optionally bind to CO_storage for persistence. - -config CANOPENNODE_PROG_DOWNLOAD_EDS_MAX_SIZE - int "Maximum EDS file size (bytes)" - depends on CANOPENNODE_PROG_DOWNLOAD - default 2048 - range 256 1048576 - help - Upper limit for OD 0x1F23 (“Store EDS NMT slave”) data length. - If the received EDS exceeds this size, the transfer should be - rejected/aborted. Keep this reasonably small to avoid large - RAM allocations during transfer on constrained targets. - -config CANOPENNODE_PROG_DOWNLOAD_PERMANENT - bool "Program commit is permanent upgrade" - default y - help - If enabled, COMMIT (0x1F51 command) will request a permanent - upgrade of the programmed image. - If disabled, COMMIT will request a test upgrade instead, - requiring a later confirmation to keep the image. - -endmenu - -menu "CANopen LED Indicators - Specified in standard CiA 303-3" - -config CANOPENNODE_LEDS_ENABLE - bool "Enable calculation of the CANopen LED indicators" - default n - -config CANOPENNODE_LEDS_CALLBACK - bool "Enable custom callback after LED state changes" - default y if CANOPENNODE_LEDS_ENABLE - default n if !CANOPENNODE_LEDS_ENABLE - -config CANOPENNODE_LEDS_TIMERNEXT - bool "Enable calculation of timerNext_us for LED indicators" - default y if CANOPENNODE_LEDS_ENABLE - default n if !CANOPENNODE_LEDS_ENABLE - -endmenu - -menu "Safety Related Data Objects (SRDO) - Specified in standard EN 50325-5 (CiA 304)" - -config CANOPENNODE_GFC_ENABLE - bool "Enable GFC (Guarding Function Control)" - default n - -config CANOPENNODE_GFC_CONSUMER - bool "Enable GFC consumer" - depends on CANOPENNODE_GFC_ENABLE - default n - -config CANOPENNODE_GFC_PRODUCER - bool "Enable GFC producer" - depends on CANOPENNODE_GFC_ENABLE - default n - -config CANOPENNODE_SRDO_ENABLE - bool "Enable SRDO (Safety Related Data Objects)" - default n - -config CANOPENNODE_SRDO_CHECK_TX - bool "Enable SRDO TX data check" - depends on CANOPENNODE_SRDO_ENABLE - default n - -config CANOPENNODE_SRDO_CALLBACK - bool "Enable SRDO callback" - depends on CANOPENNODE_SRDO_ENABLE - default n - -config CANOPENNODE_SRDO_TIMERNEXT - bool "Enable SRDO timerNext_us calculation" - depends on CANOPENNODE_SRDO_ENABLE - default n - -config CANOPENNODE_SRDO_MINIMUM_DELAY - int "Minimum time between the first and second SRDO (Tx) message (us)" - range 0 1000000 - default 0 - -endmenu - -menu "LSS master/slave - Specified in standard CiA 305" - -config CANOPENNODE_LSS_SLAVE - bool "Enable LSS slave" - default n - -config CANOPENNODE_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND - bool "Enable fast-scan direct response" - depends on CANOPENNODE_LSS_SLAVE - default n - -config CANOPENNODE_LSS_MASTER - bool "Enable LSS master" - default n - -config CANOPENNODE_LSS_CALLBACK - bool "Enable LSS callback" - default n - -endmenu - -menu "Gateways - Specified in standard CiA 309" - -config CANOPENNODE_GTW_MULTI_NET - bool "Enable multiple network interfaces in gateway device" - depends on 0 - default n - -config CANOPENNODE_GTW_ASCII - bool "Enable gateway device with ASCII mapping" - select CANOPENNODE_FIFO_ENABLE - select CANOPENNODE_FIFO_ASCII_COMMANDS - default n - -config CANOPENNODE_GTW_ASCII_SDO - bool "Enable SDO client in gateway-ascii" - depends on CANOPENNODE_GTW_ASCII - select CANOPENNODE_SDO_CLIENT_ENABLE - select CANOPENNODE_FIFO_ASCII_DATATYPES - default n - -config CANOPENNODE_GTW_ASCII_NMT - bool "Enable NMT master in gateway-ascii" - depends on CANOPENNODE_GTW_ASCII - select CANOPENNODE_NMT_MASTER - default n - -config CANOPENNODE_GTW_ASCII_LSS - bool "Enable LSS master in gateway-ascii" - depends on CANOPENNODE_GTW_ASCII - select CANOPENNODE_LSS_MASTER - default n - -config CANOPENNODE_GTW_ASCII_LOG - bool "Enable non-standard message log read" - depends on CANOPENNODE_GTW_ASCII - default n - -config CANOPENNODE_GTW_ASCII_ERROR_DESC - bool "Print error descriptions as comments in gateway-ascii" - depends on CANOPENNODE_GTW_ASCII - default n - -config CANOPENNODE_GTW_ASCII_PRINT_HELP - bool "Enable non-standard \"help\" command" - depends on CANOPENNODE_GTW_ASCII - default n - -config CANOPENNODE_GTW_ASCII_PRINT_LEDS - bool "Display CANopen status LEDs on terminal" - depends on CANOPENNODE_GTW_ASCII - select CANOPENNODE_LEDS_ENABLE - default n - -config CANOPENNODE_GTW_BLOCK_DL_LOOP - int "Number of process loops in case of block download" - range 1 127 - default 1 - help - Additional local loop iterations while a block download is in progress - to speed up transfer (up to 127). - -config CANOPENNODE_GTWA_COMM_BUF_SIZE - int "Size of command buffer in ASCII gateway object" - range 16 4096 - default 200 - help - Increase to >=1000 when doing large block transfers. - -config CANOPENNODE_GTWA_LOG_BUF_SIZE - int "Gateway: log buffer size" - range 128 4096 - default 2000 - -endmenu - -menu "CRC 16 calculation" - -config CANOPENNODE_CRC16_ENABLE - bool "Enable CRC16 calculation" - default n - -config CANOPENNODE_CRC16_EXTERNAL - bool "CRC functions are defined externally" - depends on CANOPENNODE_CRC16_ENABLE - select CRC - default y if CANOPENNODE_CRC16_ENABLE - help - If enabled, the application must provide: - void crc16_ccitt_single(uint16_t *crc, uint8_t chr); - uint16_t crc16_ccitt(const uint8_t block[], size_t len, uint16_t crc); - If disabled, the internal CRC16 functions will be used. - -endmenu - -menu "FIFO buffer" - -config CANOPENNODE_FIFO_ENABLE - bool "Enable FIFO buffer" - default n - -config CANOPENNODE_FIFO_ALT_READ - bool "FIFO alternate read (needed by SDO client block)" - depends on CANOPENNODE_FIFO_ENABLE - default n - -config CANOPENNODE_FIFO_CRC16_CCITT - bool "FIFO CRC16-CCITT (needed by SDO client block)" - depends on CANOPENNODE_FIFO_ENABLE - select CANOPENNODE_CRC16_ENABLE - default n - -config CANOPENNODE_FIFO_ASCII_COMMANDS - bool "FIFO ASCII command helpers" - depends on CANOPENNODE_FIFO_ENABLE - default n - -config CANOPENNODE_FIFO_ASCII_DATATYPES - bool "FIFO ASCII datatype helpers" - depends on CANOPENNODE_FIFO_ENABLE && CANOPENNODE_FIFO_ASCII_COMMANDS - default n - help - Helpers to read/write integers/floats/strings in ASCII. - -endmenu - -menu "Trace recorder" - -config CANOPENNODE_TRACE_ENABLE - bool "Enable Trace recorder" - default n - -config CANOPENNODE_TRACE_OWN_INTTYPES - bool "Provide custom PRIu32/PRId32 macros (no )" - depends on CANOPENNODE_TRACE_ENABLE - default n - -endmenu - -menu "Debug messages" - -config CANOPENNODE_DEBUG_COMMON - bool "Define default CO_DEBUG_COMMON(msg) macro" - default n - -config CANOPENNODE_DEBUG_SDO_CLIENT - bool "Define default CO_DEBUG_SDO_CLIENT(msg) macro" - select CANOPENNODE_DEBUG_COMMON - default n - -config CANOPENNODE_DEBUG_SDO_SERVER - bool "Define default CO_DEBUG_SDO_SERVER(msg) macro" - select CANOPENNODE_DEBUG_COMMON - default n - -endmenu - -menu "Object Dictionary (EDS)" - -config CANOPENNODE_EDS_FILE_PATH - string "EDS file (path relative to application root)" - default "" - help - Path to the EDS used to generate OD.c/OD.h. - Leave empty to use: - example/DS301_profile.eds - -endmenu - -menu "CANopenNode TX Workqueue Options" - -config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE - int "TX workqueue stack size" - default 1024 - range 256 16384 - help - Stack size (in bytes) for the CANopenNode TX workqueue thread. - -config CANOPENNODE_TX_WORKQUEUE_PRIORITY - int "TX workqueue priority" - default 0 - help - Thread priority for the CANopenNode TX workqueue. - Lower numbers mean higher priority. - -endmenu - -menu "CANopenNode Thread Options" - -config CANOPENNODE_RT_THREAD - bool "Use real-time thread for CANopen processing" - default y - help - If enabled, a dedicated real-time thread will be created for CANopen - processing. Otherwise, the application must call CO_process() periodically. - -config CANOPENNODE_RT_THREAD_STACK_SIZE - int "Real-time thread stack size" - default 1024 - help - Stack size (bytes) for the CANopenNode real-time thread. - Only used if CANOPENNODE_RT_THREAD is enabled. - Increase if you use many PDOs, SDOs, or large OD entries. - Decrease if you have memory constraints and use few CANopen features. - Typical values: 1024-4096 bytes. - Measure actual stack usage to optimize. - -config CANOPENNODE_RT_THREAD_PRIORITY - int "Real-time thread priority" - default -1 - help - Thread priority for the CANopenNode real-time thread. - Only used if CANOPENNODE_RT_THREAD is enabled. - Lower numbers mean higher priority. - Typical values: -1 to -3 for real-time processing. - -config CANOPENNODE_RT_THREAD_IDLE_MS - int "Real-time thread idle time (ms)" - default 10 - help - Time (ms) the CANopenNode real-time thread sleeps when idle. - Only used if CANOPENNODE_RT_THREAD is enabled. - Lower values mean more CPU usage but lower latency. - Typical values: 1-100 ms. - -config CANOPENNODE_RT_THREAD_TIMERNEXT - bool "Enable timerNext_us calculation in real-time thread" - default y - help - If enabled, timerNext_us will be calculated in the real-time thread. - Only used if CANOPENNODE_RT_THREAD is enabled. - Disable to save CPU if you don't use features that need timerNext_us. - -config CANOPENNODE_RT_THREAD_AUTO_START - bool "Auto-start CANopenNode real-time thread" - default y - help - If enabled, the CANopenNode real-time thread will be started automatically - at POST_KERNEL. Otherwise, you must call CO_RT_threadStart() manually. -endmenu - -menu "CANopenNode Initialization" - -config CANOPENNODE_INIT_PRIORITY - int "CANopenNode initialization priority" - default 90 - help - Priority for CANopenNode initialization. - Lower numbers mean earlier initialization. - Typical values: 80-100. - Must be lower than the application's main thread priority. - -config CANOPENNODE_INIT_NODE_ID - int "CANopenNode node ID" - default 1 - range 0 127 - help - Node ID for the CANopenNode instance. - Must be unique on the CAN bus. - -endmenu - -module = CANOPEN -module-str = canopen -source "subsys/logging/Kconfig.template.log_config" - -endif # CANOPENNODE +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 BitConcepts, LLC +# +# CANopenNode — Zephyr module Kconfig +# +# This Kconfig file exposes CANopenNode features to Zephyr as CONFIG_* options. +# It lets you enable/disable protocol modules (NMT, SDO, PDO, etc.), choose +# Zephyr-specific integrations (storage backend, LED GPIO bridge), and set +# module-level parameters (buffers, timeouts, thread options). +# +# @file Kconfig +# @author BitConcepts, LLC +# +# This file is part of , a CANopen Stack. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +# Usage notes: +# - Enable top-level CONFIG_CANOPENNODE=y in prj.conf to include the stack. +# - Most options default to sensible values; adjust per application needs. +# - Some features imply others via 'select' (see help for each symbol). +# - For LED helpers (CiA 303-3), provide devicetree aliases: +# aliases { +# co_led_run = &led0; +# co_led_err = &led1; +# }; +# - For Object Dictionary generation, set CONFIG_CANOPENNODE_EDS_FILE_PATH +# to an EDS relative to your application root (see CMakeLists.txt logic). + +menuconfig CANOPENNODE + bool "CANopenNode protocol stack support" + depends on CAN + default n + help + Enable the CANopenNode stack integration for Zephyr. + +if CANOPENNODE + +menu "NMT / Heartbeat producer - Specified in standard CiA 301" + +config CANOPENNODE_NMT_CALLBACK_CHANGE + bool "Enable custom callback after NMT state changes" + default y + help + Enable a custom callback invoked after the NMT state changes. + Configure via CO_NMT_initCallbackChanged(). + +config CANOPENNODE_NMT_MASTER + bool "Enable simple NMT master" + default n + help + Enable a simple NMT master object to control other nodes' + NMT states (start/stop/reset). + +config CANOPENNODE_NMT_CALLBACK + bool "Enable custom callback after preprocessing received NMT message" + default y + help + Enable a custom callback invoked after a received NMT message + is preprocessed. Configure via CO_NMT_initCallbackPre(). + +config CANOPENNODE_NMT_TIMERNEXT + bool "Enable NMT timerNext_us calculation" + default y + help + Enable calculation of timerNext_us for NMT to schedule next processing. + +config CANOPENNODE_NMT_FIRST_HB_TIME_MS + int "First heartbeat delay (ms)" + range 0 65535 + default 0 + help + Delay before the first Heartbeat after boot/reset. + 0 = no extra delay (start HB with the normal 0x1017 period). + Typical values: 200-1000 ms to let peers install filters and avoid + false HB-consumer timeouts during bus bring-up. + +endmenu + +menu "NMT startup/control" + +config CANOPENNODE_NMT_STARTUP_TO_OPERATIONAL + bool "Start in Operational after init (CO_NMT_STARTUP_TO_OPERATIONAL)" + default y + +config CANOPENNODE_NMT_ERR_ON_BUSOFF_HB + bool "Error on bus-off / HB timeout (CO_NMT_ERR_ON_BUSOFF_HB)" + default y + +config CANOPENNODE_NMT_ERR_ON_ERR_REG + bool "Error on nonzero masked error register (CO_NMT_ERR_ON_ERR_REG)" + default y + +config CANOPENNODE_NMT_ERR_TO_STOPPED + bool "On error -> go to Stopped (else Pre-op) (CO_NMT_ERR_TO_STOPPED)" + default n + +config CANOPENNODE_NMT_ERR_FREE_TO_OPERATIONAL + bool "Auto-return to Operational when errors clear (CO_NMT_ERR_FREE_TO_OPERATIONAL)" + default n + +comment "Error register mask (low 8 bits of NMT control)" + +endmenu + +menu "Heartbeat consumer - Specified in standard CiA 301" + +config CANOPENNODE_HB_CONS_ENABLE + bool "Enable heartbeat consumer" + default n + help + Monitor heartbeat messages from other nodes and trigger actions + based on their status. + +choice CANOPENNODE_HB_CONS_CALLBACK_MODE + prompt "Heartbeat consumer callback mode" + depends on CANOPENNODE_HB_CONS_ENABLE + optional + default CANOPENNODE_HB_CONS_CALLBACK_CHANGE + help + Select how heartbeat/NMT-change callbacks are handled. + Leave unset for no callbacks. Only one option can be active. + +config CANOPENNODE_HB_CONS_CALLBACK_CHANGE + bool "Single common callback after NMT state change" + help + Enable a single common callback invoked on NMT state changes. + Configure via CO_HBconsumer_initCallbackNmtChanged(). + +config CANOPENNODE_HB_CONS_CALLBACK_MULTI + bool "Per-node callbacks" + help + Enable per-node callbacks for NMT change, heartbeat started, + timeout, and remote reset. Configure via: + CO_HBconsumer_initCallbackNmtChanged(), + CO_HBconsumer_initCallbackHeartbeatStarted(), + CO_HBconsumer_initCallbackTimeout(), + CO_HBconsumer_initCallbackRemoteReset(). + +endchoice + +config CANOPENNODE_HB_CONS_QUERY_FUNCT + bool "Enable heartbeat and NMT query functions" + depends on CANOPENNODE_HB_CONS_ENABLE + default n + +config CANOPENNODE_HB_CONS_CALLBACK + bool "Enable custom callback after heartbeat message received" + depends on CANOPENNODE_HB_CONS_ENABLE + default n + help + Enable a callback invoked after a heartbeat message is preprocessed. + Configure via CO_HBconsumer_initCallbackPre(). + +config CANOPENNODE_HB_CONS_TIMERNEXT + bool "Enable heartbeat consumer timerNext_us calculation" + depends on CANOPENNODE_HB_CONS_ENABLE + default y + +config CANOPENNODE_HB_CONS_OD_DYNAMIC + bool "Enable dynamic behaviour of heartbeat consumer OD variables" + depends on CANOPENNODE_HB_CONS_ENABLE + default y + +endmenu + +menu "CANopen Node Guarding slave and master objects - Specified in standard CiA 301" + +config CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE + bool "Enable Node guarding slave" + default n + +config CANOPENNODE_NODE_GUARDING_MASTER_ENABLE + bool "Enable Node guarding master" + default n + +config CANOPENNODE_NODE_GUARDING_MASTER_COUNT + int "Max nodes monitored by guarding master" + range 1 127 + default 127 + +config CANOPENNODE_NODE_GUARDING_TIMERNEXT + bool "Enable Node guarding timerNext_us calculation" + depends on CANOPENNODE_NODE_GUARDING_SLAVE_ENABLE || CANOPENNODE_NODE_GUARDING_MASTER_ENABLE + default n + +endmenu + +menu "Emergency producer/consumer - Specified in standard CiA 301" + +config CANOPENNODE_EM_PRODUCER + bool "Enable emergency producer" + default n + +config CANOPENNODE_EM_PROD_CONFIGURABLE + bool "Enable configurable COB-ID for emergency producer" + default n + +config CANOPENNODE_EM_PROD_INHIBIT + bool "Enable inhibit time for emergency producer" + default n + +config CANOPENNODE_EM_HISTORY + bool "Enable emergency error history" + default y + +config CANOPENNODE_EM_CONSUMER + bool "Enable emergency consumer" + default n + +config CANOPENNODE_EM_STATUS_BITS + bool "Enable emergency status bits in Object Dictionary" + default n + +config CANOPENNODE_EM_CALLBACK + bool "Enable custom callback after emergency message received" + default y + +config CANOPENNODE_EM_TIMERNEXT + bool "Enable emergency timerNext_us calculation" + default y + +config CANOPENNODE_EM_ERR_STATUS_BITS_COUNT + int "Emergency error status bits (multiple of 8)" + range 48 256 + default 80 + +# Optional error-register conditions (enable default expressions in mapper) +config CANOPENNODE_ERR_CONDITION_CURRENT + bool "Condition for calculating Error register: CURRENT" + default n + +config CANOPENNODE_ERR_CONDITION_VOLTAGE + bool "Condition for calculating Error register: VOLTAGE" + default n + +config CANOPENNODE_ERR_CONDITION_TEMPERATURE + bool "Condition for calculating Error register: TEMPERATURE" + default n + +config CANOPENNODE_ERR_CONDITION_DEV_PROFILE + bool "Condition for calculating Error register: DEVICE PROFILE" + default n + +endmenu + +menu "SDO server - Specified in standard CiA 301" + +config CANOPENNODE_SDO_SERVER_SEGMENTED + bool "Enable segmented SDO server" + default n + +config CANOPENNODE_SDO_SERVER_BLOCK + bool "Enable block SDO server" + select CANOPENNODE_SDO_SERVER_SEGMENTED + select CANOPENNODE_CRC16_ENABLE + default n + help + Use 127-segment block transfers with optional CRC for large, efficient transfers. + +config CANOPENNODE_SDO_SERVER_CALLBACK + bool "Enable SDO server callback" + default y + +config CANOPENNODE_SDO_SERVER_TIMERNEXT + bool "Enable SDO server timerNext_us calculation" + default y + +config CANOPENNODE_SDO_SERVER_OD_DYNAMIC + bool "Enable dynamic behaviour of SDO server OD variables" + default y + +config CANOPENNODE_SDO_SERVER_BUFFER_SIZE + int "SDO server buffer size" + range 900 4096 if CANOPENNODE_SDO_SERVER_BLOCK + range 20 4096 if !CANOPENNODE_SDO_SERVER_BLOCK + default 900 if CANOPENNODE_SDO_SERVER_BLOCK + default 32 + help + Internal buffer for SDO server. + - >=20 for segmented + - >=900 recommended for block (127 x 7 bytes) + +config CANOPENNODE_SDO_SERVER_TIMEOUT_MS + int "SDO server timeout (ms)" + range 50 60000 + default 1000 + +endmenu + +menu "SDO client - Specified in standard CiA 301" + +config CANOPENNODE_SDO_CLIENT_ENABLE + bool "Enable SDO client" + select CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_SEGMENTED + bool "Enable SDO client segmented transfer" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_BLOCK + bool "Enable SDO client block transfer" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + select CANOPENNODE_SDO_CLIENT_SEGMENTED + select CANOPENNODE_FIFO_ALT_READ + select CANOPENNODE_FIFO_CRC16_CCITT + default n + +config CANOPENNODE_SDO_CLIENT_LOCAL + bool "Enable local transfer (client/server same node)" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default n + +config CANOPENNODE_SDO_CLIENT_CALLBACK + bool "Enable SDO client callback" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default y + +config CANOPENNODE_SDO_CLIENT_TIMERNEXT + bool "Enable SDO client timerNext_us calculation" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default y + +config CANOPENNODE_SDO_CLIENT_OD_DYNAMIC + bool "Enable dynamic behaviour of SDO client OD variables" + depends on CANOPENNODE_SDO_CLIENT_ENABLE + default y + +config CANOPENNODE_SDO_CLIENT_BUFFER_SIZE + int "SDO client buffer size" + range 1000 4096 if CANOPENNODE_SDO_CLIENT_BLOCK + range 7 4096 if CANOPENNODE_SDO_CLIENT_SEGMENTED && !CANOPENNODE_SDO_CLIENT_BLOCK + default 1000 if CANOPENNODE_SDO_CLIENT_BLOCK + default 32 if !CANOPENNODE_SDO_CLIENT_BLOCK + help + Circular buffer used by SDO client. Can be <= object size since it is + processed over multiple calls. >=7 for segmented; >=1000 recommended for block. + +config CANOPENNODE_SDO_CLIENT_TIMEOUT_MS + int "SDO client timeout (ms)" + range 50 60000 + default 1000 + +endmenu + +menu "Time producer/consumer - Specified in standard CiA 301" + +config CANOPENNODE_TIME_ENABLE + bool "Enable TIME object and TIME consumer" + default n + +config CANOPENNODE_TIME_PRODUCER + bool "Enable TIME producer" + depends on CANOPENNODE_TIME_ENABLE + default n + +config CANOPENNODE_TIME_CALLBACK + bool "Enable TIME callback" + depends on CANOPENNODE_TIME_ENABLE + default y + +config CANOPENNODE_TIME_OD_DYNAMIC + bool "Enable dynamic behaviour of TIME OD variables" + depends on CANOPENNODE_TIME_ENABLE + default y + +endmenu + +menu "SYNC and PDO producer/consumer - Specified in standard CiA 301" + +config CANOPENNODE_SYNC_ENABLE + bool "Enable SYNC object and SYNC consumer" + default n + +config CANOPENNODE_SYNC_PRODUCER + bool "Enable SYNC producer" + depends on CANOPENNODE_SYNC_ENABLE + default n + +config CANOPENNODE_SYNC_CALLBACK + bool "Enable SYNC callback" + depends on CANOPENNODE_SYNC_ENABLE + default y + +config CANOPENNODE_SYNC_TIMERNEXT + bool "Enable SYNC timerNext_us calculation" + depends on CANOPENNODE_SYNC_ENABLE + default y + +config CANOPENNODE_SYNC_OD_DYNAMIC + bool "Enable dynamic behaviour of SYNC OD variables" + depends on CANOPENNODE_SYNC_ENABLE + default y + +config CANOPENNODE_RPDO_ENABLE + bool "Enable receive PDO objects (RPDOs)" + default n + +config CANOPENNODE_TPDO_ENABLE + bool "Enable transmit PDO objects (TPDOs)" + default n + +config CANOPENNODE_RPDO_TIMERS_ENABLE + bool "Enable RPDO timers" + depends on CANOPENNODE_RPDO_ENABLE + default y if CANOPENNODE_RPDO_ENABLE + default n + +config CANOPENNODE_TPDO_TIMERS_ENABLE + bool "Enable TPDO timers" + depends on CANOPENNODE_TPDO_ENABLE + default y if CANOPENNODE_TPDO_ENABLE + default n + +config CANOPENNODE_PDO_SYNC_ENABLE + bool "Enable PDO SYNC" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + select CANOPENNODE_SYNC_ENABLE + default y + help + Synchronize PDO processing with network SYNC messages. + +config CANOPENNODE_PDO_OD_IO_ACCESS + bool "Enable PDO OD IO access" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + select CANOPENNODE_PDO_OD_DYNAMIC + default y + help + Use OD IO accessors (OD_IO_t) for mapped PDO variables. + +config CANOPENNODE_PDO_CALLBACK + bool "Enable PDO callback" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default y + +config CANOPENNODE_PDO_TIMERNEXT + bool "Enable PDO timerNext_us calculation" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default y + +config CANOPENNODE_PDO_OD_DYNAMIC + bool "Enable dynamic behaviour of PDO OD variables" + depends on CANOPENNODE_RPDO_ENABLE || CANOPENNODE_TPDO_ENABLE + default y + +endmenu + +menu "Data storage - Data storage with CANopen OD objects 1010 and 1011, CiA 301" + +config CANOPENNODE_STORAGE_ENABLE + bool "Enable data storage" + default n + help + Persist OD entries via 0x1010/0x1011. + +endmenu + +menu "Storage Backend" + depends on CANOPENNODE_STORAGE_ENABLE + +choice CANOPENNODE_STORAGE_BACKEND_CHOICE + prompt "Select CANopenNode OD storage backend" + default CANOPENNODE_STORAGE_BACKEND_RAM + +config CANOPENNODE_STORAGE_BACKEND_SETTINGS + bool "Zephyr Settings subsystem" + select SETTINGS + select CANOPENNODE_CRC16_ENABLE + help + Use Zephyr's Settings subsystem to persist OD entries. + +config CANOPENNODE_STORAGE_BACKEND_RAM + bool "RAM-only (no persistence)" + help + Store OD values in RAM only. Lost on reset. + +config CANOPENNODE_STORAGE_BACKEND_NONE + bool "None (disable OD storage)" + help + Disable OD storage completely. + +endchoice + +endmenu + +menu "Program Download - Specified in standard CiA 302-3" + +config CANOPENNODE_PROG_DOWNLOAD + bool "Enable Program Download object (CiA 302-3)" + select CANOPENNODE_CRC16_ENABLE + select FLASH_MAP + depends on FLASH + default n + help + Enables CO_Prog_Download: OD entries 0x1F21, 0x1F23, 0x1F24, 0x1F50, + 0x1F51, 0x1F56, 0x1F57. Streams data via registered backend and can + optionally bind to CO_storage for persistence. + +config CANOPENNODE_PROG_DOWNLOAD_EDS_MAX_SIZE + int "Maximum EDS file size (bytes)" + depends on CANOPENNODE_PROG_DOWNLOAD + default 2048 + range 256 1048576 + help + Upper limit for OD 0x1F23 (“Store EDS NMT slave”) data length. + If the received EDS exceeds this size, the transfer should be + rejected/aborted. Keep this reasonably small to avoid large + RAM allocations during transfer on constrained targets. + +config CANOPENNODE_PROG_DOWNLOAD_PERMANENT + bool "Program commit is permanent upgrade" + default y + help + If enabled, COMMIT (0x1F51 command) will request a permanent + upgrade of the programmed image. + If disabled, COMMIT will request a test upgrade instead, + requiring a later confirmation to keep the image. + +endmenu + +menu "CANopen LED Indicators - Specified in standard CiA 303-3" + +config CANOPENNODE_LEDS_ENABLE + bool "Enable calculation of the CANopen LED indicators" + default n + +config CANOPENNODE_LEDS_CALLBACK + bool "Enable custom callback after LED state changes" + default y if CANOPENNODE_LEDS_ENABLE + default n if !CANOPENNODE_LEDS_ENABLE + +config CANOPENNODE_LEDS_TIMERNEXT + bool "Enable calculation of timerNext_us for LED indicators" + default y if CANOPENNODE_LEDS_ENABLE + default n if !CANOPENNODE_LEDS_ENABLE + +endmenu + +menu "Safety Related Data Objects (SRDO) - Specified in standard EN 50325-5 (CiA 304)" + +config CANOPENNODE_GFC_ENABLE + bool "Enable GFC (Guarding Function Control)" + default n + +config CANOPENNODE_GFC_CONSUMER + bool "Enable GFC consumer" + depends on CANOPENNODE_GFC_ENABLE + default n + +config CANOPENNODE_GFC_PRODUCER + bool "Enable GFC producer" + depends on CANOPENNODE_GFC_ENABLE + default n + +config CANOPENNODE_SRDO_ENABLE + bool "Enable SRDO (Safety Related Data Objects)" + default n + +config CANOPENNODE_SRDO_CHECK_TX + bool "Enable SRDO TX data check" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_CALLBACK + bool "Enable SRDO callback" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_TIMERNEXT + bool "Enable SRDO timerNext_us calculation" + depends on CANOPENNODE_SRDO_ENABLE + default n + +config CANOPENNODE_SRDO_MINIMUM_DELAY + int "Minimum time between the first and second SRDO (Tx) message (us)" + range 0 1000000 + default 0 + +endmenu + +menu "LSS master/slave - Specified in standard CiA 305" + +config CANOPENNODE_LSS_SLAVE + bool "Enable LSS slave" + default n + +config CANOPENNODE_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND + bool "Enable fast-scan direct response" + depends on CANOPENNODE_LSS_SLAVE + default n + +config CANOPENNODE_LSS_MASTER + bool "Enable LSS master" + default n + +config CANOPENNODE_LSS_CALLBACK + bool "Enable LSS callback" + default n + +endmenu + +menu "Gateways - Specified in standard CiA 309" + +config CANOPENNODE_GTW_MULTI_NET + bool "Enable multiple network interfaces in gateway device" + depends on 0 + default n + +config CANOPENNODE_GTW_ASCII + bool "Enable gateway device with ASCII mapping" + select CANOPENNODE_FIFO_ENABLE + select CANOPENNODE_FIFO_ASCII_COMMANDS + default n + +config CANOPENNODE_GTW_ASCII_SDO + bool "Enable SDO client in gateway-ascii" + depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_SDO_CLIENT_ENABLE + select CANOPENNODE_FIFO_ASCII_DATATYPES + default n + +config CANOPENNODE_GTW_ASCII_NMT + bool "Enable NMT master in gateway-ascii" + depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_NMT_MASTER + default n + +config CANOPENNODE_GTW_ASCII_LSS + bool "Enable LSS master in gateway-ascii" + depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_LSS_MASTER + default n + +config CANOPENNODE_GTW_ASCII_LOG + bool "Enable non-standard message log read" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_ERROR_DESC + bool "Print error descriptions as comments in gateway-ascii" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_PRINT_HELP + bool "Enable non-standard \"help\" command" + depends on CANOPENNODE_GTW_ASCII + default n + +config CANOPENNODE_GTW_ASCII_PRINT_LEDS + bool "Display CANopen status LEDs on terminal" + depends on CANOPENNODE_GTW_ASCII + select CANOPENNODE_LEDS_ENABLE + default n + +config CANOPENNODE_GTW_BLOCK_DL_LOOP + int "Number of process loops in case of block download" + range 1 127 + default 1 + help + Additional local loop iterations while a block download is in progress + to speed up transfer (up to 127). + +config CANOPENNODE_GTWA_COMM_BUF_SIZE + int "Size of command buffer in ASCII gateway object" + range 16 4096 + default 200 + help + Increase to >=1000 when doing large block transfers. + +config CANOPENNODE_GTWA_LOG_BUF_SIZE + int "Gateway: log buffer size" + range 128 4096 + default 2000 + +endmenu + +menu "CRC 16 calculation" + +config CANOPENNODE_CRC16_ENABLE + bool "Enable CRC16 calculation" + default n + +config CANOPENNODE_CRC16_EXTERNAL + bool "CRC functions are defined externally" + depends on CANOPENNODE_CRC16_ENABLE + select CRC + default y if CANOPENNODE_CRC16_ENABLE + help + If enabled, the application must provide: + void crc16_ccitt_single(uint16_t *crc, uint8_t chr); + uint16_t crc16_ccitt(const uint8_t block[], size_t len, uint16_t crc); + If disabled, the internal CRC16 functions will be used. + +endmenu + +menu "FIFO buffer" + +config CANOPENNODE_FIFO_ENABLE + bool "Enable FIFO buffer" + default n + +config CANOPENNODE_FIFO_ALT_READ + bool "FIFO alternate read (needed by SDO client block)" + depends on CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_FIFO_CRC16_CCITT + bool "FIFO CRC16-CCITT (needed by SDO client block)" + depends on CANOPENNODE_FIFO_ENABLE + select CANOPENNODE_CRC16_ENABLE + default n + +config CANOPENNODE_FIFO_ASCII_COMMANDS + bool "FIFO ASCII command helpers" + depends on CANOPENNODE_FIFO_ENABLE + default n + +config CANOPENNODE_FIFO_ASCII_DATATYPES + bool "FIFO ASCII datatype helpers" + depends on CANOPENNODE_FIFO_ENABLE && CANOPENNODE_FIFO_ASCII_COMMANDS + default n + help + Helpers to read/write integers/floats/strings in ASCII. + +endmenu + +menu "Trace recorder" + +config CANOPENNODE_TRACE_ENABLE + bool "Enable Trace recorder" + default n + +config CANOPENNODE_TRACE_OWN_INTTYPES + bool "Provide custom PRIu32/PRId32 macros (no )" + depends on CANOPENNODE_TRACE_ENABLE + default n + +endmenu + +menu "Debug messages" + +config CANOPENNODE_DEBUG_COMMON + bool "Define default CO_DEBUG_COMMON(msg) macro" + default n + +config CANOPENNODE_DEBUG_SDO_CLIENT + bool "Define default CO_DEBUG_SDO_CLIENT(msg) macro" + select CANOPENNODE_DEBUG_COMMON + default n + +config CANOPENNODE_DEBUG_SDO_SERVER + bool "Define default CO_DEBUG_SDO_SERVER(msg) macro" + select CANOPENNODE_DEBUG_COMMON + default n + +endmenu + +menu "Object Dictionary (EDS)" + +config CANOPENNODE_EDS_FILE_PATH + string "EDS file (path relative to application root)" + default "" + help + Path to the EDS used to generate OD.c/OD.h. + Leave empty to use: + example/DS301_profile.eds + +endmenu + +menu "CANopenNode TX Workqueue Options" + +config CANOPENNODE_TX_WORKQUEUE_STACK_SIZE + int "TX workqueue stack size" + default 1024 + range 256 16384 + help + Stack size (in bytes) for the CANopenNode TX workqueue thread. + +config CANOPENNODE_TX_WORKQUEUE_PRIORITY + int "TX workqueue priority" + default 0 + help + Thread priority for the CANopenNode TX workqueue. + Lower numbers mean higher priority. + +endmenu + +menu "CANopenNode Thread Options" + +config CANOPENNODE_RT_THREAD + bool "Use real-time thread for CANopen processing" + default y + help + If enabled, a dedicated real-time thread will be created for CANopen + processing. Otherwise, the application must call CO_process() periodically. + +config CANOPENNODE_RT_THREAD_STACK_SIZE + int "Real-time thread stack size" + default 1024 + help + Stack size (bytes) for the CANopenNode real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. + Increase if you use many PDOs, SDOs, or large OD entries. + Decrease if you have memory constraints and use few CANopen features. + Typical values: 1024-4096 bytes. + Measure actual stack usage to optimize. + +config CANOPENNODE_RT_THREAD_PRIORITY + int "Real-time thread priority" + default -1 + help + Thread priority for the CANopenNode real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. + Lower numbers mean higher priority. + Typical values: -1 to -3 for real-time processing. + +config CANOPENNODE_RT_THREAD_IDLE_MS + int "Real-time thread idle time (ms)" + default 10 + help + Time (ms) the CANopenNode real-time thread sleeps when idle. + Only used if CANOPENNODE_RT_THREAD is enabled. + Lower values mean more CPU usage but lower latency. + Typical values: 1-100 ms. + +config CANOPENNODE_RT_THREAD_TIMERNEXT + bool "Enable timerNext_us calculation in real-time thread" + default y + help + If enabled, timerNext_us will be calculated in the real-time thread. + Only used if CANOPENNODE_RT_THREAD is enabled. + Disable to save CPU if you don't use features that need timerNext_us. + +config CANOPENNODE_RT_THREAD_AUTO_START + bool "Auto-start CANopenNode real-time thread" + default y + help + If enabled, the CANopenNode real-time thread will be started automatically + at POST_KERNEL. Otherwise, you must call CO_RT_threadStart() manually. +endmenu + +menu "CANopenNode Initialization" + +config CANOPENNODE_INIT_PRIORITY + int "CANopenNode initialization priority" + default 90 + help + Priority for CANopenNode initialization. + Lower numbers mean earlier initialization. + Typical values: 80-100. + Must be lower than the application's main thread priority. + +config CANOPENNODE_INIT_NODE_ID + int "CANopenNode node ID" + default 1 + range 0 127 + help + Node ID for the CANopenNode instance. + Must be unique on the CAN bus. + +endmenu + +module = CANOPEN +module-str = canopen +source "subsys/logging/Kconfig.template.log_config" + +endif # CANOPENNODE